Ceph 和 OpenStack 是一个非常有用和非常受欢迎的组合. 不过, 部署 Ceph / OpenStack 经常会有一些容易避免的缺点 - 我们将帮助你解决它们.
技术沙龙 | 4 月 21 日多位区块链专家进行区块链技术应用场景解读!
使用 ceph 作为存储的 openstack, 看到一篇非常非常有价值的文章, 这篇文章整理了 openstack 结合 ceph 的最佳方式, 包括了一些 openstack 使用 ceph 后的参数优化, 以及 SSD OSD 磁盘的使用方式建议, 一些 pool 池的使用建议, 解答了相当一部分的疑惑.
Ceph 和 OpenStack 是一个非常有用和非常受欢迎的组合. 不过, 部署 Ceph / OpenStack 经常会有一些容易避免的缺点 - 我们将帮助你解决它们.
使用 show_image_direct_url and the Glance v2 API
使用 ceph 的 RBD(RADOS Block Device), 你可以创建克隆, 你可以将克隆理解为可写的快照(快照通常是只读的). 克隆只会为相对于父快照变化的部分创建对象, 这意味着:
可以节省空间. 这是显而易见的, 但是这并不能很有说服力, 毕竟存储是分布式系统当中最便宜的部分
克隆中没有修改的部分还是由原始卷提供. 这很重要, 因为很容易命中相同的 RADOS 对象, 相同的 osd, 不论是用的哪个克隆. 而且这意味着, 这些对象是从 OSD 的页面缓存进行响应, 换句话说, 是 RAM 提供. RAM 比任何存储访问方式速度都快, 所以从内存当中提供大量的读取是很好的. 正因为这样, 从克隆的卷提供数据读取, 要比相同数据全拷贝的情况下速度要快一些
Cinder(当从 image 创建一个卷)和 Nova(从 ceph 提供临时磁盘)都能够使用 ceph 的后端的 RBD image 的克隆, 并且是自动的, 但这个只有在 glance-api.conf 中设置了 show_image_direct_url=true 才会使用, 并且配置使用 Glance v2 API 进行连接 Glance.
设置 libvirt/images_type = rbd on Nova compute nodes
在 NOVA 中 (使用 libvirt 的 KVM 计算驱动), 有几个存储临时镜像的配置, 不从 Cinder 卷启动的情况. 你可以设置 nova?compute.conf 的[libvirt] 当中的 images_type:
- [libvirt]
- images_type =
默认的类型是磁盘, 这意味着你启动一个新的 vm 的时候, 将会发生下面的事:
nova-compute 在你的虚拟机管理节点上链接到 Glance API, 查找所需要的 image, 下载这个 image 到你的计算节点, 默认在 / var/lib/nova/instances/_base 路径下
然后会创建一个 qcow2 文件, 使用下载的这个 image 做它的 backing file
这个过程在计算节点上会占用大量的空间, 并且会一旦这个镜像没有提前在计算节点上下载好, 就会需要等很久才能启动虚拟机, 这也使得这样的 vm 不可能实时的迁移到另外一台主机而不产生宕机时间
将 images_types 设置为 rbd 后意味着 disk 是存储在 rbd 的后端的, 是原始镜像的克隆, 并且是立即创建的, 没有延时启动, 没有浪费空间, 可以获得所有克隆的好处, 参考文档
在 Nova 计算节点上启用 RBD 缓存
librbd 是支持 Qemu / KVM RBD 存储驱动程序的 ceph 的库, 可以使用虚拟化主机的 RAM 进行磁盘的缓存. 你应该使用这个.
是的, 它是一个可以安全使用的缓存. 一方面, virtio-blk 与 Qemu RBD 驱动程序的组合将正确地实现磁盘刷新. 也就是说, 当虚拟机中的应用程序显示 "我现在想在磁盘上存储此数据" 时, virtio-blk,Qemu 和 Ceph 将一起工作, 只有在写入完成时才会报告
写入主 OSD
复制到可用的副本 OSD
只是写入所有的 osd journal 才会 acknowledged
此外, Ceph RBD 具有一个智能保护: 即使它被配置为 write-back 缓存, 它也将拒绝这样做(这意味着它将 write-through 模式操作), 直到它接收到用户的第一次 flush 请求. 因此, 如果你运行一个永远不会这样做的虚拟机, 因为它被错误配置或者它的客户操作系统很老的, 那么 RBD 将固执地拒绝缓存任何写入. 相应的 RBD 选项称为 rbd cache writethrough until flush, 它默认为 true, 你不应该禁用它.
你可以通过修改 nova-compute 配置文件的下面选项开启 writeback caching
- [libvirt]
- images_type = rbd
- ...
- disk_cachemodes="network=writeback"
你应该这样去做
为 images, volumes, and ephemeral disks 使用单独的池
现在你已经在 Glance 开启了 enabled show_image_direct_url=true, 配置 Cinder and nova-compute 与 Glance 交互 的时候使用 v2 API, 配置 nova-compute 使用 libvirt/images_type=rbd, 所有的 VMs 和 volumes 都使用 rbd 克隆, 克隆可以跨存储进行, 意味着你可以创建 RBD image(已经快照)在一个存储池, 然后它的克隆在另外一个存储池
你应该这样做, 有几个原因:
单独的池意味着您可以分别控制对这些池的访问. 这只是一个标准的缓解危险方法: 如果您的 nova-compute 节点被攻破, 并且攻击者可以损坏或删除临时磁盘, 那么这是坏的 - 但如果他们也可能损坏您的 Glance 图像那将会更糟.
单独池也意味着您可以有不同的池设置, 例如 size 或 pg_num 的设置.
最重要的是, 单独的池可以使用单独的 crush_ruleset 设置. 下面我们会做介绍
通常有三个不同的池: 一个用于 Glance 图像(通常命名为 glance 或图像), 一个用于 Cinder 卷(cinder 或卷), 一个用于 VM(nova-compute 或 vms).
不需要使用 SSD 作为你的 Ceph OSD journal
在这篇文章的建议中, 这一个可能是最令人感觉到奇怪和不认可的. 当然, 传统的情况下都会认为, 你应该总是把你的 OSD journal 在更快的设备上, 并且你应该以 1:4 到 1:6 的比例部署 ssd 和普通磁盘, 对吧?
让我们来看看. 假设你是按 1:6 的配比方法, 你的 SATA 转盘能够以 100 MB/s 的速度写. 6 个 OSD, 每个 OSD 使用企业 SSD 分区上的分区作为. 进一步假设 SSD 能够以 500MB/s 写入.
恭喜你, 在那种情况下, 你刚刚使你的 SSD 成为瓶颈. 虽然你的 OSDs 聚合带宽支持 600 MB / s, 你的 SSD 限制你大约 83%的性能.
在这种情况下, 你实际上可以用 1:4 的比例, 但使你的聚合带宽只快了一点点, SSD 的没有很大的优势
现在, 当然, 考虑另一种选择: 如果你把你的 journal 放在 OSD 相同的设备上, 那么你只能有效地使用一半的驱动器的标称带宽, 平均来说, 因为你写两次到同一设备. 所以这意味着没有 SSD, 你的有效单个 osd 带宽只有大约 50 MB/s, 所以你从 6 个驱动器中得到的总带宽更像是 300 MB/s, 对此, 500MB/ s 仍然是一个实质性的改进.
所以你需要将自己的配比匹配到上面的计算当中, 并对价格和性能进行自己的评估. 只是不要认为 SSD journal 将是万灵药, 也许使用 ssd 算是一个好主意, 关键在于比较
使用 all-flash OSDs
有一件事要注意, 你的 SSD journal 不会提高读. 那么, 怎样利用 SSD 的提高读取呢?
使用 ssd 做 OSD. 也就是说, 不是 OSD journal, 而是具有文件存储和 journal 的 OSD. 这样的 ssd 的 OSD 不仅仅是写入速度快, 而且读取也会快.
将 all-flash OSDs 放入独立的 CRUSH root
假设你不是在全闪存硬件上运行, 而是运行一个经济高效的混合集群, 其中一些 OSD 是普通的, 而其他是 SSD(或 NVMe 设备或其他), 你显然需要单独处理这些 OSD. 最简单和容易的方法就是, 除了正常配置的默认根之外再创建一个单独的 CRUSH 根.
例如, 您可以按如下所示设置 CRUSH 层次结构:
- ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
- -
- -1 4.85994 root default
- -2 1.61998 host elk
- 0 0.53999 osd.0 up 1.00000 1.00000
- 1 0.53999 osd.1 up 1.00000 1.00000
- 2 0.53999 osd.2 up 1.00000 1.00000
- -3 1.61998 host moose
- 3 0.53999 osd.3 up 1.00000 1.00000
- 4 0.53999 osd.4 up 1.00000 1.00000
- 5 0.53999 osd.5 up 1.00000 1.00000
- -4 1.61998 host reindeer
- 6 0.53999 osd.6 up 1.00000 1.00000
- 7 0.53999 osd.7 up 1.00000 1.00000
- 8 0.53999 osd.8 up 1.00000 1.00000
- -5 4.85994 root highperf
- -6 1.61998 host elk-ssd
- 9 0.53999 osd.9 up 1.00000 1.00000
- 10 0.53999 osd.10 up 1.00000 1.00000
- 11 0.53999 osd.11 up 1.00000 1.00000
- -7 1.61998 host moose-ssd
- 12 0.53999 osd.12 up 1.00000 1.00000
- 13 0.53999 osd.13 up 1.00000 1.00000
- 14 0.53999 osd.14 up 1.00000 1.00000
- -8 1.61998 host reindeer-ssd
- 15 0.53999 osd.15 up 1.00000 1.00000
- 16 0.53999 osd.16 up 1.00000 1.00000
- 17 0.53999 osd.17 up 1.00000 1.00000
在上面的示例中, OSDs 0-8 分配到默认根, 而 OSDs 9-17(我们的 SSD)属于根 highperf. 我们现在可以创建两个单独的 CRUSH rule:
- rule replicated_ruleset {
- ruleset 0
- type replicated
- min_size 1
- max_size 10
- step take default
- step chooseleaf firstn 0 type host
- step emit
- }
- rule highperf_ruleset {
- ruleset 1
- type replicated
- min_size 1
- max_size 10
- step take highperf
- step chooseleaf firstn 0 type host
- step emit
- }
默认 crush rule 是 replicated_ruleset, 从默认根选择 OSD, 而 step take highperf 在 highperf_ruleset 当中意味着它只会选择在 highperf 根的 OSD.
为存储池池指定 all-flash rule
将单个池分配给新的 CRUSH crule(并因此分配给不同的 OSD 集), 使用一个命令:
ceph osd pool set crush_ruleset
... 其中是池的名称, 是您的 CRUSH RULE 的 ID. 你可以在线执行此操作, 而客户端正在访问其数据 - 当然会有很多 remapped 和 backfill, 因此您的整体性能会受到一些影响.
现在, 假设你的环境普通存储比 SSD 存储更多. 因此, 您将需要为 all-flash OSD 选择单独的池. 这里有一些池可以先迁移到 all-flash. 您可以将以下列表解释为优先级列表: 在向群集添加更多 SSD 容量时, 可以逐个将池移动到全闪存存储.
Nova ephemeral RBD 池(vms,nova-compute)
radosgw bucket indexes .rgw.buckets.index and friends) - 如果你使用 radosgw 替换你 OpenStack Swift
Cinder volume pools (cinder, volumes)
radosgw data pools (.rgw.buckets and friends) - 如果您需要在 Swift 存储上进行低延迟读取和写入
Glance image pools (glance, images)
Cinder backup pools (cinder-backup) - 通常是这是最后一个转换为 all-flash 的池.
配置一些具有低延迟本地存储的非 Ceph 计算主机
现在, 毫无疑问, 有一些应用场景, Ceph 不会产生你所需要的延迟. 也许任何基于网络的存储都无法满足. 这只是存储和网络技术最近发展的直接结果.
就在几年前, 对块设备的单扇区非缓存写入的平均延迟大约为毫秒或 1000 微秒 (μs). 相比之下, 在承载 512 字节(1 扇区) 有效载荷的 TCP 分组上引起的延迟大约为 50μs, 这使得 100μs 的往返行程. 总而言之, 从网络写入设备 (而不是本地写入) 所产生的额外延迟约为 10%.
在过渡期间, 对于相同价格的器件的单扇区写入本身约为 100μs, 顶级的, 一些价格还是合理的设备下降到约 40μs. 相比之下, 网络延迟并没有改变那么多 - 从千兆以太网到 10 GbE 下降约 20%.
因此, 即使通过网络访问单个未复制的 SSD 设备, 现在的延迟将为 40 + 80 = 120μs, 而本地仅为 40μs. 这不是 10%的开销了, 这是一个惊人的三倍
使用 Ceph, 这变得更糟. Ceph 多次写入数据, 首先到主 OSD, 然后 (并行) 写入所有副本. 因此, 与 40μs 的单扇区写操作相比, 我们现在至少有两次写操作的延迟, 再加上两次网络往返, 即 40×2 + 80×2 =240μs, 是本地写延迟的 6 倍
好消息是, 大多数应用程序不关心这种延迟开销, 因为它们延迟不是关键的. 坏消息是, 有些非常在意.
所以, 你应该放弃 Ceph 因为这样吗? 不. 但是请考虑添加一些未使用 libvirt / images_type = rbd 配置的计算节点, 而是使用本地磁盘映像. 将这些主机进行主机聚合, 并将它们映射到指定的 flavor. 建议您的用户, 他们选择这种 flavor 来跑低延迟的应用程序.
来源: http://stor.51cto.com/art/201804/570355.htm