• ceph工作原理


    一、概述

    Ceph是一个分布式存储系统,诞生于2004年,最早致力于开发下一代高性能分布式文件系统的项目。随着云计算的发展,ceph乘上了OpenStack的春风,进而成为了开源社区受关注较高的项目之一。

    1.CRUSH算法

    Crush算法是ceph的两大创新之一,简单来说,ceph摒弃了传统的集中式存储元数据寻址的方案,转而使用CRUSH算法完成数据的寻址操作。CRUSH在一致性哈希基础上很好的考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。Crush算法有相当强大的扩展性,理论上支持数千个存储节点。

    2.高可用

    Ceph中的数据副本数量可以由管理员自行定义,并可以通过CRUSH算法指定副本的物理存储位置以分割故障域,支持数据强一致性;ceph可以忍受多种故障场景并自动尝试并行修复。

    3.搞扩展性

    Ceph不同于swift,客户端所有的读写操作都要经过代理节点。一旦集群并发量增大时,代理节点很容易成为瓶颈。Ceph本身并没有主控节点。扩展起来比较容易,并且理论上,它的性能会随着磁盘数量的增大而线性增长。

    4.特性丰富

    Ceph支持三种调用接口: 对象存储块存储文件系统挂载。 三种方式可以一同使用。在国内一些公司的云环境中,通常会采集用ceph作为OpenStack的唯一后端存储来提升数据转发效率。

    二、CEPH的基本结构

    Ceph的基本结构组成如下图:

     Ceph的底层是RADOS、RADOS本身也是分布式存储系统,CEPH所有的存储功能都是基于RADOS实现。RADOS采用C++开发。所提供的原生Librados API包括和C++两种。Ceph的上层应用调用本机上的librados API,再由后者通过socket与RADOS集群中的其它节点通信并完成各种操作。

    RADOS GateWay、RBD其作用是在librados库的基础上提供抽象层次更高、更便于应用或客户端使用的上层接口。其中,RADOS GW是一个提供与Amazon S3和Swift兼容的RESTful API的gateway,以供相应的对象存储应用开发使用。RBD则提供了一个标准的块设备接口,常用于虚拟化的场景下为虚拟机创建volume。目前,Red Hat已经将RDB驱动集成在KVM/QEMU中,以提高虚拟机访问性能。这两种方式目前在云计算中应用的比较多。

    CEPHFS则提供了POSIX接口,用户可直接通过客户端挂载使用。它是内核态的程序,所以无需调用用户控件的librados库。它通过内核中的net模块于Rados进行交互。

    三、Ceph的基本组件

     上图所示,Ceph主要三个基本进程

      .Osd

      用于集群中所有数据与对象的存储。处理集群数据的复制、恢复、回填、再平衡。并想其他osd守护进程发送心跳,然后想Mon提供一些空间信息。

      当Ceph存储集群设定数据有两个副本时(一共存两份),则至少需要两个OSD守护进程即两个OSD节点,集群才能达到active+clean状态。

      .MDS(可选)

      为ceph文件系统提供元数据计算、缓存与同步。在ceph中,元数据也是存储在osd节点中,mds类似于元数据的代理缓存服务器。MDS进程并不是必须的进程,只有需要使用CEPHFS时,才需要配置MDS节点。

      .Monitor

      监控整个集群的状态,维护集群的cluster MAP二进制表,保证集群数据的一致性。ClusterMAP描述了对象块存储的物理位置,以及一个将设备聚合到物理位置的桶列表。

    四、OSD

    ceph数据的存储过程,如下图:

     无论使用哪种存储方式(对象、块、挂载),存储的数据都会被切分成对象(Obiects)。Objects size大小可以由管理员调整,通常为2M或者4M。每个对象都会有一个唯一的OlD,由ino于ono生成,虽然这些名词看上去很复杂,其实相当简单。ino即是文件的File ID,用于在全局唯一标示每一个文件,而ono则是分片的编号。比如:一个文件FileID 为A,它被切成了两个对象,一个对象编号0,另一个编号1,那么这两个文件的oid则为A0于A1。Oid的好处是可以唯一标示每个不同的对象,并且存储了对象与文件的从属关系。由于ceph的所有数据都虚拟成了整齐划一的对象,所以在读写时效率都会比较高。

    但是对象并不会直接存储进OSD中,因为对象的size很小,在一个大规模的集群中可能有几百到几千万个对象。这么多对象光是遍历寻址,速度都是缓慢的;并且如果将对象直接通过某种固定映射的哈希算法映射到osd损坏时,对象无法自动迁移至其他的、osd上面(因为映射函数不允许)。为了解决这些问题,ceph引入归置组的概念,即PG。

    PG是一个逻辑概念,我们Linux系统中可以直接看到对象,但是无法直接看到PG 。它在数据寻址时类似于数据库中的索引:每个对象都会固定映射进一个PG中,所以当我们要寻找一个对象时,只需要先找到对象所属的PG,然后遍历这个PG就可以了,无需遍历所有对象。而且在数据迁移时,也是以PG作为基本单位进行迁移,ceph不会直接操作对象。

    对象时如何映射进PG的?还记得OID么?首先使用静态hash函数对OID做hash取出征码,用特征码于PG的数量去模,得到的序列号则是PGID。 由于这种设计方式,PG的数量多寡直接决定了数据分布的均匀性,所以合理设置的PG数量可以很好的提升CEPH集群的性能并使用数据均匀分布。

    最后PG会根据管理员设置的副本数量进行复制,然后通过crush算法存储到不同的OSD节点上(其实是把PG中所有对象存储到节点上),第一个osd节点即为主节点,其余均为从节点。

    下面一段ceph的伪代码,简要描述了ceph的数据存储流程

    locator = object_name
    obj_hash =  hash(locator)
    pg = obj_hash % num_pg
    osds_for_pg = crush(pg)    # returns a list of osds
    primary = osds_for_pg[0]
    replicas = osds_for_pg[1:]

     上图中更好的诠释了ceph数据流的存储过程,数据无论是从三中接口哪一种写入的,最终都要切分成对象到底层的RADOS中。逻辑上通过算法先映射到PG上,最终存储近OSD节点里。图中除了之前介绍的概念之外多了一个pools的概念。

     Pool是管理员自定义的命名空间,像其他的命名空间一样,用来隔离对象与PG。我们在调用API存储即使用对象存储时,需要指定对象存储进哪一个POOL中。除了隔离数据,我们也可以分别对不同的POOL设置不同的优化策略,比如副本数、数据清洗次数、数据块及对象大小等。

    OSD是强一致性的分布式存储,它的读写流程图如下:

    Ceph的读写操作采用了主从模型,客户端要读写数据时,只能向对象所对应的主osd节点发起请求。主节点在接受到写请求时,会同步的向从OSD中写入数据。当所有的OSD节点都写入完成后,主节点才会向客户端报告写入完成的信息。 因此保证了主从节点数据的高度一致性。而读取的时候,客户端也只会向主osd节点发起读请求,并不会有类似于数据库中的读写分离的情况出现,这也是出于强一致性的考虑。由于所有写操作都要交给主osd节点来处理,所以在数据量很大时,性能可能会比较慢,为了克服这个问题以及让ceph能支持事务,每个osd节点都包含了一个journal文件

    osd进程: 在ceph中,每一个osd进程都可称作是一个osd节点,也就是说,每台存储服务器上可能包含了众多的osd节点,每个osd节点监听不同的端口,类似于在同一台服务器上跑多个mysql或者Redis。每个osd节点可以设置一个目录作为实际存储区域,也可以是一个分区,一整块硬盘。 如下图,当前这台机器上跑了两个osd进程,每个osd监听4个端口,分别用于接收客户请求、传输数据、发送心跳、同步数据等操作。

    上图所示:osd节点默认监听tcp的6800到6803端口,如果同一台服务器上有多个osd节点,则依次往后排序。

    在生产环境中的osd最少可能都有上百个,所以每个osd都有一个全局的编号,类似osd0,osd1,osd2…… 序号根据osd诞生的顺序排列,并且是全局唯一的。存储了相同PG的osd节点除了向mon节点发送心跳外,还会互相发送心跳信息已检测pg数据副本是否正常。

    前面介绍数据流时说过,每个osd节点都包含一个journal文件

     

       默认大小为5G,也就是说每创建一个osd节点,还没有使用就要被journal占走5G的空间。这个值是可以调整的,具体大小要依osd的总大小而定。

    journal的作用类似于mysql innodb引擎中的事务日志系统。当有突发的大量写入操作时,ceph可以先把一些零散的,随机的IO请求保存到缓存中进行合并,然后在统一内核发起IO请求。这样做效率会比较高,但是一旦osd节点崩溃,缓存中的数据就会丢失,所以数据在还未写进硬盘中,都会记录到journal文件中,当osd崩溃后重新启动时,会自动尝试从journal恢复因崩溃丢失的缓存数据。 因此journal的io是非常密集的,而且由于一个数据要io两次,很大程度上也损耗了硬件的io性能,所以通常在生产环境中,使用osd来单独存储journal文件以提高ceph读写性能。

    五、monitor节点

    Mon节点监控着整个ceph集群的状态信息,监听于tcp的6789端口。每一个ceph集群中至少要有一个Mon节点,官方推荐每个集群至少部署三台。 Mon节点中保存了最新的版本集群数据分布图(cluster map)的副本。客户端在使用时,需要挂载Mon节点的6789端口,下载最新的cluster map,通过crush算法获得集群中各osd的IP地址,然后再与osd节点直接建立连接来传输数据。 所以对于ceph来说,并不需要有集群式的主节点用于计算与寻址,客户端分摊了这部分工作。而且客户端也可以直接和osd通信,省去了中间代理服务器的额外开销。

    Mon节点之间使用Paxos算法来保持各节点cluster map的一致性; 各Mon节点的功能总体上是一样的,相互间的关系可以被简单理解为主备关系。如果住Mon节点损坏,其他Mon存活节点超过半数时,集群还可以正常运行。当故障Mon节点恢复时,会主动想其他Mon节点拉取最新的cluster map。

    Mon节点并不会主动轮询各个osd的当前状态,相反,osd只有在一些特殊情况下才会上报自己的信息,平常只会简单的发送心跳。

    特殊情况包括:1、新的OSD被加入集群; 2、某个OSD发现自身或其他OSD发生异常。Mon节点在收到这些上报信息时,则会更新cluster map信息并加以扩散。

    推荐使用以上架构:

    这里的ceph除了管理网段外,设了两个网段,一个用于客户端读写传输数据。另一个用于各OSD节点之间同步数据和发送心跳信息等。这样做的好处是可以分担网卡的IO压力。否则在数据清洗时,客户端的读写速度会变得极为缓慢。

    六、MDS

    Mds是ceph集群中的元数据服务器,而通常它不是必须的,因为只有在使用ceph的时候才需要它,而且在云计算中用的更广泛的是另外两只存储方式。

    Mds虽然是元数据服务器,但是它不负责存储元数据,元数据也是被切成飞翔在各个osd节点中的:如下图

     在创建CEPHFS时,要至少创建两个POOL,一个用于存放数据,另一个用于存放元数据。Mds只是负责接受用户的元数据查询请求,然后从osd中把数据取出映射进自己的内存中供客户访问。所以mds其实类似一个代理缓存服务器,提osd分担了用户的访问压力,如下图:

  • 相关阅读:
    Go语言的性能测试对比
    学习笔记
    使用TCPDump分析Redis的Pipeline比Multi更快的原因
    基于Redis/Memcached的高并发秒杀设计
    这些 .Net and Core 相关的开源项目,你都知道吗?(持续更新中...)
    《.Net 的冰与火之歌》寄雁传书,你必须知道的C#参数知识大盘点
    分享自己的超轻量级高性能ORM数据访问框架Deft
    Expression2Sql的一些语法更新
    介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql
    记一次随机字符串生成算法的随机概率与性能的提升
  • 原文地址:https://www.cnblogs.com/fengyuanfei/p/13892254.html
Copyright © 2020-2023  润新知