從源碼分析 MGR 的流控機制( 三 )

代碼的邏輯看上去有點復雜 。
接下來 , 我們通過一個具體的示例看看 flow_control_step 函數的實現邏輯 。
基于案例定量分析測試集群有三個節點組成:127.0.0.1:33061,127.0.0.1:33071 和 127.0.0.1:33081 。
運行在多主模式下 。
使用 sysbench 對 127.0.0.1:33061 進行插入測試(oltp_insert) 。
為了更容易觸發流控,這里將 127.0.0.1:33061 節點的 group_replication_flow_control_applier_threshold 設置為了 10 。
以下是觸發流控時 127.0.0.1:33061 的日志信息 。
[Note] [MY-011726] [Repl] Plugin group_replication reported: 'Flow control - update member stats: 127.0.0.1:33061 stats certifier_queue 0, applier_queue 0 certified 7841 (177), applied 0 (0), local 7851 (177), quota 146 (156) mode=1'[Note] [MY-011726] [Repl] Plugin group_replication reported: 'Flow control - update member stats: 127.0.0.1:33071 stats certifier_queue 0, applier_queue 0 certified 7997 (186), applied 8000 (218), local 0 (0), quota 146 (156) mode=1'[Note] [MY-011726] [Repl] Plugin group_replication reported: 'Flow control - update member stats: 127.0.0.1:33081 stats certifier_queue 0, applier_queue 15 certified 7911 (177), applied 7897 (195), local 0 (0), quota 146 (156) mode=1'[Note] [MY-011727] [Repl] Plugin group_replication reported: 'Flow control: throttling to 149 commits per 1 sec, with 1 writing and 1 non-recovering members, min capacity 177, lim throttle 0'以 127.0.0.1:33081 的狀態數據為例,我們看看輸出中各項的具體含義:

  • certifier_queue 0:認證隊列的長度 。
  • applier_queue 15:應用隊列的長度 。
  • certified 7911 (177):7911 是已經認證的總事務數,177 是上一周期進行認證的事務數(m_delta_transactions_certified) 。
  • applied 7897 (195):7897 是已經應用的總事務數,195 是上一周期應用的事務數(m_delta_transactions_applied) 。
  • local 0 (0):本地事務數 。括號中的 0 是上一周期的本地事務數(m_delta_transactions_local) 。
  • quota 146 (156):146 是上一周期的 quota_size,156 是上一周期的 quota_used 。
  • mode=1:mode 等于 1 是開啟流控 。
因為 127.0.0.1:33081 中 applier_queue 的長度(15)超過 127.0.0.1:33061 中的 group_replication_flow_control_applier_threshold 的設置(10) , 所以會觸發流控 。
觸發流控后,會調用 flow_control_step 計算下一周期的 m_quota_size 。
1. 循環遍歷各節點的狀態信息 。集群的吞吐量(min_capacity)取各個節點 m_delta_transactions_certified 和 m_delta_transactions_applied 的最小值 。具體在本例中,min_capacity = min(177, 186, 218, 177, 195) = 177 。
2. min_capacity 不能太小,不能低于 lim_throttle 。im_throttle 的取值邏輯如下:
  • 初始值是 0.05 * min (group_replication_flow_control_applier_threshold, group_replication_flow_control_certifier_threshold) 。
    具體在本例中,min_capacity = 0.05 * min(10, 25000) = 0.5 。
  • 如果設置了 group_replication_flow_control_min_recovery_quota 且 num_non_recovering_members 為 0,則會將  group_replication_flow_control_min_recovery_quota 賦值給 min_capacity 。
    num_non_recovering_members 什么時候會為 0 呢?在新節點加入時,因為認證隊列中積壓的事務過多而觸發的流控 。
  • 如果設置了 group_replication_flow_control_min_quota,則會將 group_replication_flow_control_min_quota 賦值給 min_capacity 。
3. quota_size = min_capacity * 0.9 = 177 * 0.9 = 159 。這里的 0.9 是 1 - group_replication_flow_control_hold_percent /100 。之所以要預留部分配額,主要是為了處理積壓事務 。
4. quota_size 不能太大,不能超過 group_replication_flow_control_max_quota 。
5. 注意,這里計算的 quota_size 是集群的吞吐量,不是單個節點的吞吐量 。如果要計算當前節點的吞吐量,最簡單的辦法是將 quota_size / 有實際寫操作的節點數(num_writing_members) 。
怎么判斷一個節點是否進行了實際的寫操作呢?很簡單,上一周期有本地事務提交,即 m_delta_transactions_local > 0 。具體在本例中,只有一個寫節點,所以 , 當前節點的 quota_size 就等于集群的 quota_size , 即 159 。

推薦閱讀