菜鸟笔记
提升您的技术认知

brpc 笔记

bthread(一) 前言bthread(二) 线程模型及bthreadbthread(三) bthread数据结构bthread(四) bthread用户接口和代码执行路径bthread(五) 无锁队列rq的代码实现bthread(六) 小结brpc的精华bthread源码剖析brpc介绍、编译与使用brpc源码解析(一)—— rpc服务添加以及服务器启动主要过程brpc源码解析(二)—— brpc收到请求的处理过程brpc源码解析(三)—— 请求其他服务器以及往socket写数据的机制brpc源码解析(四)—— Bthread机制brpc源码解析(五)—— 基础类resource pool详解brpc源码解析(六)—— 基础类socket详解brpc源码解析(七)—— worker基于ParkingLot的bthread调度brpc源码解析(八)—— 基础类EventDispatcher详解brpc源码解析(九)—— 基础类WorkStealingQueue详解brpc源码解析(十)—— 核心组件bvar详解(1)简介和整体架构brpc源码解析(十一)—— Reducer类和Adder类解析brpc源码解析(十二)—— 核心组件bvar详解 AgentGroup类详解brpc源码解析(十三)—— 核心组件bvar详解(4)combiner详解brpc源码解析(十四)—— 核心组件bvar详解 sampler详解brpc源码解析(十五)—— bthread栈创建和切换详解brpc源码解析(十六)—— 作为client的连接建立和处理详解brpc源码解析(十七)—— bthread上的类futex同步组件butex详解brpc源码解析(十八)—— MPSC队列ExecutionQueue详解brpc源码解析(十九)—— 双buffer数据结构DoublyBufferedData详解brpc源码解析(二十)—— 用于访问下游的Channel类详解

brpc源码解析(十一)—— Reducer类和Adder类解析

阅读 : 609

上一篇文章聊了下bvar的整体组织架构,本篇将从最基本的计数器Adder的使用出发,分析Reducer和Adder的源码来阐述下最基本也是最重要的bvar工作机制,后续再进一步深入分析相关基础组件和其他类型的bvar,我觉得这也是一个比较有效地阅读分析这种基础类库源码的方式。整个brpc源码解析系列其实也是这么一个组织结构,先从使用的部分切入,相对熟悉之后再进一步深入到各个具体的重要部分。

首先这里先贴一个上篇文章引用了的brpc官方文档里的例子:

bvar::Adder value;
value << 1 << 2 << 3 << -4;

暂时不考虑全局曝光,以上也是bvar最常见的使用方式,用类型作为模板参数定义一个bvar变量后,就可以在各个线程中使用运算符<<往里面追加值了。Adder继承自Reducer(用于利用二元运算符把多个值合并为一个值),因此我们先来分析下Reducer类,然后再看Reducer。

1. Reducer类

Reducer定义如下:

Reducer继承自Variable,Variable中主要是曝光相关的,这里先不过多讨论。Reducer是一个三个模板参数的模板类,分别是数据类型T;reduce操作符Op;Op的逆向操作符InvOp,默认是VoidOp,也就是没有逆向操作符。InvOp在定时采样的时候会用到,本篇文章暂不涉及,后面解析采样相关机制的时候再详细说明。注意这三个typedef,分别定义了combiner、agent和sampler的类型,和Reducer本身的模板参数强相关。

类变量如下:

两种sampler因为不是必须的,所以是指针,而combiner和Invop则是需要直接初始化的普通类变量,之所以只有invop是因为combiner里面会保存op,不需要重复保存。

构造函数如下:

将模板参数提供给给combiner和_inv_op初始化,sampler初始化为NULL,只有被window之类的追踪了才会去新建sampler,单纯的使用reducer不需要sampler。

看完了构造相关的再看下核心功能,根据bvar的用途,核心功能自然也就两个,往里写新值和读汇总值。

往里写值是通过重载的<<运算符实现的,这个重载函数里。首先是调用combiner的get_or_create_tls_agent函数拿到当前线程的agent,内部实现上就是tls的相关操作,如果还未分配则会新建agent,得到agent之后用操作符和值进行修改操作。

get_value比较简单,主要就是通过combiner聚合各个agent的值,不过要注意上面的check,这个check是说如果当前bvar已被window跟踪定时采样而且不存在invop,比如Maxer,是不能调用这个函数的,因为依赖tls的关系,对于这类没有invop的reducer,在定时采样(take_sample)的时候需要reset agent,调用这个函数取不到正确值。

2. Adder类

Adder直接继承自Reducer,定义如下:

很简洁,三个构造函数分别对应不全局曝光、不指定前缀曝光指定和前缀曝光的场景,分别会调用Reducer的构造函数。注意这里继承的是Reducer,也就是加减分别为OP和Invop,这两个OP定义如下:

3. 总结

这里主要介绍了下Reducer和Adder这个最常见的Reducer,以及bvar最基本的数据读写机制,可以看到主要就是通过运算符调用底层的agent和combiner进行数据的聚合等操作。后面将会进一步介绍底层依赖的agent、combiner实现、Window等时间窗口类型如何通过sampler采样等比较关键的机制。