-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bthread task group add tag #2358
Conversation
这个是划分线程池的一个新的想法,我觉得这样实现对性能损失最少,现在提上来的代码是一个DEMO,总结一下: |
1ff809d
to
9998367
Compare
进一步,是不是可以像flare一样支持NUMA架构? |
|
d65c234
to
c70890f
Compare
ad2fc96
to
0fad86c
Compare
@wwbmmm 再review评估一下吧,看起来有需求的用户还挺多的。 |
坐等合入 |
@justmao945 @yanglimingcn @wwbmmm 我请教个小问题,大机型下,如果划分容器时直接绑定numa,这样就没有 remote access 了。在软件层面实现 numa aware 似乎只能逼近这个状态。所以为什么不直接用容器绑定numa?是因为内存的限制吗?还是因为有些场景不能接受使用容器,必须要用物理整机? |
c8616de
to
8dd7426
Compare
的确有些场景不能或者不方便使用容器,我所接触的,比如,一些使用了dpdk、spdk、rdma等等这些对性能要求比较极致的应用,都绕过了内核,相当于自己直接管理硬件了。 |
大内存应用 😢 |
8dd7426
to
4963aa3
Compare
@yanglimingcn 大佬请教个问题,我在你代码基础上修改了一下,一个server内部分service,然后每个service绑定一个bthread group tag,收到消息后根据tag进行分发。现在有一个问题,发现bthread_count监控数值不对,比如3个tag,总和是对的,但是有些group tag不对,看起来应该是task原来在group1上运行,但是退出是跑到group2上:
我的处理是在
tag是service注册时打上的。 |
你这个func_cp里面执行什么内容了呢,如果执行done->Run可能会有tag切换吧,因为你这么改的话,epoll_wait这个线程只能属于tag0吧,所以它的执行上下文都是tag0的。 |
done我感觉应该没问题的,是跑在对应tag的bthread里面,这个func_cp就是调用服务端的代码了。我合一下 #2476 这个PR再试试 |
@yanglimingcn 我知道问题所在了,的确是done的调用问题,我们用了另外一个braft的库,里面调用done是塞入到bthread::ExecutionQueue里面,这块代码没有改导致的。 |
请问这个PR的改动,如果使用了bthread::ExecutionQueue,ExecutionQueue里面的任务如何区分按照哪个tag去调度的呢? 还是整个ExecutionQueue对应于一个tag呢? |
最好还是一个tag启动一个execq比较合适 |
启动ExecutionQueue的时候,在attr里面指定上tag,就是整个ExecutionQueue都会在这个tag所在的线程池里执行了是么? |
1、execq会启动协程,这个协程设置好attribute的tag就可以了 |
感觉ExecutionQueue这个用起来还是有点问题,比如in_place执行的场景,task是在当前bthread执行的,就有可与初始化execq时指定的attr的tag不一致,如果task里面用到了bthread_mutex,就可能存在跨线程池唤醒的问题。 在我们的项目里面还有一个场景,感觉也有可能有问题,具体如下: 由于对外服务和braft使用了不同的tag,braft的on_apply调用是在execq中执行,按这个PR前面的讨论,会指定attr的tag为braft使用的tag,那么on_apply执行所使用的bthread就会是braft的tag,在on_apply中调用bthread_cond_signal,就会发生跨线程池使用bthread同步原语的问题了。 如果是这种场景,根据前面的讨论,应该是不适合让对外服务和braft服务使用不同的tag来调度了。不知道这样的理解是否正确? |
划分线程池的目的是为了隔离,感觉你对外服务和braft已经在上层通过execq做了隔离,是不是就没必要再使用这个功能了呢? |
braft目前用起来有一个有点棘手的问题,每个raft group都会开启4个execq,包括fsm caller、log manager、node apply、raft meta。当raft group数量比较多,或者fsm caller中有长耗时操作,或者fsm caller的调用内有pthread阻塞,braft实际上就会把brpc的所有线程用满,导致整个进程都无法处理新的message,导致braft本身的心跳也会超时。 如前文所述,对外服务的业务逻辑涉及到写braft状态机,并等待fsm caller执行完成后的callback再返回response给调用方。因此就会存在对外服务的线程池与braft的execq之间需要使用bthread同步原语。除了这种情况之外,服务本身还有一些业务逻辑的处理也涉及到提交raft状态机等待状态写入成功后才能继续执行的逻辑,也会涉及到跨线程池同步。 表达能力比较差,可能描述得不好:)。
这个地方比较难处理的点是braft的逻辑几乎都是通过execq来执行的,当execq的数量变大之后,实际上一个execq就相当于一个并发,可以跑满一个线程。execq数量多了之后,线程数就不够用了,这个问题是最早希望使用tag调度来限制braft使用的资源的一个主要原因。但是使用了tag调度之后,跨线程池使用bthread原语又会有问题,就有点不好处理。 我们现在通过一些方法已经基本实现了控制braft的并发度了,结合tag调度这个feature,应该能扩展一些新的方法来做这个事情。 技术上bthread原语跨线程池的使用,以后是否有办法支持呢? |
技术上是能实现的,但是做起来也有些复杂,同步的代码确实更好一些,否则execq里面就得调用callback了吧? |
确实还是有同步代码的需求。有些场景如果用callback,就会使callback里的逻辑很重,虽然技术上是可以的,但是代码看起来就很难看了。 |
ok,这块后续可以支持。 |
@yanglimingcn 我有几个疑问。比如我有一个server,tag是tag1。
|
是的 |
|
What problem does this PR solve?
Issue Number:
Problem Summary:
What is changed and the side effects?
Changed:
Side effects:
Performance effects(性能影响):
Breaking backward compatibility(向后兼容性):
Check List: