这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
Redis是什么
为什么需要redis
- Mysql数据量增长,数据读写压力增长
- 数据分冷热,将热数据存储到内存中
redis使用场景
读场景
先去redis中读,如果redis中找不到,再去mysql读,并写入redis
写场景
写入redis后,修改redis
Redis 基本工作原理
- 数据从内在中读写
- 支持AOF和RDB方式将数据持久化。每一条写命令会向AOF文件末尾加一条日志,重启服务时会重新执行AOF文件记录的命令。
- 单线程处理所有操作命令
Redis的应用案例
连续签到
用户每日有一次签到机会,如果断签,连续签到计数器将归0,每天必须在23:59:59前签到。
- Key: cc_uuid_1234565
- value: 252
- expireAt: 后天的0点
用户每次签到,将计数器加1,并把过期时间设置为后天0点
消息通知
用list作为消息队列:生产者将消息lpush进入队列左侧,消费者rpop从右侧消费消息。
当文章更新时,将更新后的文章推送到ES,用户就能搜索到最新的文章数据。
计数
维护用户的关注数、粉丝数、点赞数等数据。如果每次在数据库中count的话数据库压力很大。
一个用户有多项计数需求,可通过hash结构存储。
排行榜
积分变化时,排名要实时变更。使用zset数据类型,支持添加元素、排序输出。
限流
要求1秒内放行的请求为N,超过N则禁止访问
Key:时间戳
Value:计数器
每个请求让当前时间戳的计数器加1,计数器小于阈值则放行,大于阈值则禁止访问。
分布式锁
并发场景,要求一次只能有一个协程执行。执行完成后,其它等待中的协程才能执行。
可以使用redis的setnx实现,利用了两个特性:
- Redis是单线程执行命令
- setnx只有不存在才能执行成功。
Redis使用注意事项
大Key、热Key
大Key的定义
String value的字节数大于10kb
Hash/Set/Zset/list等元素个数大于5000个或总value字节数大于10MB
大Key的危害
- 读取成本高
- 容易导致慢查询
- 主从复制异常,服务阻塞,无法正常响应请求
业务侧使用大Key的表现
- 请求Redis超时
消除大Key的方法
- 拆分:将大Key拆分为小Key,例如将一个string拆分成多个string
- 压缩:gzip,snappy,lz4等
- 集合类结构(hash,list,set,zset):拆分、区分冷热
热Key的定义
用户访问一个Key的QPS特别高,导致Server实例出现CPU负载突增或不均的情况。
解决热Key的方法
- 设置Localcache
- 拆分:将热Key复制写入多份
- 使用Redis代理:实现热Key发现和LocalCache两个功能。
慢查询场景
容易导致redis慢查询的操作
- 批量操作一次传入过多的元素
- zset大部分命令时间复杂度是O(logn),数据量大时也可能导致慢查询
- 操作的单个value过大
- 对大key进行delete、expire等操作
缓存穿透、缓存雪崩
缓存穿透
热点数据查询绕过缓存,直接查询数据库
通常不会缓存不存在的数据,这类查询都会直接打到db,如果有系统bug或人为攻击,容易导致db反应慢甚至宕机
解决方法:缓存空值、布隆过滤器
缓存雪崩
大量缓存同时过期
同一时间大量key过期,也会导致大量请求落到db上
解决方法:分散过期时间、使用缓存集群