简单介绍 redis
一个百万级开发者使用的开源K-V 键值对内存数据库,端口 6379;网站 redis.io ;应用于缓存、消息队列等,
redis 使用场景
- 缓存
- 消息队列
- 限流
redis 安装
redis 常用数据结构
● string
● list
○ 可实现栈、队列
● hash
○ 一般用于存储数据库返回的对象
● set
○ 不可重复,无序
● sortset
○ 添加了 key 值权重,可排序
● bitmap
○ 存储的是连续的二进制数字(0.1),可用于用户行为分析,统计活跃用户,用户在线状态
redis 持久化
redis 提供了两种数据文件
○ RDB(默认):快照
○ AOF:每秒或者有数据修改写入 AOF 文件
redis 事务
redis 不支持原子性事务,官方没有提供
redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能
○ MULTI 命令1、命令2 … EXEC,执行提交操作
○ DISCARD 取消事务提交
○ WATCH 当监测到某个key 值发生改变时不提交事务
如何解决?
○ Lua 脚本(错误无法撤销,不是原子性)
○ Redis 7.0 新增了 Redis functionsopen in new window 特性
过期字典
过期字典 key 指向着缓存中过期 key
删除策略
○ 惰性删除:取出 key 值的时候过期检查,CPU 友好
○ 定期删除:每隔一点时间进行过期检查,内存友好
内存淘汰机制
● volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
● volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
● volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
● allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
● allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
● no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
● volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
● allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key
缓存穿透
大量访问缓存中不存在的key值,请求落到数据库上,严重可导致数据库宕机
解决:
○ 请求校验,防止不规范请求
○ 请求数据量少的情况下可以给缓存中放置一个key, value 为空
○ 布隆过滤器
缓存雪崩
缓存中的 key 大面积失效,请求落到数据库上,严重可导致数据库宕机
解决:
○ 搭建集群
○ 缓存中的 key 设置随机过期时间
数据库和缓存数据不一致问题
缓存的写入速度是要比数据库的写入速度要快很多
3种常用的缓存读写策略
○ 旁路缓存模式
■ 先更新数据库,再删除缓存 为啥不能先删缓存,再更新数据库?
● 会导致数据库跟缓存数据不一致问题 请求1删除A缓存-请求2从数据库读取A数据-请求1更新数据库A数据 请求2读到的A数据跟数据库的A数据存在不一致
■ 先更新数据库,再删缓存是否就没有问题了?
● 也可能会出现数据不一致问题,但是概率相对来说比较小 若前提是缓存中不存在A数据,请求1在第一秒的时候从数据库读取了A数据,在第二秒时请求2更新了数据库中A数据并删除缓存,再第三秒请求1将第一秒读取到的A数据写入缓存中,这就完成数据库中的A数据跟缓存中的A数据不一致
■ 旁路缓存模式存在的缺陷
○ 1.首次请求数据不在缓存中 可以提前把热点数据放入缓存中
○ 2.写操作频繁,导致缓存频繁被删除,影响缓存命中 数据库和缓存一致,更新数据库并删除缓存,需要添加一个锁保证更新缓存时不存在线程安全问题 数据库和缓存不一致,允许较短时间内,给缓存设置一个较短的时间,缓存过期会同步更新最新的数据库数据
○ 读写穿透
■ 存在首次获取缓存数据不存在问题,可以提前将热点数据放入缓存中
○ 异步缓存写入
■ 相比读写穿透模式,异步缓存写入是在缓存读写操作以后一定时间内更新数据库 存在问题,会有数据丢失问题,比如服务器宕机情况下,适用于那种数据实效性不强,数据一致性要求不那么高的场景
哨兵模式
redis 实例大于3,master 主节点,node 从节点
Sentinel 的三个作用是什么?
○ 监控
○ 故障转移
○ 通知
Sentinel 如何判断一个 redis 实例是否健康?
○ 每隔 1 秒发送一次 ping 命令,如果超过一定时间没有响应则认为是主观下线
○ 如果大多数 sentinel 都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
○ 首先选定一个 slave 作为新的 master,执行 slaveof no one
○ 然后让所有节点都执行 slaveof 新 master
○ 修改故障节点配置,添加 slaveof 新 master
redis 碎片
产生原因
○ redis向操作系统申请的数据存储空间大于实际数据需要的存储空间
○ 频繁的修改数据也会导致内存碎片的产生,因为数据库删除并更新缓存,该数据内存并不会轻易还给操作系统
查看内存碎片
○ info memory
清理内存碎片
○ 采用redis自动内存碎片清理可能会对redis性能完成影响
更新数据库成功,删除缓存失败
常见解决思路
○ 增加cache重试机制,可以动态自定义设置cache更新的次数