ceph是分布式集群:
1>软件定义存储(sds)
sds是减少存储基础设施的tcd(总体成本)所需要的。除了降低成本外,sds还提供灵活性,可伸缩性和可靠性,ceph是一种真正的sds,它可以运行在没有厂商锁定的普通硬件上,与传统的存储系统(软硬件结合不同),在sds中,你可以从任何制造商中自由选择硬件,也可以根据自己的需要自由的设计异构硬件解决方案,ceph在此硬件上的软件定义存储提供了你需要的所有,并将负责所有事情,从软件层提供所有的企业存储特性。
2>云存储
ceph已经和openstack结合起来,成为openstack后端存储的标配,同时又支持所有kubernets动态存储。
3>统一存储体系架构
统一存储指单个系统提供文件和块存储。真正的存储就像ceph,支持单个系统的块,文件和对象存储。ceph的核心思想是提供分布式存储,该系统具有大规模的可伸缩性和高性能性,并且没有单点故障,从根本上说,它被设计成硬件上运行具有高度的可伸缩性(可达eb)级别甚至更高。
4>分布式的核心掌握
基本上把握存储的IO流程架构,
包含:HDD(机械盘)、SSD、RAID 、DAS、NAS、SAN、CIFS、NFS、对象存储、容灾备份 。
掌握分布式存储的核心:分布式琐、分布式事务、一致性、选举机制、数据分布机制。
DAS(Direct-attached Storage):服务器本地存储;开发机的直连模式。
SAN(Storage Area Network):基于块的存储;服务器主机通过光纤交换机连接存储阵列,建立专用于数据存储的区域网络;SAN使用高端RAID阵列;SAN协议主要分为FCSAN(利用光纤协议转发SCSI协议)和IPSAN(利用tcp/ip协议转发SCSI协议);SAN主要用于存储量大的地方,但是成本高,扩展性较差,标准尚未确定。
NAS(Network Attached Storage) : 网络存储器,它以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者, 有点类似于文件共享。
ceph:带宽使用万M和十万M,使用tcp/ip协议,适用于云环境。
1.块设备的解释
物理层对外提供服务,使用它的系统,有用自己的文件系统格式化。这样一旦被一个系统使用,就独占了。块存储,主要操作对象是磁盘。常用的块存储协议有:FC(光纤),iSCSI(tcp/ip)。和文件存储相比,没有文件和目录树的概念,一般协议也不会定义磁盘的创建和删除操作。协议更注重传输控制。DAS和SAN都是块存储系统。
2.块存储的特点:
1.通过ceph clients使用块设备。
2.精简配置: thin provisioning: 建立1个G的空间,不会立即分配1G,只会分配到能够使用的空间。
3.动态扩容: dynamically resizeable: 支持块设备的放大和缩小。
4.快照,克隆: snapshots,clone: 快照是可读,克隆是可读可写。
5.写时拷贝(copy-on-write):写时拷贝是两个对象共用一片内存地址,当一个对象进行改变的时候,才会开辟空间对另外一个的对象进行保存。
6.caching:缓存。
7.rbd驱动以及集成到Linux内核中。
8.支持计算模块kvm,qemu(模拟器),libvirt。
9.支持虚拟机和物理服务器。
10.支持format-1 和 format-2类型:默认指定format-1, format-2支持写时拷贝。
3.扩展知识点
典型设备:磁盘阵列,硬盘,虚拟硬盘
块设备的接口通常以QEMU_Driver或者Kernel Module的方式存在,这种接口需要实现Linux的Block Device的接口或者QEMU提供的Block Driver接口,如Sheepdog,AWS的EBS,青云的云硬盘和阿里云的盘古系统,还有Ceph的RBD(RBD是Ceph面向块存储的接口)
块存储主要是将裸磁盘空间整个映射给主机使用的,就是说例如磁盘阵列里面有5块硬盘(为方便说明,假设每个硬盘1G),然后可以通过划逻辑盘、做Raid、或者LVM(逻辑卷)等种种方式逻辑划分出N个逻辑的硬盘。(假设划分完的逻辑盘也是5个,每个也是1G,但是这5个1G的逻辑盘已经于原来的5个物理硬盘意义完全不同了。例如第一个逻辑硬盘A里面,可能第一个200M是来自物理硬盘1,第二个200M是来自物理硬盘2,所以逻辑硬盘A是由多个物理硬盘逻辑虚构出来的硬盘。)
接着块存储会采用映射的方式将这几个逻辑盘映射给主机,主机上面的操作系统会识别到有5块硬盘,但是操作系统是区分不出到底是逻辑还是物理的,它一概就认为只是5块裸的物理硬盘而已,跟直接拿一块物理硬盘挂载到操作系统没有区别的,至少操作系统感知上没有区别。
此种方式下,操作系统还需要对挂载的裸硬盘进行分区、格式化后,才能使用,与平常主机内置硬盘的方式完全无异。
优点:
1、 这种方式的好处当然是因为通过了Raid与LVM等手段,对数据提供了保护。
2、 另外也可以将多块廉价的硬盘组合起来,成为一个大容量的逻辑盘对外提供服务,提高了容量。
3、 写入数据的时候,由于是多块磁盘组合出来的逻辑盘,所以几块磁盘可以并行写入的,提升了读写效率。
4、 很多时候块存储采用SAN架构组网,传输速率以及封装协议的原因,使得传输速度与读写速率得到提升。
缺点:
1、采用SAN架构组网时,需要额外为主机购买光纤通道卡,还要买光纤交换机,造价成本高。
2、主机之间的数据无法共享,在服务器不做集群的情况下,块存储裸盘映射给主机,再格式化使用后,对于主机来说相当于本地盘,那么主机A的本地盘根本不能给主机B去使用,无法共享数据。
3、不利于不同操作系统主机间的数据共享:另外一个原因是因为操作系统使用不同的文件系统,格式化完之后,不同文件系统间的数据是共享不了的。例如一台装了WIN7/XP,文件系统是FAT32/NTFS,而Linux是EXT4,EXT4是无法识别NTFS的文件系统的。就像一只NTFS格式的U盘,插进Linux的笔记本,根本无法识别出来。所以不利于文件共享。
1.文件存储的解释
为了解决块设备无法共享的问题,ceph提高文件存储, 也就是在文件系统一层对外提供服务,系统只用访问文件系统一级就可以,各个系统都可以根据接口去访问,主要操作对象是文件和文件夹。支持posix接口,支持cifs,nfs,ftp协议。协议更注重接口的灵活,以及访问权限控制。NAS就是文件存储。(类似于共享文件夹一样)+
2.文件系统的详细解释
典型设备:FTP服务器、NFS服务器,Samba服务器
通常意义是支持POSIX接口,它跟传统的文件系统如Ext4是一个类型的,但区别在于分布式存储提供了并行化的能力,如Ceph的CephFS(CephFS是Ceph面向文件存储的接口),但是有时候又会把GFS,HDFS这种非POSIX接口的类文件存储接口归入此类。为了克服上述文件无法共享的问题,所以有了文件存储。
文件存储也有软硬一体化的设备,但是其实普通拿一台服务器/笔记本,只要装上合适的操作系统与软件,就可以架设FTP与NFS服务了,架上该类服务之后的服务器,就是文件存储的一种了。
主机A可以直接对文件存储进行文件的上传下载,与块存储不同,主机A是不需要再对文件存储进行格式化的,因为文件管理功能已经由文件存储自己搞定了。
优点:
1、造价较低:随便一台机器就可以了,另外普通以太网就可以,根本不需要专用的SAN网络,所以造价低。
2、方便文件共享:例如主机A(WIN7,NTFS文件系统),主机B(Linux,EXT4文件系统),想互拷一部电影,但是不行,加了个主机C(NFS服务器),然后可以先A拷到C,再C拷到B就OK了。(例子比较肤浅,请见谅……)
缺点:
1、读写速率低,传输速率慢:以太网,上传下载速度较慢,另外所有读写都要1台服务器里面的硬盘来承担,相比起磁盘阵列动不动就几十上百块硬盘同时读写,速率慢了许多。
2、企业级的NAS存储采用RAID技术提升了数据的可靠性和读写速率,同时采用万兆光纤接口提升了网络传输速率,适合于中小规模的医院用于PACS系统非结构化数据的存取,当数据量达到PB级别时NAS会出现瓶颈。
1.对象存储的解释
为了解决块存储的无法共享和文件存储读写慢的问题,ceph提供对象存储。
2.特点
1.对象存储, 不能直接当成文件系统使用
2.只能通过api访问(或者第三方命令使用restful s3 和 restful swift-compatiable api interfaces)
3.详细的对象存储解释
对象存储的出现就是为解决了存储海量大数据的问题。比如存储万亿的视频、图片,照片等。比如进行海量的数据归档,数据备份等。对象存储可以存储海量非结构化数据,然后进行大数据分析。
对象存储其采用key-volume的扁平化存储架构设计,使用简单,调用API就能进行数据存储和读取。可以存储海量数据,这点传统存储和NAS就没辙。在海量数据场景中你只能选择对象存储。如果传统SAN存储是跑车,NAS是货车,那么对象存储就是万亿吨海上集装箱大油轮。
典型设备:内置大容量硬盘的分布式服务器,总体上来讲,对象存储同兼具SAN高速直接访问磁盘特点及NAS的分布式共享特点。核心是将数据通路(数据读或写)和控制通路(元数据)分离,并且基于对象存储设备(Object-based Storage Device,OSD)构建存储系统,每个对象存储设备具有一定的智能,能够自动管理其上的数据分布。
monitors(MON):ceph监视器通过保存集群状态的映射来跟踪整个集群的监控状况,一般监控数为奇数,方便仲裁, 防止脑裂;一个Ceph集群需要多个Monitor组成的小集群,它们通过Paxos同步数据,用来保存OSD的元数据。mon之间的关系:一个多Monitor的Ceph的架构通过法定人数来选择leader, 并在提供一致分布式决策时使用Paxos算法集群, mons必须保证百分之51的mon是可被访问的,当出现多monitors时,使用paxos算法来选择leader,避免单点故障。
落盘数据格式: rocksdb
auth认证
流程讲解:
①客户端携带 /etc/ceph/ceph.client.admin.keyring 的 key 信息向 MON 节点请求认证,申请session key
②MON 节点生成 session key,并通过客户端提供的 key 加密 session key 发送给客户端
③客户端用 key 来解密获取 session key
④利用session key向MON节点申请tiket,MON 节点验证session key是否准确性,并且发放tiket。
⑤使用tiket访问OSD
⑥OSD验证tiket有效性,并发送数据
ceph创建认证命令:
ceph auth ls
ceph auth get-or-create client.zc mon “allow *” osd “allow rwx”
ceph auth get client.zc -o /root/ceph.client.zc.keyring
ceph auth del client.zc
管理和维护cluster map
- Monitor Map。 Monitor Map包括有关monitor节点端到端的信息, 其中包括Ceph集群ID,监控主机名和IP地址和端口号, 它还存储了当前版本信息以及最新更改信息, 可以通过以下命令查看monitor map。
# ceph mon dump
# ceph mon stat
- OSD Map。 OSD Map包括一些常用的信息, 如集群ID, 创建OSD Map的版本信息和最后修改信息, 以及pool相关信息, pool的名字、 pool的ID、 类型, 副本数目以及PGP, 还包括OSD信息, 如数量、 状态、 权重、 最新的清洁间隔和OSD主机信息。 可以通过执行以下命令查看集群的OSD Map。
# ceph osd dump
- PG Map。 PG Map包括当前PG版本、 时间戳、 最新的OSD Map的版本信息、 空间使用比例, 以及接近占满比例信息, 同时, 也包括每个PG ID、 对象数目、 状态、 OSD的状态以及深度清理的详细信息, 可以通过以下命令来查看PG Map。
# ceph pg dump
- CRUSH Map。 CRUSH Map包括集群存储设备信息, 故障域层次结构和存储数据时定义失败域规则信息; 可以通过以下命令查看CRUSH Map。
# ceph osd crush dump
- MDS Map。 MDS Map包括存储当前MDS Map的版本信息、 创建当前Map的信息、 修改时间、 数据和元数据POOL ID、 集群MDS数目和MDS状态, 可通过以下命令查看集群MDS Map信息。
详细的扩展文档:
https://catkang.github.io/2017/11/21/ceph-paxos.html
ceph对象存储设备(OSD:object storage device): 负责响应客户端请求返回具体数据的进程
监控OSD共有四种状态(up/down代表状态,in/out代表是否在集群)
up且in: 说明该OSD正常运行,且已经承载至少一个PG的数据。正常状态;
Up且out: 说明该OSD正常运行,但并未承载任何PG。
Down且in: 说明该OSD发生异常,但仍然承载着至少一个PG,其中仍然存储着数据。异常状态
Down且out:说明该OSD已经彻底发生故障,且已经不再承载任何PG。
1.数据存储:一旦应用程序向ceph集群发出写操作,数据就以对象的形式存储在osd中,这是ceph集群中存储用户数据的唯一组件;一个osd守护进程绑定到集群中的一个物理磁盘或者分区。
2.Undersized/degarded: 降级,当某个osd被down掉,会出现降级状态,当时不影响客户端数据的读写,只要当前副本数大于最小副本数量就可以正常读写。
3.Recovery:当down掉的osd重新恢复回来,可以根据Pg日志重新算出不一致对象的列表来修复副本上的数据,此时就是Recovery.
4.backfilling:当某个OSD长时间损坏后重新将新的OSD加入集群,它已经无法根据PG日志来修复,这个时候则需要执行回填过程,Backfill过程是通过逐一对比两个PG的对象列表来修复。当新的OSD加入集群产生的数据迁移,也是通过Backfill过程来完成数据一致。
5.重平衡:当在集群中新增一个OSD设备时,整个集群将会发生数据迁移使数据重新分布达到均衡。在Ceph集群中数据迁移的的基本单位是PG。其实在迁移过程中是将PG中的所有对象作为一个整体来进行迁移。当在Ceph存储集群中添加新的OSD时,CURSH会重新计算PG_ID,相应的集群映射表也会更新,基于重新计算的结果,对象数据的存放位置也会发生变化。重平衡也是通过数据回填进行数据恢复的。
6.心跳: osd需要和与其共同承载同一个pg的其他osd交换信息。已确定各自是否正常工作,是否需要进行维护操作。
7.数据迁移的流程:
1、当新加入一个OSD时,会改变系统的CRUSH Map,从而引起对象映射过程中的变化;
2、PG到OSD的crush rule映射关系发生了变化,从而引发数据的迁移。
8.osd故障流程:当ceph集群中出现组件故障时(通常是指OSD,当然也有可能是网络),ceph会将OSD标记为Down,如果在300秒内MON没有收到回复,集群就会进入恢复状态。这个等待时间可以修改ceph配置文件中"mon_osd_down_out_interval=xxx"项来调整等待时间。
可以通过ceph daemon osd.4 config show |grep "mon_osd_down_out_interval"
PG全称Placement Groups,是一个逻辑的概念,一个PG包含多个OSD。引入PG这一层其实是为了更好的分配数据和定位数据。pg是数据分布和复制的单位。
第一个作用是划分数据分区,每个PG管理的数据区间相同,因而数据能够均匀地分布到PG上;
第二个作用是充当Dyanmo中Token的角色,即决定分区位置,实际上,这和Dynamo中固定分区数目,以及维持分区数目和虚拟节点数目相等的原则是同一回事。在没有多副本的情况下,Dynamo中分区的数据直接存储到Token,而每个Token对应唯一的一个物理存储节点。
详细补充:在多副本(假设副本数目为N)的情况下,分区的数据会存储到连续的N个Token中。但这会引入一个新问题:因为副本必须保持在不同的物理节点,但是如果这组Token中存在两个或多个Token对应到同个物理存储节点,那么就必须要跳过这样的节点。Dynamo采用Preference列表来记录每个分区对应的物理节点。然而,Dynmao论文中没有详述分区的Preference列表如何选取物理节点,以及选取物理节点时该如何隔离故障域等问题。
(osd0,osd1,osd2..osdn)=CRUSH(x)
Ceph的PG担当起Dynamo中Token、固定分区以及Preference列表的角色,解决的是同样的问题。PG的Acting集合对应于Dynamo的Preference列表。
官方给出的计算公式是这样的:
Total PGs = (Total_number_of_OSD * 100) / max_replication_count
但每个池中pg数量最好接近或等于2的次方
例:
有100个osd,2副本,5个pool
总的pg数量:Total PGs =100*100/2=5000
每个pool的PG:Per Pools=5000/5=1000 创建pool的时候就指定pg为1024
ceph osd pool create pool_name 1024
(1)Active:当前拥有最新状态数据的pg正在工作中,能正常处理来自客户端的读写请求。
(2)inactive:正在等待具有最新数据的OSD出现,即当前具有最新数据的pg不在工作中,不能正常处理来自客户端的读写请求。
(3)Clean:PG所包含的object达到指定的副本数量,即object副本数量正常。
(4)Unclean:PG所包含的object没有达到指定的副本数量,比如一个PG没在工作,另一个PG在工作,object没有复制到另外一个PG中。
(5)Degraded:主osd没有收到副osd的写完成应答,比如某个osd处于down状态。
(6)Undersized:pg的副本数少于pg所在池所指定的副本数量,一般是由于osd down的缘故。
(7)down:包含必备数据的副本挂了,pg此时处理离线状态,不能正常处理来自客户端的读写请求。
(8)Peering:PG所在的OSD对PG中的对象的状态达成一个共识(维持对象一致性)。
(9)Recovering:pg间peering完成后,对pg中不一致的对象执行同步或修复,一般是osd down了或新加入了osd。
(10)Backfilling:一般是当新的osd加入或移除掉了某个osd后,pg进行迁移或进行全量同步。
(11)Stale:主osd未在规定时间内向mon报告其pg状态,或者其它osd向mon报告该主osd无法通信。
(12)Scrubbing(deep + Scrubbing):pg对对象的一致性进行扫描。
(13)Inconsistent:PG中存在某些对象的各个副本的数据不一致,原因可能是数据被修改。
(14)Repair:pg在scrub过程中发现某些对象不一致,尝试自动修复。
1.硬盘坏了的osd:
ceph osd reweight 2 0.0
systemctl stop ceph-osd@3
ceph osd out 2
ceph osd crush remove osd.2
ceph auth del osd.2
ceph osd rm osd.2
2.报Unfound objects
ceph集群知道该对象存在,但无法定位该object在哪时会报这个错误。
解决办法:
<1>尝试让失败的osd起来,如果起来后集群恢复正常,则结束
<2>尝试将该pg的unfound对象回滚到上一个版本,ceph pg $pgid(1.3f) mark_unfound_lost revert,如果恢复正常,则结束。
<3>如果还是不行,那只有将该object删除掉了,注意这会导致丢失数据,ceph pg $pgid (1.3f) mark_unfound_lost delete
3.报inconsistent objects
pg中保存的object中有些副本数据不一致,有些事伴随着scrub errors错误
<1>ceph health detail 找出问题pg
<2>尝试ceph pg repair $pgid,若成功,则结束(这个执行修复后一般要等久点,实在不能自动repair,再用以下方式)
<3>通过ceph pg map $pgid,找出主osd,打开其日志查看是哪个object不一致.
<4>找出所有该objects所有副本存放的位置,用摘要算法(md5sum,sha256)等计算出其hash值,如果是3副本,删除与其他副本不一致的;如果是2副本,则可能会误删。
<5> 再次执行 ceph pg repair $pgid
4.出现stale pg
pg出现stale状态,也就是pg处于僵死状态,该状态是无法处理新的请求了的,新的请求过来只会block,这种情况一般是由于所有副本pg的osd都挂了,要模拟其实也很简单,比如设置2副本,然后将2个不同故障域的osd挂掉即可出现,最好的恢复方法当然是重新拉起这两个osd,但有时可能出现这样的情况,两个osd永远也拉不起来了,然后你把这两个osd清理出去了,清理完后这些pg当然就是stale的状态,这时的恢复方法只能是丢掉这个pg里的数据了,重新创建pg:
<1>使用命令ceph pg dump |grep stale 找出所有的stale的pg,也可以ceph health detail |grep stale
<2>执行ceph pg force_create_pg $pg_id命令强制重新创建pg,这时可以看到pg会转为creating状态
<3>重启ceph集群中的所有OSD
Ceph最底层的存储单元是Object对象,每个Object包含元数据(描述数据的数据)和原始数据。每个object都有全局唯一的id,不同于文件存储,object的大小可以突破文件级的限制,并且还有丰富的元数据;整个object索引是一个扁平结构里面实现的。
存储对象的逻辑分区;可以设置所有权和访问对象,设置对象副本的数目以及pg的数目
pool是逻辑单位,包含多个pg。
# 创建pool池,指定副本/纠删码
ceph osd pool create pg(pool_name) 128 128
ceph osd pool create {poolname} {pg-num} [{pgp-num}] [replicated] \ [crush-ruleset-name] [expected-num-objects]
ceph osd pool create {poolname} {pg-num} {pgp-num} erasure \ [erasure-code-profile] [crush-ruleset-name] [expected_num_o
# 设置配额
ceph osd pool set-quota {poolname} [max_objects {obj-count}]
# 删除存储池
ceph osd pool delete {poolname} [{poolname} --yes-i-really-really
# 重命名
ceph osd pool rename {current-pool-name} {new-pool-name}
# 创建快照
ceph osd pool mksnap {poolname} {snap-name}
# 删除快照
ceph osd pool rmsnap {poolname} {snap-name}
# 设置pool副本数
ceph osd pool set pg(pool_name) size 4
# 查看pool 池
ceph osd lspools <===> rados lspools
ceph osd dump|grep -i pool
# 通过存储池查看pg
ceph pg ls-by-pool {poolname}
ceph pg ls poolid
# 通过osd查看pg
ceph pg ls-by-osd {osd.id}
# 给存储池以对象形式写入指定的数据
rados -p pg(poolname) put/get object5 /etc/hosts (把host上传作为object5)
# 删除存储池中的对象
rados -p pg(poolname) rm objects1
# 获取存储池中的列表
rados -p pg(poolname) ls
# 存储池创建快照
rados mksnap snapshot01 -p pg(poolname) 创建快照
rados rollback -p pg(poolname) object1 snapshot01 快照回滚
rados lssnap -p pg(poolname) 显示存储池的快照
rados listsnaps object1 -p pg(poolname) 显示某个对象的快照
示例:
# 创建pool
ceph osd pool create hpc_pool 128 128
# 设置副本数为3
ceph osd pool set hpc_pool size 3
# 上传文件到ceph
rados -p hpc_pool put object1 /tmp/helloceph
# 查看对象
rados -p hpc_pool ls
# 显示对象文件的映射关系
ceph osd map hpc_pool objec1
# osdmap e60 pool 'dd' (1) object 'object1' -> pg 1.bac5debc (1.1c) -> up ([0,2], p0) acting ([0,2], p0)
ceph metadata server(MDS): mds跟踪文件层次结构,仅为ceph fs文件系统存储元数据;MDS全称Ceph Metadata Server,是CephFS服务依赖的元数据服务。
ceph manager:ceph manager守护进程(ceph-mgr)是在kraken版本中引入的,它与monitor守护进程一起运行,为外部监视和管理系统提供额外的监视和接口。
1.ceph的管理结构是RADOS, RADOS全称Reliable Autonomic Distributed Object Store(可靠自治分布式对象存储)
2.功能是: 存储数据,维护数据的一致性和可靠性;RADOS存储负责这些对象,而不管他们的数据类型如何,RADOS层确保数据始终保持一致,为此,它执行数据复制,故障检测和恢复,以及跨集群节点的数据迁移和再平衡,用户可使用它来实现数据分配、Failover(容错机制:实效转移)等集群操作。
Librados是Rados提供库,因为RADOS是协议很难直接访问,因此上层的RBD、RGW和CephFS都是通过librados访问的,目前提供PHP、Ruby、Java、Python、C和C++支持。
CRUSH是Ceph使用的数据分布算法,类似一致性哈希,让数据分配到预期的地方。
RBD全称RADOS block device,是Ceph对外提供的块设备服务。
RGW全称RADOS gateway,是Ceph对外提供的对象存储服务,接口与S3和Swift兼容。
CephFS全称Ceph File System,是Ceph对外提供的文件系统服务。
1.写数据的流程图
2.写数据的流程分析:
1.客户端写的步骤:
1.client 创建cluster handler。
2.client 读取配置文件。
3.client 连接上monitor,获取cluster map信息。
4.client 读写io会根据pool--->pg--->osd--->主osd。
5.向主osd写入数据,然后主osd数据节点同时写入另外两个副本节点数据。
6.等待主节点以及另外两个副本节点写完数据状态。
7.主节点及副本节点写入状态都成功后,返回给client,io写入完成。
2.写的优点:
写主要是给主osd写入,再由主osd同步到各个副本中。可以节省流量和保证副本的强一致性。
3.如何保证副本的强一致性
1.某个client需要向Ceph集群写入file时,将file分割为N个object,之后确定存储该N个object的N组OSDs。假设副本数为3,下面取其中一个object以及其对应的一组OSDs来说明:这一组中3个OSD具有各自不同的序号,第一序号OSD为这一组的Primary OSD,而后两个则依次是Secondary OSD和Tertiary OSD。
2.确定三个OSD之后,client直接与Primary OSD通信,发起写入操作(步骤1)。Primary OSD收到请求后,分别向Secondary OSD和Tertiary OSD发起写入操作(步骤2、3)。当Secondary OSD和Tertiary OSD各自完成写入操作后,将分别向Primary OSD发送确认信息(步骤4、5)。当Primary OSD确信其他两个OSD的写入完成后,则自己也完成数据写入,并向client确认object写入操作完成(步骤6)。
3.采用这样的写入流程,本质上是为了保证写入过程中的可靠性,尽时能避免造成数据丢失。
1.读io的流程图
2.读io的流程分析
1.client端直接与主osd发送读取请求;
2.如果主osd挂了,就会有第二个会接替主primary osd从本地磁盘读取数据,返回给client完成数据的读取过程。
3.如果新加入的OSD1取代了原有的OSD4成为primary osd, 由于osd1上未创建PG, 不存在数据,那么PG上的 I/O 无法进行,怎样工作的呢?
步骤:
1.client连接monitor获取cluster_map信息。
2.同时新主osd1由于没有pg数据会主动上报monitor告知让osd2临时接替为主。临时主osd2会把数据全量同步给新主osd1。
3.client IO读写直接连接临时主osd2进行读写。osd2收到读写io,同时写入另外两副本节点。
4.等待osd2以及另外两副本写入成功。osd2三份数据都写入成功返回给client, 此时client io读写完毕。
5.如果osd1数据同步完毕,临时主osd2会交出主角色。osd1成为主节点,osd2变成副本。
1.流程图:
2.流程分析:
ceph io算法流程:
file--->objects--->pgs---->osds # file:用户需要读写的文件。
第一个流程: File->Object映射:
a. ino (File的元数据,File的唯一id)。
b. ono (File切分产生的某个object的序号,默认以4M切分一个块大小)。
c. oid (object id: ino + ono)。
第二个流程: object->pgs映射:
概括:Object是RADOS需要的对象。Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。
a.mask = PG总数m(m为2的整数幂)-1 。
b. hash(oid) & mask-> pgid 。
第三个流程是pg->osd:
PG(Placement Group),用途是对object的存储进行组织和位置映射,(类似于redis cluster里面的slot的概念),一个PG里面会有很多object,采用CRUSH算法,将pgid代入其中,然后得到一组OSD。该映射功能性特别强,它会受crush_map以及rule的影响,只有在crush_map和存储策略均不发生改变时,pg和osd映射关系才固定。
a. CRUSH(pgid)->(osd1,osd2,osd3) 。
3.ceph伪代码实现流程:
locator = object_name
obj_hash = hash(locator)
pg = obj_hash % num_pg
osds_for_pg = crush(pg) # returns a set of osds
primary = osds_for_pg[0]
replicas = osds_for_pg[1:]
流程:
1.客户端创建一个pool,需要为这个pool指定pg的数量。
2.创建pool/image,并对rbd设备进行挂载。
3.用户写入的数据进行切块,每个块的大小默认为4M,并且每个块都有一个名字,名字就是object+序号。
4.将每个object通过pg进行副本位置的分配。
5.pg根据cursh算法会寻找3个osd,把这个object分别保存在这三个osd上。
6.osd上实际是把底层的disk进行了格式化操作,一般部署工具会将它格式化为xfs文件系统。
7.object的存储就变成了存储一个文rbd0.object1.file。
查看流程的命令:
# 查看存储池中的对象
rados -p pool_name ls # 1.显示的rbd_data.ion.non是ion和non.
# 查看存储池的数据
rados -p pool_name get objname outfile (objname是以rbd_data.ion.non来描述的)
hexdump -c outfile
# 查看存储池的元数据
rados -p pool_name listomapvals rbd_header.122131231
# 查看pg信息 # 3.显示pg_id和osd的对应关系
ceph pg ls
# 查看某个Pg_id的具体信息
ceph pg 1.2f6 query
1.简介
pool是ceph存储数据时的逻辑分区,它起到namespace的作用。每个pool包含一定数量(可配置)的PG。PG里的对象被映射到不同的Object上。pool是分布到整个集群的。pool可以做故障隔离域,根据不同的用户场景不一进行隔离。
1.ceph数据扩容
场景数据迁移流程:
现状3个OSD, 4个PG
扩容到4个OSD, 4个PG
说明
每个OSD上分布很多PG, 并且每个PG会自动散落在不同的OSD上。如果扩容那么相应的PG会进行迁移到新的OSD上,保证PG数量的均衡。
一致性hash算法的引入:
场景:设想你曾几何时存了一部动作片到Ceph集群中。你拿着你的笔记本来到机房,你所看到的Ceph集群是数个机架的服务器。你在想,我的动作片最终是存储在哪里?
你考虑的实际是数据定位的问题。
常见有两种数据定位方法:
记录:将"数据A:位置location(A)"这样的信息记录下来,访问数据时查询记录,获取位置,再进行读取。
计算:存放数据A时,其存储位置location(A)是即时计算得到的。能感觉到这种方式更为便利。
问题是当数据量存储太大,所需要的效率和内存要求也会很大。所以采用计算。
常见的计算方式是一致性哈希(consistent hashing)
基本思路是,面对数据A,以数据A的文件名等类似信息为key,通过一致性哈希计算consist hash(keyA)->location(A)得到存储位置。
ceph使用的是crush算法:Controlled(控制的),Scalable(可扩展的),Decentralized Placement of Replicated Data(副本数据分散放置)。
一致性hash算法简介:
普通hash算法不能很好的解决节点增加和删除的问题。所以使用一致性hash算法。
一致性hash算法是将数据和存储节点映射到同个hash空间。如下图所示。Hash环中的3存储节点把Hash空间划分成3个分区,每个存储节点负责一个分区上的数据。例如,如图(a)所示落在分区[N2,N0]上的数据存储在节点N0。如图(b)所示,当节点N0离开时,原来由它负责的[N2,N0]分区将同[N0,N1]分区合并成[N2,N1]分区,并且都由节点N1负责,也就是说,本来存储在节点N0上的数据都迁移到节点N1,而原来存储在N1和N2节点的数据不受影响,图(c)给出了当节点N3加入时,原来[N2,N0]分区分裂成[N3,N0]和[N2,N3]两个分区,其中[N3,N0]分区上是数据迁移到新加入的N3节点。但是存在删除节点后出现数据分布不均匀(hash空间划分不均匀)的问题,所以引入了虚拟节点的概念。
虚拟节点:一致性Hash的不足,存储节点不能将Hash空间划分地足够均匀。如上图(a)所示,分区[N2,N0]的大小几乎是其它两个分区大小之和。这容易让负责该分区的节点N0负载过重。假设3个节点的磁盘容量相等,那么当节点N0的磁盘已经写满数据时其它两个节点上的磁盘还有很太的空闲空间,但此时系统已经无法继续向分区[N2,N0]写入数据,从而空间资源浪费。
虚拟节点是相对于物理存储节点而言的,虚拟节点负责的分区上的数据最终存储到其对应的物理节点。N1_0代表该虚拟节点对应于物理节点的第0个虚拟节点。增加虚拟节点后,物理节点N0负责[N1_0,N0]和[N0,N0_0]两个分区,物理节点N1负责[N0_0,N1]和[N2_0,N1_0]两个分区,物理节点N2负责[N1,N2]和[N2,N2_0]两个分区,三个物理节点负责的总的数据量趋于平衡。实际应用中,可以根据物理节点的磁盘容量的大小来确定其对应的虚拟节点数目。虚拟节点数目越多,节点负责的数据区间也越大。
分区和分区位置:当节点加入或者离开时,分区会相应地进行分裂或合并。这不对新写入的数据构成影响,但对已经写入到磁盘的数据需要重新计算Hash值以确定它是否需要迁移到其它节点。因为需要遍历磁盘中的所有数据,这个计算过程非常耗时。
1.故障域隔离。同份数据的不同副本分布在不同的故障域,降低数据损坏的风险;
2.负载均衡。数据能够均匀地分布在磁盘容量不等的存储节点,避免部分节点空闲部分节点超载,从而影响系统性能;
3.控制节点加入或者离开时引起的数据迁移量。当节点离开时,最优的数据迁移是只有离线节点上的数据被迁移到其它节点,正常工作的节点的数据不会发生迁移。
1.crush算法简介
2.crush算法和一致性hash算法的区别:
crush算法和一致性hash算法类似,只不过pg充当了虚拟节点,用以分割区域,每个pg管理的数据相同,因此能均匀分布在pg上。crush算法是伪随机算法。CRUSH是Ceph使用的数据分布算法,类似一致性哈希,让数据分配到预期的地方。
Ceph分布数据的过程:首先计算数据x的Hash值并将结果和PG数目取余,以得到数据x对应的PG编号。然后,通过CRUSH算法将PG映射到一组OSD中。最后把数据x存放到PG对应的OSD中。这个过程中包含了两次映射,第一次是数据x到PG的映射。如果把PG当作存储节点,那么这和文章开头提到的普通Hash算法一样。不同的是,PG是抽象的存储节点,它不会随着物理节点的加入或则离开而增加或减少,因此数据到PG的映射是稳定的;第二次是PG到osd set的映射。
作用
功能一:PG管理的数据区间相同,因而数据能够均匀地分布到PG上;
功能二:决定整个存储集群中的“管辖区域”(如图所示:每个pg都有一小段)。需要注意的是,这个“管辖区域”是逻辑上放划分;
问题点:
在多副本(假设副本数目为N)的情况下,分区的数据会存储到连续的N个物理节点中。但这会引入一个新问题:因为副本必须保持在不同的物理节点,但是如果这组pg中存在两个或多个pg对应到同个物理存储节点,那么就必须要跳过这样的节点。crush采用Preference列表来记录每个分区对应的物理节点。
Cluster Map
反映了存储系统层级的物理拓扑结构。定义了OSD集群具有层级关系的静态拓扑结构。OSD层级使得 CRUSH算法在选择OSD时实现了机架感知能力,也就是通过规则定义, 使得副本可以分布在不同的机架、不同的机房中、提供数据的安全性 。
Placement Rules
决定了一个PG的对象副本如何选择的规则,通过这些可以自己设定规则,用户可以自定义设置副本在集群中的分布。data distribution policy由 placement rules组成。crush rules决定了每个数据对象有多少个副本,这些副本存储的限制条件(比如3个副本放在不同的机架中)。
cluster map : monitor map, osd map,crush map,mds map(只针对文件系统);
cluster map:包含当前磁盘,服务器,机架的层级结构.详细的说描述了可用存储资源和层级结构(比如有多少个机架,每个机架上有多少个服务器,每个服务器上有多少个磁盘),CRUSH Map是一个树形结构。OSD Map更多记录的是OSD Map的属性(epoch/fsid/pool信息以及osd的ip等等)。叶子节点是device(也就是osd),其他的节点称为bucket节点,这些bucket都是虚构的节点,可以根据物理结构进行抽象,当然树形结构只有一个最终的根节点称之为root节点,中间虚拟的bucket节点可以是数据中心抽象、机房抽象、机架抽象、主机抽象等。
修改crush map 的命令:
1.编译crush map:
ceph osd getcrushmap -o {compiled-crushmap-filename}
# 取得的map是个二进制文件,不能直接使用文本工具阅读,需要进行反编译,命令如下:
crushtool -d {compiled-crushmap-filename} -o {decompiled-crushmap-filename}
# 取得可编辑map之后,可以根据需求,设计相应的crush结构,来实现数据分落。编辑后首先进行编译成二进制文件,如下命令:
crushtool -c {decompiled-crush-map-filename} -o {compiled-crush-map-filename}
# 最后把crushmap应用到ceph集群里,PG会根据新的map进行重新分布,如下所示:
ceph osd setcrushmap -i {compiled-crushmap-filename}
2.通过手动命令修改
添加bucket
ceph osd crush add-bucket <name> <type>
ceph osd crush add-bucket rack01 rack
移除bucket
ceph osd crush move <name> <location>
ceph osd crush move rack01 root=default
添加OSD到crush map
ceph osd crush add {id-or-name} {weight} [(bucket-type}={bucket-name}..…]
ceph osd crush add osd.5 1.0 root=default datacenter=dcl room=rooml row=foo rack=bar host=foo-bar-1
数据分布策略Placement Rules主要特点:
rule replicated_ruleset #规则集的命名,创建pool时可以指定rule集
{
ruleset 0 #rules集的编号,顺序编即可
type replicated #定义pool类型为replicated(还有erasure模式)
min_size 1 #pool中最小指定的副本数量不能小1
max_size 10 #pool中最大指定的副本数量不能大于10
step take default #查找bucket入口点,一般是root类型的bucket
step chooseleaf firstn 0 type host #选择一个host,并递归选择叶子节点osd
step emit #结束
}
id:中间节点的bucket id都是负数,这个主要是和具体的设备相区别的。设备osd为正数,bucket为负数
weight:bucket的权重
alg:bucket的类型;bucket算法:uniform.list.tree.straw
hash:bucket中使用到的hash算法
item:bucket里包含哪些元素
一个Crush map一般包括四个部分:
1)配置参数
[plain] view plain copy
# 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
2)设备,比如说我有一个三个osd组成的ceph环境,那么设备就有三个
[plain] view plain copy
# devices
device 0 osd.0
device 1 osd.1
device 2 osd.2
3)bucket类型。
[plain] view plain copy
# 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
ceph通过bucket这个逻辑概念来描述这个Crush map树形结构的中间节点。bucket就像是一个容器,一个中间节点就是一个bucket,它的孩子节点就是bucket里包含的items。
4)bucket的具体定义
[plain] view plain copy
root default {
id -1 # do not change unnecessarily
# weight 3.000
alg straw
hash 0 # rjenkins1
item rack1 weight 3.000
}
id:中间节点的bucket id都是负数,这个主要是和具体的设备相区别的。
weight:bucket的权重
alg:bucket的类型
hash:bucket中使用到的hash算法
item:bucket里包含哪些元素
3.2 Rules
有了Crush map之后,如何一步一步从bucket中选出元素,这个就是有rule来定义的。一个rule就是一系列的操作,一般一个pool都会对应有一个rule。
一个rule的定义是这样的:
[plain] view plain copy
rule replicated_ruleset {
ruleset 0
type replicated
min_size 1
max_size 10
step take default
step choose firstn 0 type osd
step emit
}
ruleset:id,表明这个rule是属于这个ruleset的。
type:表明这个rule在哪使用,storage drive (replicated) or a RAID。
min_size和max_size用来限定这个rule的使用范围,即当一个pool的副本数小于min_size或者大于max_size的时候不使用这个rule。
放置策略规则:
step开头的就是三个操作。
1.take是选择一个bucket,然后从这个bucket开始往下遍历,找出OSD。
2.choose是从bucket中找出若干个type类型的项,
3.还有一个chooseleaf操作是bucket中选出若干个leaf节点。至于个数是由firstn后面的数字指定的。如果是0,就按照副本数选择,如果是正数,就按个数来,如果是负数,就按副本数+负数得到的值来选。最后一步是emit,就是输出结果。
1> bucket随机选择算法
hash(x,r,i) x为pg_id, r 为选择的副本序号, i为bucket的id号
2> uniform bucket: 伪随机排列算法
3> list bucket: 链表算法
4> tree bucket : 根据hash得到[0-1]的值v,如果值v在左子树的权重0-w1/wn之间,则选择左子树,否则选择右子树。
5> straw bucket: 默认选择算法
说明:集群中有部分sas和ssd磁盘,现在有个业务线性能及可用性优先级高于其他业务线,能否让这个高优业务线的数据都存放在ssd磁盘上。
心跳是用于节点间检测对方是否故障的,以便及时发现故障节点进入相应的故障处理流程。
问题:
故障检测时间和心跳报文带来的负载之间做权衡。
心跳频率太高则过多的心跳报文会影响系统性能。
心跳频率过低则会延长发现故障节点的时间,从而影响系统的可用性。
故障检测策略应该能够做到:
及时:节点发生异常如宕机或网络中断时,集群可以在可接受的时间范围内感知。
适当的压力:包括对节点的压力和对网络的压力。
容忍网络抖动:网络偶尔延迟。
扩散机制:节点存活状态改变导致的元信息变化需要通过某种机制扩散到整个集群。
ceph心跳检测:
OSD节点会监听public(公共网)、cluster(集群网)
public端口(公共网): 监听来自Monitor和Client的连接,主要是业务数据。
cluster端口(集群网):监听来自OSD Peer的连接,主要是osd内部恢复数据。
hbclient:发送ping心跳的messenger。
步骤:
OSD报告给Monitor:
Ceph通过伙伴OSD汇报失效节点和Monitor统计来自OSD的心跳两种方式判定OSD节点失效。
对于一个网络通信系统:
1.高性能,性能评价的两个指标:宽带和延迟
2.稳定可靠,数据不丢包,在网络中断时候,实现重连。
网络通信模块的实现源码是:src/msg的目录下,其首先定义一个网络通信的框架,分别对应三个子目录: simple,async,xio三种不同的实现方式
网络通信框架三种不同的实现方式:
设计模式(Subscribe/Publish):订阅发布模式又名观察者模式,它意图是“定义对象间的一种一对多的依赖关系, 当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。
步骤:
通信协议格式需要双方约定数据格式。消息的内容主要分为三部分:
class Message : public RefCountedObject {
protected:
ceph_msg_header header; // 消息头
ceph_msg_footer footer; // 消息尾
bufferlist payload; // "front" unaligned blob
bufferlist middle; // "middle" unaligned blob
bufferlist data; // data payload (page-alignment will be preserved where possible)
/* recv_stamp is set when the Messenger starts reading the
* Message off the wire */
utime_t recv_stamp; //开始接收数据的时间戳
/* dispatch_stamp is set when the Messenger starts calling dispatch() on
* its endpoints */
utime_t dispatch_stamp; //dispatch 的时间戳
/* throttle_stamp is the point at which we got throttle */
utime_t throttle_stamp; //获取throttle 的slot的时间戳
/* time at which message was fully read */
utime_t recv_complete_stamp; //接收完成的时间戳
ConnectionRef connection; //网络连接
uint32_t magic = 0; //消息的魔术字
bi::list_member_hook<> dispatch_q; //boost::intrusive 成员字段
};
struct ceph_msg_header {
__le64 seq; // 当前session内 消息的唯一 序号
__le64 tid; // 消息的全局唯一的 id
__le16 type; // 消息类型
__le16 priority; // 优先级
__le16 version; // 版本号
__le32 front_len; // payload 的长度
__le32 middle_len;// middle 的长度
__le32 data_len; // data 的 长度
__le16 data_off; // 对象的数据偏移量
struct ceph_entity_name src; //消息源
/* oldest code we think can decode this. unknown if zero. */
__le16 compat_version;
__le16 reserved;
__le32 crc; /* header crc32c */
} __attribute__ ((packed));
struct ceph_msg_footer {
__le32 front_crc, middle_crc, data_crc; //crc校验码
__le64 sig; //消息的64位signature
__u8 flags; //结束标志
} __attribute__ ((packed));
QoS (Quality of Service,服务质量)起源于网络技术,它用来解决网络延迟和阻塞等问题,能够为指定的网络通信提供更好的服务能力。问题:我们总的Ceph集群的IO能力是有限的,比如带宽,IOPS。如何避免用户争取资源,如果保证集群所有用户资源的高可用性,以及如何保证高优用户资源的可用性。所以我们需要把有限的IO能力合理分配。
dmClock是一种基于时间标签的I/O调度算法,最先被Vmware提出来的用于集中式管理的存储系统。(目前官方QOS模块属于半成品)。
基本思想:
基于令牌桶算法(TokenBucket)实现了一套简单有效的qos功能,满足了云平台用户的核心需求。基本思想:
步骤:
现有框架图:
当集群中添加一个osd存储设备,整个集群发生数据迁移,发生数据迁移的单位是pg,即数据迁移是将Pg中的所有对象作为一个整体来进行迁移。通过peering完成一个pg内的所有副本通pg日志达到数据一致性的过程,系统优先恢复该对象后,才能完成写操作。提供数据的自动恢复功能;ceph的recovery是根据在peering过程中产生,依据pg日志推算出的不一致对象列表来修复其他副本上的数据.当某个osd长时间实效后重新加入集群,无法通过pg日志来修复,就需要进行backfill(回填)过程,backfill是通过逐一对比两个pg对象列表来修复,当重新加入一个osd产生数据迁移,也需要通过backfill过程来完成。
快照是某一个存储设备在某一时刻的全部只读镜像, 克隆是某一个时刻的全部可写镜像,区别是: 快照是只能读,克隆可写,rbd的克隆基于rbd的快照基础上,在客户端librbd上实现了copy-on-write克隆机制
rados是实现以pool为基础的自动分层机制,
第一层 cache pool: 高速存储设备(ssd)
第二层 data pool: 大容量低速设备(hdd设备),可以用ec模式来降低存储空间
通过cache tier来提高关键数据和热点数据的性能,同时降低存储开销
通过在后台定期(默认每天一次)扫描,比较一个pg内的对象在其他的osd上的各个副本的元数据和数据检查是否一致,根据扫描的内容分两种:
1> 比较对象各个副本的元数据,代码比较小,扫描比较高效,对系统影响比较小
2> deep scrub需要进一步的比较副本的数据内容检查数据是否一致
通过将写入的数据分成n份,并通过n份原始数据块计算出m份效验数据块,n+m存储在不同的设备或者节点中,可以允许m个数据块失效,通过n+m份的任意n份数据,还原出其他的数据块。
对象的元数据:对象的元数据是用于对象描述信息的数据,以简单的key-value形式存在,在rados存储系统中有两种实现:xattrs和omap;xattrs保存在对象对应文件的扩展属性中,这就要求对象存储的本地文件系统支持扩展属性(场景:保存一些较小而经常访问的信息);omap:就是object map的简称,就是一些键值对,保存在文件系统之外的独立的key-value存储系统中(保存一些大但不是经常访问的数据)。