本文来自OPPO互联网技术团队,如需要转载,请注明出处及作者。欢迎关注我们的公众号:OPPO_tech
Parker 是 OPPO 互联网自研的一个基于 RocksDB 的分布式 KV 存储系统,它是一款类 Redis 的存储系统,主要解决的是用户使用 Redis 遇到的内存超限启动恢复时间长,一主多从代价大,硬件成本昂贵,无法存储海量数据等问题。
1. Parker简介
Parker 具有如下特性:
-
支持海量存储:单个集群存储容量可达数百 TB,线上单集群 TPS 峰值可达百万级。
-
支持水平扩展:存储容量、读写性能都可通过增加机器的方式水平扩展。通过数据分片 (slot) 的方式,将不同的分片散落在不同的节点,保证存储容量和读写性能的可扩展 。
-
服务高可用:每个数据分片包含两副本,主备副本可在秒级内切换,保证单个数据分片的读写服务的高可用。
-
兼容部分 Redis 协议:Parker 对外通信协议兼容 Reids Cluster 协议,支持 String 和 Hash 类型及对应的操作函数,即用户可以通过 Redis 客户端来读取 Parker 中的数据。
-
支持 TTL 特性:一条数据写入后,超过 TTL 指定的时间戳,就过期淘汰,对用户不可见。这就需要 Parker 能及时删除过期数据,回收过期数据占用的磁盘空间。
2. 遇到问题
我们在容量为 5TB 的存储服务器上部署了 8 个 Parker 实例,写入的数据设置为 3 天过期,预计在数据写入速度和过期回收速度平衡的情况下,单实例会保持有 300GB 的存储占用。
实际上 Parker 运行五天后发现磁盘使用率不断攀升,开始写入的前三天,磁盘使用率直线上升,而后虽然上升速度有所减缓,但是总体上升速度还是比较快,与预期效果有严重偏差。虽然数据在 TTL 过期之后无法读取到,但是实际上磁盘空间并没有得到及时回收,这导致磁盘使用率居高不下。
3. 原因分析
3.1 RocksDB 原理
Parker 的底层存储引擎使用的是 RocksDB ,RocksDB 底层数据存储是 LSM 架构。数据分为不同的层,默认是 7 层,compaction styles 默认选择 leveled compaction。如下图所示:
用户写入数据到 RocksDB 时,会先将数据写入到一个 Memtable 中,当一个 Memtable 写满了之后,就会变成 immutable 的 Memtable。RocksDB 在后台会通过一个 flush 线程将这个 Memtableflush 到磁盘,生成一个 Sorted String Table (SST) 文件,放在 Level 0 层。当 Level 0 层的 SST 文件个数