从源码分析 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 , 其它都是候选节点 。

推荐阅读