当前位置: 首页 > news >正文

【brpc学习实践十一】session-local与thread-local应用与brpc抽象工厂模式实践

什么是session-local与thread-local

百度内的检索程序大量地使用了thread-local storage (缩写TLS),有些是为了缓存频繁访问的对象以避免反复创建,有些则是为了在全局函数间隐式地传递状态。你应当尽量避免后者,这样的函数难以测试,不设置thread-local变量甚至无法运行。session-local与thread-local是brpc解决thread-local问题的两种机制,实际上还有一种,可自行查阅官网文档。这两种机制其实就是提供了一个保存rpc请求过程中的用户关注数据的保存、处理接口。

session-local

session-local data与一次server端RPC绑定: 从进入service回调开始,到调用server端的done结束,不管该service是同步还是异步处理。 session-local data会尽量被重用,在server停止前不会被删除。

设置ServerOptions.session_local_data_factory后访问Controller.session_local_data()即可获得session-local数据。若没有设置,Controller.session_local_data()总是返回NULL。

若ServerOptions.reserved_session_local_data大于0,Server会在提供服务前就创建这么多个数据。

struct MySessionLocalData {MySessionLocalData() : x(123) {}int x;
};class EchoServiceImpl : public example::EchoService {
public:...void Echo(google::protobuf::RpcController* cntl_base,const example::EchoRequest* request,example::EchoResponse* response,google::protobuf::Closure* done) {...brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base);// Get the session-local data which is created by ServerOptions.session_local_data_factory// and reused between different RPC.MySessionLocalData* sd = static_cast<MySessionLocalData*>(cntl->session_local_data());if (sd == NULL) {cntl->SetFailed("Require ServerOptions.session_local_data_factory to be set with a correctly implemented instance");return;}...
struct ServerOptions {...// The factory to create/destroy data attached to each RPC session.// If this field is NULL, Controller::session_local_data() is always NULL.// NOT owned by Server and must be valid when Server is running.// Default: NULLconst DataFactory* session_local_data_factory;// Prepare so many session-local data before server starts, so that calls// to Controller::session_local_data() get data directly rather than// calling session_local_data_factory->Create() at first time. Useful when// Create() is slow, otherwise the RPC session may be blocked by the// creation of data and not served within timeout.// Default: 0size_t reserved_session_local_data;
};

session_local_data_factory的类型为DataFactory,我们需要实现其中的CreateData和DestroyData。
brpc的DataFactory源码:

class DataFactory {
public:virtual ~DataFactory() {}// Implement this method to create a piece of data.// Notice that this method is const.// Returns the data, NULL on error.virtual void* CreateData() const = 0;// Implement this method to destroy a piece of data that was created// by Create().// Notice that this method is const.virtual void DestroyData(void*) const = 0;
};

实际上只是实现了一个抽象工厂的基类,对于产品族、具体工厂类都没有定义,这些是由具体业务去实现的。
注意:CreateData和DestroyData会被多个线程同时调用,**必须线程安全。**通常我们会在继承DataFactory的相关操作中添加锁保障线程安全。后面会有例子讲到。

class MySessionLocalDataFactory : public brpc::DataFactory {
public:void* CreateData() const {return new MySessionLocalData;}  void DestroyData(void* d) const {delete static_cast<MySessionLocalData*>(d);}  
};MySessionLocalDataFactory g_session_local_data_factory;int main(int argc, char* argv[]) {...brpc::Server server;brpc::ServerOptions options;...options.session_local_data_factory = &g_session_local_data_factory;...

我们需要将具体产品类的对象指针传入DestroyData以便brpc能帮我们回收资源,这里的资源回收是无需我们人工干预的,brpc已经帮我们进行管理:
如下源码:
在server start的时候就会根据传入的tls参数来进行启动一个sever bthread,随后在server结束时我们传入的具体session local数据会被抽象DestroyData指针调用destroy掉。

 // Init _keytable_pool always. If the server was stopped before, the pool// should be destroyed in Join()._keytable_pool = new bthread_keytable_pool_t;if (bthread_keytable_pool_init(_keytable_pool) != 0) {LOG(ERROR) << "Fail to init _keytable_pool";delete _keytable_pool;_keytable_pool = NULL;return -1;}if (_options.thread_local_data_factory) {_tl_options.thread_local_data_factory = _options.thread_local_data_factory;if (bthread_key_create2(&_tl_options.<

相关文章:

  • Linux设置Nginx开机自启
  • 【Openstack Train安装】九、Nova安装
  • 【微服务】java 规则引擎使用详解
  • 《Effective C++》条款27
  • python 生成器的作用
  • sql手工注入漏洞测试(MYSQL)-墨者-url信息
  • express+mySql实现用户注册、登录和身份认证
  • WEB渗透—反序列化(九)
  • golang 集成logrus日志框架
  • 基于SpringBoot的旅游网站的设计与实现
  • Could not resolve all files for configuration ‘:app:androidJdkImage‘.
  • Go语言使用AES加密解密
  • 漏洞复现--致远 M3 反序列化 mobile_portal RCE
  • 原生GPT本地及云端部署方式保姆级教程
  • 嵌入式硬件基础知识——1
  • CODING 缺陷管理功能正式开始公测
  • golang中接口赋值与方法集
  • Promise面试题,控制异步流程
  • Spring Boot MyBatis配置多种数据库
  • springboot_database项目介绍
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 浏览器缓存机制分析
  • 批量截取pdf文件
  • 人脸识别最新开发经验demo
  • 跳前端坑前,先看看这个!!
  • 如何正确理解,内页权重高于首页?
  • ​iOS安全加固方法及实现
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • #AngularJS#$sce.trustAsResourceUrl
  • #预处理和函数的对比以及条件编译
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (02)vite环境变量配置
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET 表达式计算:Expression Evaluator
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .Net组件程序设计之线程、并发管理(一)
  • ::before和::after 常见的用法
  • @GlobalLock注解作用与原理解析
  • [] 与 [[]], -gt 与 > 的比较
  • [2023-年度总结]凡是过往,皆为序章
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [C#]获取指定文件夹下的所有文件名(递归)
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [CISCN2019 华北赛区 Day1 Web2]ikun
  • [daily][archlinux][game] 几个linux下还不错的游戏
  • [HDU3710]Battle over Cities
  • [HEOI2013]ALO
  • [IE9] IE9 Beta崩溃问题解决方案
  • [javaSE] 数据结构(二叉查找树-插入节点)
  • [Kubernetes]8. K8s使用Helm部署mysql集群(主从数据库集群)
  • [NOIP2011DAY1P1]铺地毯