MySQL:MGR节点上线恢复简析



仅仅作为自己的学习笔记,不做其他用途。原文中有大图,参考https://www.jianshu.com/p/d27f46975453


一、恢复的主要阶段

实际上节点的加入会经历几个主要的流程

  • 发起一个Control_notification调用Gcs_xcom_control::retry_do_join连接到种子节点, 发送加入的请求给xcom线程,xom线程检测到有节点加入后,然后由xcom线程下发Global_view_notification给各个节点(包括加入节点)表示有节点申请加入。
  • 各个节点收到Global_view_notification的消息后,获取本节点的一些信息,比如本节点执行的gtid信息、视图更新后的节点信息等。完成后发送一个信息给xcom线程 (Cargo_type::CT_INTERNAL_STATE_EXCHANGE)
  • xcom线程下发Data_notification ,交由xcom engine线程处理,主要就是安装视图
  1. 对于现有节点而言,主要更新视图信息,将加入节点的状态更改为recovery
  2. 对于加入节点而言,也是先将自己的状态设置为recovery然后进行恢复。
  • 加入节点恢复完成后,会发送online消息给各个节点,各个节点将节点状态状态 设置为online。

在加入的过程中视图版本会加1,由于view change event会封装在一个事务里面,因此 GTID也会加1,封装的过程主要处于Certification_handler::handle_event中对于view change event的处理。

二、加入阶段数据恢复的简图

这里我们主要看看加入节点的恢复流程,这里主要涉及到3个线程的协同工作,用图表示:

MySQL:MGR节点上线恢复简析
恢复简图.jpg

本处小结:

  • 很显然由于group_replication_clone_threshold参数默认巨大,因此很难选择clone插件,除非GTID为空。
  • 节点处于recovery状态是比较早的,如果其中流程出错,看到的视图信息依旧是recovery,比如选择donor节点恢复出现问题,这是常见的。
  • 节点上线依赖参数group_replication_recovery_complete_at的设置,默认设置为TRANSACTIONS_APPLIED,如果有大量的事务应用,那么节点上线可能推迟,因此加入节点选择低峰期进行。
  • incoming队列的缓存的是否如果过多,可能出现问题。因此加入节点选择低峰期。

三、代码部分笔记


Gcs_xcom_control::process_control_message
  视图版本+1
  ->Gcs_xcom_control::install_view
    根据新的节点信息建立新的视图
   ->Plugin_gcs_events_handler::on_view_changed
    ->Plugin_gcs_events_handler::handle_joining_members
     -> is_joining == ture
       先学习这个分支
       ->状态在恢复当中 MEMBER_IN_RECOVERY
       update_member_status(
        new_view.get_joined_members(), Group_member_info::MEMBER_IN_RECOVERY,
        Group_member_info::MEMBER_OFFLINE, Group_member_info::MEMBER_END);
       
       ->设置super read only  如果设置出错
       enable_server_read_mode(PSESSION_DEDICATED_THREAD)
       ->如果是多主需要考虑自增是否符合要求
       new_view.get_members().size() > auto_increment_increment
        挂起applier通道----->applier通道处于挂起状态
       ->根据下发的view id进行View_change_packet的构建,并且推送给
         applier通道的pipeline 进行处理 Applier_module.add_view_change_packet 
         View_change_packet *view_change_packet = new View_change_packet(view_id);
         applier_module->add_view_change_packet(view_change_packet);
       ->进行恢复方式的选择
        ->是否使用clone
          recovery_strategy = remote_clone_handler->check_clone_preconditions();
          ->这里根据参数来判定,到底是使用clone还是recovery的方式
       ->如果是clone则新建clone线程
         remote_clone_handler->clone_server 先不考虑clone
       ->如果是recovery则新建recovery线程
         recovery_module->start_recovery(new_view.get_group_id().get_group_id(),new_view.get_view_id().get_representation())
         启动恢复线程,加入的是group id和view id
         见下面的流程
         

进行恢复
Recovery_module::start_recovery
   ->初始化group_name和view_id
     this->group_name = group_name;
     recovery_state_transfer.initialize(rec_view_id); 
   ->启动新线程
     ->launch_handler_thread
      ->handler->recovery_thread_handle()
      实际调用为Recovery_module::recovery_thread_handle
        ->step0
          
        ->step1
          applier_module->wait_for_applier_complete_suspension(&recovery_aborted);
          等待applier线程的SQL线程应用完现有的relay log的事务,等待是通过收到的GTID
          为最终等待的GTID,完成后进入下一步
        ->step2
          如果只有一个节点,直接进入上线流程,跳过步骤3
        ->step3
          进行recovery流程
          recovery_state_transfer.state_transfer(stage_handler); 
          ->establish_donor_connection
            建立donor的连接
           ->选择donor节点?这里看的和前期看的不同,需要确认
             这里暴露了一些构建的方法,比如必须是online。
           ->尝试连接donor节点,并且进行不同的报错
             initialize_donor_connection
           ->进行恢复
             start_recovery_donor_threads
             这里带入了view_id,也就是进行恢复结束的位置为view change event的来到
             ->donor_connection_interface.start_threads(truetrue, &view_id, true);
        ->step4     
           ->applier_module->awake_applier_module();
             唤醒apllier通道继续应用缓存的event,这里前面挂起了applier通道,只是event和消息
             缓存到了incoming队列。!!!!
           ->Recovery_module::wait_for_applier_module_recovery
             等待上线,开启循环
             while (!recovery_aborted && applier_monitoring)
             ->获取incoming 队列大小
               applier_module->get_message_queue_size();
             ->获取每秒恢复应用事务的数量
             ->如果参数设置为 cerify,则上线条件为
               ->恢复期间认证为0则继续进行处理
                 根据需要认证的事务总数和已经认证的事务数量进行统计,其中已经认证的事务数量在Certifier::certify的末尾进行增加。
             ->如果参数设置为applier,则上线条件为
               ->1.如果剩余需要过pipeline流程的事务,数量少于每秒恢复的事务数量,说明已经很少了,下一秒即可执行完成
               ->2.如果incoming队列为0 、每秒恢复的事务数量为0 、applier的SQL线程处于空闲状态了
                 如果满足上面其中一个1个条件,进入等待,等待为接受的GTID全部应用完成。
             ->如果不满足上面的条件则进行循环等待
               否则进行睡眠 incoming队列大小有关,但最大睡眠 为 100*5000 微秒
               
         ->step5 
          ->发送节点恢复完成的消息
           notify_group_recovery_end();
           这个消息是发给xcom的,因此是全员消息,应该是通知各个节点更改本节点状态为online
         ->step7
           终止recovery线程
             
             
            
             
applier_module->add_view_change_packet(view_change_packet);       
   xcom engine推送view change packet给 applier进行pipeline处理
    
Applier_module::applier_thread_handle
   -> packet_application_error = apply_view_change_packet((View_change_packet *)packet, fde_evt, cont);
    -> Applier_module::apply_view_change_packet
      -> Applier_module::inject_event_into_pipeline
        ->Event_cataloger::handle_event
          ->Event_handler::next
            ->Certification_handler::handle_event
              -> Certification_handler::extract_certification_info
                ->Certification_handler::log_view_change_event_in_order
                  ->Certification_handler::inject_transactional_events
                     生成一个gtid事务,包含事务的所有event,并且会分配gtid
                     ->Event_handler::next

参考:https://zhuanlan.zhihu.com/p/40627399

原文始发于微信公众号(MySQL学习):MySQL:MGR节点上线恢复简析

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/20242.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!