项目原地址:https://mp.weixin.qq.com/s/RZEC97Ai9NmWuTySYlza2Q

AI百科2个月前发布 快创云
39 0

  这篇文章的主题是记录一次程序的性能优化过程,包括在优化过程中遇到的问题以及如何解决这些问题。目的是为读者提供一个优化的思路。需要注意的是,我的方法并非唯一,性能优化之路上遇到的问题往往有多种解决方案。

  首先,需要明确的是,脱离需求谈优化是无效的。因此,如果有人声称在特定机器上实现了百万并发,这很可能是一种误导。单纯的并发数是没有意义的。其次,在进行优化之前,必须设定一个明确的目标,即需要优化到什么程度。没有目标的优化是不可控的。最后,必须准确找出性能瓶颈所在,而不能盲目地进行一系列尝试。

  在我之前的工作中,我负责了一个单独模块的拆分工作。这个模块原本是集成在主站代码中的,但由于并发量过大,为了防止出现问题后影响主站服务,我决定将其拆分出来。拆分的要求是:压力测试QPS不能低于3万,数据库负载不能超过50%,服务器负载不能超过70%,单次请求时长不能超过70ms,错误率不能超过5%。

  环境配置如下:服务器为4核8G内存,运行CentOS7系统,使用SSD硬盘;数据库为Mysql5.7,最大连接数为800;缓存使用redis,容量为1G。这些环境都是购买自腾讯云的服务。压测工具为locust,通过腾讯的弹性伸缩实现分布式的压测。

  需求描述如下:用户进入首页后,从数据库中查询是否有合适的弹窗配置。如果没有,则继续等待下一次请求;如果有合适的配置,则返回给前端。这里开始有多个条件分支:如果用户点击了弹窗,则记录用户点击,并且在配置的时间内不再返回配置;如果用户未点击,则24小时后继续返回本次配置;如果用户点击了但没有后续配置了,则继续等待下一次请求。

  根据需求,我们明确了几个关键点:1、需要找出适合用户的弹窗配置;2、需要记录用户下一次返回配置的时间并存储到数据库中;3、需要记录用户对返回的配置执行了什么操作并存储到数据库中。

  我们可以看到,上述三个重点都存在数据库的操作,不仅有读库操作,还有写库操作。如果不加缓存的话,所有的请求都会压到数据库上,这会导致数据库连接数被占满,出现拒绝访问的错误。同时,由于sql执行过慢,请求无法及时返回。因此,我们首先要做的就是将写库操作剥离开来,提升每一次请求的响应速度,优化数据库连接。整个系统的架构图如下:

系统架构图
系统架构图

  我们将写库操作放到一个先进先出的消息队列中来做。为了减少复杂度,使用了redis的list来做这个消息队列。

  然后进行压测,结果如下:QPS在6000左右时502错误大幅上升至30%,服务器cpu在60%-70%之间来回跳动,数据库连接数被占满tcp连接数为6000左右。很明显,问题还是出在数据库上。经过排查sql语句后得知原因是找出适合用户的配置操作时每次请求都要读取数据库所导致的连接数被用完。因为我们的连接数只有800个,一旦请求过多就会导致数据库瓶颈。问题找到了我们继续优化更新的架构如下:

更新后的架构图
更新后的架构图

  我们将全部的配置都加载到缓存中只有在缓存中没有配置的时候才会去读取数据库。

  接下来我们再次压测结果如下:QPS压到2万左右的时候就上不去了服务器cpu在60%-80%之间跳动数据库连接数为300个左右每秒tpc连接数为1.5万左右。

  这个问题困扰了我比较久因为我们可以看到我们2万的QPS但是tcp连接数却并没有达到2万我猜测tcp连接数就是引发瓶颈的问题但由于什么原因导致的暂时无法确定。这时猜测既然是无法建立tcp连接是否有可能是服务器限制了socket连接数验证猜测我们在终端输入ulimit -n命令显示的结果为65535看到这里觉得socket连接数并不是限制我们的原因为了验证猜测将socket连接数调大为100001。再次进行压测结果如下:QPS压到2.2万左右的时候就上不去了服务器cpu在60%-80%之间跳动数据库连接数为300个左右每秒tpc连接数为1.7万左右。虽然有一点提升但并没有实质性的变化接下来的几天时间我发现都无法找到优化的方案那几天确实很难受找不出来优化的方案过了几天再次将问题梳理了一遍发现虽然socket连接数足够但是并没有全部被用上猜测每次请求过后tcp连接并没有立即被释放导致socket无法重用。经过查找资料找到了问题所在:tcp链接在经过四次握手结束连接后并不会立即释放而是处于timewait状态会等待一段时间以防止客户端后续的数据未被接收。好了问题找到了我们要接着优化首先想到的就是调整tcp链接结束后等待时间但是linux并没有提供这一内核参数的调整如果要改必须要自己重新编译内核幸好还有另一个参数net.ipv4.tcp_max_tw_buckets timewait 的数量默认是 180000我们调整为6000然后打开timewait快速回收和开启重用完整的参数优化如下:

  我们再次压测结果显示:QPS达到5万服务器cpu为70%数据库连接正常tcp连接正常响应时间平均为60ms错误率为0%。至此整个服务的开发、调优和压测工作结束。回顾这一次调优我得到了很多经验最重要的是深刻理解了web开发不是一个独立的个体而是网络、数据库、编程语言、操作系统等多门学科结合的工程实践这就要求web开发人员有牢固的基础知识否则出现了问题还不知道怎么分析查找。

© 版权声明

相关文章