zoukankan      html  css  js  c++  java
  • ceph学习之CRUSH

    CRUSH的全称是Controlled Replication Under Scalable Hashing,是ceph数据存储的分布式选择算法,也是ceph存储引擎的核心。在之前的博客里介绍过,ceph的客户端在往集群里读写数据时,动态计算数据的存储位置。这样ceph就无需维护一个叫metadata的东西,从而提高性能。

    ceph分布式存储有关键的3R: Replication(数据复制)、Recovery(数据恢复)、Rebalancing(数据均衡)。在组件故障时,ceph默认等待300秒,然后将OSD标记为down和out,并且初始化recovery操作。这个等待时间可以在集群配置文件的mon_osd_down_out_interval参数里设置。在recovery过程中,ceph会重新产生受故障影响的数据。

    因为CRUSH会复制数据到不同的磁盘,这些数据副本在recovery时就变得有用。在恢复过程中,CRUSH会尽量移动最小数量的数据,并且产生一个新的集群布局,从而使集群从故障中恢复。

    当新的主机或磁盘加入到集群时,CRUSH开始rebalancing操作,它将数据从存在的主机、磁盘迁移到新的主机、磁盘。rebalancing时会尽量利用所有磁盘,以提高集群性能。例如,某个ceph集群包含2000个OSD,现在新加入20个OSD,这样仅1%的数据将被迁移。在迁移中所有存在的磁盘会并行工作,使得迁移工作尽快完成。当然,如果ceph集群在重度使用中,推荐做法是新加入的磁盘设置权重0,并且逐步提高权重,使得数据迁移缓慢发生,以免影响性能。所有的分布式存储在扩容时都建议这样操作,比如我之前写的swift容量管理文章。

    在实际中可能经常需要调整集群的布局。默认的CRUSH布局很简单,执行ceph osd tree命令,会看到仅有host和OSD这两种bucket类型在root下面。默认的布局对分区容错很不利,没有rack、row、room这些概念。下面我们增加一种bucket类型:rack(机架)。所有的host(主机)都应位于rack下面。

    注:如下文字及图片,都来自《learning ceph》这本书。建议读者有时间详读原著。

    (1)执行ceph osd tree得到当前的集群布局:

    osdtree

    (2)增加rack:

    1
    2
    3
    $ ceph osd crush add-bucket rack01 rack
    $ ceph osd crush add-bucket rack02 rack
    $ ceph osd crush add-bucket rack02 rack

    (3)将host移动到rack下面:

    1
    2
    3
    $ ceph osd crush move ceph-node1 rack=rack01
    $ ceph osd crush move ceph-node2 rack=rack02
    $ ceph osd crush move ceph-node3 rack=rack03

    (4)将rack移动到默认的root下面:

    1
    2
    3
    $ ceph osd crush move rack03 root=default
    $ ceph osd crush move rack02 root=default
    $ ceph osd crush move rack01 root=default

    (5)再次运行ceph osd tree命令,会看到新的布局已产生,所有host都位于特定rack下面。按此操作,就完成了对CRUSH布局的调整。

    osdtree2

    对一个已知对象,可以根据CRUSH算法,查找它的存储结构。比如data这个pool里有一个文件resolv.conf:

    1
    2
    $ rados -p data ls
    resolv.conf

    显示它的存储结构:

    1
    2
    $ ceph osd map data resolv.conf
    osdmap e43 pool 'data' (0) object 'resolv.conf' -> pg 0.9f1f5993 (0.13) -> up ([1,2,0], p1) acting ([1,2,0], p1)

    输出结果说明:

    • osdmap e43: 这是osdmap的epoll版本
    • pool ‘data’: 这是pool名字
    • object ‘resolv.conf’: 这是对象名字
    • pg 0.9f1f5993 (0.13): 这是PG号
    • up ([1,2,0], p1): 存储该PG的3个OSD都是活跃的,这是一个有序数组,第一个是primary OSD
    • acting ([1,2,0], p1): 说明该PG存储在哪3个OSD里,同上也是有序数组

    ceph osd map命令只是自己计算一遍CRUSH,它并不确认目标pool里是否真有这个对象,所以随便输入什么文件名,它总是返回成功。

    关于对象在ceph里的存储,遵循如下示意图:

    pgstru

    首先要存储的大数据(比如rbd设备),被打散成一系列小对象,每个对象会计算出它对应的PG号。取决于replication size的不同,每个PG会分布到多个OSD上。PG的全称是placement groups,它是一个逻辑存储单位,存在的目的是为了更好的管理和定位数以亿计的存储对象。

    如何根据对象计算出PG号,以及PG号如何分布到具体的OSD上,这个就是CRUSH算法,如下示意图:

    crushmap

    首先,根据对象名和pool里配置的PG数量(这些都已知),运用哈希函数计算出PG号。接下来根据PG号、集群状态、存储规则,运行CRUSH算法,找出具体负责存储的首要和次要OSD。最后客户端从这些OSD上对存储对象进行数据读和写。

    安装ceph的文档里,也提到了如何查看、编辑和更新crushmap。crushmap与ceph的存储架构有关,在实际中可能需要经常调整它。如下先把它dump出来,再反编译成明文进行查看。

    1
    2
    3
    $ ceph osd getcrushmap -o crushmap.original
    got crush map from osdmap epoch 56
    $ crushtool -d crushmap.original -o crushmap

    然后查看这个文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    ceph@ceph:~$ cat crushmap
    # begin crush map
    tunable choose_local_tries 0
    tunable choose_local_fallback_tries 0
    tunable choose_total_tries 50
    tunable chooseleaf_descend_once 1
    tunable straw_calc_version 1
     
    # devices
    device 0 osd.0
    device 1 osd.1
    device 2 osd.2
     
    # types
    type 0 osd
    type 1 host
    type 2 chassis
    type 3 rack
    type 4 row
    type 5 pdu
    type 6 pod
    type 7 room
    type 8 datacenter
    type 9 region
    type 10 root
     
    # buckets
    host ceph2 {
    id -2 # do not change unnecessarily
    # weight 0.240
    alg straw
    hash 0 # rjenkins1
    item osd.0 weight 0.080
    item osd.1 weight 0.080
    item osd.2 weight 0.080
    }
    root default {
    id -1 # do not change unnecessarily
    # weight 0.240
    alg straw
    hash 0 # rjenkins1
    item ceph2 weight 0.240
    }
     
    # rules
    rule replicated_ruleset {
    ruleset 0
    type replicated
    min_size 1
    max_size 10
    step take default
    step chooseleaf firstn 0 type osd
    step emit
    }
     
    # end crush map

    这个文件包括几节,大概说明下:

    • crushmap设备:见上述文件#device后面的内容。这里列举ceph的OSD列表。不管新增还是删除OSD,这个列表会自动更新。通常你无需更改此处,ceph会自动维护。
    • crushmap bucket类型:见上述文件#types后面的内容。定义bucket的类型,包括root、datacenter、room、row、rack、host、osd等。默认的bucket类型对大部分ceph集群来说够用了,不过你也可以增加自己的类型。
    • crushmap bucket定义:见上述文件#buckets后面的内容。这里定义bucket的层次性架构,也可以定义bucket所使用的算法类型。
    • crushmap规则:见上述文件#rules后面的内容。它定义pool里存储的数据应该选择哪个相应的bucket。对较大的集群来说,有多个pool,每个pool有它自己的选择规则。

    crushmap的bucket是按层次性分布的,见如下示意图:

    crushlevel

    crushmap应用的实际场景,举个例子,我们可以定义一个pool名字为SSD,它使用SSD磁盘来提高性能。再定义一个pool名字为SATA,它使用SATA磁盘来获取更好的经济性。不过我手头并没有这样的测试环境,如下配置并非针对我的测试环境进行。假设有3个ceph存储node,每个node上都有独立的osd服务。

    首先在crushmap文件里增加如下节:

    crushssd

    上述增加2个root bucket,注意id不要冲突。item后面是ceph的node列表,我们假设node1运行SSD硬盘,node2、node3运行SATA硬盘。

    再增加2条规则:

    crushrule

    • ruleset 3这个规则里,step take sata表示优先选择sata的bucket
    • ruleset 4这个规则里,step take ssd表示优先选择ssd的bucket

    修改完后,重新编译crushmap并且加载到集群中使之生效。

    1
    2
    3
    $ crushtool -c crushmap -o crushmap.new
    $ ceph osd setcrushmap -i crushmap.new
    set crush map

    接下来观察ceph -s是否健康状态OK。如果健康OK,增加2个pool:

    1
    2
    3
    $ ceph osd pool create sata 64 64
     
    $ ceph osd pool create ssd 64 64

    给上述2个新创建的pool分配crush规则:

    1
    2
    3
    $ ceph osd pool set sata crush_ruleset 3
     
    $ ceph osd pool set ssd crush_ruleset 4

    查看规则是否生效:

    1
    $ ceph osd dump |egrep -i "ssd|sata"

    现在写往sata pool的目标,将优先存储到SATA设备上。写往ssd pool的目标,将优先存储到SSD设备上。可以用rados命令进行测试:

    1
    2
    3
    $ rados -p ssd put filename file.ssd
     
    $ rados -p sata put filename file.sata

    最后使用ceph osd map命令检查它们的存储位置:

    1
    2
    3
    $ ceph osd map ssd file.ssd
     
    $ ceph osd map sata file.sata

    本文转自:http://blog.dnsbed.com/archives/1714

  • 相关阅读:
    【整数划分系列】
    【51nod-1183】编辑距离
    【河南第十届省赛-D】年终奖金
    【河南第十届省赛-B】情报传递
    【河南省第十届ACM 省赛 A-谍报分析】
    Node.js函数介绍(参数为一个函数)
    Webstorm设置Node.js智能提示
    TortoiseSVN服务器ip地址修改后如何使用
    vue项目组件的全局注册
    ES6 类(Class)基本用法和静态属性+方法详解
  • 原文地址:https://www.cnblogs.com/netmouser/p/6878969.html
Copyright © 2011-2022 走看看