searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Ceph代码走读——PG Peering

2023-09-01 01:34:28
135
0

1、 PG Peering的触发入口

 

需要执行peering的PG,最终需要入队:

|- OSD:: enqueue_peering_evt(

      pgid,

      PGPeeringEventRef(

        std::make_shared<PGPeeringEvent>(

          osdmap->get_epoch(),

          osdmap->get_epoch(),

          NullEvt())));

 

2、 PG Peering执行入口

|-void OSD::dequeue_peering_evt

|-advance_pg(curmap->get_epoch(), pg, handle, rctx)    // 如果PG的MAP 大于等于 shard 的MAP,触发peering; 检查pg是否需要执行OSDMap更新

    \-PG::do_peering_event

        \-PeeringState::handle_event()

        |-machine.process_event()    // 向PG 状态机投递事件。NullEvt()事件等。触发PG peering的执行

 

3、 PG Peering状态机执行

1、状态机转换为start状态

|-Initial状态

     \-boost::statechart::transition< Initialize, Reset >,    // 收到Initialize事件,状态机转换为Reset状态

|-Started状态,自动转换为Start状态

\-PeeringState::Reset::react(const ActMap&)    //收到ActMap事件

 

|-transit< Started >()    // 转换为Started/start状态

 

2、状态机按照PG角色(主、从)触发执行

|-Start状态执行

|-PeeringState::Start::Start()

    if (ps->is_primary()) {

        post_event(MakePrimary());    //主进入Primary, Started, Peering 状态,执行PeeringState::Peering::Peering

    } else { //is_stray

        post_event(MakeStray());    // 从进入 Stray, Started 状态, 等待主更新

    }

3、 主开始peering。

|-PeeringState::Peering::Peering(my_context ctx)

    ps->state_set(PG_STATE_PEERING);    // 设置PG外部状态为PG_STATE_PEERING,标识开始peering

 

4、  PG 主Peering,第一步:GetInfo

主开始peering,peering 第一步,执行GetInfo,获取PG副本的pg info信息(主要是pg的元数据,包含版本信息等)

4.1  向副本发送GetInfo 消息

|-PeeringState::GetInfo::GetInfo

    ps->check_past_interval_bounds();    //检查info,.history中记录的Pg peering信息是否正确。及历史版本是否与info一致

|-PeeringState::log_weirdness()    // 检查pg_log 与pg info版本的一致性

|-PastIntervals::PriorSet PeeringState::build_prior()    // 获取PG所有版本的在当前OSDMap中为存活状态的osd,并判定PG是否为DOWN。

        \-PastIntervals::PriorSet::PriorSet()

            \- std::set<pg_shard_t> all_probe = past_intervals.get_all_probe(ec_pool);    // 获取PG所有版本的osd

                |- pi_compact_rep::get_all_participants

            |- 判定PG 所有版本的osd (all_probe)是否处于 down状态,用osdmap 中记录的osd状态判定。

            |- past_intervals.iterate_mayberw_back_to()    // 检查PG版本大于l ast_epoch_started的interval(PG集合),其在现在的OSDMap中 ,对应的osd是否是down状态,如果在此间隔期PG不可修复,且有down 的,标识PG down、pg_down = true;

    \- PeeringState::GetInfo::get_infos()    // 对prior_set中probe成员(在当前osdmap中,PG所有版本为存活状态的osd),获取pg_info(pg的版本信息))

        |-PeeringState::PeeringMachine::send_query

4.2  GetInfo 返回值(PG主收到副本发送的PG info 版本信息)

|-boost::statechart::result PeeringState::GetInfo::react(const MNotifyRec& infoevt)

\- PeeringState::proc_replica_info()

        |-update_history(oinfo.history);    // 用副本pg_info_t 中,history内容,更新本地pginfo的history。

|-if (!is_up(from) && !is_acting(from))    // 如果收到的副本成员,即不是acting成员,说明是PG老旧版本的成员。当PG当前数据已经修复完成,向该成员发送删除PG请求。

purge_strays();    // 向副本发送删除PG请求。

 

5、 PG 主Peering,第二步:GetLog

    peering 第二步,执行GetLog,主要流程为:用第一步获取到的副本的pg info信息, 选举出一个权威副本(拥有最高版本的PG),及能够上线的副本(与权威副本日志有交集),获取权威副本的pg log信息。并将主的pg log与权威副本合并(对齐)。

5.1  选举权威副本,及上线副本,向权威副本发送GetLog 消息

|-PeeringState::GetLog::GetLog(my_context ctx)

\-PeeringState::choose_acting  // 选出权威info , 并找出与权威info 有交集的副本acting_recovery_backfill(recovery修复),及与权威没有交集的up 副本backfill_targets,用于后续修复(backfill修复)。auth_log_shard为拥有权威info 的OSD

|-map<pg_shard_t, pg_info_t>::const_iterator auth_log_shard = find_best_info()    //比较PG副本返回的PG info 信息, 选出一个:last_epoch_started最大,且last_update最大中的日志最长的log_tail

        |-PeeringState::calc_replicated_acting()    // 过滤出与权威info 有交集的成员。过滤顺序为:先过滤up成员,如果过滤出来总数量不足副本数,再过滤acting成员,如果过滤出来总数量不足副本数,再过滤其他获取到info的副本。

|-PeeringState::recoverable    // 判定PG是否可修复, 即,与权威info 有交集的OSD数量,是否达到存储池要求的副本数量,

    |-如果权威就是主本身,Getlog完成。

    |-context<PeeringMachine>().send_query()    // 主向权威发送pg_query_t::LOG消息, 获取权威的日志到本地。要求从request_log_from版本开始。

 

5.2 GetLog 返回值处理(PG主收到权威副本发送的PG Log信息)

|-boost::statechart::result PeeringState::GetLog::react(const GotLog&)

\-PeeringState::proc_master_log()    // 将权威日志与本地日志进行合并(内存中),并记录日志能够识别的丢失对象。

        \-PeeringState::merge_log

            \-PGLog::merge_log()       // 将本地日志与权威日志对齐。并解决分歧对象。(让对象处于正确的版本,miissing列表)

                |-if (olog.tail < log.tail)    // 如果权威日志尾部比主本地尾部长,将权威日志比主尾部长的部分的日志,增加到本地日志内存缓存中(以对象为维度的key等的索引日志,及日志内容)

|-log.index(*to);  

|-log.log.splice(log.log.begin(), olog.log, from, to);

|-if (olog.head < log.head)    // 如果本地日志头,比权威日志头长(分歧日志,解决分歧日志。

\-PGLog::rewind_divergent_log    // 本地日志头比权威头长的部分为分歧日志

                        |-divergent = log.rewind_from_head(newhead)    //拆剪出分歧日志

|-_merge_divergent_entries()    // 将分歧日志中的对象,放到missing列表中。目的:分歧对象要回滚到对象的上一个版本。

|-if (olog.head > log.head    // 权威日志头 长于本地日志头,

|-append_log_entries_update_missing()    // 将权威长的部分追加到本地日志头,并加入missing列表,等待修复

|-peer_missing[from].claim(omissing);    // 记录副本丢失对象列表

 

6、 PG 主Peering,第三步:GetMissing

GetMissing部分,主要是主获取上线副本的pg日志,将拉取到的上线副本的日志,与本地pg主日志进行合并(对齐),找出副本日志中的不一致对象,作为后续修复的依据。

 

6.1 GetMissing 发送拉取副本日志请求。

|-PeeringState::GetMissing::GetMissing    // 对于与权威日志有交集的副本, 拉取副本日志,为修复做准备

|-context< PeeringMachine >().send_query()    // pg_query_t::LOG, 拉取部分日志, pg_query_t::FULLLOG, 拉取全部日志

6.2 GetMissing 收到副本发送的日志。

|-boost::statechart::result PeeringState::GetMissing::react(const MLogRec& logevt)

\-PeeringState::proc_replica_log    // 将返回的副本日志,与本地日志对齐(本地内存中,日志已经与权威日志一致), 并找到丢失对象版本放到missing列表中,(丢失对象,是指本地比权威日志长的那一部分——对象的丢失版本)

    |-post_event(Activate(ps->get_osdmap_epoch()));    // 如果所有副本都处理完成,进入Activate状态。

7  Active激活各个副本

7.1  主发消息激活副本

|-PeeringState::Active::Active(my_context ctx)

\-PeeringState::activate()   

|-PG::schedule_event_on_commit()    // 注册提交成功的回调函数,此回调函数 会将ActivateCommitted事件投递给PG状态机。

        |-if (is_primary())    // 如果是主,向acting_recovery_backfill(与权威有交集)副本发送消息,发送主自己的I info ,log( 权威),MOSDPGLog类型的消息,激活该PG的从OSD上的副本

            |-封装向所有即将上线的成员(acting_recovery_backfill)发送pg info,pg log。消息

                |-if (pi.last_update == info.last_update)    //pi为getinfo时取到的pginfo信息。 当PG最后更新的版本一致,说明该PG副本本身就是clean的,只发送pg_info来激活从OSD。M为消息封装。

|-m = new MOSDPGLog

|-else if(  pg_log.get_tail() > pi.last_update || pi.last_backfill == hobject_t() ||

                             (backfill_targets.count(*i) && pi.last_backfill.is_max()))    // 需要Backfill操作的OSD,发送pg_info,以及osd_min_pg_log_entries数量的PG日志

                    |-m = new MOSDPGLog

|-else    // 需要Recovery操作的OSD,发送pg_info,以及从缺失的日志。

|-m = new MOSDPGLog

|-PG::send_cluster_message()    // 向副本发送封装好的m消息。

 

        |- 恢复地址的构建。

        |-state_set(PG_STATE_ACTIVATING);    // 设置PG状态

 

7.2 副本收到主发送的激活消息

副本收到主发送的pglog 或者 pginfo信息,会将自己本地的与主发送的对齐,并应答主MSG_OSD_PG_INFO消息。

 

1.收到MSG_OSD_PG_LOG

|-boost::statechart::result PeeringState::Stray::react(const MLogRec& logevt)

    |-PeeringState::merge_log    // 将本地log 与主发送的权威log对齐。

2 收到MSG_OSD_PG_INFO

 

2.2.7.3 主收到副本同步Pginfo,Pglog成功的MSG_OSD_PG_INFO消息

1.

|-boost::statechart::result PeeringState::Active::react(const MInfoRec& infoevt)

|-if (ps->peer_activated.size() == ps->acting_recovery_backfill.size())    // 如果主收到了所有副本同步pginfo pglog成功的应答消息。

        |-PeeringState::Active::all_activated_and_committed()

|-post_event(PeeringState::AllReplicasActivated());    // 触发所有副本执行成功函数

2.

boost::statechart::result PeeringState::Active::react(const AllReplicasActivated &evt)

0条评论
作者已关闭评论
林****媛
2文章数
2粉丝数
林****媛
2 文章 | 2 粉丝
林****媛
2文章数
2粉丝数
林****媛
2 文章 | 2 粉丝
原创

Ceph代码走读——PG Peering

2023-09-01 01:34:28
135
0

1、 PG Peering的触发入口

 

需要执行peering的PG,最终需要入队:

|- OSD:: enqueue_peering_evt(

      pgid,

      PGPeeringEventRef(

        std::make_shared<PGPeeringEvent>(

          osdmap->get_epoch(),

          osdmap->get_epoch(),

          NullEvt())));

 

2、 PG Peering执行入口

|-void OSD::dequeue_peering_evt

|-advance_pg(curmap->get_epoch(), pg, handle, rctx)    // 如果PG的MAP 大于等于 shard 的MAP,触发peering; 检查pg是否需要执行OSDMap更新

    \-PG::do_peering_event

        \-PeeringState::handle_event()

        |-machine.process_event()    // 向PG 状态机投递事件。NullEvt()事件等。触发PG peering的执行

 

3、 PG Peering状态机执行

1、状态机转换为start状态

|-Initial状态

     \-boost::statechart::transition< Initialize, Reset >,    // 收到Initialize事件,状态机转换为Reset状态

|-Started状态,自动转换为Start状态

\-PeeringState::Reset::react(const ActMap&)    //收到ActMap事件

 

|-transit< Started >()    // 转换为Started/start状态

 

2、状态机按照PG角色(主、从)触发执行

|-Start状态执行

|-PeeringState::Start::Start()

    if (ps->is_primary()) {

        post_event(MakePrimary());    //主进入Primary, Started, Peering 状态,执行PeeringState::Peering::Peering

    } else { //is_stray

        post_event(MakeStray());    // 从进入 Stray, Started 状态, 等待主更新

    }

3、 主开始peering。

|-PeeringState::Peering::Peering(my_context ctx)

    ps->state_set(PG_STATE_PEERING);    // 设置PG外部状态为PG_STATE_PEERING,标识开始peering

 

4、  PG 主Peering,第一步:GetInfo

主开始peering,peering 第一步,执行GetInfo,获取PG副本的pg info信息(主要是pg的元数据,包含版本信息等)

4.1  向副本发送GetInfo 消息

|-PeeringState::GetInfo::GetInfo

    ps->check_past_interval_bounds();    //检查info,.history中记录的Pg peering信息是否正确。及历史版本是否与info一致

|-PeeringState::log_weirdness()    // 检查pg_log 与pg info版本的一致性

|-PastIntervals::PriorSet PeeringState::build_prior()    // 获取PG所有版本的在当前OSDMap中为存活状态的osd,并判定PG是否为DOWN。

        \-PastIntervals::PriorSet::PriorSet()

            \- std::set<pg_shard_t> all_probe = past_intervals.get_all_probe(ec_pool);    // 获取PG所有版本的osd

                |- pi_compact_rep::get_all_participants

            |- 判定PG 所有版本的osd (all_probe)是否处于 down状态,用osdmap 中记录的osd状态判定。

            |- past_intervals.iterate_mayberw_back_to()    // 检查PG版本大于l ast_epoch_started的interval(PG集合),其在现在的OSDMap中 ,对应的osd是否是down状态,如果在此间隔期PG不可修复,且有down 的,标识PG down、pg_down = true;

    \- PeeringState::GetInfo::get_infos()    // 对prior_set中probe成员(在当前osdmap中,PG所有版本为存活状态的osd),获取pg_info(pg的版本信息))

        |-PeeringState::PeeringMachine::send_query

4.2  GetInfo 返回值(PG主收到副本发送的PG info 版本信息)

|-boost::statechart::result PeeringState::GetInfo::react(const MNotifyRec& infoevt)

\- PeeringState::proc_replica_info()

        |-update_history(oinfo.history);    // 用副本pg_info_t 中,history内容,更新本地pginfo的history。

|-if (!is_up(from) && !is_acting(from))    // 如果收到的副本成员,即不是acting成员,说明是PG老旧版本的成员。当PG当前数据已经修复完成,向该成员发送删除PG请求。

purge_strays();    // 向副本发送删除PG请求。

 

5、 PG 主Peering,第二步:GetLog

    peering 第二步,执行GetLog,主要流程为:用第一步获取到的副本的pg info信息, 选举出一个权威副本(拥有最高版本的PG),及能够上线的副本(与权威副本日志有交集),获取权威副本的pg log信息。并将主的pg log与权威副本合并(对齐)。

5.1  选举权威副本,及上线副本,向权威副本发送GetLog 消息

|-PeeringState::GetLog::GetLog(my_context ctx)

\-PeeringState::choose_acting  // 选出权威info , 并找出与权威info 有交集的副本acting_recovery_backfill(recovery修复),及与权威没有交集的up 副本backfill_targets,用于后续修复(backfill修复)。auth_log_shard为拥有权威info 的OSD

|-map<pg_shard_t, pg_info_t>::const_iterator auth_log_shard = find_best_info()    //比较PG副本返回的PG info 信息, 选出一个:last_epoch_started最大,且last_update最大中的日志最长的log_tail

        |-PeeringState::calc_replicated_acting()    // 过滤出与权威info 有交集的成员。过滤顺序为:先过滤up成员,如果过滤出来总数量不足副本数,再过滤acting成员,如果过滤出来总数量不足副本数,再过滤其他获取到info的副本。

|-PeeringState::recoverable    // 判定PG是否可修复, 即,与权威info 有交集的OSD数量,是否达到存储池要求的副本数量,

    |-如果权威就是主本身,Getlog完成。

    |-context<PeeringMachine>().send_query()    // 主向权威发送pg_query_t::LOG消息, 获取权威的日志到本地。要求从request_log_from版本开始。

 

5.2 GetLog 返回值处理(PG主收到权威副本发送的PG Log信息)

|-boost::statechart::result PeeringState::GetLog::react(const GotLog&)

\-PeeringState::proc_master_log()    // 将权威日志与本地日志进行合并(内存中),并记录日志能够识别的丢失对象。

        \-PeeringState::merge_log

            \-PGLog::merge_log()       // 将本地日志与权威日志对齐。并解决分歧对象。(让对象处于正确的版本,miissing列表)

                |-if (olog.tail < log.tail)    // 如果权威日志尾部比主本地尾部长,将权威日志比主尾部长的部分的日志,增加到本地日志内存缓存中(以对象为维度的key等的索引日志,及日志内容)

|-log.index(*to);  

|-log.log.splice(log.log.begin(), olog.log, from, to);

|-if (olog.head < log.head)    // 如果本地日志头,比权威日志头长(分歧日志,解决分歧日志。

\-PGLog::rewind_divergent_log    // 本地日志头比权威头长的部分为分歧日志

                        |-divergent = log.rewind_from_head(newhead)    //拆剪出分歧日志

|-_merge_divergent_entries()    // 将分歧日志中的对象,放到missing列表中。目的:分歧对象要回滚到对象的上一个版本。

|-if (olog.head > log.head    // 权威日志头 长于本地日志头,

|-append_log_entries_update_missing()    // 将权威长的部分追加到本地日志头,并加入missing列表,等待修复

|-peer_missing[from].claim(omissing);    // 记录副本丢失对象列表

 

6、 PG 主Peering,第三步:GetMissing

GetMissing部分,主要是主获取上线副本的pg日志,将拉取到的上线副本的日志,与本地pg主日志进行合并(对齐),找出副本日志中的不一致对象,作为后续修复的依据。

 

6.1 GetMissing 发送拉取副本日志请求。

|-PeeringState::GetMissing::GetMissing    // 对于与权威日志有交集的副本, 拉取副本日志,为修复做准备

|-context< PeeringMachine >().send_query()    // pg_query_t::LOG, 拉取部分日志, pg_query_t::FULLLOG, 拉取全部日志

6.2 GetMissing 收到副本发送的日志。

|-boost::statechart::result PeeringState::GetMissing::react(const MLogRec& logevt)

\-PeeringState::proc_replica_log    // 将返回的副本日志,与本地日志对齐(本地内存中,日志已经与权威日志一致), 并找到丢失对象版本放到missing列表中,(丢失对象,是指本地比权威日志长的那一部分——对象的丢失版本)

    |-post_event(Activate(ps->get_osdmap_epoch()));    // 如果所有副本都处理完成,进入Activate状态。

7  Active激活各个副本

7.1  主发消息激活副本

|-PeeringState::Active::Active(my_context ctx)

\-PeeringState::activate()   

|-PG::schedule_event_on_commit()    // 注册提交成功的回调函数,此回调函数 会将ActivateCommitted事件投递给PG状态机。

        |-if (is_primary())    // 如果是主,向acting_recovery_backfill(与权威有交集)副本发送消息,发送主自己的I info ,log( 权威),MOSDPGLog类型的消息,激活该PG的从OSD上的副本

            |-封装向所有即将上线的成员(acting_recovery_backfill)发送pg info,pg log。消息

                |-if (pi.last_update == info.last_update)    //pi为getinfo时取到的pginfo信息。 当PG最后更新的版本一致,说明该PG副本本身就是clean的,只发送pg_info来激活从OSD。M为消息封装。

|-m = new MOSDPGLog

|-else if(  pg_log.get_tail() > pi.last_update || pi.last_backfill == hobject_t() ||

                             (backfill_targets.count(*i) && pi.last_backfill.is_max()))    // 需要Backfill操作的OSD,发送pg_info,以及osd_min_pg_log_entries数量的PG日志

                    |-m = new MOSDPGLog

|-else    // 需要Recovery操作的OSD,发送pg_info,以及从缺失的日志。

|-m = new MOSDPGLog

|-PG::send_cluster_message()    // 向副本发送封装好的m消息。

 

        |- 恢复地址的构建。

        |-state_set(PG_STATE_ACTIVATING);    // 设置PG状态

 

7.2 副本收到主发送的激活消息

副本收到主发送的pglog 或者 pginfo信息,会将自己本地的与主发送的对齐,并应答主MSG_OSD_PG_INFO消息。

 

1.收到MSG_OSD_PG_LOG

|-boost::statechart::result PeeringState::Stray::react(const MLogRec& logevt)

    |-PeeringState::merge_log    // 将本地log 与主发送的权威log对齐。

2 收到MSG_OSD_PG_INFO

 

2.2.7.3 主收到副本同步Pginfo,Pglog成功的MSG_OSD_PG_INFO消息

1.

|-boost::statechart::result PeeringState::Active::react(const MInfoRec& infoevt)

|-if (ps->peer_activated.size() == ps->acting_recovery_backfill.size())    // 如果主收到了所有副本同步pginfo pglog成功的应答消息。

        |-PeeringState::Active::all_activated_and_committed()

|-post_event(PeeringState::AllReplicasActivated());    // 触发所有副本执行成功函数

2.

boost::statechart::result PeeringState::Active::react(const AllReplicasActivated &evt)

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0