深入理解ceph-disk运行机制
谷忠言
一,背景
目前项目所用的ceph集群内部的一个节点, 一般需要管理大约十块硬盘左右的数据存储空间,外加一到两块ssd组成的journal空间。Ceph要求每个osd对应的数据盘挂载到特定的目录,对应的ssd的journal分区也不能加载错,否则osd 无法启动。
目前对于数据盘的挂载采用的是基于/etc/fstab的方式。
上图是某个节点的/etc/fstab的实例。/dev/slot* 是一个由diskctl_init.sh 脚本产生的从/dev/slot* 到/dev/sdx的映射。如下图所示。
Diskctl_init.sh的原理是生成的slot 与主板物理槽位磁盘接口形成固定映射,这样当盘符漂移的时候,/dev/slot* 始终对应物理槽位的磁盘。只要磁盘不插拔更换物理槽位,osd 就能加载正确的数据盘。
而对于ssd journal分区,则是直接采用的journalà盘符的裸映射。
存在的问题:
1. Ssd journal分区的盘符裸映射, 有时候会导致机器重启,ceph服务起不来。测试发现,正是由于盘符漂移,裸映射成为死链。
2. Diskctl_init.sh 生成的slot 映射, 据同事反映,也可能有潜在的问题。具体细节不详。
二,调研ceph-disk
Ceph-disk 是官方发布的一个用于部署osd 数据及journal分区或目录的工具。基于python.安装ceph rpm包将默认安装此工具,安装目录是/usr/sbin/ceph-disk。由于此工具涉及数据盘及journal盘的分区。需要root权限。
ceph-disk 是如何工作的?
通过ceph-disk 部署osd, 数据分区和journal 分区将自动挂载到正确的目录,机器重启也能保证工作。通过ceph-disk部署osd, 将大大提高ceph部署运维的自动化程度,并降低操作出错几率。
以新创建OSD为例,描述ceph-disk的工作机制。
分为两大步骤:prepare disk 和activate disk
假设/dev/sdg是OSD要使用的数据盘, /dev/sdk 是SSD, OSD要使用的journal分区在这里创建。则创建OSD 并上线的命令如下:
Ceph-disk prepare /dev/sdg /dev/sdk
Ceph-disk activate /dev/sdg1
下面详细深入其过程。
1. 准备journal分区。
Prepare_journal_dev()调用分区工具sgdisk从/dev/sdk上划分一块journal分区。
有以下注意要点:
a. 在调用sgdisk之前,prepare_journal_dev()会获取ceph.conf文件中指定的osd_journal_size大小,我们的ceph.conf指定大小如下:
b. 实际部署环境中,由于作为journal的ssd分区并不需要很大空间,所以一个ssd很可能被多个osd共享来划分各自的journal分区,我们的环境是,一个300G的ssd 划分成5个(甚至更多的)20G的分区,挂载成5个osd的journal.
c. Ceph-disk 在部署journal分区的时候,能自动侦测SSD盘已有分区数,不破坏已有分区,分配不冲突的新分区号来创建分区。
d. 如果不指定创建分区的uuid,ceph-disk会自动为journal分区生成一个,称之为journal_uuid.
e. 在调用sgdisk的时候,还有一个重要的参数,--typecode. Ceph-disk 使用一个特殊的UUID 作为创建journal的typecode:
至于为何用此特殊UUID做typecode, 基本上此UUID可作为辨识分区为ceph journal的凭证,稍后深入解释。
至此,prepare_journal_dev()已经准备好了sgdisk所需的各个参数,下面给出一个实际发生的参数例子:
/usr/sbin/sgdisk --new=6:0:+20480M--change-name="6:ceph journal" --partition-guid=6:c6422c03-d320-4633-b35d-4f43c6cdd9fa--typecode=6:45b0969e-9b03-4f30-b4c6-b4b80ceff106 --mbrtogpt -- /dev/sdk
2. 在目录/dev/disk/by-partuuid/下为此journal分区创建link:
简单介绍一下这个link如何产生的。
在调用sgdisk 创建完journal分区后,ceph-disk 调用partx更新分区表,会触发一个块设备/分区udev event并通知到内核。Ceph编写了udev规则文件如下:
Udev daemon在收到由partx产生的udev event后,根据以上的ceph规则文件,将调用/usr/sbin/ceph-disk-udev脚本。正是在这个脚本里,在目录/dev/disk/by-partuuid/下为此journal分区创建了link。此脚本还有另外一个扫描OSD专属分区的功能,后文会提及。暂时不表。
这个link有什么用?
由于这个link是根据partition uuid生成的,可以把它看成是到特定journal分区的固定映射。后文会指出osd的journal将映射到此link:
由此图看出,位于osd 数据分区里的journal是一个link,指向一个固定的位置:/dev/disk/by-partuuid/c6422c03-d320-4633-b35d-4f43c6cdd9fa, 再由这个link指向真正的journal分区,由此解决的盘符漂移带来的问题。下文介绍的osd 数据分区的link也是基于此原理。
3. 准备OSD数据分区。
这个过程跟准备journal分区大体一样。区别在于:
a. 调用sgdisk 使用—largest-new来使用磁盘最大可能空间。所以/dev/sdg会有一个分区sdg1,它使用所有的空间。
b. 格式化/dev/sdg1。这里对ceph-disk做了小的定制,默认使用了ext4分区格式。
c. 将此分区mount到一个临时的目录,然后再其中创建一个名为journal的link,指向/dev/disk/by-partuuid/c6422c03-d320-4633-b35d-4f43c6cdd9fa。至此,OSD的journal分区映射完成。最后umount。
d. 再次调用sgdisk,写入一个重要的参数,--typecode. Ceph-disk 使用一个特殊的UUID 作为创建OSD的typecode:
同JOURNAL_UUID, 为何用此特殊UUID做typecode, 是因为此UUID可作为辨识分区为ceph OSD数据分区的凭证,稍后深入解释。
4. 在目录/dev/disk/by-partuuid/下为此OSD 数据分区创建link。
过程同journal的link创建过程。
5. Activate过程。
Activate的命令是 ceph-disk activate /dev/sdg1。
但其实并不需要显式的调用这个命令。原因是,准备好OSD 数据分区后,udev event 触发了ceph-disk-udev。而ceph-disk-udev会自动调用ceph-disk activate /dev/sdg1。
下面介绍这个过程是如何自动化的。详情参见ceph-disk-udev脚本。
新的OSD 数据分区的生成,触发udev event, 通过ceph udev rule,最终调用ceph-disk-udev,分析该分区的typecode,发现是OSD_UUID,即表明是ceph OSD的数据分区,于是触发ceph-disk activate /dev/sdg1:
Typecode 为JOURNAL_UUID的情况也一样,只不过是通过ceph-disk activate-journal 来启动OSD.
在介绍ceph-disk activate /dev/sdg1的具体流程。
a. 将/dev/sdg1 挂载至临时目录,一般为var/lib/ceph/tmp/mnt.xxx
b. 分配OSD id,及调用ceph osd create 产生 osd id
c. 初始化OSD, 如ceph-osd –mkfs –osd-data –osd-journal
d. 根据osd id 重新挂载到最终目录: var/lib/{cluster}/osd/ceph-{osd.id}
e. Service ceph start osd
对于osd id 已经存在,重启osd的case,也会用到ceph-disk activate,这种情况稍有不同,不需要产生新的osd id,只需要将/dev/sdg1挂载至临时目录,获取osd id后,重新挂载到最终目录。
Ceph-disk 支持的其他命令如下:
prepare Prepare a directory or disk for aCeph OSD
activate Activate a Ceph OSD
activate-journal Activate an OSD via its journal device
activate-all Activate all tagged OSD partitions
list List disks, partitions, and CephOSDs
suppress-activate Suppress activate on a device (prefix)
unsuppress-activate
Stop suppressingactivate on a device (prefix)
zap Zap/erase/destroy a device'spartition table (and
contents)
特别强调几点:
a. Suppress的字面意思就是抑制,用在这里的意图主要是,如果只想prepare各个分区,暂时不想activate OSD(创建osd 上线),可以使用此命令,等到所有的分区都prepare好了,unsuppress 一把,再activate-all.
b. Activate-journal 是通过制定journal 分区来启动osd, 如:ceph-diskactivate-journal /dev/sdk6. Ceph-disk 执行的流程为:
通过 ceph-osd -i 0 --get-journal-uuid --osd-journal /dev/sdk6 返回osd_uuid. 有了osd_uuid,就能找到osd 数据分区了,即定位/dev/disk/by-partuuid/$osd_uuid,这样就回到了使用osd 数据分区来activate的命令逻辑,即ceph-disk activate /dev/sdg1。
这里要解释 为什么是ceph-osd-i 0?在此条命令中, -i 后面可以跟任何一个整数,在get-journal-uuid中会被忽略。但问题是,不加-i, ceph-osd格式检查就会报错。
还有就是—get-journal-uuid,字面意思好像是获取journal分区的uuid,但实际上返回的一个叫journal.header 结构体里的fsid. 此fsid的值就是 osd 数据分区的uuid. 所以命令ceph-osd -i 0 --get-journal-uuid --osd-journal /dev/sdk6 返回值是osd_uuid。不得不抱怨一把,这个命令太容易让人产生混乱。理清逻辑是从源码中分析得来的。从这个小问题可以看出开源软件比起商业软件,细处略显粗糙,还需精细打磨。
c. 如果prepare不显式指定 journal, 如 ceph-disk prepare /dev/sdg, 则处理逻辑为:
在sdg上划出两个分区,sdg2 为20G的journal分区,sdg1为剩下空间大小的osd 数据分区。
注意事项
Ceph-disk的定制:
1. default fstype ext4
2. keyring的问题,由于目前的ceph部署没有enablekeyring,所以屏蔽了相关代码。
ceph-disk –v将打印更详细的log, 如果想深入理解ceph-disk命令的运行过程,此参数非常有效。
权限问题:
chmod -R 777/home/ceph/software/ceph/var/lib/ceph/osd/ceph-*
删除OSD产生的死链问题。