某项目从3000并发到10W并发的优化记录

  in   tech with  0  comment

最近在做一个某集团一个线上直播的活动,由于时间紧迫,而且项目描述不清。所以开发和部署的时候没有做特别的优化,但是第一次测试的时候问题非常大。主要出在并发上面。这里记录一下优化记录。

背景

因为是临时通知,所以从项目开始到测试仅仅一周时间,所以就快速开发了一个版本,使用 php + mysql,部署的话非常简单的用了一台8核8G的测试服务器,16核16G的正式服务器,lamp 结构。因为给我的员工名单只有10万左右,预计分析的并发量大概有3000-5000,压力测试也没有什么问题。结果活动彩排当天,内部 app 推送、合作厂商 app 内推送、老总发了个微信朋友圈,然后并发在十分钟内过两万,然后就崩了。。。一脸懵逼。

原因

出这么回事当然要写问题报告和整改方案。查看服务器日志发现以下问题。

这个问题是最大的,半个小时之内流量达到30T。

间歇性 cpu 达到 100%

间歇性 cpu 达到 100%

分析

主要因为前端资源问题,静态资源没有压缩、图片太大、没有使用 CDN、没有延时加载、资源没有合并

因为当时在处理别的事情,所以并没有看到当时服务器进程信息,无法确定具体原因。但是分析是因为 apache 多核支持不好、静态资源处理性能不好、而且前端资源大多没有合并、请求数太大,而且没有控制 apache 的连接数和等待时间,导致大量并发堵塞。之后查看 apache 的 log 发下如下错误

[Wed Apr 19 14:01:34.639455 2017] [mpm_prefork:error] [pid 3649] AH00161: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting

结合其他错误日志和访问日志基本上可以定位到问题

查看数据库的 log 发现主要因为是频繁写入导致。频繁写入只要因为程序中记录用户行为记录导致。

解决

  1. 静态资源压缩、合并、迁移到 cdn

  2. 前后分离、保证静态页面加载速度、数据异步加载、localstorage 缓存部分容灾数据。

  3. 后端使用 redis 缓存常用数据、日志记录加入 redis 队列定时或定量统一入库

  4. 多台服务器进行负载均衡、数据库读写分离、主从同步

  5. apache更换为nginx并升级到最新版

  6. centOs 从 6.8升级到7.3,php5.6升级到php7

实施

服务器部署,大概如下图

QQ截图20170423141529.png

静态资源使用 gulp 进行文件的压缩,具体可以参见之前写文章:打造自己的 gulp 前端自动化任务

redis 队列使用实例,

$redis->sAdd('jump_list',$_GET['um']); //队列大于100时写入文件 if($redis->ssize('jump_list')>100){ $list=$redis->smembers('jump_list'); //清空队列 $redis->delete('jump_list'); //入库 $time=time(); $ip=$_SERVER["REMOTE_ADDR"]; foreach ($list as $v) { $data[]=[ 'username'=>$v, 'addtime'=>$time, 'type'=>2, 'ip'=>$ip ]; } $database->insert('user_log',$data); }

负载均衡因为时间紧迫,没有自己搭建请求转发服务器,而是使用某云的负载均衡。

文件同步

由于代码部署在多台服务器中,所以测试服务器要和生产服务器文件进行同步,这里使用 scp 进行文件同步。因为用到 shell 的流程就控制所以需要用到 expect 。服务器没有的需要先安装一下。

#!/usr/bin/expect -f set password test spawn scp -r /home/wwwroot/default root@10.24.162.xxx:/home/wwwroot set timeout 300 expect "root@10.24.162.xxx's password:" set timeout 300 send "$password\r" set timeout 300 send "exit\r" expect eof

结果

修改之后单台服务器压测并发能达到12000-15000左右。CPU 几乎没有负载。

Responses