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设计原理与实现
相关文章:

ceph源码阅读 erasure-code
1、ceph纠删码 纠删码(Erasure Code)是比较流行的数据冗余的存储方法,将原始数据分成k个数据块(data chunk),通过k个数据块计算出m个校验块(coding chunk)。把nkm个数据块保存在不同的节点,通过n中的任意k个块还原出原始数据。EC包含编码和解…...

C++ 之 命名空间
namespace_百度百科,有示例...

MyBatis关系映射
文章目录 前言一、一对一映射1.1 创建实体1.2 xml配置 二、一对多映射2.1 创建实体2.2 resultMap配置2.3 测试 三、 多对多映射3.1 创建实体3.2 resultMap配置3.3 测试 前言 MyBatis是一个Java持久化框架,它提供了一种将数据库表和Java对象之间进行关系映射的方式。…...

DVWA失效的访问控制
失效的访问控制,可以认为是系统对一些功能进行了访问或权限限制,但因为种种原因,限制并没有生效,造成失效的访问控制漏洞,比如越权等 这里以DVWA为例,先访问低难度的命令执行并抓包 删除cookie,并在请求头…...

docker 笔记2 Docker镜像和数据卷
参考: 1.镜像是什么?(面试题) 是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文…...

java springboot 时间格式序列化 UTC8
背景 我们在项目中使用序列化和反序列化组件中,默认一般采用Jackson,如果遇到特殊配置,我们该怎么配置呢,大致有如下两种方式:采用配置文件【application.yml】和代码配置 配置文件 比如添加jackson节点 spring:jac…...

攻防世界-Get-the-key.txt
原题 解题思路 notepad看到,这应该是一个压缩包,解压。 但是解压的时候提示格式不对,不是zip,rar可以。解压出来有一个key.txt,打开就行。...

MyBatisPlus之DQL编程控制
🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 MyBatisPlus之DQL编程控制 一、 条件查询方式&…...

本地使用GFPGAN进行图像人脸修复
人脸修复 1.下载项目和权重文件2.部署环境3.下载权重文件4.运行代码5.网页端体验 首先来看一下效果图 1.下载项目和权重文件 https://github.com/iptop/GFPGAN-for-Video.git2.部署环境 根据README文件部署好环境,额外还需要: cd GFPGAN-1.3.8 pyt…...

Linux--进程概念
1.什么是程序?什么是进程?有什么区别? 程序:是静态的概念,gcc xxx.c -o pro 磁盘中生成的pro文件,叫做程序。 进程:是程序的一种与运行活动,通俗的意思是程序跑起来了,系…...

dex2oat编译模式、触发场景、命令强制执行
dex2oat简单理解就是把delvik虚拟机的可执行文件dex转化成AndroidRuntime虚拟机的可执行文件oat。 Android T版本由PKMS下发命令、native层进程installd负责具体执行dex2oat操作。installd回去调用dex2oat64完成编译工作,可以将dex2oat64理解成一个程序。源码路径&…...

深度学习 | TCN时间卷积神经网络模型答疑
深度学习 | TCN时间卷积神经网络模型答疑 目录 深度学习 | TCN时间卷积神经网络模型答疑问题汇总问题回答参考资料问题汇总 1.使用 TCN 进行序列建模有哪些优势? 2.TCN 的特征? 问题回答 1.使用 TCN 进行序列建模具备以下优势: 并行性。与 RNN 中后继时间步长的预测必须等待…...

Linux之修改服务端口号
本次演示以SSH服务为例,SSH默认监听端口是22,先保留了22端口,所以我们要进入ssh的配置文件添加新端口并注释或删掉原有端口。 1、使用vi编辑器修改文件 sshd_config,路径是/etc/ssh/sshd_config,找到“#Port 22”,添加新的端口号10086。 2、如果你关闭了…...

LeetCode笔记:Weekly Contest 361
LeetCode笔记:Weekly Contest 361 0. 吐槽1. 题目一 1. 解题思路2. 代码实现 2. 题目二 1. 解题思路2. 代码实现 3. 题目三 1. 解题思路2. 代码实现 4. 题目四 1. 解题思路2. 代码实现 比赛链接:https://leetcode.com/contest/weekly-contest-361 0. …...

Springboot快速搭建Web API项目
内容概述 SpringBoot最常见得用途就是web api项目。 本文介绍使用自动配置功能,通过最简洁的pom依赖,快速搭建一个示例项目。 实现的功能为:接收http请求并返回json格式的数据。 一、配置pom.xml依赖 1.引入springweb依赖 <dependenc…...

数据结构day06(单向循环链表、双向链表)
双向链表的练习代码 head.h #ifndef __HEAD_H__ #define __HEAD_H__ #include <stdio.h> #include <stdlib.h> #include <string.h> typedef int database; typedef struct double_link_list{union{database data;int len;};struct double_link_list* pre;…...

zabbix -- 新建主机
目录 一、新建主机 二、新建监控项 IP主机192.168.136.55zabbix控制端/服务端192.168.136.56zabbix被控端/客户端 一、新建主机 主机参数 名称、群组(每台主机必须属于某个主机组内)、ip、端口 创建完成,如果你的ZBX为灰色,代…...

=>符号含义
>主要有两方面的作用,一个限制属性状态,另一个简化匿名委托和Lambda 用法一:定义只读属性 public class ManPeople { public string Sex > "男";public string Name { get; set; }}public class WomanPeople { publi…...

Docker+Jenkins(blueocean)+Gitee构建CICD流水线实战
一、配置JDK 1.1 编辑profile文件 vim /etc/profile export JAVA_HOME/home/jdk/jdk1.8.0_301 export JRE_HOME$JAVA_HOME/jre export CLASSPATH.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib export PATH$PATH:$JAVA_HOME/bin:$JRE_HOME/bin 1.2 使配置生效 source /etc/pro…...

Redis快速入门
文章目录 0. Redis介绍1. Centos下Redis安装2. redis.conf配置文件介绍3. redis相关命令4.redis中发布订阅和事务4.1 发布订阅(Pub/Sub)4.2 事务 5. redis封装系统服务6. 问题与解决6.1 启动Redis报错:Could not create Server TCP listening…...

EasyExcel 修改导出的文件属性
EasyExcel 修改导出的文件属性 导出的文件有多种属性,本文只针对sheet名称进行举例 需要自定义拦截器 ExcelWriter excelWriter EasyExcel.write(fileName).withTemplate(stream).registerWriteHandler(new TemplateSheetStrategyHandler()).build()registerWriteHandler (n…...

电子班牌云平台系统——智慧校园管理工具,多媒体信息发布、走班排课、家校互通、物联控制、教务管理、考勤管理、素质评价、日常办公
电子班牌云平台源码,saas模式微服务架构 电子班牌是一款智慧校园管理工具,也是校园多媒体展示平台。智慧班牌融合了多媒体信息发布、走班排课、家校互通、物联控制、教务管理、考勤管理、素质评价、日常办公等一系列应用,是校园管理的现代化手…...

docker-compose 部署 Seata整合nacos,Postgresql 为DB存储
docker-compose 部署 Seata整合nacos,Postgresql 为DB存储 环境 详情环境可参考 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 我这里 <spring.cloud.alibaba-version>2021.1</spring.cloud.alibaba-version>所…...

three.js 场景中如何彻底删除模型和性能优化
three.js 场景中如何彻底删除模型和性能优化 删除外部模型 在three.js场景中,要彻底删除外部模型,需要执行以下几个步骤: 从场景中移除模型 你可以使用 scene.remove(model) 或者 scene.remove(model.children[0]) 将模型从场景中移除。如果…...

Bridge Champ举办人机对战赛:NFT游戏与传统竞技共生发展编织新格局
概要 现在,NFT与体育竞技正日益紧密地联系在一起。一些体育项目开始推出与赛事或球队相关的NFT,同时也有部分NFT游戏开始举办电子竞技赛事。这种共生发展正在改变体育竞技的生态。 笔者采访了桥牌冠军项目相关负责人,探讨NFT游戏与传统体育竞技的融合潜力。桥牌冠军近期成功举…...

Visual Studio软件_MSC_VER值(MSVC编译器版本)的获取方法
本文介绍查看Visual Studio软件_MSC_VER值的方法。 _MSC_VER是微软公司推出的C/C 编译器——MSVC编译器的一个内置宏,其值表示当前Visual Studio软件中MSVC编译器的具体版本。不同的Visual Studio软件版本对应着不同的MSVC编译器版本——无论是不同发布年份的版本&…...

02-Linux-IO多路复用之select、poll和epoll详解
前言: 在linux系统中,实际上所有的 I/O 设备都被抽象为了文件这个概念,一切皆文件,磁盘、网络数据、终端,甚至进程间通信工具管道 pipe 等都被当做文件对待。 在了解多路复用 select、poll、epoll 实现之前ÿ…...

echo、print_r、print、var_dump 、die
die()和exit()函数都有终止线程的作用 是php断点调试需要使用的最主要的函数 die()函数一般与“or”一并使用,写作“or die()” var_dump()和print_r() var_dump() 显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值&#…...

【LeetCode75】第四十四题 省份数量
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们一个二维数组,表示城市之间的连通情况,连在一起的城市为一个省份,问我们一共有多少个省份。 这…...

把DTC从Excel导入cdd的方法
本文是基于CANdelaStudio12.0讲解 问题一:当导入DTC的xxx.cdi文件报如下红色错误 可能原因:在设置具有下拉框的属性的内容时,输入的内容不在下拉框列表中 解决办法:在.cddt文件中更新“”Error Code Table“”内容,把新的选项更新…...