【Ceph】Ceph介绍、原理、架构-程序员宅基地

技术标签: 存储|ceph  java  后端  开发语言  

目录

理解Ceph的三种存储接口:块设备、文件系统、对象存储

干货|非常详细的 Ceph 介绍、原理、架构

1. Ceph架构简介及使用场景介绍

1.1 Ceph简介

1.2 Ceph特点

1.3 Ceph架构

1.4 Ceph核心组件及概念介绍

1.5 三种存储类型-块存储

1.6 三种存储类型-文件存储

1.7 三种存储类型-对象存储

2. Ceph IO流程及数据分布

2.1 正常IO流程图

2.2 新主IO流程图

2.3 Ceph IO算法流程

2.4 Ceph IO伪代码流程

2.5 Ceph RBD IO流程

2.6 Ceph RBD IO框架图

2.7 Ceph Pool和PG分布情况

2.8 Ceph 数据扩容PG分布

3. Ceph心跳机制

3.1 心跳介绍

3.2 Ceph 心跳检测

3.3 Ceph OSD之间相互心跳检测

3.4 Ceph OSD与Mon心跳检测

3.5 Ceph心跳检测总结

4. Ceph通信框架

4.1 Ceph通信框架种类介绍

4.2 Ceph通信框架设计模式

4.3 Ceph通信框架流程图

4.4 Ceph通信框架类图

4.5 Ceph通信数据格式

5. Ceph CRUSH算法

5.1 数据分布算法挑战

5.2 Ceph CRUSH算法说明

5.3 Ceph CRUSH算法原理

5.4 CRUSH算法案例

6. 定制化Ceph RBD QOS

6.1 QOS介绍

6.2 Ceph IO操作类型

6.3 Ceph 官方QOS原理

6.4 定制化QOS原理

Ceph技术栈/学习图谱

CEPH架构图

分层架构

组织架构

 逻辑结构


理解Ceph的三种存储接口:块设备、文件系统、对象存储

【ceph】理解Ceph的三种存储接口:块设备、文件系统、对象存储_bandaoyu的note-程序员宅基地

干货|非常详细的 Ceph 介绍、原理、架构

1. Ceph架构简介及使用场景介绍

1.1 Ceph简介

Ceph是一个统一的分布式存储系统,设计初衷是提供较好的性能、可靠性和可扩展性。

1.2 Ceph特点

  • 高性能
    a. 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。
    b.考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。
    c. 能够支持上千个存储节点的规模,支持TB到PB级的数据。

  • 高可用性
    a. 副本数可以灵活控制。
    b. 支持故障域分隔,数据强一致性。
    c. 多种故障场景自动进行修复自愈。
    d. 没有单点故障,自动管理。

  • 高可扩展性
    a. 去中心化。
    b. 扩展灵活。
    c. 随着节点增加而线性增长。

  • 特性丰富
    a. 支持三种存储接口:块存储、文件存储、对象存储。
    b. 支持自定义接口,支持多种语言驱动。

1.3 Ceph架构

Ceph 存储集群由几个不同的daemon组成,每个daemon负责Ceph 的一个独特功能并。每个守护进程是彼此独立的。


 

支持三种接口:

  • Object:有原生的API,而且也兼容Swift和S3的API。(对象)
  • Block:支持精简配置、快照、克隆。(块)
  • File:Posix接口,支持快照。(文件)

 

1.4 Ceph核心组件及概念介绍

作者:启迪云
链接:https://www.zhihu.com/question/21718731/answer/561372178
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

下面将简要介绍每个Ceph组件的功能:

RADOS(Reliable Autonomic Distributed Object Store, RADOS)
RADOS是Ceph 存储集群的基础。Ceph 中的一切都以对象的形式存储,而RADOS 就负责存储这些对象,而不考虑它们的数据类型。RADOS 层确保数据一致性和可靠性。对于数据一致性,它执行数据复制、故障检测和恢复。还包括数据在集群节点间的recovery。

OSD
实际存储数据的进程。通常一个OSD daemon绑定一个物理磁盘。Client write/read 数据最终都会走到OSD去执行write/read操作。

MON(monitor)
Monitor在Ceph集群中扮演者管理者的角色,维护了整个集群的状态,是Ceph集群中最重要的组件。

Mon保证集群的相关组件在同一时刻能够达成一致,相当于集群的领导层,负责收集、更新和发布集群信息。为了规避单点故障,在实际的Ceph部署环境中会部署多个Mon,同样会引来多个Mon之前如何协同工作的问题。在一个标准的Ceph环境中,Monitor的功能可以分为以下两点
管好自己
多个monitor之间如何协同工作,怎么同步数据;
管理集群信息
数据的存储,保证数据存储的正确性等等。

Librados
简化访问RADOS的一种方法,目前支持PHP、Ruby、Java、Python、C和C++语言。它提供了Ceph 存储集群的一个本地接口RADOS ,并且是其他服务(如RBD 、RGW) 的基础,以及为CephFS 提供POSIX 接口。librados API 支持直接访问RADOS ,使得开发者能够创建自己的接口来访问Ceph 集群存储。

RBD
Ceph块设备。对外提供块存储。可以像磁盘一样被映射、格式化已经挂载到服务器上。支持snapshot。

RGW
Ceph对象网关,提供了一个兼容S3和Swift的restful API接口。RGW还支持多租户和Openstack的keyston身份验证服务。

MDS
Ceph元数据服务器,跟踪文件层次结构并存储只供CephFS使用的元数据。Ceph块设备和RADOS网关不需要元数据。MDS不直接给client提供数据服务。

CephFS
提供了一个任意大小且兼容POSlX的分布式文件系统。CephFS 依赖Ceph MDS 来跟踪文件层次结构,即元数据。
Ceph RADOS
RADOS 是Ceph 存储系统的核心,也称为Ceph 存储集群。Ceph 的所有优秀特性都是由RADOS 提供的,包括分布式对象存储、高可用性、高可靠性、没有单点故障、向我修复以及自我管理等。RADOS 层在Ceph 存储架构中扮演着举足轻重的角色。Ceph 的数据访问方法(如RBD 、CephFS 、RADOS GW 和librados ) 的所有操作都是在RADOS 层之上构建的。
当Ceph 集群接收到来向客户端的写请求时,CRUSH 算法首先计算出存储位置,以此决定应该将数据写入什么地方。然后这些信息传递到队DOS 层进行进一步处理。基于CRUSH 规则集,RADOS 以小对象的形式将数据分发到集群内的所有节点。最后,将这些对象存储在OSD 中。
当配置的复制数大于1时,队DOS 负责数据的可靠性。同时,它复制对象,创建副本,并将它们存储在不同的故障区域中,换言之,同一个对象的副本不会存放在同一个故障区域中。然而,如果有更多个性化需求和更高的可靠性,就需要根据实际需求和基础架构来优化CRUSH 规则集。RADOS 能够保证在一个RADOS 集群中的对象副本总是不少于一个,只要你有足够的设备。
除了跨集群存储和复制对象之外,RADOS 也确保对象状态的一致性。在对象不一致的情况下,将会利用剩下的副本执行恢复操作。这个操作自动执行,对于用户而言是透明的,从而为Ceph 提供了自我管理和自我修复的能力。如果仔细分析Ceph 的架构图,你会发现它有两部分: RADOS 在最下部,它完全处于Ceph集群的内部,没有提供给客户端直接接口;另一部分就是在RADOS 之上的面向所有客户端的接口。
Ceph 对象存储设备
Ceph 的OSD 是Ceph 存储集群中最重要的一个基础组件,它负责将实际的数据以对象的形式存储在每一个集群节点的物理磁盘驱动器中。Ceph 集群中的大部分工作是由OSD 守护进程完成的。存储用户数据是真正最耗时的部分。

Ceph OSD 以对象的形式存储所有客户端数据,并在客户端发起数据请求时提供相同的数据。Ceph 集群包含多个OSD 。对于任何读或写操作,客户端首先向monitor 请求集群的map ,然后,它们就可以无须monitor 的干预直接与OSD 进行I/O操作也正是因为产生数据的客户端能够直接写入存储数据的OSD 而没有任何额外的数据处理层,才使得数据事务处理速度如此之快。与其他存储解决方案相比,这种类型的数据存储和取回机制是Ceph 所独有的。
Ceph 的核心特性(比如可靠性、自平衡、自恢复和一致性)都始于OSD 。根据配置的副本数, Ceph通过跨集群节点复制每个对象多次来提供可靠性,同时使其具有高可用性容错性。OSD 上的每个对象都有一个主副本和几个辅副本,辅副本分散在其他OSD 上。由于Ceph 是一个分布式系统且对象分布在多个OSD 上,因此每一个OSD 对于一些对象而言是主副本。但同时对于其他对象而言就是辅副本,存放辅副本的OSD 受主副本OSD 控制;然而,它们也可能又成为主副本OSD 。
Ceph的OSD由一个已经存在Linux 文件系统的物理磁盘驱动器和10SD 服务组成。
Linux文件系统对于OSD 守护进程而言是相当重要的,因为它决定了支持哪些扩展属性( XATTR) 。这些文件系统扩展属性能够为OSD 守护进程提供内部对象的状态、快照、元数据和ACL 等信息.这有助于数据管理。

OSD在拥有有效Linux 分区的物理磁盘驱动器上进行操作。Linux 分区可以是Btrfs (B树文件系统)、XFS 或ext4。Ceph 集群的性能基准测试的主要标准之一就是文件系统的选择。

  • Btrfs

与使用XFS 和ext4 文件系统的OSD 相比,使用Btrfs 文件系统的OSD 能够提供更佳的性能。使用Btrfs 最主要的一个优点是支持写时复制和可写的快照,这对于虑拟机的部署和克隆非常有用。在文件系统中它还支持透明的压缩、普遍的校验和多设备的统一管理。还支持高效的XATTR 、对于小文件的合井,还有SSD上所熟知的集成卷管理,并支持在线fsck 的特性。然而,尽管有如此多的新特性,Btrfs 目前还不具备应用于生产系统的条件,但对于测试而言它是一个很好的选择。
 

  • XFS

这是一个可靠、成熟且非常稳定的文件系统,因此,我们推荐在生产环境的Ceph 集群中使用它。XFS 是Ceph存储中最常用的文件系统.也是推荐OSD 使用的文件系统。然而,从另一个方面来看,XFS 又不如Btrfs。XFS 在元数据扩展性上存在性能问题,XFS 也是一种日志文件系统, 也就是说.每次客户端发送数据以写入Ceph 集群时,肯先需要写人口志空间,然后再写入XFS 文件系统这样的两次写入操作增加了开销从而使得XFS 的性能不如Btrfs,Btrfs 没有使用日志。
 

  • Ext4

ext4 文件系统也是一种日志文件系统,是一个远合生产环境下Ceph OSD 使用的文件系统;然而,它的受欢迎程度不如XFS 。从性能的角度来看,ext4 文件系统也不如Btrfs。

Ceph OSD 使用诸如Btrfs 和XFS 的日志文件系统。在将数据提交到备用存储之前,Ceph 首先将数据写入一个称为日志( journal) 的独立存储区域,日志是相同的机械磁盘(如OSD) 或不同的SSD 磁盘或分区上一小块缓冲区大小的分区,甚至也可以是文件系统上的一个文件。在这种机制中,Ceph 的所有写都是先到日志,然后再到备用存储,如下图所示。
 


Ceph Monitor
顾名思义,Ceph monitor 负责监控整个集群的健康状况。它们以守护进程的形式存在,这些守护进程通过存储集群的关键信息来维护集群成员状态、对等节点状态,以及集群配置信息。Ceph monitor 通过维护整个集群状态的主副本来完成它的任务。集群map 包括monitor 、OSD 、PG 、CRUSH 和MDS map o 所有这些map 统称为集群map 。让我们简单地浏览一下每个map 的功能。

  • monitor map

它维护着monitor 节点间端到端的信息,其中包括Ceph 集群ID 、monitor 主机名、IP 地址及端口号。它还存储着当前map 的创建版本和最后一次修改的信息。可以通过下面的命令检查集群的monitor map:
# ceph mon dump

  • OSD map :

它存储着一些常见的信息,如集群ID、OSD map 创建版本和最后一次修改信息,以及与池相关的信息(如池名字、池ID 、类型、副本数和归置组) 。它还存储着OSD 的一些信息,如数目、状态、权重、最近处于clean 状态的间隔以及OSD 主机等信息。可以通过执行以下命令获取集群的OSD map:
# ceph osd dump
PG map :
它存储着归置组的版本、时间戳、最新的OSD map 版本、容量充满的比例以及容量接近充满的比例等信息。它同时也跟踪每个归置组的ID 、对象数、状态状态时间戳、OSD 的叩集合、OSD 的acting 集合,最后还有清洗等信息。要检查集群的PG map ,执行:
# ceph pg dump

  • CRUSH map:

它存储着集群的存储设备信息、故障域层次结构以及在故障域中定义如何存储数据的规则。要查看集群的CRUSH map ,执行:
# ceph osd crush dump

  • MDS map:

它存储着当前MDS map 的版本,map 的创建和修改时间,数据和元数据池的ID ,集群中MDS 的数目以及MDS 的状态。要查看集群MDS map ,执行:
# ceph mds dump

一个典型的Ceph 集群通常包含多个monitor 节点。多monitor 的Ceph 架构使用了仲
裁( quorum ) ,使用Paxos 算法为集群提供了分布式决策机制。集群中monitor 数目应该是奇数,最低要求是一个monitor 节点,推荐的数是3 。自monitor开始仲裁操作,至少需要保证一半以上的monitor 始终处于可用状态,这样才可以防止其他系统可以看到的脑裂问题。

这就是为什么推荐使用奇数个monitor。在所有的集群monitor 巾,其中有一个是领导者( leader ) 。如果领导者monitor不可用其他monitor 节点也有权成为领导者。生产环境下的集群必须至少有三个monitor节点来提供高可用性。

对于企业级生产环境,建议使用专门的monitor 节点。这样, 一旦你的OSD 节点发生
故障,只要你有足够的monitor 运行在独立的机器上,你仍然可以连接到你的Ceph 集群。在存储的规划阶段,也应该考虑物理机架的布局。你应该将monitor节点分散到所有的故障域中,例如,不同的开关、电源和物理机架。如果你有多个数据中心连接在同一个高速网络,monitor 节点应该放到不同的数据中心。
Ceph块存储
块存储是企业环境中最常见的一种数据存储格式。Ceph 块设备也称为RADOS 块设备(RBD) ;它为物理层的虚拟机监控程序以及虚拟机提供块存储解决方案。Ceph 的RBD 驱动程序已经被集成到Linux 内核( 2.6.39 或更高版本)中,而且已经被QEMU/KVM 支持,它们能无缝地访问Ceph 块设备。
Linux主机能全力支持内核RBD (KRB D ) 并通过librados 映射Ceph 块设备。然后RADOS将Ceph 块设备的对象以分布式模式存储在集群中。一旦Ceph 块设备映射到Linux主机,它也可以当作裸分区或标记为文件系统,然后进行挂载。

Ceph对象网关
Ceph 对象网关,也称做RADOS 网关,它是一个代理,可以将HTTP 请求转换为RADOS ,同时也可以把RADOS 请求转换为HTTP 请求,从而提供RESTful 对象存储,这兼容S3 和Swift。Ceph 对象存储使用Ceph 对象网关守护进程( radosgw) 与librgw 、librados (Ceph 集群)交互。这是使用libfcgi 作为FastCGI的一个模块来实现的,并且可以被任何支持FastCGl的Web 服务器使用。
 

Ceph文件系统
CephFS 在RADOS 层之上提供了一个兼容POSIX 的文件系统。它使用MDS 作为守护进程,负责管理其元数据并将它和其他数据分开,这有助于降低复杂性并提高可靠性。CephFS 继承了RADOS 的特性并为数据提供了动态再平衡。
 

「Ceph 分布式核心组件」

集群文件系统最初始于1990年代末和2000年代初。Lustre是最早利用可伸缩文件系统实现产品化的产品之一。多年来,出现了其他一些Lustre衍生产品,包括GlusterFSGPFSXtreemFSOrangeFS等。这些文件系统都集中于为文件系统实现符合POSIX的挂载,并且缺乏通用的集成API

Ceph的架构并不需要考虑到需要与POSIX兼容的文件系统——这完全得益于云的时代。利用RADOSCeph可以扩展不受元数据约束限制的块设备。这极大地提高了存储性能,但是却使那些寻求基于Ceph的大型文件系统挂载方法的人们望而却步。直到Ceph Jewel10.2.0)版本发布为止,CephFS已经是稳定且可靠的文件系统——允许部署POSIX挂载的文件系统。

Ceph支持块,对象和文件存储,并且具有横向扩展能力,这意味着多个Ceph存储节点(服务器)共同提供了一个可快速处理上PB数据(1PB = 1,000 TB = 1,000,000 GB)的存储系统。利用作为基础的硬件组件,它还可以同时提高性能和容量。

Ceph具有许多基本的企业存储功能,包括副本,纠错码,快照,自动精简配置,分层(在闪存和普通硬盘之间缓存数据的能力——即缓存)以及自我修复功能。为了做到这一点,Ceph利用了下面将要探讨的几个组件。

Ceph Nautilusv14.2.0)开始,现在有五个主要的守护程序或服务,它们集成在一起以提供Ceph服务的正常运行。这些是:

  1. 「ceph-mon」: Monitor确实提供了其名称所暗示的功能——监视群集的运行状况。该监视器还告诉 OSD在 replication期间将数据放置在何处,并保留主 CRUSH Map

  2. 「ceph-osd」: OSD是 Ceph的基础数据存储单元,它利用 XFS文件系统和物理磁盘来存储从客户端提供给它的块数据。

  3. 「ceph-mds」: MDS守护程序提供了将 Ceph块数据转换为存储文件的 POSIX兼容挂载点的功能,就像您使用传统文件系统一样。

  4. 「ceph-mgr」: MGR守护程序显示有关群集状态的监视和管理信息。

  5. 「ceph-rgw」: RGW守护程序是一个 HTTP API守护程序,对象存储网关实际上是调用 librados的 API来实现数据的存储和读取。而该网关同时提供了兼容 AWS S3和 OpenStack Swift的对象存储访问接口( API)。

从术语的角度来看,Ceph需要了解一些重要的知识。

Ceph基于CRUSH算法构建, 并支持多种访问方法(文件,块,对象)。CRUSH算法确定对象在OSD上的位置,并且可以将这些相同的块拉出以进行访问请求。

Ceph利用了可靠,自治,分布式的对象存储(或RADOS),该对象存储由自我修复,自我管理的存储节点组成。前面讨论的OSD守护程序是RADOS群集的一部分。

放置组(PG)的全称是placement group,是用于放置object的一个载体,所以群集中PG的数量决定了它的大小。pg的创建是在创建ceph存储池的时候指定的,同时跟指定的副本数也有关系,比如是3副本的则会有3个相同的pg存在于3个不同的osd上,pg其实在osd的存在形式就是一个目录。PG可以由管理员设置,新版本中也可以根据集群使用情况自动缩放。

RBDRADOS Block Device的简称,RBD块存储是最稳定且最常用的存储类型。RBD块设备类似磁盘可以被挂载。RBD块设备具有快照、多副本、克隆和一致性等特性,数据以条带化的方式存储在Ceph集群的多个OSD中。可以在Ceph中用于创建用于虚拟化的镜像块设备,例如KVMXen。通过利用与RADOS兼容的API libradosVM的访问不是通过iSCSINFS,而是通过存储API来实现的。

Ceph万字总结|如何改善存储性能以及提升存储稳定性 - 博客 - 编程圈

  • Monitor
    一个Ceph集群需要多个Monitor组成的小集群,它们通过Paxos同步数据,用来保存OSD的元数据。
  • OSD
    OSD全称Object Storage Device,也就是负责响应客户端请求返回具体数据的进程。一个Ceph集群一般都有很多个OSD。
  • MDS
    MDS全称Ceph Metadata Server,是CephFS服务依赖的元数据服务。
  • Object
    Ceph最底层的存储单元是Object对象,每个Object包含元数据和原始数据。
  • PG
    PG全称Placement Grouops,是一个逻辑的概念,一个PG包含多个OSD。引入PG这一层其实是为了更好的分配数据和定位数据。
  • RADOS
    RADOS全称Reliable Autonomic Distributed Object Store,是Ceph集群的精华,用户实现数据分配、Failover等集群操作。
  • Libradio
    Librados是Rados提供库,因为RADOS是协议很难直接访问,因此上层的RBD、RGW和CephFS都是通过librados访问的,目前提供PHP、Ruby、Java、Python、C和C++支持。
  • CRUSH
    CRUSH是Ceph使用的数据分布算法,类似一致性哈希,让数据分配到预期的地方。
  • RBD
    RBD全称RADOS block device,是Ceph对外提供的块设备服务。
  • RGW
    RGW全称RADOS gateway,是Ceph对外提供的对象存储服务,接口与S3和Swift兼容。
  • CephFS
    CephFS全称Ceph File System,是Ceph对外提供的文件系统服务。

Cephåºç¡ç¥è¯ååºç¡æ¶æè¤è¯- luohaixian - åå¢å­

p_w_picpath

https://www.pdl.cmu.edu/PDL-FTP/Storage/ceph-exp-sosp19.pdf

 https://www.pdl.cmu.edu/PDL-FTP/Storage/ceph-exp-sosp19.pdf

1.5 三种存储类型-块存储

典型设备:磁盘阵列,硬盘

主要是将裸磁盘空间映射给主机使用的。

优点

  • 通过Raid与LVM等手段,对数据提供了保护。
  • 多块廉价的硬盘组合起来,提高容量。
  • 多块磁盘组合出来的逻辑盘,提升读写效率。

缺点

  • 采用SAN架构组网时,光纤交换机,造价成本高。
  • 主机之间无法共享数据。

使用场景

  • docker容器、虚拟机磁盘存储分配。
  • 日志存储。
  • 文件存储。

1.6 三种存储类型-文件存储

典型设备:FTP、NFS服务器

为了克服块存储文件无法共享的问题,所以有了文件存储。

在服务器上架设FTP与NFS服务,就是文件存储。

优点

  • 造价低,随便一台机器就可以了。
  • 方便文件共享。

缺点

  • 读写速率低。
  • 传输速率慢。

使用场景

  • 日志存储。
  • 有目录结构的文件存储。

1.7 三种存储类型-对象存储

典型设备:内置大容量硬盘的分布式服务器(swift, s3)

多台服务器内置大容量硬盘,安装上对象存储管理软件,对外提供读写访问功能。

优点

  • 具备块存储的读写高速。
  • 具备文件存储的共享等特性。

使用场景:(适合更新变动较少的数据)

  • 图片存储。
  • 视频存储。

2. Ceph IO流程及数据分布

2.1 正常IO流程图

步骤

1. client 创建cluster handler。

2. client 读取配置文件。

3. client 连接上monitor,获取集群map信息。

4. client 读写io 根据crshmap 算法请求对应的主osd数据节点。

5. 主osd数据节点同时写入另外两个副本节点数据。

6. 等待主节点以及另外两个副本节点写完数据状态。

7. 主节点及副本节点写入状态都成功后,返回给client,io写入完成。

2.2 新主IO流程图

说明

如果新加入的OSD1取代了原有的 OSD4成为 Primary OSD, 由于 OSD1 上未创建 PG , 不存在数据,那么 PG 上的 I/O 无法进行,怎样工作的呢?

步骤

1. client连接monitor获取集群map信息。

2. 同时新主osd1由于没有pg数据会主动上报monitor告知让osd2临时接替为主。

3. 临时主osd2会把数据全量同步给新主osd1。

4. client IO读写直接连接临时主osd2进行读写。

5. osd2收到读写io,同时写入另外两副本节点。

6. 等待osd2以及另外两副本写入成功。

7. osd2三份数据都写入成功返回给client, 此时client io读写完毕。

8. 如果osd1数据同步完毕,临时主osd2会交出主角色。

9. osd1成为主节点,osd2变成副本。

2.3 Ceph IO算法流程

1. File用户需要读写的文件。File->Object映射:

a. ino (File的元数据,File的唯一id)。
b. ono(File切分产生的某个object的序号,默认以4M切分一个块大小)。
c. oid(object id: ino + ono)。

2. Object是RADOS需要的对象。Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。Object->PG映射:

a. hash(oid) & mask-> pgid 。
b. mask = PG总数m(m为2的整数幂)-1 。

3. PG(Placement Group),用途是对object的存储进行组织和位置映射, (类似于redis cluster里面的slot的概念) 一个PG里面会有很多object。采用CRUSH算法,将pgid代入其中,然后得到一组OSD。PG->OSD映射:

a. CRUSH(pgid)->(osd1,osd2,osd3) 。

2.4 Ceph IO伪代码流程

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

2.5 Ceph RBD IO流程

(RBD就是Ceph里的块设备。RBD : Ceph’s RADOS Block Devices , Ceph block devices are thin-provisioned, resizable and store data striped over multiple OSDs in a Ceph cluster.)

步骤

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。

2.6 Ceph RBD IO框架图

librbd和krbd(kernel rbd)

ceph 作为一个统一存储的分布式存储系统,提供了对象,文件和块存储三种存储接口。其中块存储又提供了两种client接口用于块存储的不同场景使用。

(1)librbd:这是ceph 块存储目前使用最多的一个场景,也就是云计算场景对接openstack或者其他平台。这也是ceph出现十几年,但是前几年才大火的一个原因,搭上云计算的顺风车。这个场景不是这个系列的重点,就不做详细分析了。

(2)krbd(kernel rbd):这是ceph 块设备直接对接到linux 系统的场景。也就是说,在linux kernel当中提供了一个块设备的driver,直接对ceph server端进行数据IO。这个场景主要用于不能直接利用librbd 进行业务改造的场景。比如 container 场景(实际上对于container,最适合的应该是文件存储,但是ceph的文件存储cephfs,并不是很稳定,所以暂时使用krbd来使用)。另外相比于librbd,krbd 还有最大的优势在于,其可以充分利用linux block layer的众多特性,比如pagecache,bcache,md,multiqueue等等。

ceph kernel rbd (一): 简介_csdn_yds的专栏-程序员宅基地_krbd

客户端写数据osd过程

1. 采用的是librbd的形式,使用librbd创建一个块设备,向这个块设备中写入数据。

2. 在客户端本地通过调用librados接口,然后经过pool,rbd,object、pg进行层层映射,在PG这一层中,可以知道数据保存在哪3个OSD上,这3个OSD分为主从的关系。

3. 客户端与primay OSD建立SOCKET 通信,将要写入的数据传给primary OSD,由primary OSD再将数据发送给其他replica OSD数据节点。

2.7 Ceph Pool和PG分布情况

说明

  • pool是ceph存储数据时的逻辑分区,它起到namespace的作用。
  • 每个pool包含一定数量(可配置)的PG。
  • PG里的对象被映射到不同的Object上。
  • pool是分布到整个集群的。
  • pool可以做故障隔离域,根据不同的用户场景不一进行隔离。

2.8 Ceph 数据扩容PG分布

场景数据迁移流程

  • 现状3个OSD, 4个PG
  • 扩容到4个OSD, 4个PG

现状

扩容后

说明

每个OSD上分布很多PG, 并且每个PG会自动散落在不同的OSD上。如果扩容那么相应的PG会进行迁移到新的OSD上,保证PG数量的均衡。

3. Ceph心跳机制

3.1 心跳介绍

心跳是用于节点间检测对方是否故障的,以便及时发现故障节点进入相应的故障处理流程。

问题

  • 故障检测时间和心跳报文带来的负载之间做权衡。
  • 心跳频率太高则过多的心跳报文会影响系统性能。
  • 心跳频率过低则会延长发现故障节点的时间,从而影响系统的可用性。

故障检测策略应该能够做到

  • 及时:节点发生异常如宕机或网络中断时,集群可以在可接受的时间范围内感知。
  • 适当的压力:包括对节点的压力,和对网络的压力。
  • 容忍网络抖动:网络偶尔延迟。
  • 扩散机制:节点存活状态改变导致的元信息变化需要通过某种机制扩散到整个集群。

3.2 Ceph 心跳检测

OSD节点会监听public、cluster、front和back四个端口

  • public端口:监听来自Monitor和Client的连接。
  • cluster端口:监听来自OSD Peer的连接。
  • front端口:供客户端连接集群使用的网卡, 这里临时给集群内部之间进行心跳。
  • back端口:供客集群内部使用的网卡。集群内部之间进行心跳。
  • hbclient:发送ping心跳的messenger。

3.3 Ceph OSD之间相互心跳检测

步骤

  • 同一个PG内OSD互相心跳,他们互相发送PING/PONG信息。
  • 每隔6s检测一次(实际会在这个基础上加一个随机时间来避免峰值)。
  • 20s没有检测到心跳回复,加入failure队列。

3.4 Ceph OSD与Mon心跳检测

OSD报告给Monitor:

  • OSD有事件发生时(比如故障、PG变更)。
  • 自身启动5秒内。
  • OSD周期性的上报给Monito
    • OSD检查failure_queue中的伙伴OSD失败信息。
    • 向Monitor发送失效报告,并将失败信息加入failure_pending队列,然后将其从failure_queue移除。
    • 收到来自failure_queue或者failure_pending中的OSD的心跳时,将其从两个队列中移除,并告知Monitor取消之前的失效报告。
    • 当发生与Monitor网络重连时,会将failure_pending中的错误报告加回到failure_queue中,并再次发送给Monitor。
  • Monitor统计下线OSD
    • Monitor收集来自OSD的伙伴失效报告。
    • 当错误报告指向的OSD失效超过一定阈值,且有足够多的OSD报告其失效时,将该OSD下线。

3.5 Ceph心跳检测总结

Ceph通过伙伴OSD汇报失效节点和Monitor统计来自OSD的心跳两种方式判定OSD节点失效。

  • 及时:伙伴OSD可以在秒级发现节点失效并汇报Monitor,并在几分钟内由Monitor将失效OSD下线。
  • 适当的压力:由于有伙伴OSD汇报机制,Monitor与OSD之间的心跳统计更像是一种保险措施,因此OSD向Monitor发送心跳的间隔可以长达600秒,Monitor的检测阈值也可以长达900秒。Ceph实际上是将故障检测过程中中心节点的压力分散到所有的OSD上,以此提高中心节点Monitor的可靠性,进而提高整个集群的可扩展性。
  • 容忍网络抖动:Monitor收到OSD对其伙伴OSD的汇报后,并没有马上将目标OSD下线,而是周期性的等待几个条件:
    • 目标OSD的失效时间大于通过固定量osd_heartbeat_grace和历史网络条件动态确定的阈值。
    • 来自不同主机的汇报达到mon_osd_min_down_reporters。
    • 满足前两个条件前失效汇报没有被源OSD取消。
  • 扩散:作为中心节点的Monitor并没有在更新OSDMap后尝试广播通知所有的OSD和Client,而是惰性的等待OSD和Client来获取。以此来减少Monitor压力并简化交互逻辑。

4. Ceph通信框架

4.1 Ceph通信框架种类介绍

网络通信框架三种不同的实现方式:

  • Simple线程模式
    特点:每一个网络链接,都会创建两个线程,一个用于接收,一个用于发送。
    缺点:大量的链接会产生大量的线程,会消耗CPU资源,影响性能。
  • Async事件的I/O多路复用模式
    特点:这种是目前网络通信中广泛采用的方式。k版默认已经使用Asnyc了。
  • XIO方式使用了开源的网络通信库accelio来实现
    特点:这种方式需要依赖第三方的库accelio稳定性,目前处于试验阶段。

4.2 Ceph通信框架设计模式

设计模式:订阅发布模式(Subscribe/Publish),又名观察者模式,它意图是“定义对象间的一种一对多的依赖关系,
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。

4.3 Ceph通信框架流程图

步骤

  • Accepter监听peer的请求, 调用 SimpleMessenger::add_accept_pipe() 创建新的 Pipe 到 SimpleMessenger::pipes 来处理该请求。
  • Pipe用于消息的读取和发送。该类主要有两个组件,Pipe::Reader,Pipe::Writer用来处理消息读取和发送。
  • Messenger作为消息的发布者, 各个 Dispatcher 子类作为消息的订阅者, Messenger 收到消息之后, 通过 Pipe 读取消息,然后转给 Dispatcher 处理。
  • Dispatcher是订阅者的基类,具体的订阅后端继承该类,初始化的时候通过 Messenger::add_dispatcher_tail/head 注册到 Messenger::dispatchers. 收到消息后,通知该类处理。
  • DispatchQueue该类用来缓存收到的消息, 然后唤醒 DispatchQueue::dispatch_thread 线程找到后端的 Dispatch 处理消息。

640?wx_fmt=png

ceph_message_2

4.4 Ceph通信框架类图

4.5 Ceph通信数据格式

通信协议格式需要双方约定数据格式。

消息的内容主要分为三部分:

  • header //消息头,类型消息的信封
  • user data //需要发送的实际数据
    • payload //操作保存元数据
    • middle //预留字段
    • data //读写数据
  • footer //消息的结束标记
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));

5. Ceph CRUSH算法

5.1 数据分布算法挑战

  • 数据分布和负载均衡:
    a. 数据分布均衡,使数据能均匀的分布到各个节点上。
    b. 负载均衡,使数据访问读写操作的负载在各个节点和磁盘的负载均衡。
  • 灵活应对集群伸缩
    a. 系统可以方便的增加或者删除节点设备,并且对节点失效进行处理。
    b. 增加或者删除节点设备后,能自动实现数据的均衡,并且尽可能少的迁移数据。
  • 支持大规模集群
    a. 要求数据分布算法维护的元数据相对较小,并且计算量不能太大。随着集群规模的增 加,数据分布算法开销相对比较小。

5.2 Ceph CRUSH算法说明

  • CRUSH算法的全称为:Controlled Scalable Decentralized Placement of Replicated Data,可控的、可扩展的、分布式的副本数据放置算法。
  • pg到OSD的映射的过程算法叫做CRUSH 算法。(一个Object需要保存三个副本,也就是需要保存在三个osd上)。
  • CRUSH算法是一个伪随机的过程,他可以从所有的OSD中,随机性选择一个OSD集合,但是同一个PG每次随机选择的结果是不变的,也就是映射的OSD集合是固定的。

5.3 Ceph CRUSH算法原理

CRUSH算法因子:

  • 层次化的Cluster Map
    反映了存储系统层级的物理拓扑结构。定义了OSD集群具有层级关系的 静态拓扑结构。OSD层级使得 CRUSH算法在选择OSD时实现了机架感知能力,也就是通过规则定义, 使得副本可以分布在不同的机 架、不同的机房中、提供数据的安全性 。
  • Placement Rules
    决定了一个PG的对象副本如何选择的规则,通过这些可以自己设定规则,用户可以自定义设置副本在集群中的分布。

5.3.1 层级化的Cluster Map

CRUSH Map是一个树形结构,OSDMap更多记录的是OSDMap的属性(epoch/fsid/pool信息以及osd的ip等等)。

叶子节点是device(也就是osd),其他的节点称为bucket节点,这些bucket都是虚构的节点,可以根据物理结构进行抽象,当然树形结构只有一个最终的根节点称之为root节点,中间虚拟的bucket节点可以是数据中心抽象、机房抽象、机架抽象、主机抽象等。

5.3.2 数据分布策略Placement Rules

数据分布策略Placement Rules主要有特点

a. 从CRUSH Map中的哪个节点开始查找
b. 使用那个节点作为故障隔离域
c. 定位副本的搜索模式(广度优先 or 深度优先)

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        #结束
}

5.3.3 Bucket随机算法类型

  • 一般的buckets:适合所有子节点权重相同,而且很少添加删除item。
  • list buckets:适用于集群扩展类型。增加item,产生最优的数据移动,查找item,时间复杂度O(n)。
  • tree buckets:查找负责度是O (log n), 添加删除叶子节点时,其他节点node_id不变。
  • straw buckets:允许所有项通过类似抽签的方式来与其他项公平“竞争”。定位副本时,bucket中的每一项都对应一个随机长度的straw,且拥有最长长度的straw会获得胜利(被选中),添加或者重新计算,子树之间的数据移动提供最优的解决方案。

5.4 CRUSH算法案例

说明

集群中有部分sas和ssd磁盘,现在有个业务线性能及可用性优先级高于其他业务线,能否让这个高优业务线的数据都存放在ssd磁盘上。

普通用户

高优用户

配置规则
 

6. 定制化Ceph RBD QOS

6.1 QOS介绍

QoS (Quality of Service,服务质量)起源于网络技术,它用来解决网络延迟和阻塞等问题,能够为指定的网络通信提供更好的服务能力。

问题

我们总的Ceph集群的iIO能力是有限的,比如带宽,IOPS。如何避免用户争取资源,如果保证集群所有用户资源的高可用性,以及如何保证高优用户资源的可用性。所以我们需要把有限的IO能力合理分配。

6.2 Ceph IO操作类型

  • ClientOp:来自客户端的读写I/O请求。
  • SubOp:osd之间的I/O请求。主要包括由客户端I/O产生的副本间数据读写请求,以及由数据同步、数据扫描、负载均衡等引起的I/O请求。
  • SnapTrim:快照数据删除。从客户端发送快照删除命令后,删除相关元数据便直接返回,之后由后台线程删除真实的快照数据。通过控制snaptrim的速率间接控制删除速率。
  • Scrub:用于发现对象的静默数据错误,扫描元数据的Scrub和对象整体扫描的deep Scrub。
  • Recovery:数据恢复和迁移。集群扩/缩容、osd失效/从新加入等过程。

6.3 Ceph 官方QOS原理

mClock是一种基于时间标签的I/O调度算法,最先被Vmware提出来的用于集中式管理的存储系统。(目前官方QOS模块属于半成品)。

基本思想:

  • reservation 预留,表示客户端获得的最低I/O资源。
  • weight 权重,表示客户端所占共享I/O资源的比重。
  • limit 上限,表示客户端可获得的最高I/O资源。

6.4 定制化QOS原理

6.4.1 令牌桶算法介绍

基于令牌桶算法(TokenBucket)实现了一套简单有效的qos功能,满足了云平台用户的核心需求。

基本思想

  • 按特定的速率向令牌桶投放令牌。
  • 根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送。
  • 符合匹配规则的报文,则需要令牌桶进行处理。当桶中有足够的令牌则报文可以被继续发送下去,同时令牌桶中的令牌量按报文的长度做相应的减少。
  • 当令牌桶中的令牌不足时,报文将不能被发送,只有等到桶中生成了新的令牌,报文才可以发送。这就可以限制报文的流量只能是小于等于令牌生成的速度,达到限制流量的目的。

6.4.2 RBD令牌桶算法流程

步骤

  • 用户发起请求异步IO到达Image中。
  • 请求到达ImageRequestWQ队列中。
  • 在ImageRequestWQ出队列的时候加入令牌桶算法TokenBucket。
  • 通过令牌桶算法进行限速,然后发送给ImageRequest进行处理。

6.4.3 RBD令牌桶算法框架图

现有框架图:

令牌图算法框架图:

原文:https://www.jianshu.com/p/cc3ece850433 作者:李航

干货|非常详细的 Ceph 介绍、原理、架构 - 知乎


Ceph技术栈/学习图谱

CEPH架构图

分层架构

组织架构

 逻辑结构

Ceph FS

Ceph æ件系ç»ï¼åï¼ - æ中é¾è¾- åå¢å­

Ceph æ件å­å¨_diyuan8262çä¸æ -CSDNåå¢

cephå·¥ä½åçååè£â å°åIT

Ceph学习(æ¶æ) | Z.S.K.'s Records

An Integrated Indexing and Search Service for Distributed File Systems

An Integrated Indexing and Search Service for Distributed File Systems

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bandaoyu/article/details/111593001

智能推荐

已知num为无符号十进制整数,请写一非递归算法,该算法输出num对应的r进制的各位数字。要求算法中用到的栈采用线性链表存储结构(1<r<10)。-程序员宅基地

文章浏览阅读74次。思路:num%r得到末位r进制数,num/r得到num去掉末位r进制数后的数字。得到的末位r进制数采用头插法插入链表中,更新num的值,循环计算,直到num为0,最后输出链表。//重置,s指针与头指针指向同一处。//更新num的值,至num为0退出循环。//末位r进制数存入s数据域中。//头插法插入链表中(无头结点)//定义头指针为空,s指针。= NULL) //s不为空,输出链表,栈先入后出。

开始报名!CW32开发者扶持计划正式进行,将助力中国的大学教育及人才培养_cw32开发者扶持计划申请-程序员宅基地

文章浏览阅读176次。武汉芯源半导体积极参与推动中国的大学教育改革以及注重电子行业的人才培养,建立以企业为主体、市场为导向、产学研深度融合的技术创新体系。2023年3月,武汉芯源半导体开发者扶持计划正式开始进行,以打造更为丰富的CW32生态社区。_cw32开发者扶持计划申请

希捷硬盘开机不识别,进入系统后自动扫描硬件以识别显示_st2000dm001不认盘-程序员宅基地

文章浏览阅读5.7k次。2014年底买的一块2TB希捷机械硬盘ST2000DM001-1ER164,用了两年更换了主板、CPU等,后来出现开机不识别的情况,具体表现为:关机后开机,找不到硬盘,就进入BIOS了,只要在BIOS状态下待机半分钟左右再重启,硬盘就会出现。进入系统后,重启(这个过程中主板对硬盘始终处于供电状态),也不会出现不识别硬盘的现象。就好像是硬盘或主板上某个电容坏了一样,刚开始给硬盘通电的N秒钟内电容未能..._st2000dm001不认盘

ADO.NET包含主要对象以及其作用-程序员宅基地

文章浏览阅读1.5k次。ADO.NET的数据源不单单是DB,也可以是XML、ExcelADO.NET连接数据源有两种交互模式:连接模式和断开模式两个对应的组件:数据提供程序(数据提供者)&DataSetSqlConnectionStringBuilder——连接字符串Connection对象用于开启程序和数据库之间的连接public SqlConnection c..._列举ado.net在操作数据库时,常用的对象及作用

Android 自定义对话框不能铺满全屏_android dialog宽度不铺满-程序员宅基地

文章浏览阅读113次。【代码】Android 自定义对话框不能铺满全屏。_android dialog宽度不铺满

Redis的主从集群与哨兵模式_redis的主从和哨兵集群-程序员宅基地

文章浏览阅读331次。Redis的主从集群与哨兵模式Redis的主从模式全量同步增量同步Redis主从同步策略流程redis主从部署环境哨兵模式原理哨兵模式概述哨兵模式的作用哨兵模式项目部署Redis的主从模式1、Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。2、为了分担读压力,Redis支持主从复制,保证主数据库的数据内容和从数据库的内容完全一致。3、Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步。全量同步Redis全量复制一般发_redis的主从和哨兵集群

随便推点

mysql utf-8的作用_为什么不建议在MySQL中使用UTF-8-程序员宅基地

文章浏览阅读116次。作者:brightwang原文:https://www.jianshu.com/p/ab9aa8d4df7d最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后出现了一个离奇的错误:Incorrect string value: ‘😃 我用的是UTF-8编码的客户端,服务器也是UTF-8编码的,数据库也是,就连要保存的这个字符串“????..._mysql utf8的作用

MATLAB中对多张图片进行对比画图操作(包括RGB直方图、高斯+USM锐化后的图、HSV空间分量图及均衡化后的图)_matlab图像比较-程序员宅基地

文章浏览阅读278次。毕业这么久了,最近闲来准备把毕设过程中的代码整理公开一下,所有代码其实都是网上找的,但都是经过调试能跑通的,希望对需要的人有用。PS:里边很多注释不讲什么意思了,能看懂的自然能看懂。_matlab图像比较

16.libgdx根据配置文件生成布局(未完)-程序员宅基地

文章浏览阅读73次。思路:  screen分为普通和复杂两种,普通的功能大部分是页面跳转以及简单的crud数据,复杂的单独弄出来  跳转普通的screen,直接根据配置文件调整设置<layouts> <loyout screenId="0" bg="bg_start" name="start" defaultWinId="" bgm="" remark=""> ..._libgdx ui 布局

playwright-python 处理Text input、Checkboxs 和 radio buttons(三)_playwright checkbox-程序员宅基地

文章浏览阅读3k次,点赞2次,收藏13次。playwright-python 处理Text input和Checkboxs 和 radio buttonsText input输入框输入元素,直接用fill方法即可,支持 ,,[contenteditable] 和<label>这些标签,如下代码:page.fill('#name', 'Peter');# 日期输入page.fill('#date', '2020-02-02')# 时间输入page.fill('#time', '13-15')# 本地日期时间输入p_playwright checkbox

windows10使用Cygwin64安装PHP Swoole扩展_win10 php 安装swoole-程序员宅基地

文章浏览阅读596次,点赞5次,收藏6次。这是我看到最最详细的安装说明文章了,必须要给赞!学习了,也配置了,成功的一批!真不知道还有什么可补充的了,在此做个推广,喜欢的小伙伴,走起!_win10 php 安装swoole

angular2里引入flexible.js(rem的布局)_angular 使用rem-程序员宅基地

文章浏览阅读1k次。今天想实现页面的自适应,本来用的是栅格,但效果不理想,就想起了rem布局。以前使用rem布局,都是在原生html里,还没在框架里使用过,百度没百度出来,就自己琢磨,不知道方法规范不规范,反正成功了,操作如下:1、下载flexible.js2、引入到angular项目里3、根据自己的需要修改细节3.1、在flexible.js里修改每份的像素,3.2、引入cssrem插件,在设置里设..._angular 使用rem

推荐文章

热门文章

相关标签