eBay PB 级日志系统的存储方案实践( 三 )


而关闭 proxy write 后,则先对 obj_x 做一次 promote,在 Cache Tier 中产生一个空对象,再直接写入 128KB 数据即可 。
相比之下,后者节约了 Base Tier 一次 128KB 写和一次 128KB 读,对于由全机械硬盘构成的 Base Tier 来说,这样的节约意义重大,并且应用的写入延迟大大降低了 。这部分 Ceph 具体代码,可以阅读
PrimaryLogPG::maybe_handle_cache_detail 的实现 。
其他的配置优化包括设置 min_flush_age 和 min_evict_age 来保证最近一小时的数据不会被刷出 Cache,以及对 target_max_byte, target_dirty_ratio, target_dirty_ratio_high 的调整,在此不一一赘述 。
通过上述一系列优化,如图 3 所示,在写入侧, Cache Tier 非常好地完成了写入缓冲与合并,来自应用的 25K IOPS 经由 Cache Tier 缓冲与合并之后到 Base Tier(fs_data) 写入请求只有 1.5K IOPS 。
换句话说,通过 Cache Tier 我们减少了 94 的写 IOPS 。

eBay PB 级日志系统的存储方案实践

文章插图
 
图 3 集群客户端写入性能(点击可查看大图)
而在读取侧,如图 4 所示,几乎所有的 IO 都在 Cache Tier 上发生, Base Tier 读流量近乎为 0  。
eBay PB 级日志系统的存储方案实践

文章插图
 
图 4 集群客户端读取性能(点击可查看大图)
综合来看,在 Cache Tier 上的总 IOPS 达到了 70K ,而 Base Tier 只有 1.5K IOPS 。通过深入理解业务的 IO 模型,合理配置 Cache Tier,我们实现了 分层存储  。
应用享受到了全闪存集群的性能,成本上却接近全机械盘的价格,实现了了性价比最大化 。03 遇到的问题下面分享几个在实施日志存储方案中遇到的 软硬件问题 ,附上我们的 解决方案 ,以供大家参考 。
1. Bluestore Allocator(空间分配器)在上线过程中,我们很顺利地度过了 25%,50% 的流量 。但在 75% 流量时,遇到了诡异的性能问题 。如下图 5 所示, Cache Tier 的写入延迟暴增 ,甚至能达到分钟级别,通过 OSD Performance Counter 很快把问题缩小到 Bluestore 内部, 结合日志发现延迟主由
STATE_KV_COMMITING_LATSTATE_KV_COMMITING_LAT 约等于 commit_lat 。
我们第一个怀疑的对象是 RocksDB 的性能,尤其是 compaction 带来的影响,并在此做了大量的调优,然而一无所获 。
但我们发现,在调优的过程中,为了修改参数重启 OSD 服务后,被重启的 OSD 能保持 20 小时 良好性能,之后延迟慢慢衰减到重启以前 。既然重启 OSD 能暂时缓解问题,那 RocksDB 就没有嫌疑了。
eBay PB 级日志系统的存储方案实践

文章插图
 
【eBay PB 级日志系统的存储方案实践】图 5 Bluestore commit latency 性能监控(点击可查看大图)
如下图 6 所示,进一步观察分析 性能计数器(performance counter) 的数据并结合代码,我们注意到: STATE_KV_DONE_LAT 虽然平均值只有 STATE_KV_COMMITING_LAT 的 3%,但与 STATE_KV_COMMITING_LAT 有明显的相关性 。
这个发现大大缩小了问题的范围,因为 STATE_KV_DONE_LAT 所覆盖的代码范围基本只包含 _txc_finish 这一个函数 。在某些时候,_txc_finish 释放空间后,需要等待超过 100 毫秒 才能获得分配器的锁 。同时, perf 的结果也指向了 StupidAllocator 这个循环  。
eBay PB 级日志系统的存储方案实践

文章插图
 
图 6(点击可查看大图)
如下图 7 所示,进一步分析日志,我们发现在 StupidAllocator 中的空间碎片非常严重  。虽然磁盘利用率不超过 50% ,但分配器里已经没有超过 256K 的 数据段(segment) 可供分配 。这就解释了为什么 StupidAllocator 会在上述的分配空间循环中耗费大量时间 。因为分配时持有了分配器锁,所以释放空间时需要等待很长时间来获得锁 。
eBay PB 级日志系统的存储方案实践

文章插图
 
图 7(点击可查看大图)
通过分析 Bluestore 的分配表,我们发现其实物理空间并没有碎片化,只是 StupidAllocator 在内存中的实现导致了碎片化 。StupidAllocator 是一个类似于内存管理中 Buddy 分配的一个实现 。
通过下图 8 的例子,我们看看碎片是如何产生的:一个 20K 的连续空间,经过 5 次 4K 分配,和乱序的 5 次 对应的 4K 释放后,会变成 8k+4k+8k 三块空间 。


推荐阅读