-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Use butil::ThreadLocal to store keytable #2645
Conversation
object_pool应该没法完全解决 #1449 的问题吧,从object_pool取出来的KeyTable有可能已经有data了,先调用bthread_setspecific函数,旧data还是会泄漏。 |
Lines 170 to 183 in b601c89
Lines 888 to 914 in b601c89
应该没法废弃bthread_keytable_pool_t ,因为Server已经用了bthread_keytable_pool_t了,并对外提供了与之相关的设置项。 改造bthread_keytable_pool_t,将free_keytables由全局改成TLS,这样mutex就可以废弃了。同时修改reserved_thread_local_data语义:每个TLS上预留的data数量。这样可行吗? |
如果使用TLS的话,当server结束调用Join时,通过bthread_keytable_pool_destroy方法需要删除所有线程内保存的TLS free_keytables才行,感觉也不是很方便? 我的理解,目前的实现是一个server会绑定一个全局的bthread_keytable_pool_t,在server的声明周期内,server和其生成的bthread使用同一个pool,在server结束时会销毁所有创建的KeyTable,通过bthread_keytable_pool_t内的链表;然后会从全局的KeyInfo中删除所有注册的Key。但是使用全局一个链表会存在锁的竞争问题,不知道理解的对不对。 |
改造bthread_keytable_pool_t ,其中引入一个类似Object_pool的成员,通过在成员内部使用tls变量来避免加互斥锁。然后对bthread_keytable_pool_t 中的锁的使用从互斥锁改为读写锁,来维护destroyed的值。在return_keytable内使用读锁,bthread_keytable_pool_init,bthread_keytable_pool_destroy时加写锁。这样就可以避免在sever未退出时多个线程return_keytable产生的锁的竞争。 |
嗯,我也是这样理解的。不过一般接口实现的瓶颈都是在业务逻辑,所以这个锁的影响应该不大。 |
之前考虑过在bthread_keytable_pool_t中使用ObjectPool,但是ObjectPool好像不能实现reserved_thread_local_data吧? destroyed应该可以用原子变量,就不用锁了吧。 |
用butil::ThreadLocal应该挺方便的吧。 |
使用butil::ThreadLocal的话,new的object只有当线程结束才会释放,而目前基于bthread_keytable_pool_t的实现是在server Join后即清理释放所有的table,从KeyInfo中移除注册的key信息。如果使用butil::ThreadLocal,可以在delete后,析构所有的keytable吗? |
|
butil::ThreadLocal析构时,会delete使用过butil::ThreadLocal的每个线程上的local data。应该可以满足需求吧。 |
ResourcePool也是单例哦。
嗯嗯,return_keytable和bthread_keytable_pool_destroy需要互斥,不能用原子变量。 无论是ObjectPool还是ResourcePool的实现方式,即使destroyed=1,也是要将KeyTable返回给ObjectPool或者ResourcePool的吧。 |
请问一下这块逻辑具体在哪里呢?我没有看到butil::ThreadLocal这个类的定义。是ThreadLocalPointer吗? |
Lines 144 to 154 in b601c89
|
d147ced
to
b339a7b
Compare
@chenBright hello,我根据讨论修改了实现,可以帮忙看一下么 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@wwbmmm 也看看这个PR |
g->current_task()->local_storage.keytable = old_kt; | ||
} | ||
} | ||
KeyTable* keytable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class 类型不建议直接把成员暴露成public,要么改成struct,要么封装成getter/setter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成了struct
delete kt; | ||
return; | ||
} | ||
kt->next = (KeyTable*)pool->free_keytables; | ||
pool->free_keytables = kt; | ||
auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
全局free_keytables里的kt一旦被借走就永远还不回去free_keytables了吗?这样keytables的复用率会降低吧,如果线程数很多,可能会占用更多的内存
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是不会返回给free_keytables了。free_keytables的大小是根据server.option的reserved_thread_local_data变量设置的,默认为0。
不过这里的线程指的应该只是一个bthread_keytable_pool_t pool所对应的server的brpc_worker threads,而不是普通的pthread。
所以相比使用单链表管理,如果brpc_worker thread是公平调度的话,内部的butil::ThreadLocal维护的链表长度应该是比使用一个单链表来说要短,但是性能会更好,因为同样存在回收机制,内存不会多太多。
对这个场景有点疑问,如果bthread生命周期很短,为什么还要使用bthread_local变量呢,用pthread local、局部变量或者通过函数参数传递不行吗 |
场景是:使用brpc框架通信,server下面接着一个数据库。使用bthread pool用于处理数据库的查询请求,数据库内部的实现使用了bthread级别的锁和tls来避免阻塞线程。数据库内部需要使用一些thread_local变量(bthread_local)来保证其一致性并减少重复创建。 |
LGTM |
请问下按照这样做了设计之后,有具体的性能测试报告么?能够直观的显示这种改造在特定场景下带来的性能提升 |
相同的负载下,修改前单链表维护的keytable,锁成为瓶颈。cpu被打满,sy时间占比高; |
这里有个疑问,为什么不直接把bthread_keytable_pool_t改成thread-local的呢?@MJY-HUST |
What problem does this PR solve?
Issue Number:

#2635
Problem Summary:
当brpc server 下处理的应用执行时间较短(bthread生命周期短),且使用了bthread_local变量时,由于keytable 由bthread_keytable_pool_t中的一个全局链表维护,borrow_keytable、return_keytable时内部加互斥锁,导致锁成为瓶颈。
基于此,重新设计了bthread_keytable_pool_t:
新的bthread_keytable_pool_t结构体中,使用butil::ThreadLocalbthread::KeyTableList* list 保存TLS的KeyTable list。同时保留原有的free_keytables,不改变reserved_thread_local_data的语义,调用bthread_keytable_pool_reserve会在全局链表中预分配keytable.原有的互斥锁改为读写锁。
What is changed and the side effects?
Changed:
Side effects:
Performance effects(性能影响):
Breaking backward compatibility(向后兼容性):
Check List: