Ceph是加州大学Santa Cruz分校的Sage Weil(DreamHost的联合创始人)专为博士论文(PhD)设计的新一代自由软件分布式文件系统。自2007年毕业之后,Sage开始全职投入到Ceph开发之中,使其能适用于生产环境。
Ceph的主要目标是设计成基于POSIX的没有单点故障的(SPoF)分布式文件系统,容量轻松扩展到数PB,数据能够容错和无缝复制。2010年3月,Linus Torvalds将Ceph client合并到内核2.6.34中(Ceph Dependencies)。
不幸的是,这些目标之间会互相竞争(例如,可扩展性会降低或者抑制性能或者影响可靠性)。Ceph 开发了一些非常有趣的概念(例如,动态元数据分区,去中心化的数据分布和多副本存储),Ceph 的设计还包括保护单一点故障的容错功能,它假设大规模(PB 级存储)存储故障是常见现象而不是例外情况。
低开销(内核级的驱动支持,性能更高,不影响用户级更新功能完善) 灵活性(统一底层object对象存储,上层提供fs,block,radosgw,librados接口,方便开发) 扩展性(容量设计可达PB级别) 完整性(PAXOS分布式选举和CURSH存储算法) 开源代码(更加透明安全,迭代更快,社区反馈和推广都相对成熟,代码会越来越完善)
对Btrfs依赖强,但btrfs目前还不成熟,临时解决方法是使用xfs来替换 ceph的程序整体成熟度欠佳,会有内存泄漏和OSD/MON 偶发crash的异常出现
对象存储系统的基本问题是如何分布数据到上千个存储设备上?
一个robust解决方案是把数据随机分布到存储设备上,这个方法能够保证负载均衡,保证新旧数据混合在一起。但是简单HASH分布不能有效处理设备数量的变化,导致大量数据迁移。
Ceph开发了CRUSH(Controled Replication Under Scalable Hashing),一种伪随机(确定性)的数据分布算法,它能够在层级结构的存储集群中有效的分布对象的副本。
CRUSH算法函数只需要参数:object id或object group id,并返回一组存储设备(用于保存object副本)。 CRUSH需要cluster map(描述存储集群的层级结构)、和副本分布策略(rule)。
CRUSH有三个关键优点:
任何组件都可以独立计算出每个object所在的位置(去中心化)。 只需要很少的元数据(cluster map),只要当删除添加设备时,这些元数据才需要改变。 副本策略定义包括bucket, rock, host, row 三种角色和四种结构算法,搭配定制。
参考资料
CRUSH算法通过每个设备的权重来计算数据对象的分布。对象分布是由cluster map和data distribution policy决定的。cluster map描述了可用存储资源和层级结构(比如有多少个机架,每个机架上有多少个服务器,每个服务器上有多少个磁盘)。data distribution policy由placement rules组成。rule决定了每个数据对象有多少个副本,这些副本存储的限制条件(比如3个副本放在不同的机架中)。
CRUSH算出x到一组OSD集合(OSD是对象存储设备):
(osd0, osd1, osd2 … osdn) = CRUSH(x)
CRUSH利用多参数HASH函数,HASH函数中的参数包括x,使得从x到OSD集合是确定性的和独立的。CRUSH只使用了cluster map、placement rules、x。CRUSH是伪随机算法,相似输入的结果之间没有相关性。
参考资料
ceph中引入了PG(placement group)的概念,PG是一个虚拟的概念,并不对应什么实体,类似于逻辑分区,一个PG可存放多个对象,每个存储节点可有上百个PG(官方推荐值为100)。
一个PG(placement group)由一个OSD列表组成,OSD的个数,就是对象的副本数,如三副本的PG就是由一个主,两个副本的OSD列表组成。
首先是经过一个哈希函数把key映射到Placement Group(简称PG)。PG第二层是通过一致性哈希函数CRUSH从PGID映射到到实际存放数据的主机,对于给定PGID和副本数量,CRUSH会生成副本位置信息。其中第一个副本是主,其它为从。
主副本负责接收来自客户端的写,产生日志同步给从副本。如果出现多个客户端并发写,主副本也扮演协调者决定并发写的顺序。当少量机器发生宕机时,作为一致性哈希函数,CRUSH产生的PG副本的位置不会有很大改别。同时,缺失数据的其它副本散落在整个集群,这就保证了补齐副本数据时可以利用整个集群的网络带宽。
| MooseFS(MFS) | Ceph | GlusterFS | Lustre | |
|---|---|---|---|---|
| Metadata server | 单个MDS。存在单点故障和瓶颈。 | 多个MDS,不存在单点故障和瓶颈。MDS可以扩展,不存在瓶颈。 | 无,不存在单点故障。靠运行在各个节点上的动态算法来代替MDS,不需同步元数据,无硬盘I/O瓶颈。 | 双MDS(互相备份)。MDS不可以扩展,存在瓶颈。 |
| FUSE | 支持 | 支持 | 支持 | 支持 |
| 访问接口 | POSIX | POSIX | POSIX | POSIX/MPI |
| 文件分布/数据分布 | 文件被分片,数据块保存在不同的存储服务器上。 | 文件被分片,每个数据块是一个对象。对象保存在不同的存储服务器上。 | Cluster Translators(GlusterFS集群存储的核心)包括AFR、DHT和Stripe三种类型。AFR相当于RAID1,每个文件都被复制到多个存储节点上。Stripe相当于RAID0,文件被分片,数据被条带化到各个存储节点上。Translators可以组合,即AFR和stripe可以组成RAID10,实现高性能和高可用。 | 可以把大文件分片并以类似RAID0的方式分散存储在多个存储节点 |
| 冗余保护/副本 | 多副本 | 多副本 | 镜像 | 无 |
| 数据可靠性 | 由数据的多副本提供可靠性。 | 由数据的多副本提供可靠性。 | 由镜像提供可靠性。 | 由存储节点上的RAID1或RAID5/6提供可靠性。假如存储节点失效,则数据不可用。 |
| 备份 | 提供备份工具。支持远程备份。 | |||
| 故障恢复 | 手动恢复 | 当节点失效时,自动迁移数据、重新复制副本。 | 当节点、硬件、磁盘、网络发生故障时,系统会自动处理这些故障,管理员不需介入。 | 无 |
| 扩展性 | 增加存储服务器,可以提高容量和文件操作性能。但是由于不能增加MDS,因此元数据操作性能不能提高,是整个系统的瓶颈。 | 可以增加元数据服务器和存储节点。容量可扩展。文件操作性能可扩展。元数据操作性能可扩展。 | 容量可扩展。 | 可增加存储节点,提高容量可文件操作性能,但是由于不能增加MDS,因此元数据操作性能不能提高,是整个系统的瓶颈。 |
| 安装/部署 | 简单 | 简单 | 简单 | 复杂。而且Lustre严重依赖内核,需要重新编译内核。 |
| 开发语言 | C | C++ | C | C |
| 适合场景 | 大量小文件读写 | 小文件 | 适合大文件。对于小文件,无元数据服务设计解决了元数据的问题。但GlusterFS并没有在I/O方面作优化,在存储服务器底层文件系统上仍然是大量小文件,本地文件系统元数据访问是瓶颈,数据分布和并行性也无法充分发挥作用。因此,GlusterFS的小文件性能还存在很大优化空间。 | 大文件读写 |
| 产品级别 | 小型 | 中型 | 中型 | 重型 |
| 应用 | 国内较多 | 无 | 较多用户使用 | HPC的集群任务调度器 |
| 优缺点 | 实施简单,但是存在单点故障。 | 不稳定,目前还在实验阶段,不适合于生产环境。 | 无元数据服务器,堆栈式架构(基本功能模块可以进行堆栈式组合,实现强大功能)。具有线性横向扩展能力。由于没有元数据服务器,因此增加了客户端的负载,占用相当的CPU和内存。但遍历文件目录时,则实现较为复杂和低效,需要搜索所有的存储节点。因此不建议使用较深的路径。 | 很成熟 |
OS-NODE1 客户端,测试前端 OS-FS1 Ceph OSD,MON,MDS,一块系统盘,两块OSD数据盘(/dev/sdb1,/dev/sdc1) XFS文件系统 (mkfs.xfs -l internal,lazy-count=1,size=128m -i attr=2 -d agcount=8 -i size=512) mount -t xfs -o rw,swalloc,noexec,nodev,noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k Ceph 0.56(Notable) 性能好于 v0.55(bobtail),0.48(argonaut) kenel >= 3.6.x livirt >= 0.9.13 qemu >= 0.14
v3.6.6 or later in the v3.6 stable series v3.4.20 or later in the v3.4 stable series
CONFIGBTRFSFS=m CONFIGBTRFSFSPOSIXACL=y # CONFIGBTRFSFSCHECKINTEGRITY is not set CONFIGCEPHFS=m CONFIGCEPHLIB=m CONFIGCEPHLIBPRETTYDEBUG=y - CONFIGCEPHLIBUSEDNSRESOLVER=y CONFIGBLKDEVDRBD=m - # CONFIGDRBDFAULTINJECTION is not set
yum install -y cryptopp.x86_64 cryptopp-devel.x86_64 libedit.x86_64 libedit-devel.x86_64 \ libatomic_ops-devel.x86_64 snappy.x86_64 snappy-devel.x86_64 boost-devel.x86_64 ./configure --prefix=/usr/local --sysconfdir=/etc --localstatedir=/var \ --without-hadoop --without-nss --without-fuse --without-debug \ --with-tcmalloc --with-rest-bench \ --disable-static --disable-cephfs-java
[global] ; For version 0.55 and beyond, you must explicitly enable ; or disable authentication with "auth" entries in [global]. auth cluster required = cephx auth service required = cephx auth client required = cephx keyring = /etc/ceph/keyring [osd] osd data = /srv/ceph/osd$id osd journal = /srv/ceph/osd$id/journal osd journal size = 512 keyring = /etc/ceph/keyring.$name osd mkfs type = xfs ; solve rbd data corruption (sileht: disable by default in 0.48) filestore fiemap = false ; The following assumes ext4 filesystem. filestore xattr use omap = true [mon] mon data = /srv/ceph/mon$id [mon.a] host = OS-FS1 mon addr = 192.168.10.2:6789 [osd.0] host = OS-FS1 devs = /dev/sdb1 [osd.1] host = OS-FS1 devs = /dev/sdc1
mkcephfs -a -c /etc/ceph/ceph.conf #也支持导入crushmap,osdmap mkcephfs -a -c /etc/ceph/ceph.conf --crushmap /etc/ceph/crush.map --osdmap /etc/ceph/osd.map
mount -t ceph 192.168.10.2:6789:/ /srv/ -o name=admin,secret=$(awk '/key/{print $3}' /etc/ceph/ceph.keyring)
rados lspools rados mkpool nova rados rmpool nova rbd list [nova] rbd create foo --pool nova --size 4096 rbd map foo --pool rbd --name client.admin rbd map foo --pool nova --keyring /etc/ceph/ceph.keyring rbd showmapped rbd unmap /dev/rbd6
[root@OS-NODE1 ~]# rbd map foo --pool nova --keyring /etc/ceph/ceph.keyring [root@OS-NODE1 ~]# rbd showmapped id pool image snap device 1 nova foo - /dev/rbd1 [root@OS-NODE1 ~]# mkfs.xfs -d agcount=4 -l size=32m /dev/rbd1 [root@OS-NODE1 ~]# mount /dev/rbd1 /mnt/ceph/
添加mon.3
假设已经有两台服务器组合成集群,各自运行监视器和OSD集群,如今要添加一台新的机器,充当第三个监视器。
登录集群中的话任意机器,命令导出 authmap,monmap,osdmap →生成 keyring
ceph auth get mon. -o authmap ceph mon getmap -o monmap ceph osd getmap -o osdmap #生成mon.3运行环境 ceph-mon -c /etc/ceph/ceph.conf --mkfs --monmap monmap --osdmap osdmap -k authmap -i 3 #启动mon.3 #/etc/init.d/ceph start mon.3 #/etc/init.d/ceph -a restart mon #这时候可以看到集群中的其它机器,看到mon.3的加入了 #ceph -s #如果没有加入,手动添加节点 #ceph mon add 3 192.168.0.99:6789在ceph.conf中添加节点,保证下回能够正常启动删除mon.3
#ceph mon remove 3 # vi /etc/ceph/ceph.conf 移除mon.3 #/etc/init.d/ceph -a restart mon从ceph.conf中去除节点,保证下回能够正常启动
[osd.2] host = OS-FS1 devs = /dev/sda3 ............ [root@OS-FS1 ceph]# ceph osd create osd.2 2 [root@OS-FS1 ceph]# ceph-osd -i 2 --mkfs --mkkey 2013-01-09 11:21:39 -1 created object store /srv/ceph/osd2 journal /srv/ceph/osd2/journal for osd.2 fsid 2013-01-09 11:21:39 -1 created new key in keyring /srv/ceph/osd2/keyring [root@OS-FS1 ceph]# ceph auth add osd.2 osd 'allow *' mon 'allow rwx' -i /srv/ceph/osd2/keyring 2013-01-09 16:26:24.614887 7f731523e760 -1 read 56 bytes from /srv/ceph/osd2/keyring added key for osd.2 [root@OS-FS1 ceph]# ceph osd getcrushmap -o map [root@OS-FS1 ceph]# crushtool -d map -o map.txt # 编译文件加入新的节点信息 [root@OS-FS1 ceph]# crushtool -c map.txt -o newmap [root@OS-FS1 ceph]# ceph osd setcrushmap -i newmap 2013-01-09 16:36:16.830139 7fa24c4fd760 -1 read 542 bytes from newmap set crush map [root@OS-FS1 ceph]# ceph -s health HEALTH_OK monmap e1: 1 mons at {a=192.168.10.2:6789/0}, election epoch 2, quorum 0 a osdmap e9: 3 osds: 3 up, 3 in pgmap v353: 576 pgs: 576 active+clean; 8730 bytes data, 1646 MB used, 939 GB / 941 GB avail mdsmap e4: 1/1/1 up {0=a=up:active}ceph auth add必须添加,否则权限报错!
ceph osd setmaxosd很重要# 先在集群中导出monmap,然后拷贝到新节点 ceph mon getmap -o monmap # 在新增的OSD节点上运行先运行 easyCeph.sh genConfig生成ceph.conf配置文件,然后运行以下命令 for i in `sed -r -n "/\[osd.[0-9]*\]/s@\[osd.(.*)\]@\1@gp" /etc/ceph/ceph.conf`;do ceph-osd -c /etc/ceph/ceph.conf --monmap monmap -i $i --mkfs --mkkey done # 拷贝OSD节点上的keyring.*到集群中的/tmp临时目录下,运行auth导入集群的认证 cd /tmp for i in keyring.osd.*;do ii=${i#keyring.osd.} ceph auth add osd.$ii osd 'allow *' mon 'allow rwx' -i /tmp/keyring.osd.$ii done # 检查keyring是否正确导入 ceph auth list #################################################################### # 在新节点上重新编译easyCeph.sh主机列表,生成新的ceph.conf和crushmap,然后分别导入到所有机器上生效 ./easyCeph.sh genConfig;./easyCeph.sh genCrushmap;./easyCeph.sh syncConfig #################################################################### # 在集群的任意节点上放大maxosd ceph osd setmaxosd 10000 # 在新的节点上启动OSD /etc/init.d/ceph start/restart osd,mon ceph osd crush set 301 osd.301 1.0 pool=default rack=rack-1 host=ceph3 ceph osd setcrushmap -i /etc/ceph/crush.map # OSD有up,down,in,out四种状态 # 从运行中的集群中移除故障OSD的步骤如下: ceph osd crush remove osd.301 ceph auth del osd.301 ceph osd down 301 ceph osd out 301 ceph osd rm 301 # 新增OSD并插入生产 ceph osd up 301 ceph osd in 301新增OSD的时候,最好是以rep size的倍数增加,可以降低degrade的比例,但不知是不是bug?
ceph osd down osd.301 /etc/init.d/ceph stop osd.301
Ceph立即感知到节点故障,开始做降级处理
ceph osd out 301
当我们把301这个节点摘除后,Ceph开始做数据平衡
/etc/init.d/ceph start osd.301 ceph osd in 301
重启节点,加入分布图,数据恢复中
先还原309号OSD,操作如下
umount /srv/ceph/osd309 mount -t xfs -o rw,noexec,nodev,noatime,nodiratime,barrier=0 -L /disk/sata9 /srv/ceph/osd309 /etc/init.d/ceph restart osd.309 ceph osd in 309
先还原301号OSD,操作如下
继续平衡数据,直到降级后的数据全部恢复(约15分钟恢复1OSD)
再来一次插拔,换个干净的硬盘添加进去
ceph osd out 310
dmesg | tail -5 -> /dev/sdb mkfs.xfs -f -l internal,lazy-count=1,size=128m -i attr=2 -d agcount=8 -i size=512 /dev/sdb xfs_admin -L /disk/sata10 /dev/sdb mount -t xfs -o rw,noexec,nodev,noatime,nodiratime,barrier=0 -L /disk/sata10 /srv/ceph/osd310
ceph mon getmap -o monmap ceph-osd -c /etc/ceph/ceph.conf --monmap monmap -i 310 --mkfs --mkkey ceph auth add osd.310 osd 'allow *' mon 'allow rwx' -i /etc/ceph/keyring.osd.310 ceph auth list ceph osd setmaxosd 10000
/etc/init.d/ceph restart osd.310 ceph osd in 310
When you create a pool, set the number of placement groups to a reasonable value (e.g., 100). Consider the total number of placement groups per OSD too. Placement groups are computationally expensive, so performance will degrade when you have many pools with many placement groups (e.g., 50 pools with 100 placement groups each). The point of diminishing returns depends upon the power of the OSD host.Important Increasing the number of placement groups in a pool after you create the pool is still an experimental feature in Bobtail (v 0.56). We recommend defining a reasonable number of placement groups and maintaining that number until Ceph’s placement group splitting and merging functionality matures.单个pool中的PG数量不能超过65536,多个池并存可以,但注意性能
ceph pg dump --format plain > pg_map awk '/^[0-9]\./{print $1,$14,$15}' pg_map | sort -k1n > pg_map.sort
pgs 排队等候开始回填
Ceph正在扫描并同步pgs的整个内容,而不是从最近操作的日志中推断出需要同步的内容。回填是一种特殊的恢复状态。
状态不一致,不干净
Ceph尚未将pgs组中的某些对象复制到完整的三副本状态
pgs组中的待正确放置位置的数据
配置组已经长时间处于非激活状态(比如,它一直无法处理读写请求)
配置组长时间未被清理(比如,它没有完全从上一个错误中恢复)
配置组的状态没有被OSD更新过,意味着所有存储在该配置组的节点都down掉了
每个osd分配一个journal,默认日志大小为1000M,可调整,这是个回环可以重复写的文件圈。
分离OSD的data和journal到不同设备,推荐用ssd来记录journal,可以提高整体性能。
检查各服务器上的Ceph安装版本是否一致
OSD的容量警告有两个级别:
health warning: mon osd nearfull ratio = .60 health error : mon osd full ratio = .95因此当ceph -s 报告容量警告时,一定要及时添加硬件资源,但到达95%会报Error。
此Error并非表示出错,只是ceph为了保证已经存在的数据的完整性,不再接受新数据写入的防御措施,但后果依然严重,要提前避免
现在在平衡数据的过程中,有时候会莫名其妙的发生osd hang的现象,进程依然在运行,但集群不能接受新数据,从日志上分析出现的slow request时间特别长,这时候,就需要restart osd,才能恢复,估计是软件bug.
解决思路
监控日志中的slow request的时间值和数据写入量是否为0,如果出现以上情况,则检查ceph pg dump_stuck unclean中出现频率最高的osd,并且重启
建议使用两个分开的网络,因为ceph支持两个网络:位于前端的公网、位于后端的集群网,可以防止OSD平衡数据或者遇到攻击时,导致延时增大和性能下降;当OSD间的流量中断时,归置组就再也不能进入active+clean状态了,它也会阻止用户读写数据。
杜绝此类问题发生的最佳方法就是彻底分开集群网和公网,推荐使用至少2个网卡
只有一个公网也可以,但仅限于内部演示。
osd: put large xattrs in leveldb osd: move pg info into leveldb mon: ObjectMap,key→value的map属性,其保存在levelDB
radosgw是遵循fastcgi协议的网关服务,可以通过前端的nginx/apache/varnish做负载均衡.
目前ceph版本,无论是不是有写入操作,增加pg/pgp数目,会造成ceph的osd崩溃,因此不建议线上调整假设单台机器12个磁盘=12个osd,
按照200台机器的规模算,12200100/3=80000,最多只能支持60000个pg_numEach placement group requires some amount of system resources: **Directly**: Each PG requires some amount of memory and CPU. **Indirectly**: The total number of PGs increases the peering count.PG不能设置过大,容易造成系统资源不足和性能瓶颈
尽可能多的OSD是集群中的负载平衡。 As many OSDs you have as better is the load-balance in the cluster. Let’s assume that you use 1 disk per OSD, it means that you will prefer 2 disk of 500G instead of 1T disk. SSD的使用大大提高了OSD的性能。 The usage of a SSD dramatically improves your OSD’s performance 副本数为2会带来比副本数为3更多的性能,但它的安全性较低。 Replica count of 2 brings more performance than a replica count of 3, but it’s less secure 使用专用的私有网络进行内部OSD复制确实可以提高性能。Using a dedicated private network for the internal OSDs replication really improve the performance 使用更高带宽的网络硬件来克服1G带宽限制很容易。 It’s really easy with decent hardware to overcome the 1G bandwidth limitation 将filestore flusher选项设置为false可以从根本上改善您的性能,主要是在旧系统。 Setting the filestore flusher option to false can radically improve your performance, mainly on old system 即使更多的pg意味着更好的负载平衡,但大量的pg并不会提高性能。 Even if more pg means better load-balance, setting a large number of pg doesn’t enhance your performance
Weighting Bucket Items
Ceph expresses bucket weights as double integers, which allows for fine weighting. A weight is the relative difference between device capacities. We recommend using 1.00 as the relative weight for a 1TB storage device. In such a scenario, a weight of 0.5 would represent approximately 500GB, and a weight of 3.00 would represent approximately 3TB. Higher level buckets have a weight that is the sum total of the leaf items aggregated by the bucket.
A bucket item weight is one dimensional, but you may also calculate your item weights to reflect the performance of the storage drive. For example, if you have many 1TB drives where some have relatively low data transfer rate and the others have a relatively high data transfer rate, you may weight them differently, even though they have the same capacity (e.g., a weight of 0.80 for the first set of drives with lower total throughput, and 1.20 for the second set of drives with higher total throughput).
修改weight会影响osdmap的变化
确保每个节点keyring文件中key值相同
/var/lib/ceph/mon/{ceph-node}/keyring
ceph osd pool set rbd pg_num 128 ceph osd pool set rbd pgp_num 128
[root@Mysql-SSD-Bakcup ~]# ceph health detail HEALTH_WARN clock skew detected on mon.DBS-SAD-018; Monitor clock skew detected mon.DBS-SAD-018 addr 192.168.147.18:6789/0 clock skew 40.2243s > max 5s (latency 0.000928916s)同步国际时间,如果执行完以上两步仍有报错,则需要重启所有monitor(/etc/init.d/ceph restart mon)
[root@MySQL-Backup ~]# ceph health detail HEALTH_ERR 1 pgs inconsistent; 1 pgs repair; 5 scrub errors pg 0.4a4 is active+clean+scrubbing+deep+inconsistent+repair, acting [15,4,49] 5 scrub errors [root@MySQL-Backup ~]# ceph osd find 15 { "osd": 15, "ip": "192.168.146.12:6832\/14224", "crush_location": { "host": "EBS-SAD-002", "root": "default" } } 问题PG:0.4a4 OSD编号:15,4,49
[root@MySQL-Backup ~]# ceph pg repair 0.4a4 instructing pg 0.4a4 on osd.15 to repair
要洗刷一个pg组,执行命令:
ceph pg scrub 0.4a4 ceph pg deep-scrub 0.4a4 ceph pg repair 0.4a4
修复pg所属的三块osd ,执行命令如下:
ceph osd repair 75 ceph osd repair 6 ceph osd repair 35
查询pg 使用主osd信息
ceph pg 2.37c query |grep primary # <-- 查询出哪个主 osd 号 journalctl -xeu ceph-osd@38 # <-- 查看日志有什么错误,删除那个 input/output error 所在的文件
删除md5sum报IO错误的文件,然后执行
ceph pg repair 14.16a
pg状态恢复正常
CEPH会定期(默认每个星期一次)对所有的PGs进行scrub,即通过检测PG中各个osds中数据是否一致来保证数据的安全。
当CEPH更换一块坏硬盘,进行数据修复后,出现了大量的PGs不能及时进行scrub,甚至有些PGs数据不一致,导致CEPH系统报警,如下所示:
Cluster Status:HEALTH_WARN 126 pgs not deep-scrubbed in time
此时,需要提高对PGs的scrub速度。默认情况下一个OSD近能同时进行一个scrub操作且仅当主机低于0.5时才进行scrub操作。我运维的CEPH系统一个PG对应10个OSDs,每个OSD仅能同时进行一个scrub操作,导致大量scrub操作需要等待,而同时进行的scrub操作数量一般为8个。因此需要在各台存储服务器上对其OSDs进行参数修改,来提高scrub速度。
ceph health detail|awk '/not deep-scrubbed since/{print "ceph pg deep-scrub "$2}'
[root@MySQL-Backup ~]# ceph health detail HEALTH_ERR 1 pgs are stuck inactive for more than 300 seconds; 1 pgs stale; 1 pgs stuck stale; 2 requests are blocked > 32 sec; 1 osds have slow requests pg 2.70 is stuck stale for 173219.873722, current state stale+active+clean, last acting [52] 2 ops are blocked > 131.072 sec on osd.52 1 osds have slow requests [root@EBS-SAD-005 ~]# ceph pg dump_stuck stale ok pg_stat state up up_primary acting acting_primary 2.70 stale+active+clean [52] 52 [52] 52 [root@MySQL-Backup deploy-key]# ceph pg map 2.70 osdmap e9983 pg 2.70 (2.70) -> up [52] acting [52]
[root@EBS-SAD-005 ~]# ceph pg 2.7 query > x.log # 留待排查 [root@EBS-SAD-005 ~]# ceph pg ls|grep ^2.70 2.70 866 0 0 0 0 3613425664 3006 3006 stale+active+clean 2019-01-26 10:04:28.891302 8106'2738703 8127:1254451 [52]
[root@MySQL-Backup ~]# ceph pg force_create_pg 2.70 pg 2.70 now creating, ok
dmesg | tail[96615.562272] rbd: image foo: image uses unsupported features: 0x38
for i in deep-flatten fast-diff object-map;do rbd feature disable foo $i;done一些编码的转译:exclusive-lock -> 0x4
sgdisk -Z /dev/sdb
解决办法: xfs_repair -L /dev/sdb1
在kubelet中追加配置
--runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice
在准备一台主机作为OSD或元数据服务器时,你得收集监视器、OSD、和MDS的初始密钥环,可用下列命令:
ceph-deploy gatherkeys EBS-SAD-002
那么就会先找
/etc/ceph/ceph.client.admin.keyring
然后再找
/var/lib/ceph/bootstrap-osd/ceph.keyring /var/lib/ceph/bootstrap-mds/ceph.keyring
实时返回集群中的密钥
a6ac67145475bbf202b6adb7c23ccb6f ceph.bootstrap-mds.keyring b8b37b5c940564f9fa6444d9a2f3d2cc ceph.bootstrap-mgr.keyring 28da5445fae3288df51aab15ccb27293 ceph.bootstrap-osd.keyring ce9876c07c4285c4138e0948dde80d86 ceph.bootstrap-rgw.keyring 591b0bb706aa2a688ec47201527d8cdd ceph.client.admin.keyring
systemctl start ceph.target # start all daemons or systemctl start ceph-osd.target # start osd daemons systemctl start ceph-mon.target # start mon daemons systemctl start ceph-mds.target # start mds daemons
systemctl start ceph-osd@{id} systemctl start ceph-mon@{hostname} systemctl start ceph-mds@{hostname}
systemctl status ceph-osd@12 # check status of osd.12
ceph osd pool get rbd pg_num ceph osd pool set rbd pg_num 1440 ceph osd pool set rbd pgp_num 1440 ceph osd pool rename rbd cold-mysql ceph osd pool ls detail #查看资源池的具体信息,包括副本数,pg_num,pgp_num ceph osd pool set poolname size X #设置资源池副本数 rbd create ssd_mysql --size 10000 #创建镜像空间大小,默认单位为G for i in exclusive-lock deep-flatten fast-diff object-map;do rbd feature disable gitlab-backup $i;done rbd mv ssd_mysql ssd-mysql rbd map/unmap/showmapped
blockdev --getsize64 /dev/rbd0 #获取镜像大小 rbd resize --size 20000 ssd-mysql #设置新的镜像大小 resize2fs /dev/rbd0 #动态扩容,如果是xfs则应该使用xfs_growfs
列举机器上的磁盘
ceph-deploy --ceph-conf /etc/ceph/ceph.conf disk list EBS-SAD-001 # ceph-disk list # lsof /dev/sdbxx # 判断哪个journal 与 osd 相对应
脚本判断挂载点及日志盘
#!/bin/sh sed -r -i '/ceph/d' /etc/fstab df -h|awk '/ceph-[0-9]/{print $1,$NF}' > /tmp/.xxx while read LINE;do dev=`echo $LINE|cut -f1 -d' '|cut -d'/' -f3` uuid=`blkid |sed -r -n "/$dev/s@.*(UUID=.*)@\1@gp"` dir=`echo $LINE|cut -f2 -d' '` journal_dev=$(blkid | grep `cat $dir/journal_uuid`|awk -F: '{print $1}') echo -e "#$uuid\t$dir\txfs\tdefaults 0 0\t# $dev -> $journal_dev" >> /etc/fstab done < /tmp/.xxx
找出对应盘符的磁盘
while `sleep 2`;do dd if=/dev/sdg1 of=/dev/null bs=300M count=10;done
检查磁盘是否健康的脚本
for dev in $(lsblk |grep -B1 ceph|awk '/^sd/{print $1}');do smartctl -A /dev/sdi|awk ' /^ 5/{if($NF>300) print "'$dev'"} /^188|^197|^198/{if($NF>100) print "'$dev'"} /^183/{if($NF>10) print "'$dev'"} ' done # smartctl -H /dev/$dev
# 增加或维护osd之前,先暂停数据平衡 for opt in nobackfill norebalance norecover noout;do ceph osd set $opt;done # set -> unset解除 # 摘除一个osd,但事先要获取设备名,盘符及日志盘分区 systemctl stop ceph-osd@3 ceph osd out osd.3 ceph osd crush rm 3 ceph auth del osd.3 ceph osd rm 3 umount /var/lib/ceph/osd/ceph-3 # 尝试修复osd磁盘,但不要强求能够恢复 xfs_repair /dev/sdo1 #修复分区,无法修复就更换磁盘 # 初始化新osd ceph-deploy --ceph-conf /etc/ceph/ceph.conf disk list EBS-SAD-002 ceph-deploy --ceph-conf /etc/ceph/ceph.conf disk zap EBS-SAD-002:sdg ceph-deploy --ceph-conf /etc/ceph/ceph.conf osd prepare EBS-SAD-002:sdg1:sdb6 ceph-deploy --ceph-conf /etc/ceph/ceph.conf osd activate EBS-SAD-002:sdg1:sdb6 ceph osd crush reweight osd.16 0.1
#!/bin/sh stop(){ for opt in nobackfill norebalance norecover noout;do ceph osd set $opt done systemctl stop ceph-osd@$ID ceph osd out osd.$ID ceph osd crush rm $ID ceph auth del osd.$ID ceph osd rm $ID umount /var/lib/ceph/osd/ceph-$ID } start(){ ceph-deploy disk zap EBS-SAD-001:sdf ceph-deploy osd prepare EBS-SAD-001:sdf:sdb5 ceph-deploy osd activate EBS-SAD-001:sdf1:sdb5 ceph osd crush reweight osd.3 3.63689 for opt in nobackfill norebalance norecover;do ceph osd unset $opt done } ID=$2 [ -z $ID ] && echo "$0 stop osd-id" && exit 0 case $1 in start) start;; stop) stop;; *) echo "$0 start|stop" exit 0;; esac
[global] fsid = 7a261d53-a9d0-493e-aa1f-d22ab9d55dbc mon_initial_members = EBS-SAD-001, EBS-SAD-002, EBS-SAD-003, EBS-SAD-004 mon_host = 192.168.146.11,192.168.146.12,192.168.146.13,192.168.146.14 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx mon_clock_drift_allowed = 5 osd_journal_size = 20480 public_network=192.168.0.0/16 max_open_files=131072 mon_osd_down_out_interval=86400 # 此参数有待验证
Ceph 支持对 rbd 快照创建很多 写时复制(Copy-on-write, COW) 克隆. 快照层次化能够使 Ceph 块设备客户端非常快速地建立镜像. 比如你可以创建一个块设备, 让一个 Linux VM 对其读写; 然后对镜像建立快照, 保护这一快照, 这样你就可以创建任意多的 COW 克隆体.
在了解了 Ceph RBD 的快照功能后, 我们就可以来看看如何通过快照来对 RBD image 进行备份. 过程也非常简单.
#!/bin/sh BASE_DIR=$(dirname $0) CONF_DIR=${BASE_DIR}/conf source $CONF_DIR/auth POOL="rbd" IMAGE="cold-db-76-77" NUMS="72" rbd snap list $POOL/$IMAGE > $IMAGE.list NUM=`wc -l $IMAGE.list | awk '{print $1}'` sleep $(($RANDOM%120)) if [ $NUM -gt $NUMS ];then diff=$((NUM-NUMS)) for id in $(sed -r -n "2,${diff}p" $IMAGE.list | awk '{print $2}');do rbd snap rm $POOL/$IMAGE@$id done fi #mysql -u$DB_USER -p$DB_PASSWD -e "FLUSH TABLES WITH READ LOCK" xfs_freeze -f /usr/mysqldata /usr/bin/rbd snap create $POOL/$IMAGE@`date +%Y%m%d-%H%M` xfs_freeze -u /usr/mysqldata
定时修复脚本 fixed_ceph.sh
#!/bin/sh FILE="/tmp/bad_ceph.log" dingding(){ curl 'https://oapi.dingtalk.com/robot/send?access_token=0f0b2e4b29ccedbfa6ef2b609dbbc1dbda3aa074c4f198337acad55119f3cba5' \ -H 'Content-Type: application/json' \ -d '{"msgtype": "text", "text": { "content": "[Ceph-new]:OSD.'"$1 $2"' " } }' } touch $FILE if [ -s $FILE ];then while read id;do echo $id ceph health detail | grep -q "$id .*repair" if [ $? != 0 ];then ceph health detail | grep -q "$id" if [ $? = 0 ];then dingding $id "bad to repaired" ceph pg repair $id else dingding $id "is OK" sed -r -i -e '/^$/d' -e "/$id/d" $FILE fi fi done < $FILE else ceph health detail | grep -iq err [ $? == 0 ] && (ceph health detail | sed -r -n 's@.* pg (.*) is (.*)@\1@gp' > $FILE) num=$(ceph health detail | grep -ic inactive) if [ $num -ge 2 ];then dingding PG_NOT_HEALTH " > $num" fi num=$(ceph health detail | awk '/PG_NOT_DEEP_SCRUBBED/{print $2}') if [ $num -ge 3 ];then dingding PG_NOT_DEEP_SCRUBBED " > $num" fi fi
[root@updbs-74-75 data]# rbd showmapped id pool image snap device 0 rbd cold-db-74-75 - /dev/rbd0 1 rbd backup-db-105 - /dev/rbd1
rbd resize rbd/backup-db-105 --size 4096G Resizing image: 100% complete...done.
[root@updbs-74-75 data]# xfs_growfs /sqlbackup/ meta-data=/dev/rbd1 isize=256 agcount=33, agsize=16382976 blks = sectsz=512 attr=2, projid32bit=1 = crc=0 finobt=0 data = bsize=4096 blocks=524288000, imaxpct=5 = sunit=1024 swidth=1024 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=0 log =internal bsize=4096 blocks=256000, version=2 = sectsz=512 sunit=8 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 data blocks changed from 524288000 to 1073741824
可以很清楚的看到三种不同的方法,最终的触发的迁移量是不同的,处理的好的话,能节约差不多一半的迁移的数据量,这个对于生产环境来说还是很好的,关于这个建议先在测试环境上进行测试,然后再操作,上面的操作只要不对磁盘进行格式化,操作都是可逆的,也就是可以比较放心的做,记住所做的操作,每一步都做完都去检查 PG 的状态是否是正常的
host EBS-SAD-001 EBS-SAD-002 EBS-SAD-003 EBS-SAD-004 EBS-SAD-005 EBS-SAD-006 ceph-master
Port 65422
Identityfile ~/.ssh/id_rsa
192.168.144.83 ceph-master 192.168.146.11 EBS-SAD-001 192.168.146.12 EBS-SAD-002 192.168.146.13 EBS-SAD-003 192.168.146.14 EBS-SAD-004 192.168.146.15 EBS-SAD-005 192.168.146.16 EBS-SAD-006
[global] fsid = 7a261d53-a9d0-493e-aa1f-d22ab9d55dbc mon_initial_members = EBS-SAD-001, EBS-SAD-002, EBS-SAD-003, EBS-SAD-004, EBS-SAD-005 mon_host = 192.168.146.11,192.168.146.12,192.168.146.13,192.168.146.14,192.168.146.15 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx mon_clock_drift_allowed = 5 osd_journal_size = 20480 public_network=192.168.0.0/16 max_open_files=131072 mon_osd_down_out_interval=86400
ceph-deploy --overwrite-conf config push EBS-SAD-001 EBS-SAD-002 EBS-SAD-003 EBS-SAD-004 EBS-SAD-005
ceph-deploy --overwrite-conf mon add EBS-SAD-005
prepare 命令只准备 OSD 。在大多数操作系统中,硬盘分区创建后,不用 activate 命令也会自动执行 activate 阶段(通过 Ceph 的 udev 规则)。详情见激活 OSD。
前提是:
Ceph cluster should be health “OK” state All placement groups (PGs) should be “active + clean” Set ceph osd noout to stop the rebalancing activity.
Update the ceph.conf file with desired journal size. set noout – so that no data migration start /etc/init.d/ceph stop osd.id ceph-osd -i <osdid> –flush-journal - cd /var/lib/ceph/osd/ceph-osd.1 && rm journal - ceph-osd –mkjournal -i <osd id> - /etc/init.d/ceph start osd.< id> - ceph –admin-daemon /var/run/ceph/ceph-osd.<osd-id>.asok config get osdjournal_size Finally unset the noout flag. : ceph osd unset noout
先执行ceph osd create,直到create出已经删除的osd的序号.
[root@EBS-SAD-005 /]# ceph osd create 52 [root@EBS-SAD-005 /]# ceph auth add osd.52 osd 'allow *' mon 'allow rwx' -i /var/lib/ceph/osd/ceph-52/keyring [root@EBS-SAD-005 /]# ceph osd crush add 52 3.63689 host=EBS-SAD-005 [root@EBS-SAD-005 /]# systemctl start ceph-osd@52
注意:在生产环境中,一般不会再新节点加入ceph集群后,立即开始数据回填,这样会影响集群性能。所以我们需要设置一些标志位,来完成这个目的。
#ceph osd set noin #ceph osd set nobackfill #ceph osd set norecover在用户访问的非高峰时,取消这些标志位,集群开始在平衡任务。
#ceph osd unset noin #ceph osd unset nobackfill #ceph osd unset norecover
ceph中两种类型分区的type code:
| type | type code |
|---|---|
| journal | 45b0969e-9b03-4f30-b4c6-b4b80ceff106 |
| osd | 4fbd7e29-9d25-41b8-afd0-062c0ceff05d |
在 /usr/lib/udev/rules.d/95-ceph-osd.rules 中可以看到:
# OSD_UUID ACTION=="add", SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-062c0ceff05d", \ OWNER:="ceph", GROUP:="ceph", MODE:="660", \ RUN+="/usr/sbin/ceph-disk --log-stdout -v trigger /dev/$name" ACTION=="change", SUBSYSTEM=="block", \ ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-062c0ceff05d", \ OWNER="ceph", GROUP="ceph", MODE="660" # JOURNAL_UUID ACTION=="add", SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="45b0969e-9b03-4f30-b4c6-b4b80ceff106", \ OWNER:="ceph", GROUP:="ceph", MODE:="660", \ RUN+="/usr/sbin/ceph-disk --log-stdout -v trigger /dev/$name" ACTION=="change", SUBSYSTEM=="block", \ ENV{ID_PART_ENTRY_TYPE}=="45b0969e-9b03-4f30-b4c6-b4b80ceff106", \ OWNER="ceph", GROUP="ceph", MODE="660"
ceph中创建journal分区和data分区:
sgdisk -n {part num}:0:+{part size}G {disk} -t {part num}:4fbd7e29-9d25-41b8-afd0-062c0ceff05d -c {part num}:”ceph data” sgdisk -n {part num}:0:+{part size}G {disk} -t {part num}:45b0969e-9b03-4f30-b4c6-b4b80ceff106 -c {part num}:”ceph journal”
删除原来的pool,必须要先删除fs,有顺序!
ceph osd pool ls ceph config set mon mon_allow_pool_delete true ceph fs rm cephfs --yes-i-really-mean-it ceph osd pool rm cephfs.cephfs.data cephfs.cephfs.data --yes-i-really-really-mean-it ceph osd pool rm cephfs.cephfs.meta cephfs.cephfs.meta --yes-i-really-really-mean-it ceph osd erasure-code-profile set gcec k=2 m=1 crush-failure-domain=host ceph osd pool create gcfsdata erasure gcec ceph osd pool set gcfsdata allow_ec_overwrites true ceph osd pool create gcfsmeta ceph fs new cephfs gcfsmeta gcfsdata --force
创建新的cephfs后,就需要给节点配置ceph.conf和cephfs.keyring
[global] fsid = a5d6a556-cce7-11ef-8106-6a1a3a5aac7e mon_host = [v2:10.17.4.201:3300/0,v1:10.17.4.201:6789/0] [v2:10.17.4.202:3300/0,v1:10.17.4.202:6789/0] [v2:10.17.4.203:3300/0,v1:10.17.4.203:6789/0] # /etc/ceph/ceph.client.cephfs.keyring [client.cephfs] key = AQCNHH1nRZdROBAA8qdXEC40sUl+jQ512dHBDA==
ceph-osd --flush-journal -i 56 ceph-osd --mkjournal -i 56
急救步骤
parted -m -s $dev rm 1 parted -m -s $dev mklabel gpt parted -m -s $dev mkpart primary xfs 2048s 100% partx -a $dev
制作脚本
#!/bin/sh journal_disk=/dev/sdb partition=1 for osd_id in {0..11}; do journal_uuid=$(sudo cat /var/lib/ceph/osd/ceph-$osd_id/journal_uuid) sgdisk --new=$partition:0:+20480M --change-name=$partition:'ceph journal' --partition-guid=$partition:$journal_uuid --typecode=$partition:$journal_uuid --mbrtogpt -- $journal_disk partprobe $journal_disk ceph-osd --mkjournal -i $osd_id echo systemctl start ceph-osd@$osd_id let partition+=1 done chown ceph.ceph ${journal_disk}*
ceph daemon /var/run/ceph/ceph-mon.asok config show|grep mon_osd_down_out_interval ceph daemon /var/run/ceph/ceph-mon.asok config set mon_osd_down_out_interval 86400
系统盘坏了,再也无法进入系统,时间紧张,来不及修复旧系统,直接用新ssd重装系统。 安装过程略…….
进入新系统后:
执行 ssh-keygen 创建临时公密钥,上传覆盖为自己的 执行 adjust-centos7.sh 优化系统,升级新内核 导入 /etc/yum.repos.d/ceph.repo ; yum install ceph 安装相关版本的软件 导入 /etc/hosts , 主机间需要通讯 拷贝 /etc/ceph/. 相关证书用于ceph命令 执行 checkcephmount.sh, 找出主机 osd whoami 与 journaluuid 之间的关联 - 执行 createcephjournal.sh, 重新创建 journaluuid 分区(sgdisk ; ceph-osd –mkjournal) 执行 chown -R ceph.ceph /dev/sdx(rules: KERNEL==“sdb*”, OWNER=“ceph”, GROUP=“ceph”, MODE=“0660”; udevadm trigger)
执行 systemctl start ceph-osd@osd_id
ceph又报警了,IP不通,连接显示器键盘无反应,重启机器后,开机点不亮,由此判断是硬件问题,赶紧带上家伙赶机房:
ssd磁盘(系统盘坏了要带,但此例不是它的问题) sata磁盘(数据盘,但开机不亮说明不是数据盘问题)赶到机房,先重新插拔内存条,看能不能起死回生,但是无用功,由此判断是主板问题(后发现是其中一条内存有问题),但短期之内不能立即联系到硬件厂商解决问题(先报修了,再自己想办法)
找一台配置相当的机器,至少要能够容纳12 * sata盘 + 2 * ssd盘 进入修复系统(为什么是修复系统,后面会说),发现网络起不来。。。 排查疑难一:网卡命名方式会改变,enps4f0 → ens7f0 类似xxx 排查疑难二:磁盘在不同的阵列卡,盘符居然也发生了变化,导致ceph的udev规则不能生效,后果是进不了系统,只好进修复系统排查,巨坑!!! 排查疑难三:由于是进了修复系统,手动要启动一系列进程(network,sshd),ceph osd也不能自动挂载了,于是现场搓了一段代码,挂载一个查看一个whoami,然后再挂载到正确的点上chown ceph:ceph /dev/sdxx
排查疑难四:ceph-osd启动失败,通过journalctl查看,是journal盘没有权限写入,这个是ceph的特性,可以把日志和数据分离,我猜是udev的规则没有开机启动加入相应的权限,于是排查udev规则,找到/usr/bin/systemctl --no-block restart ceph-disk@dev/sd${i}1.service至此,ceph节点恢复完毕,加入集群,开始平衡数据…
新版本的ceph支持祼盘引擎 bluestore,评测性能比xfs文件系统好太多了,所以就用了新的ceph版本和存储引擎,ceph会通过操作lvm来创建osd,好处是容易操作多种不同磁盘介质.
ceph-volume lvm zap /dev/sdg ceph-volume lvm prepare --bluestore --data /dev/sdg ceph-volume lvm activate --bluestore 133 2e4cc047-56ab-4fda-bd29-c924ea0ad097
ceph rdma协议的集群总是报daemons have recently crashed,而且数目越来越多,然并没有找到相关错误的日志
ceph health detail ceph crash archive-all ceph config set mgr mgr/crash/warn_recent_interval 0