|
本文的环境均为:Openstack+Ceph 运行虚拟机的场景,即主要使用RBD,不包含RGW,MDS。虚机的系统盘(Nova),云硬盘(Cinder),镜像盘(Glance)的块均保存在共享存储Ceph中。 环境准备: e6 U5 K* X6 `" r; N4 r
. w7 V& l7 f9 h: t7 q$ T- i3 ^8 I 本文环境为 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 |
4 ~# d$ p4 z& v! n7 ]9 H S
在集群整体迁移完后,各个组件分布如下,也就是说,将运行于 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 |
3 q) G, W1 ?& N/ L8 d3 _7 c
在迁移之前,我们创建一个虚机,一个云盘,上传一个镜像,虚机此时正常运行,并将这这块云盘挂载到虚机上: [root@con ~(keystone_admin)]# nova list
; d2 @* F4 ^4 N) J S+--------------------------------------+---------+--------+------------+-------------+-------------------------+
) s& U ?1 ~0 X/ _0 `1 ^| ID | Name | Status | Task State | Power State | Networks |
' A/ |2 r' Y7 \2 W# [9 ^3 G+--------------------------------------+---------+--------+------------+-------------+-------------------------+6 ?& [ [6 R4 A; |' B1 T
| f52191f-9645-448f-977b-80ca515387f7 | vm1-test | ACTIVE | - | Running | provider=192.168.8.111 |
5 Q0 ]" X4 x t1 h2 ]5 g+--------------------------------------+---------+--------+------------+-------------+-------------------------+
5 X( \% c- u( n3 N[root@con ~(keystone_admin)]# cinder list 7 R8 N5 z& D4 k
+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+& @+ D0 l9 ?+ z" `3 o
| ID | Status | Display Name | Size | Volume Type | Bootable | Attached to |/ i% n; k* X, H
+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+. j7 `, q7 i" N$ k0 `
| 39c76d96-0f95-490c-b7db-b3da6d17331 | in-use | cinder-rbd | 1 | None | false | f52191f-9645-448f-977b-80ca515387f7 |
, I/ N( c4 P+ o d" o1 `# v+--------------------------------------+--------+--------------+------+-------------+----------+--------------------------------------+
* d# a. N+ W6 w; \/ P w% [[root@con ~(keystone_admin)]# ip netns exec `ip netns` ssh cirros@192.168.8.111/ \5 e# a' O) n# G3 i6 ^
cirros@192.168.8.111's password:
# r. e" L/ q. R$ lsblk
* y+ _, }$ {( ^. M) {NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT/ H5 \/ S# c4 {/ I' l+ G8 J( j
vda 253:0 0 1G 0 disk
6 _) P& i7 N4 W8 z4 L, U`-vda1 253:1 0 1011.9M 0 part /$ M3 T( J+ o' n, K) o" B
vdb 253:16 0 1G 0 disk " b/ t$ e( H' w0 m, e) g) l
$ Ceph 集群状态: [root@ceph cluster]# ceph -s
7 L' O( n' q# \ ]3 S' e, ?3 r# J! c cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d
' f2 y/ ?5 z' S! d health HEALTH_OK
/ e9 b7 n! p$ p( x2 o2 l7 T! g 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}
6 d( m/ o2 s. u! v @ election epoch 174, quorum 0,1,2 con,com,ceph4 }1 \$ j. s) X+ X1 F- v& g* K
osdmap e57: 3 osds: 3 up, 3 in; ?2 ?% H& f; S# y
flags sortbitwise,require_jewel_osds. a. t- y9 Q- e A2 v
pgmap v6577: 768 pgs, 3 pools, 45659 kB data, 23 objects
( C' D2 C$ R) y8 M0 w& ^ 178 MB used, 766 GB / 766 GB avail
' x% {. P5 {, `6 F+ y. S7 }' _3 i 768 active+clean. [3 a2 w( z& _- p' u2 Y
, s' G9 O2 d5 w" F w
[root@ceph cluster]# ceph osd tree
- I0 j! r" X" i$ k% tID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
2 ~8 H% A7 o: q' ^- b& u3 L-1 0.74876 root default
, F6 W+ D6 b( p9 s, K/ S |$ \-2 0.24959 host ceph l% _, B6 d5 c& d* O7 o
0 0.24959 osd.0 up 1.00000 1.00000
: |6 q1 p% |3 {7 s. n4 ~-3 0.24959 host con 4 l' g9 p+ ?4 C& c
1 0.24959 osd.1 up 1.00000 1.00000 $ ?% x1 m+ I. G* w T1 A0 ]7 D e
-4 0.24959 host com
% k3 M5 U) p) U6 U 2 0.24959 osd.2 up 1.00000 1.00000 ' Y) w) ~) t4 n, i
4 U7 i8 T- ]! k4 b( g! Y[root@ceph cluster]# ceph osd pool ls detail
6 V' }8 V5 p0 A) ?. j) r8 e' O0 zpool 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( K1 o8 ^0 B& W7 z! ^; A @
removed_snaps [1~3]' X2 W1 g, u; f
pool 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
3 ?" B% V9 E+ d( ^2 d g removed_snaps [1~3]
6 U. d/ [6 J7 B) g' D1 X! ?# t# Tpool 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 0
- R" {" k# W1 N, g removed_snaps [1~9]. W! V6 N& t. q
7 X A: O( c- A1 i* f# j! ~OSD的数据迁移6 z$ G6 M6 z7 [# r% k f
. t, s9 }* l4 o# V6 u7 |, Q/ C8 `1 P: R5 B1 I) ~! p: z1 m* `
本次迁移主要分为两个组件的迁移,即 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上。 , F' Z3 H' k/ B3 M! H6 n
迁移思路" G" \. j4 C6 J! V! {
% B/ m- G/ v7 T: w
• 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上。
. W' b& q7 p: g, v6 P1 s& u* b 迁移指令1.初始化新的OSD一定要记住:在部署目录下的ceph.conf内添加 osd_crush_update_on_start =false,再开始部署新的OSD,并且一定要检查新节点配置,包括但不限于: yum 源,免秘钥配置,ceph的版本,主机名,防火墙,selinux,ntp,ntp,ntp,重要的时间对齐说三遍! 部署新的OSD: ### 前往部署目录
2 I5 a, ~5 O: o' f. P1 \0 I5 A7 ~cd /root/cluster( }) K$ Y! G* C5 X9 u5 N; S" q
echo "osd_crush_update_on_start = false " >> ceph.conf # E5 n1 _6 y0 F) l; ^8 |& e
ceph-deploy --overwrite-conf osd prepare new_mon_1:sdb new_mon_2:sdb new_mon_3:sdb --zap-disk
/ A# P/ {$ C: H: C$ u B+ I7 j9 bceph-deploy --overwrite-conf osd activate new_mon_1:sdb1 new_mon_2:sdb1 new_mon_3:sdb1添加完这三个OSD后,集群总共有六个OSD,此时不会有数据迁移。结构如下: 7 w+ @0 a7 T! D5 d$ r
[root@ceph ~]# ceph osd tree
5 g$ T7 G/ m- i: vID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
8 w9 p# W9 \- Y# e( e-1 0.75000 root default
, ^9 B$ M, z, o7 G-2 0.25000 host ceph + F. x h& e2 [% I
0 0.25000 osd.0 up 1.00000 1.00000 / G9 J& ?5 D3 J, E4 J! m
-3 0.25000 host con
% }$ i: o$ M* ~( b! a4 U 1 0.25000 osd.1 up 1.00000 1.00000
1 @, `1 B; ?" Z-4 0.25000 host com
9 A; `+ f& c/ F) F( K 2 0.25000 osd.2 up 1.00000 1.00000 2 B, K8 B* e9 C
3 0 osd.3 up 1.00000 1.00000
3 _: l* p: z: ]9 l( } 4 0 osd.4 up 1.00000 1.00000
! b7 b/ v* E( o9 A 5 0 osd.5 up 1.00000 1.00000构建新的new_root根节点,并将这三个新的OSD加入到新的根节点下(注意OSD和主机的物理对应关系): ~- x$ _& h- I
ceph osd crush add-bucket new_root root
+ d. O* G t; J gceph osd crush add-bucket new_mon_1 host
9 v" `0 {" |& W, w5 S3 a! n3 e W3 \ceph osd crush add-bucket new_mon_2 host
# _9 \( X! Y: c d9 ?" mceph osd crush add-bucket new_mon_3 host
6 h# m* [) ~1 Q( dceph osd crush move new_mon_1 root=new_root
+ q6 U' \ l* y" rceph osd crush move new_mon_2 root=new_root0 N3 a* [6 V+ p9 D
ceph osd crush move new_mon_3 root=new_root) }, j. C) u; n4 M! Y9 B, t
ceph osd crush add osd.3 0.25 host=new_mon_1
4 j8 B; u2 w [ceph osd crush add osd.4 0.25 host=new_mon_2, p7 H5 ^1 y# R7 b c7 \2 F A
ceph osd crush add osd.5 0.25 host=new_mon_3此时,新的 TREE 结构如下: [root@ceph ~]# ceph osd tree0 B' D' W# g! W
ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
# Q9 F$ x3 N, v X; \# C-5 0.75000 root new_root 7 J% [8 m7 e- U0 h
-6 0.25000 host new_mon_1 ! w$ K/ n) c* @# c( H, D J
3 0.25000 osd.3 up 1.00000 1.00000 & N+ |4 F" o+ X* n) F
-7 0.25000 host new_mon_2
& z1 \$ b# M- C4 H, y- B% e) d 4 0.25000 osd.4 up 1.00000 1.00000
, F p$ w3 M6 o, Q8 D, [-8 0.25000 host new_mon_3
. F% R/ F4 B4 O+ D 5 0.25000 osd.5 up 1.00000 1.00000
! [1 _- J$ B' l5 K7 v-1 0.75000 root default
4 {( o+ s/ ?9 F3 I( S-2 0.25000 host ceph ' y# l/ y Q" k" c) [7 ~
0 0.25000 osd.0 up 1.00000 1.00000
! L1 a" V6 g; u-3 0.25000 host con / M; O+ R3 ~: p6 ?, B6 w
1 0.25000 osd.1 up 1.00000 1.00000
( Q0 v$ b( c, f2 u* K9 C1 [( Q-4 0.25000 host com 0 m" f$ y( m+ K( _
2 0.25000 osd.2 up 1.00000 1.00000
! J9 C$ j2 ]: s h$ v) l3 r3 J7 n5 U+ M+ k
5 \8 k2 w5 ], I2 ~: B" n5 r 2.编辑 CRUSH MAP
K4 e$ L d0 [+ @) `7 u) N导出CRUSH MAP,并编辑添加三条新的 CRUSH RULE: ### 导出CRUSH MAP3 E4 g1 v: m5 |/ L4 ^# Y
ceph osd getcrushmap -o map 2 [2 `$ G6 [9 g D
crushtool -d map -o map.txt. c" Q/ N9 g/ \- L+ a1 Y9 G
### 在map.txt 最后添加以下内容
' E7 N: Y) Z4 E2 e, `) ?vim map.txt
4 Y: `$ ~+ n) k" ]2 \
3 Q, R. ~) j$ K$ u# ]# rules) Y4 j; k( G: Y
rule replicated_ruleset {
7 i1 ]; s, L Z ruleset 0
# r( T( ?/ n9 a* J% ^ type replicated9 o" X3 O! [' O) }. o
min_size 1- I& w2 X( p* h8 P5 T7 h+ X. n$ i6 \9 }
max_size 10& |+ z8 m: {; Y* e- P6 B. O
step take default+ p2 t% H/ K! `' F: K6 t
step chooseleaf firstn 0 type host
# _6 a ]7 b# e% w. C' e step emit3 b8 {7 R4 r- m( u) i5 {% x2 N7 S
}
9 F2 |9 H) j8 E% b& @>>>>>>>>>>>>>> 添加开始 >>>>>>>>>>4 E2 k, s y! n4 |( g
rule replicated_ruleset1 {4 u6 [0 m" }' b* b V, g( f
ruleset 14 ]& b6 n+ D$ y% \/ M$ H! f1 w' F
type replicated2 d( _; ?% w# Q( D- b; f; M1 L! }
min_size 1& _' r q) q" g6 L% @; f
max_size 101 z/ u! ~; e- X; C9 _: b
step take default8 m6 S6 }' N4 M9 `
step chooseleaf firstn 2 type host; `2 m% D) D1 A @5 c4 `) Q
step emit
* \; D) t. A6 a9 |0 c}3 V0 h9 `8 b, F/ K+ Q
rule replicated_ruleset2 {" F) w5 ]/ {+ U6 F
ruleset 25 c' `0 k v& i/ x3 |6 {5 r# R
type replicated$ E8 g/ p9 [" m6 K' F- H0 b3 a
min_size 1) s. F6 d1 R" k7 D: F" p k3 b- p# ~ n
max_size 10
- ^2 j4 I2 I+ M2 m$ E. M- Z5 _ step take default! U0 f( V3 j" r v$ `
step chooseleaf firstn 2 type host* T: \- J9 i* _3 j; l: C0 O$ p/ ]4 [
step emit
9 ?, \; P* X0 ?6 i" \, p% E step take new_root: X+ l6 ~9 |0 D z- E
step chooseleaf firstn 2 type host: M' b4 h; W9 a
step emit1 G6 y: M! r3 O
}# @/ Y: m* {% a- i% [0 z# d
rule replicated_ruleset3 {
, s* G. N/ p! M3 k9 \- {7 ^6 t ruleset 3
`0 _, j# J8 C x* A9 ]1 _ type replicated& Q4 {, X' X. ?. W/ v- l- Q
min_size 1) L# Y1 X5 ~. d. M3 \$ E) d& Q
max_size 10
# j% ^# |% [- q: I* ]/ L6 u step take new_root
, v4 ^" `. n# v step chooseleaf firstn 2 type host6 G7 J Q! S* O- P5 }8 \
step emit
- I0 J0 t4 p% J1 W}
+ P! p, ?$ \- H- s! ] q& V8 D<<<<<<<<<<<< 添加结束 <<<<<<<<<<<< f7 d) S( k# @ t( Z1 x
# end crush map% ] z& e* Q4 X6 d$ }3 f+ ^
2 |: u9 u! p0 u) s: _### 编译 CRUSH MAP,并注入到集群中
* O7 y& w: s! Y5 l5 Z$ F- B6 C% ~' V: d& ?4 f9 N2 h6 [2 [
crushtool -c map.txt -o map.bin- H5 P0 j0 Y2 B( F5 ?$ N
ceph osd setcrushmap -i map.bin9 R' K( R) n$ r H& q1 w* A
* F6 j3 j5 S& x3 E9 }5 g* V1 V0 u3. 开始迁移数据
7 |+ q. w& o6 r. C+ l+ x* r到目前为止的所有操作均不会发生数据迁移,对线上业务也就没有影响,下面我们要开始通过修改 POOL 的 CRUSH RULESET 和 副本数来实现数据的整体迁移(这里我们取 volumes 池来介绍): ###确认当前 volumes 池使用的是 crush_ruleset 0
1 E2 o3 l# _2 |9 ~[root@ceph cluster]# ceph osd pool get volumes crush_ruleset 4 w8 J; }& G; c$ p+ m- }
crush_ruleset: 06 ?# y9 x% S; E4 _, O$ |6 M/ m, v! k
, r& P3 v5 i" w9 G v& `### 将 volumes 池的 crush_ruleset 设置为 1,设置完后,集群一切正常,PG均为active+clean
4 {8 M" i8 b$ A( @9 Z6 h: v[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 12 d# H9 d# U7 J& V& i3 g
set pool 1 crush_ruleset to 1
[- v( e9 g+ }; U; K! h4 P0 _0 j* r5 }. n* j
### 将 volumes 池的 副本数设置为4, 设置完后,PG经过短暂 Peer,变为 active+undersized+degraded
1 w' a- C& @ M, d9 [[root@ceph cluster]# ceph osd pool set volumes size 4
5 j o! d' D3 |+ ]% a' Y" Pset pool 1 size to 4% @ g4 Z, G/ o( ]' o6 ~
5 T, b8 c+ }; t3 ^1 U( C[root@ceph cluster]# ceph -s
% {4 d" A5 L$ G cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d R* h& F7 ]/ x3 z- Q- B
health HEALTH_WARN6 \& @2 [% i3 {% u- O
256 pgs degraded
6 E9 q$ }4 P3 P 256 pgs undersized
7 y/ t; J( ^: ?; ?. O recovery 183984/368006 objects degraded (49.995%)/ o$ B) e* u9 L; h- h
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}( z8 V+ _: Y0 e, J% w
election epoch 182, quorum 0,1,2 con,com,ceph
2 M M, b; c2 T* h# E3 s2 O osdmap e106: 6 osds: 6 up, 6 in# v+ ~1 ?- Y k" P: d' _9 a
flags sortbitwise,require_jewel_osds7 F: b6 @- e0 z5 f7 f
pgmap v23391: 768 pgs, 3 pools, 403 MB data, 92011 objects
8 K4 K/ a; s7 J. O 1523 MB used, 1532 GB / 1533 GB avail- T6 j' ~# H- f) s8 t
183984/368006 objects degraded (49.995%)) K3 t% @( D* p2 ~4 e
512 active+clean7 N' F2 J+ W4 w6 q
256 active+undersized+degraded
7 {- g$ K+ g" L8 \4 ^; t! y) e6 y2 X' O$ A5 L
9 M6 C. ]# V5 j5 ~
[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 2( {& \9 d2 h' h
set pool 1 crush_ruleset to 2( l, M( I: b4 K& i1 S- [
L, O! j3 V6 d2 o### 等到 volumes 池的所有PG均变为 active+clean 后,将 volumes 池的 crush_ruleset 设置为3, 此步骤后,volumes 池的 PG状态变为 active+remapped。但是不影响集群IO。
) e% C. p R5 L. `
% e: O' H! o% V- X% W[root@ceph cluster]# ceph osd pool set volumes crush_ruleset 2
+ @/ b3 W# T8 A2 j; aset pool 1 crush_ruleset to 2: W) L( K: T$ e2 t8 X2 d+ j
L c$ Y- A0 `2 c4 ~! J
set pool 1 crush_ruleset to 3
, @; C; B* P& f4 S4 b- x# T f) Q$ X' S: y1 Z
### 此时,将 volumes 池的 副本数 设置为2 ,此时 PG 状态经过 peer 之后,很快变为 active+clean ,volumes 池的两副本均落在新的节点下,并且后台在自行删除之前旧节点上的数据。; J: I$ O+ T5 ]) A
' Y3 O) ?3 W* L* i" m. {5 i, o2 l[root@ceph cluster]# ceph osd pool set volumes size 2+ `( e- B6 q7 g) k0 m% T
0 v+ ]8 C! O0 a5 A% v" c4 q
注意事项9 ?' _- i* P) {( e
- I' Q$ s/ x( j; l6 N8 B( S5 r; O0 j. U" h5 }0 g
由于本次数据迁移是在生产环境上执行的,所以没有直接执行将数据从旧节点直接 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 卡住现象。因此我们需要制定完善的回退步骤,在意外发生的时候,能够快速将环境回退到上一步集群正常的状况,而不是在意外发生时惊出一身冷汗,双手颤抖得敲指令。。。所以,下面的表格给出了这个变更操作的每一步的回退步骤: 9 z+ Q8 [% z$ G+ {( ~
[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。 |
/ M3 _2 m* T: ]
为何不直接迁移数据到新节点?总体来看数据迁移过程,最耗时的地方是数据从两副本变为四副本的过程,其余过程是短暂且可以快速回退的,而如果直接将池的 crush_ruleset 设置为 3 ,数据开始从旧节点直接backfill到新节点上,其实这么做也是可以的,但是这里我们就会遇到一个问题,一旦数据复制了一天或者一段时间后,集群出现了问题,比如性能骤降,要求必须回退到操作之前的状态,此时已经有部分PG完成了迁移,也就是说旧节点上的两副本已经删除了,那么回退到上一步后,还会发生数据从新节点向旧节点的复制,那么之前复制了多久的数据,可能就需要多久来恢复旧节点上删除的数据,这很不友好。而用了我们的方法来复制数据的话,不会存在这个问题,因为这里的方法在最后一步将池的副本设置为2之前,旧节点上的数据始终都是在的,并且不会发生任何迁移,我们可以在任意意外情况下,通过几条指令将集群恢复到变更之前的状态。
, Q* d& i3 a' q' s% D5 D' Z 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
4 i2 f( `2 Z( v$ p1 N' Wqemu 3171 1 17 14:32 ? 00:31:08 /usr/libexec/qemu-kvm -name guest=instance-0000000b........./ i/ R6 j+ V. e) I+ _9 S
2 ~- E" H- ~; m+ l5 f2 K6 a' |. J
[root@con ~(keystone_admin)]# netstat -tnp |grep 3171|grep 6789
- _ F& M/ x0 V3 Z2 c! b. Otcp 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
, d d3 I! l& `4 W# V
+ W# P- I p+ l5 I! a& D[root@con ~(keystone_admin)]# netstat -tnp |grep 3171|grep 6789
7 R) r, `- h7 U# y Ntcp 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
8 p. _0 ^2 a, R& B- Z5 ? 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: ### 具体字段为:
4 @' A5 y9 I) K$ g+ f" f1 G* emysql => # R0 ~+ w- r8 ~5 c- \
nova => block_device_mapping => connection_info
% @$ e o) M# T; b5 l/ Y! h/ k1 {% P( o
*************************** 23. row ***************************1 x: O! r2 ~; O2 |# x0 A
created_at: 2018-03-19 08:50:59
, V3 D2 w9 J+ p3 G0 t. Y ~ updated_at: 2018-03-26 06:32:06) ]$ h' P* W/ |
deleted_at: 2018-03-26 09:20:02 j6 o! D1 A% x: S" w
id: 29
* Z Q, {# G( ~$ D/ H; p device_name: /dev/vdb
5 m7 ?! b5 l5 ` Kdelete_on_termination: 0
- W+ y/ b$ y% @3 e. F0 G snapshot_id: NULL
1 S9 O S' `2 `% ~. ]" E volume_id: 39c76d96-0f95-490c-b7db-b3da6d17331b) M4 V2 A/ t/ l* e
volume_size: NULL
* g$ p7 d9 V# \; a& W1 V# W8 y no_device: NULL
) r: U" ?8 T. H- ^& z) V 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"]}}
/ O( |6 p# e' p instance_uuid: 4f52191f-9645-448f-977b-80ca515387f7& T& j2 k/ r$ P$ Y! G
deleted: 29
2 c" Z2 N! Y! A2 P source_type: volume- z5 ^" l; E# R' o" W3 c7 k
destination_type: volume9 o) y/ |2 v' y
guest_format: NULL
- K) D9 o8 x) E1 I0 g7 @/ c device_type: disk* x. M) }9 ^6 h! e) J# [, I8 D
disk_bus: virtio
+ h8 Z; R5 s: N& Z: Z# b! Z boot_index: NULL/ X* u7 h9 N% M2 P S: Y# t, A
image_id: NULL迁移指令这里,我们使用 ceph-deploy 来增删 MON 节点,主要是为了操作的简洁和安全性着想。 首先,我们需要将新的三个MON的IP地址加入到所有节点的/etc/ceph/ceph.conf的mon_host 字段中。保证此时mon_host内是六个MON的IP地址。 ### 添加 new_mon_1 % {2 C3 p' a+ ?4 D( c
[root@ceph cluster]# ceph-deploy mon add new_mon_1
# c1 E6 D4 ]$ v+ f[root@ceph cluster]# ceph -s
z$ c5 }; N( |, \6 t# m- T cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d
( x6 D" V3 I* s! C8 X! x' ~ health HEALTH_OK8 m6 Z/ v4 m9 R. Y* _% e
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}
) f" R( n, V3 U; l; L" x
}, ]/ s* I5 p- N: f### 删除 con 删除完后,建议等待1-3min再添加新的MON,使得qemu-kvm进程可以建立新的socket链接。8 e c8 H- p8 ^2 q3 N* j
[root@ceph cluster]# ceph-deploy mon destroy con: A( u1 z& _9 f
[root@ceph cluster]# ceph -s
4 V$ s4 s& K' }/ h- G cluster 166889ab-fa7b-4a07-83da-6dfc92913a3d& S9 x, U* b) Z7 A, M8 ^) M: ~
health HEALTH_OK4 ^# \1 U) s7 b( S4 d
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}
; Z: q6 S4 Z: ?' N3 N$ g
0 E3 f8 B, f7 ?5 I### 依次添加 new_mon_2 ,删除 com,添加 new_mon_3 , 删除 ceph:
0 D9 J7 w2 e$ z% d+ N8 W0 w: y[root@ceph cluster]# ceph-deploy mon add new_mon_27 J! `& K& r0 d6 a6 }3 ~3 V! |. ~5 @5 R
[root@ceph cluster]# ceph-deploy mon destroy com , d G& Z; g5 x7 e# z
### 等待1-3min,9 H+ Y( r0 E/ w+ t$ e! _9 m9 i9 N
[root@ceph cluster]# ceph-deploy mon add new_mon_3
6 e; ]( X* O' A M& c0 M5 M[root@ceph cluster]# ceph-deploy mon destroy ceph4 K7 G1 P$ C1 L3 E6 D
( D* z L+ z0 t7 x( Q
[root@con ~(keystone_admin)]# ceph -s
1 k* x" `2 a9 m9 Q Ycluster 166889ab-fa7b-4a07-83da-6dfc92913a3d
$ Y+ j0 K- b7 C4 A health HEALTH_OK* Y; ~6 Z1 I% M# z! u* @
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地址。 ! h( O! q& J; E h9 I3 K
Glance & Cinder & Nova 服务重启无需重启 Glance 服务。 需要重启 所有计算节点的 nova-compute 和 控制节点的 Cinder 服务,否则会导致虚机无法创建等问题。 ## 在计算节点
/ L; z9 I) U, ? G0 [openstack-service restart nova-compute, }/ ]. y: |3 f6 d; h2 J1 H& K
## 在控制节点
}, Y- P! W2 S. k3 {) n" k& r" S* lopenstack-service restart cinderNova由于 nova 不会更新之前的已经挂载的磁盘所连接的MON IP 信息,这会导致虚机在重启等动作时,尝试连接到旧的已经被摧毁的MON的地址,导致动作卡住,因此这里要单独改一下数据库内的MON IP 信息: 这里我们将 192.168.10.10/11/12 改为 192.168.10.13/14/15 mysql >>
1 E8 k O/ C0 ?6 O- l& ?" n" z
# s$ X2 B5 `. W+ C! T& I( x& fuse nova;/ u* Z4 `: ^) _/ l. H
update block_device_mapping set connection_info=(replace(connection_info,'192.168.10.10','192.168.10.13'));. J; K9 Y' X- z7 k' F# M n" ]3 o$ d
update block_device_mapping set connection_info=(replace(connection_info,'192.168.10.11','192.168.10.14')); q5 }% S: U3 Q8 s& j& s2 _2 p
update block_device_mapping set connection_info=(replace(connection_info,'192.168.10.12','192.168.10.15'));4 v/ k5 |( J: [( h0 B9 G
0 q7 l8 |9 J+ X* ~" u3 f) O
exit;更新完数据库后,这次数据迁移算是大功告成了。为何不需要重启虚机服务呢,这里再做一些简单的介绍: qemu-kvm 虚机进程是一个长连接的 Ceph Client,自虚机启动后,进程就和 Ceph 集群保持着连接,在我们更改 MON 后,这些 Client 会自动尝试重连 monmap 里面的其他MON,从而更新 monmap, 来获取最新的 MON 。修改 /etc/ceph/ceph.conf不会对虚机进程产生影响,除非虚机重启等,但是,虚机可以通过更新 monmap 的方式来感知集群MON的改变。 |