找回密码
 注册
查看: 570|回复: 0

ceph 如何运维

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2023-3-17 10:06:55 | 显示全部楼层 |阅读模式
本文先介绍 Ceph, 然后会聊到一些正确使用 Ceph 的姿势;在集群规模小的时候,Ceph 怎么玩都没问题;但集群大了(到PB级别),这些准则可是保证集群健康运行的不二法门;
. n+ O% v# W; E1 `% P9 t  V6 u) s; P4 F9 u6 f+ h
Ceph 最初的目标是做一个分布式文件系统,直到现在这个目标也不能算完美实现;目前官网上对它的文件系统还是谨慎推荐的态度(不建议对线上核心业务部署);
- j5 G3 \- e6 x& v5 Q7 T( X4 f: p5 m: q6 a7 \: Y2 K/ f
业界使用 Ceph ,大多是用它的对象存储;
+ ?( N+ ?: m8 w9 v: K& u& L9 y9 ~9 S
Ceph 客户端) O2 t6 u& v9 V/ c4 `
Ceph 支持三种存储接口:对象存储 RGW(rados gateway)、块存储 RBD(rados block device) 和文件存储 CephFS;* K3 d5 E0 k; S
; k/ u. `3 I7 F. @% W
这三个接口只是在客户端的封装库不同,到服务端了都是对象存储;
0 c3 }9 b3 b) c/ t5 b2 t7 l
$ s; J- `' m9 H: N+ }7 O
9 d3 q% \) N6 A  R! F对象存储(RGW:RADOS gateway)
( B: ?0 ~) T+ F7 a7 a8 T0 {8 uCeph 对象存储服务提供了 REST 风格的 API ,它有与 Amazon S3 和 OpenStack Swift 兼容的接口。也就是通常意义的键值存储,其接口就是简单的GET、PUT、DEL和其他扩展;
; L: p3 @0 V* d# F: M; o
* B: ~; N' L; Y1 J$ T; S块存储(RBD:RADOS block device)
! X( V# M; B" w1 e5 E0 u; ERBD 是通过librbd库对应用提供块存储,主要面向云平台的虚拟机提供虚拟磁盘;RBD类似传统的SAN存储,提供数据块级别的访问;
' O1 A  _  J" A. d9 @. S- h3 h6 z, ~; K: J  {
目前 RBD 提供了两个接口,一种是直接在用户态实现, 通过 QEMU Driver 供 KVM 虚拟机使用。 另一种是在操作系统内核态实现了一个内核模块。通过该模块可以把块设备映射给物理主机,由物理主机直接访问。- K" t1 J! S- E+ e% X0 A
; B7 R7 J5 ]9 h+ z, M: `8 X4 C! @2 T  e
文件存储: x  S. n- w4 t7 G! p3 p* c
Ceph 文件系统服务提供了兼容 POSIX 的文件系统,可以直接挂载为用户空间文件系统。它跟传统的文件系统如Ext4是一个类型,区别在于分布式存储提供了并行化的能力;  Y) D) i1 G- N1 ^
) f6 v6 _4 ]* y: M  J& N+ B
原生接口! G: L& d6 c, P
除了以上3种存储接口, 还可以直接使用 librados 的原生接口,直接和RADOS通信;
: l4 g7 C& E: T2 q9 k$ O; ^  K3 c! v+ s) h. A& Y
原生接口的优点是是它直接和和应用代码集成,操作文件很方便;但它的问题是它不会主动为上传的数据分片;一个1G的大对象上传,落到 Ceph 的存储磁盘上就是1G的文件;- `( p7 p- M7 @' b6 [' Y* ~) F
$ o; E9 p$ ?/ M# t/ U# ?; z
而以上三个接口是具有分片功能(即:条带化 file-striping)( c* S" X, d; v: r1 B% h; x

' W$ u' l0 x9 S7 ~% O3 V! OPS:两个对象的区分
/ ?1 @* K: y3 `
, Y0 ?; x/ t: w1 y9 }/ _需要说明下,这里提到两个对象的概念:一个是 RGW中的对象存储,一个是 Ceph 的后端存储的对象;这两个需要区分:3 H6 S, g5 Y  b# h' v' c
( s- Y1 f. F& Q
第一个对象面向用户,是用户接口能访问到的对象;
: U* |1 e, @; s# l  O7 T8 s
6 p5 @: Y- |* T! A第二个对象是ceph 服务端操作的对象;5 ~, E: }# h4 T4 u3 e( }5 ^
4 N8 G& |5 v" Z+ ?  x6 b
eg:使用RGW接口,存放一个1G的文件,在用户接口看到的就是存放了一个对象(1);而通过RGW 分片成多个对象(2)后最终存储到磁盘上;
5 n! j1 \; q- g1 N% z2 Q  Y  s% s: X% o( \. r
2 U; Q6 T: U* z1 \: R( d
Ceph 服务端% t- R5 c2 F$ u
% S. F6 a+ \: Q+ Q
  o9 S: @/ D1 C- u6 Z! m7 u
服务端 RADOS 集群主要由两种节点组成:一种是为数众多的、负责完成数据存储和维护功能的OSD(Object Storage Device),另一种则是若干个负责完成系统状态检测和维护的monitor。4 P+ K& \2 J1 [" o8 `2 ~$ k2 f

0 O# v% i8 b7 T9 p, ]+ wMonitor
/ I+ u3 W4 N4 l; N; t; _Monitor 集群提供了整个存储系统的节点信息等全局的配置信息,通过 Paxos 算法保持数据的一致性。3 H0 M% n1 q6 T

# J: b) R* t) B$ c2 i* a3 k& `' hPool 、PG和OSD
+ j9 C' P+ b2 D7 R' ]4 GPool是存储对象的逻辑分区,它规定了数据冗余的类型和对应的副本分布策略;支持两种类型:副本(replicated)和 纠删码( Erasure Code);目前我们公司内部使用的Pool都是副本类型(3副本);
) K0 s; ?. O5 }8 t  s- t6 E. B  Y" z
PG( placement group)是一个放置策略组,它是对象的集合,该集合里的所有对象都具有相同的放置策略;简单点说就是相同PG内的对象都会放到相同的硬盘上; PG是 ceph的核心概念, 服务端数据均衡和恢复的最小粒度就是PG;" X0 D+ _9 `, O* o  ~
! ]( L- X8 w0 S, I, Z. K: c* Y
OSD是负责物理存储的进程,一般配置成和磁盘一一对应,一块磁盘启动一个OSD进程;
+ D1 J6 e9 n$ D
! I, N' t1 W8 `2 U下面这张图形象的描绘了它们之间的关系:
& U  z9 s9 V3 m/ _" w# F2 J  h$ s( X  j* w0 r! k, [5 b
一个Pool里有很多PG,/ {0 f3 N0 J' K- e9 x8 B
一个PG里包含一堆对象;一个对象只能属于一个PG;
5 T6 c$ m, l. K1 T4 VPG有主从之分,一个PG分布在不同的OSD上(针对三副本类型)1 F  y% W' j9 h8 X2 J  p
( Q2 ?2 D' S0 e5 ?) J

# O0 k  N- A! B8 X/ b  F( b7 |讲究的PG
: u& \8 g) n. a: b2 Y: \4 K- \3 q' L5 _" g4 ]
一个Pool里设置的PG数量是预先设置的,PG的数量不是随意设置,需要根据OSD的个数及副本策略来确定:
! q6 n1 u4 {( i! B1 V3 U6 J; Y0 ]- G
Total PGs = ((Total_number_of_OSD * 100) / max_replication_count) / pool_count+ u; u/ g: Q$ r% B* g0 q! V

. t" _% F. d& G  Z4 f& o5 ?2 n- d) |/ Y& d8 x' k
线上尽量不要更改PG的数量,PG的数量的变更将导致整个集群动起来(各个OSD之间copy数据),大量数据均衡期间读写性能下降严重;
1 o8 |! s1 E* v9 _; x8 W3 }4 y9 W+ n' y% m
良好的工程实践建议(掉坑后的教训):& \1 y" I$ [: ]- @2 Y: ?0 w( }
预先规划Pool的规模,设置PG数量;一旦设置之后就不再变更;后续需要扩容就以 Pool 为维度为扩容,通过新增Pool来实现(Pool通过 crushmap实现故障域隔离);
0 U5 m. M: ~$ a$ j$ F  p) Q  r( a. U6 E
对象的寻址过程
3 o7 o5 _' G8 C查找对象在集群中的存储的位置,具体分为两步:$ }! C2 D5 m  z/ ~' S: A. U
第一步,对象到PG的映射;将对象的id 通过hash映射,然后用PG总数对hash值取模得到pg id:2 E2 S0 l9 r; @1 T, F
7 f! a4 O4 }+ `: U
pg_ id = hash( object_ id ) % pg_num
1 U4 S0 H4 y# r% V: R2 J
1 x/ i+ r/ l- n5 A& @
( I6 k' I5 e2 P8 N7 a" ?# @. N8 L第二步,PG到osd列表映射; 通过crush算法计算PG 上的对象分布到哪些OSD硬盘上;4 r7 \" q% I- E( I) e* z

/ A& j% Z) p4 O  W& sCRUSH(PG_ID) =⇒ OSD
$ |) ]8 ]$ P5 `7 G/ rCRUSH算法是 ceph的精华所在;& Y2 r; [" Y, D

' O- X2 r" \' V- `crush的目标
9 {. `0 K+ d* G4 J" h先看看crush算法的希望达成的目标:
! ~) H5 o3 f. t0 Z0 Y2 h# Z8 T9 F; `$ w: d/ O
数据均匀的分布到集群中;
; ]1 w1 k2 ~: `! L$ c6 }, Y, e. Y需要考虑各个OSD权重的不同(根据读写性能的差异,磁盘的容量的大小差异等设置不同的权重)
4 o& E9 M, V/ B2 h% ^当有OSD损坏需要数据迁移时,数据的迁移量尽可能的少;
( H5 O% h! ]1 C* a; h+ q, }crush算法1 P  s( M5 r% ?' A: a
简单说下crush算法的过程:
6 P( M& R" j2 D6 o+ A第一步输入PG id、可供选择的OSD id 列表,和一个常量,通过一个伪随机算法,得到一个随机数,伪随机算法保证了同一个key总是得到相同的随机数,从而保证每次计算的存储位置不会改变;
) V) f1 n6 M) V& i8 F2 S
/ R3 [5 r6 T$ b9 A, a9 B. H6 tCRUSH_HASH( PG_ID, OSD_ID, r ) = draw
9 B" W% [  o' T8 H9 R, `第二步将上面得到的随机数和每个OSD的权重相乘,然后挑出乘积最大的那个OSD;
5 V9 i0 w) S# X3 G( ~- c; B( w% F- O* {# ^
( draw &0xffff ) * osd_weight = osd_straw3 S; I: J6 Q0 E  I& O3 Q! r
在样本容量足够大之后,这个随机数对挑中的结果不再有影响,起决定性影响的是OSD的权重,也就是说,OSD的权重越大,被挑中的概率越大。, Q# X* K% J' y, o; s
到这里了我们再看看crush算法如何达成的目标:# ]/ R. n/ p5 J, x( [) V/ \
通过随机算法让数据均衡分布,乘以权重让挑选的结果考虑了权重;而如果出现故障OSD,只需要恢复这个OSD上的数据,不在这个节点上的数据不需移动;$ h: t- ^$ K2 K+ H. m8 B" ?
- [  Q" z" t0 b. G$ f' s/ U
crush优缺点
% \7 j  L  y% [- _4 v, i1 x/ P' _; [聊到这里,crush算法的优缺点就明显了:
! Y3 ]7 x5 C( g优点如下:
3 v+ t) ]( Z5 h4 Z4 N9 c- Z$ _7 H0 n6 o2 K& C
输入元数据( cluster map、 placement rule) 较少, 可以应对大规模集群。
% n8 V, P1 q% r/ r! z, e可以应对集群的扩容和缩容。0 E+ p# `/ H% d+ ?
采用以概率为基础的统计上的均衡,在大规模集群中可以实现数据均衡。( [: I& t3 C  ^
缺点呢:
! D# t6 W: W% Y8 B8 K. w' J* ?: h
9 A: K5 d$ u% l1 L& J3 U( B7 O- l在小规模集群中, 会有一定的数据不均衡现象(权重的影响低,主要起作用的是伪随机算法)。
, p/ b# n9 V7 C6 s看清楚了寻址的过程,就明白为啥PG不能轻易变更了;PG是寻址第一步中的取模参数,变更PG会导致对象的PG id 都发生变化,从而导致整个集群的数据迁移;) c3 w1 ?# }# h& |4 E2 h5 _

) U4 F! Z+ l: \+ d4 D这里只是做个引子,关于crush算法,这篇文章讲的通俗直白,有兴趣的移步:大话Ceph--CRUSH那点事儿
' a7 H) k9 P3 J
. @8 Y( H/ [; o- k3 h( ^/ y7 ICeph 是Sega本人的博士论文作品, 其博士论文被整理成三篇短论文,其中一篇就是 CRUSH,
/ k# X: p1 u5 J9 p0 ACRUSH论文标题为《CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data》,介绍了CRUSH的设计与实现细节。8 f' e8 R6 A: m. l
(PS:另外两篇是 RADOS和 CephFS, 分别讲 Ceph 的服务器实现和 Ceph 文件系统的细节实现)
0 p! `' t- i: q6 g) D; O0 T+ d5 E' C4 c
故障域的划分
0 Z: I" o) w+ I; o' A/ j9 X刚开始接触 Ceph,通常会忽略 crushmap,因为即使对它不做任何设置,也不影响我们的正常使用;
' I& n1 |1 y# F3 \) e一旦集群大了,没有它集群就处于一个危险的运行状态中;
* V' s8 B3 _0 _% }& D没有故障域的划分,整个集群就处于一个未隔离的资源池中;
5 k0 w3 W) K) K+ w& s一个对象存过去,可能落在 500个OSD硬盘的任意三个上;
; B. H5 e% ]. r4 K' e如果一块硬盘坏了,可能带来的是全局影响(副本copy,这个硬盘上丢失的PG副本可能分布在全局各个硬盘上);/ r3 M$ i* J* W4 k/ x9 s5 y

, G' O+ |2 l1 \7 O% y# u, q使用crushmap 将整个集群的OSD 划分为一个个故障域,类似将一个集群按业务划分成为了多个小集群;每个Pool 只会用到特定的 OSD,这样,一旦某个OSD 损坏,影响的只是某个业务的某个Pool,将故障的范围控制在一个很小的范围内。, T9 [; p/ ?, ?5 |! ?! V. c

% Y7 D# t9 z; |4 x+ o- V6 t/ X7 D良好的工程实践建议:+ i  C' N! \) t1 U
使用crushmap 划分故障域,将pool限制在特定的osd list上,osd的损坏只会引起这个pool内的数据均衡,不会造成全局影响;
/ G3 G& d0 T& S( [/ s5 D' k- i+ k2 D1 r* s  ?0 J% ?. X
服务端对象的存储
/ w8 h1 H8 y) a/ |8 w! {9 W对象是数据存储的基本单元, 一般默认 4MB 大小(这里指的是RADOS的底层存储的对象,非RGW接口的对象)。7 l0 R0 H" I! x" O2 f

# c  E" \' e, k' K6 E; A/ K0 {5 ?$ p7 O( i对象的组成分为3部分:key 、value、元数据;
7 X8 |8 d4 y4 {+ ]
* m" v4 |) j7 w5 H7 q元数据可直接存在文件的扩展属性中(必须是标准的文件属性),也可存到levelDb中;
, E. P" D: d" L+ j. j" tvalue 就是对象数据,在本地文件系统中用一个文件存储;, S8 x4 g+ O1 P7 f8 u
对于大文件的存储,Ceph 提供的客户端接口会对大文件分片(条带化)后存储到服务端;这个条带化操作是在客户端接口程序完成的,在 Ceph 存储集群内存储的那些对象是没条带化的。客户端通过 librados 直接写入 Ceph 存储的数据不会分片。
9 z! g7 t$ N  ^5 i- p3 h
2 @2 r0 C5 e* [6 j良好的工程实践建议:6 C, F* {9 N( M0 Z& |6 J" m- I
对于对象存储,只使用 Ceph 提供的 RGW 接口, 不使用 librados原生接口;不仅有分片功能,扩展也更容易(RGW是无状态的,可水平扩展);大量大对象直接存放到 Ceph中会影响 Ceph 稳定性(存储容量达到60%后);- n3 c! \" b* W) D

. _, B5 [* F0 C; e! a/ u0 C总结
6 m+ i+ J, \2 M5 w3 S3 |% e% \上线 Ceph 前,5 R2 m9 f  }8 c
先规划未来一年的预期使用量,为每个 pool 一次性设置 PG之后不再变更;
4 Q6 q. b1 @5 S+ `使用crushmap 设置故障域隔离,将磁盘故障后带来的数据平衡控制在一个小的范围之内。
5 B: O6 _6 h8 ~7 O. ?接口方面推荐只使用Ceph 提供的RGW 接口,不使用 librados原生接口。5 Z+ E9 a# e: `9 K' l8 y

2 K1 F# V: M  I1 F9 V2 C做好这些, 你的 Ceph 用起来会省心很多。
' b5 _. d9 l4 k
& R8 Z$ ], c9 M0 v$ g( X
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-12 00:04 , Processed in 0.017507 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表