《Redis核心技术与实战》读书笔记
2022-04-24 09:59:50 4 举报
AI智能生成
作为KV数据库,redis在互联网行业应用十分广泛,面试高频知识点,redis在CPU使用、内存组织、持久化和网络通信方面的设计非常经典,非常值得学习
作者其他创作
大纲/内容
数据结构
简单动态字符串
整数数组
双向链表
跳表
散列表
压缩列表
Stream
消息队列
数据类型
基本数据类型
ZSet
Set
Hash
List
String
扩展数据类型
BitMap
二值场景,比如签到
HyperLogLog
基数统计
GEO
LBS
RedisTimeSeries
时间序列
自定义数据类型
键K&值V存储结构
全局哈希表
哈希冲突
链式哈希
rehash
原理
哈希表1和哈希表2,默认写哈希表1,满了后扩容哈希表2、哈希表1转移到更大容量的哈希表2
渐进式rehash
每次请求执行
定时执行
IO模型
IO多路复用(epoll)
持久化
AOF
AOF日志内容
命令
后写
先执行命令,后写AOF日志
写回策略(appendfsync)
Always
同步写,主线程执行
Everysec
先写AOF文件缓冲区,定时入盘
No
先写AOF文件缓冲区,交给OS入盘
AOF重写
子进程执行bgrewriteaof
可靠性保证
重写期间,写命令往两个AOF文件缓冲区写
阻塞点
fork子进程
内存页表(虚拟内存和物理内存的映射)的拷贝,实例越大,内存页表越大
写时复制
AOF重写期间,写命令主线程需要申请新的内存空间,按页申请,每页默认4k
huge page 建议关闭
RDB
RDB日志内容
压缩后的二进制数据
命令
save主线程
fork bgsave 子进程(默认)
阻塞点
同AOF重写
混合
RDB间隔期间记录AOF
最终是一个混合RDB的AOF文件
主从模式
读写分离
主库提供读写,从库提供读
主从同步
replicaof
子进程执行
同步内容
RDB文件(全量同步)
replication buffer(增量同步)
主从建立连接后创建
同步步骤
1、主从建立连接,协商同步,主库生成RDB,从库记录主机信息和复制进度信息
2、发送RDB文件,从库先删库后回放RDB
3、发送replication buffer,从库加载replication buffer
网络断连
repl_backlog_buffer
一直存在,主库会一直写
环形结构,存在覆写的可能
调整参数repl_backlog_size大小
对比offset,进行增量同步
如果出现覆写,必须执行一次全量同步
找到主从差异后,最终还是发送replication buffer
主-从-从模式
级联复制
脑裂
主库假死
min-slaves-to-write
主库能进行数据同步的最少从库数量
假设从库有 K 个,可以将 min-slaves-to-write 设置为 K/2+1(如果 K 等于 1,就设为 1),
min-slaves-max-lag
主从库间进行数据复制时,从库给主库发送 ACK 消息的最大延迟(以秒为单位)
将 min-slaves-max-lag 设置为十几秒(例如 10~20s)
可能存在的问题
主从不一致
同步延迟
监控主从复制差异,超过阈值便取消从库的连接,恢复后再连接
读过期数据
过期延后
使用EXPIREAT/PEXPIREAT
主从时钟保持一致
删除策略
redis3.2以上版本
故障
配置不合理
protected-mode no
bind 配置项设置为其它哨兵实例的 IP 地址
cluster-node-timeout(10-20s)
哨兵模式
管理主从
任务
监控主从
周期性给主从发送PING,down-after-milliseconds时间内响应
主观下线
客观下线(真下线)
quorum
选新主
候选者
1、去除已断开连接的从库
2、去除断连超过一定次数的从库
规则
优先级
slave-priority
复制进度
比较offset
runID
越小越优先
通知客户端
基于pub/sub,哨兵发布,客户端订阅
哨兵定制了很多频道供客户端订阅
主库下线事件
从库重新配置事件
新主库事件
客户端主动查询
主从切换
读请求正常,写请求失败
leader选举
1、拿到半数以上投票
2、票数大于等于quorum
哨兵集群
主库发现机制
哨兵配置主库信息
哨兵发现机制
基于pub/sub,主库发布,哨兵订阅
从库发现机制
哨兵给主库发送INFO命令获取从库列表
客户端配置哨兵集群信息,而不是主从库信息
哨兵配置信息要保持一致
至少3个哨兵组成集群
down-after-milliseconds配置
1、越大,误判率越低,影响业务越久
2、越小,影响业务越短,误判率越高
切片集群
核心思想:数据分散保存在多个实例中
Cluster
16384个哈希槽
key根据CRC16算法得到对应的哈希槽
16384个哈希槽分布在不同的redis实例
自动分配
手动分配
每个实例互相拥有各自的哈希槽信息,去中心化
Gossip 协议通信
PING
PONG
客户端缓存哈希槽和实例的映射关系
重定向机制
哈希槽重新分配
redis实例新增删除
负载均衡
相关命令
MOVED
会触发客户端的映射更新
ASK
ASKING
需要开发支持集群的客户端
集群规模上限1000个实例
数据倾斜
数据量倾斜
bigkey
避免
拆分
Slot分配不均衡
迁移
CLUSTER SLOTS
CLUSTER SETSLOT
CLUSTER GETKEYSINSLOT
MIGRATE
Hash Tag
key中需要参与计算的部分加上花括号
不同key拥有相同的部分,可以通过Hash Tag分配到同一个实例中
数据访问倾斜
热点数据
针对只读热点数据,增加副本,key加随机前缀,分配到不同实例
针对读写热点数据,只能增加资源
Codis
四大组件
codis-server集群
基于redis的二次开发产品
codis-proxy集群
代理层,客户端与此交互
zk集群
配置中心
codis dashboard&codis fe
web可视化运维
数据分布和路由
1024个哈希槽
哈希槽分配
dashboard
手动分配
自动分配
dashboard将哈希槽和server的映射关系存储到zk集群
proxy将哈希槽和server的映射关系缓存到本地
key根据CRC32算法得到具体的哈希槽,根据映射关系得到具体的server,由proxy代理请求
扩容和迁移
扩容
新增server
新增proxy
迁移
同步迁移
server阻塞
异步迁移
server不阻塞,异步等到目标server的ACK确认
迁移的数据设置为只读
bigkey迁移优化
临时过期时间
拆分指令
可靠性
针对每个server增加哨兵主从
Redis异步线程(4.0)
pthread_create创建子线程处理异步任务
bigkey的删除
推荐UNLINK
清空数据库
在 FLUSHDB 和 FLUSHALL 命令后加上 ASYNC 选项
AOF日志写
多核CPU
多核架构
多个物理核,利用超线程技术,每个物理核可以包含2个逻辑核
NUMA 架构
CPU socket
几个物理核组成一个socket,共享一个L3
一个应用程序访问所在 Socket 的本地内存和访问远端内存的延迟并不一致
三级缓存
L1、L2物理核私有
逻辑核共享物理核的L1、L2
L3物理核共享
redis绑核
避免 Redis 总是在不同 CPU 核上来回调度执行
命令
taskset
避免 Redis 跨 CPU Socket 访问网络数据
把网络中断程序和 Redis 实例绑在同一个 CPU Socket 上
lscpu
查看核编号,便于准备绑核
风险
产生CPU竞争
方案
绑定物理核而非逻辑核
优化源码
内存碎片
不够大且又不连续的一系列内存
来源
内存分配器策略
固定大小分配
数据所需大小和分配的大小不一致
数据的修改删除
判断
INFO memory命令
1<mem_fragmentation_ratio<=1.5
合理
mem_fragmentation_ratio>1.5
重启redis实例(不推荐)
碎片整理
activedefrag
开启自动碎片整理
active-defrag-ignore-bytes
内存碎片的字节数阈值
active-defrag-threshold-lower
内存碎片空间占操作系统比例阈值
active-defrag-cycle-min
用 CPU 时间的比例下限阈值
active-defrag-cycle-max
用 CPU 时间的比例上限阈值
缓冲区
场景
暂存客户端发送的命令数据,或者是服务器端返回给客户端的数据结果
主从节点间进行数据同步时,用来暂存主节点接收的写命令和数据
输入缓冲区
溢出
bigkey
服务端处理过慢
查看缓冲区CLIENT LIST
qbuf
已使用大小
qbuf-free
剩余大小
无法调整大小,默认1G
注意点
避免 bigkey
避免redis主线程阻塞
输出缓冲区
固定大小16K
OK和错误信息
动态大小
溢出
返回bigkey大量数据
monitor命令
产线禁止使用
缓冲区设置太小
client-output-buffer-limit配置
原子操作
单个命令实现多个命令
Lua脚本
redis事务
命令
MULTI、EXEC
类似begin和commit
MULTI开启事务,后续的操作会先放入队列,EXEC真正执行操作
ACID
原子性
入队报错,保证
执行报错,不保证
实例宕机,开启AOF时保证,不开启不保证
一致性
执行报错不保证,其他保证
隔离性
WATCH机制保证
持久性
由于redis持久化机制不保证数据不丢失,因此不保证
应用场景
缓存
淘汰策略
noeviction
volatile-random
volatile-ttl
volatile-lru
volatile-lfu
allkeys-random
allkeys-lru
allkeys-lfu
缓存类型
只读缓存
读写缓存
同步直写
可靠性高
异步写回
低延迟
缓存一致性
缓存穿透
访问不存在的key
缓存默认值或者空值
布隆过滤器
缓存击穿
热点数据过期
热点数据不设置过期时间
缓存雪崩
大量key同时过期
过期时间加盐
服务降级
非核心数据直接返回预定信息,核心数据查询数据库
实例宕机
熔断、限流
主从集群
分布式锁
单个redis
加锁
SETNX
PX,增加锁失效时间,防止占用过久
区分客户端加锁,解锁时进行匹配,防止误解锁
解锁
lua脚本
多个redis
Redlock
思想:让客户端和多个独立的 Redis 实例依次请求加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,那么我们就认为,客户端成功地获得分布式锁了,否则加锁失败
加锁
加锁步骤
1、获取客户端时间
2、客户端按顺序依次向 N 个 Redis 实例执行加锁操作
3、一旦客户端完成了和所有 Redis 实例的加锁操作,客户端就要计算整个加锁过程的总耗时。
加锁成功条件
客户端从超过半数(大于等于 N/2+1)的 Redis 实例上成功获取到了锁
客户端获取锁的总耗时没有超过锁的有效时间
解锁
执行N个解锁的Lua脚本
消息队列
三大保证
有序
可重复消费
消息需要有唯一ID
消费端支持幂等
消息可靠性
基于LIST
先进先出
有序性保证
存
LPUSH
生产者保证消息的唯一ID
取
RPOP
消费者需要不断循环主动获取
BRPOP
阻塞式获取
BRPOPLPUSH
备份消息
可靠性的保证
不支持多个消费者
基于Streams(redis 5.0)
存
XADD
保证有序,自动生成唯一ID
ID规则:毫秒戳+当前毫秒戳的序号,如:1599203861727-0
取
XREAD
可以按照ID读取
支持阻塞式读取
XGROUP
创建消费组
XREADGROUP
消费组读取消息
可靠性
内部队列留存消息,收到XACK后删除
XPENDING
查询每个消费组内所有消费者已读取但尚未确认的消息
XACK
向消息队列确认消息处理已完成
秒杀
特征
瞬时并发量访问大
读多写少
阶段
秒杀前
商品详情静态化,CDN、浏览器缓存等加速访问
秒杀中
查询库存和扣减库存在redis中操作,并保证原子操作
利用分布式锁,保证只有一个客户端能查询库存扣减库存
秒杀后
退单、下单、支付、出库、物流等在数据库执行
布隆过滤器
Bitmap
注册中心
map存储结构
限流
zset
数据库
redis6.0新特性
IO多线程
并行的网络IO
io-threads-do-reads yes
io-threads 6
io-threads-do-reads yes
io-threads 6
客户端缓存
Tracking功能
普通模式
CLIENT TRACKING ON|OFF
服务端监测客户端读取的key是否有修改,发生变化便给客户端发送invalidate消息
读一次,监测并在修改时反馈一次
CLIENT TRACKING ON|OFF
广播模式
CLIENT TRACKING ON BCAST PREFIX user
客户端注册希望监听的key的前缀
服务端广播给所有注册的客户端
CLIENT TRACKING ON BCAST PREFIX user
权限控制ACL
创建用户并分配权限
RESP3.0
RESP2.0
字节数组形式进行编码,需要解码
直接通过不同的开头字符,区分不同的数据类型
NVM内存
传统DRAM内存
优点
直接持久化保存数据
读写速度接近DRAM
大容量
AEP内存工作模式
Memory模式
不持久化
App Direct 模式
持久化
Java客户端
Jedis
Redisson
lettuce
收藏
收藏
0 条评论
下一页