Ceph pg分裂流程及可行性分析
转自:https://www.ustack.com/blog/ceph-pg-fenlie/
1 pg分裂
Ceph作为一个scalable的分布式系统,集群规模会逐渐增大,为了保证数据分布的均匀性,好的做法是在扩容时根据集群规模适当调整pg_num和pgp_num的值。
PG作为Ceph数据流过程的中间层,它的数目pg_num和另一个值pgp_num(二者一般是相等的)直接影响集群的数据分布情况。pgp_num决定了多少pg会拿来存放数据,也就是说并不是所有创建出来的pg都会存放数据。理论上来说,它们的值越大,数据分布越均匀,但也意味着消耗更多的资源比如内存,所以生产环境中,它们的值不是随意设置的,社区建议按照一个计算公式pg_num=(osd num*100)/pool size来设置。
调整pg的数目会触发相关pg的分裂操作(但不会数据迁移,因为分裂后的pg会map到其父pg对应的osd集合),调整pgp_num会导致集群内发生数据迁移,算是一个比较重的操作,一般在实际生产环境鲜有人会进行这个操作,所以相关的代码逻辑没有经过大规模生产环境的验证。但当Ceph集群数据分布出现问题时,调整pg_num/pgp_num是一种解决办法。
本文结合实际测试和理论分析两方面来证明pg split在生产环境是否可以操作?
2 实际测试
在集群处于高水位(磁盘占用均在80%以上)的情况下,主要是从实际操作的角度观察以下内容:
- pg split是否可行
- 对ceph集群和用户IO请求的影响
- 如何降低操作带来的影响
2.1 测试环境
目前所有测试均在一个测试环境上完成,其包括3个节点,共9个SSD OSDs,对应的Ceph版本是Firefly,OS是CentOS 7.1。测试之前会使用fio将集群写到高水位,在测试时启动fio产生较大的workload。
2.2 测试用例及结果
测试用例涵盖了目前我们可能出现pg增长的case。
从实际的测试来看,增加pg_num时,集群1~2s内即可恢复,增加pgp_num时,集群会出现数据迁移,并且IO会出现一些抖动恢复时间随着调整的幅度不同而不同。当调整的幅度较大时,还会导致osd出现down的情况。整体上从影响和可控性来说,针对pg_num和pgp_num的值一次增加一个对集群的影响最小,即集群状态恢复到正常所需的时间最短,并且对IO的影响也较小。
3 代码分析
PG split整个过程分为两步操作,修改pg_num和pgp_num。
1)修改pg_num和pgp_num的操作实际上会转化为OSDmap的变化,Leader Monitor会负责更新map。
//monitor收到命令
Pipe::reader() /* read msgs from socket */
->Pipe::read_message()
->Message::decode_message()
->new MCommand() (MSG_MON_COMMAND)
->DispatchQueue::fast_dispatch();(Or queued)
->Messanger::ms_fast_dispatch();
//monitor处理命令
Monitor::handle_command() Monitor.cc
->PaxosService::dispatch()
->OSDMonitor::preprocess_query() (MSG_MON_COMMAND)
->OSDMonitor::preprocess_command()
->OSDMonitor::prepare_update()
->OSDMonitor::prepare_command()
->OSDMonitor::prepare_command_impl(osd pool set)
->prepare_command_pool_set()
Monitor的操作只是完成了ceph的pg_num/pgp_num的修改,并在Mon之间同步好新的OSD map,然后发布map。
2) Monitor更新完map后,会发布新的map给相应的OSD
monc 和mon通信,然后扔到osd的_dispatch()里面进行统一处理(OSD::_dispatch)
-> OSD::handle_osd_map()
-> OSD::consume_map()里面处理pg split.
-> OSDService::expand_pg_num()来进一步处理拆分流程。
-> OSDService::_maybe_split_pgid() //pg的拆分以及拆哪个都是通过spg_t pg_t,
-> queue_null()把pg扔到peering队列。
这一步主要是根据mask和seed检查得出哪些pg需要split。
3)OSD开始处理peering队列里的事件
ThreadPool::worker()
-> _void_process() BatchWorkQueue
->_process() OSD::PeeringWQ处理pg的状态机
->OSD::process_peering_events()
->OSD::advance_pg()
-> OSD::split_pgs()
-> OSD::split_colls()
-> OSD::split_into()
collections就是一个objects的集合,其实就是一个pg。从上面的代码来看,pg split()操作的核心就是split_colls()和split_into()两个函数,下面接着它们。
4)split_colls()函数
该函数包括两步:创建collection和分裂collection
A)create_collection() (OP_MKCOLL)
OpWQ::store->_do_op() (FileStore::_do_op)
->FileStore::_do_transactions()
->FileStore::_create_collection()
-> ::mkdir() //创建文件夹
-> init_index() //为目录创建索引
-> _set_replay_guard()
B) split_collection() (OP_SPLIT_COLLECTION2)
OpWQ::store->_do_op() (FileStore::_do_op)
->FileStore::_do_transactions()
->FileStore::_split_collection()
->FileStore::_set_global_replay_guard()
->sync_filesystem(“/var/lib/ceph/osd/ceph-*/”)
->chain_fsetxattr(fd,GLOBAL_REPLAY_GUARD_XATTR)
->::fsync(fd)
->FileStore::_set_replay_guard(srcfd)
->::fsync(fd)
->object_map->sync(hoid, &spos)
->chain_fsetxattr(fd,REPLAY_GUARD_XATTR)//record what we did
->::fsync(fd);
->FileStore::_set_replay_guard(dstfd)
->from->split();
HashIndex::_split()
HashIndex::col_split_level()
a)找出需要移动的sub目录以及object
b)create相应的目录
c)srccol.start_col_split();
InProgressOp op_tag(InProgressOp::COL_SPLIT, path);
op_tag.encode(bl);
add_attr_path();
fsync_dir();
d)dstcol.start_col_split();
e)move_subdir(from, to, path);
f)move_object(from, to, path);
g)set_info(to_info)/set_info(from_info);
h)end_split_or_merge(path);
5)split_into()
A)更新pg以及pg log相关信息包括,last_complete,last_update, last_user_version, log_tail
/**
* map a pg to its acting set as well as its up set. You must use
* the acting set for data mapping purposes, but some users will
* also find the up set useful for things like deciding what to
* set as pg_temp.
* Each of these pointers must be non-NULL.
*/
B)pg_to_up_acting_osds()//设置active osd set和up osd set,并选出对应的primary
-> _pg_to_osds() //执行crush算法,算出的osd列表作为raw osd,并找出primary
-> crush->find_rule()
-> crush->do_rule()
-> _apply_primary_affinity()
-> _raw_to_up_osds() //从raw中找出up的osd集合
-> _apply_primary_affinity() //处理设置了primary affinity的osd
-> _get_temp_osds()
C)init_primary_up_acting()//
D)OSDMap::calc_pg_role() //根据acting osd集合,计算出pg的角色
E)split_ops(child)
-> split_replay_queue()
-> osd->dequeue_pg(), 将pg存入waiting_for_peered队列中,
-> OSD::split_list(waiting_for_peered)
-> OSD::split_list(waiting_for_map)
如果m_seed & mask,则将request插入到child中执行。
4 结论
总的来说,在firefly版本通过小幅度增加pg_num和pgp_num,进行pg 分裂操作是可行的。修改pg_num时,会通过计算得出哪些pg需要split,创建相应的collection并在OSD内移动数据。修改pgp_num时,会导致pg执行Crush算法,数据会在整个集群范围内进行平衡。
关于作者:
乔建峰,UnitedStack有云存储Team的PTL,四年的传统存储驱动程序开发经验,熟悉SCSI、FC、iSCSI、iSER协议,目前主要专注于Ceph、OpenStack社区。
Ceph pg分裂流程及可行性分析的更多相关文章
- ceph PG数量调整/PG的状态说明
优化: PG Number PG和PGP数量一定要根据OSD的数量进行调整,计算公式如下,但是最后算出的结果一定要接近或者等于一个2的指数.调整PGP不会引起PG内的对象的分裂,但是会引起PG的分布的 ...
- Ceph PG介绍及故障状态和修复
1 PG介绍pg的全称是placement group,中文译为放置组,是用于放置object的一个载体,pg的创建是在创建ceph存储池的时候指定的,同时跟指定的副本数也有关系,比如是3副本的则会有 ...
- 利用火焰图分析ceph pg分布
前言 性能优化大神Brendan Gregg发明了火焰图来定位性能问题,通过图表就可以发现问题出在哪里,通过svg矢量图来查看性能卡在哪个点,哪个操作占用的资源最多 在查看了原始数据后,这个分析的原理 ...
- 记一次ceph pg unfound处理过程
今天检查ceph集群,发现有pg丢失,于是就有了本文~~~ 1.查看集群状态 [root@k8snode001 ~]# ceph health detail HEALTH_ERR 1/973013 o ...
- [转] 关于 Ceph PG
本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...
- ceph增加osd流程
假如需要新增一个主机名:osd4 ip:192.168.0.110的OSD1.在osd4创建挂载目录及放置配置文件的目录 ssh 192.168.0.110 (这里是从mon主机ssh到osd4主机) ...
- Ceph源码解析:读写流程
转载注明出处,整理也是需要功夫的,http://www.cnblogs.com/chenxianpao/p/5572859.html 一.OSD模块简介 1.1 消息封装:在OSD上发送和接收信息. ...
- Ceph中PG和PGP的区别
http://www.zphj1987.com/2016/10/19/Ceph%E4%B8%ADPG%E5%92%8CPGP%E7%9A%84%E5%8C%BA%E5%88%AB/ 一.前言 首先来一 ...
- 分布式存储Ceph之PG状态详解
https://www.jianshu.com/p/36c2d5682d87 1. PG介绍 继上次分享的<Ceph介绍及原理架构分享>,这次主要来分享Ceph中的PG各种状态详解,PG是 ...
随机推荐
- python模块学习(四)
re模块 就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C ...
- 我的Android进阶之旅------>Android使用9Patch图片作为不失真背景
做人要大度,海纳百川,做事要圆滑,左右逢源,这让我想到了编程也是如此,代码要扩展,界面也要考虑自适应. 这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用. 1 ...
- PAT 1069. 微博转发抽奖(20)
小明PAT考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔N个人就发出一个红包.请你编写程序帮助他确定中奖名单. 输入格式: 输入第一行给出三个正整数M(<= 1000).N ...
- 剑指offer 面试33题
面试33题:题:二叉搜索树的后序遍历序列 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 解题思路:递 ...
- python常用模块-2
一 .time模块 表示时间的三种方式: 时间戳:数字(计算机能认识的) 时间字符串:t='2012-12-12' 结构化时间:time.struct_time(tm_year=2017, tm_mo ...
- 希望and目标
软件工程是一门枯燥的课程,这门课我不喜欢上,容易犯困,但就因为如此.我不得不好好的学习,我希望在这门课上.我能将基础学扎实,在实践上可以自己慢慢研究,我的目标不是很远大,学好.学扎实..在这门课上一周 ...
- HackerRank - maximum-perimeter-triangle 【水】
题意 给出一系列数字,判断其中哪三个数字可以构成一个三角形,如果有多个,输出周长最大的那个,如果没有输出 - 1 思路 数据较小,所有情况FOR一遍 判断一下 AC代码 #include <cs ...
- Loadrunder之脚本篇——参数化同行取值
select next row 记录选择方式 Same line as,这个选项只有当参数多余一个时才会出现,其作用是根据某一个参数的行号取同一行. 例中的做法如下: 将多个参数存放在一个参数文件中: ...
- iOS 11 Xcode9开发 新特性学习 (新方法篇)
1 . 引入github (1) 在Xcode 9 中,引入了 gitHub,新源代码管理导航器 可以展示branch分支和 tag标签. (2)点进去,就可以看指定一次commit了哪些东西 2 ...
- Spring_HelloWord
环境:IntelliJ 14 : jdk1.8 Spring操作步骤 1.新建项目---Spring Batch 2.IntelliJ会自动加载jar包 3.现在就可以在src目录下写Java类文 ...