八旗云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 111|回复: 1

论文笔记:阿里云盘古 2.0 存储系统

[复制链接]

1

主题

1

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2023-4-19 19:29:17 | 显示全部楼层 |阅读模式
摘要

阿里云盘古存储系统在近几年发表了多篇论文。本文记录自己的一点阅读笔记和心得。
盘古 2.0 论文:More Than Capacity: Performance-oriented Evolution of Pangu in Alibaba (FAST '23)
盘古(Pangu)是阿里云存储系统,为上层的所有应用提供基础服务。
这篇论文讲述了盘古自 2016 年以后的不断更新发展,盘古从追求容量的 1.0 时代向追求高性能与低时延的 2.0 时代转型。这篇论文更侧重于工程实践,揭示了很多实践中出现的问题,并应用了大量的前沿技术,为读者提供了一个完整的存储系统的 design choices。
技术要点:
1. 用户态操作系统,减少内核切换开销,减少数据拷贝。
2. Append-only 文件系统,充分利用局部性,可回放的特性。
3. Hardware & Software co-design,部分功能硬件卸载。
背景

2015 年以前,盘古 1.0 以 HDD 硬盘为主要存储介质,并使用传统 Ethernet/IP 网络进行分布式互联。近年来,计算机硬件不断更迭,更高速的 NVMe SSD 发展迅速,RDMA 网络技术日趋成熟。在更高性能的业务的要求下,盘古应用新兴的硬件和技术推出了 2.0 版本。
如今,盘古的设计目标有以下三点:
1. 低时延——百微秒级的 IO 平均时延,毫秒级的 P999 尾时延。
2. 高吞吐。
3. 对上层服务(如 EBS、OSS、数据库)提供统一的底层抽象。
盘古设计架构




盘古架构

盘古的总体架构如图所示,本篇论文介绍了其中 Pangu Core 的设计。
盘古系统由三部分组成,ClientChunkserverMaster,其中 Client 和 Chunkserver 是论文的重点。

  • Pangu Client: 上层应用服务通过 SDK 向 Client 提出对盘古系统的任务请求,Client 随后负责与 Master 和 Chunkserver 通信来完成任务请求。
  • Chunkserver: 文件被抽象为 stream,stream 由许多个 chunk 组成,这些 chunk 会分散存储在多个 Chunkserver 上。
  • Master: 管理 metadata,提供 namespace 服务和 stream 服务。namespace 服务主要包括对文件目录树和命名空间的维护;stream 服务维护对 chunk 的索引等。采用基于 Raft 的一致性协议。
Monitoring 系统对应了另一篇论文 Perseus,此外还有一篇 Fisc 介绍了 Cloud-native 的文件系统。
Client 设计

Client 采用 heavyweight 的设计理念,负责的任务较多,包括回复上层应用请求、为 Master 提供更新、管理数据备份、满足 SLA(Service Level Agreement)。
与 Master 的通信

当上层应用向 Client 提出任务请求时,Client 需要首先向 Master 通信查找相关 metadata,从而得知数据在哪几个 Chunkserver 上。为提高效率,论文提出了如下几点技术方案:

  • Aggregation:Client 将一个较短时间内的所有向 Master 的请求进行聚合,从而减少通信次数。Master 收到一批请求后,进行并行处理,返回一批结果。Client 收到结果后进行 demultiplexing。
  • Cache:Client 会将已获得的 metadata 进行缓存。
  • Prefetching:Master 不仅仅回答 Client 请求的 chunk 的 metadata,还会额外回复相关的 chunk 的 metadata,即利用数据局部性减少请求次数。
  • Data pggybacking:QUIC 和 HTTP 3 的思路,将一些控制请求与数据请求合并,例如对 Chunkserver 提出创建 chunk 请求和写入数据请求可以合并成一个请求一次发送。
与 Chunkserver 的通信

Client 获得 metadata 后,与 Chunkserver 进行通信,进行数据读取/更新。这里为满足 SLA,即满足上层服务的低时延要求,提出了如下设计。
数据需要在多个 Chunkserver 上进行备份,由 Client 分别进行写入,对某一台 Chunkserver 写入成功时,会收到 Success 的回复。实际往往采用三份备份。

  • Chasing
写数据时,Client 如果成功写入了 3 台 Chunkserver,直接完成任务。如果成功写入了 2 台(超过半数),进入 Chasing 模式。此时,Client 把数据留在内存里(保证系统总有三份备份),然后等待一个毫秒级时间阈值,如果等待期间收到了第 3 台 Chunkserver 的 Success,就依然认为写入成功,释放内存。如果始终没有收到,此时观察当前剩余待写入数据量,如果小于一个预设阈值,就继续尝试写入,否则就告知 Master,让 Master 在后台换一个 Chunkserver 把数据拷贝过去。
2. Non-stop write
如果成功写入了仅仅 1 台 Chunkserver,就告知 Master 这部分数据没有写好,同时直接再找两个 Chunkserver 写接下来的数据,即 Non-stop。Master 在后台将刚刚仅写了一份的数据复制到额外的两个 Chunkserver 上进行备份。如果 3 台全部失败,那就无法 Non-stop write,只能老老实实再找 3 台 Chunkserver 重新写,而这也是个很低概率的事件了。
3. Backup read
如果 Client 向 Chunkserver 发起读取请求后一段时间没有收到回复,直接向备份 Chunkserver 发起读请求,通过激进的读取来降低时延。这个时间阈值是根据硬盘类型、网络协议、IO 请求大小来动态计算,细节未披露。
4. Blacklisting
设置两组黑名单。挂掉的 Chunkserver 列入 deterministic blacklist(确定性黑名单),而回复时延超过一定阈值的 Chunkserver 根据这个时延大小按一定概率放入 non-deterministic blacklist(非确定性黑名单)。Client 定期检查可否将 Chunkserver 移出黑名单。由于 TCP 和 RDMA 协议使用的网卡和链路可能是不同的,因此它们要分别设立黑名单。
可以看到,总体来说采用了较为激进的设计思路来降低时延,使用冗余换时间。
Chunkserver 设计

Chunkserver 是直接存储数据的节点。其上运行了一个用户态操作系统 USSOS(User-Space Storage Operating System)),重新设计了 OS 的基本功能。用户态 OS 通过 Kernel Bypass 直接让用户态程序管理硬件,避免了内核态/用户态切换开销,同时可以采用更针对性的定制化方案,对 Chunkserver 这种需要处理大量数据的 data-intensive 的应用来说比较合适。
实现方案使用 DPDK + SPDK + RDMA。
DPDK(Data Plane Development Kit)和 SPDK(Storage Performance Development Kit)分别是针对网络和存储的用户态程序开发工具包,实现用户态程序直接接管硬件,让数据通路避免通过内核繁杂的逻辑,通过定制逻辑可以减少上下文切换和数据拷贝,提高性能。
RDMA(Remote Direct Memory Access)则是将网卡(NIC)与 DMA 技术融合在了一起,RDMA 网卡可直接将本地内存数据通过网络传输到远端机器内存中,不需要两边的 CPU 处理网络协议栈,更不需要内核参与,实现了 kernel bypass(内核旁路) + hardware offload(硬件卸载)。
内存管理


  • Run-to-completion model: 即一个线程完成一波数据的全部处理逻辑,可以避免线程切换开销带来的时延、避免跨线程通信和同步,各自用自己的内存,数据局部性好,易开发。与之相对的是 Pipeline model(流水线),即一个线程完成一步任务,然后交给别的线程继续处理,这种方式扩展性更好,但也更复杂。
  • Huge-page memory(内存大页):普通 OS 通常使用 4KB 的页面大小,这样对于大量数据处理来说,会涉及很多的页面,带来很多的缺页,引入 IO,效率低。因此采用了 huge-page,使用 2MB 甚至 1GB 的页面大小。
  • Zero-copy(零拷贝):在存储协议栈和网络协议栈之间使用共享内存,再利用 RDMA 网卡对内存数据的直接读取与写入,实现数据通路全程零拷贝。
任务调度

由于使用了 Run-to-completion model,每个 Chunkserver 上是固定数量的线程数,当有任务时,根据请求的哈希值均匀分配到某个线程上。
饥饿问题:如果一个请求的任务需要过多的时间来完成(如查表、遍历表、分配内存等),同样对应了这个线程的后续任务就会被阻塞,产生饥饿,导致部分任务时延大大增加。
解决方案:

  • 通过心跳来监测一个任务运行了多久。
  • 使用 QoS,为每个请求设置优先级,进行优先级之间的隔离,高优先级先执行。
  • NAPI:借鉴 Linux 的 NAPI,采用 polling(轮询) + event-driven(事件驱动) 相结合的方式,网卡对应了一个文件描述符,当有任务到达时通过文件描述符触发中断唤醒网卡,即事件驱动,网卡处理任务,并进入轮询模式,不断询问是否还有后续任务,如果有则可以快速处理,无需进行中断处理;如果一段时间没有后续任务,就回到事件驱动模式,等待中断。
Append-only 文件系统

盘古实现了一个用户态文件系统 USSFS(User-Space Storage File System),其中提供了一个文件抽象 FlatLogFile。这个文件系统是 Append-only 的,即修改数据不会原地替换,而是通过不断添加日志的方式进行修改。Append-only 的顺序读写方式对 SSD 很友好,减少了随机读写,且不会重复擦写同一块区域,有利于提高硬盘寿命。日志积累到一定程度后,使用一个垃圾回收机制将结果整理,保存检查点。如果发生崩溃,也可以通过日志进行回放恢复。
所有的文件都会被切分成一个个 chunk 进行物理存储,与其它分布式文件系统的基本思想是一致的。特别的,chunk 的 metadata 与数据是连续存储的,而不是像传统文件系统一样是分开存储的。这样的好处是可以一次操作同时更新 metadata 和数据,而不必使用两次操作。Chunk 的大小并不是固定的,而是从 1MB 到 2GB 不等。这个思路与早先的 OS 内存管理机制是一样的。



Chunks 示意图(Footer 就是 metadata)

新的瓶颈

以上完成了一个基本成形的盘古系统,但随着实际的运行,网络、内存、CPU 成为了新的瓶颈。例如如果一个服务器装载了 12 个 SSD,可提供 36 GB/s 的读速度和 9.6 GB/s 的写速度。这样的速度对网络、内存乃至 CPU 的性能都提出了挑战。
网络瓶颈

首先网络带宽已经从 25 Gbps 升级到 100 Gbps。网络协议大量使用基于 RDMA 的 RoCEv2 协议而非传统 TCP。在 NSDI '21 中,曾有一篇论文介绍其 RDMA 网络。此前盘古使用的是无损网络,即通过流量控制算法在网络中进行速率控制,避免交换机缓冲区溢出导致丢包,但无损流量控制会产生头阻(Head-of-line blocking),且会产生暂停帧风暴,不利于大规模部署。如今,已改为有损网络,即允许网络中发生丢包,但具体实现未披露,推测使用了类似 IRN 的技术。
此外,还对流量进行了优化,即减少需要传输的数据量。

  • 使用 Erasure Coding。这是一种在需要多备份存储的场景下可以减少总存储空间的编码方式。一个简单的例子是,想要存储 data = 95,令 x = 9、y = 5,于是可以联立三个方程 x + y = 14、x - y = 4、2x + y = 23,那么实际存储时,不再直接存三份 95,而是存储三个方程,而只需要任意两个方程就可以恢复出原本的数据。通过良好的设计,可以使得存储三个方程所需的空间小于三份数据所需的空间,从而减少对网络带宽的要求。
  • 进行压缩,LZ4 算法。
  • 动态带宽分配,白天为业务流量预留较多带宽,夜晚为背景流量(如垃圾回收机制)提供较多带宽。
内存瓶颈

1. 相比一整块较大的内存,更倾向于使用多块较小容量的内存以充分利用内存通道的带宽,且充分利用 NUMA 架构。
2. 以往 RDMA 仅在传输时延敏感流时使用、背景流使用 TCP,如今对背景流量也使用 RDMA 传输,提高传输效率。
3. Remote Direct Cache Access (RDCA),网卡直接与 CPU LLC Cache 通信,跳过内存:
动机:网卡的传输速率达到了 100 Gbps,且硬件处理速度极快,因此准备好的待发送数据其实只会在内存中停留一小会儿就会被发送出去,接收数据亦然。因此,只需要几 MB 级别的内存空间即可完成大量数据的传输。而 MB 级别的空间大小,可直接利用 CPU 的 LLC Cache 进行存储,跳过内存。RDCA 就是让网卡直接从 LLC Cache 中读取数据发送,避免经过内存,接收数据时,直接写入 LLC Cache,CPU 直接处理,从而打破了内存瓶颈的限制。
方案:

  • 设置 Cache 内缓冲池,并行数据处理提高处理速度,结合硬件卸载进一步加速(下文介绍)。
  • 震荡发生时(即偶尔处理速度变慢,导致 Cache 缓冲池不够用),临时分配额外的 Cache 缓冲块用来做缓冲,如果仍然不足,通过 ECN 对网络进行反压。
实现:利用了 Intel DDIO 技术。
CPU 瓶颈

CPU 需要处理大量数据的序列化/反序列化、数据压缩、CRC 校验码计算,这带来了极大的计算资源消耗。盘古从以下几点进行优化:

  • 混合 RPC 序列化算法。控制信息使用 Protobuf 序列化与反序列化,数据则使用 FlatBuffer,后者在序列化后存储了一定的结构信息,有利于提高读取效率,因此适合大量的数据。
  • 超线程(Hyper Thread)管理。论文发现,Intel 的超线程技术(硬件实现单个物理核双超线程提供两个逻辑核)在高性能场景下存在同核超线程之间的相互干扰,因此利用 CPU wait 指令对超线程进行控制。具体来说,monitormwait 指令可实现线程睡眠并监听某处内存,直到该处内存改变才被唤醒,由此强迫超线程睡眠。
  • 硬件卸载。将数据压缩的逻辑卸载到 FPGA 硬件上,将 CRC 计算通过硬件逻辑集成在网卡上,由此让压缩和 CRC 计算由专用硬件来完成,释放了 CPU 资源。
总结与思考

论文并没有创造什么独一无二的新技术,但其揭示了许多工程实践中会遇到的问题,并且将现有的前沿工程技术融会贯通,形成了一组可行的方案,非常值得学习。
盘古为追求低时延,总体比较激进,大量使用空间换时间、超发、冗余的设计思路,因此带来了 CPU、内存和网络的瓶颈,又通过更为前卫的方式消除这些瓶颈。这其中必然存在许多可以 tradeoff 的部分,同时一些处理方案比较简单粗暴,针对细节技术有很多的可优化空间。
回复

使用道具 举报

1

主题

3

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2023-4-19 19:29:59 | 显示全部楼层
请问一下,简单粗暴的点是什么,细节优化指哪些呢[蹲]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|八旗云

GMT+8, 2025-10-11 19:47 , Processed in 0.090947 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表