文章/pangu-performance-oriented-evolution
27 分钟阅读
阿里盘古性能导向的演进
梳理阿里盘古从容量优先到性能导向的架构演进。
More Than Capacity: Performance-oriented Evolution of Pangu in Alibaba
摘要
本文介绍了盘古存储系统如何随着硬件技术的发展和商业模式的变化进行演进,以提供高性能、高可用的存储服务。IO 延迟达到 100us 的水平。 发展分为两阶段:
- 迎接 SSD 和 RDMA,大幅降低 io 延迟,提供高吞吐高 iops
- 容量导向转变为性能导向
- 使用更大的 ssd
- RDMA 25GbE 升级为 100GbE
- 引入了一系列关键设计:
- 减少流量放大
- 远程缓存直接访问
- CPU 计算卸载
简介
- 承载阿里核心业务(电商、支付)
- 万亿文件、EB 级别容量
盘古 1.0:面向容量
2009-2015 HDD,延迟毫秒级 网络,Gbps 级别 盘古 1.0 基于 ext4 和内核态 TCP 性能达到了 HDD 和 Gbps 网络的极限 用户此时关注于获得大量空间,而不是高性能
盘古 2.0
2015 开始,开发盘古 2.0 目标:提供高性能存储服务 延迟 100us 级别 观察到:
- 盘古 1.0 中使用的多种文件类型,特别是允许随机访问的文件类型在 ssd 上表现不佳。ssd 可以在顺序操作上实现高吞吐和 iops
- 由于数据复制和频繁中断,内核空间软件栈无法跟上 ssd 和 rdma 的高 iops 和低延迟
- the paradigm shift from server-centric datacenter architectures to resource-disaggregated datacenter architectures poses additional challenges to achieving low I/O latency
- 数据中心架构发生转变:以服务器为中心 -> 资源分离的数据中心架构
第一阶段
- 设计了一个统一的,append-only 的持久化层
- 引入自包含分块布局 (a self-contained chunk layout)
- 以降低文件写入的 io 延迟
- 设计了一个用户空间的存储操作系统 USSOS - run-to-completion 的线程模型,实现用户空间存储栈和用户空间网络栈之间的高效协作 - 用户空间的调度机制,实现足够的 CPU 和内存资源分配 - 动态 SLA 保证机制 实现 P 999 毫秒级 io 延迟
第二阶段
适应以性能为导向的商业模式,进行基础设施更新,突破网络/内存/CPU 瓶颈 2018 以来,越来越多的企业将业务转移到阿里云,他们对存储性能和延迟有严格要求。 新冠以来转变更快。 沿着基于 clos 的拓扑(如 FatTree 结构)用原有的服务器和交换机扩展不够经济:高总成本(空间、电力、冷却、劳动力),高环境成本(碳排放)。因此盘古开发了内部的高容量存储服务器(每台 96TB SSD),25GbE 升级到 100GbE。 提出一系列技术应对性能瓶颈,充分利用资源:
- 降低网络流量放大率,动态调整流量优先级
- RDCA:远程直接缓存访问应对内存瓶颈
- 消除序列化反序列化
- 引入 CPU wait 指令,在超线程间同步解决 CPU 瓶颈
小结
一阶段结束时,盘古 2.0 成功支持弹性 SSD 块存储服务,延迟在 100us 级别,iops 一百万。2018 双十一,盘古 2.0 支持阿里数据库延迟为 280us。对于 OTS 存储,他在盘古 2.0 中的延迟比在 1.0 中低一个数据级。写密集服务(如 EBS 云盘),P 999 的延迟小于 1ms。对于读密集型服务(在线搜索),P 999 低于 11ms。 第二阶段,网络从 2 x 25 Gbps 升级到 2 x 100 Gbps,突破了网络内存和 CPU 的瓶颈,每台 taishan 存储服务器(normalize)吞吐增加 6.1 倍。
背景
盘古的概述

由 Pangu Core、Pangu Service、Pangu Monitoring System 组成,通过高速网络相互连接。
Pangu Core:提供了 append-only 持久化语义。
- client:heavyweight client,为 service 提供 SDK,接收文件请求,与 master 和 chunkserver 通信响应请求。实现副本管理、SLA 保证、数据一致性。
- master:元数据服务,基于 Raft。
- 分解为两个服务,namespace 服务和 stream meta 服务。stream 是一组块的抽象。这两个服务通过目录树划分元数据(实现元数据局部化)、使用 hashing 实现负载均衡。namespace 服务提供文件信息(目录树、namespace(应该是多租户的概念?)),stream meta 提供文件到 chunks 的映射(比如 chunk 的位置)。
- chunkserver:以 chunk 形式存储数据,配备一个用户空间存储系统 USSFS
- USSFS 为不同硬件提供高性能、append-only 的存储引擎
- 比如用于叠瓦盘的 SMRstore
- 盘古 2.0 一阶段中,每个文件三副本,后来引入垃圾收集 GCworker,EC 存储文件
- 盘古 2.0 二阶段中,关键业务使用 EC 取代三副本,降低流量放大。
- USSFS 为不同硬件提供高性能、append-only 的存储引擎
基于 Pangu Core,提供传统的云存储服务(EBS、OSS、NAS),以及面向云的文件系统 Fisc。
Pangu Monitoring System(监控系统)
- 比如 Perseus 为 Pango core 和 Pangu service 提供实时监控,和 AI 辅助的 root cause 分析服务
设计目标
- 低延迟
- 平均 100us
- 即使有网络抖动和服务器故障也提供 ms 级别 P999 SLA
- 高吞吐:吃满硬件
- 统一的高性能底座

阶段一
Append-only fs
盘古的持久层提供了与盘古所有存储服务(如 EBS、OSS 和 NAS)的接口。 在盘古的早期开发中,持久层为不同的存储服务提供不同的接口。 例如:它为低延迟的 NAS 服务提供 LogFile 接口,为高吞吐量的 Maxcompute 数据分析服务提供 TempFile 接口。 然而,这种设计带来了大量的开发和管理的复杂性。具体来说,对于每一个存储服务,盘古的开发人员都必须设计和实现一个新的接口。这是一个复杂的、劳动密集型的、容易出错的过程。 为了简化开发和管理,引入了统一的文件类型:FlatLogFile 盘古的开发者必须确保通过 FlatLogFile 进行的数据操作,尤其是写操作,能够在存储介质上高效、可靠地执行。因此,所有的的升级和改变对盘古的开发者来说是透明的。储存服务的升级和改变对盘古开发人员来说是透明的,这大大简化了盘古的开发丰富了盘古的开发和管理。 为了确保通过 FlatLogFile 进行的数据操作能够在 SSD 上有效执行,我们对 FlatLogFile 的顺序操作进行了对齐以实现高性能。
Heavyweight Client
从 master 获得 chunk 信息,client 负责进行复制或者 EC。Client 实现重试机制,应对偶尔出现的抖动(比如网络丢包)。还实现了探测机制,定期从主控获得最新的 chunkserver 状态,评估 chunkserver 的服务质量。
Append-only chunk 管理
典型的文件系统(比如 ext4)将文件存储在块中,一个文件和他的元数据是通过两次写入分别写入存储介质的,增加了写入延迟,缩短了 SSD 寿命。 为了解决这个问题,pangu 在 chunkserver 上以 chunks 的形式存储文件。每个 chunk 存储数据和自己的元数据。因此,一个 chunk 通过一次操作(而不是两次)写入存储介质,大大降低写入延迟,提高了存储介质寿命。

一个 chunk 包括多个 sector unit。每个 sector unit 包括:data、padding、footer。 Footer 存储 chunk 元数据:chunk id、len、CRC。 独立的分块布局允许 chunkserver 能够从故障中自行恢复。 具体来说,当 client 将连续的独立块写入存储介质时,chunkserver 在内存中存储这些 chunk 的元数据副本,并定期将这些存到存储介质上进行 checkpoint。 当故障发生并导致一些未完成的写入时,chunkserver 会从 checkpoint 中加载元数据并与之进行比较。如果存在差异,chunkserver 会检查 chunks 的 CRC 以恢复到最新的正确状态。
元数据操作优化
master namespace 服务负责目录树和文件管理。 stream 服务负责 chunk 信息。stream 是一组 chunk 的抽象概念。同一 stream 中的 chunk 属于同一个文件。
并行化
高内聚的元数据会被映射到不同的元数据服务器。 它还使用了一种新的数据结构:支持可预测的目录 ID,并允许客户端高效地并行执行路径解析。
还有几种技术可以加快 client 从 stream 服务检索 chunk 的方式。
- 长度可变的 big chunk。big chunk 的好处:降低元数据的量,避免 client 频繁请求 big chunk 造成的不必要 io 延迟,有助于提高 SSD 寿命。然而,简单的增加 chunk 大小会增加碎片化的风险(想想 ZBS NFS 里的小文件,一个 47B 文件占用 256M 逻辑空间)。因此引入了可变长 chunk(1MB~2GB)。降低了碎片化的概率,并且保持与 pangu1.0 的兼容性。
- EBS 服务的分块大小有 P95 为 64 MB,P99 的量化为 286.4 MB
- Client 端缓存 chunk 信息。每个客户端有一个本地元数据缓存池,减少元数据查询请求数量。缓存池基于 LRU。当一个 service 想要访问数据时,client 首先查询本地的元数据缓存。当缓存未命中,或者缓存命中但是 chunkserver 提示元数据已过期(如由于副本迁移),client 会向 master 发出请求获得最新的元数据。
- Chunk 信息请求的批量化(batching)。client 在很短的时间内汇总多个 chunk 信息请求,批量发送给 master,提高查询效率。master 并行处理成批的请求,汇总结果发回 client。
- 贪婪的 chunk 信息预取(prefetching)。当 master 收到读取请求时,会给 client 返回相关 chunk 和其他 chunk 的元数据。当 master 收到写请求时,会返回更多的 chunkserver 来响应。如果遇到写入异常,可以在不请求的情况下切换 chunkserver。
- 数据捎带,降低一个 RTT。client 从 master 检索到 chunk 地址后,将 chunk create 请求和写入数据合并为一个请求,并发送给 chunkserver。
Chunkserver USSOS
坚持通过内核空间进行数据操作的传统设计是低效的:导致频繁的系统中断消耗 CPU 资源、导致用户空间和内核空间之间不必要的数据重复(memory copy) 为了应对这些问题,我们 bypass kernel,为 chunkserver 开发一个高性能的 userspace 存储操作系统。
- 设备管理
- run-to-completion 现成模型
- 用户级内存管理
- 用户空间调度
- 为 SSD 定制的 USSFS
USSOS 基于 RDMA、DPDK、SPDK 建立,但超越并统一了网络栈和存储栈。 在传统的管道线程模型中,一个请求被分解成各个阶段,每个阶段在一个线程上运行。相反,在 USSOS 中,请求从头到尾都在一个线程上运行,在运行到完成的模型中,减少了由上下文切换、线程间通信和线程间同步引起的开销。
内存管理
关于共享内存的工作有:vhost、shmipc 其次,线程请求一个巨大的内存空间,作为网络工作和存储栈之间的共享内存。具体来说,从网络收到的数据通过 RDMA 协议存储在共享 hugepage。在发送 hugepage 的元数据(addr、size)后,可以通过 SPDK 直接从 hugepage 写入存储介质。这样就实现了网络到存储的零拷贝。通过 io 数据的 user-level share hugepage,不同角色(比如 chunkserver 和 GCworker)之间的数据传输也可以实现零拷贝。
CPU 调度
防止一个任务阻塞后面的任务。每个 chunkserver 有固定数量的工作线程。分配给同一工作线程的请求以 fifo 顺序执行。因此对于一个给定的请求,如果一个任务需要太多的时间(表查询,表搜索、遍历、内存分配、监控和统计),他将占用资源并且阻止后续任务,降低了请求的性能,使得其他请求处于饥饿状态。对于 heavy task,引入了心跳机制来监控任务的运行时间并设置情报。如果一个任务的时间片用完了,会被放到后台线程中,从 critical path 中移除。对于 system overhead,使用 tcmalloc 缓存,让高频操作在缓存中完成。 优先级调度,保证高 QoS。不同的请求有不同的 qos 目标(用户请求:高优先级,GC:低优先级)。然而一个低优先级的请求可能会 block 后来的高优先级请求,并且由同一个 worker thread 执行。因此很难保证一个高优先级的请求总是能优先执行。USSOS 有一个优先级队列,任务根据 qos 目标放入相应的优先级队列。 polling 和 eventloop 的切换(NAPI)。NIC 提供一个 fd,通过 fd 事件通知应用程序的数据到达。app 默认处于事件驱动,收到 nic 的通知切换到 polling 模式。如果一段时间内没有收到任何 io 请求,切换回事件驱动模式。
Append-only USSFS
通过 FlatLogFile 的 append-only 语义, USSFS 支持 append-only 写入,并提供一套基于块的语义,如 open, close, seal, format, read, append 而不是像 Ext 4 那 样的标准 POSIX 语义。 采用不同机制最大化 SSD 性能:
- self-contained chunk:降低数据操作的次数
- 不像 ext4 在 inode 和 file dir 之间建立层次关系,而是所有对文件的操作都记录在 log 文件中,元数据在 mount 时通过 replay log 来建立。
- polling。
高性能高可用
Chasing

其中, 比如三副本写入两副本就可以返回成功。考虑这样的情况 [1 2 3],[1 2] 返回成功,[3] 在 时没有返回成功。Client 向上层返回成功,并且在内存中保留 chunk,等待另一个毫秒级的 (来自经验值)。如果 3 在 能返回成功,client 释放掉内存中的 chunk。如果 3 没能完成写入,但是没有完成的部分小于另一个经验值 ,client 对 3 发起重试。如果大于 ,client 会封存这个 chunk,以便这个 chunk 不会有后续的 append,然后 client 通知 master,master 将从 [1 2] 对 3 进行数据的复制,确保最终有三副本。 在谨慎选择 和 的情况下,chasing 大大减低了长尾写延迟,并且不会增加数据丢失的风险。具体来说,以 MaxCopy=3 的情况为例,在两个副本成功地完全写入 chunkservers 后,系统中有三个副本,而第三个副本在客户端的内存中。在 期间,只有当两个 chunkserver 副本的 SSD 损坏,客户端内存中的最后一个副本也发生故障或集群断电时,才会发生数据丢失。因为 SSD 的年故障率 ( 即 1.5%∼1.5% ) 和服务器的年停机率(即<2%)很接近,所以当两个副本成功写入,第三个副本被 Chasing 时,数据丢失的概率与三个副本都成功写入时的概率大致相同。
Non-stop write
发生故障时,client 封存这个 chunk,向 master 报告成功写入的数据长度,然后使用一个新的 chunk 继续写未完成的数据。如果写入密封块的数据被破坏了,我们会使用其他的副本在后台流量中把这个数据的副本复制到新的块中。如果没有副本可用,客户端会将这些数据写到新的 chunk。
Backup read
client 收到之前发送的读取请求的响应前,向其他 chunkserver 发送额外的 read 请求作为备份。两个关键参数:发送 backup read request 的数量和等待时间。为此,pangu 计算了不同磁盘类型和 io 大小的延迟(参考 perseus),并且利用这些信息动态的调整发送 backup read request 的时间,并且限制了数量控制系统负载。
黑名单
为了避免向服务质量差的 chunkserver 发送 io 请求,引入了两个黑名单:确定性黑名单和非确定性黑名单。当 pangu 确定一个 chunkserver 无法使用时(例如 SSD 损坏),这个服务器添加到确定性黑名单中。如果一个 chunkserver 可以提供服务,延迟超过了一定的阈值,添加到非确定性黑名单中,其概率随着服务延迟的增加而增加。如果该服务器的延迟超过所有服务器的延迟的中位数数倍,会被直接添加到非确定性黑名单中,概率为 1。为了从黑名单中释放 chunkserver,客户端定期(比如每秒)向这些服务器发送 io 进行探测。如果确定性黑名单上的服务器成功返回请求的响应,会从黑名单中移除。如果是非确定性黑名单,根据响应的时间来进行决策。 pangu 限制了黑名单的服务器总数,以确保系统的可用性,每个 chunkserver 引入一个宽限期。为 tcp 链路和 rdma 链路分别维护黑名单,分别进行探测。
评估

阶段二:适应性能导向的商业模式
单台 taishan 服务器的 SSD 吞吐量可以达到 20GB/s 以上。有了这样高性能的存储,自然会观察到其他的资源(网络、内存、 CPU)成为 pangu 的存储瓶颈。因此进行了网络的升级(25 Gbps->100 Gbps)。
网络瓶颈
带宽扩展。一开始使用 lossless rdma。当 rdma 中有太多的暂停帧时,关闭 nic 端口或者在几秒钟内从 rdma 切换到 tcp。然而这些机制不能处理基于暂停帧的其他问题(deadlock、head-of-line blocking)。后来升级到 lossy rdma,禁用暂停帧,避免这些问题。
流量优化。降低流量放大率:EC 和数据压缩。 使用 EC 替代三副本的技术挑战:在 EC 中存储小文件是很昂贵的,因为在具有固定长度的数据上执行 EC 需要大量的 zero padding。引入了机制避免:小写请求聚合,EC 和三副本动态切换。使用 Intel ISA-L 避免 EC 计算延迟。网络流量放大率可以从 6.375 倍减少到 4.875 倍。 压缩 FlatLogFile:client 和 GCworker 写文件前都会进行压缩。使用 LZ4 算法,平均压缩率达到 50%。因此,流量放大率可以从 4.875 倍进一步降低到 2.9375 倍
前台流量和后台流量的动态带宽分配。例如,如果整个存储集群有足够的空闲空间,我们会在时间上降低阈值,限制后台流量(如 GC 流量)的带宽,而让前台流量使用更 多的带宽。对于淘宝网,盘古在白天到午夜设置了一个低阈值,以应对大量的前端访问请求。午夜过后,盘古增加了门槛,因为前台的流量减少了。
内存瓶颈
盘古的基本内存瓶颈在于网络进程(即执行 DMA 操作的网卡)和接收主机中的应用进程(如数据复制、数据复制和垃圾回收)之间对内存带宽的高度争夺。 由于 NIC 无法获得足够的内存带宽,因此对 NIC 产生了严重的 PCIe 背压。因此,NIC 的缓冲区被飞行中的数据包填满。最终,它丢弃了溢出的数据包,触发了网络中的拥 堵控制机制,导致整体性能下降(例如,每台服务器的网络吞吐量下降 30% ,延迟增加 5%-10% , IOPS 下降 10%)。这种现象并不是盘古独有的。谷歌最近也报道 了这个问题。 三步走解决这个问题:
- 充分利用内存通道
- 后台流量从 TCP 切换到 RDMA
- 远程直接缓存访问(RDCA),发送方直接访问接收方的缓存。
小容量 DRAM。我们在服务器上增加了更多小容量的 DRAM(例如 16 GB),充分利用内存通道。启用 NUMA,避免跨 socket 内存访问Ultra path interconnect。 后台流量从 TCP 切换到 RDMA。TCP 比 RDMA 至少多 4 次 memcpy。切换后,后台流量的内存带宽消耗降低了 75%。为了保证前台流量的 QoS,设计了一个类似 Linux tc 的机制控制背景流量。
远程直接缓存访问。发送方绕过接收方的内存,直接访问其缓存。 在盘古的生产工作负载中,我们观察到一个重要的现象:数据离开网卡后在内存中停留的时间非常短(即平均数百微秒)。假设网卡离开后的平均时间为 200 us,对于一个双端口的 100 Gbps 网卡,我们只需要 5 MB 的时间来存储离开网卡的数据 三个组件:
- 缓存驻留的缓冲池。该池使用共享接收队列(SRQ)来接收小消息,并使用配备有基于窗口的速率控制机制的 READ 缓冲区来接收大消息,这样,RDMA 操作所需的内存缓冲区就可以放入缓存。
- 迅速的缓存回收。为了支持 100-Gbps NIC 以尽可能少的 LLC 运行,我们设计了 swift 缓存回收机制,通过(1)沿管道并行处理数据,以及(2)使用硬件卸载和轻量级(非)序列化优化处理,减少数据在 NIC 后的时间跨度。
- 缓存压力意识的逃避机制。为了处理偶尔的抖动(例如、SSD 慢速写入和应用异常),逃逸机制监控保留的 LLC 的使用情况,并采取相应的行动,包括(1)通过向驻缓存的缓冲池添加新的缓冲区来替换滞留数据的缓存缓冲区,这样 RDCA 中能够容纳新到请求的可用缓存的大小保持不变;(2)如果发生太多的替换,主动将运行缓慢的应用的数据复制到内存,这样其他应用可以使用 RDCA 的缓冲池,并且该池不会占用太多的缓存;和 (3) 让 NIC 在拥塞通知数据包中标记显式拥塞通知 (ECN),以便在复制到内存失败或不足以释放缓存压力时表示拥塞。 利用 Intel DDIO 实现了 RDCA。 对于典型的存储工作负载,RDCA 在每台服务器上消耗了 12 MB 的 LLC 缓存(占总缓存的 20%),降低了平均内存带宽消耗量减少了 89%,网络吞吐量提高了 9%。 我们发现,RDCA 在非存储工作负载中也很有效,例如,它减少了集体的平均延迟。在对延迟敏感的 HPC 应用中,通信速度提高了,达到 35.1%。RDCA 于 2022 年底在盘古中推出。
CPU 瓶颈
即使通过优化来打破网络和内存瓶颈,盘古在 100 Gbps 网络中的吞吐量仍然只能达到其理论值的 80% 。这是因为数据序列化和反序列化、数据压缩和数据 CRC 计算等操作会消耗很多 CPU 资源,使 CPU 成为盘古的另一个瓶颈。
混合 RPC。protobuf 对 RPC 请求进行序列化反序列化,花费大约 30% CPU,主要发生在少数 RPC 类型的数据路径上。数据面用 flatbuffer 原始结构直接发送接收,不进行序列化。控制面继续用 protobuf。每个 CPU 核心的网络吞吐量,增加了约 59%
使用 CPU wait 支持超线程。最初没有开启超线程,随着 CPU 核心的稀缺,开始采用。超线程两个性能问题:
- 同一个物理核心上的超线程需要切换上下文。
- 一个 ht 执行任务影响另一个 ht,造成两个任务的延迟增加。比如一个 network idle-polling thread 在一个 ht 上执行,另一个 ht 跑 lz4 压缩,与压缩线程完全占据物理核心的情况相比,数据压缩的延迟增加 25%。 引入 CPU wait 指令,由
monitor和mwait组成,需要少于 5 ms 进行调用。引入 CPU 等待后,network idle-polling thread 会在被监控的内存地址处等待,直到该内存地址被其他线程写入时才会被唤醒。在mwait过程中,它所运行的 HT 进入空闲睡眠状态,这是 C0 以外的 C 状态之一,不会干扰其他 HT。此外,用系统调用唤醒 HT 的时间是 ms 级的。与没有 wait 相比,网络吞吐量增加了 31.6%。
monitor和mwait是一对 x86 指令集架构中的指令,它们主要用于支持处理器的超线程技术。超线程技术允许一个物理核心模拟两个或更多的逻辑处理器,从而提高处理器的资源利用率,使其能够在同一时间处理更多的线程。
monitor和mwait指令的作用是在某种程度上提高处理器的能效比,它们允许处理器在等待某个特定内存地址的值发生改变时进入低功耗状态。这可以在一些多线程编程场景中节省能源,例如同步原语(如自旋锁)和其他线程间通信机制。
monitor指令用于设置一个监视区域,即一个特定的内存地址范围。当处理器执行monitor指令时,它会监视指定的内存地址,以检测该地址的值是否发生变化。
mwait指令用于让处理器进入一种低功耗状态,称为“睡眠”状态。在这种状态下,处理器会暂停执行,等待指定内存地址的值发生变化。当监视的内存地址发生变化时,处理器会被唤醒并继续执行。
CRC 和压缩卸载到 FPGA。压缩卸载到 FPGA 上,3 GB/s 吞吐节约 10c。CRC 计算卸载到网卡上。CPU 对网卡计算的 CRC 进行汇总和检查。节约 30% CPU 开销。
运营经验
细粒度的监控和智能诊断。在盘古 2.0 中,我们通过两个关键设计改进了盘古的监控系统,以满足高性能的要求(即 100μs 级的 I/O 延迟)。 首先,我们将监控的时间粒度从 15 秒提高到 1 秒,并扩展了日志服务[68]来设计一个按需追踪的系统。与盘古 1.0 中的粗粒度监控相比,这使得我们可以在每个文件操作的基础上进行追踪,以准确捕捉细粒度的异常事件(例如,内存分配异常和日志打印超时)。 第二,我们采用人工智能来更好地捕捉异常事件和其根源之间的因果关系。推断出的根本原因由运营团队评定,并反馈给训练有素的模型以提高其准确性。这种设计大幅提高了诊断的准确性,并减少了所需的人工努力。
端到端 CRC。懒得说了。拜占庭错误。
USSOS SLA 抖动。比如 tcmalloc 进入 global memory allocation 时(比如一个新线程需要内存)或者 memory organization 阶段(too many RDMA queue pairs try to reserve high-order memory space),就会变得过于耗时。引入了一个 userspace 内存分配池,优化了 rdma 驱动使用匿名页。周期性的重量级任务(比如打印日志)转移到异步线程,避免影响数据操作 SLA。第三,我们发现当内存占用率很高并且 USSOS 需要执行内存回收时,USSOS 的 CPU 利用率明显增加。因此,我们调整了内存重新收集的阈值,以减少 USSOS 进入内存重新收集的机会。我们还在后台重新收集分配给缓冲区和高速缓存的内存。
处理 MCE(correctable machine check exceptions)提高可用性。最初,USSOS(§3.2)可以监控这种硬件故障,但它不能感知内核如何迁移物理内存以隔离异常。因此,当 USSOS 试图根据其过时的虚拟-物理内存地址映射来访问已经迁移的物理内存时,就会发生错误。为此,我们在 USSOS 的 MCE 监控守护程序中加入了一个处理程序。一旦发现可纠正的 MCE 的数量超过阈值,与之相关的用户空间进程将暂停,让处理程序通知内核迁移内存。迁移之后,进程恢复并在访问内存页之前更新其映射表。这种设计提高了盘古的可用性,而性能的下降可以忽略不计。例如,我们在一个 2300 台服务器的集群中观察到 22 天内<330 个可纠正的 MCEs。
来自不同供应商的异质性内存带宽。盘古部署了来自不同供应商的内存。我们的测试表明,在 1:1 的内存读写比下,三个不同供应商的 128 GB 内存的可实现带宽分别为 94 GB/s 、 84 GB/s 和 60 GB/s ( 即 57%的差异)。这种异质的内存带宽会导致集群的 性能下降。这一观察告诉我们要更加关注内存的性能,而不是容量。这也是我们最早发现的接收器主机数据通路拥堵的证据,也是 RDCA(§4.2.3)的直接动机。
经验教训
首先,用户空间系统的开发和操作比较简单。例如,我们的数据显示,在内核空间文件系统中,修复错误需要两个月的时间,但在 USSFS 中只需要几个星期。在用户空间开发新的功能(例如,zoned namespace)需要更少的开发人员和更短的时间。此外,监测和跟踪用户空间系统的行为并相应地调整其参数也比较容易。
第二,开发用户空间系统应该从内核空间的设计中学习。特别是,为了建立一个高性能的 USSOS,我们不仅需要统一存储和网络堆栈,还需要为内存管理、CPU 调度和硬件故障处理设计用户空间模块。内核空间在这些功能方面相当出色。因此,用户空间系统可以通过向它学习而受益。
Pmem。PMem 有很多优点,比如快速的数据持久化,对 RDMA 友好,低读取延迟(PMem 上 6µs 对 SSD 上 80µs),低尾部延迟,以及对缓存友好。因此,我们在盘古开发了一个基于 PMem 的 30 微秒 EBS 服务。然而,英特尔决定关闭其 PMem 业务,迫使我们重新考虑这项服务。在开发新的服务时,我们需要更全面的计划 (例如,考虑替代性、可持续性和成本权衡)。但我们乐观地认为,新的存储类存储器将出现,对这些问题有更好的解决方案。
整个硬件卸载压缩的开发需要一个 20 人的团队花费两年时间,期间我们解决了很多问题,如 FPGA 硬件成本,压缩数据的完整性,以及与硬件中其他功能的共存。最后,结果的好处大大超过了这个成本。
讨论
邮箱用于身份识别和回复通知,并由 Waline 存储。