incubator-pegasus icon indicating copy to clipboard operation
incubator-pegasus copied to clipboard

并发批量请求服务器,服务端处理都在1ms以内返回,但客户端等请求都返回到回调处理时总共经历了6~8ms。

Open mzss0 opened this issue 5 years ago • 11 comments

Bug Report

Please answer these questions before submitting your issue. Thanks!

  1. What did you do? If possible, provide a recipe for reproducing the error. 万兆网卡。空数据(1000~5000)async_multi_get,c++接口测试
  2. What did you expect to see? 期望在服务端请求时延(1ms以内)内返回,或者2倍左右
  3. What did you see instead? 总请求耗时5ms以上
  4. What version of Pegasus are you using? v1.12

mzss0 avatar May 07 '20 09:05 mzss0

服务端处理都在1ms以内返回

请问服务端1ms耗时是如何看出的?

客户端等请求都返回到回调处理时总共经历了6~8ms

你可以给一下服务端的总吞吐, 并实验看是否吞吐下降后, 延迟也会下降.

neverchanje avatar May 08 '20 05:05 neverchanje

服务端处理都在1ms以内返回

请问服务端1ms耗时是如何看出的?

从tcpdump抓包或者服务端记录都能看出来

客户端等请求都返回到回调处理时总共经历了6~8ms

这个计时是客户端程序从发起到接收所有时间

你可以给一下服务端的总吞吐, 并实验看是否吞吐下降后, 延迟也会下降. 单条批量测试都能看见,从总吞吐看是一致的

这边处理的是只读请求,数据库数据量不论大小都有这个现象。表设计是100分区,客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget。就能复现上述情况

mzss0 avatar May 16 '20 13:05 mzss0

"服务端记录" 是指的哪个记录?

"客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget"

刚开始客户端建立TCP连接需要时间, 偶尔的TCP预热也需要时间, 一个比较准确的benchmark还是参照我们在https://pegasus-kv.github.io/overview/benchmark的测试结果. 首先运行时间要足够长, 其次应该有明确一些的延迟数值, 我们后续也会提供更细粒度延迟的统计.

neverchanje avatar May 18 '20 03:05 neverchanje

@mzss0 非常感谢你的反馈,以帮助我们提升性能。

是否可以使用async_get来试试?看看服务端返回时间和客户端感知时间的差距是不是还是很大,以帮助我们定位是不是客户端的问题。

另外可以不开启并发,而是只串行发送,看看是不是还有相同问题。

qinzuoyan avatar May 18 '20 03:05 qinzuoyan

"服务端记录" 是指的哪个记录?

serverstat命令看到的服务端信息

"客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget"

这个预热我做了处理,处理后第一次很明显没有过长耗时,处理方法就是获取客户端以后随便请求了一个不存在的key

刚开始客户端建立TCP连接需要时间, 偶尔的TCP预热也需要时间, 一个比较准确的benchmark还是参照我们在https://pegasus-kv.github.io/overview/benchmark的测试结果. 首先运行时间要足够长, 其次应该有明确一些的延迟数值, 我们后续也会提供更细粒度延迟的统计.

benchmark的测试场景跟我们所用的不一样。一开始也是采用这种方式去测试的。后面我们单独做了压测和点测,然后有了上述问题。。

mzss0 avatar May 18 '20 09:05 mzss0

@mzss0 非常感谢你的反馈,以帮助我们提升性能。

是否可以使用async_get来试试?看看服务端返回时间和客户端感知时间的差距是不是还是很大,以帮助我们定位是不是客户端的问题。

这个我们定位处理过,也做过优化,客户端和服务端的map结构在mget里是极耗时的,我们尝试修改了服务端,让请求数据有序返回,即使有空的也在对应位置加了空数据,保证一一对应,然后mget采用vector。提升了这边场景下的性能。我这边的计时统计是在rrdbclient的回调里,可以很明显看到这个客户端处理多了些时间

另外可以不开启并发,而是只串行发送,看看是不是还有相同问题。

单发不会有这个问题,但是不符合这边使用场景。。

mzss0 avatar May 18 '20 09:05 mzss0

@mzss0 上面你的意思是map数据结构导致了性能下降?那修改后对性能有多大提升?

qinzuoyan avatar May 18 '20 09:05 qinzuoyan

@mzss0 上面你的意思是map数据结构导致了性能下降?那修改后对性能有多大提升?

是用vector替换set,map。这个跟测试场景有关系,可以抛开rpc调用单独测试mget前的key处理和回调里面的数据整合。这边测试key的数据量是5000,分区是256

a,用原pegasus的asyncmultiget接口,通过多个set存多个分区的sortkey和rrdbclient回调返回的整合 b,去掉set结构用两个vector处理sortkey和返回定位,vector的size可以在初始化的时候预分配

b的耗时是a的一半以内,量大的话用多线程可以压缩更多,这一点map和set都做不到。

分区的数量后面做了调整,经测试不同分区数在上述场景下的点测时延效果,随着分区数的增加,是有个先降后升的。

mzss0 avatar May 18 '20 10:05 mzss0

上面提到的问题这边查看代码和测试验证已经有了结论了,一是创建连接的时候阻塞了其他并行的读操作,二是异步mget从开始调用到最后调用rpc请求都是串行的。这边的预热没有创建连接,只是从meta拿了config配置

mzss0 avatar Jun 01 '20 01:06 mzss0

"一是创建连接的时候阻塞了其他并行的读操作"

你意思是C++客户端内部在连接建立的时候阻塞读? 如果是的话我们可以看一下具体实现.

二是异步mget从开始调用到最后调用rpc请求都是串行的

没理解这句话的意思.

这边的预热没有创建连接,只是从meta拿了config配置

是的, 我们C++客户端暂时没支持连接预热, 我们只在java客户端支持了: https://pegasus-kv.github.io/clients/java-client#%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9E%E6%8E%A5%E9%A2%84%E7%83%ADwarm-up

neverchanje avatar Jun 01 '20 04:06 neverchanje

"一是创建连接的时候阻塞了其他并行的读操作"

你意思是C++客户端内部在连接建立的时候阻塞读? 如果是的话我们可以看一下具体实现.

二是异步mget从开始调用到最后调用rpc请求都是串行的

没理解这句话的意思.

这边的预热没有创建连接,只是从meta拿了config配置

是的, 我们C++客户端暂时没支持连接预热, 我们只在java客户端支持了: https://pegasus-kv.github.io/clients/java-client#%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9E%E6%8E%A5%E9%A2%84%E7%83%ADwarm-up

1,rdsn网络那一块,network.cpp的send_message函数,有读写锁

2,这边的场景每次mget请求会触发多个分区的mget请求,这一部分请求只在发送rpc请求异步等待的时候是并行的,从收到请求到发送是串行。

其实我这边还有一个疑问,在运行测试的时候,定位到address这个类的创建会耗时,具体应该是编译器做了什么操作,因为这个类没有实现默认构造函数,也可能是编译优化做了什么。从观察来说,就是在calltask函数到调用dsnrpccall之前,不确定是哪里有阻塞,而且只在前面几个请求出现,并行情况下多了5ms左右

mzss0 avatar Jun 03 '20 02:06 mzss0