背景
云主机创建有两种方式, 一种通过镜像下载来创建, 另一种通过快照回滚来创建, 前者是通用的传统方式, 后者依赖于 CBS 云盘能力 随着 CBS 云盘使用越来越广泛, 腾讯云主机创建也由原来的镜像下载切换到 CBS 云盘快照回滚模式
通过传统镜像下载的方式来创建云主机, 在云主机拉起前, 需要将整个镜像文件都下载到宿主机上, 所以云主机的创建时间很大程度上依赖所选取的镜像和当时下载镜像的带宽当遇到比较大的镜像时, 云主机创建时间经常会达到几百秒, 这样的用户体验不是太好; 另外, 当批量创建时, 需要消耗大量的内网带宽资源, 需要在尽量占用网络带宽的同时做好 Qos, 保证不影响用户的正常使用
使用云盘快照回滚的方式来创建云主机, 不需要提前下载镜像, 而是在云主机拉起时, 优先将要访问的数据从快照系统搬迁到 CBS 云盘系统中 我们观察到, 云主机拉起过程中访问的数据量和镜像大小并不是严格的线性关系, 即便是较大的镜像, 在云主机拉起时也只会访问到很少一部分数据, 搬迁流程如下:
图 1. 云盘快照数据搬迁流程
当有快照回滚请求时, 我们首先会在后台启动一个任务, 将快照数据按顺序从 COS 读出写入到存储池中, 同时我们不会阻碍用户对回滚磁盘的正常读写 当有用户请求过来时 (步骤 1), 会先在 driver 中检查对应 lba 的快照数据是否已经被写入, 如果写入则 IO 直接下发 (步骤 7), 否则, 会阻塞 IO 并先给 scheduler 发送 trigger 请求 (步骤 3),scheduler 会优先将 trigger 请求处理, 交给搬迁模块将对应的快照数据从 COS 读出, 写入到存储池 (步骤 345), 等写入完毕后, scheduler 先记录搬迁 bitmap 到 zk 并给 driver 返回 trigger response 和当前的快照数据回滚进度 (步骤 6),driver 收到后则不再阻塞 io, 让其正常下发 (步骤 7)
聚焦延迟和并发, 云主机创建优化之路
云盘快照回滚优先搬迁关键数据这种机制为我们批量创建云主机奠定了基础, 在此基础上, 我们还围绕着延迟和并发这两点做了一系列优化
transfer 增加 cache
子机批量创建时, 经常是使用同一个镜像克隆出几百或上千台子机, 如果所有数据都从 COS 系统拉取, 对 COS 的读压力会非常大, 会触发 COS 的 Qos 流控为了让批量创建时读取镜像的流量不再受限于 COS 的带宽, 我们在 transfer 中增加了 cache, 每个 transfer 中都缓存镜像的部分数据块, 一旦命中 transfer 的 cache 就不再从 COS 拉取数据, 这样每个 transfer 只需拉取一次镜像; 当 cache 流量达到瓶颈时, 可以通过临时增加节点来增加带宽, 具备水平扩展能力
在增加了 cache 后, 我们对 transfer 部署也做了优化, 每个 zone 都部署了若干个节点, 当有数据块搬迁请求时, 任务总是会优先落到和 CBS 盘底层存储节点相同 zone 的 transfer 上, 这样就可以实现就近搬迁
通过 cache 优化, 可以将单个数据块的搬迁耗时从 100+ms 降低到 10+ms, 大大降低了 IO 延迟
图 2. transfer cache
scheduler 性能优化
在快照回滚创建云主机过程中, 核心处理逻辑在 scheduler, 因为 client 端每个 IO trigger 请求都要经过 scheduler, 并且由于每个由 trigger 触发的快照数据块搬迁都要在 zk 里记录起来, 所以 scheduler 的负载以及 zk 写入能力会直接影响到整个快照系统的吞吐
首先, 我们优化了 scheduler, 将请求接收处理以及与后端交互部分的逻辑拆开来, 形成流水线, 尽量减少因某个请求处理慢导致其他请求排队的情况, 每个部分都由一个线程池来并行处理, 尽量将整机的计算能力利用起来;
其次, 针对 zk 写入压力大的问题, 我们将写入 zk 的数据做了分类, 变化不频繁的一些元数据还是写入 zk; 而记录 trigger 搬迁状态的那些元数据, 需要频繁修改, 这部分数据不适合存 zk, 我们将其 offload 到一个 qps 更高的存储系统上, 这样一来, scheduler 的处理能力得到了成倍的增长
另外, 为防止回滚的流量影响到其他用户对磁盘的正常使用, 我们在 scheduler 做了必要的 Qos 首先限制落到同一个副本组的回滚带宽, 在整个副本组带宽空闲时, 回滚流量不能超过限制; 而当整个副本组的带宽达到上限时, 回滚带宽会自动回退, 优先保证用户的正常 IO 延迟其次, 当同时有顺序搬迁任务和 trigger 请求任务时, 优先处理 trigger 请求任务, 保证用户体验
最后, 我们通过对 scheduler 改造, 做到水平可扩展, 使其不再成为性能瓶颈
来源: https://www.cnblogs.com/ccloud/p/8609955.html