序言
此文章待重构排版。
优雅的key结构
Redis 的 Key 虽然可以自定义,但最好遵循下面的几个最佳实践约定:
- 遵循基本格式:
[业务名称]:[数据名]:[id]
- 长度不超过44字节
- 不包含特殊字符
优点:
- ① 可读性强
- ② 避免key冲突
- ③ 方便管理
- 更节省内存:虽然 key 是 string 类型, 但其底层编码包含 int、embt 和 raw 三种。embst 在小于 44 字节使用,采用连续内存空间,内存占用更小
BigKey
在使用 Redis 时,常常会听到 BigKey 这个名词,那么,什么是 BigKey?为什么尽量需要避免使用 BigKey 呢?又怎么去发现 BigKey 呢?
简介
简单来说,BigKey 通常以 Key 的大小和 Key 中成员的数量来综合判定,例如:
- Key 本身的数据量过大: 一个 String 类型的 Key,它的值为 5 MB
- Key 中的成员数过多: 一个 ZSET 类型的 Key, 它的成员数量为 10000 个
- Key 中成员的数据量过大: 一个 Hash 类型的 Key, 它的成员数量虽然只有 1000 个,但这些成员的Value(值)总大小为 100 MB
推荐值:
- 单个 key 的 value 小于 10KB
- 对于集合类型的 key,建议元素数量小于 1000
危害
- 网络阻塞:对 BigKey 执行读请求时,少量的 QPS 就可能导致带宽使用率被占满,导致Redis实例,乃至所在物理机变慢
- 数据倾斜:若 BigKey 所在的 Redis 节点内存使用率远超其他实例,无法使数据分片的内存资源达到均衡
- 线程阻塞:对元素较多的 hash、list、zset 类型等做运算会耗时较久,使主线程被阻塞
- CPU 压力:对 BigKey 的数据序列化和反序列化会导致 CPU 的使用率飙升,影响 Redis 节点和本机其它应用
如何发现 BigKey?
redis-cli –bigkeys
利用redis-cli
提供的--bigkeys
参数, 可以遍历分析所有key
,并返回 Key 的整体统计信息与每个数据的 Top1 的 bigkey。
缺点是信息不够完整。
scan 扫描
自己编程, 利用 scan 扫描 Redis 中的所有 key, 利用 strlen、hlen 等命令判断key的长度 (此处不建议使用 MEMORY USAGE)
第三方工具
利用第三方工具,如 Redis-Rdb-Tools、rdb_bigkeys 分析 RDB 快照文件, 全面分析内存使用情况。
网络监控
自定义工具, 监控进出Redis的网络数据, 超出预警值时主动告警。
如何删除 BigKey
BigKey 内存占用较多,即便时删除这样的 key 也需要耗费很长时间,导致 Redis 主线程阻塞,引发一系列问题。
另外,需要事先评估删除是否对生产业务存在比较大的影响,否则不建议操作。
Redis 3.0 及以下版本
如果是集合类型,则遍历 BigKey 的元素,先逐个删除子元素,最后删除 BigKey
Redis 4.0 以后
Redis 在 4.0 后提供了异步删除的命令:unlink
如何选择恰当的数据类型?
例1:比如存储一个 User 对象,我们有三种存储方式:
- ① 直接存储 JSON 字符串
- 优点:实现简单粗暴
- 缺点:数据耦合,不够灵活
- ② 将字段打散再存储
- 优点:可以灵活访问对象任意字段
- 缺点:占用空间大、没办法做统一控制
- ③ 使用 hash 结构存储
- 优点:底层使用zipist,空间占用小,可以灵活访问对象的任意字段
- 缺点:代码相对复杂
例2:假如有 hash 类型的 key,其中有 100 万对 field 和 value, field 是自增 id,这个 key 存在什么问题?如何优化?
慢查询
慢查询:在 Redis 执行时耗时超过某个阈值的命令,称为慢查询。
查看
查看慢查询日志相关命令:
slowlog len
: 查询慢查询日志长度slowlog get [n]
:读取 n 条慢查询日志slowlog reset
: 清空慢查询列表
优化
慢查询的阈值可以通过配置指定:
slowlog-log-slower-than
: 慢查询阈值,单位是微秒。默认是 10000,建议 1000,通过config set slowlog-log-slower-than 1000
设置
慢查询会被放入慢查询日志中, 日志的长度有上限,可以通过配置指定:
slowlog-max-len
: 慢查询日志 (本质是一个队列)的长度。默认是128, 建议1000,tong gconfig set slowlog-max-len 1000
设置
安全配置
Redis 会绑定在0.0.0.0:6379
, 这样将会将 Redis 服务暴露到公网上, 而 Redis 如果没有做身份认证, 会出现严重的安全漏洞.
漏洞出现的核心的原因有以下几点:
- Redis 未设置密码
- Linux 使用了 root 账号权限启动 Redis
- 利用了 Redis 的
config set
命令动态修改 Redis 配置
为了避免这样的漏洞,这里给出一些建议:
- ① Redis一定定要设置密码
- ② 禁止线上使用下面命令: keys、flushall、 flushdb、 config set等命令。可以利用
rename-command
禁用 - ③ bind:限制网卡,禁止外网网卡访问
- ④ 开启防火墙
- ⑤ 不要使用 root 账户启动 Redis
- ⑥ 尽量不是有默认的端口
内存配置
当 Redis 内存不足时,可能导致 Key 频繁被删除、响应时间变长、QPS 不稳定等问题。当内存使用率达到 90% 以上时就需要我们警惕,并快速定位到内存占用的原因。
内存类型 | 说明 |
---|---|
数据内存 | Redis 最主要的部分,存储键值信息。主要问题是 BigKey 问题、内存碎片问题 |
进程内存 | Redis 主进程本身运行肯定需要占用内存,如代码、常量池等等;这部分内存大约几兆,在大多数生产环境中与 Redis 数据占用的内存相比可以忽略。 |
缓冲区内存 | 一般包括客户端缓冲区、AOF 缓冲区、复制缓冲区等。客户端缓冲区又包括输入缓冲区和输出缓冲区两种。这部分内存占用波动较大,不当使用 BigKey,可能导致内存溢出 |
Redis提供了一些命令,可以查看到Redis目前的内存分配状态:
info memory
memory <key_name>
内存缓冲区配置
内存缓冲区常见的有三种:
- 复制缓冲区:主从复制的
repl_backlog_buf
,如果太小可能导致频繁的全量复制, 影响性能。通过repl-backlog-size
来设置,默认1mb - AOF 缓冲区: AOF 刷盘之前的缓存区域, AOF 执行 rewrite 的缓冲区。 无法设置容量上限
- 客户端缓冲区:分为输入缓冲区和输出缓冲区, 输入缓冲区最大 1G 且不能设置。 输出缓冲区可以设置