incubator-pegasus
incubator-pegasus copied to clipboard
并发批量请求服务器,服务端处理都在1ms以内返回,但客户端等请求都返回到回调处理时总共经历了6~8ms。
Bug Report
Please answer these questions before submitting your issue. Thanks!
- What did you do? If possible, provide a recipe for reproducing the error. 万兆网卡。空数据(1000~5000)async_multi_get,c++接口测试
- What did you expect to see? 期望在服务端请求时延(1ms以内)内返回,或者2倍左右
- What did you see instead? 总请求耗时5ms以上
- What version of Pegasus are you using? v1.12
服务端处理都在1ms以内返回
请问服务端1ms耗时是如何看出的?
客户端等请求都返回到回调处理时总共经历了6~8ms
你可以给一下服务端的总吞吐, 并实验看是否吞吐下降后, 延迟也会下降.
服务端处理都在1ms以内返回
请问服务端1ms耗时是如何看出的?
从tcpdump抓包或者服务端记录都能看出来
客户端等请求都返回到回调处理时总共经历了6~8ms
这个计时是客户端程序从发起到接收所有时间
你可以给一下服务端的总吞吐, 并实验看是否吞吐下降后, 延迟也会下降. 单条批量测试都能看见,从总吞吐看是一致的
这边处理的是只读请求,数据库数据量不论大小都有这个现象。表设计是100分区,客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget。就能复现上述情况
"服务端记录" 是指的哪个记录?
"客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget"
刚开始客户端建立TCP连接需要时间, 偶尔的TCP预热也需要时间, 一个比较准确的benchmark还是参照我们在https://pegasus-kv.github.io/overview/benchmark的测试结果. 首先运行时间要足够长, 其次应该有明确一些的延迟数值, 我们后续也会提供更细粒度延迟的统计.
@mzss0 非常感谢你的反馈,以帮助我们提升性能。
是否可以使用async_get来试试?看看服务端返回时间和客户端感知时间的差距是不是还是很大,以帮助我们定位是不是客户端的问题。
另外可以不开启并发,而是只串行发送,看看是不是还有相同问题。
"服务端记录" 是指的哪个记录?
serverstat命令看到的服务端信息
"客户端请求5000条空数据,数据随机分布所有分区,然后并行请求这100个mget"
这个预热我做了处理,处理后第一次很明显没有过长耗时,处理方法就是获取客户端以后随便请求了一个不存在的key
刚开始客户端建立TCP连接需要时间, 偶尔的TCP预热也需要时间, 一个比较准确的benchmark还是参照我们在https://pegasus-kv.github.io/overview/benchmark的测试结果. 首先运行时间要足够长, 其次应该有明确一些的延迟数值, 我们后续也会提供更细粒度延迟的统计.
benchmark的测试场景跟我们所用的不一样。一开始也是采用这种方式去测试的。后面我们单独做了压测和点测,然后有了上述问题。。
@mzss0 非常感谢你的反馈,以帮助我们提升性能。
是否可以使用async_get来试试?看看服务端返回时间和客户端感知时间的差距是不是还是很大,以帮助我们定位是不是客户端的问题。
这个我们定位处理过,也做过优化,客户端和服务端的map结构在mget里是极耗时的,我们尝试修改了服务端,让请求数据有序返回,即使有空的也在对应位置加了空数据,保证一一对应,然后mget采用vector。提升了这边场景下的性能。我这边的计时统计是在rrdbclient的回调里,可以很明显看到这个客户端处理多了些时间
另外可以不开启并发,而是只串行发送,看看是不是还有相同问题。
单发不会有这个问题,但是不符合这边使用场景。。
@mzss0 上面你的意思是map数据结构导致了性能下降?那修改后对性能有多大提升?
@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都做不到。
分区的数量后面做了调整,经测试不同分区数在上述场景下的点测时延效果,随着分区数的增加,是有个先降后升的。
上面提到的问题这边查看代码和测试验证已经有了结论了,一是创建连接的时候阻塞了其他并行的读操作,二是异步mget从开始调用到最后调用rpc请求都是串行的。这边的预热没有创建连接,只是从meta拿了config配置
"一是创建连接的时候阻塞了其他并行的读操作"
你意思是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
"一是创建连接的时候阻塞了其他并行的读操作"
你意思是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左右