最近业务推送越来越频繁,导致瞬时压力非常大,虽然以前的代码确实很多地方像一坨 shit,实在无法下手从代码重构业务优化了,但是还是从其他方面做了一些调整来把性能提升了。
第一,升级了一下 MongoDB 从 2.4 到 3.2,换成了 wt 引擎以及 ssd 盘
线上 MongoDB 集群由于云厂商的原因最近总是挂,而且由于使用的 2.4 的版本,导致配置如果出现变动还需要重启实例,之前的资源最早用的是普通云盘,性能确实也一般,平时推送瞬时压力上来,单台 MongoDB 实例连接数能够飙到最高 5000,当然这里面肯定有慢查询的功劳,但是有些数据量其实很小,按照 MongoDB 的脾气,就是全部加载到内存中访问也不是个事,ssd 其实就可以充当一个低配版本的内存了。
第二,使用 openresty,启用了 nginx 缓存
虽然我已经懒得吐槽产品为啥非要在 feed 流的页面狂加状态,导致每个人的列表都不一样,缓存很难做,还是直到某一天推送压力实在太大,后端服务出现短时不可用,当然只是 feed 流业务,于是我们果断上了对部分单页上了 nginx 缓存,暂时也不理会各种状态的事情了,效果确实很好,部分压力大的接口基本不会穿透到后端 APP。
第三,优化了后端 APP 和 nginx 的连接配置
在巡查 nginx 日志发现,部分后端 APP 和 nginx 的连接频繁连接断开,造成没有复用的现象,查了一遍 nginx 发现 keepalive 该配的都配了,然后又怀疑是 gunicorn 的问题,最后发现 gunicorn 在 keep-alive 时默认等待时间是 2s 就会关闭连接,实在是太短了,手动调整了一下,后端 APP 和 nginx 的 time_wait 明显变少了,连接建立起来之后断的情况变少了。
第四,优化了部分 MySQL 的连接
Feed 流部分业务对某些 MySQL 连接的特别频繁,让负责业务的程序员看了看之前的代码,发现有些老的需求频繁使用 MySQL 连接,完全没有必要,部分数据可以做全局变量共享,却写了局部的,导致 MySQL 会受到大量请求,于是开始优化提升这些变量称为全局,做缓存,减少 MySQL 连接次数。
第五,升级 MySQL 硬件配置
MySQL 虽然实例不少,也做了主从结构,在某些耗时的 join 计算以及推送时,有时候还是很慢,于是对部分业务做了升级,把原来的 6G 内存调到了 12G,并且优化了 InnoDB_pool_buffer 的大小,确实解决了不少慢的查询和计算。
第六,改造升级了 rpc proxy
RPC proxy 是一个类似 nginx 的代理层,用 tornado 实现,主要做 rpc client 和 后端 server 的中转和负载均衡,单台请求最高能到 1 万 qps,但是不支持容错,导致部分后端节点挂了之后,还是会收到来自 proxy 的请求,于是做了升级改造,支持故障节点自动下线、自动释放故障节点连接池,待节点恢复之后,自动上线供 client 层调用。
升级改造用 tornado 提供的周期性检测特性,也就是在 ioloop 循环时不断检查定时器是否满足条件而去调用,由于 tornado 是个单线程,proxy 内部也没有开启过多线程,所有操作基本无锁,开销很小。
第七,替换 twemproxy 为 codis
twemproxy 最大的痛点就是无法平滑扩容,如果 redis 内从不足,需要水平扩容,就需要对原来 redis 中的数据进行手动迁移,比较麻烦,而且 twemproxy 单节点相比 redis 单节点来说性能不足,由于 twemproxy 是单进程的,单节点如果达到 1w qps 已经很卡了,为了解决 twemproxy 的性能问题,必须不断的加机器,或多开进程,然后不断的修改内网域名配置。
codis 扩容是半自动的,运维手动点点可以完成,而且 codis 的单机性能确实要好于 twemproxy。
第八,用 Go 做了一个内部用的发布系统
现在的团队发布用的 walle 和 fabric,用 fabric 写好远程部署脚本,然后再通过 walle 调用,walle 这个工具对于整个团队来说太透明了,出错不容易查看,不知道哪里出问题,必须要运维介入,而且部署日志不友好,于是用 Go 写了一个发布系统替换 walle。
新的部署系统是根据自身业务定制的,支持部署日志回传以及上传到第三方云平台,能够非常方便的查看部署日志,而且通过一个友好的 web 页面可以实时知道当前的部署进度,具体到任意一台主机。