Conversation
| bool except_state = true; | ||
| // epoll tid should be stolen first. | ||
| for (auto &epoll_state : _epoll_tid_states[tag]) { | ||
| if (epoll_state.second.compare_exchange_strong( |
There was a problem hiding this comment.
bool except_state = true;是不是应该在这个循环里
There was a problem hiding this comment.
是的,之前因为考虑只有一个 tag,设置在外面了,我修改一下
|
能否在bthread这个层面上,创建协程的时候设置一个属性,使它具有更高的优先级呢?现在这里专门设置了epoll_XXX,感觉有点特化。 |
+1。
这样是不是更好呢? |
现在只有一个连接,epoll bthread调度不是很频繁。是不是可以起多一些client和epoll bthread再测一下呢? |
1 你说得对,是有点特化,这么改简单点 如果是带优先级的bthread 可能就得改调度了,涉及到任务抢占/饥饿问题,可能麻烦一点 2 你说的也对可能会堆积,但是epoll任务是比较少的 如果改了优先级,会存在你说的优先级高的任务太多导致其他任务饿死 |
|
@zhengJade 延时性能的提升主要是因为epoll bthread优先调度了吗? |
这样的特化,可能在一些其它用户哪里有些不适用,要尽量保持和原来的兼容性。
epoll任务的多少,是由客户端那边决定的,这个不太好预期。 |
|
@yanglimingcn 我觉得可以增加一个属性来表示高优先级,但是要说明一点,就是 epoll 的 任务被 steal 的前提肯定是有 worker 需要 steal from task_control,所以可证明 worker 自己的 queue 应该没有任务,证明他是空闲的,这个时候应该优先让其响应网络事件,这有两个好处
|
好的,我再测试一下多 client 的效果 |
@chenBright
|
@wanghenshui |
#ifndef BTHREAD_FAIR_WSQ 我看这块的代码是把任务的调度反转了,能达到先执行epoll的目的? |
能否分别测一下这两个优化各自提升多少性能呢? |
这里我应该没修改过吧,我是把 epoll 的 tid 单独提取出来了,优先 steal 这个 tid
我应该没有修改过这个,我是把 epoll 的 tid 提取出来了,然后优先 steal 这个,来达到优先执行 epoll 的目的 |
较少 signal 这个我单独优化过,基本没什么提升,然后分析了原因才发现是因为压力大的时候,Q 其实是不平均的,直接的一个原因就是 epoll 的 tid 有时候会很难被 steal 到,这导致所有的 worker 呈现出,要做完当前所有的任务才可以进行 epoll,在某一瞬间导致有些 worker 进入了 wait 状态,然后整体就看起来,worker 没有 wait 状态的时间很少很少,所以就是没啥作用,于是才想着更改 epoll 的优先级 |
|
最近新春,公司太忙了,没时间搞这个 PR (><),等我这边喘口气,改成优先队列,然后多客户端再测试一次 |
|
如果网络事件非常频繁的话,是不是可以直接让epoll thread不切走呢?比如把这里: https://github.com/apache/brpc/blob/master/src/brpc/socket.cpp#L2265 |
|
优化前后长尾延迟没看到明显的变化? |
6e0b330 to
7ca337d
Compare
如果不切走,那非 epoll worker 是不是只能通过 steal 的方式来执行任务了?,队列更不均匀 |
长尾是指? |
e5a0ab8 to
708725a
Compare
@chenBright 以下是 5w QPS,3 客户端,压了一段时间后 rt, p9999,readQPS 的表现 |
目前没法知道。 但是应该也会有类似的问题,bthread_start_backgruond出的bthread和epoll bthread也不一定能得到及时的调度。 |
这个还有希望合进去嘛 |
@wwbmmm @yanglimingcn ping |
| bool TaskControl::steal_task(bthread_t* tid, size_t* seed, size_t offset) { | ||
| auto tag = tls_task_group->tag(); | ||
|
|
||
| if (_priority_qs[tag].steal(tid)) { |
There was a problem hiding this comment.
所有线程都访问这个是否会造成全局竞争?
@wwbmmm
这里的 _priority_qs 我记得本身就是线程安全的
There was a problem hiding this comment.
不是说线程安全的问题,我的意思是这个可能影响性能。我不确定,因为实际场景有很多,可能在你的场景里这个性能不是问题,但是在某些场景里可能会有问题,比如event_dispatcher_num很大,有很多epoll thread的情况?
There was a problem hiding this comment.
同一个 tag 下的 worker 肯定会存在竞争的,这个应该算是预期之内,性能损失量级跟下文的 g->_rq.steal(tid) 相当,原来 steal 的竞争产生的损失约为 N * M(N 为 tag 数量,常数级,M 为 g->_rq.steal(tid) 单次时间),现在为 (N + 1) * M
There was a problem hiding this comment.
@zhengJade 我理解,原来的steal在遍历worker的时候起始点和步长不一样,遍历的worker会错开。但是现在变成了steal同一个,tag内的竞争变激烈了,那么这里的M(g->_rq.steal(tid) 单次时间)也会变大了。
|
LGTM |
|
LGTM
@zhengJade @chenBright 我问一下,如果把epoll变成bthread_start_urgent和按照优先级队列处理epoll,最终执行的逻辑上看有什么区别呢? |
@yanglimingcn ”把epoll变成bthread_start_urgent“指的是哪部分?现在epoll bthread处理都是bthread_start_urgent处理读事件的吧。 |
我大概理解了,如果用bthread_start_background处理读事件,epoll会一直占有一个worker,这个PR不会让epoll一直占用一个worker,但是也会让epoll线程优先调度。 |
|
@zhengJade Thank you for your contribution! |
@legionxiong 这里是多少 client 呢,还有,是否有其他配置变动呢,比如说配置了多少 worker |
是这样的,要让任务分在不同的 worker 而不能通过 steal 的方式 |
PR 有问题直接圈我来修,最近换工作有点忙,才来看 |
@zhengJade 可能是#3030 这个问题导致的。 |





What problem does this PR solve?
对 brpc 性能做了提升
Problem Summary:
目前的 brpc 网络事件存在两个问题
What is changed and the side effects?
epoll 线程不在 queue 中,独立出来
Side effects:
Performance effects(性能影响): 性能平均提升 20%-25%
Breaking backward compatibility(向后兼容性): 兼容
压测结果
优化前
优化后
1w

压测补充
@chenBright 这里补充了多客户端压测
多客户端压测,使用了 5 个客户端,各发 1w
优化前
5 个采集周期平均值
(370 + 401 + 406 + 392 + 365)/ 5 = 382.2 us
优化后
5 个采集周期平均值
(360 + 324 + 301 + 328 + 319)/ 5 = 326.4
(382.2 - 326.4) / 382.2 = 14.6%
大约有 14.6% 的一个提升
Check List: