|
|
个人主要关注的技术领域:高性能Nginx开发、分布式缓存、分布式存储。
4 `- a+ m, |5 j1.说明介绍 1.1 基本原理
/ j/ }9 @7 O2 ? YRBD Mirror原理其实和MySQL的主从同步原理非常类似,前者基于journaling,后者基于binlog,简单地说就是利用日志进行回放(replay):通过在存储系统中增加Mirror组件,采用异步复制的方式,实现异地备份。(此处的journal是指Ceph RBD的journal,而不是OSD的journal)
* @6 u0 S& E$ a! b3 w+ h$ s该能力利用了 RBD image 的日志特性,以确保集群间的副本崩溃一致性。镜像功能需要在同伴集群( peer clusters )中的每一个对应的 pool 上进行配置,可设定自动备份某个存储池内的所有 images 或仅备份 images 的一个特定子集。 rbd-mirror 守护进程负责从远端集群拉取 image 的更新,并写入本地集群的对应 image 中。) O5 o' O: y: y
当RBD Journal功能打开后,所有的数据更新请求会先写入RBD Journal,然后后台线程再把数据从Journal区域刷新到对应的image区域。RBD journal提供了比较完整的日志记录、读取、变更通知以及日志回收和空间释放等功能,可以认为是一个分布式的日志系统。: L+ F) s$ w; j2 g; _) G) I8 I
1.2 工作流程
1 \: D5 L" j( ~+ V- S3 b8 f
3 T$ V) _ c; u$ U P8 P+ w1、当接收到一个写入请求后,I/O会先写入主集群的Image Journal
! W w$ l( E* t! _ F) r) i) Y2、Journal写入成功后,通知客户端5 k; P/ ? @0 n8 w; B5 v
3、客户端得到响应后,开始写入image# ~, O+ g; r- M
3、备份集群的mirror进程发现主集群的Journal有更新后,从主集群的Journal读取数据,写入备份集群(和上面序号一样,是因为这两个过程同时发生)9 a9 _" Q& [/ M/ O0 w
4、备份集群写入成功后,会更新主集群Journal中的元数据,表示该I/O的Journal已经同步完成 A, S# J% D6 E5 d+ A# ~
5、主集群会定期检查,删除已经写入备份集群的Journal数据。
8 |0 ]! w$ y# z9 ~2 T; I) d以上就是一个rbd-mirror工作周期内的流程,在现有的Jewel版本中30s为一次工作周期,暂时不能改变这个周期时间。- J* a7 t7 n! P! q9 Q7 a
1.3 优点
+ Y9 x% W0 K! @* G/ D- D% `) N$ N1、当副本在异地的情况下,减少了单个集群不同节点间的数据写入延时;- U7 [( M! a& V7 X: }4 i# M9 {4 O
2、减少本地集群或异地集群由于意外断电导致的数据丢失。! k$ {8 O' p* S
1.4 单向备份与双向备份, X" m$ P+ b( L; d2 I: O7 P
双向备份:两个集群之间互相同步,两个集群都要运行rbd-mirror进程。$ l' _0 j- p" f+ w3 X8 p
单向备份:分为主集群和从集群,只在从集群运行rbd-mirror进程,主集群的修改会自动同步到从集群。7 |( r6 U. U# P2 z
1.5 安装须知
8 \5 ?8 B0 Z" @* F' NRBD 镜像功能需要 Ceph Jewel 或更新的发行版本。6 B! [: ~5 R9 I4 M8 \1 C. P
目前Jewel版本只支持一对一,不支持一对多。
' { P b9 ]+ K- s两个集群 (local和remote) 需要能够互通。, Y9 ]- G7 |* D$ _( @3 c
RBD需要开启journal特性, 启动后会记录image的事件。8 w! W5 c% h' B) x+ p6 y1 Q3 g
2. mirroring 模式1 O$ [% X' \# H: ?) t
mirroring是基于存储池进行的peer,ceph支持两种模式的镜像,根据镜像来划分有:
! i5 u; T3 `; R" f+ q. {: O; }$ X' s7 M存储池模式% x8 ?7 L7 f! A9 A/ `( G' Y
一个存储池内的所有镜像都会进行备份
1 C+ J( H2 b% ?% Z3 J1 Q5 [1 d镜像模式# O$ C% ]9 t' t- j
只有指定的镜像才会进行备份% ^5 H* Z5 Q8 k3 o6 E1 b
2.1 存储池模式 2.1.1 创建存储池. C6 @* F3 b8 L2 t9 C
创建一个用于测试的存储池:" e+ y1 t8 U* F; z# }5 ?7 r( O
#local集群9 k2 W' t, t- }
ceph osd pool create test_pool 100 100 replicated --cluster= localpool 'test_pool'created
D- b! j$ c K2 n7 X& e/ w' s* I#remote集群
" t. R( P3 w$ ^ceph osd pool create test_pool 100 100 replicated --cluster=remotepool 'test_pool'created 2.1.2 启用存储池模式8 K$ v, B# @2 p6 v' h6 I5 I
开启存储池rbdmirror的镜像功能:
9 `5 M$ c1 ]# |! O( y" W+ z0 b) _0 O#local集群
' d! i' w1 n# orbd mirror pool enabletest_pool pool --cluster= local1 r1 n6 @5 Q2 z# K) ^& v
#remote集群
. U& i' O/ Z2 \( q* Vrbd mirror pool enabletest_pool pool --cluster=remote 2.1.3 创建RBD& P- ^1 U4 K9 a2 a) O
主集群创建一个测试用的RBD:3 g# V6 ]4 D3 n* F0 A4 u+ a- t) j
rbd create test_pool/test_image --size=1024 --cluster= local2.1.4 主集群开启jounaling特性
$ C* j' Z R J0 [9 J& y3 h; b启动后会才会记录image的事件,才可以被rbd-mirror检测到并同步到从集群:9 O4 h5 n: b0 c0 o
rbd feature enabletest_pool/test_image exclusive-lockrbd feature enabletest_pool/test_image journaling 2.1.5. 增加同伴集群) @, W6 S) V+ E* f1 @" t
把local和remote设为同伴,这个是为了让rbd-mirror进程找到它peer的集群的存储池:
3 G5 I5 A& N3 g2 S9 crbd mirror pool peer add test_pool client.admin@remote --cluster= local
3 k1 U3 e2 U0 S" ?+ c" xrbd mirror pool peer add test_pool client.admin@ local--cluster=remote
t# C% W4 x4 S7 r% S4 ?#如果需要删除peer 语法:2 S6 ^0 Z# u5 g
rbd mirror pool peer remove <pool-name> <peer-uuid>
+ [0 [) l+ N$ |- X% v查看peer的情况:
; d: |5 R$ ] Vrbd mirror pool info --pool=test_pool --cluster= localMode: poolPeers:UUID NAME CLIENTf0929e85-259d-450b-917e-9eb231b7e43b remote client.admin rbd mirror pool info --pool=test_pool --cluster=remoteMode: poolPeers:UUID NAME CLIENT5851ba6a-e383-4ef0-9b9d-5ae34c9518a6 localclient.admin 2.1.6 开启rbd-mirror的同步进程8 H- H% w( A/ U2 i
a. 先用调试模式启动进程看看情况,在remote的机器上执行) S5 X s6 W5 W2 n) r% c* }
#remote:9 f1 [2 y7 { `( r- d% o, s0 F
rbd-mirror -d --setuser ceph --setgroup ceph --cluster remote -i admin2 U, S( \. m# t/ [! l0 Y' C# x5 d
b. 如果确认没问题就用服务来控制启动7 g! K8 H! y& I9 T2 j6 H% v% `
#remote% X" B0 C) Q5 P9 S7 t% G( Q
vim [url=]/usr/lib/systemd/system/ceph-rbd-mirror@.service[/url]
7 c+ V3 v' g; G m/ P+ S( a#修改3 j% S; _ C) [* r8 a S
Environment= CLUSTER=remote
7 [. U, t2 o# D kc. 在remote机器上启动# `- y* x$ W' i% M0 }% C+ B
systemctl start ceph-rbd-mirror @adminps -ef|grep rbdceph 43251117: 59? 00: 00: 00/usr/bin/rbd-mirror -f --cluster remote --id admin --setuser ceph --setgroup ceph 2.1.7 检查同步结果- c- Z6 t5 V1 L
a. 查询local集群镜像的同步的状态
6 D8 D# S6 T Q6 P& t' \#local5 V$ a: N+ k/ W; v" k9 {' d
rbd mirror image status test_pool/test_image --cluster remotetest_image: global_id: dabdbbed-7c06-4e1d-b860-8dd104509565 state: up+replaying deion: replaying, master_position=[object_number=2, tag_tid=2, entry_tid=3974], mirror_position=[object_number=3, tag_tid=2, entry_tid=2583], entries_behind_master=1391 last_update: 2017-01-22 17:54:22
! q& R5 M2 d8 _0 B4 \b. 检查数据是否同步到remote集群 m1 T/ s4 i# j9 W
#remote
- I# u1 H0 F& ^7 q/ r5 Brbd info test_pool/test_image 2.2 镜像模式 2.2.1 主集群开启jounaling特性: I% P7 I* [4 Q( c$ z" l& R
启动后会才会记录image的事件,才可以被rbd-mirror检测到并同步到从集群4 B. y7 s1 x4 Q; l2 S' |2 c
#local0 R7 N2 R! B! ?: }7 l
rbd feature enabletest_pool/test_image exclusive-lockrbd feature enabletest_pool/test_image journaling 2.2.2 开启存储池的mirror的模式 #local:
! O$ j; |: w9 _rbd mirror pool enabletest_pool image
( D D% n/ O- B7 c( N1 j#remote:# g5 }9 M7 t. J
ceph osd pool create test_pool 100 100 replicated --cluster=remotepool 'rbdmirror'created rbd mirror pool enabletest_pool image 2.2.3 开启image的mirror #local
8 \$ _8 a, L& J$ ~; }' orbd mirror image enabletest_pool/test_imageMirroring enabled rbd info test_pool/test_image --cluster= localrbd image 'test_image': size 10240 MB in2560 objects order 22 (4096 kB objects) block_name_prefix: rbd_data.105774b0dc51 format: 2 features: layering, exclusive-lock, journaling flags: create_timestamp: Wed Dec 13 16:46:08 2017 journal: 105774b0dc51 mirroring state: enabled mirroring global id: 013f9e35-9d08-40fc-bf24-1e11a07a0910 mirroring primary: true2.2.4 增加同伴集群& ~$ |( L7 f# T0 ~# ]; m
把local和remote设为同伴,这个是为了让rbd-mirror进程找到它peer的集群的存储池: x" X( ^3 g% f+ g8 z/ r
rbd mirror pool peer add test_pool client.admin@remote --cluster= local
; n3 }- K' {0 v, F! ~/ Brbd mirror pool peer add test_pool client.admin@ local--cluster=remote
; ]$ P0 o4 x# B. U( X4 E#如果需要删除peer 语法:
2 H: v# t, I* urbd mirror pool peer remove <pool-name> <peer-uuid>3 x% I6 T" h: C( j5 D, ^
查看peer的情况:. E. r5 d# O" k+ d0 Z
rbd mirror pool info --pool=test_pool --cluster= localMode: poolPeers:UUID NAME CLIENTf0929e85-259d-450b-917e-9eb231b7e43b remote client.admin rbd mirror pool info --pool=test_pool --cluster=remoteMode: poolPeers:UUID NAME CLIENT5851ba6a-e383-4ef0-9b9d-5ae34c9518a6 localclient.admin 2.2.5 开启rbd-mirror的同步进程
n/ a% [/ { U8 n: ra. 先用调试模式启动进程看看情况,在remote的机器上执行* }" q ]3 D( e
#remote:" U4 W2 {) ]) @
rbd-mirror -d --setuser ceph --setgroup ceph --cluster remote -i admin
- U0 a7 s1 B! ~& @/ Rb. 如果确认没问题就用服务来控制启动
/ O8 C0 n4 k+ |' V, m' c#remote- k9 }: ~$ K2 [- }' N1 I |. h3 I5 g
vim [url=]/usr/lib/systemd/system/ceph-rbd-mirror@.service[/url]5 Y. E6 W5 i1 P, x
#修改# ~7 h" g) q7 U; F3 i
Environment= CLUSTER=remote
4 U8 d3 k4 ^# P& w( F4 Uc. 在remote机器上启动
3 A, a$ A' o+ o1 X% s' Gsystemctl start ceph-rbd-mirror @adminps -ef|grep rbdceph 43251117: 59? 00: 00: 00/usr/bin/rbd-mirror -f --cluster remote --id admin --setuser ceph --setgroup ceph 2.2.6 检查同步结果
- T& F$ t0 M% y6 }; B% qa. 查询local集群镜像的同步的状态# b, {# o* P+ y0 B
#local
/ h# ~5 W5 {0 C6 b( I& y: `rbd mirror image status test_pool/test_image --cluster remotetest_image: global_id: dabdbbed-7c06-4e1d-b860-8dd104509565 state: up+replaying deion: replaying, master_position=[object_number=2, tag_tid=2, entry_tid=3974], mirror_position=[object_number=3, tag_tid=2, entry_tid=2583], entries_behind_master=1391 last_update: 2017-01-22 17:54:22
- O/ o: e1 S8 K' l; Db. 检查数据是否同步到remote集群" S" S" r9 m* G
#remote
8 _, U1 E' H& Krbd info test_pool/test_image 3. 测试对比报告 3.1 单主集群性能 3.1.1 rbd性能测试1 a+ m. A! I% V9 I! H- X
顺序读写 //block size是4M,30个线程并发 测试结果:30线程并发,带宽:935 MB/s 平均IOPS:228.33# `+ u* r# D1 V! h+ ^
rbd bench-write test_image --io-threads 30 --pool=test_pool --io-pattern seq --io-total 17199730000 --io-size 4096000elapsed: 18 ops: 4200 ops/sec: 228.33 bytes/sec: 935243763.72
& M: U, o3 R; P" |+ D随机读写 //block size是4M,30个线程并发 测试结果:30线程并发,带宽:936 MB/s 平均IOPS: 228.57; F2 t L2 F5 J! i" b
rbd bench-write test_image --io-threads 30 --pool=test_pool --io-pattern rand --io-total 17199730000 --io-size 4096000elapsed: 18 ops: 4200 ops/sec: 228.57 bytes/sec: 936229596.77 3.2 主备集群性能 3.2.1 rbd性能测试9 T- Y: H' l, n- P) j. ~8 c2 ^ ?
顺序读写 //block size是4M,30个线程并发 测试结果:30线程并发,带宽:182 MB/s 平均IOPS:44.53
2 L' J5 H% u6 r+ R m! Wrbd bench-write test_image --io-threads 30 --pool=test_pool --io-pattern seq --io-total 17199730000 --io-size 4096000elapsed: 94 ops: 4200 ops/sec: 44.53 bytes/sec: 182382108.66- C2 W f/ X. Z3 S; Y0 `
随机读写 //block size是4M,30个线程并发 测试结果:30线程并发,带宽:149 MB/s 平均IOPS: 36.50" J7 d; ^- h0 U7 t
rbd bench-write test_image --io-threads 30 --pool=test_pool --io-pattern rand --io-total 17199730000 --io-size 4096000elapsed: 115 ops: 4200 ops/sec: 36.50 bytes/sec: 149499469.69 3.3 测试结果4 g& d6 `( o8 y- N+ @
通过测试结果,可以看出启用rbd-mirror 会导致主集群性能下降5倍多。! H$ ^8 N2 U. P( A' j9 n
工具 集群模式 块大小 并发数 顺序读写 随机读写
4 T9 P+ F }- X" a4 {% f4 Frbd bench-write 单主集群 4M 30 带宽:935 MB/s
! L+ ~% Z, X0 G+ H# p& R平均IOPS:228.33
5 `% [' @/ z9 u: m* M: s! R带宽:936 MB/s
' r& P- |5 [0 n3 _( i平均IOPS: 228.57: X9 m5 c5 Y) e/ ]& H0 \" q; `# {0 `
rbd bench-write 主备集群 4M 30 带宽:182 MB/s2 p/ e" o7 S2 L; @9 |, c z! H* K; j
平均IOPS:44.53' Y8 V! g- D$ S$ m
带宽:149 MB/s: j2 v& C, E5 a* |
平均IOPS: 36.50. P, T* o1 z/ J
4. 分析原因 4.1 journal流程, n( I0 P. d# ]& k
当RBD Journal功能打开后,所有的数据更新请求会先写入Image Journal0 d* ^. O. R# g& S% M1 V# S
写入成功后,通知客户端
. {+ N }* y3 p3 Z客户端得到响应后,开始写image
; C, n% k( h1 ~4 J备份集群的mirror进程发现主集群的Journal有更新后,从主集群的Journal读取数据,写入备份集群
% n- H- G( k( C% [' O9 x备份集群写入成功后,会更新主集群Journal中的元数据,表示该I/O的Journal已经同步完成
5 a6 Q% P! I8 r* Y, y7 T4.2 优化! z/ Q1 q8 l$ T* N5 V% X
Use a small SSD/NVMe-backed pool for journals* W" w; j; D! ~
‘rbd journal pool = <fast pool name>’' p5 ~* j/ Z8 d: J
Batch multiple events into a single journal append
. A. r& m6 a; T) a. j: S‘rbd journal object flush age = <seconds>’% I- `- O7 L; e7 @- b' n
Increase journal data width to match queue depth
1 C5 ^ Y B; `, _% }- l‘rbd journal splay width = <number of objects>’3 s. _: B( i$ J( G" Q/ ~$ f
Future work: potentially parallelize journal append + image write between write barriers6 m$ o. N& m7 H ` t
1. rbd journal pool 功能没实现sudo ceph daemon osd.0 config setrbd_journal_pool = test_pool3{ "error": "error setting 'rbd_journal_pool' to '= test_pool3': (38) Function not implemented"} 2. 调整参数从10-100,效果不明显rbd_journal_object_flush_age = 100rbd_journal_splay_width = 100 4.3 官方待改进 4.3.1 引入一致性组0 G) i: w- r o8 k) j. W
journaling可以看做是另一个rbd的image(一些rados对象),一般情况下,先写日志,然后返回客户端,然后被写入底层的rbd的image,出于性能考虑,这个journal可以跟它的镜像不在一个存储池当中。
% R0 } t" B) I- e) Q; D0 T/ c目前是一个image一个journal,最近应该会沿用这个策略,直到ceph引入一致性组。关于一致性组的概念就是一组卷,然后用的是一个RBD image。可以在所有的组中执行快照操作,有了一致性的保证,所有的卷就都在一致的状态。4 ]9 W! M& L; N$ K6 J2 h
3.当一致性组实现的时候,我们就可以用一个journal来管理所有的RBD的镜像,可以给一个已经存在image开启journal,ceph将会将你的镜像做一个快照,然后对快照做一个复制,然后开启journal,这都是后台执行的一个任务可以启用和关闭单个镜像或者存储池的mirror功能,0 t' t7 A% j& o g
如果启用了journal功能,那么每个镜像将会被复制可以使用 rbd mirror pool enable启用它。
4 A# A9 F+ i& V, B& c$ Y5 N' _4.3.2 并行写
5 M( h6 s3 q9 U2 ]Future work: potentially parallelize journal append + image write between write barriers7 O9 s, d5 e0 v- N2 [* H
参考官方文档如下:
, C! [+ h( D; y% p官方类似问题:https://www.spinics.net/lists/ceph-users/msg31676.html
0 Q0 L1 I& K @1 m( k& ^4.4 结论' k- h @" d$ o* ^) u
由于核心流程就是先写日志,然后写image需要写两份的逻辑,所以导致性能就会有损失。! S, M7 E/ x0 ^: ?
根据官方的参数优化也没有明显的效果,建议等待官方更新features。
5 i0 F4 z' h0 j$ M |
|