千家信息网

Redis为什么要避免big key

发表于:2024-10-25 作者:千家信息网编辑
千家信息网最后更新 2024年10月25日,这篇文章主要介绍了Redis为什么要避免big key,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。避免 big keyRedis 执
千家信息网最后更新 2024年10月25日Redis为什么要避免big key

这篇文章主要介绍了Redis为什么要避免big key,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

避免 big key

Redis 执行命令是单线程的,这意味着 Redis 操作「big key」有阻塞的风险。

big key 通常指的是 Redis 存储的 value 过大。包括:

  • 单个 value 过大。如 200M 大小的 String。

  • 集合元素过多。如 List、Hash、Set、ZSet 中有几百、上千万数据。

举个例子,假设我们有一个 200M 大小的 String key,名称为「foo」。

执行如下命令

127.0.0.1:6379> GET foo

当返回结果时,Redis 会分配 200m 的内存,并执行 memcpy 拷贝。

void _addReplyProtoToList(client *c, const char *s, size_t len) {    ...    if (len) {        /* Create a new node, make sure it is allocated to at         * least PROTO_REPLY_CHUNK_BYTES */        size_t size = len < PROTO_REPLY_CHUNK_BYTES? PROTO_REPLY_CHUNK_BYTES: len;        // 分配内存(例子中为 200m)        tail = zmalloc(size + sizeof(clientReplyBlock));        /* take over the allocation's internal fragmentation */        tail->size = zmalloc_usable_size(tail) - sizeof(clientReplyBlock);        tail->used = len;        // 内存拷贝        memcpy(tail->buf, s, len);        listAddNodeTail(c->reply, tail);        c->reply_bytes += tail->size;        closeClientOnOutputBufferLimitReached(c, 1);    }}

而 Redis 输出 buf 为 16k

// server.h#define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */typedef struct client {    ...    char buf[PROTO_REPLY_CHUNK_BYTES];} client;

这意味着 Redis 无法单次返回响应数据,需要注册「可写事件」,从而触发多次 write 系统调用。

这里有两个耗时点:

  • 分配大内存(也可能释放内存,如 DEL 命令)

  • 触发多次可写事件(频繁执行系统调用,如 write、epoll_wait)

那么,如何找出 big key 呢?

如果 slow log 出现了简单命令,如 GET、SET、DEL,大概率是出现了 big key。

127.0.0.1:6379> SLOWLOG GET    3) (integer) 201323  // 单位微妙    4) 1) "GET"       2) "foo"

其次,可以通过 Redis 分析工具来查找 big key。

$ redis-cli --bigkeys -i 0.1...[00.00%] Biggest string found so far '"foo"' with 209715200 bytes-------- summary -------Sampled 1 keys in the keyspace!Total key length in bytes is 3 (avg len 3.00)Biggest string found '"foo"' has 209715200 bytes1 strings with 209715200 bytes (100.00% of keys, avg size 209715200.00)0 lists with 0 items (00.00% of keys, avg size 0.00)0 hashs with 0 fields (00.00% of keys, avg size 0.00)0 streams with 0 entries (00.00% of keys, avg size 0.00)0 sets with 0 members (00.00% of keys, avg size 0.00)0 zsets with 0 members (00.00% of keys, avg size 0.00)

对于 big key,有以下几点建议:

1.业务中尽量避免 big key 出现。当出现 big key 时,你要判断这样设计是否合理,又或者是出现了 bug。

2.将 big key 拆分为多个小 key。

3.使用替代命令。

  • 如果 Redis 版本大于 4.0,可使用 UNLINK 命令替代 DEL。Redis 版本大于 6.0,可开启 lazy-free 机制。将释放内存操作,放到后台线程执行。

  • LRANGE、HGETALL 等替换为 LSCAN、HSCAN 分次获取。

但我还是建议在业务中避免 big key。

感谢你能够认真阅读完这篇文章,希望小编分享的"Redis为什么要避免big key"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

0