|
本文的环境均为:Openstack+Ceph 运行虚拟机的场景,即主要使用RBD,不包含RGW,MDS。虚机的系统盘(Nova),云硬盘(Cinder),镜像盘(Glance)的块均保存在共享存储Ceph中。 环境准备! r! h; M/ z& R. {
8 `( `/ l" q4 ~3 L) Y/ H* T 本文环境为 Openstack (Kilo) + Ceph(Jewel)
本文所用的环境包含一套完整的 Openstack 环境,一套 Ceph 环境,其中 Nova/Cinder/Glance 均已经对接到了 Ceph 集群上,具体节点配置如下: [td]| 主机名 | IP地址 | Openstack 组件 | Ceph 组件 | | con | 192.168.10.10 | nova,cinder,glance,neutron | mon,osd*1 | | com | 192.168.10.11 | nova,neutron | mon,osd*1 | | ceph | 192.168.10.12 | | mon,osd*1 |
# W( h) @! E5 g2 ~+ W+ c/ Q在集群整体迁移完后,各个组件分布如下,也就是说,将运行于 con,com,ceph三个节点的 Ceph 集群迁移到 new_mon_1,new_mon_2,new_mon_3 这三台新机器上。 [td]| 主机名 | IP地址 | Openstack 组件 | Ceph 组件 | | con | 192.168.10.10 | nova,cinder,glance,neutron | | | com | 192.168.10.11 | nova,neutron | | | ceph | 192.168.10.12 | | | | new_mon_1 | 192.168.10.13 | | mon,osd*1 | | new_mon_2 | 192.168.10.14 | | mon,osd*1 | | new_mon_3 | 192.168.10.15 | | mon,osd*1 |
: Q# b% f/ t D4 w% n
在迁移之前,我们创建一个虚机,一个云盘,上传一个镜像,虚机此时正常运行,并将这这块云盘挂载到虚机上: [root@con ~(keystone_admin)]# nova list + M/ w' `8 v. [$ a$ `2 _8 G
+--------------------------------------+---------+--------+------------+-------------+-------------------------+4 k$ n2 g, h6 T- c
| ID | Name | Status | Task State | Power State | Networks |( ?6 J& @! o4 @ g( Y/ T! G6 K
+--------------------------------------+---------+--------+------------+-------------+-------------------------+
( ^; p5 g G; x5 D| f52191f-9645-448f-977b-80ca515387f7 | vm1-test | ACTIVE | - | Running | provider=192.168.8.111 |) |: v6 }7 G* I, c& I$ w
+--------------------------------------+---------+--------+------------+-------------+-------------------------+
4 y( M- f8 Z9 k3 @$ Z6 I" |: h[root@con ~(keystone_admin)]# cinder list
3 i( b q) o/ n @. G% ~5 W( d+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+) r! E. S& L* I
| ID | Status | Display Name | Size | Volume Type | Bootable | Attached to |% A3 p# e6 o9 u
+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+5 X# X- k# I* x" W. t- `1 N
| 39c76d96-0f95-490c-b7db-b3da6d17331 | in-use | cinder-rbd | 1 | None | false | f52191f-9645-448f-977b-80ca515387f7 |9 T5 t" ^! ~ f" `, X: j0 [+ C
+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+
" U; M( G$ [$ Q9 h4 X[root@con ~(keystone_admin)]# ip netns exec `ip netns` ssh cirros@192.168.8.111
6 A0 k; x& V2 S5 N4 k$ Xcirros@192.168.8.111's password: # N& Q7 V3 M* X( A6 m
$ lsblk; s1 W c' s+ U7 {, F
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
1 A/ N9 ~5 n- g/ }; vvda 253:0 0 1G 0 disk
1 i7 [. h7 X5 P2 A4 T& M) P' ``-vda1 253:1 0 1011.9M 0 part /' |5 a# p9 u- f" p1 t
vdb 253:16 0 1G 0 disk
$ q$ }8 a6 e. p$ Ceph 集群状态: [root@ceph cluster]# ceph -s: b2 u8 z- B! h9 G: z# Z
cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d# Z( p- Y5 B+ W6 y+ F( N
health HEALTH_OK
9 S! A5 X9 B. q2 _8 F, j monmap e47: 3 mons at {ceph=192.168.10.12:6789/0,com=192.168.10.11:6789/0,con=192.168.10.10:6789/0}% u% v: t6 j) T
election epoch 174, quorum 0,1,2 con,com,ceph5 I9 ^/ ?) J6 h) E4 X' e/ s( h* [
osdmap e57: 3 osds: 3 up, 3 in& l* i4 C& {9 ?2 \4 p* @" @
flags sortbitwise,require_jewel_osds
& v ?4 s) K7 ?1 \ pgmap v6577: 768 pgs, 3 pools, 45659 kB data, 23 objects- y4 q9 {1 j6 J# L4 W
178 MB used, 766 GB / 766 GB avail
, |( J n. v1 h& ^6 n8 F: P 768 active+clean
' M+ E+ e- \4 I9 j) i E% Y7 B- \. i a% Y5 {( a
[root@ceph cluster]# ceph osd tree# {2 N- s2 d4 K0 X8 f
ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
. t; Z0 W$ ^: M. f5 G) G j-1 0.74876 root default 3 N9 h0 ?7 x$ [+ k6 ]8 T
-2 0.24959 host ceph % W! I d9 q5 t2 A, [7 F( O
0 0.24959 osd.0 up 1.00000 1.00000 y& z0 n& t1 y U e7 ], \
-3 0.24959 host con `8 d# e3 E, ^
1 0.24959 osd.1 up 1.00000 1.00000 * J4 P4 m3 T3 }7 J' _
-4 0.24959 host com
& o4 F$ V% B2 Z9 ^0 v 2 0.24959 osd.2 up 1.00000 1.00000
# B+ k9 N% S4 c9 G
& N. m) Q4 n' [[root@ceph cluster]# ceph osd pool ls detail 9 e. n0 g- i8 I. k, Y+ i
pool 1 'volumes' replicated size 2 min_size 1 crush_ruleset 0 object_hash rjenkins pg_num 256 pgp_num 256 last_change 58 flags hashpspool stripe_width 0
" U, c8 @" k1 f7 m$ `( G: [2 d removed_snaps [1~3]
) n* X% _2 G8 T9 ?& npool 2 'vms' replicated size 2 min_size 1 crush_ruleset 0 object_hash rjenkins pg_num 256 pgp_num 256 last_change 59 flags hashpspool stripe_width 0/ s+ Y: e, ?1 e& j& U
removed_snaps [1~3]$ B- P( \# Q! M/ ~
pool 3 'images' replicated size 2 min_size 1 crush_ruleset 0 object_hash rjenkins pg_num 256 pgp_num 256 last_change 60 flags hashpspool stripe_width 08 S( i* {/ Z" |* L/ W
removed_snaps [1~9]
& c- ~; l3 Q E U7 x; k9 g1 J+ f g& l7 j `7 @. J9 g% Z" H$ A
OSD的数据迁移
, k$ a( q& C r: N- d8 N2 x; w6 a" m" y& ^
* }6 u U; {* H) u/ H2 W9 N( u
本次迁移主要分为两个组件的迁移,即 MON 和 OSD,这里我们先介绍 OSD 的数据迁移。相比迁移MON来说,OSD的数据迁移步骤更为单纯一些,因为所有操作均在 Ceph 侧执行,对 Openstack 来说是透明的。 原理简介由于CRUSH算法的伪随机性,对于一个PG来说,如果 OSD tree 结构不变的话,它所分布在的 OSD 集合总是固定的(同一棵tree下的OSD结构不变/不增减),即对于两副本来说: PG 1.0 => [osd.66, osd.33] 当副本数减少时,PG 1.0 => [osd.66] ,也就是说会删除在osd.33上的第二副本,而在 osd.66上的主副本是维持不变的,所以在降低副本数时,底层OSD实际上只删除了一份副本,而并没有发生数据的迁移。 当副本数增加时,PG 1.0 => [osd.66, osd.33, osd.188, osd.111],也就是说四副本的前两个副本依旧是之前的两个副本,而后面增加的两副本会从主副本osd.66将数据backfill到各自的OSD上。 % R, d* {9 x6 O) M4 T- y4 b7 M
迁移思路
: i3 U: Y; n* E- R3 t4 o% \
9 x3 f+ ] e# p% S' I
• crush rule 0 (原先默认生成的): 从 old_tree 下选出size副本(这里size=2)。 • crush rule 1 (新生成的第一条): 从 old_tree 下选出两副本。对于副本数为2的集群来说,crush_rule_0 和 crush_rule_1 选出的两副本是一样的。 • crush rule 2 (新生成的第二条): 从 old_tree 下选出两副本,再从 new_tree 下选出两副本。由**原理简介第二段**可知, 由于 old_tree 下面的 OSD结构不变也没有增加,所以 crush_rule_0 和 crush_rule_1 选出的前两副本是**一样的**。 • crush rule 3 (新生成的第三条): 从 new_tree 下选出两副本。 由于crush_rule_1 的第二次选择为选出 new_tree下的前两副本,这和 crush_rule_2 选出两副本(也是前两副本)其实是**一样的**。 注入新的CRUSHMAP后,我们做如下操作: • 将所有pool(当然建议一个pool一个pool来,后面类似) 的 CRUSH RULE 从 crush_rule_0 设置为 crush_rule_1 ,此时所有PG均保持active+clean,状态没有任何变化。 • 将所有pool的副本数设置为4, 由于此时各个 pool 的CRUSH RULE 均为 crush_rule_1 ,而这个 RULE 只能选出两副本,剩下两副本不会被选出,所以此时所有PG状态在重新 peer 之后,变为 active + undersized + degraded,由于不会生成新的三四副本,所以集群没有任何数据迁移(backfill) 动作,此步骤耗时短暂。 • 将所有pool的 CRUSH RULE 从 crush_rule_1 设置为 crush_rule_2,此时上一条动作中没有选出的三四副本会从 new_tree 下选出,并且原先的两副本不会发生任何迁移,整个过程宏观来看就是在 old_tree -> new_tree 单向数据复制克隆生成了新的两副本,而旧的两副本没有移动。此时生成新的两副本耗时较长,取决于磁盘性能带宽数据量等,可能需要几天到一周的时间,所有数据恢复完毕后,集群所有PG变为 active+clean 状态。 • 将所有pool的 CRUSH RULE 从 crush_rule_2 设置为 crush_rule_3,此时所有PG状态会变为 active+remapped,发生的另一个动作是,原先四副本的PG的主副本是在 old_tree 上的某一个OSD上的,现在这个PG的主副本变为 new_tree下的选出的第一个副本,也就是发生了主副本的切换。比如原先 PG 1.0 => [osd.a, osd.b, osd.c, osd.d] 在这步骤之后会变成 PG 1.0 => [osd.c, osd.d]。原先的第三副本也就是new_tree下的第一副本升级为主副本。 • 将所有pool的副本数设置为2,此时PG状态会很快变为 active+clean,然后在OSD层开始删除 old_tree 下的所有数据。此时数据已经全部迁移到新的OSD上。
6 d8 G5 x$ Q: o9 w2 ~! ? 迁移指令1.初始化新的OSD一定要记住:在部署目录下的ceph.conf内添加 osd_crush_update_on_start =false,再开始部署新的OSD,并且一定要检查新节点配置,包括但不限于: yum 源,免秘钥配置,ceph的版本,主机名,防火墙,selinux,ntp,ntp,ntp,重要的时间对齐说三遍! 部署新的OSD: ### 前往部署目录
* C; w. A* x, t' Ccd /root/cluster2 s5 i7 c+ o4 u f+ S
echo "osd_crush_update_on_start = false " >> ceph.conf
- o0 Z! N) i; U- Oceph-deploy --overwrite-conf osd prepare new_mon_1:sdb new_mon_2:sdb new_mon_3:sdb --zap-disk
* v7 U" i' V d6 ]% p1 }0 Iceph-deploy --overwrite-conf osd activate new_mon_1:sdb1 new_mon_2:sdb1 new_mon_3:sdb1添加完这三个OSD后,集群总共有六个OSD,此时不会有数据迁移。结构如下: & t, V6 b# I% r
[root@ceph ~]# ceph osd tree U; @8 w) C7 O: b- _. Q+ h
ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY 2 |# ~! z( q* ^6 F
-1 0.75000 root default
, j6 m" v" @" a6 }/ y. }4 C, `/ i F- ^-2 0.25000 host ceph
4 \9 x4 C: ~4 J* G& t 0 0.25000 osd.0 up 1.00000 1.00000
- W& g+ b2 C# q2 C- r-3 0.25000 host con , h k' ]! ~0 D0 d& n/ D
1 0.25000 osd.1 up 1.00000 1.00000
2 c+ L' i0 y/ t& s-4 0.25000 host com % i- v& T/ ~2 P9 }- L. }
2 0.25000 osd.2 up 1.00000 1.00000 / Q" h3 n3 @* }4 l6 }) R3 l
3 0 osd.3 up 1.00000 1.00000
. C: e$ h+ B% I- }- L6 ^- [ 4 0 osd.4 up 1.00000 1.00000 5 g4 X! x1 ~6 h, n# ?9 [: N2 e
5 0 osd.5 up 1.00000 1.00000构建新的new_root根节点,并将这三个新的OSD加入到新的根节点下(注意OSD和主机的物理对应关系):
) a5 A7 A% O1 k% [/ l1 x2 i$ f ceph osd crush add-bucket new_root root, u9 M4 Y( H! m( g1 @
ceph osd crush add-bucket new_mon_1 host
3 M- g) I! K$ d9 Gceph osd crush add-bucket new_mon_2 host, a' ~1 X4 A& B$ v, l" B
ceph osd crush add-bucket new_mon_3 host3 N; H$ d, @6 u: ]& N- w3 L% `
ceph osd crush move new_mon_1 root=new_root
* h7 }- L4 ], {* o/ a* z1 Hceph osd crush move new_mon_2 root=new_root
' O8 Z( q+ G) E; J9 W; A3 z- mceph osd crush move new_mon_3 root=new_root5 R S4 {, ^" `5 M1 ?, w1 L- a$ u( |
ceph osd crush add osd.3 0.25 host=new_mon_1$ z8 }. w x6 x* h
ceph osd crush add osd.4 0.25 host=new_mon_23 E' g! q" b1 c9 [
ceph osd crush add osd.5 0.25 host=new_mon_3此时,新的 TREE 结构如下: [root@ceph ~]# ceph osd tree
* k( {8 l0 Q; o4 `0 dID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
* Z6 u9 S6 g7 ^# F$ d! i-5 0.75000 root new_root + r% ~9 q h+ s% `
-6 0.25000 host new_mon_1 1 c8 x; i* W! u. {, f) R: g
3 0.25000 osd.3 up 1.00000 1.00000
' l- \4 o$ |2 B4 @" D-7 0.25000 host new_mon_2 # m a+ S) b3 P: E
4 0.25000 osd.4 up 1.00000 1.00000 9 C, z6 t* b/ {! e0 v; c! |8 U+ ?
-8 0.25000 host new_mon_3
% P5 K# a: h+ M. j! z, T! W8 B0 o 5 0.25000 osd.5 up 1.00000 1.00000
9 P0 v' l' D. R' }-1 0.75000 root default 1 Y' N6 r/ J& P
-2 0.25000 host ceph : ~% p6 q# O6 s4 C$ c1 W
0 0.25000 osd.0 up 1.00000 1.00000
0 s# Q0 g+ Y2 x9 _( i; ^3 l# I-3 0.25000 host con + V2 b% }: ^2 U* l" j" p
1 0.25000 osd.1 up 1.00000 1.00000 9 U$ i' j. J& g6 L
-4 0.25000 host com
8 x8 A- |0 q& j& h" w 2 0.25000 osd.2 up 1.00000 1.00000' h! O$ O k' W$ ^
, d. M2 L" T3 K$ F- H+ d% l
% F* c9 L3 [% s
2.编辑 CRUSH MAP+ C$ e" J }3 V5 ]9 ~/ z- n
导出CRUSH MAP,并编辑添加三条新的 CRUSH RULE: ### 导出CRUSH MAP/ T/ A. t; l3 z* e$ q
ceph osd getcrushmap -o map
! B# r$ [& A" k8 h) tcrushtool -d map -o map.txt* M' g9 T( ]& s6 I6 o1 i# F- k2 R
### 在map.txt 最后添加以下内容" A" T0 v0 Q7 y% ]( W8 z ] W
vim map.txt
7 q* S5 p/ b4 a! x
" ^& U& b2 @0 }. l# rules, D6 L6 H+ u! A" L9 s' d: A
rule replicated_ruleset {8 w2 x) L3 n! S3 b; t- t
ruleset 0# `0 i$ W+ B* g/ L+ s
type replicated
" } U+ W( O0 [" e2 h% V5 H# ? min_size 1
+ M4 K0 n( j7 `& P: B, t max_size 10
F% b1 m% U; O# }' A+ Z step take default+ {( Z0 M) g2 ]
step chooseleaf firstn 0 type host: J" a: T' }" d4 j, [9 E+ O
step emit
4 v' h' r. t0 o5 T! O" ^}
- I% J' a d' Y) Z1 y1 H6 j>>>>>>>>>>>>>> 添加开始 >>>>>>>>>>
% F" f* W9 }2 [. d% `) j) p& B drule replicated_ruleset1 {. d! s9 p/ q( ?2 d, p3 Q
ruleset 19 K, @1 @* p' `$ i+ E5 y8 r
type replicated
8 l6 f7 z' ~3 I: W min_size 16 |, u' |* j3 ]# v' Z
max_size 10
! H+ t* L0 c: {- R* L) `* D: b step take default
3 e# ]1 p7 r" t; f5 i/ f1 y2 [7 t7 w step chooseleaf firstn 2 type host+ R9 [- F( A( |
step emit
6 z* x9 P/ x" s9 H% x, O- D3 `}" N3 Q l2 q. T- {8 I, p3 {( u
rule replicated_ruleset2 {
5 f# z6 y# q$ D& s' E ruleset 2) d* k) a2 E$ ?9 ~! `
type replicated
1 w+ D O( i8 f/ P) i' F min_size 1" {5 `1 d! g% k# w5 f
max_size 10
, L% A5 ^9 U" c. G) g) l step take default P' p/ z: x( B2 Q0 k
step chooseleaf firstn 2 type host
. ^4 F6 C x8 T step emit8 A b1 s R r( O, A5 Z9 a
step take new_root9 B) _: g' P( F! \0 l" r. ^/ ?8 \3 q
step chooseleaf firstn 2 type host4 h- Y4 k" r" b: U" j
step emit
3 c; k+ w# m0 X L, `}. r! Z I% B4 M: t5 \3 d
rule replicated_ruleset3 {, E. ?5 a9 t6 U
ruleset 34 o5 b9 G+ J' F' }$ m8 h
type replicated
; }- c4 d J2 C min_size 17 L. z5 |' {* W. F# {2 H
max_size 10$ ^0 f! W1 t' [' ~* a
step take new_root
: ?: c+ q- p4 { step chooseleaf firstn 2 type host8 q. o. c% X/ u2 i; t
step emit
0 i" D7 B$ B, Z h/ E# ?}
' d0 W; Q. Q% {<<<<<<<<<<<< 添加结束 <<<<<<<<<<<<- |( M9 B% X) J$ W& s$ ^6 z/ J; \
# end crush map
" p' H. X/ {9 T3 o% O0 L. h+ L9 c# S5 P1 X
### 编译 CRUSH MAP,并注入到集群中/ V0 ]5 [4 p0 g" b g1 c0 V
2 C/ Y, R; x; |. l: T$ Wcrushtool -c map.txt -o map.bin) t5 t( j9 ?# g6 y( \
ceph osd setcrushmap -i map.bin8 ~; R. `3 o& J- E3 o
. L( }% G7 I j+ I5 T/ U
3. 开始迁移数据5 @) [; @4 e) \0 v: t
到目前为止的所有操作均不会发生数据迁移,对线上业务也就没有影响,下面我们要开始通过修改 POOL 的 CRUSH RULESET 和 副本数来实现数据的整体迁移(这里我们取 volumes 池来介绍): ###确认当前 volumes 池使用的是 crush_ruleset 0
V1 x/ k+ ^7 c: I[root@ceph cluster]# ceph osd pool get volumes crush_ruleset
5 r2 f' X7 D$ m1 Vcrush_ruleset: 0
8 O4 h# `) ]2 C" A$ ^/ k! N+ D! L8 l4 r( U3 w/ k7 G+ x5 E
### 将 volumes 池的 crush_ruleset 设置为 1,设置完后,集群一切正常,PG均为active+clean
q* q- f' S. i+ z0 E7 C2 w8 E+ V[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 1
# }; s$ L& T1 \0 b. m& O @set pool 1 crush_ruleset to 1
7 ?( v' e( x1 K3 ~0 f& F f* g* h0 v, d$ h* ]
### 将 volumes 池的 副本数设置为4, 设置完后,PG经过短暂 Peer,变为 active+undersized+degraded
5 P. {6 ^) W6 p r7 l& J[root@ceph cluster]# ceph osd pool set volumes size 43 W* |% B, s, E- @ r
set pool 1 size to 4* V& W$ a1 I# }+ k
. o4 {0 C- L- @[root@ceph cluster]# ceph -s
; @ z3 J! _; G4 Z8 Z& w cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d1 ]4 r8 C7 Z+ g5 s
health HEALTH_WARN$ v5 t0 t9 a4 x$ s: P. d; H
256 pgs degraded! |* f, ~3 O& Y8 y
256 pgs undersized
8 @2 y! p1 L3 l+ z: ? recovery 183984/368006 objects degraded (49.995%)( ]* t6 u7 D8 X2 }4 l: S% [' R
monmap e47: 3 mons at {ceph=192.168.100.112:6789/0,com=192.168.100.111:6789/0,con=192.168.100.110:6789/0}0 M5 E6 E2 R8 @
election epoch 182, quorum 0,1,2 con,com,ceph
2 s. M& l2 z! c f' ^7 ~ X osdmap e106: 6 osds: 6 up, 6 in8 r: h$ l, D5 \( A/ C+ |
flags sortbitwise,require_jewel_osds+ ^1 X& t% J7 A% y+ @
pgmap v23391: 768 pgs, 3 pools, 403 MB data, 92011 objects" O: W9 N M6 U
1523 MB used, 1532 GB / 1533 GB avail
$ v. |" \, ^8 y 183984/368006 objects degraded (49.995%)
' z' k2 ~" E3 x9 y5 O' l3 m* [ 512 active+clean
, [+ D8 a( r4 L& W8 E3 J6 E 256 active+undersized+degraded
% O/ d( _, t/ P4 ^. \; \7 p6 l4 Y1 N E
* N8 o5 A/ V* {2 F! r4 W; Z
[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 2- c! i" ]+ K, J: [2 c" ~, D
set pool 1 crush_ruleset to 2: V- w) z% {8 e1 ~8 u$ j( O
: r" t/ a; c9 t: ^6 M
### 等到 volumes 池的所有PG均变为 active+clean 后,将 volumes 池的 crush_ruleset 设置为3, 此步骤后,volumes 池的 PG状态变为 active+remapped。但是不影响集群IO。/ ]+ n: q, ^6 Y% K
; [: o" t) v+ X+ C! O2 P$ d[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 22 q- C4 o/ P: f6 \# l8 O# c
set pool 1 crush_ruleset to 2
- F6 s, u, ?" I i" S1 @. K1 I& j9 H! \* l/ y- f1 M
set pool 1 crush_ruleset to 30 c9 A$ G; ?, L% Q' x) m) d# m
. b& S. g! H2 C8 ^( o
### 此时,将 volumes 池的 副本数 设置为2 ,此时 PG 状态经过 peer 之后,很快变为 active+clean ,volumes 池的两副本均落在新的节点下,并且后台在自行删除之前旧节点上的数据。
9 E" j4 ~- J* x K' d: x+ t
% x/ E% L$ a6 R u0 j[root@ceph cluster]# ceph osd pool set volumes size 2
; _* j& C8 m* g' i
4 T2 [$ V0 }. X* }2 v注意事项
2 p. H, T3 R3 B4 x/ i2 [8 H1 s* t3 T/ ]0 a* Z$ O$ `' ?& Z- Z- w
3 I! D% b, w+ v; U& d由于本次数据迁移是在生产环境上执行的,所以没有直接执行将数据从旧节点直接 mv到新节点,而是选择了执行步骤较为复杂的上面的方案,先 scp 到新节点,再 rm掉旧节点的数据。并且每一个步骤都是可以快速回退到上一步的状态的,对于生产环境的操作,是比较友好的。在本次方案测试过程中,遇到了如下的一些问题,需要引起充分的注意: Ceph 版本不一致: 由于旧的节点的 Ceph 版本为 0.94.5 ,而新节点安装了较新版本的 10.2.7, 在副本 2=>4 的过程中Peer是正常的,而将池的crush_ruleset 设置为3 ,也就是将新节点的 PG 升级为主副本后,PG由新节点向旧节点发生Peer,此时会一直卡住,PG始终卡在了 remapped + peering,导致该 pool 无法IO。在将新旧节点 Ceph 版本一致后(旧节点升级,新节点降级),此现象得以消除。 为了确保此现象不会在实际操作中发生,应该在变更之前,新建一个测试pool,对其写入部分数据,再执行所有数据迁移指令,查看此过程是否顺畅,确认无误后,再对生产pool进行操作! 新节点 OSD 的重启问题: 如果没有添加了osd_crush_update_on_start 这个配置参数,那么当新节点的OSD重启后,会自动添加到默认的 root=default 下,然后立刻产生数据迁移,因此需要添加这个参数,保证OSD始终位于我们人为指定的节点下,并不受重启影响。这是个基本的Ceph运维常识,但是一旦遗忘了,可能造成较为严重的影响。更不用说防火墙时钟这些配置了。 集群性能降低:总体来说,在副本从2克隆为4这段时间(约2-3天,取决于集群数据量)内,集群的实际IO表现降低到变更前的 25%->80% 左右,时间越往后表现越接近变更前,这虽然不会导致客户端的IO阻塞,但从客户反馈来看,可以感知到较为明显的卡顿。因此克隆时间应该选择业务量较低的节假日等。 新节点IP不cluster_network范围内:这个比较好解决,只需要增大部署目录ceph.conf内的cluster_network 或者 public_network的掩码范围即可,不需要修改旧节点的,当然网络还是要通的。 变更的回退:对于生产环境来说,尽管执行步骤几乎是严谨不会出错的,但是难免会遇到意外情况,就比如上面的版本不一致导致的 peer 卡住现象。因此我们需要制定完善的回退步骤,在意外发生的时候,能够快速将环境回退到上一步集群正常的状况,而不是在意外发生时惊出一身冷汗,双手颤抖得敲指令。。。所以,下面的表格给出了这个变更操作的每一步的回退步骤: , `! g& ?% L$ {) H
[td]| 变更步骤 | 实际影响 | 回退指令 | 回退影响 | | ceph osd pool set volumes crush_ruleset 1 | 无 | ceph osd pool set volumes crush_ruleset 0 | 无 | | ceph osd pool set volumes size 4 | PG由active+clean,变为 active+undersized+degraded | ceph osd pool set volumes size 2 | PG很快恢复active+clean | | ceph osd pool set volumes crush_ruleset 2 | PG 开始 backfill,需要较长时间 | ceph osd pool set volumes crush_ruleset 1 | PG很快恢复到active+undersized+degraded,并删除在新节点生成的数据。 | | ceph osd pool set volumes crush_ruleset 3 | PG 很快变为 active+remapped。 | ceph osd pool set volumes crush_ruleset2 | PG很快恢复到 active+clean | | ceph osd pool set volumes size 2 | PG 很快变为 active+clean,并且后台删除旧节点数据。 | ceph osd pool set volumes size 3 | PG 变为active+remapped。 |
6 ~: [$ c0 M- _+ f! \5 }6 d
为何不直接迁移数据到新节点?总体来看数据迁移过程,最耗时的地方是数据从两副本变为四副本的过程,其余过程是短暂且可以快速回退的,而如果直接将池的 crush_ruleset 设置为 3 ,数据开始从旧节点直接backfill到新节点上,其实这么做也是可以的,但是这里我们就会遇到一个问题,一旦数据复制了一天或者一段时间后,集群出现了问题,比如性能骤降,要求必须回退到操作之前的状态,此时已经有部分PG完成了迁移,也就是说旧节点上的两副本已经删除了,那么回退到上一步后,还会发生数据从新节点向旧节点的复制,那么之前复制了多久的数据,可能就需要多久来恢复旧节点上删除的数据,这很不友好。而用了我们的方法来复制数据的话,不会存在这个问题,因为这里的方法在最后一步将池的副本设置为2之前,旧节点上的数据始终都是在的,并且不会发生任何迁移,我们可以在任意意外情况下,通过几条指令将集群恢复到变更之前的状态。 w+ } t" H7 I/ D
MON的迁移原理介绍相比于 OSD 的数据迁移,MON 的迁移比较省时省力一些,步骤相对简单,但是里面涉及的原理比较复杂,操作也需要细心又细心。 首先,我们的环境为典型的 Openstack+Ceph的环境,其中 Openstack 的三个组件: Nova/Cinder/Glance 均已经对接到了Ceph集群中,也就是说虚机系统盘,云硬盘,镜像都保存在Ceph中。而这三个客户端调用Ceph的方式不太一样: 我们需要知道的是,当一个 Client需要连接 Ceph 集群时,它首先通过自己的用户名和秘钥(client.cinder/client.nova...) 来连接到 /etc/ceph/ceph.conf配置文件指定IP的MON,认证成功后,可以获取集群的很多MAP( monmap,osdmap,crushmap...),通过这些 MAP,即可向 Ceph 集群读取数据。 对于一个虚机进程(qemu-kvm)来说,虚机启动之初,它即获取到了集群的 monmap, 而当所连接 MON 的 IP 变化时,比如这个 MON 挂掉时,它便会尝试连接 monmap 里面的其他 IP 的 MON,如果每个MON都挂了,那么这个 Client 就不能连接上集群获取最新的 monmap,osdmap等。下面我们以一个 pid为3171的 qemu-kvm 进程来演示这一过程: [root@con ~(keystone_admin)]# ps -ef|grep kvm - ~. u4 g0 `$ f" E7 z5 T
qemu 3171 1 17 14:32 ? 00:31:08 /usr/libexec/qemu-kvm -name guest=instance-0000000b.........' R+ l" U) g4 V( }: j
) N+ k, k/ N D[root@con ~(keystone_admin)]# netstat -tnp |grep 3171|grep 6789
9 x' r/ V3 H2 k; ztcp 0 0 192.168.100.110:59926 192.168.10.12:6789 ESTABLISHED 3171/qemu-kvm 可以看到,这个进程连接着IP为 192.168.10.12 的 MON,而我们手动将这个IP的 MON 停掉,则会发现这个进程又连接到了剩余两个IP的MON之一上: [root@con ~(keystone_admin)]# ssh 192.168.10.12 systemctl stop ceph-mon.target
7 d% m' N' N- [% }) ^
8 ^ v) u0 ]8 j" q7 z( A8 q9 v[root@con ~(keystone_admin)]# netstat -tnp |grep 3171|grep 6789
! F/ ^/ u& h& c! itcp 0 0 192.168.10.10:48792 192.168.10.11:6789 ESTABLISHED 3171/qemu-kvm 因此,如果我们每次都增加一个MON,再删除一个MON,那么在删除一个MON之后,之前连接到这个MON上的 Client 会自动连接到一个其他MON,并且再获取最新的monmap。那么我们增删过程就是: 原先有三个MON: con, com, ceph 增加 new_mon_1,变为四个: con, com, ceph, new_mon_1 删除con,变为三个:com, ceph, new_mon_1 增加 new_mon_2,变为四个: com, ceph, new_mon_1, new_mon_2 删除com,变为三个:ceph, new_mon_1, new_mon_2 增加 new_mon_3,变为四个: ceph, new_mon_1, new_mon_2, new_mon_3 删除con,变为三个:new_mon_1, new_mon_2, new_mon_3 ( }% D; q" X" K" }- i
Nova 侧的一个问题在实际操作中,发现了一个问题,会导致虚机无法重启等问题。 当虚机挂载一个云硬盘时,Nova 会将挂载这个云盘时所连接的MON IP 写入到数据库中,而在修改完MON的IP后,新的MON IP不会被更新到数据库中,而虚机启动时会加载 XML 文件,这个文件由数据库对应字段生成,由于没有更新 MON IP,所以 qemu-kvm 进程在启动时,会尝试向旧的MON IP发起连接请求,当然,旧MON已经删除,导致连接不上而卡住,最终致使虚机进程启动了,但是虚机状态始终不能更新为 RUNNING。 可以通过打开客户端的ceph.conf 内的 debug_rbd=20/20,查看qemu-kvm进程调用librbd时生成的log发现进程在启动时始终尝试连接旧的MON IP。 这里,我们只能手动修改数据库中记录的IP地址来确保虚机重启后能够连接上新的MON,需要注意的是,仅仅修改虚机XML文件是无法生效的,因为会被数据库内的字段覆盖而连上旧MON: ### 具体字段为: * z' j6 F' z0 r. R5 [4 Y
mysql => 8 y) w- G, B: `, g1 e
nova => block_device_mapping => connection_info
8 \5 Q# \) }* `+ s" s/ i9 H' K$ S3 p& H! }3 f! v5 I3 \: M, z
*************************** 23. row ***************************; N0 y( |6 Y/ Y1 }' J7 i! w% U3 g7 P
created_at: 2018-03-19 08:50:59
/ O9 E5 b9 ?) I7 d7 B1 | updated_at: 2018-03-26 06:32:068 X) P$ W8 \4 }6 }* r' t
deleted_at: 2018-03-26 09:20:021 S. I Z! W% n. X& L
id: 29
: r5 c) T% f1 F+ W) l device_name: /dev/vdb
' x7 G+ ?' x a% |delete_on_termination: 0
f- P1 Z% I0 g! R; m snapshot_id: NULL
4 [' U* t1 O) K8 Z0 w volume_id: 39c76d96-0f95-490c-b7db-b3da6d17331b
! K) y" F: V. f% A volume_size: NULL
$ B. h# V2 o# E no_device: NULL
& p, j8 O$ P) m$ U connection_info: {"driver_volume_type": "rbd", "serial": "39c76d96-0f95-490c-b7db-b3da6d17331b", "data": {"secret_type": "ceph", "name": "volumes/volume-39c76d96-0f95-490c-b7db-b3da6d17331b", "secret_uuid": "0668cc5e-7145-4b27-8c83-6c28e1353e83", "qos_specs": null, "hosts": ["192.168.10.10", "192.168.10.11", "192.168.10.12"], "auth_enabled": true, "access_mode": "rw", "auth_username": "cinder", "ports": ["6789", "6789", "6789"]}}6 t2 o) X$ L m2 T& N' q7 ^
instance_uuid: 4f52191f-9645-448f-977b-80ca515387f7
B) t6 ^+ x* ?9 ? v9 Y deleted: 29
: I& f& e, d% M/ ~( @: q2 L source_type: volume8 H7 N" B% U& i' b$ D4 f8 p
destination_type: volume) j! N! H. w. G- j* q& L
guest_format: NULL" z. X8 S4 R( K. N+ x
device_type: disk$ D" \1 ?* M& M
disk_bus: virtio
3 W' b& }7 N4 ^2 R( w boot_index: NULL
! Y S1 I3 j5 |! a6 E image_id: NULL迁移指令这里,我们使用 ceph-deploy 来增删 MON 节点,主要是为了操作的简洁和安全性着想。 首先,我们需要将新的三个MON的IP地址加入到所有节点的/etc/ceph/ceph.conf的mon_host 字段中。保证此时mon_host内是六个MON的IP地址。 ### 添加 new_mon_1 / H5 W6 h& Q* w- J, x1 `% ?/ \
[root@ceph cluster]# ceph-deploy mon add new_mon_1
6 { F6 J( v! ^' V[root@ceph cluster]# ceph -s: l: @8 d+ l* O0 s
cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d, U. U* I% J3 x" l& Z6 D
health HEALTH_OK. N6 p, [3 N& ]- f
monmap e48: 4 mons at {ceph=192.168.10.12:6789/0,com=192.168.10.11:6789/0,con=192.168.10.10:6789/0,new_mon_1=192.168.10.13:6789/0}3 h( Q$ a& [0 l: p
7 N7 N9 q$ Z' ^, r8 O
### 删除 con 删除完后,建议等待1-3min再添加新的MON,使得qemu-kvm进程可以建立新的socket链接。% B; t3 w" ~5 }; I3 U |% t
[root@ceph cluster]# ceph-deploy mon destroy con
0 P/ r( t% Q0 ?[root@ceph cluster]# ceph -s- S0 y6 s k' n; ^; i# q7 p6 u
cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d
; L3 _2 w1 J% | health HEALTH_OK# D' ~1 X" l% t* e2 ]
monmap e49: 3 mons at {ceph=192.168.10.12:6789/0,com=192.168.10.11:6789/0,new_mon_1=192.168.10.13:6789/0}$ c6 R* ]- F2 O; H3 g, e) y
0 |) o7 C) L/ l% y0 S* f- {9 W
### 依次添加 new_mon_2 ,删除 com,添加 new_mon_3 , 删除 ceph:6 W, s0 J- N( V6 p( d5 t( ]
[root@ceph cluster]# ceph-deploy mon add new_mon_2
7 l& g: C& \8 D[root@ceph cluster]# ceph-deploy mon destroy com
. N4 e5 H5 s: C/ B5 C8 M### 等待1-3min,
9 ?0 T W1 a% R( V2 y& q5 f, h[root@ceph cluster]# ceph-deploy mon add new_mon_3
: e, i5 |" [* s$ y0 q4 S[root@ceph cluster]# ceph-deploy mon destroy ceph! `5 e& h/ e4 j6 {
9 B' L/ g2 F+ Y( ]1 Q2 D
[root@con ~(keystone_admin)]# ceph -s
% w# ^, e8 L5 O- d# r: p2 [cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d
' @. d3 w( O- ~! G health HEALTH_OK/ f( ^& Z3 N* s0 N
monmap e53: 3 mons at {new_mon_1=192.168.10.13:6789/0,new_mon_2=192.168.10.14:6789/0,new_mon_3=192.168.10.15:6789/0}此时,将所有节点/etc/ceph/ceph.conf内的mon_host字段中原先的MON删除,只保留三个新的MON IP地址。 3 f$ B* b5 Z+ V4 `& B: o! y8 u( `( s
Glance & Cinder & Nova 服务重启无需重启 Glance 服务。 需要重启 所有计算节点的 nova-compute 和 控制节点的 Cinder 服务,否则会导致虚机无法创建等问题。 ## 在计算节点
" g( C/ d% b3 u% u( r2 [1 U; }openstack-service restart nova-compute
5 W. b' Y: n; `9 N! d6 o& H## 在控制节点
& S# P0 Q) e2 U3 o0 Qopenstack-service restart cinderNova由于 nova 不会更新之前的已经挂载的磁盘所连接的MON IP 信息,这会导致虚机在重启等动作时,尝试连接到旧的已经被摧毁的MON的地址,导致动作卡住,因此这里要单独改一下数据库内的MON IP 信息: 这里我们将 192.168.10.10/11/12 改为 192.168.10.13/14/15 mysql >>
3 c8 X. h1 I7 r* o) J5 W/ z. C+ ?* u" S' ? b0 [4 ?
use nova;
$ P5 V. [. u9 N! _5 d( _' }update block_device_mapping set connection_info=(replace(connection_info,'192.168.10.10','192.168.10.13'));. Z8 u* ~7 ~6 `" j: K
update block_device_mapping set connection_info=(replace(connection_info,'192.168.10.11','192.168.10.14'));
0 J% E0 N3 v% w% g' C& Supdate block_device_mapping set connection_info=(replace(connection_info,'192.168.10.12','192.168.10.15'));
& K9 q* n* U' w+ k* r, u' K" q6 ]% }0 G& n ?" R! J) u
exit;更新完数据库后,这次数据迁移算是大功告成了。为何不需要重启虚机服务呢,这里再做一些简单的介绍: qemu-kvm 虚机进程是一个长连接的 Ceph Client,自虚机启动后,进程就和 Ceph 集群保持着连接,在我们更改 MON 后,这些 Client 会自动尝试重连 monmap 里面的其他MON,从而更新 monmap, 来获取最新的 MON 。修改 /etc/ceph/ceph.conf不会对虚机进程产生影响,除非虚机重启等,但是,虚机可以通过更新 monmap 的方式来感知集群MON的改变。 |