Ceph EC pg backfill run

这篇具有很好参考价值的文章主要介绍了Ceph EC pg backfill run。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

pg的backfill请求也是发送到osd的work queue中与业务IO一起竞争。

PGRecovery::run backfill

 57 void PGRecovery::run( 
 58  OSD *osd, 
 59  OSDShard *sdata, 
 60  PGRef& pg, 
 61  ThreadPool::TPHandle &handle) 
 62 { 
 63  osd->do_recovery(pg.get(), epoch_queued, reserved_pushes, handle); 
 64  pg->unlock();                                   
 65 } 
 

OSD::do_recovery

  1. Call pg->start_recovery_ops
  2. 释放占用资源,并进行pg的下一轮恢复请求调度。
10018 void OSD::do_recovery( 
10019  PG *pg, epoch_t queued, uint64_t reserved_pushes, 
10020  ThreadPool::TPHandle &handle) 
10021 { 
... 
10031  float recovery_sleep = get_osd_recovery_sleep();   
... 
10070   dout(10) << "do_recovery starting " << reserved_pushes << " " << *pg << dendl; 
... 
10075   bool do_unfound = pg->start_recovery_ops(reserved_pushes, handle, &started); 
10076   dout(10) << "do_recovery started " << started << "/" << reserved_pushes 
10077       << " on " << *pg << dendl; 
... 
10089  service.release_reserved_pushes(reserved_pushes);            
10090 } 
 

PrimaryLogPG::start_recovery_ops

  1. 入参的max即osd_recovery_max_single_start,决定了pg得到执行一次recovery op后能同时恢复多少个object。
  2. 执行recovery请求必须是primary pg
  3. 检查是否设置了nobackfill。
  4. 检查是否人为设置了norebalance。
  5. 检查是否完成资源预约。
  6. Call recover_backfill。
12452 bool PrimaryLogPG::start_recovery_ops( 
12453  uint64_t max, 
12454  ThreadPool::TPHandle &handle, 
12455  uint64_t *ops_started) 
12456 { 
... 
12461  ceph_assert(is_primary());                       
... 
12465  ceph_assert(recovery_queued);                
12466  recovery_queued = false;  // recovery op已经得到,pg的下一轮恢复需要重新入队检查 
... 
12502  if (recovering.empty() &&                      
12503    state_test(PG_STATE_BACKFILLING) && 
12504    !backfill_targets.empty() && started < max && 
12505    missing.num_missing() == 0 && 
12506    waiting_on_backfill.empty()) { 
12507   if (get_osdmap()->test_flag(CEPH_OSDMAP_NOBACKFILL)) {         
12508    dout(10) << "deferring backfill due to NOBACKFILL" << dendl; 
12509    deferred_backfill = true; 
12510   } else if (get_osdmap()->test_flag(CEPH_OSDMAP_NOREBALANCE) &&     
12511        !is_degraded()) { 
12512    dout(10) << "deferring backfill due to NOREBALANCE" << dendl; 
12513    deferred_backfill = true; 
12514   } else if (!backfill_reserved) {                    
12515    dout(10) << "deferring backfill due to !backfill_reserved" << dendl; 
12516    if (!backfill_reserving) { 
12517     dout(10) << "queueing RequestBackfill" << dendl; 
12518     backfill_reserving = true; 
12519     queue_peering_event( 
12520      PGPeeringEventRef( 
12521       std::make_shared<PGPeeringEvent>( 
12522        get_osdmap_epoch(), 
12523        get_osdmap_epoch(), 
12524        RequestBackfill()))); 
12525    } 
12526    deferred_backfill = true; 
12527   } else { 
12528    started += recover_backfill(max - started, handle, &work_in_progress);   
12530  } 
12531 
12532  dout(10) << " started " << started << dendl; 
 

PrimaryLogPG::recover_backfill

  1. pg第一次执行backfill,需要把peer_backfill_info、backfill_info、backfills_in_flight重置。
  2. 更新primary的begin obj为last_backfill_started。
  3. 检查backfill info(记录恢复进度)是否要更新恢复对象的范围,一次最多scan 512个obj。
  4. 遍历backfill targets,更新所有peer_backfill_info的begin对象。

Backfill targets是要回填的目标pg shard,例如:

[1,28,120,278,90,17,210,322,184,186]/[1,121,192,278,106,17,60,322,31,53]为一个pg当前的up set和acting set。由于扩容导致up set与acting set不一致,需要backfill,backfill target为:

[28(1),90(4),120(2),184(8),186(9),210(6)]

  1. 如果backfill_info为空,表示没有要backfill的obj。
  2. 获取所有backfill targets中排序最小的obj作为check obj。

有了check obj之后,backfill target的pg shard都要向check obj看齐:

  • check obj < primary的begin obj,说明拥有该check obj的peer需要删除该check obj
  • check obj >= primary的begin obj,定义了need_ver_targs, missing_targs, keep_ver_targs, skip_targs 4个容器。
  • 如果peer begin obj的版本与primary begin obj的版本不一致,拥有该check obj的peer需要加入need_ver_targs进行修复。
  • Peer begin obj ver == begin ver的peer不需要修复,加入keep_ver_targs。
  • 缺少begin obj的peer加入missing_targs进行修。
  • peer的last backfill >= begin obj,该peer可以跳过该obj的恢复,加入skip_targs。
  1. 到prep_backfill_object_push说明已经确定需要恢复obj的peer,生成RecoveryOp,并记录当前正在恢复的obj到backfills_in_flight容器。
  2. ops++之后仍然小于max(osd_recovery_max_single_start),则pg可以继续执行下一个obj的恢复,这里可以作为提速。
  3. pgbackend->run_recovery_op 将recoveryOp封装成message。
13049 uint64_t PrimaryLogPG::recover_backfill( 
13050  uint64_t max, 
13051  ThreadPool::TPHandle &handle, bool *work_started) 
13052 { 
... 
13061  if (new_backfill) {   // pg第一次执行backfill,需要把peer_backfill_info、backfill_info、backfills_in_flight重置 
13062   // on_activate() was called prior to getting here 
13063   ceph_assert(last_backfill_started == earliest_backfill()); 
13064   new_backfill = false; 
13065 
13066   // initialize BackfillIntervals 
13067   for (set<pg_shard_t>::iterator i = backfill_targets.begin(); 
13068     i != backfill_targets.end(); 
13069     ++i) { 
13070    peer_backfill_info[*i].reset(peer_info[*i].last_backfill); 
13071   } 
13072   backfill_info.reset(last_backfill_started); 
13073 
13074   backfills_in_flight.clear(); 
13075   pending_backfill_updates.clear(); 
13076  } 
13077 
... 
13089  // update our local interval to cope with recent changes 
13090  backfill_info.begin = last_backfill_started;   // 更新begin对象为last_backfill_started 
13091  update_range(&backfill_info, handle);        
13092 
13093  unsigned ops = 0; 
13094  vector<boost::tuple<hobject_t, eversion_t, pg_shard_t> > to_remove;       // 放置要删除的obj 
13095  set<hobject_t> add_to_stat; 
13096 
13097  for (set<pg_shard_t>::iterator i = backfill_targets.begin();          // 遍历backfill targets,更新peer_backfill_info的begin对象 
13098    i != backfill_targets.end(); 
13099    ++i) { 
13100   peer_backfill_info[*i].trim_to(                   
13101    std::max(peer_info[*i].last_backfill, last_backfill_started)); 
13102  } 
13103  backfill_info.trim_to(last_backfill_started); 
13104 
13105  PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op();           
13106  while (ops < max) { 
... 
13116   dout(20) << "  my backfill interval " << backfill_info << dendl; 
... 
13148   if (backfill_info.empty() && all_peer_done()) {                
13149    dout(10) << " reached end for both local and all peers" << dendl; 
13150    break; 
13151   } 
13152 
13153   // Get object within set of peers to operate on and 
13154   // the set of targets for which that object applies. 
13155   hobject_t check = earliest_peer_backfill();           
13156 
13157   if (check < backfill_info.begin) {                       
... 
13189   } else { 
13190    eversion_t& obj_v = backfill_info.objects.begin()->second; 
13191 
13192    vector<pg_shard_t> need_ver_targs, missing_targs, keep_ver_targs, skip_targs;                                             
13193    for (set<pg_shard_t>::iterator i = backfill_targets.begin(); 
13194      i != backfill_targets.end(); 
13195      ++i) { 
13196     pg_shard_t bt = *i; 
13197     BackfillInterval& pbi = peer_backfill_info[bt]; 
13198     // Find all check peers that have the wrong version 
13199     if (check == backfill_info.begin && check == pbi.begin) { 
13200      if (pbi.objects.begin()->second != obj_v) { 
13201       need_ver_targs.push_back(bt); 
13202      } else { 
13203       keep_ver_targs.push_back(bt); 
13204      } 
13205     } else { 
13206      pg_info_t& pinfo = peer_info[bt]; 
13207 
13208      // Only include peers that we've caught up to their backfill line 
13209      // otherwise, they only appear to be missing this object 
13210      // because their pbi.begin > backfill_info.begin. 
13211      if (backfill_info.begin > pinfo.last_backfill) 
13212       missing_targs.push_back(bt); 
13213      else 
13214       skip_targs.push_back(bt); 
13215     } 
13216    } 
... 
13225    if (!need_ver_targs.empty() || !missing_targs.empty()) {        
13227     ceph_assert(obc); 
13228     if (obc->get_recovery_read()) { 
13229      if (!need_ver_targs.empty()) { 
13230       dout(20) << " BACKFILL replacing " << check 
13231          << " with ver " << obj_v 
13232          << " to peers " << need_ver_targs << dendl; 
13233      } 
13234      if (!missing_targs.empty()) {                       
13235       dout(20) << " BACKFILL pushing " << backfill_info.begin 
13236         << " with ver " << obj_v 
13237         << " to peers " << missing_targs << dendl; 
13238      } 
13239      vector<pg_shard_t> all_push = need_ver_targs; 
13240      all_push.insert(all_push.end(), missing_targs.begin(), missing_targs.end());  // 记录所有要推送的target shard 
13241 
13242      handle.reset_tp_timeout();    // 防止线程心跳超时 
13243      int r = prep_backfill_object_push(backfill_info.begin, obj_v, obc, all_push, h);     
... 
13249      ops++;                                  
... 
13276  } 
... 
13315  pgbackend->run_recovery_op(h, get_recovery_op_priority()); 
 

ECBackend::run_recovery_op

  1. 遍历RecoveryOp
  2. Call continue_recovery_op生成RecoveryMessages
  3. dispatch_recovery_messages完成ECSubRead请求发送
 715 void ECBackend::run_recovery_op( 
 716  RecoveryHandle *_h, 
 717  int priority) 
 718 { 
 719  ECRecoveryHandle *h = static_cast<ECRecoveryHandle*>(_h); 
 720  RecoveryMessages m; 
 721  for (list<RecoveryOp>::iterator i = h->ops.begin(); 
 722    i != h->ops.end(); 
 723    ++i) { 
 724   dout(10) << __func__ << ": starting " << *i << dendl; 
 725   ceph_assert(!recovery_ops.count(i->hoid)); 
 726   RecoveryOp &op = recovery_ops.insert(make_pair(i->hoid, *i)).first->second; 
 727   continue_recovery_op(op, &m); 
 728  } 
 729 
 730  dispatch_recovery_messages(m, priority); 
 731  send_recovery_deletes(priority, h->deletes); 
 732  delete _h; 
 733 } 
 

ECBackend::continue_recovery_op

恢复过程表示为一个状态机:

  • IDLE:IDLE为recovery op的初始状态。读取将被启动,状态转为READING
  • READING:正在等待一次读取操作,一旦完成,转到WRITING状态。
  • WRITING:等待push完成,一旦完成,转到COMPLETE状态。
  1. get_min_avail_to_read_shards找到存在缺失object的pg shard,因为需要在这些pg shard上读取object来push到新的pg shard上。
  2. 读取请求封装到RecoveryMessages
 567 void ECBackend::continue_recovery_op( 
 568  RecoveryOp &op, 
 569  RecoveryMessages *m) 
 570 { 
 571  dout(10) << __func__ << ": continuing " << op << dendl; 
 572  while (1) { 
 573   switch (op.state) { 
 574   case RecoveryOp::IDLE: { 
 575    // start read 
 576    op.state = RecoveryOp::READING; 
 577    ceph_assert(!op.recovery_progress.data_complete); 
 578    set<int> want(op.missing_on_shards.begin(), op.missing_on_shards.end()); 
 579    uint64_t from = op.recovery_progress.data_recovered_to; 
 580    uint64_t amount = get_recovery_chunk_size(); 
 581 
 582    if (op.recovery_progress.first && op.obc) { 
 583     /* We've got the attrs and the hinfo, might as well use them */ 
 584     op.hinfo = get_hash_info(op.hoid); 
 585     ceph_assert(op.hinfo); 
 586     op.xattrs = op.obc->attr_cache; 
 587     encode(*(op.hinfo), op.xattrs[ECUtil::get_hinfo_key()]); 
 588    } 
 589 
 590    map<pg_shard_t, vector<pair<int, int>>> to_read;                    
 591    int r = get_min_avail_to_read_shards(                         
 592     op.hoid, want, true, false, &to_read); 
 593    if (r != 0) { 
 594     // we must have lost a recovery source 
 595     ceph_assert(!op.recovery_progress.first); 
 596     dout(10) << __func__ << ": canceling recovery op for obj " << op.hoid 
 597         << dendl; 
 598     get_parent()->cancel_pull(op.hoid); 
 599     recovery_ops.erase(op.hoid); 
 600     return; 
 601    } 
 602    m->read( 
 603     this, 
 604     op.hoid, 
 605     op.recovery_progress.data_recovered_to, 
 606     amount, 
 607     std::move(want), 
 608     to_read, 
 609     op.recovery_progress.first && !op.obc); 
 610    op.extent_requested = make_pair( 
 611     from, 
 612     amount); 
 613    dout(10) << __func__ << ": IDLE return " << op << dendl; 
 614    return; 
 615   } 
 

后面就是等待读取请求回复,收到所有的回复之后,发起push。收到所有的pushreply之后说明该obj完成backfill。以此重复,完成pg所有需要backfill的obj。文章来源地址https://www.toymoban.com/news/detail-688320.html

到了这里,关于Ceph EC pg backfill run的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Ceph】基于ceph-deploy部署Ceph集群详解

    DAS(直接附加存储,是 直接接到计算机主板总线上的存储 ) IDE、SATA、SCSI、SAS、USB接口的磁盘 所谓接口就是一种 存储设备驱动下的磁盘设备 ,提供 块级别的存储 NAS(网络附加存储,是 通过网络附加到当前主机文件系统之上的存储 ) NFS、CIFS、FTP 文件系统级别的存储,本

    2024年02月16日
    浏览(27)
  • [ceph] ceph应用

    #创建一个 Pool 资源池,其名字为 mypool,PGs 数量设置为 64,设置 PGs 的同时还需要设置 PGP(通常PGs和PGP的值是相同的): PG (Placement Group),pg 是一个虚拟的概念,用于存放 object,PGP(Placement Group for Placement purpose),相当于是 pg 存放的一种 osd 排列组合 #查看集群 Pool 信息  #查看

    2024年01月18日
    浏览(23)
  • 【Ceph】Ceph集群应用详解

    接上文基于ceph-deploy部署Ceph集群详解 Pool是Ceph中 存储Object对象抽象概念 。我们可以将其理解为 Ceph存储上划分的逻辑分区 ,Pool由多个PG组成;而 PG通过CRUSH算法映射到不同的OSD上 ;同时Pool可以设置副本size大小,默认副本数量为3。 Ceph客户端向monitor请求集群的状态,并向P

    2024年02月16日
    浏览(29)
  • Ceph入门到精通-ceph 源码编译

    Please see https://ceph.com/ for current info. Most of Ceph is dual licensed under the LGPL version 2.1 or 3.0. Some miscellaneous code is under a BSD-style license or is public domain. The documentation is licensed under Creative Commons Attribution Share Alike 3.0 (CC-BY-SA-3.0). There are a handful of headers included here that are licensed under the GP

    2024年02月12日
    浏览(31)
  • 【ceph相关】ceph基准性能测试工具

    参考文档:RedHat-Ceph性能基准 本篇主要介绍几种ceph原生基准性能测试工具以及各自对应使用方法 不同于fio、vdbench等上层应用接口测试工具,ceph提供了一些自带的基准性能测试工具,用于测试rados、rbd等底层存储基准性能,可以比对底层基准性能和上层应用基准性能,确定潜

    2023年04月08日
    浏览(29)
  • Ceph入门到精通-Ceph版本升级命令

    Cephadm 可以安全地将 Ceph 从一个错误修复版本升级到下一个错误修复版本。为 例如,你可以从v15.2.0(第一个八达通版本)升级到下一个 点发布,v15.2.1。 自动升级过程遵循 Ceph 最佳实践。例如: 升级顺序从管理器、监视器开始,然后是其他守护程序。 每个守护程序仅在 Ce

    2024年02月10日
    浏览(33)
  • Ceph:关于Ceph 集群如何访问的一些笔记

    准备考试,整理 Ceph 相关笔记 博文内容涉及,Ceph 集群四种访问方式介绍及 Demo,Ceph 客户端支持的操作介绍 理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式

    2024年02月09日
    浏览(29)
  • Ceph:关于 Ceph 用户认证授权管理的一些笔记

    准备考试,整理 Ceph 相关笔记 博文内容涉及, Ceph 用户管理,认证管理,权限管理 以及相关 Demo 理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众

    2024年02月11日
    浏览(42)
  • ceph集群搭建详细教程(ceph-deploy)

    ceph-deploy比较适合生产环境,不是用cephadm搭建。相对麻烦一些,但是并不难,细节把握好就行,只是命令多一些而已。 服务器主机 public网段IP(对外服务) cluster网段IP(集群通信) 角色 deploy 192.168.2.120 用于部署集群、管理集群 ceph-node1 192.168.2.121 192.168.6.135 ceph-mon、ceph-mgr、

    2024年02月04日
    浏览(26)
  • 【Ceph集群应用】Ceph块存储之RBD接口详解

    接上文基于ceph-deploy部署Ceph集群详解 (1)创建一个名为rbd-demo的专门用于RBD的存储池 (2)将存储池转换为RBD模式 (3)初始化存储池 (4)创建镜像 (5)镜像管理 查看存储池下存在哪些镜像 查看镜像的详细信息 修改镜像大小 直接删除镜像 推荐使用trash命令,这个命令删除

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包