從源碼分析 MGR 的新主選舉算法( 三 )

函數中的 PRIMARY_ELECTION_PATCH_CONSIDERATION 是 0x080017,即 MySQL 8.0.17 。
在 MySQL 8.0.17 中,Group Replication 引入了兼容性策略 。引入兼容性策略的初衷是為了避免集群中出現節點不兼容的情況 。
該函數首先會對 all_members_info 按照版本從小到大排序 。
接著會基于第一個節點的版本(最小版本)確定 lowest_version_end 。
MGR 用 lowest_version_end 標記最低版本的結束點 。只有 lowest_version_end 之前的節點才是候選節點 。
lowest_version_end 的取值邏輯如下:

  1. 如果最小版本大于等于 MySQL 8.0.17,則會將最小版本之后的第一個節點設置為 lowest_version_end 。
  2. 如果集群中既有 5.7,又有 8.0,則會將 8.0 的第一個節點設置為  lowest_version_end 。
  3. 如果最小版本小于  MySQL 8.0.17,且只有一個大版本(major_version),則會取 all_members_info->end() 。此時,所有節點都是候選節點 。
為了方便大家理解代碼的邏輯,函數注釋部分還列舉了四個案例 , 每個案例對應一個典型場景 。后面我們會具體分析下 。
sort_members_for_election最后,我們看看 sort_members_for_election 函數的實現邏輯 。
void sort_members_for_election(    std::vector<Group_member_info *> *all_members_info,    std::vector<Group_member_info *>::iterator lowest_version_end) {  Group_member_info *first_member = *(all_members_info->begin());  // 獲取第一個節點的版本,這個節點版本最低 。  Member_version lowest_version = first_member->get_member_version();  // 如果最小版本大于等于 MySQL 5.7.20,則根據節點的權重來排序 。權重越高,在 vector 中的位置越靠前 。  // 注意,這里只會對 [all_members_info->begin(), lowest_version_end) 這個區間內的元素進行排序,不包括 lowest_version_end 。  if (lowest_version >= PRIMARY_ELECTION_MEMBER_WEIGHT_VERSION)    std::sort(all_members_info->begin(), lowest_version_end,              Group_member_info::comparator_group_member_weight);  else   // 如果最小版本小于 MySQL 5.7.20,則根據節點的 server_uuid 來排序 。server_uuid 越小,在 vector 中的位置越靠前 。    std::sort(all_members_info->begin(), lowest_version_end,              Group_member_info::comparator_group_member_uuid);}函數中的 PRIMARY_ELECTION_MEMBER_WEIGHT_VERSION 是 0x050720 , 即 MySQL 5.7.20 。
如果最小節點的版本大于等于 MySQL 5.7.20,則會基于權重來排序 。權重越高,在 all_members_info 中的位置越靠前 。
如果最小節點的版本小于 MySQL 5.7.20 , 則會基于節點的 server_uuid 來排序 。server_uuid 越小,在 all_members_info 中的位置越靠前 。
注意 , std::sort 中的結束位置是 lowest_version_end,所以 lowest_version_end 這個節點不會參與排序 。
comparator_group_member_weight在基于權重進行排序時,如果兩個節點的權重一致 , 還會進一步比較這兩個節點的 server_uuid 。
這個邏輯是在 comparator_group_member_weight 中定義的 。
權重一致,節點的 server_uuid 越?。?在 all_members_info 中的位置越靠前 。
bool Group_member_info::comparator_group_member_weight(Group_member_info *m1,                                                       Group_member_info *m2) {  return m1->has_greater_weight(m2);}bool Group_member_info::has_greater_weight(Group_member_info *other) {  MUTEX_LOCK(lock, &update_lock);  if (member_weight > other->get_member_weight()) return true;  // 如果權重一致,會按照節點的 server_uuid 來排序 。  if (member_weight == other->get_member_weight())    return has_lower_uuid_internal(other);  return false;}案例分析基于上面代碼的邏輯,接下來我們分析下 sort_and_get_lowest_version_member_position 函數注釋部分列舉的四個案例:
案例 1:5.7.18, 5.7.18, 5.7.19, 5.7.20, 5.7.21, 8.0.21. 這幾個節點中,最小版本號是 5.7.18,小于 MySQL 8.0.17 。所以會比較各個節點的 major_version,因為最后一個節點(8.0.2)的 major_version 和第一個節點不一致,所以會將 8.0.2 作為 lowest_version_end 。此時,除了 8.0.2 , 其它都是候選節點 。

推薦閱讀