Redis的应用 | 青训营笔记

118 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

1 Redis简介

随着数据量增加、读写压力的不断增加,MySQL服务器或者MySQL集群的压力越来越大。为此我们可以将数据分冷热,其中热数据就是经常被访问的数据,我们将热数据存储到内存中,这时就会使用到Redis数据库。

1.1 读写场景

读场景下,我们先从Redis中读取数据,如果Redis数据库中没有再读MySQL数据;而写场景下,服务端先写入MySQL数据,然后通过监听binlog来修改Redis数据

1.2 工作原理

  • 数据从内存中读写;
  • 数据保存到硬盘上防止重启数据丢失,Redis会将增量数据保存到AOF文件,将全量数据保存到RDB文件中;
  • 单线程处理所有操作命令,按时间顺序执行。

2. 应用案例

连续签到、消息通知、计数、排行榜、限流、分布式锁

示例代码:redis_course: 青训营redis课程Demo (gitee.com)

2.1 连续签到

业务逻辑:每个用户每天进行签到,断签计数将归零,连续签到必须在每天的23:59:59前;

Redis设计:数据结构为String,可以存储字符串、数字、二进制数据等,通常和expire配合使用,应用场景有存储计数、Session等;

  • key: cc_uid_xxxxxxxxxxxx
  • value: 252
  • expireAt: 当前时间往后的后天时间0点

2.2 消息通知

业务逻辑:当文章更新时,将更新后的文章推送到ES,用户就能搜索到最新的文章数据;

Redis设计:数据结构为list,其实现由一个双线链表和listpack实现;

2.3 计数

业务逻辑:文章的被点赞数、文章的被阅读数、用户的关注数、用户的收藏数等的计数;

Redis设计:数据结构为hash,将文章的被点赞数、文章的被阅读数、用户的关注数、用户的收藏数等存入一个hash结构里面,每次通过key将所有计数信息读取出来;

2.4 排行榜

业务逻辑:积分变化时,进行排名的实时更新;

Redis设计:使用dict实现通过key操作跳表的功能;

2.5 限流

业务逻辑:假设1秒内放行的请求数为N,超过N则禁止;

Redis设计:构建一个key,添加当前时间的时间戳(精确到秒),对该Key调用incr,超过N则禁止访问;

2.6 分布式锁

业务逻辑:并发场景下要求一次只能有一个协程执行,执行完成后其他等待中的协程才能执行;

Redis设计:利用Redis的单线程执行命令以及setnx只有未设置过才能执行的特性实现分布式锁;

3. Redis注意事项

3.1 大Key

定义string类型的value字节数大于10KB,或者复杂数据结构元素个数大于5000个或者总value字节数大于10MB的Key极为大Key。大Key会导致读取成本高容易导致慢查询,请求可能超时,并且由于Redis的单线程操作容易出现服务阻塞等问题。

处理方法:将大Key拆分为小Key,或者将value进行压缩。集合类结构例如hash、list、set等可以区分冷热数据,如榜单列表使用zset,只缓存前10页的数据,后续数据走db。

3.2 热Key

定义:当用户访问一个Key的QPS特别高时,会导致Server实例出现CPU负载突增或者不均的情况。

处理方法:(1)访问Redis前,在业务服务侧设置Localcache,降低访问Redis的QPS。LocalCache中缓存过期或未命中,则从Redis中将数据更新到LocalCache。(2)将热Key复制写入多份,例如key1:valuekey2:value,访问的时候访问多个key,但value是同一个,以此将qps分散到不同实例上,降低负载,但是代价是更新时需要更新多个key,存在数据短暂不一致的风险。

3.3 慢查询

  • 批量操作一次性传入过多的key/value,如mset/hmset/sadd/zadd等O(n)操作建议单批次不要超过100,超过100之后性能下降明显;
  • zset大部分命令都是O(Iog(n)),当大小超过5k以上时,简单的zadd/zrem也可能导致慢查询;
  • 操作的单个value过大,超过10KB,即避免使用大Key;

3.3 缓存穿透和缓存雪崩

缓存穿透即热点数据查询绕过缓存直接查询数据库,缓存雪崩即大量缓存同时过期。避免方法如下:

  • 如一个不存在的userlD。这个id在缓存和数据库中都不存在。则可以缓存一个空值,下次再查缓存直接反空值;
  • 通过bloom filter算法来存储合法Key,得益于该算法超高的压缩率,只需占用极小的空间就能存储大量key值;
  • 将缓存失效时间分散开,比如在原有的失效时间基础上增加一个随机值,对于热点数据过期时间尽量设置得长一些,冷门的数据可以相对设置过期时间短一些;
  • 使用缓存集群,避免单机宕机造成的缓存雪崩。