仅仅作为自己的学习笔记,不做其他用途。
一、恢复的主要阶段
实际上节点的加入会经历几个主要的流程
- 发起一个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线程处理,主要就是安装视图
- 对于现有节点而言,主要更新视图信息,将加入节点的状态更改为recovery
- 对于加入节点而言,也是先将自己的状态设置为recovery然后进行恢复。
- 加入节点恢复完成后,会发送online消息给各个节点,各个节点将节点状态状态
设置为online。
在加入的过程中视图版本会加1,由于view change event会封装在一个事务里面,因此
GTID也会加1,封装的过程主要处于Certification_handler::handle_event中对于view change event的处理。
二、加入阶段数据恢复的简图
这里我们主要看看加入节点的恢复流程,这里主要涉及到3个线程的协同工作,用图表示:
未命名文件.jpg本处小结:
- clone插件只有在GTID差值超过group_replication_clone_threshold参数设置或者恢复库需要的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(true, true, &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
网友评论