在使用 Redis 时,可能会出现请求响应慢、网络卡顿、数据丢失的情况。排查问题的时候,发现是 big keys 的问题。

什么是 big keys

在 Redis 中,一个字符串类型最大可以达到 512MB,其他非字符串类型的集合类型(list、set、hash、zset等)可以存储 40 亿个(2^32-1),但在实际业务场景中,并不需要这么大的内存。而且对于一个请求量大的互联网软件,对数据的大小要求更加的严格。如果达到如下标准,就可以认定是 big keys 了:

  • String 类型的 key 对应的值超过 5 MB。
  • list、set、hash、zset等集合类型,集合元素个数超过 2000。

以上对 big keys 的判断标准并不是唯一,只是一个大题的标准。在实际业务开发中,对 big keys 的判断是需要根据具体的使用场景做不同的判断。比如操作某个 key 导致请求响应时间变慢,那么这个 key 就可以判定成 big keys。

big keys 是如何产生的

一般来说,big keys 的产生都是由于程序的设计不当,或者对数据的规模没有一个大体的估算。比如:

  • 统计类:例如统计某个网站的访问用户信息,网站的访问量越来越多,这个 key 的元素也会越来越大。变成了 big keys。
  • 社交类:例如某个大V微博粉丝量很大,如果不做合理的设计,也是 big keys。
  • 缓存类:一般缓存类的信息访问都比较频繁,是将从数据库查询出来的数据序列化到Redis缓存中,这里的缓存如果设计不当,或者为了方便,把所有的数据都存在一个 key 下,或者随着业务的扩大,对应的缓存也增多,也是形成 big keys。

以上几种类型都是在实际运维中遇到的。在开发中需要根据预估的数据大小来合理的设计缓存数据。

big keys 的危害

在系统中如果存在 big keys,会导致请求数据响应变慢、请求超时或者系统不稳定。

1、响应变慢、超时阻塞

Redis 是单线程工作的,同一时间只能处理一个请求,操作 big keys 时比较耗时,请求响应也变慢。其他请求也处于阻塞状态,导致请求超时。除了查询 big keys 比较耗时,删除 big keys 也会导致一样的问题。

2、网络拥塞

请求单个 big keys 产生的网络流量比较大,假设一个 big keys 为 1MB,客户端每秒访问量是 1000,那么每秒产生 1000MB 的流量,普通的千兆网卡承受不了这么大的流量。而且一般会在单机部署多个Redis实例,一个 big keys 可能也会影响其他实例。

3、内存分布不均

Redis 集群模式中,key根据不同的hash嘈分配到不同的节点上,当大部分的 big keys 分布在同一个节点,导致内存倾斜在同一个节点上,内存分布不均。在水平扩容时,需要以最大容量的节为准,浪费内存。

如何发现 big keys

Redis4.0 后提供了 --bigkeys命令,比如:

./redis-cli --bigkeys

获取每个数据类型最大的 big keys,同时给出每个类型键的个数和平均大小。因为 Redis 是单线程工作的,为了减少对线上请求的影响,执行--bigkeys命令需要注意一下几点:

  • 最好在 slave 节点执行,因为 --bigkeys 也是扫描数据,会造成其他线程阻塞。
  • 使用 --i 参数,降低扫描的执行速度,比如 --i 0.1 表示 100 毫秒执行一次。
  • 只能统计每个数据类型最大的数据。

big keys 处理

异步删除 big keys

找到 big keys 之后,首先需要删除对应的big keys,但是使用 del 命令删除 big keys 是比较耗时的。Redis4.0 后可以使用 unlink 删除,和 del 命令相比,unlink 是非阻塞的异步删除。

非字符串的 big keys,使用 hscan、sscan、zscan 方式渐进式删除,同时要注意防止big keys 过期时间自动删除问题(例如一个 200 万的 zset 设置1小时过期,会触发del操作,造成阻塞)。

big key 拆分

字符串类型的数据是减少字符串的长度,将一个字符串拆成几个小的字符串。非字符串的是减少元素数量。这些都是讲一个 key 拆成多个 key,比如:

  • 字符串类型的数据,根据数据的属性拆分。比如商品信息,根据的类别拆分 key。
  • 非字符串类型的数据,根据数据的属性拆分,可以按照日期拆分,比如每天登录人的集合,按照日期拆分,key20220101、key20220102.

如果 big keys 无法避免,那获取数据尽量不要把所有的数据都取出来,就使用分段的方式取出数据。删除的方式也类似,分段删除数据。

总结

  • big keys 会造成请求变慢、网络阻塞、数据丢失的问题。
  • big keys 是字符串字节达到很大的数量(比如 5MB),非字符串类型元素类型达到 1000 个都可以判定成 big keys,具体还需要看具体的场景。
  • big keys 的产生可能由于设计不合理或者对数据大小估算错误,导致数据偏大。
  • 解决 big keys 先紧急使用异步删除 unlink 命令删除缓存。然后将单个 key 拆分成多个小 key。
  • 如果无法避免 big keys,就使用分段查询的方式查询数据。
  • 要从几个方面分析,
    • big keys 会带来哪些问题。
    • big keys 一般怎么产生的,线上如果产生了big key,线上先怎么紧急处理。
    • 有哪些优化方案,各自有什么应用场景。

参考

详解 Redis 中 big keys 发现和解决的更多相关文章

  1. 详解Redis中两种持久化机制RDB和AOF(面试常问,工作常用)

    redis是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失.幸好Redis还为我们提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Ap ...

  2. 详解Redis中两种持久化机制RDB和AOF

    redis是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失.幸好Redis还为我们提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Ap ...

  3. 反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习

    反射实现Model修改前后的内容对比   在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责. 首先我们要创建一个User类 1 p ...

  4. Redis学习——详解Redis配置文件(三)

    一.Redis脚本简介 在我们介绍Redis的配置文件之前,我们先来说一下Redis安装完成后生成的几个可执行文件: redis-server .redis-cli .redis-benchmark ...

  5. (转载)详解Javascript中prototype属性(推荐)

    在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...

  6. 详解Redis持久化(RDB和AOF)

    详解Redis持久化(RDB和AOF) 什么是Redis持久化? Redis读写速度快.性能优越是因为它将所有数据存在了内存中,然而,当Redis进程退出或重启后,所有数据就会丢失.所以我们希望Red ...

  7. 【转】详解JavaScript中的this

    ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...

  8. 详解javascript中的this对象

    详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...

  9. 详解Vue中的computed和watch

    作者:小土豆 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.cn/user/2436173500265335 1. 前言 作为一名Vue ...

  10. 详解JavaScript中的原型

    前言 原型.原型链应该是被大多数前端er说烂的词,但是应该还有很多人不能完整的解释这两个内容,当然也包括我自己. 最早一篇原型链文章写于2019年07月,那个时候也是费了老大劲才理解到了七八成,到现在 ...

随机推荐

  1. nginx日志参数及含义

    参数含义 $remote_addr,$http_x_forwarded_for #记录客户端IP地址 $remote_user #记录客户端用户名称 $request #记录请求的URL和HTTP协议 ...

  2. 服务器设置X-Frame-Options Header响应头(Tomcat,服务器,项目)

    解决方案(修改tomcat配置文件) 打开Tomcat配置文件(conf\web.xml)搜索 httpHeaderSecurity有两处地方 <!--第一处将注释放开--> <fi ...

  3. Linux自动切换用户

    Linux自动切换用户 一.创建sh文件 touch su_user.sh 二.下载脚本 yum install -y expect 三.脚本内容 #!/bin/bash# This is our f ...

  4. 解决在JS中阻止定时器“重复”开启问题、Vue中定时器的使用

    1.问题描述 在一些需求开发中.需要设定软件提供服务的时间段(营业时间).这时可以选择定时器来实现.可以选择让定时器每隔一段时间检测当前时间是否在服务时间.到达服务时间.进入服务状态.未到服务时间.进 ...

  5. java集合框架复习----(1)

    文章目录 1 .集合框架思维导图 一.什么是集合 二.collection接口 1 .集合框架思维导图 一.什么是集合 存放在java.util.*.是一个存放对象的容器. 存放的是对象的引用,不是对 ...

  6. 如何在IDEA中创建Module、以及怎样在IDEA中删除Module?

    文章目录 1.为何要使用Module? 2.Module的创建 3.如何从硬盘上删除module 1.为何要使用Module? 目前主流的大型项目都是分布式部署的,结构类型这种多Module结构.不同 ...

  7. Redis 02: redis基础知识 + 5种数据结构 + 基础操作命令

    Redis基础知识 1).测试redis服务的性能: redis-benchmark 2).查看redis服务是否正常运行: ping 如果正常---pong 3).查看redis服务器的统计信息: ...

  8. NLP之基于Seq2Seq的单词翻译

    Seq2Seq 目录 Seq2Seq 1.理论 1.1 基本概念 1.2 模型结构 1.2.1 Encoder 1.2.2 Decoder 1.3 特殊字符 2.实验 2.1 实验步骤 2.2 算法模 ...

  9. 1.httprunner3入门

    一.httprunner3 httprunner是一款面向HTTP(S)协议的通用开源测试框架 支持三种格式的用例:YAML/JSON/Pytest,httprunner3以前不支持pytest用例 ...

  10. 一、什么是celery

    一.什么是Celery 1.1.celery是什么 celery是一个简单.灵活且可靠的,处理大量消息的分布式系统,专注于是心爱处理的异步任务队列,同事也支持任务调度. Celery的架构由三部分组成 ...