Redis 的内存不足时,是如何进行调优的?

当Redis的内存不足时,我们是如何进行调优的?

Redis は便利なのですが、メモリが半分しか使用出来ないという問題が有ります。
非同期でファイルの書き込みを行う際に、メモリのスナップショット(コピー)を取るために、その分の空きメモリが必要なのです。
ここに Redis のソースコードのコメントを翻訳したものを置いておきます。

这次,由于用于半永久信息的服务器空间不足,无法轻易删除。因此决定分析Redis的内存转储,进行未使用键的删除和数据类型的更改。

内存分析

由于内存转储对人类来说难以理解,所以我将dump.rdb文件复制到本地,然后使用Rdbtools将其导出为CSV,并在此基础上对数据进行了整理。

$ rdb -c memory dump.rdb > redis_memory.csv

# バイトサイズとキーの個数と単位バイトサイズを出す
$ cat redis_memory.csv | sed -E "1d" | sed -E 's/:[0-9]+(:|")/:{id}\1/g' | cut -d ',' -f 3,4 | awk -F ',' '{ sum[$1] += $2; count[$1] += 1 } END { for (key in sum) print key, sum[key], count[key], sum[key] /count[key] }' > redis_memory_status.csv 

由于使用了用户/123456/abc形式的密钥,所以我们用上述命令进行了聚合。

进行整形后,我们将按各自的数值对数据进行排序并进行调整。在这个案例中,尽管有一些未使用的键,但“投稿历史”占据了约9GB的容量。

调音

将投稿历史以JSON表示时,其形式如下所示的数组形式。


[{ question_id: <INTEGER>
  accessed_at: <STRING>
}
, // 
]

这个是以Ruby的哈希表序列化成的字符串进行保存,它每个用户占用了整整8MB的空间!就算增加服务器容量也无济于事,真是难以承受啊…

顺便提一下,Redis有两种内存编码方式。
有skiplist和ziplist(intset),后者可以在CPU成本和性能之间进行压缩和展开内存。intset似乎在Set的情况下使用。
你可以使用以下命令来检查所使用的编码方式。

redis> object encoding <KEY>

可以在 Redis 的配置中设置条件来应用这些编码。

hash-max-zipmap-entries 64 (hash-max-ziplist-entries for Redis >= 2.6)
hash-max-zipmap-value 512  (hash-max-ziplist-value for Redis >= 2.6)
list-max-ziplist-entries 512
list-max-ziplist-value 64
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
set-max-intset-entries 512

只要将数据类型改变得合适,应该就可以相当压缩内存了。

根据这些考虑,本次我们将之前的大食客分成了两个列表,并将日期转换为时间戳。通过此处理,预计大小将被压缩至最大1/10左右。其进展如下图所示。

graph_image.png

(日语原文)ガツンと下がっています。

(中文翻译)建议Redis使用者调整ziplist(intset)的优化,因为它可用于Hash/List/Set/SortedSet等结构。

共享内存

好吧,在上述的情况下,我们的 Redis 得到了救援,但是对于管理用户的帖子内容或更庞大的列表来说,这是无法应付的。

しかし、解決策があります。
以下の記事の様にデータを複数分割して保存する方法があります。
http://mocobeta-backup.tumblr.com/post/84793291682/redis-set
もちろん、仕組みを用意しなければならなく、CPUコストは高くなりますが、メモリに困っていたら利用してみてはいかがでしょうか?

总结

そもそもこの対応、最初から横着せずにデータ型に注意を払っていればよかったという話。

请提供以下的参考。

小型聚合数据类型的特殊编码方式
http://redis.io/topics/memory-optimization

Redis RDB Dump文件格式
https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format

广告
将在 10 秒后关闭
bannerAds