Introduction
- Pangu1.0
- 构建在HDD上,ms-level latency
- distributed kernel-space file system based on Ext4
- kernel-space TCP
- guadually added support to multiple file types(TempFile, LogFile, RandomAccessFile)
- 这里早期云上存储的主要目的是large volumes,在性能上的关注点不大
随着硬件发展,SSD/RDMA,2015年开始设计Pangu2.0,目的是提供高性能100us-level latency的存储服务。
这里有一些观察:
* Pangu1.0的多种文件类型允许随机访问,对SSD不友好。(这里主要说的是写吧)
* kernel-space软件栈比较重(内核态切换/中断,数据拷贝啥的)
* server-centric datacenter到resource-disaggregated datacenter的切换。会引入额外的延迟。(这里个人理解就是比如计算机器和存储机型放在不同的位置,导致会有一些额外的网络延迟。可能到us级别这个纬度就显得比较关键了)
Pangu2.0的第一阶段:
* append-only persistence layer
* self-contained chunk layout来降低io latency。(这里应该是说写meta什么的,TODO再展开说一下)
* user-space storage operating system。RTC thread model
* RTC在这里的好处就是处理线程不会收到中断的影响,提高局部性和稳定的延迟
* 说是有一些保障SLA的机制,具体也没说是什么
Pangu2.0第二阶段:
* in-house 高密存储机型,单机96TB SDD。网卡带宽从25G升级到100G
* 针对硬件升级继续做优化
* 优化网卡带宽(没说咋做的)
* remote direct cache access,优化内存瓶颈。(内存瓶颈是哪里来的?)
* 消除data (de)serialization,以及引入CPU wait instruction(同步超线程)来优化CPU瓶颈(感觉啥也没说。。)
秀肌肉阶段:
* OTS(阿里的table store,表格存储,应该是hbase系)从pangu1.0升级到2.0,lantecy降低一个数量级
* 写入比较多的系统,如EBS,p999 io latency小于1ms
* EBS的workload都是小IO?
* read intensive,比如在线搜索,p999 io latency小于11ms。(这是为啥,读比写慢?)
Background
和类似的两个产品相同,都是重SDK类型的
* Google Colossus https://cloud.google.com/blog/products/storage-data-transfer/a-peek-behind-colossus-googles-file-system
* Facebook的Tectonic
和Tectonic类似,把master拆了一下,搞成了namespace service和stream meta service。然后先通过directory tree进行shard,再哈希了一下。
* 这里引了下FAST22的InfiniFS
namespace service提供文件的一些信息,如directory tree/namespace。(具体不清楚怎么用的,这里应该没有提供list之类的接口,可能是file name -》 file id映射)
stream service记录从file到chunk列表的映射
早期的pangu2.0是前台三副本,后台EC。这里说为了节省带宽支持了前台EC
* 前台EC确实可以降低写流量,但是对于读来说会有放大?可能只有异常情况有放大,日常的话如果做好一点应该是没有的
还有一些其他的related work都可以看一看:
* Perseus: Pangu monitoring system,FAST23的paper。可以看看这个是怎么监控文件系统的
* RDMA相关:When Cloud Storage Meets RDMA
* KV engine: ArkDB,具体还不清楚是干啥的
* EBS做的network和storage software的codesign
Phase One: Embracing SSD and RDMA
一个一个看一下Phase One做的工作
- Append-Only File System
- Unified, Append-Only Persistence Layer
- 早期pangu会对每个存储服务都提供一种类型的文件,引入了过多的复杂性,并且也不能很好的使用SSD顺序写的性能。Pangu2.0引入了统一的文件类型叫FlatLogFile,提供Append only的语义
- 划分指责,不过接口这里看起来各个厂都不太一样,虽然底层都是Append Only的。不过还有Ceph/PolarFS系。
- 最直观的AppendOnly的优点就是底层SSD也是append only,并且immutable的chunk做复制/EC等更加容易
- Heavyweight Client
- SDK负责协调文件系统的写入,和chunkserver/master交互。以及尖刺的处理,chunkserver的探活(这里是从master拉chunkserver的信息,感觉是处理非对称网络分区的case)
- 负责指定读写的参数,类似Tectonic。用来满足不同上层业务的需求
- Append-only Chunk Management
- Ext4的写入会涉及到对SSD的两次写入,meta和data
- self-contained chunk layout,数据本身自包含,避免额外写meta,提高ssd的使用时间,降低延迟
- 一个chunk内分为若干个sector,每个sector的尾部会有一个footer用来记录meta,保护chunk id/length/crc
- chunkserver会维护一些元数据在内存中,并且可以在recover的时候把元数据恢复回来。(猜测是扫一遍chunk,相当于重放日志了)然后为了提高recover速度,可以去checkpoint这个元数据
- 这块个人感觉就是一些类似log file的设计
- metadata operation optimization
- 这里感觉主要就是对metadata的一些shard,pangu这里是先根据directory tree做partition,然后再哈希
- 这里提到了InfiniFS做的Parallel Metadata Processing,不太了解这块是在干啥
- 支持变长的chunk size,1MB to 2GB。过大的chunk size会导致fragmentation,过小的话会导致client需要经常分配chunk,对metadata也有一定的压力
- client缓存chunk的信息,感觉是日常操作了。如果访问到的chunkserver的副本已经被迁移走了,就refresh cache
- client会聚合一下对master的请求。(个人不太清楚能有多少优化,感觉用处不大的样子)
- prefetching chunk information。对于读,master会返回更多的其他chunk的信息。对于写,会多返回一些可用的chunk,这样切换的时候就不需要再去访问master了。(写入这个是有额外分配开销的?不过感觉如果多分配的chunk没有写入的话,heartbeat的时候是可以把这个meta清理掉的)
- 对chunkserver的create chunk + write chunk和成一个请求。感觉也是基操
- Unified, Append-Only Persistence Layer
- Chunkserver USSOS
- User-Level Memory Management
- 说了下,传统的pipeline thread model,每个请求会被划分为若干个stage,放到不同的线程上执行。RTC则是在单个线程上执行完,避免context-switch,线程同步导致的开销
- 分配huge page给network/storage stack共享。通过RDMA从网络上收到的数据会被直接写到这段huge page memory中,然后再通过SPDK直接从huge page memory写到存储设备中
- User-Space Scheduling Mechanism
- RTC模型处理的时候,如果单线程请求过慢(比如涉及到内存分配什么的),会卡住其他请求。Pangu会监控执行时间比较久的task,并在超时的时候放到后台线程中执行(这是怎么做的?主动yield?类似SQL Server OS那样吗)
- priority queue 来保证QoS。很细节的没说,不过这个应该是一个比较常见的话题了,在Tectonic里也讨论了挺多的
- Polling and event-driven switching,默认情况下是event driven,当收到包的时候,通知application,然后application会进入polling模式,避免中断。当请求处理完的时候,会回到event driven模式,避免CPU持续打满
- Append-Only USSFS
- USSFS提供chunk-based接口,如open/close/seal/format/read/append。就可以提供一些特化的优化,比如利用上面的self-contained chunk layout,没有inode/file directory,使用polling模式。并且在chunk比较大的情况下,以1MB的粒度分配空间,提高SSD的使用率,降低metadata的内存消耗
- User-Level Memory Management
- High Performace SLA Guarantee
- chasing
- 核心目的是避免写入尖刺,所以可以走一些类似3写2的操作。比如3副本写,只有两副本写入成功了,client会返回OK,并且在内存中记录下这个信息并等待比如ms-level的时间。如果这段时间返回成功了,client会释放这段内存。如果没有,但是丢失的部分比较少,client会重试这个错误,如果丢失的部分比较多,那么client会seal这个chunkserver,避免后续写入。然后master会负责进行复制,补齐副本
- 感觉是持久性换可用性(延迟)的样子。并且细节处理应该没那么容易
- 这里pangu说是没有使用持久性做trade off的,应为这段时间丢数据只可能发生于成功的两个副本的SSD坏了,并且client的宕机了(client中保存了这个最后一个replica的数据)。然后SSD的failure rate(~1.5%)和服务器downtime rate(~2%)接近。所以这段时间数据坏的概率和3副本SSD都跪了基本类似。(把一个副本的SSD坏 转移到了client宕机上)
- 这里也引用了几篇paper,做的同样是这个early-write-acknowledgment
- non-stop write
- 写失败的时候,直接用commit length seal老的chunk,然后写新的chunk
- backup read
- 这里有一张图,就是读结果返回之前就请求第二个chunkserver。保障读延迟
- 那感觉可以直接并发读3副本?
- blacklisting
- 如果chunkserver盘坏了,会被加入deterministic blacklist
- 如果chunkserver的延迟比较高,则会被加入non-deterministic blacklist。
- client会周期性probe这些服务器,如果返回io成功,则会从deterministic blacklist中移除。如果延迟降低,则可以从non-deterministic blacklist中移除
- TCP和RDMA的blacklist是不同的
- 为了保证可用性,在操作blacklist的时候会有一个grace period。避免网络抖动啥的突然把所有的服务器都加入blacklist了
- chasing
Phase Two: Adapting to Performance Oriented Business Model
这一节的逻辑是,Pangu引入了自研的Taishan Server,提供96T的存储,20GB的带宽。此时就更容易发现CPU/Memory/Network的瓶颈了
- Network Bottleneck
- 这里其实升级network到100Gb网卡是一个比较自然的事情,因为单块SSD的带宽要有500MB+,12/16块盘,很容易就把25G的网卡打满了。阿里之前的一篇论文有讲他们是怎么应用RDMA的
- 然后还有降低带宽放大,即网络数据传输大小/真实文件大小。
- 这里用ebs举例子,从ebs service发送文件到pangu client,有一倍。然后从client到chunkserver,写3副本,有3倍。最后是后台的gc worker,会读文件然有1倍。然后写EC文件,EC(8, 3)有1.375倍。一共是6.375倍的放大
- 可以走前台EC,EC(4, 2),降低3副本的开销。那么就是6.375 - 3 + 1.5 = 4.875倍。这里前台EC有个问题是EC需要对齐,对于小文件来说比较浪费。pangu做了写入聚合 + 动态切换3副本/EC来解决这个问题。然后计算纠删码对CPU也有一些开销,这里是用了特殊的硬件Intel ISA-L来做
- 做压缩可以降低带宽,所以pangu client和GC worker都会做一些压缩操作,这里用的是LZ4。一般可以压两倍。
- 然后还可以空间换带宽,如果空间足够,可以限制一下后台EC的带宽,来给前台提供更多的带宽。比如高峰给前台流量多一些,低峰就给后台多一些带宽做EC
- Memory Bottleneck
- 这里paper提到了一个比较不错的点:
- network process和application process对内存带宽的争抢。如果NIC无法得到足够的内存带宽,会导致NIC buffer被填满,并丢弃溢出的数据包,触发网络的拥塞控制机制,进而导致整体性能出现下降。google也提到了类似的现象。(感觉是来自于一些反压/限流机制的开销?)
- 因为这里主要是内存带宽的瓶颈,所以pangu增加了一些小内存来吃满memory channel。(感觉没有什么insight)
- 使用RDMA,应为TCP要有4次内存拷贝,导致对内存带宽吃的比较多。然后因为前台和后台都用了RDMA,需要对后台流量有一些限流的机制
- RDCA(Remote Direct Cache Access):在数据离开NIC后,数据处理的时间非常的短暂。只有200us。那么对于一个100Gb的网卡来说,只需要5MB的buffer就可以把所有需要处理的数据buffer起来。这样的话,可以在LLC上分配一段小的buffer专门给NIC使用。
- 这里还有一些细节,他们搞了一个cache-resident buffer pool,感觉就是LLC上的buffer pool。然后为了避免SSD的尖刺什么的,会有一些监控机制及时给buffer pool分配更多空间,或者移动数据到内存什么的,避免影响其他的请求。
- 非常细节的我也看不太懂了,不过从PCIe上到CPU和Memory到CPU走的不是一个总线吗?这样总线带宽有节省吗
- https://www.cnblogs.com/pengxurui/p/16893747.html 这里有个回答。北桥是片上北桥,直接连接PCIe/内存
- 这里说他们用了12MB的LLC,降低了89%的内存带宽,还是非常牛逼的
- 感觉这种已经非常极限了,PCIe NIC到LLC,然后处理完数据直接到PCIe SSD。如果再极限一点就是降低PCIe的距离,搞DPU什么的了
- 这里paper提到了一个比较不错的点:
- CPU Bottleneck
- 这里CPU开销主要来源于data serialization/deserialization, compression和CRC computation
- 通过Protobuf做序列化大概用了30%的CPU,Pangu搞了类似FlatBuffer的东西,可以避免serialize/deserialize。然后对于一些控制信息,还是用的protobuf,因为protobuf的灵活性更强
- 最初pangu没有用HT,后面为了利用资源还是启动了HT,但是为了避免HT之间相互影响,比如polling thread影响另一个做压缩的线程。会通过monitor和mwait监听polling的内存地址,避免消耗CPU。
- 这里他们说他们会做polling和event driven的切换,所以感觉这个例子不太合适?但是感觉monitor/mwait这就是专门给polling线程准备的。并且为什么一个idle polling和一个compression线程会在一个HT上也比较奇怪。感觉应该是一个盘一个物理核这样分配。
- compression放到了FPGA上,CRC放到了RDMA NIC上。(这里CRC感觉只是网络的?还是说支持给特殊的data区域计算CRC,然后CPU再聚合一下)
- Evaluation
- 这里感觉逻辑不错可以研究一下:
- 第一个是baseline,2 x 25G
- 第二个是升级了100G网卡以及SSD,但是吞吐没有翻倍,这是因为出现的内存带宽限制。内存带宽到了90G/s,接近上限105G/s了
- 第三个是通过上面提到的优化,优化内存带宽,让性能线性拓展到2倍了
- 第四个是引入PCIe gen4引入2 x 100G网卡,吞吐到了3.3X,没有翻倍是因为出现了带宽放大,有6倍
- 第五个则是引入了EC(4, 2),压缩等优化,降低带宽放大到3倍。吞吐到了5倍,也没有翻倍,是因为压缩导致CPU到瓶颈
- 第六个则是引入了hardware offload,提升吞吐到6.1倍
Operation Experiences
这里有一个处理长尾延迟的case可以看一下:
* 19年双十一,出现了迁移两个chunk,然后最后剩下的一个chunk的chunkserver跪掉的情况。导致client需要在访问3个chunkserver都失败后,重新获取最新的chunk的位置信息,从而导致延迟比较高。
* 这里应该不是迁移出现并发,而是迁移后的chunk的信息没有及时更新到client侧(即缓存信息失效了)。所以解决方法是让client周期性的去获取一下异常chunkserver的信息,并更新chunk的位置信息。(这里感觉有比较多的方式去做,这里我感觉是受到篇幅限制没有很细节的描述这个事情了)
* 20年双十一,因为内部原因导致client认为很多chunkserver都出现了异常,导致花费了大量的资源去做收集chunk信息以及处理异常chunkserver,进而导致出现io hang。后续的解决方法是对获取异常chunkserver的case做了限流。
* 直观可以学习到的case就是一些fetch array的请求,就要对array size做限流
Lessons
- USSOS,因为可控性更好,所以bug fix,feature的开发效率都高了很多。然后对于一些kernel本身做的比较好的地方,比如cpu scheduling, memory management, hardware failure handling,要借鉴一发。用户态的系统主要是对IO栈的优化
- 这么看感觉工作量还是蛮大的
- performance-cost tradeoff,一般为了满足新需求,pangu会先增加硬件。但是为了保证成本,会再后续做针对性的优化,提高在新型硬件上的资源使用率
- PMem,做了pmem,但是跪了。所以在针对新硬件做开发的时候,要多考虑他的可替代性,可维护性,以及cost tradeoffs
- hardware offloading,cost-benefit tradeoff是最根本的问题,(因为开发特化硬件需要比较多的成本)这里盘古用了20人2年的时间做了这个hardward offloading,带来了比较多的收益。(关键点是管理层需要能承受这个开销,并且需要预估好这个工作带来的收益)(个人感觉有风险的点还有一个,就是2年前认为可以优化的东西,可能2年后就不是瓶颈了,2年的时间足以改变很多东西,所以在预估的时候也需要充分考虑这个)
思考
- 可以看出来pangu的演化历程受到了很多硬件的影响。基础软件大多数的革新应该都是来源于硬件的升级,出现新的瓶颈,进而进行优化。即在某个上下文下的tradeoff,因为部分资源的升级,使得其弹性更强,在tradeoff中的地位也有所变化。
- QoS的保障,发生降级的时候,要避免影响其他人的请求。在可能出现抖动的地方都要做好控制。
Reference
https://developer.aliyun.com/article/291207
文章评论