京东热key探测框架本地压测数据记录,单机(8核)QPS约16万/s,可水平扩展

继上一次全链路压测时,热key框架由于Java低版本(1.8.0_131之前的1.8版本)获取docker内cpu核数有问题,实则获取的是宿主机的核数,造成线程数量过多,压测瞬间cpu达到100%,问题也记录在了另一篇https://blog.csdn.net/tianyaleixiaowu/article/details/106092060)。后来找到了问题原因,并成功修复了。然后还修改了一些其他的小问题,总体感觉框架比较稳定了。我就自己做了一些性能方面的压测,分别先后使用了4台、8台、16台、32台机器作为压力源,用死循环发送热key消息的方式,测试worker集群的性能,worker分别使用了8核、16核两种规格,数量都是2台,机器都是部署在docker内的。

首先说一下,我写的热key框架文章没有讲前因后果,会显得比较突兀。所以简单解释一下,worker端是一个Java程序,里面是一个netty server,用来接收来自于后端服务集群发来的字符串,然后对字符串进行归并,对相同的字符串数量进行累加,超过一定阈值的字符串,判定为热key,然后通过netty推送给这些后端服务集群。好比一个用户是个爬虫,他的userId=123456,他一直不停地访问后端集群,那么后端就会陆续把这个userId发往worker集群,worker对这个字符串的频率次数进行累加,譬如超过了设定的2秒10次就算爬虫,超过后worker集群就会把这个key推送给所有的后端服务,然后后端服务会记录到自己内存里,之后就可以对这个热key做操作了,譬如禁止他访问相关接口,做限流等等。

所以,这个worker也就是netty server它的性能就至关重要,后端集群每秒发过来或者几万、几十万、几百万个key信息,我就需要得到worker单机的QPS性能,然后根据实际的量来决定开多少个worker机器,worker是可以水平扩展的。

worker内部是使用netty单线程的bossGroup和cpu核数个workGroup,work接收到消息后自己不处理,全部写入到disruptor内,disruptor是200万的bufferSize,disruptor的消费者也是cpu核数个线程,每个线程只处理特定的key(即hash后取余分到消费者线程)。理论上消费的速度即是该应用的QPS。所以我通过反复调节线程数,缓存量等维度来测试性能表现。

之前老是有人抄我文章,到处乱发,还不注明出处。所以版权声明:本文为CSDN博主「天涯泪小武」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://tianyalei.blog.csdn.net/article/details/106327336

来看一下测试过程:

8核8G单机性能表现

worker端是固定2台机器,我用了2台8核8G的,压力机用了4台4核的,代码很简单就是死循环里netty发消息,让worker的netty server来接收并处理。netty server端我做了数量的统计,分别在接收到消息时变量totalReceiveCount数量加1,然后在数量处理完毕的地方totalDealCount加1。

很明显,接收的速率肯定是大于处理的速率的,接收到了没处理肯定是不算QPS的,当然处理的过程也很简单,就是内存计数累加,超过阈值就推送。

我每10秒打印一次接收的数量和处理过的数量,如图

 

从日志情况来看,每10秒大概处理了160万个key信息,接收量也差不多是160万,也就是基本上接收到的都被处理了,不存在明显的卡顿阻塞。这是单机的情况,两台机器情况是一致的。也就是两台每秒30多万QPS的样子。cpu占有率在70以上,但没有被打满。当前的cpu占用原则上已达到极限,故我们认为8核的单机QPS在16万。

16核单机性能表现

压力源不变,还是每10秒160万个key。

从日志上看,16核机器也是每10秒160万比较平稳,接收量和处理量保持一致。

cpu使用率明显是要比8核的小的多,大概在30%左右。说明在压力源保持不变的情况下,处理端的吞吐量是恒定的,核数多了,相应的只是cpu占用小一些。

16核单机调大线程数后性能表现

随后我把16核机器程序内处理消息的线程数调大一倍,从核数*1个线程,变成核数*2个线程,也就是变成了32个线程,日志如下,发现其实并没有什么变化,甚至有逐步下降的趋势。

原因也很明显,这是cpu密集型的应用,单核单线程处理的应该会更快,因为避免了cpu轮转切换,加大线程数并没有实际意义,如果线程过多,甚至导致性能下降。

我又恢复了16个线程,然后加大了disruptor的bufferSize,原来是200万,改成了1600万,同时将内存从16G加大到32G,大幅调大了JVM的新生代和老年代内存,同样是没什么鸟用,除了大幅增加了yong GC的耗时,其他的什么好处也没有。因为200万完全够用了,接收速率并没有比处理速率快很多,产生不了几百万的差距。

cpu倒是比内存小时占用更多了,有突破40%的趋势,主要还是因为gc时耗时大、耗cpu也高了。所以还是恢复了200万的bufferSize。

加大压力源后16核单机性能表现

之后我不断加大压力源,从4台到8台又到30台4核4G的。

可能是我压力源的死循环写的问题,导致压力源自身的发送量迟迟上不去,所以到worker接收端这边,也只是到了10秒200万的水平,看处理量,也是20万/s的样子。

worker端cpu的使用率也达到了50%。从16万/s的35%cpu到20万/s的50%。处理量和cpu的增长还算同步,但性价比其实不算高了。

在实际生产中,单机能到10万的QPS已经算是比较高的场景了,如果不够用,最好还是加个机器以分担峰值。

总结:该框架单机8核16万QPS,处于够用的状态,实际上netty server最高能处理多少,我也不清楚,没有相关的参考标的。如果能远远大于目前我的这个处理速率,可能是我程序写的不够完善。实际生产中如果量级不大,建议8c8g的机器再根据实际情况水平扩容。如果量级有突发特别密集的不确定因素存在,考虑上16核机器,毕竟16核在20万QPS时,cpu也才50%。上限远远大于8核的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章