thumbnail

redis中的大key和unlink操作

liuyuede liuyuede | 1 分钟阅读
2年前

1、什么是 bigkey

  • Key 本身的数据量过大:一个 String 类型的 Key,它的值为 5 MB。
  • Key 中的成员数过多:一个 ZSET 类型的 Key,它的成员数量为 10,000 个。
  • Key 中成员的数据量过大:一个 Hash 类型的 Key,它的成员数量虽然只有 1,000 个但这些成员的 Value(值)总大小为 100 MB。

2、bigkey 的影响

  • 集群架构下,某个数据分片的内存使用率远超其他数据分片,无法使数据分片的内存资源达到均衡
  • 如果 bigkey 一直在增长,会导致 Redis 内存 OOM,影响读写性能
  • 因为 Redis 是单线程的,对 bigkey 的增删改操作,会导致超时,甚至阻塞服务
  • 对大 Key 执行删除操作,易造成主库较长时间的阻塞,进而可能引发同步中断或主从切换

3、如何避免 bigkey

  • 如果是 hash 的话,通过一定规则拆分到不同 hash 中,特别是在集群中很有效果
  • 堆积大量过期数据会造成大 Key 的产生,例如在 HASH 数据类型中以增量的形式不断写入大量数据而忽略了数据的时效性。可以通过定时任务的方式对失效数据进行清理。
  • 对大 Key 进行直接删除

4、如何查看 bigkey

  • 可以通过 Redis 客户端命令查看:

    redis-cli --bigkeys
    
    # Scanning the entire keyspace to find biggest keys as well as
    # average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
    # per 100 SCAN commands (not usually needed).
    
    [00.00%] Biggest string found so far '"frontLastPullSysMsgId:1257:964350"' with 5 bytes
    [00.00%] Biggest string found so far '"exam_data:1233:913172:39017:140692"' with 8885 bytes
    [00.01%] Biggest string found so far '"exam_data:319:877777:14274:126728"' with 14875 bytes
    [00.03%] Biggest list   found so far '"live_merge:154_159588"' with 9 items
    [00.06%] Biggest string found so far '"exam_data:319:1101505:52328:151653"' with 19125 bytes
    [00.07%] Biggest hash   found so far '"timer_ids:company_id:1134:sys_id:5"' with 11 fields
    [00.17%] Biggest string found so far '"exam_data:908:644980:22627:146279"' with 31320 bytes
    [00.30%] Biggest hash   found so far '"timer_ids:company_id:927:sys_id:5"' with 130 fields
    [00.73%] Biggest hash   found so far '"timer_ids:company_id:264:sys_id:2"' with 551 fields
    [01.19%] Biggest string found so far '"exam_data:973:693508:33936:128891"' with 40643 bytes
    [03.09%] Biggest hash   found so far '"timer_ids:company_id:1183:sys_id:5"' with 625 fields
    [03.29%] Biggest hash   found so far '"timer_ids:company_id:1183:sys_id:2"' with 1410 fields
    [06.39%] Biggest string found so far '"exam_data:301:104065:51535:165675"' with 127069 bytes
    [06.75%] Biggest hash   found so far '"websocket_duration"' with 1560568 fields
    [37.36%] Biggest string found so far '"exam_data:301:104065:51536:165675"' with 128746 bytes
    [81.08%] Sampled 1000000 keys so far
    
    -------- summary -------
    
    Sampled 1233274 keys in the keyspace!
    Total key length in bytes is 48419022 (avg len 39.26)
    
    Biggest   list found '"live_merge:154_159588"' has 9 items
    Biggest   hash found '"websocket_duration"' has 1560568 fields
    Biggest string found '"exam_data:301:104065:51536:165675"' has 128746 bytes
    
    14 lists with 47 items (00.00% of keys, avg size 3.36)
    2736 hashs with 1726892 fields (00.22% of keys, avg size 631.17)
    1230524 strings with 1649082886 bytes (99.78% of keys, avg size 1340.15)
    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)
    
    • 优点:方便、快速、安全
    • 缺点:分析结果不可定制化,准确性与时效性差
  • 可以使用 redis-rdb-tools 或者 xueqiu/rdr,有对应的图形界面看着也很清晰

    • 优点:支持定制化分析,对线上服务无影响
    • 缺点:时效性差,RDB 文件较大时耗时较长

5、如何删除 bigkey

  • Redis 4.0 及之后版本:您可以通过 UNLINK 命令安全地删除大 Key 甚至特大 Key,该命令能够以非阻塞的方式,逐步地清理传入的 Key。
  • Redis 4.0 之前的版本:建议先通过 SCAN 命令读取部分数据,然后进行删除,避免一次性删除大量 key 导致 Redis 阻塞。
  • 清理 HASH 数据时,建议通过 HSCAN 命令配合 HDEL 命令对失效数据进行清理,避免清理大量数据造成 Redis 阻塞。

Redis 4.0 开始引入了 UNLINK 命令,他和 del 的作用是一样的。但是区别就在于 del 是单线程的,如果删除的是 bigkey 的话,会导致整个服务都被占用。

UNLINK 其实就是把 del 的操作分到了 2 个线程里面:

  • 在主线程中,从整个键空间中删除键
  • 在另一个线程回收内存

虽然分在了 2 个线程里,但是操作也是安全的,并不会带来我删着删着又被读到了的并发问题。因为它(在主线程中)从键空间中删除了对象,因此任何 Redis 命令都无法访问它。

如果你有很大的值,速度会显着提高——UNLINK 是一个 O(1) 操作(每个键;在主线程中),而不管键中保存的值的大小。使用 DEL 删除一个大值可能需要几百毫秒或更长时间,而 UNLINK 将在不到一毫秒的时间内完成(包括网络往返)。

但是并不是说 del 无用武之地了,当需要实时响应的时候最好还是 del,因为毕竟 UNLINK 是一个异步操作。

讨论区

登录评论
暂无评论