短k-v在Redis中的存储

一、背景

目前越来越多的互联网公司将特征工程集成到机器学习平台中了,而特征工程作为其中非常重要的一环,也在最近两年快速的平台化。我这边遇到的一个需求是将特征存到FeatureService中,以便线上进行预估时读取,按之前的设计,FS是本地缓存-》redis-》TiKV(也有可能是别的基于SSD的kv)。 特征会以的SequenceFile存在HDFS的指定目录, 其中value中的BytesWritable是将原始的特征以protobuf的格式写入,特征平台如果没有proto文件也无法反序列化出来做监控预警,所有的数据传递都是bytes,而线上模型是知道怎么反序列化。

单个的k-v字节数会比较少,例如k可能只是一些id,而value是一些基本特征,就算是embedding的也可能只在50个字节左右。在这篇文章中, Redis百亿级Key存储方案, 提到了如何去优化。我这边做的优化类似,另外对于为什么直接k-v存储的内存占用会的扩大到10倍左右,给出了具体的统计。有可能局限于我对redis的源码了解存在计算错误的情况,仅供参考。

二、直接key-》value存储

一个key为14字节,value为10字节的存储占用的内存空间: key_value内存占用估计

三、使用分桶+限制使用ziplist的hash存储

2.1 说明

redis的hash存储,如果是默认的设置,那么当每个hash中的key数小于512个以及每个value的长度小于64bytes,那么redis自身会使用ziplist编码而不是hashTable编码

这个限制的数值是由hash-max-ziplist-value 选项和 hash-max-ziplist-entries来控制的,可以在redis集群的配置信息里面看到是64和512. 自测100m*10bytes,存我本地的redis内存增长为200m左右.

hashTable的编码方式如下, 一旦进行编码的转换,会导致有相对于key-value更多的内存消耗,所以我们需要限制一个单个组合特征的字节数。

2.2 做法

28亿个widjointhreetableserializer的45GsequenceFile,写入后内存占用226G,相对于之前的570G的key-value存储,省了60%的存储空间。

后续可以再扩大一下映射到512的空间里面,key不用原始的Key而是新的2个字节(9位),估计内存会有进一步的下降。

如果还有时间,可以再修改redis的ziplist结构,不过估计就没有人运维了。

comments powered by Disqus