Jingyuan

Results 20 comments of Jingyuan

> https://github.com/apache/brpc/blob/b601c89aec9042a1f509ddbdad478aa4e3f118fe/src/brpc/server.h#L170-L183 > > > https://github.com/apache/brpc/blob/b601c89aec9042a1f509ddbdad478aa4e3f118fe/src/brpc/server.cpp#L888-L914 > > 应该没法废弃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产生的锁的竞争。 不知道这样是否可行

> > 如果使用TLS的话,当server结束调用Join时,通过bthread_keytable_pool_destroy方法需要删除所有线程内保存的TLS free_keytables才行,感觉也不是很方便? > > 用butil::ThreadLocal应该挺方便的吧。 bthread_keytable_pool_init的时候,new一个butil::ThreadLocal。 bthread_keytable_pool_destroy的时候,delete。 使用butil::ThreadLocal的话,new的object只有当线程结束才会释放,而目前基于bthread_keytable_pool_t的实现是在server Join后即清理释放所有的table,从KeyInfo中移除注册的key信息。如果使用butil::ThreadLocal,可以在delete后,析构所有的keytable吗?

> > 改造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应该可以用原子变量,就不用锁了吧。 1. 应该也不能直接使用Object_pool,因为它是一个单例,不能做到sever间的隔离。 2. 我看ResourcePool获取对象的模式是如下图,那么reserve时初始化多个全局的block是否可行。 ![image](https://github.com/apache/brpc/assets/52315061/492c9446-b786-4e53-a078-0a7f0bafd039) 3. return_keytable时,加读锁的临界区是判断destroyed + 将对象返回给pool,感觉不能直接使用原子变量

> > 我的理解,目前的实现是一个server会绑定一个全局的bthread_keytable_pool_t,在server的声明周期内,server和其生成的bthread使用同一个pool,在server结束时会销毁所有创建的KeyTable,通过bthread_keytable_pool_t内的链表;然后会从全局的KeyInfo中删除所有注册的Key。但是使用全局一个链表会存在锁的竞争问题,不知道理解的对不对。 > > 嗯,我也是这样理解的。不过一般接口实现的瓶颈都是在业务逻辑,所以这个锁的影响应该不大。 我们这边的场景是使用brpc server下面接了个rocksdb,当数据全被cache住时,service端的处理时间可能很短,导致瓶颈体现在了锁的竞争上 ![image](https://github.com/apache/brpc/assets/52315061/53df9c22-a8b9-43f0-8d2b-c6782f6a638f)

> > > > 如果使用TLS的话,当server结束调用Join时,通过bthread_keytable_pool_destroy方法需要删除所有线程内保存的TLS free_keytables才行,感觉也不是很方便? > > > > > > > > > 用butil::ThreadLocal应该挺方便的吧。 bthread_keytable_pool_init的时候,new一个butil::ThreadLocal。 bthread_keytable_pool_destroy的时候,delete。 > > > > > > 使用butil::ThreadLocal的话,new的object只有当线程结束才会释放,而目前基于bthread_keytable_pool_t的实现是在server Join后即清理释放所有的table,从KeyInfo中移除注册的key信息。如果使用butil::ThreadLocal,可以在delete后,析构所有的keytable吗? > > butil::ThreadLocal析构时,会delete使用过butil::ThreadLocal的每个线程上的local data。应该可以满足需求吧。...

@chenBright hello,我根据讨论修改了实现,可以帮忙看一下么

> 对这个场景有点疑问,如果bthread生命周期很短,为什么还要使用bthread_local变量呢,用pthread local、局部变量或者通过函数参数传递不行吗 场景是:使用brpc框架通信,server下面接着一个数据库。使用bthread pool用于处理数据库的查询请求,数据库内部的实现使用了bthread级别的锁和tls来避免阻塞线程。数据库内部需要使用一些thread_local变量(bthread_local)来保证其一致性并减少重复创建。 并不是所有的条件下bthread的生命周期都会很短,但是在一些场景下,如果数据都在缓存中,那么一个bthread的生命周期就会很短,此时单链表结构的keytable pool管理模式就会出现瓶颈。

> 请问下按照这样做了设计之后,有具体的性能测试报告么?能够直观的显示这种改造在特定场景下带来的性能提升 修改前: ![image](https://github.com/apache/brpc/assets/52315061/a768eaf1-c245-4ea6-b618-b0f86bcaaf59) ![image](https://github.com/apache/brpc/assets/52315061/62cb1acf-db75-4649-a1ed-0761984d3015) ![image](https://github.com/apache/brpc/assets/52315061/880aa151-730e-462e-9031-1c9b3d3b6f50) 修改后: ![image](https://github.com/apache/brpc/assets/52315061/ff286c26-a807-48f6-a5e6-d2f39516e63e) ![image](https://github.com/apache/brpc/assets/52315061/fa75079c-b122-4d06-a461-f959bc3fa619) ![image](https://github.com/apache/brpc/assets/52315061/35cee657-7d7d-410e-9350-23fe7aec5b6b)

> 请问下按照这样做了设计之后,有具体的性能测试报告么?能够直观的显示这种改造在特定场景下带来的性能提升 相同的负载下,修改前单链表维护的keytable,锁成为瓶颈。cpu被打满,sy时间占比高; 修改后,解除了锁的瓶颈,cpu利用率降低,QPS提升了一倍。火焰图上和加锁/解锁操作对应的futex_wait\futex_wake耗时部分消失