Redis缓存使用规范参考集
2023-09-09 21:18:44 阿炯

本文收集了业界一些基于Redis的使用规范,为大家的使用提供一个参考;不过在开始之前,先对其的使用概况做一个介绍。

Redis(REmote DIctionary Server)是一个基于 C 语言开发的开源 NoSQL 数据库,与传统数据库不同的是,Redis 的数据是保存在内存中的(内存数据库,支持持久化),因此读写速度非常快,被广泛应用于分布式缓存方向。并且Redis存储的是 KV 键值对数据。

为了满足不同的业务场景,Redis 内置了多种数据类型实现(比如 String、Hash、Sorted Set、Bitmap、HyperLogLog、GEO);并且其还支持事务、持久化、Lua 脚本、多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。


Redis 数据类型概览

Redis 没有外部依赖,Linux 和 OS X 是其开发和测试最多的两个操作系统,官方推荐生产环境使用 Linux。

Redis 为什么这么快

其内部做了非常多的性能优化,比较重要的有下面 3 点:
1.基于内存,内存的访问速度是磁盘的上千倍;
2.基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用;
3.内置了多种优化过后的数据类型/结构实现,性能非常高。

下面这张图片总结的挺不错的,出自 Why is Redis so fast?。


分布式缓存常见的技术选型方案有哪些

分布式缓存的话,比较老牌同时也是使用的比较多的还是 Memcached 和 Redis。不过现在基本没有看过还有项目使用 Memcached 来做缓存,都是直接用 Redis。

Memcached 是分布式缓存最开始兴起的那会比较常用的;后来随着 Redis 的发展,大家慢慢都转而使用更加强大的 Redis 了。

有一些大厂也开源了类似于 Redis 的分布式高性能 KV 存储数据库,例如,腾讯开源的 Tendis,其基于知名开源项目 RocksDB作为存储引擎,100% 兼容 Redis 协议和 Redis 4.0 所有数据模型。

不过从 Tendis 这个项目的 Github 提交记录可以看出,其开源版几乎已经没有被维护更新了,加上其关注度并不高,使用的公司也比较少。因此不建议使用 Tendis 来实现分布式缓存。

目前比较业界认可的 Redis 替代品还是下面这两个开源分布式缓存:
Dragonfly:一种针对现代应用程序负荷需求而构建的内存数据库,完全兼容 Redis 和 Memcached 的 API,迁移时无需修改任何代码,号称全世界最快的内存数据库。

KeyDB:Redis 的一个高性能分支,专注于多线程、内存效率和高吞吐量。

不过还是建议分布式缓存首选 Redis,毕竟经过这么多年的生产考研,生态也这么优秀,资料也很全面。说一下 Redis 和 Memcached 的区别和共同点

现在公司一般都是用 Redis 来实现缓存,而且 Redis 自身也越来越强大了!不过了解 Redis 和 Memcached 的区别和共同点,有助于在做相应的技术选型的时候能够做到有理有据!

共同点:
都是基于内存的数据库,一般都用来当做缓存使用。
都有过期策略。
两者的性能都非常高。

区别:
1、Redis 支持更丰富的数据类型(支持更复杂的应用场景)。它不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。Memcached 只支持最简单的 k/v 数据类型。
2、Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 把数据全部存在内存之中。
3、Redis 有灾难恢复机制。 因为可以把缓存中的数据持久化到磁盘上。
4、Redis 在服务器内存使用完之后,可以将不用的数据放到磁盘上。但是,Memcached 在服务器内存使用完之后,就会直接报异常。
5、Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 Redis 目前是原生支持 cluster 模式的。
6、Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型(Redis 6.0 针对网络数据的读写引入了多线程)。
7、Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持。并且 Redis 支持更多的编程语言。
8、Memcached 过期数据的删除策略只用了惰性删除,而 Redis 同时使用了惰性删除与定期删除。

相信看了上面的对比之后,已经没有什么理由可以选择使用 Memcached 来作为自己项目的分布式缓存了。

为什么要用Redis作缓存

下面主要从“高性能”和“高并发”这两点来回答这个问题。

1、高性能
假如用户第一次访问数据库中的某些数据的话,这个过程是比较慢,毕竟是从硬盘中读取的。但是,如果说,用户访问的数据属于高频数据并且不会经常改变的话,那么我们就可以很放心地将该用户访问的数据存在缓存中。

2、高并发
一般像 MySQL 这类的数据库的 QPS 大概都在 1w 左右(4 核 8g),但是使用 Redis 缓存之后很容易达到 10w+,甚至最高能达到 30w+(就单机 Redis 的情况,Redis 集群的话会更高)。

QPS(Query Per Second):服务器每秒可以执行的查询次数;

由此可见,直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而也就提高了系统整体的并发。

什么是 Redis Module?

Redis 从 4.0 版本开始,支持通过 Module 来扩展其功能以满足特殊的需求。这些 Module 以动态链接库(so 文件)的形式被加载到 Redis 中,这是一种非常灵活的动态扩展功能的实现方式,值得借鉴学习!大家都可以基于 Redis 去定制化开发自己的 Module,比如实现搜索引擎功能、自定义分布式锁和分布式限流。目前被 Redis 官方推荐的 Module 有:
RediSearch:用于实现搜索引擎的模块。
RedisJSON:用于处理 JSON 数据的模块。
RedisGraph:用于实现图形数据库的模块。
RedisTimeSeries:用于处理时间序列数据的模块。
RedisBloom:用于实现布隆过滤器的模块。
RedisAI:用于执行深度学习/机器学习模型并管理其数据的模块。
RedisCell:用于实现分布式限流的模块。
……

关于 Redis 模块的详细介绍,可以查看官方参考文档


喜马拉雅Redis与Pika缓存使用规范

作者:喜马拉雅 董道光

宣言:缓存不是万金油,更不是垃圾桶!

缓存作为喜马拉雅至关重要的基础组件之一,每天承载着巨大的业务请求量。一旦缓存出现故障,对业务的影响将非常严重。因此,确保缓存服务的稳定和高效运行始终是我们的重要目标。下面是对喜马缓存历史故障复盘后总结的一套缓存使用规范,在此分享给大家,希望小伙伴们能在缓存选型和使用的过程中少踩坑。

1. 缓存选型
1.1 缓存类型介绍

喜马线上缓存类型主要有 4 种:
1. redis 主从模式:官方原版
2.codis-redis:豌豆荚开源,redis 集群解决方案
3.云数据库 redis:redis-cluster 容器化部署
4.xcache:基于 codis、pika、redis 自研的一套海量 KV 存储解决方案

1.2 缓存使用模式介绍

使用模式主要分为 2 种:
1.cache 模式:数据不需要持久化,实例恢复不需要加载数据,扩缩容不需要迁移数据
2.store 模式:数据需要持久化,实例恢复需要加载数据,扩缩容需要迁移数据

下面是对各种类型缓存做了简单对比:

 
2. 缓存使用军规

2.1 缓存类型使用规范

1)redis 集群模式首选云数据库 redis,海量 KV 存储首选 xcache
云数据库 redis 采用官方 redis cluster 模式,容器化部署,支持故障自动恢复和弹性伸缩,是当前 redis 集群的主推方案,但不支持数据持久化,如果必须要做数据持久化,并且对延时要求非常高,可以使用 codis redis。数据量非常大,并且对延时要求不是特别高,可以选择 xcache。

2)redis 不要当 db 使用,如果数据一定要做持久化,可以选择 xcache
redis 当 db 使用,故障恢复数据很慢,严重影响 SLA。并且如果主从全部挂掉,slave 机器无法恢复时,数据就会完全丢失。xcache 天然支持数据持久化。

3)不要使用客户端分片模式
客户端分片模式不具备高可用和弹性伸缩能力,建议使用真正的集群模式,如 codis-redis、云数据库 redis、xcache。

4)集群模式不支持 lua、redisson 客户端,如果业务必须使用,只能选择 redis 主从模式。

5)单节点容量阀值
redis 单节点容量不要超过 10GB,xcache 单节点容量不要超过 200GB;redis 单节点容量太大时,实例重启会比较慢,影响恢复时长。

2.2 键值设计规范

1)key 尽量保持简洁性、可读性、可管理性
在保证语义的前提下,控制 key 的长度;以业务名 (或数据库名) 为前缀 (防止 key 冲突),用冒号分隔,比如业务名:表名:id;不要包含特殊字符。

2)拒绝 bigkey,防止网卡流量过高、慢查询
string 类型控制在 10KB 以内,hash、list、set、zset 元素个数不要超过 5000。

3)避免热点 key
热 key 会导致数据倾斜,以及单节点压力过大。建议业务侧将热 key 打散。

4)控制 key 生命周期
缓存不是垃圾桶,最好对 key 都设置 ttl,并且将 key 的 ttl 打散,避免 key 集中过期。

2.3 命令使用规范

1)慎用全量操作命令
禁用 `keys *` 命令,尽量不使用 hgetall、smembers 等命令。在获取 key 下的多个元素时,使用相应的 scan 命令,一次获取少量元素,分多次获取,建议一次 scan 不要超过 200 个。

2)控制 mset、mget、hmset、hmget、*scan、*range 等命令单次操作元素数量,建议不要超过 200

3)控制 pipeline 中命令的数量,建议不要超过 100

4)redis 删除 key 时,不要用 del 命令,使用 unlink 命令
del 一个大 key 会直接导致 redis 卡住。使用 unlink 命令可以异步删除 key,不会对 redis 主线程产生影响,因此也不会影响业务流量。

5)set 和 expire 命令合并成 setex 命令,减少服务端写压力。

6)evalsha 代替 eval
redis-cluster 集群中使用 evalsha 代替 eval,减少网络 IO,同时也减小 redis 网络 IO 压力提高性能。

2.4 业务缓存架构规范

1)redis 不要使用逻辑 db,只使用默认 db 0
可以通过实例隔离,不同业务的数据保存到不同的实例中。(只有 redis 主从可以选择逻辑 db,集群模式默认都使用 db0)。

2)避免多业务复用同一缓存资源
不同业务的数据使用不同的集群,S 级应用不要和 B 级应用混用,过多业务复用同一资源要做拆分。业务尽量提供 rpc 接口给其它业务调用,而不是直接让其它业务访问数据源(如一个业务写,一个业务读)。

3)xcache 尽量使用 string 类型
xcache 支持 string,hash,ehash,list,set,zset 六种数据类型,ehash 数据类型是对 hash 数据类型的扩展,支持对 field 设置过期时间。xcache 中 string 类型是速度最快的,其他数据类型都是由 string 进行组合变换而实现,六种数据的性能如下:
string > hash > set > ehash > list > zset

建议:尽量使用 string 类型

4)减少 lua 脚本使用
集群模式对 lua 支持有限制,必须保证 lua 中操作的 key 被 sharding 到同一个节点。所以尽量减少对 lua 的使用。

5)lua 脚本中不跑复杂逻辑
复杂逻辑放在业务代码中,而不是 lua 脚本中。

6)采用高效序列化方法和压缩方法
为了节省内存,如果 value 较大时,可以使用压缩工具(如 snappy 或 gzip),把数据压缩后再写入 redis。

7)避免批量任务、定时任务、周期任务流量太大影响在线业务
批量任务、定时任务、周期任务业务上要做限速。

8)业务变更,存储流量模型变化要先评估
业务模型变化,QPS、容量增加,O (N) 命令增多等都要先评估当前缓存是否抗的住,做到灰度上线,持续观察(尤其是流量高峰期)。

9)不用的资源尽早申请回收
休眠资源回收不仅可以降低业务的存储成本,还可以把资源分配给真正需要的业务,可谓是双赢。