├── .gitignore ├── Advance_usage ├── advanced_usage.md ├── cal_pg_per_osd.md ├── change_fd.md ├── change_osd_journal.md ├── find_rbd_data_loc.md ├── list_rbd_watcher.md ├── mon_backup.md ├── pg_active_remapped.md ├── pg_pgp.md ├── rbd_real_size.md └── rescue_osd_parted.md ├── Operation ├── add_rm_mon.md ├── add_rm_osd.md ├── change_cluster_conf.md ├── common_operations.md ├── log_debug.md ├── manage_crushmap.md ├── modify_mon_ip.md ├── monitor_cluster.md ├── monitor_osd.md ├── monitor_pg.md ├── operate_cluster.md ├── operate_pool.md └── user_management.md ├── README.md ├── SUMMARY.md └── Troubleshooting ├── troubleshooting.md ├── troubleshooting_lost_power.md ├── troubleshooting_mon.md ├── troubleshooting_osd.md ├── troubleshooting_pg.md └── troubleshooting_single_lost_power.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /Advance_usage/advanced_usage.md: -------------------------------------------------------------------------------- 1 | # 第三部分:Ceph 进阶 2 | 3 | 这部分内容介绍了一些 Ceph 使用中的进阶技巧,主要面向二线运维人员。 -------------------------------------------------------------------------------- /Advance_usage/cal_pg_per_osd.md: -------------------------------------------------------------------------------- 1 | # 9. 统计 OSD 上 PG 的数量 2 | 3 | ---------- 4 | 5 | 我们可以通过一个 Python 脚本,统计出每个 OSD 上分布了多少个 PG ,以此判断集群的数据分布是否均衡。 6 | 7 | #!/usr/bin/env python 8 | import sys 9 | import os 10 | import json 11 | cmd = ''' 12 | ceph pg dump | awk ' /^pg_stat/ { col=1; while($col!="up") {col++}; col++ } /^[0-9a-f]+\.[0-9a-f]+/ {print $1,$col}' 13 | ''' 14 | body = os.popen(cmd).read() 15 | SUM = {} 16 | for line in body.split('\n'): 17 | if not line.strip(): 18 | continue 19 | SUM[line.split()[0]] = json.loads(line.split()[1]) 20 | pool = set() 21 | for key in SUM: 22 | pool.add(key.split('.')[0]) 23 | mapping = {} 24 | for number in pool: 25 | for k,v in SUM.items(): 26 | if k.split('.')[0] == number: 27 | if number in mapping: 28 | mapping[number] += v 29 | else: 30 | mapping[number] = v 31 | MSG = """%(pool)-6s: %(pools)s | SUM 32 | %(line)s 33 | %(dy)s 34 | %(line)s 35 | %(sun)-6s: %(end)s |""" 36 | pools = " ".join(['%(a)-6s' % {"a": x} for x in sorted(list(mapping))]) 37 | line = len(pools) + 20 38 | MA = {} 39 | OSD = [] 40 | for p in mapping: 41 | osd = sorted(list(set(mapping[p]))) 42 | OSD += osd 43 | count = sum([mapping[p].count(x) for x in osd]) 44 | osds = {} 45 | for x in osd: 46 | osds[x] = mapping[p].count(x) 47 | MA[p] = {"osd": osds, "count": count} 48 | MA = sorted(MA.items(), key=lambda x:x[0]) 49 | OSD = sorted(list(set(OSD))) 50 | DY = "" 51 | for osd in OSD: 52 | count = sum([x[1]["osd"].get(osd,0) for x in MA]) 53 | w = ["%(x)-6s" % {"x": x[1]["osd"].get(osd,0)} for x in MA] 54 | #print w 55 | w.append("| %(x)-6s" % {"x": count}) 56 | DY += 'osd.%(osd)-3s %(osds)s\n' % {"osd": osd, "osds": " ".join(w)} 57 | SUM = " ".join(["%(x)-6s" % {"x": x[1]["count"]} for x in MA]) 58 | msg = {"pool": "pool", "pools": pools, "line": "-" * line, "dy": DY, "end": SUM, "sun": "SUM"} 59 | print MSG % msg 60 | 61 | 执行效果如下: 62 | 63 | root@OPS-ceph1:~# ./cal_pg_per_osd.py 64 | dumped all in format plain 65 | pool : 0 1 2 3 4 5 7 | SUM 66 | -------------------------------------------------------------------- 67 | osd.0 2 9 11 10 5 6 1 | 44 68 | osd.1 1 7 8 10 8 9 3 | 46 69 | osd.2 2 11 7 6 6 8 4 | 44 70 | osd.3 1 11 7 9 7 4 1 | 40 71 | osd.4 2 12 12 12 11 13 0 | 62 72 | osd.5 2 10 10 5 9 11 0 | 47 73 | osd.6 3 56 47 49 38 43 16 | 252 74 | osd.7 6 36 48 45 55 42 10 | 242 75 | osd.8 4 41 42 37 35 49 15 | 223 76 | osd.9 6 42 52 41 55 36 12 | 244 77 | osd.10 10 36 47 51 39 43 15 | 241 78 | osd.11 6 56 47 44 41 46 12 | 252 79 | osd.12 6 40 45 45 51 46 11 | 244 80 | osd.13 6 42 40 56 46 44 9 | 243 81 | osd.14 5 44 41 49 48 52 7 | 246 82 | osd.15 4 50 42 38 49 38 12 | 233 83 | osd.16 3 9 5 11 8 8 2 | 46 84 | osd.17 2 10 13 4 7 10 2 | 48 85 | osd.18 0 12 10 10 10 9 6 | 57 86 | osd.19 0 13 8 4 9 15 2 | 51 87 | osd.20 1 11 7 9 9 15 2 | 54 88 | osd.21 0 7 12 10 6 12 1 | 48 89 | osd.22 4 39 45 30 43 46 12 | 219 90 | osd.23 6 44 38 44 38 41 6 | 217 91 | osd.24 7 37 50 49 49 36 8 | 236 92 | osd.25 10 28 38 44 40 32 11 | 203 93 | osd.26 1 44 33 47 47 37 13 | 222 94 | osd.27 3 47 38 42 44 55 14 | 243 95 | osd.28 4 47 47 34 33 48 11 | 224 96 | osd.29 3 40 32 34 40 51 10 | 210 97 | osd.30 8 39 46 47 55 35 10 | 240 98 | osd.31 5 48 48 45 41 36 11 | 234 99 | osd.32 5 46 48 53 42 48 7 | 249 100 | 101 | -------------------------------------------------------------------- 102 | SUM : 128 1024 1024 1024 1024 1024 256 | -------------------------------------------------------------------------------- /Advance_usage/change_fd.md: -------------------------------------------------------------------------------- 1 | # 3. 修改 Cinder/Glance 进程的最大可用 FD 2 | 3 | ---------- 4 | 5 | 本篇内容是根据生产环境中遇到的实际问题进行的总结。 6 | 7 | ### 背景 8 | 9 | 在生产环境中遇到这样一个问题: 10 | 下发删除卷消息无法成功删除卷,后通过 cinder 命令行命令 `cinder service-list` 查询cinder 服务状态,发现 `cinder-volume host : r2202002controller@rbd-sata` 服务状态为 `DOWN` 。 11 | 12 | | cinder-volume | r2202002controller@rbd-sata | nova | enabled | down | 13 | 14 | 该状态表明该 cinder-volume 进程已经没有正常上报心跳,处于无法处理请求的状态。 15 | 16 | ### 原因分析 17 | 18 | 通过现场复现问题和查看 cinder-volume 日志,发现在出问题的时间点都有删除卷的操作下发,但是有的卷一直未结束删除卷流程,直到重启 cinder-volume 进程时才恢复。 19 | 20 | 2016-09-23 13:42:48.176 44907 INFO cinder.volume.manager [req-0182ed51-a4a7-44e4-bd3e-3d456610a135 ff01ec05ed4442799ebad096c1aa2921 584c5f2fed764ec9b840319eb2cd0608 - - -] volume b38ea39e-b1f5-4af6-a7b1-40fe1d5e80ee: deleting 21 | 22 | 2016-09-23 16:52:08.290 52145 INFO cinder.volume.manager [req-be3fe7fc-39fe-4bc3-9a70-d5be1e7330ce - - - - -] Resuming delete on volume: b38ea39e-b1f5-4af6-a7b1-40fe1d5e80ee 23 | 24 | 怀疑在删除 RDB 卷流程有挂死问题,通过进一步查看日志,发现最后走到调用 RDB Client 删除卷时就中断了: 25 | 26 | 2016-09-23 13:43:27.911 44907 DEBUG cinder.volume.drivers.rbd [req-0182ed51-a4a7-44e4-bd3e-3d456610a135 ff01ec05ed4442799ebad096c1aa2921 584c5f2fed764ec9b840319eb2cd0608 - - -] deleting rbd volume volume-b38ea39e-b1f5-4af6-a7b1-40fe1d5e80 delete_volume /usr/local/lib/python2.7/dist-packages/cinder/volume/drivers/rbd.py:666 27 | 28 | 因为该问题发生在 Ceph 集群扩容后,因此进一步怀疑和之前 Nova 挂卷后读取变慢问题一样是由于进程打开文件过多引起异常,后在实验环境中通过打开 RDB client 日志,重启 cinder-volume 进程。 29 | 30 | [client] 31 | rbd cache = true 32 | rbd cache writethrough until flush = true 33 | log file = /var/log/ceph/ceph.client.log 34 | debug client = 20 35 | debug rbd = 20 36 | debug librbd = 20 37 | debug objectcacher = 20 38 | 39 | 然后增加 cinder-volume 进程删卷时的打开文件数成功复现该问题。RDB client 日志中报 `too many open files` 异常,后在生产环境上通过复现问题和打开 RDB Client 日志观察到同样的异常,因此可以确定是由于扩容后 OSD 节点增多,RDB client 删除卷时需要和所有 OSD 建立 socket 链接,这样就会超过目前环境中 cinder-volume 进程允许打开的文件数,导致异常发生,进入挂死状态。 40 | 41 | 2016-09-26 20:08:48.953810 7f099566b700 -1 -- 192.168.219.2:0/43062437 >> 192.168.219.130:6812/12006 pipe(0x7f0acdcdc090 sd=-1 :0 s=1 pgs=0 cs=0 l=1 c=0x7f0acdcae7e0).connect couldn't created socket (24) Too many open files 42 | 2016-09-26 20:08:48.953803 7f099556a700 -1 -- 192.168.219.2:0/43062437 >> 192.168.219.113:6802/2740 pipe(0x7f0acdce0330 sd=-1 :0 s=1 pgs=0 cs=0 l=1 c=0x7f0acdcb2210).connect couldn't created socket (24) Too many open files 43 | 2016-09-26 20:08:48.953898 7f0995267700 -1 -- 192.168.219.2:0/43062437 >> 192.168.219.179:6812/31845 pipe(0x7f0acdcf12f0 sd=-1 :0 s=1 pgs=0 cs=0 l=1 c=0x7f0acdced990).connect couldn't created socket (24) Too many open files 44 | 2016-09-26 20:08:48.953913 7f099596e700 -1 -- 192.168.219.2:0/43062437 >> 192.168.219.169:6804/8418 pipe(0x7f0acdccd2f0 sd=-1 :0 s=1 pgs=0 cs=0 l=1 c=0x7f0acdcc0a90).connect couldn't created socket (24) Too many open files 45 | 2016-09-26 20:08:48.953932 7f0995368700 -1 -- 192.168.219.2:0/43062437 >> 192.168.219.136:6806/23096 pipe(0x7f0acdce8f40 sd=-1 :0 s=1 pgs=0 cs=0 l=1 c=0x7f0acdcc7cf0).connect couldn't created socket (24) Too many open files 46 | 47 | ### 解决方案 48 | 49 | 由于问题原因是 cinder-volume 允许打开的文件数没有随着 Ceph 集群的扩容做相应的调整,因此解决方案是要调整 cinder-volume 进程的允许打开文件数,目前调整为 `65535`(根据测试,发现每个删卷请求要建立大约 1000 多个链接,因此调整为 `65535` 后可以支持并发删除约 60 个 RDB 卷,后续版本会考虑基于性能基线,进行接口并发操作数量的限制,防止无限制的并发删卷导致文件打开数过大)。 50 | 51 | 1、cinder-volume 进程被封装成了 Ubuntu 上的 upstart 任务。修改 cinder-volume 进程启动配置文件 `/etc/init/cinder-volume.conf` ,增加一行配置: 52 | 53 | limit nofile 65535 65535 54 | 55 | `limit` 变量用来设置任务的资源限制。 56 | 57 | root@R1controller1:~# vi /etc/init/cinder-volume.conf 58 | description "Cinder Volume" 59 | 60 | start on (local-filesystems and net-device-up IFACE!=lo) 61 | stop on runlevel [016] 62 | 63 | respawn 64 | limit nofile 65535 65535 65 | 66 | exec su -s /bin/sh -C "exec cinder-volume --config-file /etc/cinder/cinder.conf > /dev/null 2>&1" root 67 | 68 | 2、重启 cinder-volume 进程,并用 `cat proc/pid/limits` 查询设置是否生效。 69 | 70 | root@R1controller1:~# service cinder-volume restart 71 | cinder-volume stop/waiting 72 | cinder-volume start/running, process 6298 73 | 74 | root@R1controller1:~# cat /etc/6298/limits | grep open 75 | Max open files 65535 65535 files 76 | 77 | 3、检查 cinder-volume 服务是否为 `UP` 状态。 78 | 79 | root@R1controller1:~# cinder service-list 80 | +------------------+---------------------------+------+---------+-------+----------------------------+-----------------+ 81 | | Binary | Host | Zone | Status | State | Updated_at | Disabled Reason | 82 | +------------------+---------------------------+------+---------+-------+----------------------------+-----------------+ 83 | | cinder-backup | OPS-controller1 | nova | enabled | up | 2016-09-07T20:38:30.000000 | None | 84 | | cinder-backup | OPS-controller2 | nova | enabled | up | 2016-09-07T20:38:26.000000 | None | 85 | | cinder-scheduler | OPS-controller1 | nova | enabled | up | 2016-09-07T20:38:29.000000 | None | 86 | | cinder-scheduler | OPS-controller2 | nova | enabled | up | 2016-09-07T20:38:29.000000 | None | 87 | | cinder-volume | OPS-controller1@netapp_fc | nova | enabled | up | 2016-09-07T20:38:32.000000 | None | 88 | | cinder-volume | OPS-controller1@rbd-sas | nova | enabled | up | 2016-09-07T20:38:33.000000 | None | 89 | | cinder-volume | OPS-controller1@rbd-ssd | nova | enabled | up | 2016-09-07T20:38:33.000000 | None | 90 | | cinder-volume | OPS-controller2@rbd-sas | nova | enabled | up | 2016-09-07T20:38:25.000000 | None | 91 | | cinder-volume | OPS-controller2@rbd-ssd | nova | enabled | up | 2016-09-07T20:38:27.000000 | None | 92 | +------------------+---------------------------+------+---------+-------+----------------------------+-----------------+ 93 | 94 | 4、重新进行删除卷操作,卷可以被正常删除。 95 | 96 | 5、因为 Glance 后端也对接的是 Ceph 集群,为防止 Glance 也出现该问题,建议也修改 Glance 进程的启动配置文件 `/etc/init/glance-api.conf` ,增加 `limit nofile 65535 65535` 配置行。 97 | 98 | 6、重启 glance-api 进程。 99 | 100 | service glance-api restart 101 | 102 | 7、重启完成后上传测试镜像,测试镜像可以正常上传和删除。 103 | -------------------------------------------------------------------------------- /Advance_usage/change_osd_journal.md: -------------------------------------------------------------------------------- 1 | # 4. 更换 OSD Journal 2 | 3 | ---------- 4 | 5 | 本篇中部分内容来自 [zphj1987 —— 如何替换 Ceph 的 Journal](http://www.zphj1987.com/2016/07/26/如何替换Ceph的Journal/) 6 | 7 | Ceph 在一块单独的磁盘上部署 OSD 的时候,是默认把 journal 和 OSD 放在同一块磁盘的不同分区上。有时候,我们可能需要把 OSD 的 journal 分区从一个磁盘替换到另一个磁盘上去。那么应该怎样替换 Ceph 的 journal 分区呢? 8 | 9 | 有两种方法来修改 Ceph 的 journal: 10 | 11 | - 创建一个 journal 分区,在上面创建一个新的 journal。 12 | - 转移已经存在的 journal 分区到新的分区上,这个适合整盘替换。 13 | 14 | > Ceph 的 journal 是基于事务的日志,所以正确的下刷 journal 数据,然后重新创建 journal 并不会引起数据丢失,因为在下刷 journal 的数据的时候,osd 是停止的,一旦数据下刷后,这个 journal 是不会再有新的脏数据进来的。 15 | 16 | ### 第一种方法 17 | 18 | 1、首先给 Ceph 集群设置 `noout` 标志。 19 | 20 | root@mon:~# ceph osd set noout 21 | set noout 22 | 23 | 2、假设我们现在想要替换 osd.0 的 journal。首先查看 osd.0 当前的 journal 位置,当前使用的是 `/dev/sdb2` 分区。 24 | 25 | root@mon:~# ceph-disk list | grep osd.0 26 | /dev/sdb1 ceph data, active, cluster ceph, osd.0, journal /dev/sdb2 27 | 28 | root@mon:~# ll /var/lib/ceph/osd/ceph-0/journal 29 | lrwxrwxrwx 1 root root 58 May 24 15:06 /var/lib/ceph/osd/ceph-0/journal -> /dev/disk/by-partuuid/8e95b09d-ffa9-4163-b24c-b78020022797 30 | root@mon:~# ls -l /dev/disk/by-partuuid/ 31 | total 0 32 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 39e9ad34-d7aa-4dec-865e-08952aa8aab5 -> ../../sdc1 33 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 8e95b09d-ffa9-4163-b24c-b78020022797 -> ../../sdb2 34 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 aaeca5fa-456a-4f45-8a8b-9de0c2642f44 -> ../../sdc2 35 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 d30a6d4a-6da4-4a81-a9e5-4bc69ebeec8f -> ../../sdb1 36 | 37 | 3、停止 osd.0 进程。 38 | 39 | stop ceph-osd id=0 40 | 41 | 4、下刷 journal 到 osd,使用 `-i` 指定需要替换 journal 的 osd 的编号。 42 | 43 | root@mon:~# ceph-osd -i 0 --flush-journal 44 | SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 45 | SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 | 2016-11-08 13:17:58.355025 7f8351a72800 -1 flushed journal /var/lib/ceph/osd/ceph-0/journal for object store /var/lib/ceph/osd/ceph-0 47 | 48 | 5、删除旧的 journal 。 49 | 50 | root@mon:~# ll /var/lib/ceph/osd/ceph-0/journal 51 | lrwxrwxrwx 1 root root 58 May 24 15:06 /var/lib/ceph/osd/ceph-0/journal -> /dev/disk/by-partuuid/8e95b09d-ffa9-4163-b24c-b78020022797 52 | root@mon:~# rm -rf /var/lib/ceph/osd/ceph-0/journal 53 | 54 | 6、下面用 `/dev/sdc2` 分区重建 osd.0 的 journal 。查看 `/dev/sdc2` 的 `uuid`: 55 | 56 | root@mon:~# ls -l /dev/disk/by-partuuid/ 57 | total 0 58 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 39e9ad34-d7aa-4dec-865e-08952aa8aab5 -> ../../sdc1 59 | lrwxrwxrwx 1 root root 10 Nov 8 13:17 8e95b09d-ffa9-4163-b24c-b78020022797 -> ../../sdb2 60 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 aaeca5fa-456a-4f45-8a8b-9de0c2642f44 -> ../../sdc2 61 | lrwxrwxrwx 1 root root 10 Nov 8 09:21 d30a6d4a-6da4-4a81-a9e5-4bc69ebeec8f -> ../../sdb1 62 | 63 | 新的 journal 的 uuid 的路径为 `/dev/disk/by-partuuid/aaeca5fa-456a-4f45-8a8b-9de0c2642f44` 。 64 | 65 | 7、新建 journal 的链接和 journal_uuid 文件: 66 | 67 | root@mon:~# ln -s /dev/disk/by-partuuid/aaeca5fa-456a-4f45-8a8b-9de0c2642f44 /var/lib/ceph/osd/ceph-0/journal 68 | root@mon:~# echo aaeca5fa-456a-4f45-8a8b-9de0c2642f44 > /var/lib/ceph/osd/ceph-0/journal_uuid 69 | 70 | 8、给 osd.0 创建 journal,使用 `-i` 指定 osd 的编号 。 71 | 72 | root@mon:~# ceph-osd -i 0 --mkjournal 73 | SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 | 2016-11-08 13:29:36.115461 7f64ec851800 -1 created new journal /var/lib/ceph/osd/ceph-0/journal for object store /var/lib/ceph/osd/ceph-0 75 | 76 | 9、查看新 journal 。 77 | 78 | root@mon:~# ceph-disk list | grep osd.0 79 | /dev/sdb1 ceph data, active, cluster ceph, osd.0, journal /dev/sdc2 80 | 81 | 10、启动 osd.0 。 82 | 83 | start ceph-osd id=0 84 | 85 | 11、去除 noout 的标记。 86 | 87 | ceph osd unset noout 88 | 89 | 12、检查集群的状态。 90 | 91 | root@mon:~# ceph -s 92 | cluster 614e77b4-c997-490a-a3f9-e89aa0274da3 93 | health HEALTH_OK 94 | monmap e5: 1 mons at {osd1=10.95.2.43:6789/0} 95 | election epoch 796, quorum 0 osd1 96 | osdmap e1067: 3 osds: 3 up, 3 in 97 | flags sortbitwise 98 | pgmap v309733: 384 pgs, 6 pools, 1148 MB data, 311 objects 99 | 3597 MB used, 73162 MB / 76759 MB avail 100 | 384 active+clean 101 | 102 | root@mon:~# ceph osd tree 103 | ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY 104 | -4 0.05997 root default 105 | -1 0.01999 host mon 106 | 0 0.01999 osd.0 up 1.00000 1.00000 107 | -2 0.01999 host osd0 108 | 1 0.01999 osd.1 up 1.00000 1.00000 109 | -3 0.01999 host osd1 110 | 2 0.01999 osd.2 up 1.00000 1.00000 111 | 112 | ### 第二种方法 113 | 114 | 这个属于备份和转移分区表的方法。 115 | 116 | 1、首先按方法一中的第 1 ~ 4 步,设置 `noout` 标志,停进程,下刷 journal。 117 | 118 | 2、备份需要替换 journal 的分区表。 119 | 120 | root@lab8106 ~# sgdisk --backup=/tmp/backup_journal_sdd /dev/sdd 121 | 122 | 3、 还原分区表。 123 | 124 | root@lab8106 ~# sgdisk --load-backup=/tmp/backup_journal_sde /dev/sde 125 | root@lab8106 ~# parted -s /dev/sde print 126 | 127 | 新的 journal 磁盘现在跟老的 journal 的磁盘的分区表一样的了。这意味着新的分区的 UUID 和老的相同的。如果选择的是这种备份还原的方法,那么 journal 的那个软连接是不需要进行修改的,因为两个磁盘的 uuid 是一样的,所以需要注意将老的磁盘拔掉或者清理掉分区,以免冲突。 128 | 129 | 4、重建 journal 。 130 | 131 | root@lab8106 ~# ceph-osd -i 0 --mkjournal 132 | 133 | 5、启动进程。 134 | 135 | root@lab8106 ~# start ceph-osd id=0 136 | 137 | 6、去除 `noout` 的标记。 138 | 139 | root@lab8106 ~# ceph osd unset noout 140 | -------------------------------------------------------------------------------- /Advance_usage/find_rbd_data_loc.md: -------------------------------------------------------------------------------- 1 | # 7. 查看 RBD 镜像的位置 2 | 3 | ---------- 4 | 5 | 有时,我们需要查看某个 RBD 镜像的对象都存放在哪些 PG 中,这些 PG 又分布在哪些 OSD 上。可以利用下面的 shell 脚本来实现快速查看 RBD 镜像的位置。 6 | 7 | #!/bin/bash 8 | 9 | # USAGE:./rbd-loc 10 | 11 | if [ -z ${1} ] || [ -z ${2} ]; 12 | then 13 | echo "USAGE: ./rbd-loc " 14 | exit 1 15 | fi 16 | 17 | rbd_prefix=$(rbd -p ${1} info ${2} | grep block_name_prefix | awk '{print $2}') 18 | for i in $(rados -p ${1} ls | grep ${rbd_prefix}) 19 | do 20 | ceph osd map ${1} ${i} 21 | done 22 | 23 | 执行的效果如下所示: 24 | 25 | root@mon:~# rbd ls -p images 26 | fc5b017d-fc74-4a59-80bb-a5a76e26dd4e 27 | 28 | root@mon:~# ./rbd-loc.sh images fc5b017d-fc74-4a59-80bb-a5a76e26dd4e 29 | osdmap e1078 pool 'images' (9) object 'rbd_data.1349f035c101d9.0000000000000001' -> pg 9.99b52d94 (9.14) -> up ([1,2,0], p1) acting ([1,2,0], p1) 30 | osdmap e1078 pool 'images' (9) object 'rbd_data.1349f035c101d9.0000000000000002' -> pg 9.40973ca2 (9.22) -> up ([0,2,1], p0) acting ([0,2,1], p0) 31 | osdmap e1078 pool 'images' (9) object 'rbd_data.1349f035c101d9.0000000000000003' -> pg 9.86758b2c (9.2c) -> up ([1,2,0], p1) acting ([1,2,0], p1) 32 | osdmap e1078 pool 'images' (9) object 'rbd_data.1349f035c101d9.0000000000000004' -> pg 9.3c8e78f6 (9.36) -> up ([0,1,2], p0) acting ([0,1,2], p0) 33 | osdmap e1078 pool 'images' (9) object 'rbd_data.1349f035c101d9.0000000000000000' -> pg 9.ffc971ff (9.3f) -> up ([0,2,1], p0) acting ([0,2,1], p0) 34 | 35 | 该测试环境只有 3 个 host, 每个 host 上 1 个 OSD ,3 副本设置。 -------------------------------------------------------------------------------- /Advance_usage/list_rbd_watcher.md: -------------------------------------------------------------------------------- 1 | # 10. 查看使用 RBD 镜像的客户端 2 | 3 | ---------- 4 | 5 | 有时候删除 rbd image 会提示当前 rbd image 正在使用中,无法删除: 6 | 7 | rbd rm foo 8 | 2016-11-09 20:16:14.018332 7f81877a07c0 -1 librbd: image has watchers - not removing 9 | Removing image: 0% complete...failed. 10 | rbd: error: image still has watchers 11 | This means the image is still open or the client using it crashed. Try again after closing/unmapping it or waiting 30s for the crashed client to timeout. 12 | 13 | 所以希望能查看到底是谁在使用 rbd image。 14 | 15 | 对于 rbd image 的使用,目前主要有两种形式:内核模块 map 后再 mount ;通过 libvirt 等供给虚拟机使用。都是利用 `rados listwatchers` 去查看,只是两种形式下需要读取的文件不一样。 16 | 17 | ### 内核模块 map 18 | 19 | 查看方法如下: 20 | 21 | # 查看 rbd pool 中的 image 22 | root@ceph1:~# rbd ls 23 | foo 24 | ltest 25 | test 26 | 27 | # 查看 foo 的使用者 28 | root@ceph1:~# rados -p rbd listwatchers foo.rbd 29 | watcher=10.202.0.82:0/1760414582 client.1332795 cookie=1 30 | 31 | # 去对应主机上检查 32 | root@ceph2:~#rbd showmapped |grep foo 33 | 0 rbd foo - /dev/rbd0 34 | 35 | ### 虚拟机通过 libvirt 使用 rbd image 36 | 37 | 查看方法如下: 38 | 39 | # 查看该虚拟机卷的信息 40 | root@ceph1:~# rbd info volumes/volume-ee0c4077-a607-4bc9-a8cf-e893837361f3 41 | rbd image 'volume-ee0c4077-a607-4bc9-a8cf-e893837361f3': 42 | size 1024 MB in 256 objects 43 | order 22 (4096 kB objects) 44 | block_name_prefix: rbd_data.13c3277850f538 45 | format: 2 46 | features: layering, striping 47 | flags: 48 | parent: images/3601459f-060b-460f-b73b-db74237d922e@snap 49 | overlap: 40162 kB 50 | stripe unit: 4096 kB 51 | stripe count: 1 52 | 53 | # 查看该 image 的使用者 54 | root@ceph1:~# rados -p volumes listwatchers rbd_header.13c3277850f538 55 | watcher=10.202.0.21:0/1043073 client.1298745 cookie=140256077850496 56 | 57 | 我们登录控制节点,查看对应的 cinder 卷: 58 | 59 | root@controller:~# cinder list | grep ee0c4077-a607-4bc9-a8cf-e893837361f3 60 | | ee0c4077-a607-4bc9-a8cf-e893837361f3 | in-use | | 1 | - | true | 96ee1aad-af27-4c9d-968f-291dbb2766a1 | 61 | 62 | 该卷挂载在 ID 为 `96ee1aad-af27-4c9d-968f-291dbb2766a1` 的虚拟机上。通过 `nova show` 命令验证该虚拟机是否在物理机 10.202.0.21 ( computer21 )上: 63 | 64 | root@controller:~# nova show 96ee1aad-af27-4c9d-968f-291dbb2766a1 65 | +--------------------------------------+---------------------------------------------------------------------------------+ 66 | | Property | Value | 67 | +--------------------------------------+---------------------------------------------------------------------------------+ 68 | | OS-DCF:diskConfig | AUTO | 69 | | OS-EXT-AZ:availability_zone | az_ip | 70 | | OS-EXT-SRV-ATTR:host | computer21 | 71 | | OS-EXT-SRV-ATTR:hostname | byp-volume | 72 | | OS-EXT-SRV-ATTR:hypervisor_hostname | computer21 | 73 | | OS-EXT-SRV-ATTR:instance_name | instance-00000989 | 74 | | OS-EXT-SRV-ATTR:kernel_id | | 75 | | OS-EXT-SRV-ATTR:launch_index | 0 | 76 | | OS-EXT-SRV-ATTR:ramdisk_id | | 77 | | OS-EXT-SRV-ATTR:reservation_id | r-hwiyx15c | 78 | | OS-EXT-SRV-ATTR:root_device_name | /dev/vda | 79 | | OS-EXT-SRV-ATTR:user_data | - | 80 | | OS-EXT-STS:power_state | 1 | 81 | | OS-EXT-STS:task_state | - | 82 | | OS-EXT-STS:vm_state | active | 83 | | OS-SRV-USG:launched_at | 2016-11-09T08:19:41.000000 | 84 | | OS-SRV-USG:terminated_at | - | 85 | | accessIPv4 | | 86 | | accessIPv6 | | 87 | | blue-net network | 192.168.50.27 | 88 | | config_drive | | 89 | | created | 2016-11-09T07:53:59Z | 90 | | description | byp-volume | 91 | | flavor | m1.small (2) | 92 | | hostId | 5104ee1a0538048d6ef80b14563a0cbac461f86523c5c81f5d18069e | 93 | | host_status | UP | 94 | | id | 96ee1aad-af27-4c9d-968f-291dbb2766a1 | 95 | | image | Attempt to boot from volume - no image supplied | 96 | | key_name | octavia_ssh_key | 97 | | locked | False | 98 | | metadata | {} | 99 | | name | byp-volume | 100 | | os-extended-volumes:volumes_attached | [{"id": "ee0c4077-a607-4bc9-a8cf-e893837361f3", "delete_on_termination": true}] | 101 | | progress | 0 | 102 | | security_groups | default | 103 | | status | ACTIVE | 104 | | tenant_id | f21a9c86d7114bf99c711f4874d80474 | 105 | | updated | 2016-11-09T08:19:41Z | 106 | | user_id | 142d8663efce464c89811c63e45bd82e | 107 | | zq-test network | 192.168.6.6 | 108 | +--------------------------------------+---------------------------------------------------------------------------------+ 109 | -------------------------------------------------------------------------------- /Advance_usage/mon_backup.md: -------------------------------------------------------------------------------- 1 | # 2. Monitor 的备份和恢复 2 | 3 | ---------- 4 | 5 | 本篇内容来自 [徐小胖'blog —— monitor 的增删改备](http://xuxiaopang.com/2016/10/26/exp-monitor-operation/) 6 | 7 | ### Monitor 的备份 8 | 9 | 每个 MON 的数据都是保存在数据库内的,这个数据库位于 `/var/lib/ceph/mon/$cluster-$hostname/store.db` ,这里的 `$cluster` 是集群的名字, `$hostname` 为主机名,MON 的所有数据即目录 `/var/lib/ceph/mon/$cluster-$hostname/` ,备份好这个目录之后,就可以在任一主机上恢复 MON 了。 10 | 11 | 这里参考了下 [这篇文章](https://blog.widodh.nl/2014/03/safely-backing-up-your-ceph-monitors/) 里面的备份方法,简单讲基本思路就是,停止一个 MON,然后将这个 MON 的数据库压缩保存到其他路径,再开启 MON。文中提到了之所以要停止 MON 是要保证 levelDB 数据库的完整性。然后可以做个定时任务一天或者一周备份一次。 12 | 13 | 另外最好把 `/etc/ceph/` 目录也备份一下。 14 | 15 | 这个备份路径最好是放到其他节点上,不要保存到本地,因为一般 MON 节点要坏就坏一台机器。 16 | 17 | 这里给出文中提到的备份方法: 18 | 19 | service ceph stop mon 20 | tar czf /var/backups/ceph-mon-backup_$(date +'%a').tar.gz /var/lib/ceph/mon 21 | service ceph start mon 22 | #for safety, copy it to other nodes 23 | scp /var/backups/* someNode:/backup/ 24 | 25 | ### Monitor 的恢复 26 | 27 | 现在有一个 Ceph 集群,包含 3 个 monitors: ceph-1 、ceph-2 和 ceph-3 。 28 | 29 | [root@ceph-1 cluster]# ceph -s 30 | cluster 844daf70-cdbc-4954-b6c5-f460d25072e0 31 | health HEALTH_OK 32 | monmap e2: 3 mons at {ceph-1=192.168.56.101:6789/0,ceph-2=192.168.56.102:6789/0,ceph-3=192.168.56.103:6789/0} 33 | election epoch 8, quorum 0,1,2 ceph-1,ceph-2,ceph-3 34 | osdmap e13: 3 osds: 3 up, 3 in 35 | pgmap v20: 64 pgs, 1 pools, 0 bytes data, 0 objects 36 | 101 MB used, 6125 GB / 6125 GB avail 37 | 64 active+clean 38 | 39 | 假设发生了某种故障,导致这 3 台 MON 节点全都无法启动,这时 Ceph 集群也将变得不可用。我们可以通过前面备份的数据库文件来恢复 MON。当某个集群的所有的 MON 节点都挂掉之后,我们可以将最新的备份的数据库解压到其他任意一个节点上,新建 monmap,注入,启动 MON,推送 config,重启 OSD就好了。 40 | 41 | 将 `ceph-1` 的 `/var/lib/ceph/mon/ceph-ceph-1/` 目录的文件拷贝到新节点 `ceph-4` 的 `/var/lib/ceph/mon/ceph-ceph-4/` 目录下(或者从备份路径拷贝到 `ceph-4` 节点),一定要注意目录的名称!这里 `ceph-1` 的 IP 为 `172.23.0.101`, `ceph-4` 的 IP 为 `192.168.56.104` 。`ceph-4` 节点为一个只安装了 ceph 程序的干净节点。注意下面指令执行的节点。 42 | 43 | [root@ceph-1 ~]# ip a |grep 172 44 | inet 172.23.0.101/24 brd 172.23.0.255 scope global enp0s8 45 | [root@ceph-1 ~]# ping ceph-4 46 | PING ceph-4 (192.168.56.104) 56(84) bytes of data. 47 | 64 bytes from ceph-4 (192.168.56.104): icmp_seq=1 ttl=63 time=0.463 ms 48 | 49 | [root@ceph-4 ~]# mkdir /var/lib/ceph/mon/ceph-ceph-4 50 | [root@ceph-1 ~]# scp -r /var/lib/ceph/mon/ceph-ceph-1/* ceph-4:/var/lib/ceph/mon/ceph-ceph-4/ 51 | done 100% 0 0.0KB/s 00:00 52 | keyring 100% 77 0.1KB/s 00:00 53 | LOCK 100% 0 0.0KB/s 00:00 54 | LOG 100% 21KB 20.6KB/s 00:00 55 | 161556.ldb 100% 2098KB 2.1MB/s 00:00 56 | ...... 57 | MANIFEST-161585 100% 709 0.7KB/s 00:00 58 | CURRENT 100% 16 0.0KB/s 00:00 59 | sysvinit 100% 0 0.0KB/s 00:00 60 | 61 | 同时,将 `/etc/ceph` 目录文件也拷贝到 `ceph-4` 节点,然后将 `ceph.conf` 中的 `mon_initial_members` 修改为 `ceph-4`。 62 | 63 | [root@ceph-1 ~]# scp /etc/ceph/* ceph-4:/etc/ceph/ 64 | ceph.client.admin.keyring 100% 63 0.1KB/s 00:00 65 | ceph.conf 100% 236 0.2KB/s 00:00 66 | 67 | [root@ceph-4 ~]# vim /etc/ceph/ceph.conf 68 | [root@ceph-4 ~]# cat /etc/ceph/ceph.conf 69 | [global] 70 | fsid = 844daf70-cdbc-4954-b6c5-f460d25072e0 71 | mon_initial_members = ceph-4 72 | mon_host = 192.168.56.104 73 | 74 | 新建一个 monmap,使用原来集群的 `fsid`,并且将 `ceph-4` 加入到这个 monmap,然后将 monmap 注入到 `ceph-4` 的 MON 数据库中,最后启动 `ceph-4` 上的 MON 进程。 75 | 76 | [root@ceph-4 ~]# monmaptool --create --fsid 844daf70-cdbc-4954-b6c5-f460d25072e0 --add ceph-4 192.168.56.104 /tmp/monmap 77 | [root@ceph-4 ~]# ceph-mon -i ceph-4 --inject-monmap /tmp/monmap 78 | [root@ceph-4 ~]# ceph-mon -i ceph-4 79 | [root@ceph-4 ~]# ceph -s 80 | cluster 844daf70-cdbc-4954-b6c5-f460d25072e0 81 | health HEALTH_ERR 82 | 64 pgs are stuck inactive for more than 300 seconds 83 | 64 pgs degraded 84 | 64 pgs stuck inactive 85 | 64 pgs undersized 86 | monmap e6: 1 mons at {ceph-4=192.168.56.104:6789/0} 87 | election epoch 13, quorum 0 ceph-4 88 | osdmap e36: 3 osds: 1 up, 1 in 89 | pgmap v58: 64 pgs, 1 pools, 0 bytes data, 0 objects 90 | 34296 kB used, 2041 GB / 2041 GB avail 91 | 64 undersized+degraded+peered 92 | 93 | 好消息是,`ceph -s` 有了正确的输出,坏消息就是 `HEALTH_ERR` 了。不过不用担心,这时候将 `ceph-4` 的 `ceph.conf` 推送到其他所有节点上,再重启 OSD 集群就可以恢复正常了。 -------------------------------------------------------------------------------- /Advance_usage/pg_active_remapped.md: -------------------------------------------------------------------------------- 1 | # 6. PG 卡在 active + remapped 状态 2 | 3 | ---------- 4 | 5 | ### 问题现象 6 | 7 | 有时,我们的 Ceph 集群可能会出现 PG 长时间卡在 `active + remapped` 的状态。 8 | 9 | root@ceph1:~# ceph -s 10 | cluster 5ccdcb2d-961d-4dcb-a9ed-e8034c56cf71 11 | health HEALTH_WARN 88 pgs stuck unclean 12 | monmap e2: 1 mons at {ceph1=192.168.56.102:6789/0}, election epoch 1, quorum 0 ceph1 13 | osdmap e71: 4 osds: 4 up, 3 in 14 | pgmap v442: 256 pgs, 4 pools, 285 MB data, 8 objects 15 | 690 MB used, 14636 MB / 15326 MB avail 16 | 88 active+remapped 17 | 168 active+clean 18 | 19 | ### 产生问题的原因 20 | 21 | 出现这种情况,一般是做了 osd 的 `reweight` 操作引起的,这是因为一般在做 `reweight` 的操作的时候,根据算法,这个上面的 pg 是会尽量分布在这个主机上的,而 `crush reweight` 不变的情况下,去修改 osd 的 `reweight` 的时候,可能算法上会出现无法映射的问题。 22 | 23 | ### 如何解决 24 | 25 | 1、直接做 `ceph osd crush reweigh` 的调整即可避免这个问题,这个 straw 算法里面还是有点小问题的,在调整某个因子的时候会引起整个因子的变动。 26 | 27 | 2、从 FIREFLY (CRUSH_TUNABLES3) 开始 CRUSH 里面增加了一个参数: 28 | 29 | chooseleaf_vary_r 30 | 31 | 是否递归的进行 chooseleaf 尝试,如果非 0 ,就递归的进行,这个基于 parent 已经做了多少次尝试。默认值是 0 ,但是常常找不到合适的 mapping 。在计算成本和正确性上来看最优值是 1 。对于已经有大量数据的集群来说,从 0 调整为 1 将会有大量数值的迁移,调整为 4 或者 5 的话,将会找到一个更有效的映射,可以减少数据的移动。 32 | 33 | 查看当前的值: 34 | 35 | root@ceph1:~# ceph osd crush show-tunables |grep chooseleaf_vary_r 36 | "chooseleaf_vary_r": 0, 37 | 38 | 修改 `chooseleaf_vary_r` 的值。 39 | 40 | Hammer 版本下这个参数默认为: 41 | 42 | > tunable chooseleaf_vary_r 0 43 | 44 | 修改 Crush Map 的方法请参考本手册第一部分 [9. 管理 Crushmap](./Operation/manage_crushmap.md) 。 45 | 46 | 或者,直接修改 `crush tunables` 的值为 `optimal` 。 47 | 48 | ceph osd crush tunables optimal -------------------------------------------------------------------------------- /Advance_usage/pg_pgp.md: -------------------------------------------------------------------------------- 1 | # 1. PG 和 PGP 的区别 2 | 3 | ---------- 4 | 5 | 本篇内容来自 [zphj1987 —— 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/) 6 | 7 | ### 前言 8 | 9 | 首先来一段关于 PG 和 PGP 区别的英文解释: 10 | 11 | > PG = Placement Group 12 | > PGP = Placement Group for Placement purpose 13 | > pg_num = number of placement groups mapped to an OSD 14 | > When pg_num is increased for any pool, every PG of this pool splits into half, but they all remain mapped to their parent OSD. 15 | > Until this time, Ceph does not start rebalancing. Now, when you increase the pgp_num value for the same pool, PGs start to migrate from the parent to some other OSD, and cluster rebalancing starts. This is how PGP plays an important role. 16 | > By Karan Singh 17 | 18 | 以上是来自邮件列表的 `Karan Singh` 对 PG 和 PGP 的相关解释,他也是 `Learning Ceph` 和 `Ceph Cookbook` 的作者,以上的解释没有问题,我们来看下具体在集群里面如何作用。 19 | 20 | ### 实践 21 | 22 | 环境准备,因为是测试环境,我只准备了两台机器,每台机器 4 个 OSD,所以做了一些参数的设置,让数据尽量散列: 23 | 24 | osd_crush_chooseleaf_type = 0 25 | 26 | 以上为修改的参数,这个是让我的环境故障域为 OSD 分组的。 27 | 28 | ##### 创建测试需要的存储池 29 | 30 | 我们初始情况只创建一个名为 testpool 包含 6 个 PG 的存储池: 31 | 32 | ceph osd pool create testpool 6 6 33 | pool 'testpool' created 34 | 35 | 我们看一下默认创建完了后的 PG 分布情况: 36 | 37 | ceph pg dump pgs|grep ^1|awk '{print $1,$2,$15}' 38 | dumped pgs in format plain 39 | 1.1 0 [3,6,0] 40 | 1.0 0 [7,0,6] 41 | 1.3 0 [4,1,2] 42 | 1.2 0 [7,4,1] 43 | 1.5 0 [4,6,3] 44 | 1.4 0 [3,0,4] 45 | 46 | 我们写入一些对象,因为我们关心的不仅是 PG 的变动,同样关心 PG 内对象有没有移动,所以需要准备一些测试数据,这个调用原生 `rados` 接口写最方便。 47 | 48 | rados -p testpool bench 20 write --no-cleanup 49 | 50 | 我们再来查询一次: 51 | 52 | ceph pg dump pgs|grep ^1|awk '{print $1,$2,$15}' 53 | dumped pgs in format plain 54 | 1.1 75 [3,6,0] 55 | 1.0 83 [7,0,6] 56 | 1.3 144 [4,1,2] 57 | 1.2 146 [7,4,1] 58 | 1.5 86 [4,6,3] 59 | 1.4 80 [3,0,4] 60 | 61 | 可以看到写入了一些数据,其中的第二列为这个 PG 当中的对象的数目,第三列为 PG 所在的 OSD。 62 | 63 | ##### 增加 PG 测试 64 | 65 | 我们来扩大 PG 再看看: 66 | 67 | ceph osd pool set testpool pg_num 12 68 | set pool 1 pg_num to 12 69 | 70 | 再次查询: 71 | 72 | ceph pg dump pgs|grep ^1|awk '{print $1,$2,$15}' 73 | dumped pgs in format plain 74 | 1.1 37 [3,6,0] 75 | 1.9 38 [3,6,0] 76 | 1.0 41 [7,0,6] 77 | 1.8 42 [7,0,6] 78 | 1.3 48 [4,1,2] 79 | 1.b 48 [4,1,2] 80 | 1.7 48 [4,1,2] 81 | 1.2 48 [7,4,1] 82 | 1.6 49 [7,4,1] 83 | 1.a 49 [7,4,1] 84 | 1.5 86 [4,6,3] 85 | 1.4 80 [3,0,4] 86 | 87 | 可以看到上面新加上的 PG 的分布还是基于老的分布组合,并没有出现新的 OSD 组合,因为我们当前的设置是 pgp_num 为 6,那么三个 OSD 的组合的个数就是 6 个,因为当前为 12 个 PG,分布只能从 6 种组合里面挑选,所以会有重复的组合。 88 | 89 | 根据上面的分布情况,可以确定的是,增加 PG 操作会引起 PG 内部对象分裂,分裂的份数是根据新增 PG 组合重复情况来确定的,比如上面的情况: 90 | 91 | - `1.1` 的对象分成了两份 `[3,6,0]` 92 | - `1.3` 的对象分成了三份 `[4,1,2]` 93 | - `1.4` 的对象没有拆分 `[3,0,4]` 94 | 95 | **结论: 增加 PG 会引起 PG 内的对象分裂,也就是在 OSD 上创建了新的 PG 目录,然后进行部分对象的 `move` 的操作。** 96 | 97 | ##### 增加 PGP 测试 98 | 99 | 我们将原来的 PGP 从 6 调整到 12: 100 | 101 | ceph osd pool set testpool pgp_num 12 102 | 103 | ceph pg dump pgs|grep ^1|awk '{print $1,$2,$15}' 104 | dumped pgs in format plain 105 | 1.a 49 [1,2,6] 106 | 1.b 48 [1,6,2] 107 | 1.1 37 [3,6,0] 108 | 1.0 41 [7,0,6] 109 | 1.3 48 [4,1,2] 110 | 1.2 48 [7,4,1] 111 | 1.5 86 [4,6,3] 112 | 1.4 80 [3,0,4] 113 | 1.7 48 [1,6,0] 114 | 1.6 49 [3,6,7] 115 | 1.9 38 [1,4,2] 116 | 1.8 42 [1,2,3] 117 | 118 | 可以看到 PG 里面的对象并没有发生变化,而 PG 所在的对应关系发生了变化。 119 | 120 | 我们看下与调整 PGP 前后的对比: 121 | 122 | *1.1 37 [3,6,0] 1.1 37 [3,6,0]* 123 | 1.9 38 [3,6,0] 1.9 38 [1,4,2] 124 | *1.0 41 [7,0,6] 1.0 41 [7,0,6]* 125 | 1.8 42 [7,0,6] 1.8 42 [1,2,3] 126 | *1.3 48 [4,1,2] 1.3 48 [4,1,2]* 127 | 1.b 48 [4,1,2] 1.b 48 [1,6,2] 128 | 1.7 48 [4,1,2] 1.7 48 [1,6,0] 129 | *1.2 48 [7,4,1] 1.2 48 [7,4,1]* 130 | 1.6 49 [7,4,1] 1.6 49 [3,6,7] 131 | 1.a 49 [7,4,1] 1.a 49 [1,2,6] 132 | *1.5 86 [4,6,3] 1.5 86 [4,6,3]* 133 | *1.4 80 [3,0,4] 1.4 80 [3,0,4]* 134 | 135 | 可以看到其中最原始的 6 个 PG 的分布并没有变化(标注了 `*` 号),变化的是后增加的 PG,也就是将重复的 PG 分布进行重新分布,这里并不是随机完全打散,而是根据需要去进行重分布。 136 | 137 | **结论: 调整 PGP 不会引起 PG 内的对象的分裂,但是会引起 PG 的分布的变动。** 138 | 139 | ### 总结 140 | 141 | - PG 是指定存储池存储对象的目录有多少个,PGP 是存储池 PG 的 OSD 分布组合个数。 142 | - PG 的增加会引起 PG 内的数据进行分裂,分裂到相同的 OSD 上新生成的 PG 当中。 143 | - PGP 的增加会引起部分 PG 的分布进行变化,但是不会引起 PG 内对象的变动。 -------------------------------------------------------------------------------- /Advance_usage/rbd_real_size.md: -------------------------------------------------------------------------------- 1 | # 8. 查看 RBD 镜像的实际大小 2 | 3 | ---------- 4 | 5 | 本篇内容来自 [zphj1987 —— 如何统计 Ceph 的 RBD 真实使用容量](http://www.zphj1987.com/2016/09/08/%E5%A6%82%E4%BD%95%E7%BB%9F%E8%AE%A1Ceph%E7%9A%84RBD%E7%9C%9F%E5%AE%9E%E4%BD%BF%E7%94%A8%E5%AE%B9%E9%87%8F/) 6 | 7 | Ceph 的 rbd 一直有个问题就是无法清楚的知道这个分配的空间里面到底使用了多少,使用 `rbd info` 命令查询出来的容量是预分配的总容量而非实际使用容量。在 Jewel 版中提供了一个新的接口去查询,对于老版本来说可能同样有这个需求,本篇将详细介绍如何解决这个问题。 8 | 9 | 目前已知的有三种查询方法: 10 | 11 | 1. 使用 `rbd du` 查询(Jewel 版才支持) 12 | 2. 使用 `rbd diff` 13 | 3. 根据对象统计的方法进行统计 14 | 15 | ### 方法一:使用 rbd du 查询 16 | 17 | 此命令在 Jewel 版中可用。 18 | 19 | root@mon:~# rbd du rbd/mysql-img 20 | NAME PROVISIONED USED 21 | test 52.8047M 0 22 | 23 | 不过需要注意,执行此命令要求开启 rbd image 的如下属性: 24 | 25 | layering, exclusive-lock, object-map, fast-diff 26 | 27 | 具体使用可参考 [这篇文章](http://www.zphj1987.com/2016/03/24/ceph查询rbd的使用容量(快速)/) 。 28 | 29 | ### 方法二:使用 rbd diff 30 | 31 | root@mon:~# rbd diff rbd/mysql-img | awk '{ SUM += $2 } END { print SUM/1024/1024 " MB" }' 32 | 52.8047 MB 33 | 34 | ### 方法三:根据对象统计的方法进行统计 35 | 36 | 在集群非常大的时候,再按上面的方法一个个查询,需要花很长的时间,并且需要时不时的跟集群进行交互。方法三是把统计数据一次获取下来,然后进行数据的统计分析,从而获取结果,获取的粒度是以存储池为基准的。 37 | 38 | 拿到所有对象的信息: 39 | 40 | for obj in `rados -p rbd ls`;do rados -p rbd stat $obj >> obj.txt;done 41 | 42 | 这个获取的时间长短是根据对象的多少来的,如果担心出问题,可以换个终端查看进度: 43 | 44 | tail -f obj.txt 45 | 46 | 获取 RBD 的镜像列表: 47 | 48 | rbd -p rbd ls 49 | img2 50 | mysql-img 51 | volume-e5376906-7a95-48bb-a1c6-bb694b4f4813.backup.base 52 | 53 | 获取 RBD 的镜像的 prefix : 54 | 55 | root@mon:~# for a in `rbd -p rbd ls`;do echo $a ;rbd -p rbd info $a|grep prefix |awk '{print $2}' ;done 56 | img2 57 | rb.0.f4730.2ae8944a 58 | mysql-img 59 | rb.0.f4652.2ae8944a 60 | volume-e5376906-7a95-48bb-a1c6-bb694b4f4813.backup.base 61 | rbd_data.23a53c28fb938f 62 | 63 | 64 | 获取指定RBD镜像的大小: 65 | 66 | root@mon:~# cat obj.txt |grep rb.0.f4652.2ae8944a |awk '{ SUM += $6 } END { print SUM/1024/1024 " MB" }' 67 | 52.8047 MB 68 | 69 | 将上面的汇总,使用脚本一次查询出指定存储池中所有镜像的大小: 70 | 71 | #!/bin/bash 72 | # USAGE:./get_used.sh 73 | 74 | objfile=obj.txt 75 | Poolname=${1} 76 | echo "In the pool ${Poolname}": 77 | 78 | for obj in `rados -p $Poolname ls` 79 | do 80 | rados -p $Poolname stat $obj >> $objfile 81 | done 82 | 83 | for image in `rbd -p $Poolname ls` 84 | do 85 | Imagename=$image 86 | Prefix=`rbd -p $Poolname info $image|grep prefix |awk '{print $2}'` 87 | Used=`cat $objfile |grep $Prefix|awk '{ SUM += $6 } END { print SUM/1024/1024 " MB" }'` 88 | echo $Imagename $Prefix 89 | echo Used: $Used 90 | done 91 | 92 | 执行的效果如下: 93 | 94 | root@mon:~# ./get_used.sh rbd 95 | In the pool rbd: 96 | img2 rb.0.f4730.2ae8944a 97 | Used: 3076 MB 98 | mysql-img rb.0.f4652.2ae8944a 99 | Used: 158.414 MB 100 | volume-e5376906-7a95-48bb-a1c6-bb694b4f4813.backup.base rbd_data.23a53c28fb938f 101 | Used: 96 MB 102 | 103 | 注意这里只统计了 image 里面的真实容量,如果是用了链接 clone 的,存在容量复用的问题,需要自己看是否需要统计那一部分的对象,方法同上。 -------------------------------------------------------------------------------- /Advance_usage/rescue_osd_parted.md: -------------------------------------------------------------------------------- 1 | # 5. 清空 OSD 的分区表后如何恢复 2 | 3 | ---------- 4 | 5 | 本篇内容来自 [zphj1987 —— 不小心清空了 Ceph 的 OSD 的分区表如何恢复](http://www.zphj1987.com/2016/09/24/%E4%B8%8D%E5%B0%8F%E5%BF%83%E6%B8%85%E7%A9%BA%E4%BA%86Ceph%E7%9A%84OSD%E7%9A%84%E5%88%86%E5%8C%BA%E8%A1%A8%E5%A6%82%E4%BD%95%E6%81%A2%E5%A4%8D/) 6 | 7 | 假设不小心对 Ceph OSD 执行了 `ceph-deploy disk zap` 这个操作,那么该 OSD 对应磁盘的分区表就丢失了。本文讲述了在这种情况下如何进行恢复。 8 | 9 | ### 破坏环境 10 | 11 | 我们现在有一个正常的集群,假设用的是默认的分区的方式,我们先来看看默认的分区方式是怎样的。 12 | 13 | 1、查看默认的分区方式。 14 | 15 | root@mon:~# ceph-disk list 16 | ··· 17 | /dev/sdb : 18 | /dev/sdb1 ceph data, active, cluster ceph, osd.0, journal /dev/sdb2 19 | /dev/sdb2 ceph journal, for /dev/sdb1 20 | ··· 21 | 22 | 2、查看分区情况 23 | 24 | root@mon:~# parted -s /dev/sdb print 25 | Model: SEAGATE ST3300657SS (scsi) 26 | Disk /dev/sdb: 300GB 27 | Sector size (logical/physical): 512B/512B 28 | Partition Table: gpt 29 | Disk Flags: 30 | 31 | Number Start End Size File system Name Flags 32 | 2 1049kB 1074MB 1073MB ceph journal 33 | 1 1075MB 300GB 299GB xfs ceph data 34 | 35 | 3、破坏 `/dev/sdb` 的分区表,该磁盘对应的是 `osd.0` 。 36 | 37 | root@mon:~/ceph# ceph-deploy disk zap mon:/dev/sdb 38 | [ceph_deploy.conf][DEBUG ] found configuration file at: /root/.cephdeploy.conf 39 | [ceph_deploy.cli][INFO ] Invoked (1.5.34): /usr/bin/ceph-deploy disk zap mon:/dev/sdb 40 | ··· 41 | [mon][DEBUG ] Warning: The kernel is still using the old partition table. 42 | [mon][DEBUG ] The new table will be used at the next reboot. 43 | [mon][DEBUG ] GPT data structures destroyed! You may now partition the disk using fdisk or 44 | [mon][DEBUG ] other utilities. 45 | ··· 46 | 47 | 即使这个 osd 在被使用,还是被破坏了,这里假设上面的就是一个误操作,我们看下带来了哪些变化: 48 | 49 | root@mon:~/ceph# ll /var/lib/ceph/osd/ceph-0/journal 50 | lrwxrwxrwx 1 root root 58 Sep 24 00:02 /var/lib/ceph/osd/ceph-0/journal -> /dev/disk/by-partuuid/bd81471d-13ff-44ce-8a33-92a8df9e8eee 51 | 52 | 如果你用命令行看,就可以看到上面的链接已经变红了,分区没有了: 53 | 54 | root@mon:~/ceph# ceph-disk list 55 | /dev/sdb : 56 | /dev/sdb1 other, xfs, mounted on /var/lib/ceph/osd/ceph-0 57 | /dev/sdb2 other 58 | 59 | 已经跟上面有变化了,没有 ceph 的相关分区信息了: 60 | 61 | root@mon:~/ceph# parted -s /dev/sdb print 62 | Model: SEAGATE ST3300657SS (scsi) 63 | Disk /dev/sdb: 300GB 64 | Sector size (logical/physical): 512B/512B 65 | Partition Table: gpt 66 | Disk Flags: 67 | 68 | Number Start End Size File system Name Flags 69 | 70 | 分区表完全没有信息了,到这我们可以确定分区表完全没了,如果现在重启将会发生什么?重启以后这个磁盘就是一个裸盘,没有分区的裸盘,所以此时千万**不能重启**! 71 | 72 | ### 恢复环境 73 | 74 | 首先一个办法就是当这个 OSD 坏了,然后直接按照删除节点,添加节点的方法去处理,这个应该是最主流、最通用的处理办法,但是这个方法在生产环境当中引发的数据迁移还是非常大的。我们尝试做恢复,这就是本篇主要讲的东西。 75 | 76 | 1、首先设置 `noout` 标志。 77 | 78 | root@mon:~/ceph# ceph osd set noout 79 | 80 | 2、停止 OSD 。 81 | 82 | root@mon:~/ceph# stop ceph-osd id=0 83 | 84 | 现在的 OSD 还是有进程的,所以需要停止掉再做处理。 85 | 86 | 3、查看其他 OSD 的分区信息(这里要求磁盘一致)。 87 | 88 | root@mon:~/ceph# parted -s /dev/sdc unit s print 89 | Model: SEAGATE ST3300657SS (scsi) 90 | Disk /dev/sdc: 585937500s 91 | Sector size (logical/physical): 512B/512B 92 | Partition Table: gpt 93 | Disk Flags: 94 | 95 | Number Start End Size File system Name Flags 96 | 2 2048s 2097152s 2095105s ceph journal 97 | 1 2099200s 585937466s 583838267s xfs ceph data 98 | 99 | 记住上面的数值, `print` 的时候是加了 `unit s` 这个是要精确的值的,下面的步骤会用到的这些数值。 100 | 101 | 4、进行分区表的恢复。 102 | 103 | root@mon:~/ceph# parted -s /dev/sdb mkpart ceph_data 2099200s 585937466s 104 | root@mon:~/ceph# parted -s /dev/sdb mkpart ceph_journal 2048s 2097152s 105 | 106 | 5、再次检查 /dev/sdb 的分区表。 107 | 108 | root@mon:~/ceph# parted -s /dev/sdb print 109 | Model: SEAGATE ST3300657SS (scsi) 110 | Disk /dev/sdb: 300GB 111 | Sector size (logical/physical): 512B/512B 112 | Partition Table: gpt 113 | Disk Flags: 114 | 115 | Number Start End Size File system Name Flags 116 | 2 1049kB 1074MB 1073MB ceph_journal 117 | 1 1075MB 300GB 299GB xfs ceph_data 118 | 119 | 可以看到,分区表已经回来了。 120 | 121 | 6、重新挂载分区。 122 | 123 | root@mon:~/ceph# umount /var/lib/ceph/osd/ceph-0 124 | root@mon:~/ceph# partprobe 125 | root@mon:~/ceph# mount /dev/sdb1 /var/lib/ceph/osd/ceph-0 126 | 127 | 7、删除旧的 journal ,重建 osd.0 的 journal。 128 | 129 | root@mon:~/ceph# rm -rf /var/lib/ceph/osd/ceph-0/journal 130 | 131 | root@mon:~/ceph# ceph-osd -i 0 --osd-journal=/dev/sdb2 --mkjournal 132 | SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 01 cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 133 | 2016-09-24 00:36:06.595992 7f9d0afbc880 -1 created new journal /dev/sdb2 for object store /var/lib/ceph/osd/ceph-0 134 | root@mon:~/ceph# ln -s /dev/sdb2 /var/lib/ceph/osd/ceph-0/journal 135 | root@mon:~/ceph# ll /var/lib/ceph/osd/ceph-0/journal 136 | lrwxrwxrwx 1 root root 9 Sep 24 00:37 journal -> /dev/sdb2 137 | 138 | 注意上面的操作 `--osd-journal=/dev/sdb2` 这个地方,此处写成 `/dev/sdb2` 是便于识别,这个地方在实际操作中要写上 `/dev/sdb2` 的 uuid 的路径。 139 | 140 | root@mon:~/ceph# ll /dev/disk/by-partuuid/03fc6039-ad80-4b8d-86ec-aeee14fb3bb6 141 | lrwxrwxrwx 1 root root 10 Sep 24 00:33 /dev/disk/by-partuuid/03fc6039-ad80-4b8d-86ec-aeee14fb3bb6 -> ../../sdb2 142 | 143 | 也就是这个链接的一串内容,这是为了防止盘符串了的情况下无法找到 journal 的问题。 144 | 145 | 8、启动 OSD 。 146 | 147 | root@mon:~/ceph# start ceph-osd id=0 148 | 149 | 检查下,到这 osd.0 就成功地恢复了。 150 | -------------------------------------------------------------------------------- /Operation/add_rm_mon.md: -------------------------------------------------------------------------------- 1 | # 6. 增加/删除 Monitor 2 | 3 | ---------- 4 | 5 | 一个集群可以只有一个 monitor,我们推荐生产环境至少部署 3 个。 Ceph 使用 Paxos 算法的一个变种对各种 map 、以及其它对集群来说至关重要的信息达成共识。建议(但不是强制)部署奇数个 monitor 。Ceph 需要 mon 中的大多数在运行并能够互相通信,比如单个 mon,或 2 个中的 2 个,3 个中的 2 个,4 个中的 3 个等。初始部署时,建议部署 3 个 monitor。后续如果要增加,请一次增加 2 个。 6 | 7 | ### 6.1 增加 Monitor(手动) 8 | 9 | 1、在目标节点上,新建 mon 的默认目录。`{mon-id}` 一般取为节点的 hostname 。 10 | 11 | ssh {new-mon-host} 12 | sudo mkdir /var/lib/ceph/mon/ceph-{mon-id} 13 | 14 | 2、创建一个临时目录(和第 1 步中的目录不同,添加 mon 完毕后需要删除该临时目录),来存放新增 mon 所需的各种文件, 15 | 16 | mkdir {tmp} 17 | 18 | 3、获取 mon 的 keyring 文件,保存在临时目录下。 19 | 20 | ceph auth get mon. -o {tmp}/{key-filename} 21 | 22 | 4、获取集群的 mon map 并保存到临时目录下。 23 | 24 | ceph mon getmap -o {tmp}/{map-filename} 25 | 26 | 5、格式化在第 1 步中建立的 mon 数据目录。需要指定 mon map 文件的路径(获取法定人数的信息和集群的 `fsid` )和 keyring 文件的路径。 27 | 28 | sudo ceph-mon -i {mon-id} --mkfs --monmap {tmp}/{map-filename} --keyring {tmp}/{key-filename} 29 | 30 | 6、启动节点上的 mon 进程,它会自动加入集群。守护进程需要知道绑定到哪个 IP 地址,可以通过 `--public-addr {ip:port}` 选择指定,或在 `ceph.conf` 文件中进行配置 `mon addr`。 31 | 32 | ceph-mon -i {mon-id} --public-addr {ip:port} 33 | 34 | ### 6.2 增加 Monitor( ceph-deploy ) 35 | 36 | 还可以通过 `ceph-deploy` 工具很方便地增加 MON。 37 | 38 | 1、登入 `ceph-deploy` 工具所在的 Ceph admin 节点,进入工作目录。 39 | 40 | ssh {ceph-deploy-node} 41 | cd /path/ceph-deploy-work-path 42 | 43 | 2、执行下列命令,新增 Monitor: 44 | 45 | ceph-deploy mon create {host-name [host-name]...} 46 | 47 | **注意:** 在某一主机上新增 Mon 时,如果它不是由 `ceph-deploy new` 命令所定义的,那就必须把 `public network` 加入 `ceph.conf` 配置文件。 48 | 49 | ### 6.3 删除 Monitor(手动) 50 | 51 | 当你想要删除一个 mon 时,需要考虑删除后剩余的 mon 个数是否能够达到法定人数。 52 | 53 | 1、停止 mon 进程。 54 | 55 | stop ceph-mon id={mon-id} 56 | 57 | 2、从集群中删除 monitor。 58 | 59 | ceph mon remove {mon-id} 60 | 61 | 3、从 ceph.conf 中移除 mon 的入口部分(如果有)。 62 | 63 | ### 6.4 删除 Monitor(从不健康的集群中) 64 | 65 | 本小节介绍了如何从一个不健康的集群(比如集群中的 monitor 无法达成法定人数)中删除 `ceph-mon` 守护进程。 66 | 67 | 1、停止集群中所有的 `ceph-mon` 守护进程。 68 | 69 | ssh {mon-host} 70 | service ceph stop mon || stop ceph-mon-all 71 | # and repeat for all mons 72 | 73 | 2、确认存活的 mon 并登录该节点。 74 | 75 | ssh {mon-host} 76 | 77 | 3、提取 mon map。 78 | 79 | ceph-mon -i {mon-id} --extract-monmap {map-path} 80 | # in most cases, that's 81 | ceph-mon -i `hostname` --extract-monmap /tmp/monmap 82 | 83 | 4、删除未存活或有问题的的 monitor。比如,有 3 个 monitors,`mon.a` 、`mon.b` 和 `mon.c`,现在仅有 `mon.a` 存活,执行下列步骤: 84 | 85 | monmaptool {map-path} --rm {mon-id} 86 | # for example, 87 | monmaptool /tmp/monmap --rm b 88 | monmaptool /tmp/monmap --rm c 89 | 90 | 5、向存活的 monitor(s) 注入修改后的 mon map。比如,把 mon map 注入 `mon.a`,执行下列步骤: 91 | 92 | ceph-mon -i {mon-id} --inject-monmap {map-path} 93 | # for example, 94 | ceph-mon -i a --inject-monmap /tmp/monmap 95 | 96 | 6、启动存活的 monitor。 97 | 98 | 7、确认 monitor 是否达到法定人数( `ceph -s` )。 99 | 100 | 8、你可能需要把已删除的 monitor 的数据目录 `/var/lib/ceph/mon` 归档到一个安全的位置。或者,如果你确定剩下的 monitor 是健康的且数量足够,也可以直接删除数据目录。 101 | 102 | ### 6.5 删除 Monitor( ceph-deploy ) 103 | 104 | 1、登入 `ceph-deploy` 工具所在的 Ceph admin 节点,进入工作目录。 105 | 106 | ssh {ceph-deploy-node} 107 | cd /path/ceph-deploy-work-path 108 | 109 | 2、如果你想删除集群中的某个 Mon ,可以用 `destroy` 选项。 110 | 111 | ceph-deploy mon destroy {host-name [host-name]...} 112 | 113 | **注意:** 确保你删除某个 Mon 后,其余 Mon 仍能达成一致。如果不可能,删除它之前可能需要先增加一个。 -------------------------------------------------------------------------------- /Operation/add_rm_osd.md: -------------------------------------------------------------------------------- 1 | # 7. 增加/删除 OSD 2 | 3 | ---------- 4 | 5 | 如果您的集群已经在运行,你可以在运行时添加或删除 OSD 。 6 | 7 | ### 7.1 增加 OSD(手动) 8 | 9 | 要增加一个 OSD,要依次创建数据目录、把硬盘挂载到数据目录、把 OSD 加入集群、然后把它加入 CRUSH Map。 10 | 11 | **Tip:** Ceph 喜欢统一的硬件,与存储池无关。如果你要新增容量不一的硬盘驱动器,还需调整它们的权重。但是,为实现最佳性能,CRUSH 的分级结构最好按类型、容量来组织。 12 | 13 | 1、创建 OSD。如果未指定 UUID, OSD 启动时会自动生成一个。下列命令会输出 OSD 号,后续步骤你会用到。 14 | 15 | ceph osd create [{uuid} [{id}]] 16 | 17 | 如果指定了可选参数 {id} ,那么它将作为 OSD id 。要注意,如果此数字已使用,此命令会出错。 18 | 19 | **警告:** 一般来说,我们不建议指定 {id} 。因为 ID 是按照数组分配的,跳过一些依然会浪费内存;尤其是跳过太多、或者集群很大时,会更明显。若未指定 {id} ,将用最小可用数字。 20 | 21 | 2、在新 OSD 主机上创建数据目录。 22 | 23 | ssh {new-osd-host} 24 | sudo mkdir /var/lib/ceph/osd/ceph-{osd-number} 25 | 26 | 3、如果准备用于 OSD 的是单独的磁盘而非系统盘,先把它挂载到刚创建的目录下: 27 | 28 | ssh {new-osd-host} 29 | sudo mkfs -t {fstype} /dev/{drive} 30 | sudo mount -o user_xattr /dev/{hdd} /var/lib/ceph/osd/ceph-{osd-number} 31 | 32 | 4、初始化 OSD 数据目录。 33 | 34 | ssh {new-osd-host} 35 | ceph-osd -i {osd-num} --mkfs --mkkey 36 | 37 | 在启动 `ceph-osd` 前,数据目录必须是空的。 38 | 39 | 5、注册 OSD 认证密钥, `ceph-{osd-num}` 路径里的 `ceph` 值应该是 `$cluster-$id` ,如果你的集群名字不是 `ceph` ,那就用自己集群的名字。 40 | 41 | ceph auth add osd.{osd-num} osd 'allow *' mon 'allow rwx' -i /var/lib/ceph/osd/ceph-{osd-num}/keyring 42 | 43 | 6、把新 OSD 加入 CRUSH Map 中,以便它可以开始接收数据。用 `ceph osd crush add` 命令把 OSD 加入 CRUSH 分级结构的合适位置。如果你指定了不止一个 bucket,此命令会把它加入你所指定的 bucket 中最具体的一个,并且把此 bucket 挪到你指定的其它 bucket 之内。 44 | 45 | ceph osd crush add {id-or-name} {weight} [{bucket-type}={bucket-name} ...] 46 | 47 | 比如: 48 | 49 | ceph osd crush add 21 0.08800 pool=ssd_root rack=ssd_rack01 host=ssd_ceph4 50 | 51 | 你也可以反编译 CRUSH Map、把 OSD 加入设备列表、以 bucket 的形式加入主机(如果它没在 CRUSH Map 里)、以条目形式把设备加入主机、分配权重、重编译并应用它,详情参见本手册第一部分 [9. 修改 Crushmap](./modify_crushmap.md) 。 52 | 53 | 7、启动 OSD。把 OSD 加入 Ceph 后, OSD 就在配置里了。然而它还没运行,它现在的状态为 `down & out` 。你必须先启动 OSD 它才能收数据。在 Ubuntu 上执行: 54 | 55 | sudo start ceph-osd id={osd-num} 56 | 57 | 一旦你启动了 OSD ,其状态就变成了 `up & in` 。 58 | 59 | ### 7.2 增加 OSD( ceph-deploy ) 60 | 61 | 还可以通过 `ceph-deploy` 工具很方便的增加 OSD。 62 | 63 | 1、登入 `ceph-deploy` 工具所在的 Ceph admin 节点,进入工作目录。 64 | 65 | ssh {ceph-deploy-node} 66 | cd /path/ceph-deploy-work-path 67 | 68 | 2、列举磁盘。 69 | 70 | 执行下列命令列举一节点上的磁盘: 71 | 72 | ceph-deploy disk list {node-name [node-name]...} 73 | 74 | 3、格式化磁盘。 75 | 76 | 用下列命令格式化(删除分区表)磁盘,以用于 Ceph : 77 | 78 | ceph-deploy disk zap {osd-server-name}:{disk-name} 79 | ceph-deploy disk zap osdserver1:sdb 80 | 81 | **重要:** 这会删除磁盘上的所有数据。 82 | 83 | 4、准备 OSD。 84 | 85 | ceph-deploy osd prepare {node-name}:{data-disk}[:{journal-disk}] 86 | ceph-deploy osd prepare osdserver1:sdb:/dev/ssd 87 | ceph-deploy osd prepare osdserver1:sdc:/dev/ssd 88 | 89 | `prepare` 命令只准备 OSD 。在大多数操作系统中,硬盘分区创建后,不用 `activate` 命令也会自动执行 `activate` 阶段(通过 Ceph 的 `udev` 规则)。 90 | 91 | 前例假定一个硬盘只会用于一个 OSD 守护进程,以及一个到 SSD 日志分区的路径。我们建议把日志存储于另外的驱动器以最优化性能;你也可以指定一单独的驱动器用于日志(也许比较昂贵)、或者把日志放到 OSD 数据盘(不建议,因为它有损性能)。前例中我们把日志存储于分好区的固态硬盘。 92 | 93 | **注意:** 在一个节点运行多个 OSD 守护进程、且多个 OSD 守护进程共享一个日志分区时,你应该考虑整个节点的最小 CRUSH 故障域,因为如果这个 SSD 坏了,所有用其做日志的 OSD 守护进程也会失效。 94 | 95 | 5、准备好 OSD 后,可以用下列命令激活它。 96 | 97 | ceph-deploy osd activate {node-name}:{data-disk-partition}[:{journal-disk-partition}] 98 | ceph-deploy osd activate osdserver1:/dev/sdb1:/dev/ssd1 99 | ceph-deploy osd activate osdserver1:/dev/sdc1:/dev/ssd2 100 | 101 | `activate` 命令会让 OSD 进入 `up` 且 `in` 状态。该命令使用的分区路径是前面 `prepare` 命令创建的。 102 | 103 | ### 7.3 删除 OSD(手动) 104 | 105 | 要想缩减集群尺寸或替换硬件,可在运行时删除 OSD 。在 Ceph 里,一个 OSD 通常是一台主机上的一个 `ceph-osd` 守护进程、它运行在一个硬盘之上。如果一台主机上有多个数据盘,你得逐个删除其对应 `ceph-osd` 。通常,操作前应该检查集群容量,看是否快达到上限了,确保删除 OSD 后不会使集群达到 `near full` 比率。 106 | 107 | **警告:** 删除 OSD 时不要让集群达到 `full ratio` 值,删除 OSD 可能导致集群达到或超过 `full ratio` 值。 108 | 109 | 1、停止需要剔除的 OSD 进程,让其他的 OSD 知道这个 OSD 不提供服务了。停止 OSD 后,状态变为 `down` 。 110 | 111 | ssh {osd-host} 112 | sudo stop ceph-osd id={osd-num} 113 | 114 | 2、将 OSD 标记为 `out` 状态,这个一步是告诉 mon,这个 OSD 已经不能服务了,需要在其他的 OSD 上进行数据的均衡和恢复了。 115 | 116 | ceph osd out {osd-num} 117 | 118 | 执行完这一步后,会触发数据的恢复过程。此时应该等待数据恢复结束,集群恢复到 `HEALTH_OK` 状态,再进行下一步操作。 119 | 120 | 3、删除 CRUSH Map 中的对应 OSD 条目,它就不再接收数据了。你也可以反编译 CRUSH Map、删除 device 列表条目、删除对应的 host 桶条目或删除 host 桶(如果它在 CRUSH Map 里,而且你想删除主机),重编译 CRUSH Map 并应用它。详情参见本手册第一部分 [9. 修改 Crushmap](./modify_crushmap.md) 。 121 | 122 | ceph osd crush remove {name} 123 | 124 | 该步骤会触发数据的重新分布。等待数据重新分布结束,整个集群会恢复到 `HEALTH_OK` 状态。 125 | 126 | 4、删除 OSD 认证密钥: 127 | 128 | ceph auth del osd.{osd-num} 129 | 130 | 5、删除 OSD 。 131 | 132 | ceph osd rm {osd-num} 133 | #for example 134 | ceph osd rm 1 135 | 136 | 6、卸载 OSD 的挂载点。 137 | 138 | sudo umount /var/lib/ceph/osd/$cluster-{osd-num} 139 | 140 | 7、登录到保存 `ceph.conf` 主拷贝的主机。 141 | 142 | ssh {admin-host} 143 | cd /etc/ceph 144 | vim ceph.conf 145 | 146 | 8、从 `ceph.conf` 配置文件里删除对应条目。 147 | 148 | [osd.1] 149 | host = {hostname} 150 | 151 | 9、从保存 `ceph.conf` 主拷贝的主机,把更新过的 `ceph.conf` 拷贝到集群其他主机的 `/etc/ceph` 目录下。 152 | 153 | 如果在 `ceph.conf` 中没有定义各 OSD 入口,就不必执行第 7 ~ 9 步。 154 | -------------------------------------------------------------------------------- /Operation/change_cluster_conf.md: -------------------------------------------------------------------------------- 1 | # 11. 修改集群配置 2 | 3 | ---------- 4 | 5 | 启动 Ceph 存储集群时,各守护进程都从同一个配置文件(即默认的 `ceph.conf` )里查找它自己的配置。`ceph.conf` 中可配置参数很多,有时我们需要根据实际环境对某些参数进行修改。 6 | 7 | 修改的方式分为两种:直接修改 `ceph.conf` 配置文件中的参数值,修改完后需要重启 Ceph 进程才能生效。或在运行中动态地进行参数调整,无需重启进程。 8 | 9 | ### 11.1 查看运行时配置 10 | 11 | 如果你的 Ceph 存储集群在运行,而你想看一个在运行进程的配置,用下面的命令: 12 | 13 | ceph daemon {daemon-type}.{id} config show | less 14 | 15 | 如果你现在位于 osd.0 所在的主机,命令将是: 16 | 17 | ceph daemon osd.0 config show | less 18 | 19 | ### 11.2 修改配置文件 20 | 21 | Ceph 配置文件可用于配置存储集群内的所有守护进程、或者某一类型的所有守护进程。要配置一系列守护进程,这些配置必须位于能收到配置的段落之下,比如: 22 | 23 | **`[global]`** 24 | 25 | 描述: `[global]` 下的配置影响 Ceph 集群里的所有守护进程。 26 | 实例: `auth supported = cephx` 27 | 28 | **`[osd]`** 29 | 30 | 描述: `[osd]` 下的配置影响存储集群里的所有 `ceph-osd` 进程,并且会覆盖 `[global]` 下的同一选项。 31 | 实例: `osd journal size = 1000` 32 | 33 | **`[mon]`** 34 | 35 | 描述: `[mon]` 下的配置影响集群里的所有 `ceph-mon` 进程,并且会覆盖 `[global]` 下的同一选项。 36 | 实例: `mon addr = 10.0.0.101:6789` 37 | 38 | **`[mds]`** 39 | 40 | 描述: `[mds]` 下的配置影响集群里的所有 `ceph-mds` 进程,并且会覆盖 `[global]` 下的同一选项。 41 | 实例: `host = myserver01` 42 | 43 | **`[client]`** 44 | 45 | 描述: `[client]` 下的配置影响所有客户端(如挂载的 Ceph 文件系统、挂载的块设备等等)。 46 | 实例: `log file = /var/log/ceph/radosgw.log` 47 | 48 | 全局设置影响集群内所有守护进程的例程,所以 `[global]` 可用于设置适用所有守护进程的选项。但可以用这些覆盖 `[global]` 设置: 49 | 50 | 1. 在 `[osd]` 、 `[mon]` 、 `[mds]` 下更改某一类进程的配置。 51 | 2. 更改特定进程的设置,如 `[osd.1]` 。 52 | 53 | 覆盖全局设置会影响所有子进程,明确剔除的例外。 54 | 55 | ### 11.3 运行中动态调整 56 | 57 | Ceph 可以在运行时更改 `ceph-osd` 、 `ceph-mon` 、 `ceph-mds` 守护进程的配置,此功能在增加/降低日志输出、启用/禁用调试设置、甚至是运行时优化的时候非常有用。Ceph 集群提供两种方式的调整,使用 `tell` 的方式和 `daemon` 设置的方式。 58 | 59 | ##### tell 方式设置 60 | 61 | 下面是使用 tell 命令的修改方法: 62 | 63 | ceph tell {daemon-type}.{id or *} injectargs --{name} {value} [--{name} {value}] 64 | 65 | 用 `osd` 、 `mon` 、 `mds` 中的一个替代 `{daemon-type}` ,你可以用星号( `*` )更改一类进程的所有实例配置、或者更改某一具体进程 ID (即数字或字母)的配置。例如提高名为 `osd.0` 的 `ceph-osd` 进程之调试级别的命令如下: 66 | 67 | ceph tell osd.0 injectargs --debug-osd 20 --debug-ms 1 68 | 69 | 在 `ceph.conf` 文件里配置时用空格分隔关键词;但在命令行使用的时候要用下划线或连字符( `_` 或 `-` )分隔,例如 `debug osd` 变成 `debug-osd` 。 70 | 71 | ##### daemon 方式设置 72 | 73 | 除了上面的 tell 的方式调整,还可以使用 daemon 的方式进行设置。 74 | 75 | 1、获取当前的参数 76 | 77 | ceph daemon osd.1 config get mon_osd_full_ratio 78 | 79 | { 80 | "mon_osd_full_ratio": "0.98" 81 | } 82 | 83 | 2、修改配置 84 | 85 | ceph daemon osd.1 config set mon_osd_full_ratio 0.97 86 | 87 | { 88 | "success": "mon_osd_full_ratio = '0.97' " 89 | } 90 | 91 | 92 | 3、检查配置 93 | 94 | ceph daemon osd.1 config get mon_osd_full_ratio 95 | 96 | { 97 | "mon_osd_full_ratio": "0.97" 98 | } 99 | 100 | 101 | **注意:** 重启进程后配置会恢复到默认参数,在进行在线调整后,如果这个参数是后续是需要使用的,那么就需要将相关的参数写入到配置文件 `ceph.conf` 当中。 102 | 103 | ##### 两种设置方式的使用场景 104 | 使用 tell 的方式适合对整个集群进行设置,使用 `*` 号进行匹配,就可以对整个集群的角色进行设置。而出现节点异常无法设置时候,只会在命令行当中进行报错,不太便于查找。 105 | 106 | 使用 daemon 进行设置的方式就是一个个的去设置,这样可以比较好的反馈,此方法是需要在设置的角色所在的主机上进行设置。 -------------------------------------------------------------------------------- /Operation/common_operations.md: -------------------------------------------------------------------------------- 1 | # 第一部分:常用操作 2 | 3 | 本部分介绍了 Ceph 集群的常用操作,包括进程的起停、集群的监控、用户管理、MON/OSD 的增加和删除、存储池的操作、修改集群的配置,以及 Crushmap 的管理、修改 Monitor 的 IP 等操作。 -------------------------------------------------------------------------------- /Operation/log_debug.md: -------------------------------------------------------------------------------- 1 | # 12. 日志和调试 2 | 3 | 一般来说,你应该在运行时增加调试选项来调试问题;也可以把调试选项添加到 Ceph 配置文件里来调试集群启动时的问题,然后查看 `/var/log/ceph` (默认位置)下的日志文件。 4 | 5 | **Tip:** 调试输出会拖慢系统,这种延时有可能掩盖竞争条件。 6 | 7 | 日志记录是资源密集型任务。如果你碰到的问题在集群的某个特定区域,只启用那个区域对应的日志功能即可。例如,你的 OSD 运行良好、元数据服务器却有问题,这时应该先打开那个可疑元数据服务器实例的调试日志;如果不行再打开各子系统的日志。 8 | 9 | **重要:** 详尽的日志每小时可能超过 1GB ,如果你的系统盘满了,这个节点就会停止工作。 10 | 11 | 如果你要打开或增加 Ceph 日志级别,确保有足够的系统盘空间。滚动日志文件的方法见下面的 **加快日志更迭** 小节。集群稳定运行后,可以关闭不必要的调试选项以优化运行。集群在运行中记录调试输出信息会拖慢系统、且浪费资源。 12 | 13 | ### 12.1 运行时 14 | 15 | 如果你想在运行时查看某一进程的配置,必须先登录对应主机,然后执行命令: 16 | 17 | ceph daemon {daemon-name} config show | less 18 | 19 | 例如: 20 | 21 | ceph daemon osd.0 config show | less 22 | 23 | 要在运行时激活 Ceph 的调试输出(即 `dout()` ),用 `ceph tell` 命令把参数注入运行时配置: 24 | 25 | ceph tell {daemon-type}.{daemon id or *} injectargs --{name} {value} [--{name} {value}] 26 | 27 | 用 `osd` 、 `mon` 或 `mds` 替代 `{daemon-type}` 。还可以用星号( `*` )把配置应用到同类型的所有守护进程,或者指定具体守护进程的 ID 。例如,要给名为 `ods.0` 的 `ceph-osd` 守护进程提高调试级别,用下列命令: 28 | 29 | ceph tell osd.0 injectargs --debug-osd 0/5 30 | 31 | `ceph tell` 命令会通过 monitor 起作用。如果你不能绑定 monitor,仍可以登录你要改的那台主机然后用 ceph daemon 来更改。例如: 32 | 33 | sudo ceph daemon osd.0 config set debug_osd 0/5 34 | 35 | ### 12.2 启动时 36 | 37 | 要在启动时激活调试输出(即 `dout()` ),你得把选项加入配置文件。各进程共有配置可写在配置文件的 `[global]` 段下,某类进程的配置可写在对应的守护进程段下(如 `[mon]` 、 `[osd]` 、 `[mds]` )。例如: 38 | 39 | [global] 40 | debug ms = 1/5 41 | 42 | [mon] 43 | debug mon = 20 44 | debug paxos = 1/5 45 | debug auth = 2 46 | 47 | [osd] 48 | debug osd = 1/5 49 | debug filestore = 1/5 50 | debug journal = 1 51 | debug monc = 5/20 52 | 53 | [mds] 54 | debug mds = 1 55 | debug mds balancer = 1 56 | debug mds log = 1 57 | debug mds migrator = 1 58 | 59 | ### 12.3 加快日志更迭 60 | 61 | 如果你的系统盘比较满,可以修改 `/etc/logrotate.d/ceph` 内的日志滚动配置以加快滚动。在滚动频率后增加一个日志 `size` 选项(达到此大小就滚动)来加快滚动(通过 cronjob )。例如默认配置大致如此: 62 | 63 | rotate 7 64 | weekly 65 | compress 66 | sharedscripts 67 | 68 | 增加一个 `size` 选项。 69 | 70 | rotate 7 71 | weekly 72 | size 500M 73 | compress 74 | sharedscripts 75 | 76 | 然后,打开 crontab 编辑器。 77 | 78 | crontab -e 79 | 80 | 最后,增加一条用以检查 `/etc/logrorate.d/ceph` 文件的语句。 81 | 82 | 30 * * * * /usr/sbin/logrotate /etc/logrotate.d/ceph >/dev/null 2>&1 83 | 84 | 本例中每 30 分钟检查一次 `/etc/logrorate.d/ceph` 文件。 85 | 86 | ### 12.4 VALGRIND 工具 87 | 88 | 调试时可能还需要追踪内存和线程问题。你可以在 Valgrind 中运行单个守护进程、一类进程、或整个集群。 Valgrind 是计算密集型程序,应该只用于开发或调试 Ceph,否则它会拖慢系统。Valgrind 的消息会记录到 `stderr` 。 89 | 90 | ### 12.5 子系统、日志和调试选项 91 | 92 | 大多数情况下,你可以通过子系统打开调试日志输出。 93 | 94 | #### CEPH 子系统概览 95 | 96 | 各子系统都有日志级别用于分别控制其输出日志和暂存日志(内存中),你可以分别为这些子系统设置不同的记录级别。 Ceph 的日志级别从 1 到 20 , 1 是简洁、 20 是详尽。通常,内存驻留日志不会发送到输出日志,除非: 97 | 98 | - 致命信号出现,或者 99 | - 源码中的 `assert` 被触发,或者 100 | - 明确要求发送。 101 | 102 | 调试选项允许用单个数字同时设置日志级别和内存级别,这会将二者设置为一样的值。比如,如果你指定 `debug ms = 5` , Ceph 会把日志级别和内存级别都设置为 `5` 。也可以分别设置,第一个选项是日志级别、第二个是内存级别,二者必须用斜线( / )分隔。假如你想把 `ms` 子系统的调试日志级别设为 `1` 、内存级别设为 `5` ,可以写为 `debug ms = 1/5` ,如下: 103 | 104 | debug {subsystem} = {log-level}/{memory-level} 105 | #for example 106 | debug mds log = 1/20 107 | 108 | Ceph 子系统及其默认日志和内存级别具体见 [ SUBSYSTEM, LOG AND DEBUG SETTINGS ](http://docs.ceph.com/docs/master/rados/troubleshooting/log-and-debug/#subsystem-log-and-debug-settings) 。一旦你完成调试,应该恢复默认值,或一个适合平常运营的级别。 109 | 110 | #### 日志记录选项 111 | 112 | 关于日志记录选项的详细信息,可以参考 Ceph 官方文档的对应内容 [LOGGING SETTING](http://docs.ceph.com/docs/master/rados/troubleshooting/log-and-debug/#logging-settings) 。 -------------------------------------------------------------------------------- /Operation/manage_crushmap.md: -------------------------------------------------------------------------------- 1 | # 9. 管理 Crushmap 2 | 3 | ---------- 4 | 5 | CRUSH 算法通过计算数据存储位置来确定如何存储和检索。 CRUSH 授权 Ceph 客户端直接连接 OSD ,而非通过一个中央服务器或代理。数据存储、检索算法的使用,使 Ceph 避免了单点故障、性能瓶颈、和伸缩的物理限制。 6 | 7 | CRUSH 需要一张集群的 Map,且使用 CRUSH Map 把数据伪随机地、尽量平均地分布到整个集群的 OSD 里。CRUSH Map 包含 OSD 列表、把设备汇聚为物理位置的“桶”列表、和指示 CRUSH 如何复制存储池里的数据的规则列表。 8 | 9 | 完全手动管理 CRUSH Map 也是可能的,在配置文件中设定: 10 | 11 | osd crush update on start = false 12 | 13 | ### 9.1 编辑 CRUSH Map 14 | 15 | 要编辑现有的 CRUSH Map: 16 | 17 | 1. 获取 CRUSH Map; 18 | 2. 反编译 CRUSH 图; 19 | 3. 至少编辑一个设备、桶、规则; 20 | 4. 重编译 CRUSH Map; 21 | 5. 注入 CRUSH Map。 22 | 23 | 要激活 CRUSH Map 里某存储池的规则,找到通用规则集编号,然后把它指定到那个规则集。详情参见本手册第一部分 [8. 操作 Pool](./operate_pool.md) 中调整存储池选项值部分。 24 | 25 | ##### 获取 CRUSH Map 26 | 27 | 要获取集群的 CRUSH Map,执行命令: 28 | 29 | ceph osd getcrushmap -o {compiled-crushmap-filename} 30 | 31 | Ceph 将把 CRUSH 输出( -o )到你指定的文件,由于 CRUSH Map 是已编译的,所以编辑前必须先反编译。 32 | 33 | ##### 反编译 CRUSH Map 34 | 35 | 要反编译 CRUSH Map,执行命令: 36 | 37 | crushtool -d {compiled-crushmap-filename} -o {decompiled-crushmap-filename} 38 | 39 | Ceph 将反编译( -d )二进制 CRUSH Map,且输出( -o )到你指定的文件。 40 | 41 | ##### 编译 CRUSH Map 42 | 43 | 要编译 CRUSH Map,执行命令: 44 | 45 | crushtool -c {decompiled-crush-map-filename} -o {compiled-crush-map-filename} 46 | 47 | Ceph 将把已编译的 CRUSH Map 保存到你指定的文件。 48 | 49 | ##### 注入 CRUSH Map 50 | 51 | 要把 CRUSH Map 应用到集群,执行命令: 52 | 53 | ceph osd setcrushmap -i {compiled-crushmap-filename} 54 | 55 | Ceph 将把你指定的已编译 CRUSH Map 注入到集群。 56 | 57 | ### 9.2 CRUSH Map 参数 58 | 59 | CRUSH Map 主要有 4 个段落。 60 | 61 | 1. **设备:**由任意对象存储设备组成,即对应一个 `ceph-osd `进程的存储器。 Ceph 配置文件里的每个 OSD 都应该有一个设备。 62 | 2. **桶类型:** 定义了 CRUSH 分级结构里要用的桶类型( `types` ),桶由逐级汇聚的存储位置(如行、机柜、机箱、主机等等)及其权重组成。 63 | 3. **桶实例:** 定义了桶类型后,还必须声明主机的桶类型、以及规划的其它故障域。 64 | 4. **规则:** 由选择桶的方法组成。 65 | 66 | ##### CRUSH Map 之设备 67 | 68 | 为把 PG 映射到 OSD , CRUSH Map 需要 OSD 列表(即配置文件所定义的 OSD 守护进程名称),所以它们首先出现在 CRUSH Map 里。要在 CRUSH Map 里声明一个设备,在设备列表后面新建一行,输入 `device` 、之后是唯一的数字 ID 、之后是相应的 `ceph-osd` 守护进程实例名字。 69 | 70 | # devices 71 | device {num} {osd.name} 72 | 73 | 例如: 74 | 75 | # devices 76 | device 0 osd.0 77 | device 1 osd.1 78 | device 2 osd.2 79 | device 3 osd.3 80 | 81 | ##### CRUSH Map 之桶类型 82 | 83 | CRUSH Map 里的第二个列表定义了 bucket (桶)类型,桶简化了节点和叶子层次。节点(或非叶子)桶在分级结构里一般表示物理位置,节点汇聚了其它节点或叶子,叶桶表示 `ceph-osd` 守护进程及其对应的存储媒体。 84 | 85 | 要往 CRUSH Map 中增加一种 bucket 类型,在现有桶类型列表下方新增一行,输入 `type` 、之后是惟一数字 ID 和一个桶名。按惯例,会有一个叶子桶为 `type 0` ,然而你可以指定任何名字(如 osd 、 disk 、 drive 、 storage 等等): 86 | 87 | # types 88 | type {num} {bucket-name} 89 | 90 | 例如: 91 | 92 | # types 93 | type 0 osd 94 | type 1 host 95 | type 2 chassis 96 | type 3 rack 97 | type 4 row 98 | type 5 pdu 99 | type 6 pod 100 | type 7 room 101 | type 8 datacenter 102 | type 9 region 103 | type 10 root 104 | 105 | ##### CRUSH Map 之桶层次 106 | 107 | CRUSH 算法根据各设备的权重、大致统一的概率把数据对象分布到存储设备中。 CRUSH 根据你定义的集群运行图分布对象及其副本, CRUSH Map 表达了可用存储设备以及包含它们的逻辑单元。 108 | 109 | 要把 PG 映射到跨故障域的 OSD ,一个 CRUSH Map 需定义一系列分级桶类型(即现有 CRUSH Map 的 `# type` 下)。创建桶分级结构的目的是按故障域隔离叶子节点,像主机、机箱、机柜、电力分配单元、机群、行、房间、和数据中心。除了表示叶子节点的 OSD ,其它分级结构都是任意的,你可以按需定义。 110 | 111 | 声明一个桶实例时,你必须指定其类型、惟一名称(字符串)、惟一负整数 ID (可选)、指定和各条目总容量/能力相关的权重、指定桶算法(通常是 straw )、和哈希(通常为 0 ,表示哈希算法 rjenkins1 )。一个桶可以包含一到多个条目,这些条目可以由节点桶或叶子组成,它们可以有个权重用来反映条目的相对权重。 112 | 113 | 你可以按下列语法声明一个节点桶: 114 | 115 | [bucket-type] [bucket-name] { 116 | id [a unique negative numeric ID] 117 | weight [the relative capacity/capability of the item(s)] 118 | alg [the bucket type: uniform | list | tree | straw ] 119 | hash [the hash type: 0 by default] 120 | item [item-name] weight [weight] 121 | } 122 | 123 | 例如,我们可以定义两个主机桶和一个机柜桶,机柜桶包含两个主机桶, OSD 被声明为主机桶内的条目: 124 | 125 | host node1 { 126 | id -1 127 | alg straw 128 | hash 0 129 | item osd.0 weight 1.00 130 | item osd.1 weight 1.00 131 | } 132 | 133 | host node2 { 134 | id -2 135 | alg straw 136 | hash 0 137 | item osd.2 weight 1.00 138 | item osd.3 weight 1.00 139 | } 140 | 141 | rack rack1 { 142 | id -3 143 | alg straw 144 | hash 0 145 | item node1 weight 2.00 146 | item node2 weight 2.00 147 | } 148 | 149 | 150 | ###### 调整桶的权重 151 | 152 | Ceph 用双精度类型数据表示桶权重。权重和设备容量不同,我们建议用 1.00 作为 1TB 存储设备的相对权重,这样 0.5 的权重大概代表 500GB 、 3.00 大概代表 3TB 。较高级桶的权重是所有叶子桶的权重之和。 153 | 154 | 一个桶的权重是一维的,你也可以计算条目权重来反映存储设备性能。例如,如果你有很多 1TB 的硬盘,其中一些数据传输速率相对低、其他的数据传输率相对高,即使它们容量相同,也应该设置不同的权重(如给吞吐量较低的硬盘设置权重 0.8 ,较高的设置 1.20 )。 155 | 156 | ##### CRUSH Map 之规则 157 | 158 | CRUSH Map 支持“ CRUSH 规则”的概念,用以确定一个存储池里数据的分布。CRUSH 规则定义了归置和复制策略、或分布策略,用它可以规定 CRUSH 如何放置对象副本。对大型集群来说,你可能创建很多存储池,且每个存储池都有它自己的 CRUSH 规则集和规则。默认的 CRUSH Map 里,每个存储池有一条规则、一个规则集被分配到每个默认存储池。 159 | 160 | **注意:** 大多数情况下,你都不需要修改默认规则。新创建存储池的默认规则集是 `0` 。 161 | 162 | 规则格式如下: 163 | 164 | rule { 165 | 166 | ruleset 167 | type [ replicated | erasure ] 168 | min_size 169 | max_size 170 | step take 171 | step [choose|chooseleaf] [firstn|indep] 172 | step emit 173 | } 174 | 175 | 参数说明: 176 | 177 | - `ruleset`:区分一条规则属于某个规则集的手段。给存储池设置规则集后激活。 178 | - `type`:规则类型,目前仅支持 `replicated` 和 `erasure` ,默认是 `replicated` 。 179 | - `min_size`:可以选择此规则的存储池最小副本数。 180 | - `max_size`:可以选择此规则的存储池最大副本数。 181 | - `step take `:选取起始的桶名,并迭代到树底。 182 | - `step choose firstn {num} type {bucket-type}`:选取指定类型桶的数量,这个数字通常是存储池的副本数(即 pool size )。如果 `{num} == 0` , 选择 `pool-num-replicas` 个桶(所有可用的);如果 `{num} > 0 && < pool-num-replicas` ,就选择那么多的桶;如果 `{num} < 0` ,它意味着选择 `pool-num-replicas - {num}` 个桶。 183 | - `step chooseleaf firstn {num} type {bucket-type}`:选择 `{bucket-type}` 类型的桶集合,并从各桶的子树里选择一个叶子节点。桶集合的数量通常是存储池的副本数(即 pool size )。如果 `{num} == 0` ,选择 `pool-num-replicas` 个桶(所有可用的);如果 `{num} > 0 && < pool-num-replicas` ,就选择那么多的桶;如果 `{num} < 0` ,它意味着选择 `pool-num-replicas - {num}` 个桶。 184 | - `step emit`:输出当前值并清空堆栈。通常用于规则末尾,也适用于相同规则应用到不同树的情况。 185 | 186 | ### 9.3 主亲和性 187 | 188 | 某个 Ceph 客户端读写数据时,总是连接 acting set 里的主 OSD (如 `[2, 3, 4]` 中, `osd.2` 是主的)。有时候某个 OSD 与其它的相比并不适合做主 OSD (比如其硬盘慢、或控制器慢)。最大化硬件利用率时为防止性能瓶颈(特别是读操作),你可以调整 OSD 的主亲和性,这样 CRUSH 就尽量不把它用作 acting set 里的主 OSD 了。 189 | 190 | ceph osd primary-affinity 191 | 192 | 主亲和性默认为 `1` (就是说此 OSD 可作为主 OSD )。此值合法范围为 `0-1` ,其中 `0` 意为此 OSD 不能用作主的, `1` 意为 OSD 可用作主的。此权重 `< 1` 时, CRUSH 选择主 OSD 时选中它的可能性就较低。 193 | 194 | ### 9.4 增加/移动 OSD 195 | 196 | 要增加或移动在线集群里 OSD 所对应的 CRUSH Map 条目,执行 ceph osd crush set 命令。 197 | 198 | ceph osd crush set {id-or-name} {weight} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...] 199 | 200 | ### 9.5 调整 OSD 的 CRUSH 权重 201 | 202 | 要调整在线集群中某个 OSD 的 CRUSH 权重,执行命令: 203 | 204 | ceph osd crush reweight {name} {weight} 205 | 206 | ### 9.6 删除 OSD 207 | 208 | 要从在线集群里把某个 OSD 彻底踢出 CRUSH Map,或仅踢出某个指定位置的 OSD,执行命令: 209 | 210 | ceph osd crush remove {name} {} 211 | 212 | ### 9.7 增加桶 213 | 214 | 要在运行集群的 CRUSH Map 中新建一个桶,用 ceph osd crush add-bucket 命令: 215 | 216 | ceph osd crush add-bucket {bucket-name} {bucket-type} 217 | 218 | ### 9.8 移动桶 219 | 220 | 要把一个桶移动到 CRUSH Map 里的不同位置,执行命令: 221 | 222 | ceph osd crush move {bucket-name} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...] 223 | 224 | ### 9.9 删除桶 225 | 226 | 要把一个桶从 CRUSH Map 的分级结构中删除,可用此命令: 227 | 228 | ceph osd crush remove {bucket-name} 229 | 230 | 注意:从 CRUSH 分级结构里删除时必须是空桶。 231 | 232 | 233 | ### 9.10 可调选项 234 | 235 | 从 v0.74 起,如果 CRUSH 可调选项不是最优值( v0.73 版里的默认值) Ceph 就会发出健康告警,有两种方法可消除这些告警: 236 | 237 | 1、调整现有集群上的可调选项。注意,这可能会导致一些数据迁移(可能有 10% 之多)。这是推荐的办法,但是在生产集群上要注意此调整对性能带来的影响。此命令可启用较优可调选项: 238 | 239 | ceph osd crush tunables optimal 240 | 241 | 如果切换得不太顺利(如负载太高)且切换才不久,或者有客户端兼容问题(较老的 cephfs 内核驱动或 rbd 客户端、或早于 bobtail 的 librados 客户端),你可以这样切回: 242 | 243 | ceph osd crush tunables legacy 244 | 245 | 2、不对 CRUSH 做任何更改也能消除报警,把下列配置加入 `ceph.conf` 的 `[mon]` 段下: 246 | 247 | mon warn on legacy crush tunables = false 248 | 249 | 为使变更生效需重启所有监视器,或者执行下列命令: 250 | 251 | ceph tell mon.\* injectargs --no-mon-warn-on-legacy-crush-tunables 252 | 253 | ### 9.11 CRUSH Map 实例 254 | 255 | 假设你想让大多数存储池映射到使用大容量硬盘的 OSD 上,但是其中一些存储池映射到使用高速 SSD 的 OSD 上。在同一个 CRUSH Map 内有多个独立的 CRUSH 层级结构是可能的,定义两棵树、分别有自己的根节点 —— 一个用于机械硬盘(如 root platter )、一个用于 SSD (如 root ssd ),具体的 CRUSH Map 内容如下: 256 | 257 | # devices 258 | device 0 osd.0 259 | device 1 osd.1 260 | device 2 osd.2 261 | device 3 osd.3 262 | device 4 osd.4 263 | device 5 osd.5 264 | device 6 osd.6 265 | device 7 osd.7 266 | 267 | # types 268 | type 0 osd 269 | type 1 host 270 | type 2 root 271 | 272 | # buckets 273 | host ceph-osd-ssd-server-1 { 274 | id -1 275 | alg straw 276 | hash 0 277 | item osd.0 weight 1.00 278 | item osd.1 weight 1.00 279 | } 280 | 281 | host ceph-osd-ssd-server-2 { 282 | id -2 283 | alg straw 284 | hash 0 285 | item osd.2 weight 1.00 286 | item osd.3 weight 1.00 287 | } 288 | 289 | host ceph-osd-platter-server-1 { 290 | id -3 291 | alg straw 292 | hash 0 293 | item osd.4 weight 1.00 294 | item osd.5 weight 1.00 295 | } 296 | 297 | host ceph-osd-platter-server-2 { 298 | id -4 299 | alg straw 300 | hash 0 301 | item osd.6 weight 1.00 302 | item osd.7 weight 1.00 303 | } 304 | 305 | root platter { 306 | id -5 307 | alg straw 308 | hash 0 309 | item ceph-osd-platter-server-1 weight 2.00 310 | item ceph-osd-platter-server-2 weight 2.00 311 | } 312 | 313 | root ssd { 314 | id -6 315 | alg straw 316 | hash 0 317 | item ceph-osd-ssd-server-1 weight 2.00 318 | item ceph-osd-ssd-server-2 weight 2.00 319 | } 320 | 321 | # rules 322 | rule replicated_ruleset { 323 | ruleset 0 324 | type replicated 325 | min_size 1 326 | max_size 10 327 | step take default 328 | step chooseleaf firstn 0 type host 329 | step emit 330 | } 331 | 332 | rule platter { 333 | ruleset 1 334 | type replicated 335 | min_size 0 336 | max_size 10 337 | step take platter 338 | step chooseleaf firstn 0 type host 339 | step emit 340 | } 341 | 342 | rule ssd { 343 | ruleset 2 344 | type replicated 345 | min_size 0 346 | max_size 4 347 | step take ssd 348 | step chooseleaf firstn 0 type host 349 | step emit 350 | } 351 | 352 | rule ssd-primary { 353 | ruleset 3 354 | type replicated 355 | min_size 5 356 | max_size 10 357 | step take ssd 358 | step chooseleaf firstn 1 type host 359 | step emit 360 | step take platter 361 | step chooseleaf firstn -1 type host 362 | step emit 363 | } 364 | 365 | 然后你可以设置一个存储池,让它使用 SSD 规则: 366 | 367 | ceph osd pool set crush_ruleset 2 368 | 369 | 同样,用 `ssd-primary` 规则将使存储池内的各归置组用 SSD 作主 OSD ,普通硬盘作副本。 -------------------------------------------------------------------------------- /Operation/modify_mon_ip.md: -------------------------------------------------------------------------------- 1 | # 10. 修改 MON IP 2 | 3 | ---------- 4 | 5 | Ceph 客户端和其他 Ceph 守护进程通过 `ceph.conf` 来发现 monitor。但是 monitor 之间是通过 mon map 而非 `ceph.conf` 来发现彼此。 6 | 7 | ### 10.1 修改 MON IP(正确的方法) 8 | 9 | 仅修改 `ceoh.conf` 中 mon 的 IP 是不足以确保集群中的其他 monitor 收到更新的。要修改一个 mon 的 IP,你必须先新增一个使用新 IP 的 monitor(参考[1.6 增加/删除 Monitor](./add_rm_mon.md)),确保这个新 mon 成功加入集群并形成法定人数。然后,删除使用旧 IP 的 mon。最后,更新 `ceph.conf` ,以便客户端和其他守护进程可以知道新 mon 的 IP。 10 | 11 | 比如,假设现有 3 个 monitors: 12 | 13 | [mon.a] 14 | host = host01 15 | addr = 10.0.0.1:6789 16 | [mon.b] 17 | host = host02 18 | addr = 10.0.0.2:6789 19 | [mon.c] 20 | host = host03 21 | addr = 10.0.0.3:6789 22 | 23 | 把 `mon.c` 变更为 `mon.d` 。按照本手册第一部分 [6. 增加/删除 Monitor](./add_rm_mon.md),增加一个 `mon.d` ,host 设为 `host04`,IP 地址设为 `10.0.0.4`。先启动 `mon.d` ,再按照 [6. 增加/删除 Monitor](./add_rm_mon.md) 删除 `mon.c` ,否则会破坏法定人数。 24 | 25 | ### 10.2 修改 MON IP(不太友好的方法) 26 | 27 | 有时,monitor 需要迁移到一个新的网络中、数据中心的其他位置或另一个数据中心。这时,需要为集群中所有的 monitors 生成一个新的 mon map (指定了新的 MON IP),再注入每一个 monitor 中。 28 | 29 | 还以前面的 mon 配置为例。假定想把 monitor 从 `10.0.0.x` 网段改为 `10.1.0.x` 网段,这两个网段直接是不通的。执行下列步骤: 30 | 31 | 1、获取 mon map。 32 | 33 | ceph mon getmap -o {tmp}/{filename} 34 | 35 | 2、下面的例子说明了 monmap 的内容。 36 | 37 | $ monmaptool --print {tmp}/{filename} 38 | 39 | monmaptool: monmap file {tmp}/{filename} 40 | epoch 1 41 | fsid 224e376d-c5fe-4504-96bb-ea6332a19e61 42 | last_changed 2012-12-17 02:46:41.591248 43 | created 2012-12-17 02:46:41.591248 44 | 0: 10.0.0.1:6789/0 mon.a 45 | 1: 10.0.0.2:6789/0 mon.b 46 | 2: 10.0.0.3:6789/0 mon.c 47 | 48 | 3、删除已有的 monitors。 49 | 50 | $ monmaptool --rm a --rm b --rm c {tmp}/{filename} 51 | 52 | monmaptool: monmap file {tmp}/{filename} 53 | monmaptool: removing a 54 | monmaptool: removing b 55 | monmaptool: removing c 56 | monmaptool: writing epoch 1 to {tmp}/{filename} (0 monitors) 57 | 58 | 4、新增 monitor。 59 | 60 | $ monmaptool --add a 10.1.0.1:6789 --add b 10.1.0.2:6789 --add c 10.1.0.3:6789 {tmp}/{filename} 61 | 62 | monmaptool: monmap file {tmp}/{filename} 63 | monmaptool: writing epoch 1 to {tmp}/{filename} (3 monitors) 64 | 65 | 5、检查 monmap 的新内容。 66 | 67 | $ monmaptool --print {tmp}/{filename} 68 | 69 | monmaptool: monmap file {tmp}/{filename} 70 | epoch 1 71 | fsid 224e376d-c5fe-4504-96bb-ea6332a19e61 72 | last_changed 2012-12-17 02:46:41.591248 73 | created 2012-12-17 02:46:41.591248 74 | 0: 10.1.0.1:6789/0 mon.a 75 | 1: 10.1.0.2:6789/0 mon.b 76 | 2: 10.1.0.3:6789/0 mon.c 77 | 78 | 此时,我们假定 monitor 已在新位置安装完毕。下面的步骤就是分发新的 monmap 并注入到各新 monitor 中。 79 | 80 | 1、停止所有的 monitor 。必须停止 mon 守护进程才能进行 monmap 注入。 81 | 82 | 2、注入 monmap。 83 | 84 | ceph-mon -i {mon-id} --inject-monmap {tmp}/{filename} 85 | 86 | 3、重启各 monitors 。 -------------------------------------------------------------------------------- /Operation/monitor_cluster.md: -------------------------------------------------------------------------------- 1 | # 2. 监控集群 2 | 3 | ---------- 4 | 5 | 集群运行起来后,你可以用 `ceph` 工具来监控集群的状态,典型的监控项目包括检查 OSD 状态、monitor 的状态、PG 的状态和元数据服务器的状态(目前楚天云环境并没有部署元数据服务器)。 6 | 7 | ### 2.1 交互模式 8 | 9 | 要在交互模式下运行 `ceph` ,不要带参数运行 `ceph` ,例如: 10 | 11 | ceph 12 | ceph> health 13 | ceph> status 14 | ceph> quorum_status 15 | ceph> mon_status 16 | 17 | ### 2.2 检查集群的监控状况 18 | 启动集群后、读写数据前,先检查下集群的健康状态。你可以用下面的命令检查: 19 | 20 | ceph health 21 | 22 | 如果你的配置文件或 keyring 文件不在默认路径下,你得在命令中指定: 23 | 24 | ceph -c /path/to/conf -k /path/to/keyring health 25 | 26 | 集群刚起来的时候,你也许会碰到像 `HEALTH_WARN XXX num placement groups stale` 这样的健康告警,等一会再检查下。集群准备好的话 `ceph health` 会给出 `HEALTH_OK` 这样的消息,这时候就可以开始使用集群了。 27 | 28 | ### 2.3 观察集群 29 | 要观察集群内正发生的事件,打开一个新终端,然后输入: 30 | 31 | ceph -w 32 | 33 | Ceph 会打印各种事件。例如一个包括 3 个 Mon、和 33 个 OSD 的 Ceph 集群可能会打印出这些: 34 | 35 | cluster b84b887e-9e0c-4211-8423-e0596939cd36 36 | health HEALTH_OK 37 | monmap e1: 3 mons at {OPS-ceph1=192.168.219.30:6789/0,OPS-ceph2=192.168.219.31:6789/0,OPS-ceph3=192.168.219.32:6789/0} 38 | election epoch 94, quorum 0,1,2 OPS-ceph1,OPS-ceph2,OPS-ceph3 39 | osdmap e1196: 33 osds: 33 up, 33 in 40 | pgmap v1789894: 2752 pgs, 7 pools, 590 GB data, 110 kobjects 41 | 1154 GB used, 83564 GB / 84719 GB avail 42 | 2752 active+clean 43 | client io 0 B/s rd, 25852 B/s wr, 7 op/s 44 | 45 | 2016-11-04 20:20:13.682953 mon.0 [INF] pgmap v1789893: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 44908 B/s wr, 14 op/s 46 | 2016-11-04 20:20:15.686275 mon.0 [INF] pgmap v1789894: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 25852 B/s wr, 7 op/s 47 | 2016-11-04 20:20:16.690680 mon.0 [INF] pgmap v1789895: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 32345 B/s wr, 16 op/s 48 | 2016-11-04 20:20:17.694259 mon.0 [INF] pgmap v1789896: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 57170 B/s wr, 32 op/s 49 | 2016-11-04 20:20:18.698200 mon.0 [INF] pgmap v1789897: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 33148 B/s wr, 16 op/s 50 | 2016-11-04 20:20:20.701697 mon.0 [INF] pgmap v1789898: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 16333 B/s wr, 5 op/s 51 | 2016-11-04 20:20:21.705719 mon.0 [INF] pgmap v1789899: 2752 pgs: 2752 active+clean; 590 GB data, 1154 GB used, 83564 GB / 84719 GB avail; 0 B/s rd, 17705 B/s wr, 12 op/s 52 | 53 | 输出信息里包含: 54 | 55 | - 集群的 ID 56 | - 集群健康状况 57 | - monitor map 版本和 mon 法定人数状态 58 | - OSD map 版本和 OSD 状态摘要 59 | - PG map 版本 60 | - PG 和 Pool 的数量 61 | - 集群存储的数据量,对象的总量,以及集群的已用容量/总容量/可用容量 62 | - 客户端的 iops 信息 63 | 64 | ### 2.4 检查集群的使用情况 65 | 要检查集群的数据用量及其在存储池内的分布情况,可以用 `df` 选项,它和 Linux 上的 `df` 相似。如下: 66 | 67 | ceph df 68 | 69 | 得到的输出信息大致如下: 70 | 71 | GLOBAL: 72 | SIZE AVAIL RAW USED %RAW USED 73 | 84719G 83564G 1154G 1.36 74 | POOLS: 75 | NAME ID USED %USED MAX AVAIL OBJECTS 76 | rbd 0 0 0 41381G 0 77 | volumes 1 284G 0.34 41381G 57904 78 | images 2 224G 0.27 41381G 39024 79 | backups 3 0 0 41381G 1 80 | vms 4 28736M 0.03 41381G 4325 81 | volumes-ssd 5 53758M 0.06 41381G 11854 82 | fitos_backup_pool 7 1286M 0 41381G 354 83 | 84 | 输出的 **GLOBAL** 段展示了数据所占用集群存储空间的概要。 85 | 86 | - **SIZE:** 集群的总容量。 87 | - **AVAIL:** 集群的可用空间总量。 88 | - **RAW USED:**已用存储空间总量。 89 | - **% RAW USED:**已用存储空间比率。用此值对比 `full ratio` 和 `near full ratio` 来确保不会用尽集群空间。 90 | 91 | 输出的 **POOLS** 段展示了存储池列表及各存储池的大致使用率。本段没有反映出副本、克隆和快照的占用情况。例如,如果你把 1MB 的数据存储为对象,理论使用率将是 1MB ,但考虑到副本数、克隆数、和快照数,实际使用量可能是 2MB 或更多。 92 | 93 | - **NAME:**存储池名字。 94 | - **ID:**存储池唯一标识符。 95 | - **USED:**大概数据量,单位为 KB 、MB 或 GB ; 96 | - **%USED:**各存储池的大概使用率。 97 | - **Objects:**各存储池内的大概对象数。 98 | 99 | 注意: **POOLS** 段内的数字是估计值,它们不包含副本、快照或克隆。因此,各 Pool 的 **USED** 和 **%USED** 数量之和不会达到 **GLOBAL** 段中的 **RAW USED** 和 **%RAW USED** 数量。 100 | 101 | ### 2.5 检查集群状态 102 | 要检查集群的状态,执行下面的命令: 103 | 104 | ceph status 105 | 106 | 或者: 107 | 108 | ceph -s 109 | 110 | 在交互模式下,输入 `status` 然后按回车: 111 | 112 | ceph> status 113 | 114 | Ceph 将打印集群状态,例如一个包括 1 个监视器、和 2 个 OSD 的小型 Ceph 集群可能打印: 115 | 116 | cluster b370a29d-9287-4ca3-ab57-3d824f65e339 117 | health HEALTH_OK 118 | monmap e1: 1 mons at {ceph1=10.0.0.8:6789/0}, election epoch 2, quorum 0 ceph1 119 | osdmap e63: 2 osds: 2 up, 2 in 120 | pgmap v41332: 952 pgs, 20 pools, 17130 MB data, 2199 objects 121 | 115 GB used, 167 GB / 297 GB avail 122 | 1 active+clean+scrubbing+deep 123 | 951 active+clean 124 | 125 | ### 2.6 检查 OSD 状态 126 | 你可以执行下列命令来确定 OSD 状态为 `up` 且 `in` : 127 | 128 | ceph osd stat 129 | 130 | 或者: 131 | 132 | ceph osd dump 133 | 134 | 你也可以根据 OSD 在 CRUSH MAP 里的位置来查看: 135 | 136 | ceph osd tree 137 | 138 | Ceph 会打印 CRUSH 树,包括 host 的名称、它上面的 OSD 例程、状态及权重: 139 | 140 | ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY 141 | -1 0.05997 root default 142 | -2 0.01999 host ceph01 143 | 0 0.01999 osd.0 up 1.00000 1.00000 144 | -3 0.01999 host ceph02 145 | 1 0.01999 osd.1 up 1.00000 1.00000 146 | -4 0.01999 host ceph03 147 | 2 0.01999 osd.2 up 1.00000 1.00000 148 | 149 | 另请参考本手册第一部分 [3. 监控 OSD](./monitor_osd.md)。 150 | 151 | ### 2.7 检查 Mon 状态 152 | 153 | 如果集群中有多个 Mon(很可能),你启动集群后、读写数据前应该检查 Mon 法定人数状态。运行着多个 Mon 时必须形成法定人数,最好周期性地检查 Mon 状态来确定它们在运行。 154 | 155 | 要查看 Mon map,执行下面的命令: 156 | 157 | ceph mon stat 158 | 159 | 或者: 160 | 161 | ceph mon dump 162 | 163 | 要检查监视器的法定人数状态,执行下面的命令: 164 | 165 | ceph quorum_status -f json-pretty 166 | 167 | Ceph 会返回法定人数状态,例如,包含 3 个监视器的 Ceph 集群可能返回下面的: 168 | 169 | { 170 | "election_epoch": 94, 171 | "quorum": [ 172 | 0, 173 | 1, 174 | 2 175 | ], 176 | "quorum_names": [ 177 | "OPS-ceph1", 178 | "OPS-ceph2", 179 | "OPS-ceph3" 180 | ], 181 | "quorum_leader_name": "OPS-ceph1", 182 | "monmap": { "epoch": 1, 183 | "fsid": "b84b887e-9e0c-4211-8423-e0596939cd36", 184 | "modified": "2016-11-04 20:19:57.333655", 185 | "created": "2016-06-23 14:53:07.171558", 186 | "mons": [ 187 | { 188 | "rank": 0, 189 | "name": "OPS-ceph1", 190 | "addr": "192.168.219.30:6789\/0" 191 | }, 192 | { 193 | "rank": 1, 194 | "name": "OPS-ceph2", 195 | "addr": "192.168.219.31:6789\/0" 196 | }, 197 | { 198 | "rank": 2, 199 | "name": "OPS-ceph3", 200 | "addr":"192.168.219.32:6789\/0" 201 | } 202 | ] 203 | } 204 | } 205 | 206 | ### 2.8 检查 MDS 状态 207 | 208 | 元数据服务器为 Ceph 文件系统提供元数据服务,不过在当前生产环境中并未部署 MDS 。元数据服务器有两种状态: `up | down` 和 `active | inactive` ,执行下面的命令查看元数据服务器状态为 `up` 且 `active` : 209 | 210 | ceph mds stat 211 | 212 | 要展示元数据集群的详细状态,执行下面的命令: 213 | 214 | ceph mds dump 215 | 216 | ### 2.9 检查 PG 状态 217 | 218 | PG 把对象映射到 OSD 。监控 PG 时,我们希望它们的状态是 `active` 且 `clean` 。详情请参考本手册第一部分 [4. 监控 PG](./monitor_pg.md) 219 | 220 | ### 2.10 使用管理套接字 221 | 222 | Ceph 管理套接字允许你通过套接字接口查询守护进程,它们默认存在于 `/var/run/ceph` 下。要通过管理套接字访问某个守护进程,先登录它所在的主机、再执行下列命令: 223 | 224 | ceph daemon {daemon-name} 225 | ceph daemon {path-to-socket-file} 226 | 227 | 比如,这是下面这两种用法是等价的: 228 | 229 | ceph daemon osd.0 foo 230 | ceph daemon /var/run/ceph/ceph-osd.0.asok foo 231 | 232 | 用下列命令查看可用的管理套接字命令: 233 | 234 | ceph daemon {daemon-name} help 235 | 236 | 管理套接字命令允许你在运行时查看和修改配置。 237 | 238 | 另外,你可以在运行时直接修改配置选项(也就是说管理套接字会绕过 Mon,不要求你直接登录宿主主机,不像 `ceph {daemon-type} tell {id} injectargs` 会依赖监视器)。 -------------------------------------------------------------------------------- /Operation/monitor_osd.md: -------------------------------------------------------------------------------- 1 | # 3. 监控 OSD 2 | 3 | ---------- 4 | 5 | 某 OSD 的状态可以是在集群内( `in` )或集群外( `out` )、也可以是运行着的( `up` )或不在运行的( `down` )。如果一个 OSD 处于 `up` 状态,它也可以是在集群之内 `in` (你可以读写数据)或者之外 `out` 。如果它以前是 `in` 但最近 `out` 了, Ceph 会把 PG 迁移到其他 OSD 上。如果某个 OSD `out` 了, CRUSH 就不会再分配 PG 给它。如果它 `down` 了,其状态也应该是 `out` 。默认在 OSD `down` 掉 300s 后会标记它为 `out` 状态。 6 | 7 | **注意:如果某个 OSD 状态为 down & in ,必定有问题,而且集群处于非健康状态。** 8 | 9 | OSD 监控的一个重要事情就是,当集群启动并运行时,所有 OSD 也应该是启动( `up` )并在集群内( `in` )运行的。用下列命令查看: 10 | 11 | ceph osd stat 12 | 13 | 其结果会告诉你 osd map 的版本( eNNNN ),总共有多少个 OSD 、几个是 `up` 的、几个是 `in` 的。 14 | 15 | osdmap e26753: 3 osds: 2 up, 3 in 16 | 17 | 如果处于 `in` 状态的 OSD 多于 `up` 的,用下列命令看看哪些 `ceph-osd` 守护进程没在运行: 18 | 19 | ceph osd tree :: 20 | 21 | ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY 22 | -1 0.05997 root default 23 | -2 0.01999 host ceph01 24 | 0 0.01999 osd.0 up 1.00000 1.00000 25 | -3 0.01999 host ceph02 26 | 1 0.01999 osd.1 up 1.00000 1.00000 27 | -4 0.01999 host ceph03 28 | 2 0.01999 osd.2 down 1.00000 1.00000 29 | 30 | 如果有 OSD 处于 down 状态,请尝试启动该 OSD,启动命令见本手册第一部分 [1. 操作集群](./operate_cluster.md)。如果启动失败,请参考本手册第二部分 [2. 常见 OSD 故障处理](../Troubleshooting/troubleshooting_osd.md) 中的相关部分进行处理。 31 | -------------------------------------------------------------------------------- /Operation/monitor_pg.md: -------------------------------------------------------------------------------- 1 | # 4. 监控 PG 2 | 3 | CRUSH 算法把 PG 分配到 OSD 时,它会根据存储池的副本数设置,把 PG 分配到不同的 OSD 上。比如,如果存储池设置为 3 副本, CRUSH 可能把它们分别分配到 `osd.1` 、`osd.2` 、`osd.3` 。考虑到 CRUSH Map 中设定的故障域,实际上 CRUSH 找出的是伪随机位置,所以在大型集群中,很少能看到 PG 被分配到了相邻的 OSD 。我们把涉及某个特定 PG 副本的一组 OSD 称为 **acting set** 。在某些情况下,位于 acting set 中的一个 OSD `down` 了或者不能为 PG 内的对象提供服务,这些情形发生时无需惊慌,常见原因如下: 4 | 5 | - 你增加或移除了某个 OSD 。然后 CRUSH 算法把 PG 重新分配到了其他 OSD ,因此改变了 Acting Set 的构成,并且引发了 “backfill” 过程来进行数据迁移。 6 | - 某个 OSD `down` 了、重启了,而现在正在恢复( `recovering` )。 7 | - Acting Set 中的一个 OSD `down` 了,不能提供服务,另一个 OSD 临时接替其工作。 8 | 9 | Ceph 靠 **Up Set** 处理客户端请求,它们是实际处理读写请求的 OSD 集合。大多数情况下 Up Set 和 Acting Set 是相同的。如果不同,说明可能 Ceph 正在迁移数据、某 OSD 在恢复、或者有别的问题。这种情况下, Ceph 通常表现为 “HEALTH WARN” 状态,还有 “stuck stale” 消息。 10 | 11 | 用下列命令获取 PG 列表: 12 | 13 | ceph pg dump 14 | 15 | 查看指定 PG 的 Acting Set 或 Up Set 中包含的 OSD,执行: 16 | 17 | ceph pg map {pg-num} 18 | 19 | 命令的输出会告诉你 osdmap 版本( eNNN )、PG 号( {pg-num} )、Up Set 内的 OSD ( up[] )、和 Acting Set 内的 OSD ( acting[] )。 20 | 21 | osdmap e1196 pg 0.2d (0.2d) -> up [13,30] acting [13,30] 22 | 23 | ### 4.1 节点互联 24 | 25 | 写入数据前,PG 必须处于 `active` 、而且**应该**是 `clean` 状态。假设某存储池的 PG 有 3 副本,为让 Ceph 确定 PG 的当前状态,PG 的主 OSD (即 acting set 内的第一个 OSD )会与第二和第三 OSD 建立连接、并就 PG 的当前状态达成一致意见。 26 | 27 | ![](http://i.imgur.com/2uOjQIu.png) 28 | 29 | OSD 们也向 Mon 报告自己的状态。要排除节点互联的问题,请参考本手册第二部分 [3. 常见 PG 故障处理](../Troubleshooting/troubleshooting_pg.md) 中的相关部分进行处理。 30 | 31 | ### 4.2 监控 PG 状态 32 | 如果你执行了 `ceph health` 、 `ceph -s` 、或 `ceph -w` 命令,你也许注意到了集群并非总返回 `HEALTH_OK` 。检查完 OSD 是否在运行后,你还应该检查 PG 的状态。你应该明白,在 PG 建立连接时集群**不会**返回 `HEALTH_OK` : 33 | 34 | - 刚刚创建了一个存储池,PG 还没达成一致。 35 | - PG 正在恢复。 36 | - 刚刚增加或删除了一个 OSD 。 37 | - 刚刚修改了 CRUSH Map,PG 正在迁移。 38 | - 某一 PG 的副本间的数据不一致。 39 | - Ceph 正在洗刷一个 PG 的副本。 40 | - Ceph 没有足够可用容量来完成回填操作。 41 | 42 | 如果是前述原因之一导致了 Ceph 返回 `HEALTH_WARN` ,无需紧张。很多情况下,集群会自行恢复;有些时候你得采取些措施。归置 PG 的一件重要事情是保证集群启动并运行着,所有 PG 都处于 `active` 状态、并且最好是 `clean` 状态。用下列命令查看所有 PG 状态: 43 | 44 | ceph pg stat 45 | 46 | 其结果会告诉你 PG map 的版本号( vNNNNNN )、PG 总数 x 、有多少 PG 处于某种特定状态,如 `active+clean` ( y )。 47 | 48 | vNNNNNN: x pgs: y active+clean; z MB data, aa MB used, bb MB / cc MB avail 49 | 50 | 除了 PG 状态之外, Ceph 也会报告数据占据的空间( aa )、剩余可用空间( bb )和 PG 总容量。这些数字在某些情况下是很重要的: 51 | 52 | - 集群快达到 `near full ratio` 或 `full ratio` 时。 53 | - 由于 CRUSH 配置错误致使数据没能在集群内正确分布。 54 | 55 | #### PG ID 56 | PG IDs 由存储池号(不是存储池名字)、后面跟一个点( . )、再加一个 16 进制数字的 PG ID 。用 `ceph osd lspools` 可查看存储池号及其名字,例如,默认存储池 rbd 对应的存储池号是 0 。完整的 PG ID 格式如下: 57 | 58 | {pool-num}.{pg-id} 59 | 60 | 典型例子: 61 | 62 | 0.1f 63 | 64 | 用下列命令获取 PG 列表: 65 | 66 | ceph pg dump 67 | 68 | 你也可以让它输出到 JSON 格式,并保存到文件: 69 | 70 | ceph pg dump -o {filename} --format=json 71 | 72 | 要查询某个 PG,用下列命令: 73 | 74 | ceph pg {poolnum}.{pg-id} query 75 | 76 | Ceph 会输出成 JSON 格式。 77 | 78 | { 79 | "state": "active+clean", 80 | "snap_trimq": "[]", 81 | "epoch": 26760, 82 | "up": [ 83 | 1, 84 | 2 85 | ], 86 | "acting": [ 87 | 1, 88 | 2 89 | ], 90 | "actingbackfill": [ 91 | "1", 92 | "2" 93 | ], 94 | "info": { 95 | "pgid": "0.2d", 96 | "last_update": "26708'96", 97 | "last_complete": "26708'96", 98 | "log_tail": "0'0", 99 | "last_user_version": 96, 100 | "last_backfill": "MAX", 101 | "purged_snaps": "[1~1]", 102 | "history": { 103 | "epoch_created": 1, 104 | "last_epoch_started": 26760, 105 | "last_epoch_clean": 26760, 106 | ...... 107 | "recovery_state": [ 108 | { 109 | "name": "Started\/Primary\/Active", 110 | "enter_time": "2016-11-05 11:01:12.719671", 111 | "might_have_unfound": [], 112 | "recovery_progress": { 113 | "backfill_targets": [], 114 | "waiting_on_backfill": [], 115 | "last_backfill_started": "0\/\/0\/\/-1", 116 | "backfill_info": { 117 | "begin": "0\/\/0\/\/-1", 118 | "end": "0\/\/0\/\/-1", 119 | "objects": [] 120 | }, 121 | "peer_backfill_info": [], 122 | "backfills_in_flight": [], 123 | "recovering": [], 124 | "pg_backend": { 125 | "pull_from_peer": [], 126 | "pushing": [] 127 | } 128 | }, 129 | "scrub": { 130 | "scrubber.epoch_start": "26752", 131 | "scrubber.active": 0, 132 | "scrubber.waiting_on": 0, 133 | "scrubber.waiting_on_whom": [] 134 | } 135 | }, 136 | { 137 | "name": "Started", 138 | "enter_time": "2016-11-05 11:01:11.737126" 139 | } 140 | ], 141 | "agent_state": {} 142 | } 143 | 144 | ### 4.3 找出故障 PG 145 | 146 | 如前所述,一个 PG 状态不是 `active+clean` 时未必有问题。一般来说,PG 卡住时 Ceph 的自修复功能可能会不起作用,卡住的状态细分为: 147 | 148 | - **Unclean**: PG 里有些对象的副本数未达到期望值,它们应该进行恢复。 149 | - **Inactive**: PG 不能处理读写请求,因为它们在等着一个持有最新数据的 OSD 回到 `up` 状态。 150 | - **Stale**: PG 处于一种未知状态,因为存储它们的 OSD 有一阵子没向 Mon 报告了(由参数 `mon osd report timeout` 配置)。 151 | 152 | 为找出卡住的归置组,执行: 153 | 154 | ceph pg dump_stuck [unclean|inactive|stale|undersized|degraded] 155 | 156 | 关于排除卡住的 PG 见请参考本手册第二部分 [3. 常见 PG 故障处理](../Troubleshooting/troubleshooting_pg.md) 中的相关部分进行处理。 157 | 158 | ### 4.4 定位对象位置 159 | 160 | 要把对象数据存入 Ceph 对象存储, Ceph 客户端必须: 161 | 162 | 1. 设置对象名 163 | 2. 指定存储池 164 | 165 | Ceph 客户端索取最新集群 map、并用 CRUSH 算法计算对象到 PG 的映射,然后计算如何动态地把 PG 分配到 OSD 。要定位对象位置,只需要知道对象名和存储池名字: 166 | 167 | ceph osd map {poolname} {object-name} 168 | 169 | ##### 练习:定位一个对象 170 | 171 | 我们先创建一个对象。给 rados put 命令指定一对象名、一个包含数据的测试文件路径、和一个存储池名字,例如: 172 | 173 | rados put {object-name} {file-path} --pool=data 174 | rados put test-object-1 testfile.txt --pool=data 175 | 176 | 用下列命令确认 Ceph 对象存储已经包含此对象: 177 | 178 | rados -p data ls 179 | 180 | 现在可以定位对象了: 181 | 182 | ceph osd map {pool-name} {object-name} 183 | ceph osd map data test-object-1 184 | 185 | Ceph 应该输出对象的位置,例如: 186 | 187 | osdmap e537 pool 'data' (0) object 'test-object-1' -> pg 0.d1743484 (0.4) -> up [1,0] acting [1,0] 188 | 189 | 要删除测试对象,用 rados rm 即可,如: 190 | 191 | rados rm test-object-1 --pool=data -------------------------------------------------------------------------------- /Operation/operate_cluster.md: -------------------------------------------------------------------------------- 1 | # 1. 操作集群 2 | ------------ 3 | 4 | ## 1.1 用 UPSTART 控制 CEPH 5 | 6 | 用 ceph-deploy 把 Ceph Cuttlefish 及更高版部署到 Ubuntu 14.04 上,你可以用基于事件的 Upstart 来启动、关闭 Ceph 节点上的守护进程。 Upstart 不要求你在配置文件里定义守护进程例程。 7 | 8 | ### 1.1.1 列出节点上所有的 Ceph 作业和实例 9 | 10 | sudo initctl list | grep ceph 11 | 12 | ### 1.1.2 启动所有守护进程 13 | 14 | 要启动某一 Ceph 节点上的所有守护进程,用下列命令: 15 | 16 | sudo start ceph-all 17 | 18 | ### 1.1.3 停止所有守护进程 19 | 20 | 要停止某一 Ceph 节点上的所有守护进程,用下列命令: 21 | 22 | sudo stop ceph-all 23 | 24 | ### 1.1.4 按类型启动所有守护进程 25 | 26 | 要启动某一 Ceph 节点上的某一类守护进程,用下列命令: 27 | 28 | sudo start ceph-osd-all 29 | sudo start ceph-mon-all 30 | sudo start ceph-mds-all 31 | 32 | ### 1.1.5 按类型停止所有守护进程 33 | 34 | 要停止某一 Ceph 节点上的某一类守护进程,用下列命令: 35 | 36 | sudo stop ceph-osd-all 37 | sudo stop ceph-mon-all 38 | sudo stop ceph-mds-all 39 | 40 | ### 1.1.6 启动单个进程 41 | 42 | 要启动某节点上一个特定的守护进程例程,用下列命令之一: 43 | 44 | sudo start ceph-osd id={id} 45 | sudo start ceph-mon id={hostname} 46 | sudo start ceph-mds id={hostname} 47 | 48 | 例如: 49 | 50 | sudo start ceph-osd id=1 51 | sudo start ceph-mon id=ceph-server 52 | sudo start ceph-mds id=ceph-server 53 | 54 | ### 1.1.7 停止单个进程 55 | 56 | 要停止某节点上一个特定的守护进程例程,用下列命令之一: 57 | 58 | sudo stop ceph-osd id={id} 59 | sudo stop ceph-mon id={hostname} 60 | sudo stop ceph-mds id={hostname} 61 | 62 | 例如: 63 | 64 | sudo stop ceph-osd id=1 65 | sudo stop ceph-mon id=ceph-server 66 | sudo stop ceph-mds id=ceph-server 67 | 68 | ## 1.2 用 SYSTEMD 控制 CEPH 69 | 70 | 对于所有支持 `systemd` 的 Linux 发行版(CentOS 7, Fedora, Debian Jessie 8.x, SUSE),使用原生的 `systemd` 文件来代替传统的 `sysvinit` 脚本。不过需要注意,这和 Ceph 的版本也有关系。如果 CentOS 7 + Jewel,使用的就是 `systemd` 。 71 | 72 | ### 1.2.1 列出节点上所有的 Ceph systemd units 73 | 74 | sudo systemctl status ceph\*.service ceph\*.target 75 | 76 | ### 1.2.2 启动所有守护进程 77 | 78 | 要启动某一 Ceph 节点上的所有守护进程,用下列命令: 79 | 80 | sudo systemctl start ceph.target 81 | 82 | ### 1.2.3 停止所有守护进程 83 | 84 | 要停止某一 Ceph 节点上的所有守护进程,用下列命令: 85 | 86 | sudo systemctl stop ceph\*.service ceph\*.target 87 | 88 | ### 1.2.4 按类型启动所有守护进程 89 | 90 | 要启动某一 Ceph 节点上的某一类守护进程,用下列命令: 91 | 92 | sudo systemctl start ceph-osd.target 93 | sudo systemctl start ceph-mon.target 94 | sudo systemctl start ceph-mds.target 95 | 96 | ### 1.2.5 按类型停止所有守护进程 97 | 98 | 要停止某一 Ceph 节点上的某一类守护进程,用下列命令: 99 | 100 | sudo systemctl stop ceph-mon\*.service ceph-mon.target 101 | sudo systemctl stop ceph-osd\*.service ceph-osd.target 102 | sudo systemctl stop ceph-mds\*.service ceph-mds.target 103 | 104 | ### 1.2.6 启动单个进程 105 | 106 | 要启动某节点上一个特定的守护进程例程,用下列命令之一: 107 | 108 | sudo systemctl start ceph-osd@{id} 109 | sudo systemctl start ceph-mon@{hostname} 110 | sudo systemctl start ceph-mds@{hostname} 111 | 112 | 113 | ### 1.2.7 停止单个进程 114 | 115 | 要停止某节点上一个特定的守护进程例程,用下列命令之一: 116 | 117 | sudo systemctl stop ceph-osd@{id} 118 | sudo systemctl stop ceph-mon@{hostname} 119 | sudo systemctl stop ceph-mds@{hostname} 120 | 121 | 122 | ## 1.3 把 CEPH 当服务运行 123 | 124 | 在某些环境下,还可以把 Ceph 当做服务来运行,比如 CentOS 7 + Hammer 。 125 | 126 | ### 1.3.1 启动所有守护进程 127 | 128 | 要启动本节点上的所有 Ceph 守护进程,用下列命令: 129 | 130 | sudo service ceph [start|restart] 131 | 132 | ### 1.3.2 停止所有守护进程 133 | 134 | 要停止本节点上的所有 Ceph 守护进程,用下列命令: 135 | 136 | sudo service ceph stop 137 | 138 | ### 1.3.3 按类型启动所有守护进程 139 | 140 | 要启动本节点上的某一类 Ceph 守护进程,用下列命令: 141 | 142 | sudo service ceph start {daemon-type} 143 | 144 | ### 1.3.4 按类型停止所有守护进程 145 | 146 | 要停止本节点上的某一类 Ceph 守护进程,用下列命令: 147 | 148 | sudo service ceph stop {daemon-type} 149 | 150 | ### 1.3.5 启动单个进程 151 | 152 | 要启动本节点上某个特定的守护进程例程,用下列命令: 153 | 154 | sudo service ceph start {daemon-type}.{instance} 155 | 156 | ### 1.3.6 停止单个进程 157 | 158 | 要停止本节点上某个特定的守护进程例程,用下列命令: 159 | 160 | sudo service ceph start {daemon-type}.{instance} 161 | -------------------------------------------------------------------------------- /Operation/operate_pool.md: -------------------------------------------------------------------------------- 1 | # 8. 操作 Pool 2 | 3 | ---------- 4 | 5 | 如果你开始部署集群时没有创建存储池, Ceph 会用默认存储池 rbd 存放数据。存储池提供的功能: 6 | 7 | - **自恢复力:** 你可以设置在不丢数据的前提下允许多少 OSD 失效。对多副本存储池来说,此值是一对象应达到的副本数。典型配置是存储一个对象和它的一个副本(即 size = 2 ),但你可以更改副本数;对纠删编码的存储池来说,此值是编码块数(即纠删码配置里的 m = 2 )。 8 | - **归置组:** 你可以设置一个存储池的 PG 数量。典型配置给每个 OSD 分配大约 100 个 PG,这样,不用过多计算资源就能得到较优的均衡。配置了多个存储池时,要考虑到这些存储池和整个集群的 PG 数量要合理。 9 | - **CRUSH 规则:** 当你在存储池里存数据的时候,与此存储池相关联的 CRUSH 规则集可控制 CRUSH 算法,并以此操纵集群内对象及其副本的复制(或纠删码编码的存储池里的数据块)。你可以自定义存储池的 CRUSH 规则。 10 | - **快照:** 用 `ceph osd pool mksnap` 创建快照的时候,实际上创建了某一特定存储池的快照。 11 | 12 | 要把数据组织到存储池里,你可以列出、创建、删除存储池,也可以查看每个存储池的使用统计数据。 13 | 14 | ### 8.1 列出存储池 15 | 要列出集群的存储池,命令如下: 16 | 17 | ceph osd lspools 18 | 19 | 在新安装好的集群上,默认只有一个 rbd 存储池。 20 | 21 | ### 8.2 创建存储池 22 | 23 | 创建存储池前可以先看看存储池、PG 和 CRUSH 配置参考。你最好在配置文件里重置默认 PG 数量,因为默认值并不理想。 24 | 25 | 例如: 26 | 27 | osd pool default pg num = 100 28 | osd pool default pgp num = 100 29 | 30 | 要创建一个存储池,执行: 31 | 32 | ceph osd pool create {pool-name} {pg-num} [{pgp-num}] [replicated] \ 33 | [crush-ruleset-name] [expected-num-objects] 34 | ceph osd pool create {pool-name} {pg-num} {pgp-num} erasure \ 35 | [erasure-code-profile] [crush-ruleset-name] [expected_num_objects] 36 | 37 | 各参数含义如下: 38 | 39 | - `{pool-name}`:存储池名称,必须唯一。 40 | - `{pg_num}`: 存储池的 PG 数目。 41 | - `{pgp_num}`: 存储池的 PGP 数目,此值应该和 PG 数目相等。 42 | - `{replicated|erasure}`:存储池类型,可以是副本池(保存多份对象副本,以便从丢失的 OSD 恢复)或纠删池(获得类似 RAID5 的功能)。多副本存储池需更多原始存储空间,但已实现所有 Ceph 操作;纠删存储池所需原始存储空间较少,但目前仅实现了部分 Ceph 操作。 43 | - `[crush-ruleset-name]`:此存储池所用的 CRUSH 规则集名字。指定的规则集必须存在。对于多副本(** replicated** )存储池来说,其默认规则集由 `osd pool default crush replicated ruleset` 配置决定,此规则集必须存在。 对于用 `erasure-code` 编码的纠删码( **erasure** )存储池来说,不同的 `{pool-name}` 所使用的默认( `default` )纠删码配置是不同的,如果它不存在的话,会显式地创建它。 44 | - `[erasure-code-profile=profile]`:仅用于**纠删**存储池。指定纠删码配置文件,此配置必须已由 `osd erasure-code-profile set` 定义。 45 | - `[expected-num-objects]`:为这个存储池预估的对象数。设置此值(要同时把 **filestore merge threshold** 设置为负数)后,在创建存储池时就会拆分 PG 文件夹,以免运行时拆分文件夹导致延时增大。 46 | 47 | 关于如何计算合适的 `pg_num` 值,可以使用 Ceph 官方提供的一个计算工具 [**pgcalc**](http://ceph.com/pgcalc/) 。 48 | 49 | ### 8.3 设置存储池配额 50 | 51 | 存储池配额可设置最大字节数、和/或每个存储池最大对象数。 52 | 53 | ceph osd pool set-quota {pool-name} [max_objects {obj-count}] [max_bytes {bytes}] 54 | 55 | 例如: 56 | 57 | ceph osd pool set-quota data max_objects 10000 58 | 59 | 要取消配额,设置为 `0` 即可。 60 | 61 | ### 8.4 删除存储池 62 | 63 | 要删除一存储池,执行: 64 | 65 | ceph osd pool delete {pool-name} [{pool-name} --yes-i-really-really-mean-it] 66 | 67 | 如果你给自建的存储池创建了定制的规则集,你不需要存储池时最好也删除规则集。 68 | 69 | ceph osd pool get {pool-name} crush_ruleset 70 | 71 | 加入规则集是 “123”,可以这样选择存储池: 72 | 73 | ceph osd dump | grep "^pool" | grep "crush_ruleset 123" 74 | 75 | 如果你曾严格地创建了用户及其权限给一个存储池,但存储池已不存在,最好也删除那些用户。 76 | 77 | ceph auth list | grep -C 5 {pool-name} 78 | ceph auth del {user} 79 | 80 | ### 8.5 重命名存储池 81 | 82 | 要重命名一个存储池,执行: 83 | 84 | ceph osd pool rename {current-pool-name} {new-pool-name} 85 | 86 | 如果重命名了一个存储池,且认证用户对每个存储池都有访问权限,那你必须用新存储池名字更新用户的能力(即 caps )。 87 | 88 | ### 8.6 查看存储池统计信息 89 | 90 | 要查看某存储池的使用统计信息,执行命令: 91 | 92 | rados df 93 | 94 | ### 8.7 给存储池做快照 95 | 96 | 要给某存储池做快照,执行命令: 97 | 98 | ceph osd pool mksnap {pool-name} {snap-name} 99 | 100 | ### 8.8 删除存储池的快照 101 | 102 | 要删除某存储池的一个快照,执行命令: 103 | 104 | ceph osd pool rmsnap {pool-name} {snap-name} 105 | 106 | ### 8.9 获取存储池选项值 107 | 108 | 要获取一个存储池的选项值,执行命令: 109 | 110 | ceph osd pool get {pool-name} {key} 111 | 112 | ### 8.10 调整存储池选项值 113 | 114 | 要设置一个存储池的选项值,执行命令: 115 | 116 | ceph osd pool set {pool-name} {key} {value} 117 | 118 | 常用选项介绍: 119 | 120 | - `size`:设置存储池中的对象副本数,详情参见设置对象副本数。仅适用于副本存储池。 121 | - `min_size`:设置 I/O 需要的最小副本数,详情参见设置对象副本数。仅适用于副本存储池。 122 | - `pg_num`:计算数据分布时的有效 PG 数。只能大于当前 PG 数。 123 | - `pgp_num`:计算数据分布时使用的有效 PGP 数量。小于等于存储池的 PG 数。 124 | - `crush_ruleset`: 125 | - `hashpspool`:给指定存储池设置/取消 HASHPSPOOL 标志。 126 | - `target_max_bytes`:达到 `max_bytes` 阀值时会触发 Ceph 冲洗或驱逐对象。 127 | - `target_max_objects`:达到 `max_objects` 阀值时会触发 Ceph 冲洗或驱逐对象。 128 | - `scrub_min_interval`:在负载低时,洗刷存储池的最小间隔秒数。如果是 0 ,就按照配置文件里的 osd_scrub_min_interval 。 129 | - `scrub_max_interval`:不管集群负载如何,都要洗刷存储池的最大间隔秒数。如果是 0 ,就按照配置文件里的 osd_scrub_max_interval 。 130 | - `deep_scrub_interval`:“深度”洗刷存储池的间隔秒数。如果是 0 ,就按照配置文件里的 osd_deep_scrub_interval 。 131 | 132 | ### 8.11 设置对象副本数 133 | 134 | 要设置多副本存储池的对象副本数,执行命令: 135 | 136 | ceph osd pool set {poolname} size {num-replicas} 137 | 138 | **重要:** `{num-replicas}` 包括对象自身,如果你想要对象自身及其两份拷贝共计三份,指定 size 为 3 。 139 | 140 | 例如: 141 | 142 | ceph osd pool set data size 3 143 | 144 | 你可以在每个存储池上执行这个命令。注意,一个处于降级模式的对象,其副本数小于 `pool size` ,但仍可接受 I/O 请求。为保证 I/O 正常,可用 `min_size` 选项为其设置个最低副本数。例如: 145 | 146 | ceph osd pool set data min_size 2 147 | 148 | 这确保数据存储池里任何副本数小于 `min_size` 的对象都不会收到 I/O 了。 149 | 150 | ### 8.12 获取对象副本数 151 | 152 | 要获取对象副本数,执行命令: 153 | 154 | ceph osd dump | grep 'replicated size' 155 | 156 | Ceph 会列出存储池,且高亮 `replicated size` 属性。默认情况下, Ceph 会创建一对象的两个副本(一共三个副本,或 size 值为 3 )。 -------------------------------------------------------------------------------- /Operation/user_management.md: -------------------------------------------------------------------------------- 1 | # 5. 用户管理 2 | 3 | ---------- 4 | 5 | Ceph 把数据以对象的形式存于各存储池中。Ceph 用户必须具有访问存储池的权限才能够读写数据。另外,Ceph 用户必须具有执行权限才能够使用 Ceph 的管理命令。 6 | 7 | ### 5.1 授权(能力) 8 | 9 | Ceph 用 “能力”( capabilities, caps )这个术语来描述给认证用户的授权,这样才能使用 Mon、 OSD 和 MDS 的功能。能力也用于限制对某一存储池内的数据或某个命名空间的访问。 Ceph 管理员用户可在创建或更新普通用户时赋予他相应的能力。 10 | 11 | 能力的语法符合下面的形式: 12 | 13 | {daemon-type} 'allow {capability}' [{daemon-type} 'allow {capability}'] 14 | 15 | 16 | **Monitor 能力**: Monitor 能力包括 `r` 、 `w` 、 `x` 和 `allow profile {cap}`,例如: 17 | 18 | mon 'allow rwx' 19 | mon 'allow profile osd' 20 | 21 | **OSD 能力**: OSD 能力包括 `r` 、 `w` 、 `x` 、 `class-read` 、 `class-write` 和 `profile osd` 。另外, OSD 能力还支持存储池和命名空间的配置。 22 | 23 | osd 'allow {capability}' [pool={poolname}] [namespace={namespace-name}] 24 | 25 | **MDS 能力**: MDS 能力比较简单,只需要 allow 或者空白,也不会解析更多选项。 26 | 27 | mds 'allow' 28 | 29 | 注意: Ceph 对象网关守护进程( `radosgw` )是 Ceph 存储集群的一种客户端,所以它没被表示成一种独立的 Ceph 存储集群守护进程类型。 30 | 31 | 下面描述了各种能力。 32 | 33 | `allow` 34 | 35 | **描述:** 在守护进程的访问设置之前,仅对 MDS 隐含 `rw` 。 36 | 37 | `r` 38 | 39 | **描述:** 授予用户读权限,对 monitor 具有读权限才能获取 CRUSH map。 40 | 41 | `w` 42 | 43 | **描述:** 授予用户写对象的权限。 44 | 45 | `x` 46 | 47 | **描述:** 授予用户调用类方法的能力,即同时有读和写,且能在 monitor 上执行 `auth` 操作。 48 | 49 | `class-read` 50 | 51 | **描述:** 授予用户调用类读取方法的能力, `x` 的子集。 52 | 53 | `class-write` 54 | 55 | **描述:** 授予用户调用类写入方法的能力, `x` 的子集。 56 | 57 | `*` 58 | 59 | **描述:** 授权此用户读、写和执行某守护进程/存储池,且允许执行管理命令。 60 | 61 | `profile osd` 62 | 63 | **描述:** 授权一个用户以 OSD 身份连接其它 OSD 或 Monitor。授予 OSD 们允许其它 OSD 处理复制、心跳流量和状态报告。 64 | 65 | `profile mds` 66 | 67 | **描述:** 授权一个用户以 MDS 身份连接其它 MDS 或 Monitor。 68 | 69 | `profile bootstrap-osd` 70 | 71 | **描述:** 授权用户自举引导一个 OSD 。授予部署工具,像 `ceph-disk` 、`ceph-deploy` 等等,这样它们在自举引导 OSD 时就有权限增加密钥了。 72 | 73 | `profile bootstrap-mds` 74 | 75 | **描述:** 授权用户自举引导一个 MDS。授予例如 `ceph-deploy` 的部署工具,这样它们在自举引导 MDS 时就有权限增加密钥了。 76 | 77 | ### 5.2 管理用户 78 | 79 | 用户管理功能可以让 Ceph 存储集群的管理员有能力去创建、更新和删除集群的普通用户。当创建或删除一个用户时,可能需要把 keys 分发给各客户端,以便它们可以加入到 keyring 文件中。 80 | 81 | ##### 罗列用户 82 | 可以使用下面的命令罗列用户: 83 | 84 | ceph auth list 85 | 86 | Ceph 会列出集群中的所有用户。例如,在一个只有 2 个 OSD 的简单环境中,`ceph auth list` 将会输入类似下面的内容: 87 | 88 | installed auth entries: 89 | 90 | osd.0 91 | key: AQCvCbtToC6MDhAATtuT70Sl+DymPCfDSsyV4w== 92 | caps: [mon] allow profile osd 93 | caps: [osd] allow * 94 | osd.1 95 | key: AQC4CbtTCFJBChAAVq5spj0ff4eHZICxIOVZeA== 96 | caps: [mon] allow profile osd 97 | caps: [osd] allow * 98 | client.admin 99 | key: AQBHCbtT6APDHhAA5W00cBchwkQjh3dkKsyPjw== 100 | caps: [mds] allow 101 | caps: [mon] allow * 102 | caps: [osd] allow * 103 | client.bootstrap-mds 104 | key: AQBICbtTOK9uGBAAdbe5zcIGHZL3T/u2g6EBww== 105 | caps: [mon] allow profile bootstrap-mds 106 | client.bootstrap-osd 107 | key: AQBHCbtT4GxqORAADE5u7RkpCN/oo4e5W0uBtw== 108 | caps: [mon] allow profile bootstrap-osd 109 | 110 | 注意 `TYPE.ID` 这种用户表示方法,比如 `osd.0` 表示用户类型是 `osd` 且其 ID 是 `0` , `client.admin` 表示用户类型是 `client` 且其 ID 是 `admin` (即默认的 `client.admin` 用户)。另外,每个用户条目都有一个 `key: ` 对,一个或多个 `caps:` 条目。 111 | 112 | ##### 获取用户 113 | 获取某一特定用户的信息: 114 | 115 | ceph auth get {TYPE.ID} 116 | 例如: 117 | 118 | ceph auth get client.admin 119 | 120 | 还可以给命令加上 `-o {filename}` 选项把输入保存到一个文件中。 121 | 122 | ##### 增加用户 123 | 增加一个用户就是创建一个用户名(即 `TYPE.ID`)、一个密钥和任何包含在创建命令中的能力。有以下几种方式可以新增一个用户: 124 | 125 | - `ceph auth add`:此命令是最权威的新增用户方式。它回新建一个用户,产生一个 key ,并赋予用户任何给定的能力。 126 | - `ceph auth get-or-create`:这种方式通常是最便捷的一种,因为它的返回值是包含用户名(在方括号内)和密钥的格式。如果用户已经存在,该命令会返回密钥文件格式的用户名和密钥信息。可以使用 `-o {filename}` 选项把输入保存到一个文件中。 127 | - `ceph auth get-or-create-key`:该命令可以很方便地创建用户,但是只会返回用户的密钥。对于某些只需要密钥的用户(如 libvirt )来说是很有用的。如果用户已经存在,该命令仅仅返回用户的密钥。可以使用 `-o {filename}` 选项把输入保存到一个文件中。 128 | 129 | 下面是几个例子: 130 | 131 | ceph auth add client.john mon 'allow r' osd 'allow rw pool=liverpool' 132 | ceph auth get-or-create client.paul mon 'allow r' osd 'allow rw pool=liverpool' 133 | ceph auth get-or-create client.george mon 'allow r' osd 'allow rw pool=liverpool' -o george.keyring 134 | ceph auth get-or-create-key client.ringo mon 'allow r' osd 'allow rw pool=liverpool' -o ringo.key 135 | 136 | ##### 修改用户的能力 137 | `ceph auth caps` 命令允许你指定用户并改变用户的能力。设定新的能力会覆盖当前的能力。查看当前的能力可以使用 `ceph auth get USERTYPE.USERID` 命令。要增加能力,你应该在如下格式的命令中包含当前已经存在的能力: 138 | 139 | ceph auth caps USERTYPE.USERID {daemon} 'allow [r|w|x|*|...] [pool={pool-name}] [namespace={namespace-name}]' [{daemon} 'allow [r|w|x|*|...] [pool={pool-name}] [namespace={namespace-name}]'] 140 | 141 | 例如: 142 | 143 | ceph auth get client.john 144 | ceph auth caps client.john mon 'allow r' osd 'allow rw pool=liverpool' 145 | ceph auth caps client.paul mon 'allow rw' osd 'allow rwx pool=liverpool' 146 | ceph auth caps client.brian-manager mon 'allow *' osd 'allow *' 147 | 148 | 要移除某个能力,你可能需要进行重置。如果你想取消某个用户对特定守护进程的所有访问权限,可以指定一个空的字符串。比如: 149 | 150 | ceph auth caps client.ringo mon ' ' osd ' ' 151 | 152 | ##### 删除用户 153 | 154 | 想要删除一个用户,可以用 `ceph auth del` 命令: 155 | 156 | ceph auth del {TYPE}.{ID} 157 | 158 | 其中, `{TYPE}` 是 `client`,`osd`,`mon` 或 `mds` 的其中一种。`{ID}` 是用户的名字或守护进程的 ID 。 159 | 160 | ##### 打印用户的密钥 161 | 打印某个用户的授权密钥到标准输出界面,可以执行如下命令: 162 | 163 | ceph auth print-key {TYPE}.{ID} 164 | 165 | 其中, `{TYPE}` 是 `client`,`osd`,`mon` 或 `mds` 的其中一种。`{ID}` 是用户的名字或守护进程的 ID 。 166 | 167 | 当需要往客户端软件中注入 Ceph 用户(如 libvirt)的密钥时,打印用户的密钥时很有用的。 168 | 169 | mount -t ceph serverhost:/ mountpoint -o name=client.user,secret=`ceph auth print-key client.user` 170 | 171 | ##### 导入用户 172 | 173 | 使用 `ceph auth import` 命令并指定密钥文件,可以导入一个或多个用户: 174 | 175 | ceph auth import -i /path/to/keyring 176 | 177 | 比如: 178 | 179 | sudo ceph auth import -i /etc/ceph/ceph.keyring 180 | 181 | ### 5.3 密钥管理 182 | 当你通过客户端访问 Ceph 集群时,Ceph 客户端会使用本地的 keyring 文件。默认使用下列路径和名称的 keyring 文件: 183 | 184 | - `/etc/ceph/$cluster.$name.keyring` 185 | - `/etc/ceph/$cluster.keyring` 186 | - `/etc/ceph/keyring` 187 | - `/etc/ceph/keyring.bin` 188 | 189 | 你也可以在 `ceph.conf` 中另行指定 keyring 的路径,但不推荐这样做。 190 | 191 | `$cluster` 元变量是你的 Ceph 集群名称,默认名称是 `ceph` 。`$name` 元变量是用户类型和 ID 。比如用户是 `client.admin`,那就得到 `ceph.client.admin.keyring` 。 192 | 193 | 本小节介绍如何使用 `ceph-authtool` 工具来从客户端管理 keyring 。 194 | 195 | ##### 创建密钥 196 | 创建一个空的 keyring 文件,使用 `--create-keyring` 或 `-C` 选项。比如: 197 | 198 | ceph-authtool --create-keyring /path/to/keyring 199 | 200 | 创建一个包含多个用户的 keyring 文件,推荐使用 `$cluster.keyring` 作为文件名,并存放于 `/etc/ceph` 目录下。这样就无需在本地的 `ceph.conf` 文件中指定 keyring 的路径了。 201 | 202 | sudo ceph-authtool -C /etc/ceph/ceph.keyring 203 | 204 | 创建仅包含一个用户的 keyring 文件时,建议使用集群名、用户类型和用户名称作为文件名,并存放于 `/etc/ceph` 目录下。 205 | 206 | ##### 给密钥文件中增加用户 207 | 为了获取某个用户的 keyring 文件,可以使用 `ceph auth get` 命令加 `-o` 选项,以 keyring 文件格式来保存输出。比如: 208 | 209 | sudo ceph auth get client.admin -o /etc/ceph/ceph.client.admin.keyring 210 | 211 | 当你想要向 keyring 文件中导入某个用户时,可以使用 ceph-authtool 来指定目的和源 keyring 文件。比如: 212 | 213 | sudo ceph-authtool /etc/ceph/ceph.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring 214 | 215 | ##### 创建用户 216 | 可以在 Ceph 客户端直接创建用户、密钥和能力。然后再导入 Ceph 集群。比如: 217 | 218 | sudo ceph-authtool -n client.ringo --cap osd 'allow rwx' --cap mon 'allow rwx' /etc/ceph/ceph.keyring 219 | 220 | 创建 keyring 文件、增加用户也可以同时进行。比如: 221 | 222 | sudo ceph-authtool -C /etc/ceph/ceph.keyring -n client.ringo --cap osd 'allow rwx' --cap mon 'allow rwx' --gen-key 223 | 224 | 上述步骤中,新用户 client.ringo 仅存在于 keyring 文件中,还需要把新用户加入到 Ceph 集群中。 225 | 226 | sudo ceph auth add client.ringo -i /etc/ceph/ceph.keyring 227 | 228 | ##### 修改用户能力 229 | 修改记录在 keyring 文件中的用户能力时,需要指定 keyring 、用户和新的能力选项。比如: 230 | 231 | sudo ceph-authtool /etc/ceph/ceph.keyring -n client.ringo --cap osd 'allow rwx' --cap mon 'allow rwx' 232 | 233 | 更新 Ceph 存储集群的用户,你必须更新 keyring 文件中对应用户入口的信息。 234 | 235 | sudo ceph auth import -i /etc/ceph/ceph.keyring 236 | 237 | ### 5.4 命令行使用方法 238 | Ceph 支持通过下列方式使用用户名称和密钥。 239 | 240 | `--id | --user` 241 | 242 | **描述:** Ceph 通过类型和 ID 来确定用户,如 `TYPE.ID` 或 `client.admin`, `client.user1` 。使用 `--id` 或 `--user` 选项指定用户的 ID,比如,指定使用 `client.foo` 用户: 243 | 244 | ceph --id foo --keyring /path/to/keyring health 245 | ceph --user foo --keyring /path/to/keyring health 246 | 247 | `--name | -n` 248 | 249 | **描述:** 使用 --name 或 -n 选项指定用户的全名( TYPE.ID ),比如: 250 | 251 | ceph --name client.foo --keyring /path/to/keyring health 252 | ceph -n client.foo --keyring /path/to/keyring health 253 | 254 | `--keyring` 255 | 256 | **描述:** 指定包含一个或多个用户及其密钥的 keyring 文件路径。 `--secret` 选项提供同样的功能,但对 Ceph RADOS Gateway 不生效( `--secret` 选项有其他的作用)。比如: 257 | 258 | sudo rbd map --id foo --keyring /path/to/keyring mypool/myimage -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | --- 4 | 5 | 《 Ceph 运维手册》汇总了 Ceph 在使用中常见的运维和操作问题,主要用于指导运维人员的相关工作。存储组的新员工,在对 Ceph 有了基础了解之后,也可以通过本手册进一步深入 Ceph 的使用和运维。 6 | 7 | 本书的内容大部分来自 Ceph 官方文档,另一部分来自技术博客,还有一部分来自实际使用中的经验总结。 8 | 9 | ## 环境 10 | 11 | 本手册是基于以下两种环境: 12 | 13 | * Ubuntu 14.04, Ceph Hammer 版。 14 | * CentOS 7.2, Ceph Jewel版。 15 | 16 | ## 作者 17 | 18 | 李海静 19 | lihaijing@fiberhome.com 20 | 21 | ## 本书 GitBook 地址 22 | 23 | 点击下面的地址进行在线阅读: 24 | 25 | [https://lihaijing.gitbooks.io/ceph-handbook/content](https://lihaijing.gitbooks.io/ceph-handbook/content) 26 | 27 | ## 本书 GitHub 地址 28 | 29 | 本书源文件托管在 GitHub 上,欢迎大家 Fork 本项目: 30 | 31 | [https://github.com/lihaijing/ceph-handbook](https://github.com/lihaijing/ceph-handbook) 32 | 33 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [简介](README.md) 4 | * [第一部分:常用操作](Operation/common_operations.md) 5 | * [1. 操作集群](Operation/operate_cluster.md) 6 | * [2. 监控集群](Operation/monitor_cluster.md) 7 | * [3. 监控 OSD](Operation/monitor_osd.md) 8 | * [4. 监控 PG](Operation/monitor_pg.md) 9 | * [5. 用户管理](Operation/user_management.md) 10 | * [6. 增加/删除 Monitor](Operation/add_rm_mon.md) 11 | * [7. 增加/删除 OSD](Operation/add_rm_osd.md) 12 | * [8. 操作 Pool](Operation/operate_pool.md) 13 | * [9. 管理 Crushmap](Operation/manage_crushmap.md) 14 | * [10. 修改 MON IP](Operation/modify_mon_ip.md) 15 | * [11. 修改集群配置](Operation/change_cluster_conf.md) 16 | * [12. 日志和调试](Operation/log_debug.md) 17 | * [第二部分:故障处理](Troubleshooting/troubleshooting.md) 18 | * [1. 常见 MON 故障处理](Troubleshooting/troubleshooting_mon.md) 19 | * [2. 常见 OSD 故障处理](Troubleshooting/troubleshooting_osd.md) 20 | * [3. 常见 PG 故障处理](Troubleshooting/troubleshooting_pg.md) 21 | * [4. 全局 Ceph 节点宕机处理 ](Troubleshooting/troubleshooting_lost_power.md) 22 | * [5. 单个 Ceph 节点宕机处理 ](Troubleshooting/troubleshooting_single_lost_power.md) 23 | * [第三部分:Ceph 进阶](Advance_usage/advanced_usage.md) 24 | * [1. PG 和 PGP 的区别](Advance_usage/pg_pgp.md) 25 | * [2. Monitor 的备份和恢复](Advance_usage/mon_backup.md) 26 | * [3. 修改 Cinder/Glance 进程的最大可用 FD](Advance_usage/change_fd.md) 27 | * [4. 更换 OSD Journal](Advance_usage/change_osd_journal.md) 28 | * [5. 清空 OSD 的分区表后如何恢复](Advance_usage/rescue_osd_parted.md) 29 | * [6. PG 卡在 active + remapped 状态](Advance_usage/pg_active_remapped.md) 30 | * [7. 查看 RBD 镜像的位置](Advance_usage/find_rbd_data_loc.md) 31 | * [8. 查看 RBD 镜像的实际大小](Advance_usage/rbd_real_size.md) 32 | * [9. 统计 OSD 上 PG 的数量](Advance_usage/cal_pg_per_osd.md) 33 | * [10. 查看使用 RBD 镜像的客户端](Advance_usage/list_rbd_watcher.md) 34 | 35 | -------------------------------------------------------------------------------- /Troubleshooting/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # 第二部分:故障处理 2 | 3 | 本部分就 Ceph 存储集群常见的问题做了归纳和总结,方便运维人员进行故障排除。 -------------------------------------------------------------------------------- /Troubleshooting/troubleshooting_lost_power.md: -------------------------------------------------------------------------------- 1 | # 4. 全局Ceph节点宕机处理 2 | 3 | ---------- 4 | 5 | 在极端情况下,如数据中心断电,造成 Ceph 存储集群全局宕机,可以按照本节所示流程进行 Ceph 集群上电恢复操作。 6 | 7 | ### 4.1 手动上电执行步骤 8 | 9 | 1. 如为 Ceph 集群上电,monitor server 应最先上电;集群上电前确认使用 Ceph 之前端作业服务已停止。 10 | 11 | 2. 使用 IPMI 或于设备前手动进行上电。 12 | 13 | 3. 确认 NTP 服务及系统时间已同步,命令如下: 14 | 15 | `# ps-ef | grep ntp` 16 | 17 | `# date` 18 | 19 | `# ntpq -p` 20 | 21 | 4. 登入上电之 ceph server 确认 ceph service 已正常运行,命令如下: 22 | 23 | `# ps -ef | grep ceph` 24 | 25 | 5. 登入集群 monitor server 查看状态,OSD 全都 up 集群仍为 `noout flag(s) set` 26 | 27 | `# ceph -s` 28 | 29 | `# ceph osd tree` 30 | 31 | 6. 登入 monitor server 解除 `stopping w/out rebalancing`,命令如下: 32 | 33 | `# ceph osd unset noout` 34 | 35 | `# ceph -w` 36 | 37 | 使用 `ceph-w` 可查看集群运作输出,同步完毕后集群 health 应为`HEALTH_OK` 状态。 38 | 39 | ### 4.2 恢复后检查步骤 40 | 41 | 1. 确认设备上电状态,以 IPMI 或 于设备前确认电源为开启上电状态。 42 | 2. `ping ceph monitor server`,检查 monitor server 可以 ping 通。 43 | 3. 系统时间和校时服务器时间同步。 44 | 4. `ceph -s`  状态为`HEALTH_OK` 45 | 5. `ceph osd tree` OSD 状态皆为`UP` 46 | 47 | ### 4.3 恢复使用指令及其说明 48 | 49 | 1. `ceph -s` : 确认 ceph cluster status 50 | 2. `ceph -w` : 查看集群运作输出 51 | 3. `ceph osd tree` : 查看ceph cluster上osd排列及状态 52 | 4. `start ceph-all` : 启动 所有 ceph service 53 | 5. `start ceph-osd-all` : 启动 所有 osd service 54 | 6. `start ceph-mon-all` : 启动 所有 mon service 55 | 7. `start ceph-osd id={id}` : 启动指定 osd id service 56 | 8. `start ceph-mon id={hostname}` : 启动指定 ceph monitor host 57 | 9. `ceph osd set noout` : ceph stopping w/out rebalancing 58 | 10. `ceph osd unset noout` : 解除ceph stopping w/out rebalancing 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Troubleshooting/troubleshooting_mon.md: -------------------------------------------------------------------------------- 1 | # 1. 常见 MON 故障处理 2 | 3 | ---------- 4 | 5 | Monitor 维护着 Ceph 集群的信息,如果 Monitor 无法正常提供服务,那整个 Ceph 集群就不可访问。一般来说,在实际运行中,Ceph Monitor的个数是 2n + 1 ( n >= 0) 个,在线上至少3个,只要正常的节点数 >= n+1,Ceph 的 Paxos 算法就能保证系统的正常运行。所以,当 Monitor 出现故障的时候,不要惊慌,冷静下来,一步一步地处理。 6 | 7 | ### 1.1 开始排障 8 | 9 | 在遭遇 Monitor 故障时,首先回答下列几个问题: 10 | 11 | **Mon 进程在运行吗?** 12 | 13 | 我们首先要确保 Mon 进程是在正常运行的。很多人往往忽略了这一点。 14 | 15 | **是否可以连接 Mon Server?** 16 | 17 | 有时候我们开启了防火墙,导致无法与 Monitor 的 IP 或端口进行通信。尝试使用 `ssh` 连接服务器,如果成功,再尝试用其他工具(如 `telnet` , `nc` 等)连接 monitor 的端口。 18 | 19 | **ceph -s 命令是否能运行并收到集群回复?** 20 | 21 | 如果答案是肯定的,那么你的集群已启动并运行着。你可以认为如果已经形成法定人数,monitors 就只会响应 `status` 请求。 22 | 23 | 如果 `ceph -s` 阻塞了,并没有收到集群的响应且输出了很多 `fault` 信息,很可能此时你的 monitors 全部都 down 掉了或只有部分在运行(但数量不足以形成法定人数)。 24 | 25 | **ceph -s 没完成是什么情况?** 26 | 27 | 如果你到目前为止没有完成前述的几步,请返回去完成。然后你需要 `ssh` 登录到服务器上并使用 monitor 的管理套接字。 28 | 29 | ### 1.2 使用 Mon 的管理套接字 30 | 31 | 通过管理套接字,你可以用 Unix 套接字文件直接与指定守护进程交互。这个文件位于你 Mon 节点的 `run` 目录下,默认配置它位于 `/var/run/ceph/ceph-mon.ID.asok `,但要是改过配置就不一定在那里了。如果你在那里没找到它,请检查 `ceph.conf` 里是否配置了其它路径,或者用下面的命令获取: 32 | 33 | ceph-conf --name mon.ID --show-config-value admin_socket 34 | 35 | 请牢记,只有在 Mon 运行时管理套接字才可用。Mon 正常关闭时,管理套接字会被删除;如果 Mon 不运行了、但管理套接字还存在,就说明 Mon 不是正常关闭的。不管怎样,Mon 没在运行,你就不能使用管理套接字, `ceph` 命令会返回类似 `Error 111: Connection Refused` 的错误消息。 36 | 37 | 访问管理套接字很简单,就是让 `ceph` 工具使用 `asok` 文件。对于 Dumpling 之前的版本,命令是这样的: 38 | 39 | ceph --admin-daemon /var/run/ceph/ceph-mon..asok 40 | 41 | 对于 Dumpling 及后续版本,你可以用另一个(推荐的)命令: 42 | 43 | ceph daemon mon. 44 | 45 | `ceph` 工具的 `help` 命令会显示管理套接字支持的其它命令。请仔细了解一下 `config get` 、 `config show` 、 `mon_status` 和 `quorum_status` 命令,在排除 Mon 故障时它们会很有用。 46 | 47 | ### 1.3 理解 MON_STATUS 48 | 49 | 当集群形成法定人数后,或在没有形成法定人数时通过管理套接字, 用 `ceph` 工具可以获得 `mon_status` 信息。命令会输出关于 monitor 的大多数信息,包括部分 `quorum_status` 命令的输出内容。 50 | 51 | 下面是 `mon_status` 的输出样例: 52 | 53 | { 54 | "name": "c", 55 | "rank": 2, 56 | "state": "peon", 57 | "election_epoch": 38, 58 | "quorum": [ 59 | 1, 60 | 2 61 | ], 62 | "outside_quorum": [], 63 | "extra_probe_peers": [], 64 | "sync_provider": [], 65 | "monmap": { 66 | "epoch": 3, 67 | "fsid": "5c4e9d53-e2e1-478a-8061-f543f8be4cf8", 68 | "modified": "2013-10-30 04:12:01.945629", 69 | "created": "2013-10-29 14:14:41.914786", 70 | "mons": [ 71 | { 72 | "rank": 0, 73 | "name": "a", 74 | "addr": "127.0.0.1:6789\/0" 75 | }, 76 | { 77 | "rank": 1, 78 | "name": "b", 79 | "addr": "127.0.0.1:6790\/0" 80 | }, 81 | { 82 | "rank": 2, 83 | "name": "c", 84 | "addr": "127.0.0.1:6795\/0" 85 | } 86 | ] 87 | } 88 | } 89 | 90 | 从上面的信息可以看出, monmap 中包含 3 个monitor ( *a*,*b* 和 *c*),只有 2 个 monitor 形成了法定人数, *c* 是法定人数中的 *peon* 角色(非 *leader* 角色)。 91 | 92 | 还可以看出, **a** 并不在法定人数之中。请看 `quorum` 集合。在集合中只有 *1* 和 *2* 。这不是 monitor 的名字,而是它们加入当前 monmap 后确定的等级。丢失了等级 0 的 monitor,根据 monmap ,这个 monitor 就是 `mon.a` 。 93 | 94 | 那么,monitor 的等级是如何确定的? 95 | 96 | 当加入或删除 monitor 时,会(重新)计算等级。计算时遵循一个简单的规则: `IP:PORT` 的组合值越**大**, 等级越**低**(等级数字越大,级别越低)。因此在上例中, `127.0.0.1:6789` 比其他 `IP:PORT` 的组合值都小,所以 `mon.a` 的等级是 0 。 97 | 98 | ### 1.4 最常见的 Mon 问题 99 | 100 | #### 达到了法定人数但是有至少一个 Monitor 处于 Down 状态 101 | 102 | 当此种情况发生时,根据你运行的 Ceph 版本,可能看到类似下面的输出: 103 | 104 | root@OPS-ceph1:~# ceph health detail 105 | HEALTH_WARN 1 mons down, quorum 1,2 b,c 106 | mon.a (rank 0) addr 127.0.0.1:6789/0 is down (out of quorum) 107 | 108 | ##### 如何解决? 109 | 110 | 首先,确认 mon.a 进程是否运行。 111 | 112 | 其次,确定可以从其他 monitor 节点连到 `mon.a` 所在节点。同时检查下端口。如果开了防火墙,还需要检查下所有 monitor 节点的 `iptables` ,以确定没有丢弃/拒绝连接。 113 | 114 | 如果前两步没有解决问题,请继续往下走。 115 | 116 | 首先,通过管理套接字检查问题 monitor 的 `mon_status` 。考虑到该 monitor 并不在法定人数中,它的状态应该是 `probing` , `electing` 或 `synchronizing` 中的一种。如果它恰巧是 `leader` 或 `peon` 角色,它会认为自己在法定人数中,但集群中其他 monitor 并不这样认为。或者在我们处理故障的过程中它加入了法定人数,所以再次使用 `ceph -s` 确认下集群状态。如果该 monitor 还没加入法定人数,继续。 117 | 118 | **`probing` 状态是什么情况?** 119 | 120 | 这意味着该 monitor 还在搜寻其他 monitors 。每次你启动一个 monitor,它会去搜寻 `monmap` 中的其他 monitors ,所以会有一段时间处于该状态。此段时间的长短不一。例如,单节点 monitor 环境, monitor 几乎会立即通过该阶段。在多 monitor 环境中,monitors 在找到足够的节点形成法定人数之前,都会处于该状态,这意味着如果 3 个 monitor 中的 2 个 down 了,剩下的 1 个会一直处于该状态,直到你再启动一个 monitor 。 121 | 122 | 如果你的环境已经形成法定人数,只要 monitor 之间可以互通,新 monitor 应该可以很快搜寻到其他 monitors 。如果卡在 probing 状态,并且排除了连接的问题,那很有可能是该 monitor 在尝试连接一个错误的 monitor 地址。可以根据 `mon_status` 命令输出中的 `monmap` 内容,检查其他 monitor 的地址是否和实际相符。如果不相符,请跳至**恢复 Monitor 损坏的 monmap**。如果相符,这些 monitor 节点间可能存在严重的时钟偏移问题,请首先参考**时钟偏移**,如果没有解决问题,可以搜集相关的日志并向社区求助。 123 | 124 | **`electing` 状态是什么情况?** 125 | 126 | 这意味着该 monitor 处于选举过程中。选举应该很快就可以完成,但偶尔也会卡住,这往往是 monitors 节点时钟偏移的一个标志,跳转至**时钟偏移**获取更多信息。如果时钟是正确同步的,可以搜集相关日志并向社区求助。此种情况除非是一些(*非常*)古老的 bug ,往往都是由时钟不同步引起的。 127 | 128 | **`synchronizing` 状态是什么情况?** 129 | 130 | 这意味着该 monitor 正在和集群中的其他 monitor 进行同步以便加入法定人数。Monitor 的数据库越小,同步过程的耗时就越短。 131 | 132 | 然而,如果你注意到 monitor 的状态从 synchronizing 变为 electing 后又变回 synchronizing ,那么就有问题了:集群的状态更新的太快(即产生新的 maps ),同步过程已经无法追赶上了。这种情况在早期版本中可以见到,但现在经过代码重构和增强,在较新版本中已经基本见不到了。 133 | 134 | **`leader` 或 `peon` 状态是什么情况?** 135 | 136 | 这种情况不应该发生,但还是有一定概率会发生,这常和时钟偏移有关。如果你并没有时钟偏移的问题,请搜集相关的日志并向社区求助。 137 | 138 | #### 恢复 Monitor 损坏的 monmap 139 | 140 | monmap 通常看起来是下面的样子,这取决于 monitor 的个数: 141 | 142 | epoch 3 143 | fsid 5c4e9d53-e2e1-478a-8061-f543f8be4cf8 144 | last_changed 2013-10-30 04:12:01.945629 145 | created 2013-10-29 14:14:41.914786 146 | 0: 127.0.0.1:6789/0 mon.a 147 | 1: 127.0.0.1:6790/0 mon.b 148 | 2: 127.0.0.1:6795/0 mon.c 149 | 150 | 不过也不一定就是这样的内容。比如,在早期版本的 Ceph 中,有一个严重 bug 会导致 `monmap` 的内容全为 0 。这意味着即使用 `monmaptool` 也不能读取它,因为全 0 的内容没有任何意义。另外一些情况,某个 monitor 所持有的 monmap 已严重过期,以至于无法搜寻到集群中的其他 monitors 。在这些状况下,你有两种可行的解决方法: 151 | 152 | **销毁 monitor 然后新建** 153 | 154 | 只有在你确定不会丢失保存在该 monitor 上的数据时,你才能够采用这个方法。也就是说,集群中还有其他运行正常的 monitors,以便新 monitor 可以和其他 monitors 达到同步。请谨记,销毁一个 monitor 时,如果没有其上数据的备份,可能会丢失数据。 155 | 156 | **给 monitor 手动注入 monmap** 157 | 158 | 通常是最安全的做法。你应该从剩余的 monitor 中抓取 monmap,然后手动注入 monmap 有问题的 monitor 节点。 159 | 160 | 下面是基本步骤: 161 | 162 | 1、是否已形成法定人数?如果是,从法定人数中抓取 monmap : 163 | 164 | ceph mon getmap -o /tmp/monmap 165 | 166 | 2、没有形成法定人数?直接从其他 monitor 节点上抓取 monmap (这里假定你抓取 monmap 的 monitor 的 id 是 ID-FOO 并且守护进程已经停止运行): 167 | 168 | ceph-mon -i ID-FOO --extract-monmap /tmp/monmap 169 | 170 | 3、停止你想要往其中注入 monmap 的 monitor。 171 | 172 | 4、注入 monmap 。 173 | 174 | ceph-mon -i ID --inject-monmap /tmp/monmap 175 | 176 | 5、启动 monitor 。 177 | 178 | 请记住,能够注入 monmap 是一个很强大的特性,如果滥用可能会对 monitor 造成大破坏,因为这样做会覆盖 monitor 持有的最新 monmap 。 179 | 180 | #### 时钟偏移 181 | 182 | Monitor 节点间明显的时钟偏移会对 monitor 造成严重的影响。这通常会导致一些奇怪的问题。为了避免这些问题,在 monitor 节点上应该运行时间同步工具。 183 | 184 | **允许的最大时钟偏移量是多少?** 185 | 186 | 默认最大允许的时钟偏移量是 `0.05 秒`。 187 | 188 | **如何增加最大时钟偏移量?** 189 | 190 | 通过 mon-clock-drift-allowed 选项来配置。尽管你 ***可以*** 修改但不代表你 ***应该*** 修改。时钟偏移机制之所以是合理的,是因为有时钟偏移的 monitor 可能会表现不正常。未经测试而修改该值,尽管没有丢失数据的风险,但仍可能会对 monitors 的稳定性和集群的健康造成不可预知的影响。 191 | 192 | **如何知道是否存在时钟偏移?** 193 | 194 | Monitor 会用 `HEALTH_WARN` 的方式警告你。 `ceph health detail` 应该输出如下格式的信息: 195 | 196 | mon.c addr 10.10.0.1:6789/0 clock skew 0.08235s > max 0.05s (latency 0.0045s) 197 | 198 | 这表示 `mon.c` 已被标记出正在遭受时钟偏移。 199 | 200 | **如果存在时钟偏移该怎么处理?** 201 | 202 | 同步各 monitor 节点的时钟。运行 NTP 客户端会有帮助。如果你已经启动了 NTP 服务,但仍遭遇此问题,检查一下使用的 NTP 服务器是否离你的网络太过遥远,然后可以考虑在你的网络环境中运行自己的 NTP 服务器。最后这种选择可趋于减少 monitor 时钟偏移带来的问题。 203 | 204 | #### 客户端无法连接或挂载 205 | 206 | 检查 IP 过滤表。某些操作系统安装工具会给 `iptables` 增加一条 `REJECT` 规则。这条规则会拒绝所有尝试连接该主机的客户端(除了 `ssh` )。如果你的 monitor 主机设置了这条防火墙 `REJECT` 规则,客户端从其他节点连接过来时就会超时失败。你需要定位出拒绝客户端连接 Ceph 守护进程的那条 `iptables` 规则。比如,你需要对类似于下面的这条规则进行适当处理: 207 | 208 | REJECT all -- anywhere anywhere reject-with icmp-host-prohibited 209 | 210 | 你还需要给 Ceph 主机的 IP 过滤表增加规则,以确保客户端可以访问 Ceph monitor (默认端口 6789 )和 Ceph OSD (默认 6800 ~ 7300 )的相关端口。 211 | 212 | iptables -A INPUT -m multiport -p tcp -s {ip-address}/{netmask} --dports 6789,6800:7300 -j ACCEPT 213 | 214 | 或者,如果你的环境**允许**,也可以直接关闭主机的防火墙。 215 | 216 | ### 1.5 Monitor 数据库失败 217 | 218 | #### 数据库崩溃的表现 219 | 220 | Ceph monitor 把集群的各种 map 信息存放在 key/value 数据库中,如 LevelDB 。如果 monitor 是因为数据库崩溃而失败,在 monitor 的 log 日志中应该会有如下错误信息: 221 | 222 | Corruption: error in middle of record 223 | 224 | 或: 225 | 226 | Corruption: 1 missing files; e.g.: /var/lib/ceph/mon/mon.0/store.db/1234567.ldb 227 | 228 | #### 通过健康的 Monitor(s) 恢复 229 | 230 | 如果还有幸存的 monitor,我们通常可以用新的数据库替换崩溃的数据库。并且在启动后,新加入的成员会和其他健康的伙伴进行同步,一旦同步完成,它就可以为客户端提供服务了。 231 | 232 | #### 通过 OSDs 恢复 233 | 234 | 但是万一所有的 monitors 都同时失败了该怎么办?由于建议用户在部署集群时至少安装 3 个 monitors,同时失效的可能性较小。但是数据中心意外的断电,再加上磁盘/文件系统配置不当,可能会引起底层文件系统失败,从而杀掉所有的 monitors 。这种情况下,我们可以通过存放在 OSDs 上的信息来恢复 monitor 的数据库: 235 | 236 | ms=/tmp/mon-store 237 | mkdir $ms 238 | # collect the cluster map from OSDs 239 | for host in $hosts; do 240 | rsync -avz $ms user@host:$ms 241 | rm -rf $ms 242 | ssh user@host < 30.005692 secs 239 | {date} {osd.num} [WRN] slow request 30.005692 seconds old, received at {date-time}: osd_op(client.4240.0:8 benchmark_data_ceph-1_39426_object7 [write 0~4194304] 0.69848840) v4 currently waiting for subops from [610] 240 | 241 | 可能的原因有: 242 | 243 | - 坏驱动器(查看 `dmesg` 输出) 244 | - 内核文件系统缺陷(查看 `dmesg` 输出) 245 | - 集群过载(检查系统负载、 iostat 等等) 246 | - ceph-osd 守护进程的 bug 247 | 248 | 可能的解决方法: 249 | 250 | - 从 Ceph 主机分离 VM 云解决方案 251 | - 升级内核 252 | - 升级 Ceph 253 | - 重启 OSD 254 | 255 | ### 2.5 震荡的 OSD 256 | 257 | 我们建议同时部署 public(前端)网络和 cluster(后端)网络,这样能更好地满足对象复制的网络性能需求。另一个优点是你可以运营一个不连接互联网的集群,以此避免某些拒绝服务攻击。 OSD 们互联和检查心跳时会优选 cluster(后端)网络。 258 | 259 | ![](http://i.imgur.com/1NvAPXa.png) 260 | 261 | 然而,如果 cluster(后端)网络失败、或出现了明显的延时,同时 public(前端)网络却运行良好, OSD 目前不能很好地处理这种情况。这时 OSD 们会向 monitor 报告邻居 `down` 了、同时报告自己是 `up` 的,我们把这种情形称为震荡( flapping )。 262 | 263 | 如果有原因导致 OSD 震荡(反复地被标记为 `down` ,然后又 `up` ),你可以强制 monitor 停止这种震荡状态: 264 | 265 | ceph osd set noup # prevent OSDs from getting marked up 266 | ceph osd set nodown # prevent OSDs from getting marked down 267 | 268 | 这些标记记录在 osdmap 数据结构里: 269 | 270 | ceph osd dump | grep flags 271 | flags no-up,no-down 272 | 273 | 可用下列命令清除标记: 274 | 275 | ceph osd unset noup 276 | ceph osd unset nodown 277 | 278 | Ceph 还支持另外两个标记 `noin` 和 `noout` ,它们可防止正在启动的 OSD 被标记为 `in` (可以分配数据),或被误标记为 `out` (不管 `mon osd down out interval` 的值是多少)。 279 | 280 | **注意:** `noup` 、 `noout` 和 `nodown` 从某种意义上说是临时的,一旦标记被清除了,被它们阻塞的动作短时间内就会发生。另一方面, `noin` 标记阻止 OSD 启动后加入集群,但其它守护进程都维持原样。 -------------------------------------------------------------------------------- /Troubleshooting/troubleshooting_pg.md: -------------------------------------------------------------------------------- 1 | # 3. 常见 PG 故障处理 2 | 3 | ---------- 4 | 5 | ### 3.1 PG 无法达到 CLEAN 状态 6 | 7 | 创建一个新集群后,PG 的状态一直处于 `active` , `active + remapped` 或 `active + degraded` 状态, 而无法达到 `active + clean` 状态 ,那很可能是你的配置有问题。 8 | 9 | 你可能需要检查下集群中有关 Pool 、 PG 和 CRUSH 的配置项,做以适当的调整。 10 | 11 | 一般来说,你的集群中需要多于 1 个 OSD,并且存储池的 size 要大于 1 副本。 12 | 13 | #### 单节点集群 14 | 15 | 有时候,我们需要搭建一个单节点的 Ceph 实验环境。此时,在开始创建 monitor 和 OSD 之前,你需要把 Ceph 配置文件中的 `osd crush chooseleaf type` 选项从默认值 `1` (表示 `host` 或 `node`)修改为 `0` (表示 `osd`)。这样做是告诉 Ceph 允许把数据的不同副本分布到同一 host 的 OSDs 上。 16 | 17 | #### OSD 个数小于副本数 18 | 19 | 如果你已经启动了 2 个 OSD,它们都处于 `up` 和 `in` 的状态,但 PG 仍未达到 `active + clean` 状态,那可能是给 `osd pool default size` 设置了一个大于 `2` 的值。 20 | 21 | 如果你想要在 `active + degraded` 状态( 2 副本)操作你的集群,可以设置 `osd pool default min size` 为 2 ,这样你就可以对处于 `active + degraded` 的对象写入数据。然后你还可以把 `osd pool default size` 的值改为 2 ,这样集群就可以达到 `active + clean` 状态了。 22 | 23 | 另外,修改参数 `osd pool default size/min_size`后,只会对后面新建的 pool 起作用。如果想修改已存在的 pool 的 `size/min_size` ,可用下面的命令: 24 | 25 | ceph osd pool set size|min_size 26 | 27 | **注意:** 你可以在运行时修改参数值。如果是在 Ceph 配置文件中进行的修改,你可能需要重启集群。 28 | 29 | #### POOL SIZE = 1 30 | 31 | 如果你设置了 `osd pool default size` 的值为 `1` ,那你就仅有对象的单份拷贝。OSD 依赖于其他 OSD 告诉自己应该保存哪些对象。如果第一个 OSD 持有对象的拷贝,并且没有第二份拷贝,那么也就没有第二个 OSD 去告诉第一个 OSD 它应该保管那份拷贝。对于每一个映射到第一个 OSD 上的 PG (参考 `ceph pg dump` 的输出),你可以强制第一个 OSD 关注它应该保存的 PGs : 32 | 33 | ceph pg force_create_pg 34 | 35 | #### CRUSH MAP 错误 36 | 37 | PG 达不到 clean 状态的另一个可能的原因就是集群的 CRUSH Map 有错误,导致 PG 不能映射到正确的地方。 38 | 39 | ### 3.2 卡住的 PGs 40 | 41 | 有失败发生后,PG 会进入“degraded”(降级)或“peering”(连接建立中)状态,这种情况时有发生。通常这些状态意味着正常的失败恢复正在进行。然而,如果一个 PG 长时间处于这些状态中的某个,就意味着有更大的问题。因此 monitor 在 PG 卡 ( stuck ) 在非最优状态时会告警。我们具体检查: 42 | 43 | - `inactive` (不活跃)—— PG 长时间不是 `active` (即它不能提供读写服务了); 44 | - `unclean` (不干净)—— PG 长时间不是 `clean` (例如它未能从前面的失败完全恢复); 45 | - `stale` (不新鲜)—— PG 状态没有被 `ceph-osd` 更新,表明存储这个 PG 的所有节点可能都 `down` 了。 46 | 47 | 你可以用下列命令显式地列出卡住的 PGs: 48 | 49 | ceph pg dump_stuck stale 50 | ceph pg dump_stuck inactive 51 | ceph pg dump_stuck unclean 52 | 53 | 卡在 `stale` 状态的 PG 通过重启 ceph-osd 进程通常可以修复;卡在 `inactive` 状态的 PG 通常是互联问题(参见 ***PG 挂了 —— 互联失败*** );卡在 `unclean` 状态的 PG 通常是由于某些原因阻止了恢复的完成,像未找到的对象(参见 ***未找到的对象*** )。 54 | 55 | ### 3.3 PG 挂了 —— 互联失败 56 | 57 | 在某些情况下, `ceph-osd` *互联*进程会遇到问题,阻值 PG 达到活跃、可用的状态。例如, `ceph health` 也许显示: 58 | 59 | ceph health detail 60 | HEALTH_ERR 7 pgs degraded; 12 pgs down; 12 pgs peering; 1 pgs recovering; 6 pgs stuck unclean; 114/3300 degraded (3.455%); 1/3 in osds are down 61 | ... 62 | pg 0.5 is down+peering 63 | pg 1.4 is down+peering 64 | ... 65 | osd.1 is down since epoch 69, last address 192.168.106.220:6801/8651 66 | 67 | 可以查询到 PG 为何被标记为 `down` : 68 | 69 | ceph pg 0.5 query 70 | 71 | { "state": "down+peering", 72 | ... 73 | "recovery_state": [ 74 | { "name": "Started\/Primary\/Peering\/GetInfo", 75 | "enter_time": "2012-03-06 14:40:16.169679", 76 | "requested_info_from": []}, 77 | { "name": "Started\/Primary\/Peering", 78 | "enter_time": "2012-03-06 14:40:16.169659", 79 | "probing_osds": [ 80 | 0, 81 | 1], 82 | "blocked": "peering is blocked due to down osds", 83 | "down_osds_we_would_probe": [ 84 | 1], 85 | "peering_blocked_by": [ 86 | { "osd": 1, 87 | "current_lost_at": 0, 88 | "comment": "starting or marking this osd lost may let us proceed"}]}, 89 | { "name": "Started", 90 | "enter_time": "2012-03-06 14:40:16.169513"} 91 | ] 92 | } 93 | 94 | `recovery_state` 段告诉我们互联过程因 `ceph-osd` 进程挂了而被阻塞,本例是 `osd.1` 挂了,启动这个进程应该就可以恢复。 95 | 96 | 或者,如果 `osd.1` 发生了灾难性的失败(如硬盘损坏),我们可以告诉集群它丢失( `lost` )了,让集群尽力完成副本拷贝。 97 | 98 | **重要:** 集群不能保证其它数据副本是一致且最新的,就会很危险! 99 | 100 | 让 Ceph 无论如何都继续: 101 | 102 | ceph osd lost 1 103 | 104 | 恢复将继续进行。 105 | 106 | ### 3.4 未找到的对象 107 | 108 | 某几种失败相组合,可能导致 Ceph 抱怨有找不到( `unfound` )的对象: 109 | 110 | ceph health detail 111 | HEALTH_WARN 1 pgs degraded; 78/3778 unfound (2.065%) 112 | pg 2.4 is active+degraded, 78 unfound 113 | 114 | 这意味着存储集群知道一些对象(或者存在对象的较新副本)存在,却没有找到它们的副本。下例展示了这种情况是如何发生的,一个 PG 的数据存储在 ceph-osd 1 和 2 上: 115 | 116 | - 1 挂了 117 | - 2 独自处理一些写动作 118 | - 1 起来了 119 | - 1 和 2 重新互联, 1 上面丢失的对象加入队列准备恢复 120 | - 新对象还未拷贝完, 2 挂了 121 | 122 | 这时, 1 知道这些对象存在,但是活着的 `ceph-osd` 都没有这些副本。这种情况下,读写这些对象的 IO 就会被阻塞,集群只能指望 down 掉的节点尽早恢复。这样处理是假设比直接给用户返回一个 IO 错误要好一些。 123 | 124 | 首先,你应该确认哪些对象找不到了: 125 | 126 | ceph pg 2.4 list_missing [starting offset, in json] 127 | 128 | { "offset": { "oid": "", 129 | "key": "", 130 | "snapid": 0, 131 | "hash": 0, 132 | "max": 0}, 133 | "num_missing": 0, 134 | "num_unfound": 0, 135 | "objects": [ 136 | { "oid": "object 1", 137 | "key": "", 138 | "hash": 0, 139 | "max": 0 }, 140 | ... 141 | ], 142 | "more": 0} 143 | 144 | 如果在一次查询里列出的对象太多, `more` 这个字段将为 `true` ,你就可以查询更多。 145 | 146 | 其次,你可以找出哪些 OSD 上探测到、或可能包含数据: 147 | 148 | ceph pg 2.4 query 149 | 150 | "recovery_state": [ 151 | { "name": "Started\/Primary\/Active", 152 | "enter_time": "2012-03-06 15:15:46.713212", 153 | "might_have_unfound": [ 154 | { "osd": 1, 155 | "status": "osd is down"}]}, 156 | 157 | 本例中,集群知道 `osd.1` 可能有数据,但它挂了( `down` )。所有可能的状态有: 158 | 159 | - 已经探测到了 160 | - 在查询 161 | - OSD 挂了 162 | - 尚未查询 163 | 164 | 有时候集群要花一些时间来查询可能的位置。 165 | 166 | 还有一种可能性,对象存在于其它位置却未被列出。例如,集群里的一个 ceph-osd 停止且被剔出集群,然后集群完全恢复了;后来一系列的失败导致了未找到的对象,它也不会觉得早已死亡的 ceph-osd 上仍可能包含这些对象。(这种情况几乎不太可能发生)。 167 | 168 | 如果所有可能的位置都查询过了但仍有对象丢失,那就得放弃丢失的对象了。这仍可能是罕见的失败组合导致的,集群在写操作恢复后,未能得知写入是否已执行。以下命令把未找到的( `unfound` )对象标记为丢失( `lost` )。 169 | 170 | ceph pg 2.5 mark_unfound_lost revert|delete 171 | 172 | 上述最后一个参数告诉集群应如何处理丢失的对象。 173 | 174 | - `delete` 选项将导致完全删除它们。 175 | - `revert` 选项(纠删码存储池不可用)会回滚到前一个版本或者(如果它是新对象的话)删除它。要慎用,它可能迷惑那些期望对象存在的应用程序。 176 | 177 | ### 3.5 无家可归的 PG 178 | 179 | 拥有 PG 拷贝的 OSD 可能会全部失败,这种情况下,那一部分的对象存储不可用, monitor 也就不会收到那些 PG 的状态更新了。为检测这种情况,monitor 会把任何主 OSD 失败的 PG 标记为 `stale` (不新鲜),例如: 180 | 181 | ceph health 182 | HEALTH_WARN 24 pgs stale; 3/300 in osds are down 183 | 184 | 可以找出哪些 PG 是 `stale` 状态,和存储这些归置组的最新 OSD ,命令如下: 185 | 186 | ceph health detail 187 | HEALTH_WARN 24 pgs stale; 3/300 in osds are down 188 | ... 189 | pg 2.5 is stuck stale+active+remapped, last acting [2,0] 190 | ... 191 | osd.10 is down since epoch 23, last address 192.168.106.220:6800/11080 192 | osd.11 is down since epoch 13, last address 192.168.106.220:6803/11539 193 | osd.12 is down since epoch 24, last address 192.168.106.220:6806/11861 194 | 195 | 如果想使 PG 2.5 重新上线,例如,上面的输出告诉我们它最后由 `osd.0` 和 `osd.2` 管理,重启这些 `ceph-osd` 将恢复之(可以假定还有其它的很多 PG 也会进行恢复 )。 196 | 197 | ### 3.6 只有几个 OSD 接收数据 198 | 199 | 如果你的集群有很多节点,但只有其中几个接收数据,**检查**下存储池里的 PG 数量。因为 PG 是映射到多个 OSD 的,较少的 PG 将不能均衡地分布于整个集群。试着创建个新存储池,设置 PG 数量是 OSD 数量的若干倍。更详细的信息可以参考 Ceph 官方文档 —— [Placement Groups](http://docs.ceph.com/docs/master/rados/operations/placement-groups/) 。 200 | 201 | ### 3.7 不能写入数据 202 | 203 | 如果你的集群已启动,但一些 OSD 没起来,导致不能写入数据,确认下运行的 OSD 数量满足 PG 要求的最低 OSD 数。如果不能满足, Ceph 就不会允许你写入数据,因为 Ceph 不能保证复制能如愿进行。这个最低 OSD 个数是由参数 `osd pool default min size` 限定的。 204 | 205 | ### 3.8 PG 不一致 206 | 207 | 如果收到 `active + clean + inconsistent` 这样的状态,很可能是由于在对 PG 做擦洗( scrubbing )时发生了错误。如果是由于磁盘错误导致的不一致,请检查磁盘,如果磁盘有损坏,可能需要将这个磁盘对应的 OSD 踢出集群,然后进行更换。生产环境中遇到过不一致的问题,就是由于磁盘坏道导致的。 208 | 209 | 当集群中出现 PG 不一致的问题时,执行 `ceph -s` 命令会出现下面的信息: 210 | 211 | root@mon:~# ceph -s 212 | cluster 614e77b4-c997-490a-a3f9-e89aa0274da3 213 | health HEALTH_ERR 214 | 1 pgs inconsistent 215 | 1 scrub errors 216 | monmap e5: 1 mons at {osd1=10.95.2.43:6789/0} 217 | election epoch 796, quorum 0 osd1 218 | osdmap e1079: 3 osds: 3 up, 3 in 219 | flags sortbitwise 220 | pgmap v312153: 384 pgs, 6 pools, 1148 MB data, 311 objects 221 | 3604 MB used, 73154 MB / 76759 MB avail 222 | 383 active+clean 223 | 1 active+clean+inconsistent 224 | 225 | 1、查找处于 `inconsistent` 状态的问题 PG : 226 | 227 | root@mon:~# ceph health detail 228 | HEALTH_ERR 1 pgs inconsistent; 1 scrub errors 229 | pg 9.14 is active+clean+inconsistent, acting [1,2,0] 230 | 1 scrub errors 231 | 232 | 这个有问题的 PG 分布在 `osd.1` 、 `osd.2` 和 `osd.0` 上,其中 `osd.1` 是主 OSD。 233 | 234 | 2、去主 OSD( osd.1 )的日志中查找不一致的具体对象 。 235 | 236 | root@osd0:~# grep -Hn 'ERR' /var/log/ceph/ceph-osd.1.log 237 | /var/log/ceph/ceph-osd.1.log:30:2016-11-10 13:49:07.848804 7f628c5e6700 -1 log_channel(cluster) log [ERR] : 9.14 shard 0: soid 9:29b4ad99:::rbd_data.1349f035c101d9.0000000000000001:head missing attr _ 238 | /var/log/ceph/ceph-osd.1.log:31:2016-11-10 13:49:07.849803 7f628c5e6700 -1 log_channel(cluster) log [ERR] : 9.14 scrub 0 missing, 1 inconsistent objects 239 | /var/log/ceph/ceph-osd.1.log:32:2016-11-10 13:49:07.849824 7f628c5e6700 -1 log_channel(cluster) log [ERR] : 9.14 scrub 1 errors 240 | 241 | 从日志中可以知道,是 `rbd_data.1349f035c101d9.0000000000000001` 这个对象的属性 `_` 丢失了,所以在 scrub 的过程中产生了 error 。 242 | 243 | 3、执行 `ceph pg repair` 命令修复问题 PG 。 244 | 245 | root@mon:~# ceph pg repair 9.14 246 | instructing pg 9.14 on osd.1 to repair 247 | 248 | 4、检查 Ceph 集群是否恢复到 `HEALTH_OK` 状态。 249 | 250 | root@mon:~# ceph -s 251 | cluster 614e77b4-c997-490a-a3f9-e89aa0274da3 252 | health HEALTH_OK 253 | monmap e5: 1 mons at {osd1=10.95.2.43:6789/0} 254 | election epoch 796, quorum 0 osd1 255 | osdmap e1079: 3 osds: 3 up, 3 in 256 | flags sortbitwise 257 | pgmap v312171: 384 pgs, 6 pools, 1148 MB data, 311 objects 258 | 3604 MB used, 73154 MB / 76759 MB avail 259 | 384 active+clean 260 | 261 | osd.1 的日志里也提示修复成功: 262 | 263 | 2016-11-10 14:04:31.732640 7f628c5e6700 0 log_channel(cluster) log [INF] : 9.14 repair starts 264 | 2016-11-10 14:04:31.827951 7f628edeb700 -1 log_channel(cluster) log [ERR] : 9.14 shard 0: soid 9:29b4ad99:::rbd_data.1349f035c101d9.0000000000000001:head missing attr _ 265 | 2016-11-10 14:04:31.828117 7f628edeb700 -1 log_channel(cluster) log [ERR] : 9.14 repair 0 missing, 1 inconsistent objects 266 | 2016-11-10 14:04:31.828273 7f628edeb700 -1 log_channel(cluster) log [ERR] : 9.14 repair 1 errors, 1 fixed 267 | 268 | 如果经过前面的步骤,Ceph 仍没有达到 `HEALTH_OK` 状态,可以尝试用下面这种方式进行修复。 269 | 270 | 1、停掉不一致的 object 所属的 osd 。 271 | 272 | stop ceph-osd id=xxx 273 | 274 | 2、刷新该 osd 的日志。 275 | 276 | ceph-osd -i xx --flush-journal 277 | 278 | 3、将不一致的 object 移除。 279 | 280 | mv /var/lib/ceph/osd/ceph-{osd-id}/current/{pg.id}_head/ rbd\\udata.xxx /home 281 | 282 | 4、重新启动该 osd 。 283 | 284 | start ceph-osd id=xx 285 | 286 | 5、重新执行修复命令。 287 | 288 | ceph pg repair {pg_id} 289 | 290 | 6、检查 Ceph 集群是否恢复到 `HEALTH_OK` 状态。 291 | 292 | 293 | ### 3.9 Too Many/Few PGs per OSD 294 | 295 | 有时候,我们在 ceph -s 的输出中可以看到如下的告警信息: 296 | 297 | root@node241:~# ceph -s 298 | cluster 3b37db44-f401-4409-b3bb-75585d21adfe 299 | health HEALTH_WARN 300 | too many PGs per OSD (652 > max 300) 301 | monmap e1: 1 mons at {node241=192.168.2.41:6789/0} 302 | election epoch 1, quorum 0 node241 303 | osdmap e408: 5 osds: 5 up, 5 in 304 | pgmap v23049: 1088 pgs, 16 pools, 256 MB data, 2889 objects 305 | 6100 MB used, 473 GB / 479 GB avail 306 | 1088 active+clean 307 | 308 | 这是因为集群 OSD 数量较少,测试过程中建立了多个存储池,每个存储池都要建立一些 PGs 。而目前 Ceph 配置的默认值是每 OSD 上最多有 300 个 PGs 。在测试环境中,为了快速解决这个问题,可以调大集群的关于此选项的告警阀值。方法如下: 309 | 310 | 在 monitor 节点的 ceph.conf 配置文件中添加: 311 | 312 | [global] 313 | ....... 314 | mon_pg_warn_max_per_osd = 1000 315 | 316 | 然后重启 monitor 进程。 317 | 318 | 或者直接用 `tell` 命令在运行时更改参数的值而不用重启服务: 319 | 320 | ceph tell mon.* injectargs '--mon_pg_warn_max_per_osd 1000' 321 | 322 | 而另一种情况, `too few PGs per OSD (16 < min 20)` 这样的告警信息则往往出现在集群刚刚建立起来,除了默认的 rbd 存储池,还没建立自己的存储池,再加上 OSD 个数较多,就会出现这个提示信息。这通常不是什么问题,也无需修改配置项,在建立了自己的存储池后,这个告警信息就会消失。 323 | -------------------------------------------------------------------------------- /Troubleshooting/troubleshooting_single_lost_power.md: -------------------------------------------------------------------------------- 1 | # 5. 单个Ceph节点宕机处理 2 | 3 | ---------- 4 | 5 | 在某些情况下,如服务器硬件故障,造成单台 Ceph 节点宕机无法启动,可以按照本节所示流程将该节点上的 OSD 移除集群,从而达到 Ceph 集群的恢复。 6 | 7 | ### 5.1 单台 Ceph 节点宕机处理步骤 8 | 9 | 1. 登陆 ceph monitor 节点,查询 ceph 状态: 10 | 11 | `ceph health detail` 12 | 13 | 2. 将故障节点上的所有 osd 设置成 out,该步骤会触发数据 recovery, 需要等待数据迁移完成, 同时观察虚拟机是否正常: 14 | 15 | `ceph osd out osd_id` 16 | 17 | 3. 从 crushmap 将 osd 移除,该步骤会触发数据 reblance,等待数据迁移完成,同时观察虚拟机是否正常: 18 | 19 | `ceph osd crush remove osd_name` 20 | 21 | 4. 删除 osd 的认证: `ceph auth del osd_name` 22 | 23 | 5. 删除 osd :`ceph osd rm osd_id` 24 | 25 | 26 | ### 5.2 恢复后检查步骤 27 | 28 | 1. 检查 ceph 集群状态正常; 29 | 2. 检查虚拟机状态正常; 30 | 3. 楚天云人员检查虚拟机业务是否正常; 31 | 4. 检查平台服务正常:nova、cinder、glance; 32 | 5. 创建新卷正常; 33 | 6. 创建虚拟机正常。 34 | 35 | 36 | 37 | --------------------------------------------------------------------------------