Group Replication 是一种 Shared-Nothing 的架构,每个节点都会保留一份数据 。
虽然支持多点写入 , 但实际上系统的吞吐量是由处理能力最弱的那个节点决定的 。
如果各个节点的处理能力参差不齐,那处理能力慢的节点就会出现事务堆积 。
在事务堆积的时候,如果处理能力快的节点出现了故障,这个时候能否让处理能力慢的节点(存在事务堆积)接受业务流量呢?
- 如果不等待堆积事务应用完 , 直接接受业务流量 。
一方面会读到旧数据,另一方面也容易出现写冲突 。
为什么容易出现写冲突呢?因为基于旧数据进行的写操作,它的 snapshot_version 小于冲突检测数据库中对应记录的 snapshot_version , 这个时候,冲突检测会失败 。
- 如果等待堆积事务应用完才接受业务流量 , 又会影响数据库服务的可用性 。
在实现上,Group Replication 的流控模块会定期检查各个节点的事务堆积情况 , 如果超过一定值,则会触发流控 。
流控会基于上一周期各个节点的事务认证情况和事务应用情况,决定当前节点(注意是当前节点 , 不是其它节点)下个周期的写入配额 。
超过写入配额的事务操作会被阻塞,等到下个周期才能执行 。
接下来,我们通过源码分析下流控的实现原理 。
本文主要包括以下几部分:
- 流控触发的条件 。
- 配额的计算逻辑 。
- 基于案例定量分析配额的计算逻辑 。
- 配额作用的时机 。
- 流控的相关参数 。
当接受到其它节点的状态信息时,会调用 Flow_control_module::handle_stats_data 来处理 。
下面我们看看 Flow_control_module::handle_stats_data 函数的处理逻辑 。
int Flow_control_module::handle_stats_data(const uchar *data, size_t len, const std::string &member_id) { DBUG_TRACE; int error = 0; Pipeline_stats_member_message message(data, len); m_flow_control_module_info_lock->wrlock(); // m_info 是个字典,定义是 std::map<std::string, Pipeline_member_stats> // 其中,key 是节点的地址 , value 是节点的状态信息 。 Flow_control_module_info::iterator it = m_info.find(member_id); // 如果 member_id 对应节点的状态信息在 m_info 中不存在,则插入 。 if (it == m_info.end()) { Pipeline_member_stats stats; std::pair<Flow_control_module_info::iterator, bool> ret = m_info.insert( std::pair<std::string, Pipeline_member_stats>(member_id, stats)); error = !ret.second; it = ret.first; } // 更新节点的统计信息 it->second.update_member_stats(message, m_stamp); // 检查是否需要流控 if (it->second.is_flow_control_needed()) { ++m_holds_in_period;#ifndef NDEBUG it->second.debug(it->first.c_str(), m_quota_size.load(), m_quota_used.load());#endif } m_flow_control_module_info_lock->unlock(); return error;}
首先判断节点的状态信息是否在 m_info 中存在 。如果不存在,则插入 。接着通过 update_member_stats 更新节点的统计信息 。
更新后的统计信息包括以下两部分:
- 当前数据:如 m_transactions_waiting_certification(当前等待认证的事务数),m_transactions_waiting_apply(当前等待应用的事务数) 。
- 上一周期的增量数据:如 m_delta_transactions_certified(上一周期进行认证的事务数) 。
m_delta_transactions_certified 等于 m_transactions_certified (这一次的采集数据) - previous_transactions_certified (上一次的采集数据)推荐阅读
- RAID5 IO处理之replace代码详解
- Linux Block模块之IO合并代码解析
- 从0开始写一个简单的vite hmr 插件
- React魔法堂:echarts-for-react源码略读
- 惠普星13Air锐龙版怎么样_惠普星13Air锐龙版性能表现
- 我的世界如何去末影之地(我的世界如何从末影之地回家)
- 记一次 .NET 某企业OA后端服务 卡死分析
- 【C++】从零开始的CS:GO逆向分析3——写出一个透视
- ysoserial commonscollections6 分析
- 实例分析Scheduled Thread Pool Executor与Timer的区别