欢迎光临
我们一直在努力

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 bytes

1 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)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。