dubbo vs mac-rpc 性能评测之异步调用

前言

笔者在此前发表的《dubbo vs mac-rpc 之性能评测 之 同步调用》一文中将dubbo和mac-rpc在同步调用方面的性能做了简单的对比和分析。本来不打算对异步调用这一块进行评测,因为双方在异步方法调用上差距有点大,并不太对称。但前面有很多同学和我讨论关于mac-rpc的线程模型,以及底层通讯的实现问题,笔者思来想去还是写一写比较好。欢迎大家继续和我讨论。

mac-rpc是我新近发布的作品,了解详情请访问:http://www.boarsoft.com

Dubbo的异步调用的实现

关于异步调用,Dubbo官方文档上这样写到“基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。”事实真的是这样吗?

笔者给被测试方法的dubbo:method标签的以下属性:

async="true" sent="false" return="true" timeout="6000"

为了观察服务提供者和服务消费者双方的资源消耗情况,我们需要将dubbo的线程池设置为cached,然后用300个线程并行的发起调用,每线程执行5000次异步调用,服务方法模拟延时10ms,结果如下:

服务消费者一方

服务提供者一方

对,没有看错,实际上服务消费者一方是额外启动了一个线程来发起异步处理。最终的处理时间会比同步方法调用要慢一些,CPU使用率也明显增加。服务提供者一方则不受影响。

由于Dubbo不支持在一个线程内发起同时发起多个异步调用,这意味着是在前一个异步调用未返回前,不允许再发起下一个。因此,很难象测试同步方法调用一样通过循环来发起压力测试。

mac-rpc的异步调用的实现

同样,为了能看出mac-rpc在异步调用时线程的使用情况,笔者将mac-rpc所用线程池大小设置为0~600,队列设置为SynchronousQueue,也用300个线程并行的发起调用,每线程执行5000次异步调用,服务方法模拟延时10ms,结果如下:

服务消费者一方

服务提供者一方

与dubbo不同,mac-rpc在异步调用时,服务消费者一方并不额外去启线程来执行。那么为什么服务消费者一方的线程数是400而不是300也不是600呢?这是因为mac-rpc在收RPC调用的返回时,启动了额外的线程去处理。这个设计使得mac-rpc在大量并行的执行低延时、低数据量的同步调用时更慢,但在处理高延时、大数据量的场景则更快。mac-rpc的下一版将考虑优化此处。

性能对比测试

测试方法

为了进行对比测试,并排除不必要的因素,我们让服务双方均使用600大小的固定线程池,配合600大小的LinkedBlockingQueue队列,并让服务方法模拟100ms的延时,且只返回10字符,再使用300线程并行地发起调用,每线程调用2000次,并将获得的Future对象保留起来,在程序的最后一并get,然后观察总的耗时和资源消耗情况。

测试结果

当使用固定600大小的线程池时,Dubbo的服务提供者一方出现Thread pool is EXHAUSTED警告,服务消费者一方出现 Client session timed out, have not heard from server in 37125ms 警告。意味着如何服务消费者一方迟迟不get结果,会造成服务提供者一方线程一直被占用直到超时。这应该算是dubbo的一个严重的设计缺陷。

当使用cached线程池时,Dubbo完全无法工作,服务提供者状态如下:

服务消费者状态如下:

在超时时间同为6秒的情况下,无论使用何种线程池,mac-rpc都能成功完成,使用固定600大小的线程池时,成绩最好,平均耗时为104206ms,比同步执行时快了一倍。

服务提供者状态如下:

注意:可以看出当服务消费方的RPC请求发送完成,服务提供方在一段时间后完成了所有请求,CPU降到0%,而服务消费方还在获取并处理服务方返回的响应。

服务消费者状态如下:

测试结论

mac-rpc在异步方法调用上完胜。无论从性能、抗压能力,还是稳定性上都更胜一筹。此外,除了基本的异步方法调用外,mac-rpc还支持异步通知,异步回调等多种异步形式,值得一试。

猜你喜欢

转载自my.oschina.net/u/162831/blog/1648768