ceph源码阅读 erasure-code

1、ceph纠删码

纠删码(Erasure Code)是比较流行的数据冗余的存储方法,将原始数据分成k个数据块(data chunk),通过k个数据块计算出m个校验块(coding chunk)。把n=k+m个数据块保存在不同的节点,通过n中的任意k个块还原出原始数据。EC包含编码和解码两个过程。

ceph中的EC编码是以插件的形式来提供的。EC编码有三个指标:空间利用率、数据可靠性和恢复效率。ceph提供以下几种纠删码插件:clay(coupled-layer)、jerasure、lrc、shec、isa。

clay:用于在修复失败的节点/OSD/rack时节省网络带宽和磁盘IO。

jerasure:开源库,目前ceph默认的编码方式。

isa:isa是Intel提供的EC库,利用intel处理器指令加速计算,只能运行在Intel CPU上。

lrc:将校验块分为全局校验块和局部校验块,减少单个节点失效后恢复过程的网络开销。

shec:shec(k,m,l),k为data chunk,m为coding chunk,l代表计算coding chunk时需要的data chunk数量。其最大允许失效数据块为:ml/k,恢复失效的单个数据块(data chunk)只需要额外读取l个数据块。

2、erasure-code文件结构

erasure-code是ceph的纠删码核心模块,包含5个文件夹和ErasureCodeInterface、ErasureCode、ErasureCodePlugin,采用工厂模式。

  • clay、isa、jerasure、lrc、shec是ceph的EC插件。
  • ErasureCodeInterface:提供EC插件的共有接口,每个接口有详细的说明。
  • ErasureCode:提供获取纠删码参数和核心编码、解码接口。
  • ErasureCodePlugin:提供纠删方式事件的注册、添加、删除登功能。

3、数据条带化

存储设备都有吞吐量限制,它会影响性能和伸缩性,所以存储系统一般都支持条带化(把连续的信息分片存储于多个设备)以增加吞吐量和性能。

  • 基本概念

块(chunk):基于纠删码编码时,每次编码将产生若干大小相同的块(要求这些块时有序的,否则无法解码)。ceph通过数量相等的PG将这些分别存储在不同的osd中。

条带(strip):如果编码对象太大,可分多次进行编码,每次完成编码的部分称为条带。同一个对内的条带时有序的。

分片(shared):同一个对象中所有序号相同的块位于同一个PG上,他们组成对象的一个分片,分片的编号就是块的序号。

空间利用率(rate):通过k/n计算。

对象尺寸: Ceph 存储集群里的对象有最大可配置尺寸(如 2MB 、 4MB 等等),对象尺寸必须足够大以便容纳很多条带单元、而且应该是条带单元的整数倍。

条带数量: Ceph 客户端把一系列条带单元写入由条带数量所确定的一系列对象,这一系列的对象称为一个对象集。客户端写到对象集内的最后一个对象时,再返回到第一个。

条带宽度: 条带都有可配置的单元尺寸(如 64KB )。 Ceph 客户端把数据等分成适合写入对象的条带单元,除了最后一个。条带宽度应该是对象尺寸的分片,这样对象才能 包含很多条带单元。

strip_width=chunk_size*strip_size

假设有EC(k=4,m=2),strip_size=4,chunk_size=1K,那么strip_width=4K。在ceph中,strip_width默认为4K。

  • 数据条带化过程

如果要处理大尺寸图像、大 S3 或 Swift 对象(如视频)、或大的 CephFS 目录,你就能看到条带化到一个对象集中的多个对象能带来显著的读/写性能提升。当客户端把条带单元并行地写入相应对象时,就会有明显的写性能,因为对象映射到了不同的归置组、并进一步映射到不同 OSD ,可以并行地以最大速度写入。

在上图中,客户端数据条带化到一个对象集(上图中的objectset1),它包含 4 个对象,其中,第一个条带单元是object0的stripe unit 0、第四个条带是object3的stripe unit 3,写完第四个条带,客户端要确认对象集是否满了。如果对象集没满,客户端再从第一个对象起写入条带(上图中的object0);如果对象集满了,客户端就得创建新对象集(上图的object set 2),然后从新对象集中的第一个对象(上图中的object 4)起开始写入第一个条带(stripe unit16)。

4、源码解析

  • 编码流程

ECUtil::encode是将原始数据按条带宽度进行分割,然后对条带数据编码,得到条带的数据块和校验块。把每个条带化数据块和校验块有序的链接,形成数据块和校验块。

int ECUtil::encode(const stripe_info_t &sinfo,ErasureCodeInterfaceRef &ec_impl,bufferlist &in,const set<int> &want,map<int, bufferlist> *out)
....//文件每次按strip_width的大小进行encode编码for (uint64_t i = 0; i < logical_size; i += sinfo.get_stripe_width()) {map<int, bufferlist> encoded;bufferlist buf;buf.substr_of(in, i, sinfo.get_stripe_width());//调用对应的纠删码方式进行编码int r = ec_impl->encode(want, buf, &encoded);ceph_assert(r == 0);//将条带化的数据块和校验块追加到outfor (map<int, bufferlist>::iterator i = encoded.begin();i != encoded.end();++i) {ceph_assert(i->second.length() == sinfo.get_chunk_size());(*out)[i->first].claim_append(i->second);}}....return 0;
}

接下来深入分析ec_impl->encode(want, buf,&encoded),ErasureCode是ErasureCodeInterface的子类,因此调用ErasureCode::encode。在ErasureCode::encode主要是进行map<int, bufferlist>*encoded的内存分配(encode_prepare())和数据块的编码(encode_chunks)。

int ErasureCode::encode(const set<int> &want_to_encode,const bufferlist &in,map<int, bufferlist> *encoded)
{unsigned int k = get_data_chunk_count();unsigned int m = get_chunk_count() - k;bufferlist out;//encoded的内存块分配int err = encode_prepare(in, *encoded);if (err)return err;//进行编码操作encode_chunks(want_to_encode, encoded);for (unsigned int i = 0; i < k + m; i++) {if (want_to_encode.count(i) == 0)encoded->erase(i);}return 0;
}

ErasureCode::encode_prepare()进行参数初始化和内存分配。

int ErasureCode::encode_prepare(const bufferlist &raw,map<int, bufferlist> &encoded) const
{unsigned int k = get_data_chunk_count();unsigned int m = get_chunk_count() - k;//每个块的大小unsigned blocksize = get_chunk_size(raw.length());//空白块的个数unsigned padded_chunks = k - raw.length() / blocksize;bufferlist prepared = raw;//将数据raw按blocksize大小有序分割,并将分割后的块有序写入到encodedfor (unsigned int i = 0; i < k - padded_chunks; i++) {bufferlist &chunk = encoded[chunk_index(i)];chunk.substr_of(prepared, i * blocksize, blocksize);chunk.rebuild_aligned_size_and_memory(blocksize, SIMD_ALIGN);ceph_assert(chunk.is_contiguous());}if (padded_chunks) {unsigned remainder = raw.length() - (k - padded_chunks) * blocksize;bufferptr buf(buffer::create_aligned(blocksize, SIMD_ALIGN));raw.copy((k - padded_chunks) * blocksize, remainder, buf.c_str());buf.zero(remainder, blocksize - remainder);encoded[chunk_index(k-padded_chunks)].push_back(std::move(buf));for (unsigned int i = k - padded_chunks + 1; i < k; i++) {bufferptr buf(buffer::create_aligned(blocksize, SIMD_ALIGN));buf.zero();encoded[chunk_index(i)].push_back(std::move(buf));}}for (unsigned int i = k; i < k + m; i++) {bufferlist &chunk = encoded[chunk_index(i)];chunk.push_back(buffer::create_aligned(blocksize, SIMD_ALIGN));}return 0;
}

以上的工作完成后,可以开始正式的编码encode_chunks()。这里假设编码方式为jerasure,选用RS码。

int ErasureCodeJerasure::encode_chunks(const set<int> &want_to_encode,map<int, bufferlist> *encoded)
{char *chunks[k + m];for (int i = 0; i < k + m; i++)chunks[i] = (*encoded)[i].c_str();jerasure_encode(&chunks[0], &chunks[k], (*encoded)[0].length());return 0;
}

jerasure_encode()是调用jerasure库的编码函数。

void ErasureCodeJerasureReedSolomonVandermonde::jerasure_encode(char **data,char **coding,int blocksize)
{jerasure_matrix_encode(k, m, w, matrix, data, coding, blocksize);
}
  • 解码流程

ECUtil::decode函数有两个,挑个简单的来分析。

下面的decode()函数初始化数据,并进行解码。

int ECUtil::decode(const stripe_info_t &sinfo,ErasureCodeInterfaceRef &ec_impl,map<int, bufferlist> &to_decode,bufferlist *out) {ceph_assert(to_decode.size());uint64_t total_data_size = to_decode.begin()->second.length();....for (uint64_t i = 0; i < total_data_size; i += sinfo.get_chunk_size()) {map<int, bufferlist> chunks;for (map<int, bufferlist>::iterator j = to_decode.begin();j != to_decode.end();++j) {chunks[j->first].substr_of(j->second, i, sinfo.get_chunk_size());}bufferlist bl;int r = ec_impl->decode_concat(chunks, &bl);ceph_assert(r == 0);ceph_assert(bl.length() == sinfo.get_stripe_width());out->claim_append(bl);}return 0;
}

ErasureCode::decode_concat()进行解码,并且链接哥哥数据块,还原出原数据。

int ErasureCode::decode_concat(const map<int, bufferlist> &chunks,bufferlist *decoded)
{set<int> want_to_read;for (unsigned int i = 0; i < get_data_chunk_count(); i++) {want_to_read.insert(chunk_index(i));}map<int, bufferlist> decoded_map;//解码核心部分int r = _decode(want_to_read, chunks, &decoded_map);if (r == 0) {//将解码后的数据块链接for (unsigned int i = 0; i < get_data_chunk_count(); i++) {decoded->claim_append(decoded_map[chunk_index(i)]);}}return r;
}

同样地,这里也是假设使用纠删码插件为jerasure。jerasure_decode()是调用jerasure库的解码函数。

int ErasureCodeJerasure::decode_chunks(const set<int> &want_to_read,const map<int, bufferlist> &chunks,map<int, bufferlist> *decoded)
{unsigned blocksize = (*chunks.begin()).second.length();int erasures[k + m + 1];//记录丢失块的编号int erasures_count = 0;//丢失块的个数char *data[k];char *coding[m];for (int i =  0; i < k + m; i++) {if (chunks.find(i) == chunks.end()) {erasures[erasures_count] = i;erasures_count++;}if (i < k)data[i] = (*decoded)[i].c_str();elsecoding[i - k] = (*decoded)[i].c_str();}erasures[erasures_count] = -1;ceph_assert(erasures_count > 0);return jerasure_decode(erasures, data, coding, blocksize);
}

参考资料:

1、体系结构 - Ceph Documentation

2、ceph源码分析 常涛

3、ceph设计原理与实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/60610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解密Spring MVC异常处理:从局部到全局,打造稳固系统的关键步骤

&#x1f600;前言 在现代软件开发中&#xff0c;异常处理是不可或缺的一部分&#xff0c;它能够有效地提高系统的稳定性和健壮性。在Spring MVC框架中&#xff0c;异常处理机制起着至关重要的作用&#xff0c;它允许开发者在程序运行过程中捕获、处理和报告异常&#xff0c;从…

Qt/C++编写视频监控系统80-远程回放视频流

一、前言 远程回放NVR或者服务器上的视频文件&#xff0c;一般有三种方式&#xff0c;第一种是调用厂家的SDK&#xff0c;这个功能最全&#xff0c;但是缺点明显就是每个厂家的设备都有自己的SDK&#xff0c;只兼容自家的设备&#xff0c;如果你的软件需要接入多个厂家的&…

【深入解读Redis系列】Redis系列(五):切片集群详解

首发博客地址 https://blog.zysicyj.top/ 系列文章地址[1] 如果 Redis 内存很大怎么办&#xff1f; 假设一台 32G 内存的服务器部署了一个 Redis&#xff0c;内存占用了 25G&#xff0c;会发生什么&#xff1f; 此时最明显的表现是 Redis 的响应变慢&#xff0c;甚至非常慢。 这…

分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测

分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测 目录 分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测…

数学建模:数据的预处理

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 数据预处理数据变换数据清洗缺失值处理异常值处理 数据预处理 数据变换 常见的数据变换的方式&#xff1a;通过某些简单的函数进行数据变换。 x ′ x 2 x ′ x x ′ log ⁡ ( x ) ∇ f ( x k )…

Redis 持久化和发布订阅

一、持久化 Redis 是内存数据库&#xff0c;如果不将内存中的数据库状态保存到磁盘&#xff0c;那么一旦服务器进程退出&#xff0c;服务器中的数据库状态也会消失。所以 Redis 提供了持久化功能&#xff01; 1.1、RDB&#xff08;Redis DataBase&#xff09; 1.1.1 …

第一方支付、第二方支付、第三方支付、第三方支付是什么?

我相信关于支付行业大家多多少少都有一些自己的理解&#xff0c;但是具体的一些名词如标题中的这些&#xff0c;第一方、第二方、第三方支付&#xff0c;到底指的是什么&#xff1f; 第一方支付 也就是现金支付&#xff0c;其本质的意义就是指货币支付&#xff0c;从最早出现货…

猜拳游戏小程序源码 大转盘积分游戏小程序源码 积分游戏小程序源码

简介&#xff1a; 猜拳游戏大转盘积分游戏小程序前端模板源码&#xff0c;一共五个静态页面&#xff0c;首页、任务列表、大转盘和猜拳等五个页面 图片&#xff1a;

Spring与Mybatis集成且Aop整合

目录 一、集成 1.1 集成的概述 1.2 集成的优点 1.3 代码示例 二、整合 2.1 整合概述 2.2 整合进行分页 一、集成 1.1 集成的概述 集成是指将不同的组件、部分或系统组合在一起&#xff0c;以形成一个整体功能完整的解决方案。它是通过连接、交互和协调组件之间的关系来实…

MybatisPlus-插件篇

文章目录 一、前言二、插件1、分页插件2.1.1、引入依赖2.1.1、配置分页插件2.1.3、使用分页方法 2、乐观锁插件2.1、引入依赖2.2、添加版本字段2.3、配置乐观锁插件2.4、执行更新操作 三、总结 一、前言 本文将详细介绍mybatisplus中常用插件的使用。 二、插件 1、分页插件 …

Texlive2023与Texstudio2023卸载与安装(详细全程)

早在两年前安装了texlive2020&#xff0c;最近重新使用总是报错&#xff0c;好像是因为版本过低。我就找了个时间更新一下texlive版本&#xff0c;全程如下。 1、卸载texlive老版本 1&#xff09;找到texlive目录&#xff0c;比如我的是D:\texlive\2022\tlpkg\installer&…

链路聚合原理

文章目录 一、定义二、功能三、负载分担四、分类五、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、定义 在网络中&#xff0c;端口聚合是一种将连接到同一台交换机的多个物理端口捆绑在一起&#xff0c;形成一个逻辑端口的技术。通过端口聚合&…

Llama模型结构解析(源码阅读)

目录 1. LlamaModel整体结构流程图2. LlamaRMSNorm3. LlamaMLP4. LlamaRotaryEmbedding 参考资料&#xff1a; https://zhuanlan.zhihu.com/p/636784644 https://spaces.ac.cn/archives/8265 ——《Transformer升级之路&#xff1a;2、博采众长的旋转式位置编码》 前言&#x…

Uniapp笔记(五)uniapp语法4

本章目标 授权登录【难点、重点】 条件编译【理解】 小程序分包【理解】 一、授权登录 我的模块其实是两个组件&#xff0c;一个是登录组件&#xff0c;一个是用户信息组件&#xff0c;根据用户的登录状态判断是否要显示那个组件 1、登录的基本布局 <template><…

【java】【已解决】IDEA启动报错:Lombok Requires Annotation Processing

解决办法&#xff1a; 1、根据异常提示操作&#xff1a; 直接点击错误提示后面的蓝色标识【Enable】&#xff08;小编点完了所以变灰色&#xff09;&#xff0c;此操作等价于下面的步骤&#xff1a; 【File】-->【Settings】-->【Build】-->【Compiler】-->【Ann…

【数学建模】-- 模糊综合评价

模糊综合评价&#xff08;Fuzzy Comprehensive Evaluation&#xff09;是一种用于处理不确定性和模糊性信息的决策分析方法。它通常用于解决复杂的多指标决策问题&#xff0c;其中各指标之间可能存在交叉影响和模糊性的情况。模糊综合评价通过将不确定性和模糊性量化&#xff0…

MongoDB实验——MongoDB配置用户的访问控制

MongoDB 配置用户的访问控制 一、 实验原理 理解admin数据库&#xff1a;安装MongoDB时&#xff0c;会自动创建admin数据库&#xff0c;这是一个特殊数据库&#xff0c;提供了普通数据库没有的功能&#xff0c;例如&#xff0c;有些账户角色赋予用户操作多个数据库的权限&…

地下管线三维自动建模软件MagicPipe3D V3.0发布

2023年9月1日经纬管网建模系统MagicPipe3D V3.0正式发布&#xff0c;该版本经过众多用户应用和反馈&#xff0c;在三维地下管网建模效果、效率、适配性方面均有显著提升&#xff01;MagicPipe3D本地离线参数化构建地下管网模型&#xff08;包括管道、接头、附属设施等&#xff…

0基础学习VR全景平台篇 第94篇:智慧景区浏览界面介绍

一、景区详细信息介绍 点击左上角的图标就可以看到景区详细信息例如景区简介&#xff0c;地址&#xff0c;开放信息&#xff0c;联系电话等 二、问题反馈中心 点击左下角的【问题反馈】按钮向作者进行问题反馈 三、开场地图 1、直接点击开场地图页面上的图标浏览该场景 2、通…

idea新建Java-maven项目时,出现Dependency ‘ xxx(jar包名)‘ not found的解决方案

项目场景&#xff1a; 项目场景&#xff1a;使用idea创建maven项目时&#xff0c;导入简单依赖时&#xff08;本文以mysql-connector-java为例&#xff09;。 问题描述 问题&#xff1a; 首先&#xff0c;在创建新的maven项目中&#xff0c;出现下列两种情况&#xff1a; &am…