Ceph的纠删码特性 EC(Erasure Code)代码流程

从GitHub上Clone Ceph项目,我是基于(ceph version 12.2.11 luminous 版本)的代码来分析的

一、EC(Erasure Code)是什么?
Ceph的纠删码特性EC:将写入的数据分成N份原始数据,通过这N份原始数据计算出M份效验数据。把N+M份数据分别保存在不同的设备或者节点中,并通过N+M份中的任意N份数据块还原出所有数据块。EC包含了编码和解码两个过程:将原始的N份数据计算出M份效验数据称为编码过程;通过这N+M份数据中的任意N份数据来还原出原始数据的过程称为解码过程。EC可以容忍M份数据失效,任意小于等于M份的数据失效能通过剩下的数据还原出原始数据。Ceph支持以插件的形式来指定不同的EC编码方式。不同的EC编码方式是三个指标间的折中结果,这个三指标就是是:空间利用率、数据可靠性和恢复效率。

二、不同的 EC 编码方式
1. RS类型编码, 目前应用最广泛的纠删码是ReedSolomon编码,简称RS码。下面是RS编码的两个实现(ISA + Jerasure):

1). .ISA:ISA是Intel提供的一个EC库,只能运行在Intel CPU上,它利用了Intel处理器本地指令来加速EC的计算。

2). Jerasure是一个ErausreCode开源实现库,它实现了EC的RS编码。目前Ceph中默认的编码就是Jerasure方式

RS编码的不足之处在于:在N+K个数据块中有任意一块数据失效,都需要读取N块数据来恢复丢失数据。在数据恢复的过程中引起的网络开销比较大。因此,LRC编码和SHEC编码分别从不同的角度做了相关优化。

2. LRC类型编码(特点:恢复数据块时,减少了读取网络数据块的数量)

LRC编码的核心思想为:将校验块(parity block)分为全局校验块(global parity)和局部校验块(local reconstruction parity),从而减少恢复数据的网络开销。

LRC(M,G,L)的三个参数分别为:
·M是原始数据块的数量。
·G为全局校验块的数量。
·L为局部校验块的数量。

编码过程为:把数据分成M个同等大小的数据块,通过该M个数据块计算出G份全局效验数据块。然后把M个数据块平均分成L组,每组计算出一个本地数据效验块,这样共有L个局部数据校验块。

3. SHEC类型编码(特点:恢复数据块时,减少了读取数据块的数量)

SHEC编码方式为SHEC(K,M,L),其中K代表原始数据块data chunk的数量,M代表校验块parity chunk的数量,L代表计算校验块parity chunk时需要的原始数据块data chunk的数量。其最大允许失效的数据块为:ML/K。这样恢复失效的单个数据块只需要额外读取L个数据块。

以SHEC(10,6,5)为例,其最大允许失效的数据块为:M(6) * L(5)/ K(10 ) = 3,且当一个数据块失效时,只读取5个数据块就可以恢复。

三、纠删码 EC 和 副本 Replicated 的比较
众所周知在创建Ceph的pool时,可以设置pool的冗余恢复方式,EC类型或者Replicated副本类型。指定EC类型时,可以设置N和M的参数。各种纠删码(EC的) 和 副本(Replicated)的比较如下表所示:

说明如下:
·在副本类型(三副本)的情况下,恢复效率和可靠性都比较高,缺点就是数据容量开销比较大。
·EC的RS编码,和三副本比较,数据开销显著降低,以恢复效率和可靠性为代价。
·EC的LRC编码以数据容量开销略高的代价,换取了数据恢复开销的显著降低。
·EC的SHEC编码用可靠性换代价,在LRC的基础上进一步降低了容量开销。 

四、先来过一下OSD 处理写操作的序列图,后面分析的EC写流程都是走这个框架


 
根据上面的OSD序列图来分析一下execute_ctx里发生了什么。execute_ctx的函数调用关系为:

PrimaryLogPG::execute_ctx(OpContext *ctx)

     => PrimaryLogPG::prepare_transaction(OpContext *ctx)                                    //准备transaction

            => PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)    //填充ctx变量的相关成员

    => PrimaryLogPG::issue_repop(RepGather *repop, OpContext *ctx)

            => PGBackend::submit_transaction(...)                                                         //提交transaction给PGBackend,见上图          

五、EC 写操作源代码的分析   
举例EC写操作的代码流程分析,来看相关的函数和数据结构

1. 下面分析EC的写操作时,函数PrimaryLogPG::do_osd_ops中实现操作的事务封装

//源代码文件 src/osd/PrimaryLogPG.cc
int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
{
...
PGTransaction* t = ctx->op_t.get();
...
1)多处代码都验证如果是EC类型,写操作的offset必须以stripe_width对齐,否则不支持。

源代码文件 osd_types.h里定义的requires_aligned_append() 函数判断POOL是否是EC类型

/*
 * pg_pool
 */
struct pg_pool_t {
... 
 bool requires_aligned_append() const {
    return is_erasure() && !has_flag(FLAG_EC_OVERWRITES);
  }
...
}
源代码文件 src/osd/PrimaryLogPG.cc里 do_osd_ops() 函数的 CEPH_OSD_OP_WRITE 写操作:

// --- WRITES ---
// -- object data --
case CEPH_OSD_OP_WRITE:
      ++ctx->num_write;
    ...
    if (pool.info.requires_aligned_append() &&
    (op.extent.offset % pool.info.required_alignment() != 0)) {
        result = -EOPNOTSUPP;
        break;
    }
2)如果对象不存在,do_osd_ops() 函数里调用PrimaryLogPG::maybe_create_new_object来创建

maybe_create_new_object(ctx);
来看看PrimaryLogPG::maybe_create_new_objec()函数的定义

void PrimaryLogPG::maybe_create_new_object(
  OpContext *ctx,
  bool ignore_transaction)
{
  ObjectState& obs = ctx->new_obs;
  if (!obs.exists) {
    ctx->delta_stats.num_objects++;
    obs.exists = true;
    assert(!obs.oi.is_whiteout());
    obs.oi.new_object();
    if (!ignore_transaction)
      ctx->op_t->create(obs.oi.soid);
  } else if (obs.oi.is_whiteout()) {
    dout(10) << __func__ << " clearing whiteout on " << obs.oi.soid << dendl;
    ctx->new_obs.oi.clear_flag(object_info_t::FLAG_WHITEOUT);
    --ctx->delta_stats.num_whiteouts;
  }
}
3)最后把写操作添加到事务中(t是一个PGTransaction类型的变量,通过ctx->op_t.get()): 

        if (op.extent.length == 0) {
      ...
    } else {
      t->write(
        soid, op.extent.offset, op.extent.length, osd_op.indata, op.flags);
    }
2. 在函数PrimaryLogPG::do_osd_ops实现事务封装后,由PGBackend提交整个操作上下文信息OpContext ctx给FileStore/BlueStore

PrimaryLogPG::execute_ctx(OpContext *ctx) => PrimaryLogPG::issue_repop(RepGather *repop, OpContext *ctx) => PGBackend::submit_transaction(...),其中PGBackend::submit_transaction为虚函数,具体函数由子类ReplicatedPGBackend/ECPGBackend实现,该函数submit_transaction的参数如下:
PGBackend::submit_transaction(
  const hobject_t &hoid,
  const object_stat_sum_t &delta_stats,
  const eversion_t &at_version,
  PGTransactionUPtr &&t,
  const eversion_t &trim_to,
  const eversion_t &roll_forward_to,
  const vector<pg_log_entry_t> &log_entries,
  boost::optional<pg_hit_set_history_t> &hset_history,
  Context *on_all_commit,
  ceph_tid_t tid,
  osd_reqid_t reqid,
  OpRequestRef client_op
  )

3. EC*类介绍

 类ECBackend实现了EC的读写操作。ECUtil里定义了编码和解码的函数实现。ECTransaction定了EC的事务。      

参考:《Ceph 源代码分析》  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ceph是一种开源的分布式存储系统,它支持使用删码进行数据保护。在Ceph中,删码被用来替代传统的多副本技术,以降低存储开销。引用提到,删码技术因其低存储开销的特点受到越来越多的关注。Ceph使用的删码方案是RS编码(Reed-Solomon code)。RS编码是一种被广泛使用的删码方案,它将k个数据块按照一定的编码规则生成m个校验块,通过任意的k个编码块都能重建出所有数据。以RS(4, 2)编码为例,它只需要占用1.5倍的存储空间,就可以提供与三副本技术相同的容错能力。因此,Ceph使用删码来实现数据的冗余和容错,以提供高可用性和数据保护。引用中提到,Ceph删码实现是基于C语言接口的范德蒙行列式编码。具体来说,在Ceph中,使用jerasure_encode函数调用jerasure库中的jerasure_matrix_encode函数进行编码处理。jerasure_matrix_encode函数是ErasureCodeJerasureReedSolomonVandermonde类中的一个方法,它实现了删码的编码过程。通过使用删码Ceph可以降低存储开销,并提供数据的高可用性和可靠性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [删码项目总结](https://blog.csdn.net/tianyi520jx/article/details/126965871)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [Ceph删码编码源码分析](https://blog.csdn.net/wqxl01/article/details/131045453)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值