-
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
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: