记录之前公司微信投票项目性能优化过程及安全相关
项目:微信投票,依赖于微信授权
框架:yaf,php 7.0
规则:每人每天30票(未绑定手机的20票,可以无限送礼,新用户进入直接微信授权后添加用户即可获得20票)
已有用户数:50w+
原始方案:
LNMP php模板渲染
高并发页面:投票主页,选手详情页面(含投票活动信息,选手信息,票数,礼物等)
压力并发:单机+单库 (8pvc 16g) QPS<150
公司要求:QPS 3000+,投票时间一个月,不缺钱
优化方案:
一:架构修改
1:数据库读写分离,一主三从,阿里云RDS 实现
2:服务器负载均衡,阿里云 负载均衡实现
3:Redis缓存 服务器 2 (一个用于保存session 2pvc+4g,一个用于数据缓存 4pvc+16g)
4:图片等静态资源阿里云OSS
修改架构后(未做应用缓存),压力测试 8台服务器 + 数据库1主3从 ,发现QPS 上到1000左右就很难上去了,数据库还是扛不住,增加数据库性能 效果不明显;
二:服务优化
1:开启php opcache ,这个可以直接提高PHP应用端性能一倍以上
2:将模板拆分前后端分离,模板渲染异常消耗cpu,数据传输也大
工作量:
a: 拆分后前端基本重构,
b:后端因为之前框架微信授权都是直接进PHP 实现,换成前后端分离得重新实现授权流程
c:前后端接口实现
3:前端缓存投票活动跟选手基本信息(这2个基本不会变,缓存12H,这里只缓存选手基本信息,没有投票总数,也不做排行)
4:投票对外宣传页面为静态页面里面重定向到真正主页,目的是紧急情况可以主动替换主页,实现缓存清理
5:后端缓存投票信息跟选手信息,分为base_info 跟 live_info, base_info保存基本信息,正常情况一天一更,live_info 保存选手实时票数跟礼物值,投票或者送礼后实时同步 另后台定时任务 每隔5分钟会强制数据库跟缓存同步
6:后台缓存用户信息,主要缓存进入主页需要的信息,用户 openid,phone,day_count(当天投票数)等,如果缓存未找到数据则从库中查找(或者新增)后缓存,用户信息缓存是最重要的,因为这里处理不好会出现超投票的情况,投票总数必须在投票成功后实时更新
优化原则:尽量保证大部分用户访问主页不经过数据库查找,直接换成判断处理后返回,新用户或者特殊情况可以走库
数据预热:每天投票开始前,手动将有投票送礼的用户数据缓存到redis,防止开始时流量洪峰把msql搞垮了
修改后压测,发现QPS 到1200左右就上不去…服务器 跟数据库没有压力,监测发现Redis 服务器带宽打满,连接Redis 使用了外网ip 导致带宽爆了,换为内网ip 压测QPS 4000+,服务器 负载60% mysql 负载20%…模拟数据有部分新用户跟随机数据更新,估计缓存Redis 有压力;基本满足老板要求
接口安全相关
1:在nginx 层进行IP 限流,详情请看Nginx 限流详解
2:进入页面后必须先调用后端 auth 进行微信授权,授权成功后端会记录 session 跟一个 auth_time; 判断是否有微信授权基本可以阻挡掉80%攻击了,但也不保证有些人通过微信授权后获得session_id 后疯狂调用其他接口进行攻击
3:前端调用其他接口判断session 里的auth_time 是否过期,过期了就要求重试刷新界面,这就防止上面那种情况了
4:在投票跟送礼下单接口,下单后 把 auth_time 直接过期掉,防止机器并发投票,就是投票一次必须刷新页面后重新投,默认下单也会跳页面;
5:缓存异步记录pv ,uv,ip 等 发现异常ip 黑名单
相关问题
1:负载均衡选择ip hash 后 很多用户session依旧会丢失;
原因:应该是现在很多用户都是双卡或者wifi 跟卡一起用,很多手机支持热切换数据,可能导致访问的ip 瞬间发生变化,导致session丢失
2:链接数据库,或者缓存服务器能用内网的尽量用内网,高并发很容易把外网带宽搞爆
3:数据库主从后会有延时,添加用户后会有查询操作一定记得从主库查询,从库可能没有数据,导致重复添加用户
4:数据库要记得备份