5000并发的qps是多少_高并发初体验记录-02

4f12e5bbe8020a77e11963b79f347805.png

前言

这半个多月完成了这次活动的业务代码开发和测试,至于性能调优对我而言近乎玄学。总结记录,以备参考。如有错误,欢迎指正。不过其实大佬不用浪费时间看这篇低质量的流水账了。

实测过后,一个月前老板给我说的10万qps,我就当他年老无知。别说10万了,就我们这几台服务器,只要还是用传统Java Web(Servlet)这套,5000也达不到。在BIO下,为每个请求分配一个线程去处理,就算tomcat有线程池和请求等待队列,还是得堵在那儿。另外,和第三方(活动赞助商)的技术人员沟通过后,了解到他们发奖接口的qps也就千八百,而我们的某个接口会去后台调用他们的接口,意思是不论怎么优化,活动整体是有瓶颈的。虽然想逃离去学一波netty和spring 5.0, 但先得把老师的活儿给应付了,尽力而为(崩)吧。

调优前,jmeter压测某简单接口,该接口不调用第三方接口,是外网压测(有网络延时),qps=1200,该值作为调优起跑线。(提一句,jmeter简单好用,支持系统函数生成随机字符串做参数等,可以导出jmx脚本。并且阿里云的PTS压测服务支持导入jmx脚本。这几天的收获之一就是学会用这个压测工具。)


  1. 解决带宽问题

阿里云性能监控的控制台是我的主要信息渠道。阿里云的带宽是按公网出流量算的,我发现p1服务器(nginx所在)的带宽在压测期间跑满了,立马把配置从5M升级到100M。效果立竿见影,qps到了1800,显然之前的5M带宽太小了。

2. 横向扩展服务器时,发现并解决nginx处瓶颈

在我查看nginx错误日志之前,我从没想过nginx会比tomcat先有瓶颈。但是当我加了一台业务服务器而毫无性能提升,并且有大量处于NON_ESTABLISHED状态的tcp连接时,我想到了nginx这个入口会不会有问题。

1024 worker_connections are not enough

这条nginx日志说明了问题所在,要么是你的nginx配置文件里配得太小,要么是你的服务器的操作系统允许进程打开的句柄数太小(一个socket要用一个句柄)。

dcae01d6d297e283508e5a4a8a001e02.png

把worker_connections 从1024直接改成了10240。压测时nginx不再报错,系统增加一台业务服务器后,性能有明显提升(qps: 1800 -> 2300

3. 仍然有大量TIME_WAIT状态的tcp连接

ee503142ad1fb186b7cc065992cea9fe.png

如上图所示,每个波峰代表服务器经历了一次压测。监控图显示压测期间产生大量tcp连接,但是90%以上是TIME_WAIT态,真正ESTABLISHED的tcp很少。这个问题可以去看看相关的博客(TCP连接状态详解及TIME_WAIT过多的解决方法 - 沧海一滴 - 博客园),简单来说,就是四次挥手结束tcp链接时,TIME_WAIT状态会持续两个MSL时间,可以修改系统参数以重用TIME_WAIT态的socket、加快其回收等。监控图里框起来的最后一个波峰明显合理很多,就是修改了/etc/sysctl.conf的参数的结果。

然而,这个优化对性能(qps)毫无提升。想来也是,我们的web服务器已经能建立足够多的tcp连接,可以发足够多的请求,但是业务服务器来不及处理,qps自然上不去。所以根源还是在于tomcat的性能瓶颈。

那么如何提升tomcat的请求处理能力呢?一方面,堆业务服务器的路子前面已经走通。另一方面,单机提升就涉及到tomcat参数调优。(至于JVM调优,我暂时相信默认值比自己拍脑瓜想的值更好)

4. tomcat参数调优

这里折腾了半天,并且毫无作用。以后有机会一定要深入了解下tomcat的工作机制,为什么这东西就“油盐不进”呢?

我们的业务服务器启动参数是从数据库里读取的,我查看了下之前的配置:

da3a2de5d55a89e38fa790d7ceb9ef3a.png

不看不知道,一看不得了。JVM那两个参数小点就算了,毕竟我们的业务纯IO,对象对内存的占用少。但TOMCAT这个参数也设得太小了吧(50/10/20)!线程池里最多跑50个请求,等待队列里最多缓存20个请求,加起来70个,太小太小了。

顿时感觉自己找到了一条通往高并发的阳关大道,立马参考网上的博客设置为1000/100/1000,然后高兴地开始压测。结果qps不增反跌(qps: 2300 -> 1900),nginx也接连报错,提示连接超时(Connection reset by peer)。

网上搜索了一番,大致原因如下。

acceptCount一般设置得和线程池大小相同,这个值是有讲究的。如果设得较小,可以保证接受的请求快速响应,但是超出的请求可能就直接被拒绝;而如果设得较大,可能就会出现大量的请求超时的情况,因为我们系统的处理能力是一定的。这好比一家饭店,它的人手有限(系统处理能力),如果预先摆放的桌位太多,就会装太多顾客,这会导致每桌顾客的上菜时间严重延长。

最后把这三个tomcat参数设置为100/10/40,不再折腾。(还是直接加机器靠谱)

5. 数据库优化和Redis

直接阿里云上买了一台redis server服务,按量计费。本平台的项目代码是(controller -> service -> dao)三层,我在service层新写了对应的redisHandler可以把数据往redis server里存,就不走dao去mysql了。这个实现个人觉得不好,只是图方便。因为redis和mysql其实都是数据访问,应该都往dao层里写(只是mysql对应的是用Mybatis生成的mapper)。

然后利用平台之前集成的Quatz定时任务框架,写一个定时任务把redis的数据批量插入mysql。这个方案的初衷是考虑到活动的数据最后要导出给甲方,且用redis能支持更高并发,异步批量插入数据库也能避免mysql的并发瓶颈。

最后代码实现是完成了,但我不准备用redis了。原因有二,一是对redis不熟,数据最后是要给甲方的,怕担风险;二是之前也说过,并发量还在tomcat那儿卡着呢,mysql几千的qps应该绰绰有余。

6. 分离nginx和tomcat

查看p1服务器,发现压测期间cpu占用高达90%,显然p1同时作为tomcat业务服务器和nginx网关,有点压力太大。现在有了新增的业务服务器,干脆让p1只跑nginx和一些不重的业务,把负责主要业务(platform、frontend)的tomcat在p1上停了。

这个措施带来非常可观的性能提升。这说明,只要公司不是特别穷,网关服务和业务服务还是独立部署吧。

7. 动静分离

没啥好说的,静态资源全放阿里云OSS上做cdn加速,这是最简单易行的优化措施。当然,这个提升在接口压测中是体现不出来的,但确实很重要 -- 服务器出网带宽才100M,必须节约。


后话

容灾靠重启,就这样吧。希望老板明年良心发现,早点放实习。纸上得来终觉浅,绝知此事要躬行。

附最后成果图,qps=4500(1 * nginx + 3 * 业务server,皆为2核16G)

6d25d325c3d41a8d15f4ceb80edaa6b4.png
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值