我们原来的设计是基于LinkedBlockingQueue配送,生产和消费都用于锁定,生产是putLock,消费是takeLock。 如果置换为Disruptor,则生产时锁定消失,消费时使用了BlockingWaitStrategy战略,因此也存在锁定,但由于是单线程消耗,所以几乎没有锁定竞争的消耗。
测试环境如下所示。
型号名称英特尔至强CPU E3-1230 V2 @ 3.30GHz
CPU酷睿8
cache size15360 KB
操作系统windows764位
JDK1.8.60
Disruptor3.3.2
ringBufferSize33554432
producerTypeProducerType.MULTI
witstrategyblockingwaitstrategy
根据消息处理量进行比较:
已处理的消息数:32*1024*1024=33554432
与:相比需要时间
持续时间(ms )链接块队列描述器比较
15771420973%
25725347960.77%
35433322859.41%
45297280552.95%
55745247743.12%
612424242839.65%
qpslinkedblockingqueuedisruptor比较
158143187972067137%
258610369644850165%
3617604110394805168%
4633461111962364189%
5584063213546400232%
6547916913819783252%
分析:线程数较少时,性能提高不明显。 单线程的情况下,时间降低到原来的73%,QPS降低到原来的137%。 随着线程数的增加,性能提升幅度越来越大,如果生产者是6个线程,预计时间已经降低到原来的39.65%,QPS处理量已经达到252%,线程数越多,性能提升越大。
另外一方面,LinkedBlockingQueue在线程数=4时,随着线程数变多,多线程处理消息的正效果比锁定竞争产生的负效果大,因此性能逐渐提高,但超过5条时效果会变好线程数越多,性能越差,在各个方面都可能会输给Disruptor。
从CPU占用看:
LinkedblockedQueue压力测量时的CPU性能:
Disruptor压力测量时的CPU性能:
LinkedblockedQueue的CPU占有率在30%~35%上下变动,Disruptor的CPU占有率在25%~30%上下变动,CPU占有率下降5%左右。
线程CPU时间与:相比
分析:
第一组: linkedblockedqueue-produce-1和: linkedblockedqueue-produce-2为生产者,对应的linkedblockedqueue为消费者;
第二组:Disruptor--produce-1和:Disruptor-produce-2为生产者,对应的Disruptor-1为消费者;
显然,在处理相同的消息量33554432时,LBQ的时间达到了Disruptor的2.26倍左右。
最后讨论了消息缓冲区的预分配问题。 以下是网上精彩的描述: '避开GC。 写Java程序时,很多人随手就习惯了new的各种对象。 虽然Java的GC负责回收,但是系统压力大、频繁的new一定会导致更频繁的GC。 Disruptor避免此问题的策略是“预分配”。 创建RingBuffer实例时,必须为参数指定缓冲区元素类型的Factory。 创建实例时,RingBuffer首先将整个缓冲区填充到Factory生成的实例中。 然后,当生产者生产时,它将检索以前新的实例,而不是传统的做法(将一个实例按预期新建,然后添加到buffer )。 图像的一个示例是,如果缓冲区是一个有很多纸片的地方,而纸片上记录了信息,则以前每次进入缓冲区,系统都会准备纸片,写纸片放入缓冲区,消耗完毕后立即扔掉。 现在的做法是准备好所有的纸片,想放进去的时候只需要关掉原始信息写新的东西'
在压力测试期间,会即时生成大量消息(33554432 ),从而填满老一代人,不断进行全GC。 因此,在测试时,要尽量增大内存分配,以免全GC影响测试结果。 本来,生产环境就不需要那么大的消息缓存)当前生产环境的容量只是测试时的1/100。
总之,优化后,消息总线的处理性能至少提高一倍。
3358 blog.csdn.net/jiangguilong 2000/article/details/49493105