通过套接字管理服务
Ceph 的各个守护进程运行时都会监听一个对应的套接字文件,我们可以通过对应的套接字文件来对相应的服务进行管理。
套接字文件存放与 /var/run/ceph/ 目录下,如:
$ ls /var/run/ceph/
ceph-client.rgw.ceph-node1.1051.94830126918064.asok ceph-mgr.ceph-node1.asok ceph-mon.ceph-node1.asok ceph-osd.0.asok ceph-osd.1.asok ceph-osd.2.asok
通过 ceph-osd 进程的套接字文件进行管理:
$ ceph --admin-socket /var/run/ceph-osd.0.asok --help
通过 ceph-mon 进程的套接字文件进行管理:
$ ceph --admin-daemon /var/run/ceph/ceph-mon.ceph-node1.asok help
要通过套接字文件管理对应服务的前提是:用户在对应主机上必须有 admin 权限且可正常执行 ceph -s 操作。
重启或停止集群
重启之前,要提前设置 Ceph 集群不要将 OSD 标记为 out,避免 node 节点关闭服务后被踢出 Ceph 集群外。
# 关闭服务前设置 noout
$ ceph osd set noout
# 启动服务后取消设置 noout
$ ceph osd unset noout
关闭顺序:
- 关闭服务前设置 noout;
- 关闭存储客户端停止读写数据;
- 如果使用了 RGW,则关闭 RGW 服务 ;
- 关闭 CephFS 元数据服务;
- 关闭 Ceph OSD 服务;
- 关闭 Ceph Manager 服务;
- 关闭 Ceph Monitor 服务;
启动顺序:
- 启动 Ceph Monitor 服务;
- 启动 Ceph Manager 服务;
- 启动 Ceph OSD 服务;
- 启动 CephFS 元数据服务;
- 启动 RGW 服务;
- 启动存储客户端;
- 最后取消 noout 设置;
时钟漂移
有时候我们的 Ceph 集群会出现这样的警告:
$ ceph -s
cluster:
id: 2a71ed03-5918-4126-a2ec-8fd8ac173627
health: HEALTH_WARN
clock skew detected on mon.ceph-node2
...
如上有一个警告为 clock skew detected on mon.ceph-node2,这是因为各节点的系统的时间差太大,Ceph 对各节点的时间差默认要求很严格,此时我们可以通过调大允许的时间差来解决这个问题:
# 在 ceph-mon 服务所在节点添加如下配置,然后重启 ceph-mon 服务即可生效
$ cat /etc/ceph/ceph.conf
...
# 默认值 0.05,监视器允许监测到各个 node 节点的时间偏差在 0.05 秒内
mon clock drift allowed = 3
# 如果监测到时间偏差连续 10 次超过上面设置的时长,则会在 ceph -s 输出告警信息
mon clock drift warn backoff = 10
在所有 mon 节点执行重启 ceph-mon 服务操作
============================
`$ systemctl restart ceph-mon@ceph-node<x>.service`
添加新节点
以添加 192.168.0.24 为 ceph-node4 节点为例。
1、给节点设置主机名、安装 python2 并添加 Ceph 仓库源:
$ hostnamectl set-hostname ceph-node4
$ wget -q -O- 'https://download.ceph.com/keys/release.asc' | sudo apt-key add -
$ sudo apt-add-repository 'deb https://mirrors.tuna.tsinghua.edu.cn/ceph/debian-pacific/ bionic main'
$ sudo apt update
$ apt install python2.7 -y && ln -sv /usr/bin/python2.7 /usr/bin/python2
2、修改所有 Ceph 节点的 /etc/hosts 解析:
192.168.0.21 ceph-node1.zze.xyz ceph-node1
192.168.0.22 ceph-node2.zze.xyz ceph-node2
192.168.0.23 ceph-node3.zze.xyz ceph-node3
192.168.0.24 ceph-node4.zze.xyz ceph-node4
3、在新节点创建管理用户并配置与原来的 Ceph 集群节点免密通信:
$ groupadd -r -g 2022 cephadmin && useradd -r -m -s /bin/bash -u 2022 -g 2022 cephadmin && echo cephadmin:ceph1234 | chpasswd
$ su - cephadmin
# 从原集群节点拷贝秘钥到新节点
$ scp -rp ceph-node1:/home/cephadmin/.ssh /home/cephadmin/
$ vim /etc/sudoers
# 添加一行
cephadmin ALL=(ALL:ALL) NOPASSWD:ALL
4、在原管理节点执行初始化操作并添加新 node 节点的 OSD 到当前集群:
# 初始化新 node 节点
$ ceph-deploy install --release pacific --no-adjust-repos --nogpgcheck ceph-node4
# 擦除新 node 节点上的数据盘
$ ceph-deploy disk zap ceph-node4 /dev/sdb /dev/sdc /dev/sdd
# 添加 OSD
$ ceph-deploy osd create ceph-node4 --data /dev/sdb
$ ceph-deploy osd create ceph-node4 --data /dev/sdc
$ ceph-deploy osd create ceph-node4 --data /dev/sdd
删除已有节点
停止服务器之前要把服务器的 OSD 先停止并从 Ceph 集群移除,下面演示删除 ceph-node4 节点的操作。
1、查看 ceph-node4 上有哪些 OSD:
$ ceph osd status | grep ceph-node4
9 ceph-node4 41.3M 19.9G 0 0 0 0 exists,up
10 ceph-node4 31.4M 19.9G 0 0 0 0 exists,up
11 ceph-node4 22.6M 19.9G 0 0 0 0 exists,up
2、将 ID 为 9 的 OSD 标记为踢出:
$ ceph osd out 9
刚执行移除 OSD 操作后 Ceph 会再平衡被移除 OSD 的数据到其它 OSD 上,这个过程的时长会受到该 OSD 所承载的数据量大小的影响,数据量越大则平衡时间越久,可以看到如下状态:
$ ceph health
HEALTH_WARN Reduced data availability: 19 pgs inactive, 81 pgs peering
等待集群状态重新恢复 HEALTH_OK:
$ ceph health
HEALTH_OK
3、从 crush map 中移除 ID 为 9 的 OSD 并删除它的认证信息:
$ ceph osd rm 9
# 从 crush map 删除 osd
$ ceph osd crush remove osd.9
$ ceph auth del osd.9
4、确保当前集群状态是 HEALTH_OK 后停止对应 OSD 进程:
$ ceph health
HEALTH_OK
# 在待删除节点停止 OSD 进程
$ systemctl stop ceph-osd@9.service
5、循环上述操作直至待删除节点上的所有 OSD 被移除完毕后即可下线该节点。
# 在 Ceph 管理节点清空该节点所有 Ceph 相关包和数据,可选
$ ceph-deploy purge ceph-node4
配置文件
Ceph 的主配置文件是 /etc/ceph/ceph.conf,Ceph 服务在启动时会检查它。在改配置文件中分号 ; 和 # 都是注释,ceph.conf 主要由以下配置段组成:
[global] # 全局配置
[osd] # osd 专用配置,可以使用 osd.N 来表示 ID 为 N 的 ceph-osd 进程的专用的配置
[mon] # mon 专用配置,也可以使用 mon.A 来表示某一个 monitor 节点的专用配置,其中 A 是对应节点的名称,使用 ceph mon dump 可以查看节点名称
[client] # 客户端专用配置
ceph.conf 还可以放置在 /etc/ceph/ 目录以外的地方,当同时有多个 ceph.conf 配置时它们的加载顺序如下:
CEPH_CONF 环境变量指定的路径;
程序启动时使用 -c 选项指定的配置文件位置;
/etc/ceph/ceph.conf;
~/.ceph/ceph.conf;
./ceph.conf;
配置参考:http://docs.ceph.org.cn/rados/。
存储池
副本池(replicated):定义每个对象在集群中保存为多少个副本,默认为三个副本,一主两备实现高可用,副本池是 Ceph 默认的存储池类型。
纠删码池(erasure code):把各对象存储为 N=K+M 个块,其中 K 为数据块数量,M 为编码块数量,因此存储池的尺寸为 K+M。
即数据保存在 K 个数据块,并提供 M 个冗余块提供数据高可用,那么最多能故障的块就是 M 个,实际的磁盘占用就是 K+M 块,因此相比副本池机制比较节省存储资源,一般采用 8+4 机制,即 8 个数据块+ 4 个冗余块,那么也就是 12 个数据块有 8 个数据块保存数据。
有 4 个实现数据冗余,即 1/3 的磁盘空间用于数据冗余,比默认副本池的三倍冗余节省空间,但是不能出现大于一定数据块故障。
不是所有的应用都支持纠删码池,RBD 只支持副本池而 radosgw 则可以支持纠删码池。
相对来说纠删码池不是那么常用,因为使用 Ceph 本身很大程度就是看重 Ceph 的高可用,而纠删码池虽然能节省一定空间但也会降低高可用性,并且读写过程中编码计算的过程也会有一定的性能损耗。
副本池
将一个数据对象存储为多个副本。
Ceph 使用 CRUSH 算法计算出与对象相对应的 PGID 和 主 OSD,将数据写入主 OSD。主 OSD 根据设置的副本数、对象名称、存储池名称和集群运行图(cluster map)计算出 PG 的各辅助 OSD,然后由主 OSD 将数据再同步给辅助 OSD。
读取数据:
客户端发送请求,RADOS 将请求发送到主 OSD;
主 OSD 从本地磁盘读取数据并返回数据,最终完成读请求;
写入数据:
客户端请求写人数据,RADOS发送数据到主 OSD;
主 OSD 识别副本 OSDs,并发送数据到各副本 OSD;
副本 OSDs 写人数据,并发送写入完成信号给主 OSD;
主 OSD 响应写入完成信号给客户端;
纠删码池
Ceph 从 Firefly 版本开始支持纠删码,但是不推荐在生产环境使用纠删码池。
纠删码池降低了数据保存所需要的磁盘总空间数量,但是读写数据的计算成本要比副本池高,RGW 可以支持纠删码池,RBD 不支持纠删码池。
读取数据:
从相应的 OSDs 获取数据;
编码计算出完整数据返回给客户端;
写入数据:
数据将在主 OSD 进行编码然后分发到相应的 OSDs 上去;
计算合适的数据块并进行编码;
对每个数据块进行编码并写入 OSD;
创建纠删码池:
$ ceph osd pool create erasure-pool 32 32 erasure
查看默认的纠删码池配置:
$ ceph osd erasure-code-profile get default
k=2 # 为数据块的数量,即要将原始对象分割成的块数量。例如,如果 k=2,则会将一个 10kB 对象分割成各为 5kB 的 k 个对象.
m=2 # 编码块(chunk)的数量,即编码函数计算的额外块的数量.如果有 2 个编码块,则表示有两个额外的备份,最多可以从当前 pg 中宕机 2 个 OSD 而不会丢失数据。
plugin=jerasure # 默认的纠删码池插件
technique=reed_sol_van
写入数据:
$ rados put -p erasure-pool testfile /var/log/syslog
验证数据:
$ ceph osd map erasure-pool testfile
osdmap e590 pool 'erasure-pool' (10) object 'testfile' -> pg 10.551a2b36 (10.16) -> up ([3,NONE,0,8], p3) acting ([3,NONE,0,8], p3)
查看纠删码池的 PG 状态:
$ ceph pg ls-by-pool erasure-pool | awk '{print $1,$2,$15}'
PG OBJECTS ACTING
10.0 0 [5,8,2,NONE]p5
10.1 0 [8,4,2,NONE]p8
10.2 0 [1,4,NONE,6]p1
...
PG 与 PGP
PG,Placement Group,归置组。
PGP,Placement Group for Placement purpose,归置组的组合,相当于是 PG 对应的 OSD 的排列组合关系。
官方推荐 PG 和 PGP 的数量相同。
归置组(placement group)是用于跨越多 OSD 将数据存储在存储池中的内部数据结构。归置组在 OSD 守护进程和 Ceph 客户端之间生成了一个中间层,CRUSH 算法负责将每个对象动态映射到一个归置组,然后再将每个归置组动态映射到一个或多个 OSD 守护进程,从而能够支持在新的 OSD 设备上线时进行数据重新平衡。
相对于存储池来说, PG 是一个虚拟组件,它是对象映射到存储池时使用的虚拟层。
可以自定义存储池中的归置组数量。
Ceph 出于规模伸缩及性能方面的考虑,Ceph 将存储池细分为多个归置组。把每个单独的对象映射到归置组,并为归置组分配一个主 OSD。
存储池由一系列的归置组组成,而 CRUSH 算法则根据集群运行图和集群状态,将每个 PG 均匀、伪随机(基于 hash 映射,每次的计算结果一致)的分布到集群中的 OSD 之上。
如果某个 OSD 挂掉或需要对集群进行重新平衡,Ceph 则移动或复制整个归置组而不需要单独对每个镜像进行寻址。
Ceph 基于 CRUSH 算法将归置组 PG 分配至 OSD。
当一个客户端存储对象的时候,CRUSH 算法映射每一个对象至归置组。
归置组(PG)的数量是由管理员在创建存储池的时候指定的,然后由 CRUSH 负责创建和使用,PG 的数量是 2 的 N 次方的倍数,每个 OSD 的 PG 不要超出 250 个 PG,官方推荐是每个 OSD 100 个左右 PG。
所以集群总的 PG 数量就可以按如下方式计算:
OSD 数量 * 100 / 副本数
此方式计算出的 PG 数量是总数量,假如有 12 个 OSD,使用默认的 3 副本,按如上方式进行计算:
12 * 100 / 3 = 400
上面的计算结果只是可参考的集群总的 PG 数量,而 PG 是针对存储池来说的,所以创建存储池时指定多少个 PG 还需要事先预估一下各存储池的容量使用情况,并且指定的 PG 数量要求是 2 的 n 次方。
比如计划有三个存储池 A、B、C,计划它们分别占集群总容量的比例分别为 2:4:4,所以:
A 存储池 PG 数量:400/10*2=80,取 64 或 128
B 存储池 PG 数量:400/10*4=160,取 128 或 256
C 存储池 PG 数量:400/10*2=160,取 128 或 256
通常,PG 的数量应该是数据的合理力度的子集。
例如:一个包含 256 个 PG 的存储池,每个 PG 中包含大约 1/256 的存储池数据。
当需要将 PG 从一个 OSD 移动到另一个 OSD 的时候,PG 的数量会对性能产生影响。PG 的数量过少、一个 OSD 上保存的数据会相对加多,那么 Ceph 同步数据的时候产生的网络负载将对集群的性能输出产生一定影响。PG 过多的时候,Ceph 将会占用过多的 CPU 和内存资源用于记录 PG 的状态信息。
PG的数量在集群分发数据和重新平衡时扮演者重要的角色作用。
在所有 OSD 质检进行数据持久存储以及完成数据分布会需要较多的归置组,但是他们的数量应该减少到实现 Ceph 最大性能所需的最小 PG 数量值,以节省 CPU 和内存资源。一般来说,对于有着超过 50 个 OSD 的 RADOS 集群,建议每个 OSD 大约有 50-100 个 PG 以平衡资源使用及取得更好的数据持久性和数据分布,而在更大的集群中。每个 OSD 可以有 100-200 个 PG。
删除存储池
默认情况下 ceph-mon 进程是会阻止删除存储池的操作的执行的,如下:
$ ceph osd pool rm erasure-pool erasure-pool --yes-i-really-really-mean-it
Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool
如果要允许删除这个操作,则需要额外的配置。
第一种方式是直接注入修改当前 ceph-mon 进程的运行时参数:
$ ceph tell mon.* injectargs --mon-allow-pool-delete=true
第二种方式是修改 ceph-mon 的配置,添加如下参数然后重启 ceph-mon 进程:
$ vim /etc/ceph/conf
...
[mon]
mon allow pool delete = true
然后就可以成功删除存储池,如:
$ ceph osd pool rm erasure-pool erasure-pool --yes-i-really-really-mean-it
pool 'erasure-pool' removed
PG 的状态
Peering
正在同步状态,同一个 PG 中的 OSD 需要将数据同步一致,而 Peering (对等)就是 OSD 同步过程中的状态。
Activating
Peering 已经完成,PG 正在等待所有 PG 实例同步 Peering 的结果。
Clean
干净态,PG 当前不存在待修复的对象。并且大小等于存储池的副本数,即 PG 的活动集(Acting Set)和上行集(up Set)为同一组 OSD 且内容一致。
活动集(Acting Set): PG 当前主的 OSD 和其余处于活动状态的备用 OSD 组成,当前 PG 内的 OSD 负责处理用户的读写请求。
上行集(up Set):在某一个 OSD 故障时,需要将故障的 OSD 更换为可用的 OSD,并将 PG 内部的主 OSD 同步数据到新的 OSD 上,例如 PG 内有 OSD1、OSD2、OSD3,当 OSD3 故障后需要用 OSD4 替换 OSD3,那么 OSD1、OSD2、OSD3 就是上行集,替换后 OSD1、OSD2、OSD4 就是活动集,OSD 替换完成后活动集最终要替换上行集。
Active
就绪状态或活跃状态,Active 表示主 OSD 和备 OSD 处于正常工作状态,此时的 PG 可以正常处理来自客户端的读写请求,正常的 PG 默认就是 Active+Clean 状态。
$ ceph pg stat
297 pgs: 297 active+clean; 14 MiB data, 935 MiB used, 179 GiB / 180 GiB avail
Degraded
降级状态,降级状态出现于 OSD 被标记为 down 以后,那么其他映射到此 OSD 的 PG 都会转换到降级状态。
如果此 OSD 还能重新启动完成并完成 Peering 操作后,那么使用此 OSD 的 PG 将重新恢复为 Clean 状态。
如果此 OSD 被标记为 down 的时间超过 5 分钟还没有修复,那么此 OSD 将会被 Ceph 踢出集群,然后 Ceph 会对被降级的 PG 启动恢复操作,直到所有由于此 OSD 而被降级的 PG 重新恢复为 clean 状态。
恢复数据会从 PG 内的主 OSD 恢复,如果是主 OSD 故障,那么会在剩下的两个备用 OSD 重新选择一个作为主 OSD。
Stale
过期状态,正常状态下,每个主 OSD 都要周期性的向 RADOS 集群中的监视器(Mon)报告其作为主 OSD 所持有的所有 PG 的最新统计数据,因任何原因导致某个 OSD 无法正常向监视器发送汇报信息的、或者由其他 OSD 报告某个 OSD 已经 down 的时候,则所有以此 OSD 为主 PG 则会立即被标记为 stale 状态,即他们的主 OSD 已经不是最新的数据了,如果是备份的 OSD 发生 down 的时候,则 Ceph 会执行修复而不会触发 PG 状态转换为 Stale 状态。
Undersized
PG 当前副本数小于其存储池定义的值的时候,PG 会转换为 Undersized 状态,比如两个备份 OSD 都 down 了,那么此时 PG 中就只有一个主 OSD 了,不符合 Ceph 最少要求一个主 OSD 加一个备 OSD 的要求,那么就会导致使用此 OSD 的 PG 转换为 undersized 状态,直到添加备份 OSD 添加完成,或者修复完成。
Scrubbing
Scrubbing 是 Ceph 对数据的清洗状态,用来保证数据完整性的机制,Ceph 的 OSD 定期启动 Scrub 线程来扫描部分对象,通过与其他副本比对来发现是否一致,如果存在不一致,抛出异常提示用户手动解决,scrub 以 PG 为单位,对于每一个 PG,Ceph 分析该 PG 下所有的 object,产生一个类似于元数据信息摘要的数据结构,如对象大小,属性等,叫 scrubmap。比较主与副 scrubmap,来确认是不是有 object 丢失或者不匹配,扫描分为轻量级扫描和深度扫描,轻量级扫描也叫做 light scrubs 或者 shallow scrubs 或者 simply scrubs。
Light scrub(daily)比较 object size 和属性,deep scrub(weekly)读取数据部分并通过 checksum(CRC32算法)对比和数据的一致性,深度扫描过程中的 PG 会处于 scrubbing +deep 状态。
Recovering
正在恢复态,集群正在执行迁移或同步对象和他们的副本,这可能是由于添加了一个新的 OSD 到集群中或者某个 OSD 宕掉后。PG 可能会被 CRUSH 算法重新分配不同的 OSD,而由于 OSD 更换导致 PG 发生内部数据同步的过程中的 PG 会被标记为 Recovering。
Backfilling
正在后台填充态,backfill 是 recovery 的一种特殊场景,指 peering 完成后,如果基于当前权威日志无法对 UpSet(上行集)当中的某些 PG 实例实施增量同步(例如承载这些 PG 实例的 OSD 离线太久,或者是新的 OSD 加人集群导致的 PG 实例整体迁移)则通过完全拷贝当前 Primary 所有对象的方式进行全量同步,此过程中的 PG 会处于 backfilling。
Backfill-toofull
某个需要被 Backfilling 的 PG 实例,其所在的 OSD 可用空间不足,Backfilling 流程当前被挂起时 PG 的状态。