高性能
线程模型
redis为什么那么快?
纯内存存储
数据结构好
单线程 非阻塞 为啥非阻塞 减少上下文切换 并发安全的问题?
异步
多路IO多路复用
通常说redis是单线程,主要是指网络IO和键读写是由一个线程执行,其他功能 持久化RDB AOF,异步·删除 淘汰策略,数据同步 主从 分片 同步 保证数据一致 由额外线程执行
为什么不用多线程? 架构思想 技术迭代 6.0 redis 多线程
多线程 需要线程切换,需要对共享资源的并发访问控制 如果用粗粒度 范围比较大 的锁,增加了线程,线程也会相互等待,并行变串行 排队 吞吐量没有增加。
多路复用 复用的是什么?
bind 绑定端口 6379
listen 监听端口
accept 建立连接 阻塞 监听到客户端连接请求,一直没成功,阻塞,导致其他客户端连不上
命令 Get key1 socket 插座 套接字
recv 从socket 读请求 阻塞 从客户端读数据,数据一直没到达,阻塞
parse 解析请求
get 读取命令 数据结构里去拿数据 从redis value1
send 返回结果,向sockte写数据 value1
单线程 上面的所有操作都是一个线程依次执行
效率低下
多路复用 多路IO
使得网络io操作能并行处理大量客户端请求 实现高吞吐率
怎么解决网络上两个阻塞 ?
套接字 socket linux 访问网络的一个api
针对监听套接字 accept 设置非阻塞模式 不等待
针对已经连接套接字 recv 设置非阻塞模式 不等待
不等待,去干别的事,得需要有人来通知 ? 谁来通知 内核
select poll epoll 闪亮登场 网络编程绕不过去的坎
允许内核中存在监听这些socket 套接字的连接请求或者数据请求,一旦请求或者数据到达,就会交给redis线程处理。
事件 一个连接来了,数据可以,数据可以写 事件驱动
怎么交给redis ?
事件回调 callback 可以结合rocket-mq 异步发送 成功 onSuccess 返回, mq 回调了生产者.
触发事件 然后放到事件队列,redis 单线程对该队列不断处理
调用相应的函数 ,一直对事件队列处理 及时响应
Redis 注册 accept 事件和read事件 到内核 ,内核监听到连接请求和读数据请求 调用相对的
accept 和get 函数处理
一个redis 线程处理多个io流的效果 多路复用 epoll
银行
客户(Redis客户端 )先去大堂经理 登记 询问 拿号(相当于排队,因为银行取钱太慢了)等前置工作,如果只有一个柜台(redis服务器的唯一的线程)人员来做效率低。
大堂经理(内核)一直处理 取钱 存钱 之前的工作 类似内核监听请求 然后转交给柜台
一个柜台 存钱,取钱 从内存取,没有并发控制。
Linux select epoll
FreeBSD kqueue
NIO epoll 多路复用
思考
6.0 版本提出了多线程模型,会不会引入复杂的并发控制,会带来多大性能提升?
网络编程
http://cw.hubwiz.com/card/c/56f9ee765fd193d76fcc6c17/1/3/2/
https://blog.csdn.net/weixin_39258979/article/details/80835555
Select poll epoll
https://www.xiaolincoding.com/os/8_network_system/selete_poll_epoll.html#总结
C10K
https://segmentfault.com/a/1190000007240744
数据结构
高效的数据结构,hash,跳表,Skiplist二分
放到内存里
能存什么
String 简单动态字符串
List 双向链表 压缩列表
Hash 哈希表 压缩列表
Sortd Set 跳表 压缩列表
Set 哈希表 整数数组
压缩列表 ziplist
元素少于一个定条件使用
为什么不用链表
链表存储关联是通过指针有序串联,地址不连续 随机IO
ziplist 是连续的内存块 顺序IO
磁盘读写机制 顺序IO效率高于随机IO
为什么不都用顺序IO
连续内存,意味创建和扩展的时候需要操作更多内存。连续的一大块
所以元素少的时候使用ziplist提升效率 局部性原理
O(1) 方式操作两端
数据很少 O(N) 问题不大
跳表 增加多级索引,实现快速定位
底层结构
一个件对应一个集合 大map dict
优点
O(1) 快速查找
缺点
哈希冲突
哈希冲突的概念
两个key的哈希值和哈希桶计算位置时,做好落在同一个哈希桶
Redis 如何解决 链式哈希
同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。
数据越来越多 冲突越来越多 链表越来越长,冲突链上只能通过指针依次查找 效率低下
怎么解决
rehash 扩容
增加现有的哈希桶数量,让增多的元素在更多的分散,减少单个桶的元素数量,减少冲突。
为了更高效
Redis 搞了两个全局哈希表 哈希表1 哈希表2
模式使用表1 表没有分配空间 数据越来越多
1 给表2 分配更大空间
2 把表1 的数据重新映射并拷贝到表2
3 释放表1
结合 jdk的map 理解
表1 切换 表2 ,原来的表1 留作下一次 rehash 扩容备用。
拷贝数据的时候会造成 redis 线程阻塞
渐进式 rehash 边提供服务,边拷贝 ,一次大量拷贝分摊到多次处理请求
每处理一个请求 ,从表1 中第一个索引位置开始,把这个索引位置上的数据拷贝到表2
下一次请求 从下一个索引位置 继续拷贝 。
思考
不同库
关系型 mysql oracle
K - V redis getall keys 阻塞
列式 hbase
Es doc Lucene 搜索 倒排索引 MongoDB doc
时序数据库 influxdb
持久化
AOF
Append Only File
写前日志 先写日志,后执行数据库操作 mysql redo log
写后日志 先执行命令,数据写入内存,后记录日志
redis 用的是写后日志 记录的是具体的命令 set Akey Avalue 写命令
优点
不需要检查语法,命令成功了,记日志,命令失败直接返回。避免记录错误命令 用来恢复的 快 拦截了错误的命令 文件会小, 快
不会阻塞,命令执行后才记日志,不会阻塞当前写操作 快
缺点
命令成功了,没写日志,系统宕机了,丢失风险
AOF日志在主线程执行,如果磁盘压力大,也会阻塞
三种回写机制
结合mq mysql 刷盘
Always 同步写回 命令写完,立即同步写日志到磁盘 性能影响大
Everysec 每秒写回 命令写完,日志写到AOF文件内存缓存区,每隔一秒刷盘 宕机丢一秒数据
No 操作系统控制 命令写完,日志写到AOF文件内存缓存区,操作系统决定什么时候刷盘 宕机丢数据较多
面试题
Redis 怎么保障数据不丢失?
AOF 记录的是命令,文件越来越大怎么办? AOF 重写机制
文件大带来性能问题
1 系统大小有限制,太多没法保存
2 继续写性能低
3 恢复慢
AOF 重写机制
多变一
执行了很多次
1 Set Akey Avalue
2 Set Akey Bvalue
...
合并成一次
Set Akey Bvalue
AOF 重写回阻塞么?
不会
重写由后台子进程 bgrewriteaof 完成
主线程fork出后台子进程 bgrewriteaof ,把主线程的内存拷贝一份给 bgrewriteaof 子进程,
bgrewriteaof 不影响主线程干活,把数据搞成操作命令,记日志到新的AOF文件
新来的数据怎么搞?
主线程未阻塞 会有新的的数据进来,redis 把新的数据写到缓存区
当前数据 + 缓存区的数据(新的数据) = 完整数据 丢不了
bgrewriteaof 记完后,最新操作也写入 新的AOF 文件
AOF日志为什么不共享原来的日志?
AOF 的缺点
恢复时 按照操作日志 命令 一条条搞,慢
ROB
Redis DataBase
内存快照,某一时刻的内存数据 拍个照。记录的是数据不是命令,恢复的时候直接读入内存,快。
问题
给哪些人拍照,最好全拍,数据完整
人多怎么协调?
会阻塞主线程么
两个命令
save 在主线程中执行,会导致阻塞
bgsave 搞个子进程,专门写入RDB,模式配置
bgsave 拍照的时候 人还动么?
不能动,新的操作怎么办?性能不好
能动 人拍不全 不完整
为了拍照,不让新人进来,不行
CopyOnWrite 写时复制
主线程 fork bgsave 子进程程,可以共享主线程所有内存数据
读 主线程和子进程相互不影响
写 这块数据被复制一份,生成副本,主线程在副本上操作,bgsave 在原来的数据操作,写入RDB
快照完整,主线程允许修改。
多久拍一次照?频率
1点拍一次 RDB
2点拍一次 RDB
1点半宕机 ,1点之后写的数据丢了。半个小时
是不是拍的越频繁越好 ?一秒一次?
磁盘压力大。一个还没做完,另一个又开始了,恶性循环。
fork过程会阻塞主线程。内存越大,阻塞时间越长。
增量快照
拍了一次以后,后续只对新进来的人加入快照,需要记住哪些人是新进来的?
增加额外的空间开销
怎么办?
混合使用AOF和RDB
照片一定频率的拍
拍照区间用AOF记录
文件恢复的又快,又不丢数据。好
问题
注意
单机的数据不要太大 在什么业务数据量的情况下 选择 主从结构 还是分片结构 分布式存储 数据分片
单点故障 系统一台机器 AOF RDB 可靠性可以保障么 ? 不能
扩展
写时复制 融汇贯通
https://www.cnblogs.com/jmcui/p/12377081.html
高可靠
主从复制
数据是怎么同步的?
redis 为啥不搞? 分布式事务 2PC ? 慢
AOF和RDB可以恢复数据,尽量保证数据不丢。
单点故障 ,恢复期间,不可用
怎么保证可用
多副本 主从
多副本的数据怎么保持一致?数据同步
Redis 主从模式
读写分离
读 主库 从库
写 主库 ,主库同步写给从库
为什么读写分离?
可以提高性能,把读的压力打散
能不能主从都写?数据乱套了,如果要保持一致,加锁,主从间协调 太复杂。
复制原理
第一次复制
第一步
从库和主库建立连接 从库发送 psync 告诉主库同步数据,两个参数 主库的runId,复制进度 offset
runId 随机id,唯一标识实例
第一次复制
runId ? 表示 不知道
offset -1 表示 第一次
主库收到命令 响应 FULLRESYNC 命令带两个参数 主库runId和主库目前复制进度返回给从库,
从库记录参数
第一次 复制进度是 全量复制 offset 全量
第二步
主库把所有数据同步给从库,从库收到数据,本地完成加载。
主库bgsave 生成 RDB (文件不能太大)将文件发给从库
从库接收到文件,清空当前库。
同步过程中,主库不会阻塞,生成RDB后新的写操作会记录在主库的 replication buffer
第三步
主库完成rdb发送后,把replication buffer中新的数据发给从库,从库再执行下,数据同步完成。
问题
主 生成RDB 传输RDB
一个主 多个从,好多从都来主上拉,主太累了。多次fork 阻塞请求,网络被占满。
主
从 从 从
分级
主
从
从
从
主
从从
从
把压力分散到从库上
后续通过长连接 命令传播,持续同步。
风险
网络断了,阻塞
2.8 之前 重新来一遍全量复制 开销大 不靠谱
2.8之后 增量复制
网络出问题了 主库把出问题期间的写命令 写入replication buffer,同时写入
repl_backlog_buffer replay
repl_backlog_buffer 是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。
坑
key3 和 key4 还没同步
repl_backlog_buffer 是一个环形缓冲区,缓存写满后,主库继续写,会覆盖掉之前的写入操作。
如果从库读的慢,可能导致从库还没读,就被写给覆盖了,导致主从数据不一致。 分布式锁
repl_backlog_size 参数
缓冲空间的计算公式是:
缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小
在实际应用中,可能存在一些突发的请求压力,留点buffer 2倍。
要压测 如果并发量很大,还需要调整 repl_backlog_size 参数。
如果还不行,考虑分片 cluster
哨兵机制
裁判 集群 多个裁判
特殊的redis 进程, 他和主从同时运行
主从模式,
从挂了,客户端不影响 去其他从读
主挂了,从库没法同步数据,写也不行了
集群不可用 怎么办?
3个问题 一个角色 一个家伙
监控 主库真的挂了么? 网络问题
选主 真的挂了,选哪个从库变为主库 选主机制 规则
通知 新主库的信息怎么通知给从库和客户端
怎么办?
基本原理
监控 不间断的 PING 心跳,规定时间给回复, 下线状态 主观下线 客观下线? 多个裁判都看下
选主 从多个从库里按照特定的规则选择一个合适的库
什么规则?
少数服从多数
数据比较全
筛选 + 打分
性能比较 网络响应的状态 过去的行为
运维配置 运维可以配置优先级
数据最全 大小? repl_offset
三个条件 都一样了,该选谁?
随机
从新选 影响性能 redis 保证快
每个实例都一个id ,最小id得分最高,选为主 简单粗暴
哨兵挂了,怎么选主 哨兵集群,高可用 哨兵集群组成方式
pub/sub 发布订阅机制 频道 (可以理解为 mq里的topic)
https://zhuanlan.zhihu.com/p/344269737
哨兵通过订阅频道互相发现,相互通信
哨兵和主库建立连接,就可以在主库上发布消息IP和端口,也可以从主库上订阅消息获取其他哨兵发布的连接信息
哨兵1 把自己的IP和端口 发布到主库 __sentinel__:hello 频道上,哨兵2 和哨兵3 订阅频道
哨兵2 和哨兵3 知道了哨兵1 的IP和端口
哨兵2 和哨兵3 可以和哨兵1 建立网络连接,通过这种方式 哨兵2和哨兵3 也可以建立连接。
彼此相互通信 。
哨兵还需要和从库建立连接 。判断心跳,主从切换后,通知从库
怎么知道从库的信息呢?
哨兵向主库发送info 命令获取从库列表,然后和每个从库建立连接,进行监控心跳。
INFO
https://blog.csdn.net/qq_33449307/article/details/120609365
主从切换后要把新主库的信息告诉客户端
通知 用pub/sub来实现的 redis 列表
客户端从哨兵订阅消息获取事件
主库下线事件 +sdown -sdown +odown -odown
从库重新配置事件 +slave-reconf-sent +slave-reconf-inprog +slave-reconf-done
新主库切换 +switch-master
客户端读取哨兵配置信息后,建立连接,订阅频道,获取信息。
哨兵
哪个哨兵执行主从切换? 少数服从多数
1 先判断客观下线
任何一个实例只要判断主库 主观下线 给其他实例发送 is-master-down-by-addr 命令
其他实例根据自己和主库的连接情况 投赞同还是反对。
一个哨兵获得仲裁需要的票数 哨兵配置文件配置 quorum 配置,可以标记主库客观下线,然后给其他哨兵发送命令
说我来搞我要进行主从切换,你们来投票
两个条件
1 拿到半数以上的赞成票
2 拿到的票数还需要大于等于 quorum 配置
面试题 配置两个哨兵可不可以,不可以,有个哨兵挂了,不能选主
判断主观下线后
1 投票都选自己
2 自己投过票了,收到别人的的选举信息,都说反对,会对第一个收到的投票信息同意 主打时间差 网络更好
3 网络慢的还没投票
获取半数以上赞成票 达到预设的quorum值 (配置)
如果通过一轮选举没成功选主
哨兵集群会等待一段时间 哨兵故障转移超时时间的 2 倍 ,再重新选举。成功选举投票 依赖选举命令的正常网络传播 。
要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds
很少发生哨兵同时判定主客观下线
依据网络连接,系统压力,接收到下线协商的是的时间也不同,一般都有先后顺序。
哨兵对主从状态检查是一个定时任务,间隔固定时间,每个哨兵执行的是一会加一个小小的随机偏移
错开
https://www.cnblogs.com/ivictor/p/9755065.html
Cluster
数据越来越多了?
2G 主 2G 从1 2G 从2 2G
20G 主 20G 从1 20G 从2 20G 不太行 分片 RDB 持久化 太大了,网络也慢, 影响性能
fork 在执行的时候会阻塞主进程 redis 响应变慢了
搞多个主,每个主上存部分数据, 所有的主合并在一起是完整的数据
数据库分库分表
横向扩展 多增加实例数. 加服务器 去IOE
纵向扩展 单机上升级硬件 redis 加配置 加内存,加硬盘 简单
Hash slot 哈希槽 数据和实例的关系 数据分区, 分片 16384
CRC16算法 来算这个key 发到哪个槽
Redis Cluster 采用虚拟槽分区,所有的键根据哈希函数映射到 0~16383 整数槽内,计算公式:slot = CRC16(key) % 16384。每个节点负责维护一部分槽以及槽所映射的键值数据
Redis 节点 机器1 槽 448
Redis 节点 机器2 槽 555 444
KEY sku_商品分类_1 VALUE aaa
KEY sku_商品分类_2 VALUE bbb
sku_商品分类_1 存到 448 机器1
sku_商品分类_2 存到 555 机器2
Hashtag {sku_商品分类} 444 , 存到 机器2 (有可能放了大量的数据 导致数据倾斜) 不用分别从不同的槽aaa bbb 不同的机器 机器1 机器2 上获取 .
仅{...}里的部分参与hash计算
Redis 默认 16384/N(实例数量)
通过命令手动指定 必须 16384 把分完
0- 16380 实例1 16381 - 16384 实例2
0- 16380 实例1 16381 - 16382 实例2 还差点 槽没分完 无法工作.
https://blog.csdn.net/m0_46405589/article/details/109336289
客户端怎么定位数据
哈希槽 数据和实例的关系
数据找到槽,找到实例
客户端和集群实例建立连接,实例会把槽的分配信息发给客户端,
集群刚创建的时候 每个实例知道自己的 不知道别人的
Redis 实例会把自己的哈希槽信息发给和它相连的其他实例,完成哈希槽分配信息的扩散
每个实例就会有所有哈希槽的映射关系
客户端收到哈希槽信息后,把哈希槽信息缓存到本地,客户端请求时计算键对应的哈希槽和对应的实例,就知道往哪发请求了
实例和hash槽的关系会变么?
会变
实例新增或者删除 重新分配
为了负载均衡 ,redis 重新分布
实例相互知道,客户端无法自动感知
重定向机制
客户端到实例1 get a 槽变了 -- MOVED 槽信息 实例信息
客户端根据MOVED 的信息去执行命令,并更新本地缓存
记录 槽和实例关系. 客户端记录下正确的节点与槽之间的对应关系 – 槽位路由表
数据迁移中如何处理?
ASK
正在迁移槽
属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点
1 如果找到的话,就直接执行客户端发送的命令
2 如果节点没有在自己的数据库里找到键key,那么节点会检查自己的clusterState.migrating_slots_to[10086],看键key所属的槽10086是否正在迁移,如果在迁移,节点会向客户端返回ASK错误,引导客户端到正在导入槽10086的节点去查找 键key
客户端 在 7001 节点
GET "hello"
hello在10086槽上 正在7002节点上迁移
7001 节点返回 ASK 10086 127.0.0.1:7002
客户端会转向至节点7003
先 ASK 目标节点 唯一要做的就是打开发送该命令的客户端的REDIS_ASKING标识
ASKING
然后发送命令
GET "hello"
得到结果
如果客户端不发送ASKING命令,而直接发送命令,命令将被节点拒绝执行,返回 MOVED错误
它们的区别在于:
MOVED错误代表槽的负责权已经从一个节点转移到了另一个节点: 在客户端收到关于槽i的MOVED错误之后,客户端每次遇到关于槽i的命令请求时,都可以直接将命令请求发送至MOVED错误所指向的节点,因为该节点就是目前负责槽i的节点。
与此相反,ASK错误只是两个节点在迁移槽的过程中使用的一种临时措施: 在客户端收 到关于槽i的ASK错误之后,客户端只会在接下来的一次命令请求中将关于槽i的命令请求发 送至ASK错误所指示的节点,但这种转向不会对客户端今后发送关于槽i的命令请求产生任何 影响,客户端仍然会将关于槽i的命令请求发送至目前负责处理槽i的节点,除非ASK错误再 次出现
————————————————
版权声明:本文为CSDN博主「你走吧起风了__」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46405589/article/details/109474477
https://blog.csdn.net/wf13265/article/details/115209721
淘汰策略
LRU
noeviction:不淘汰任何数据,当内存满时,新的写入操作会报错。
volatile-lru:淘汰设置了过期时间的数据中,最近最少使用的数据。这种策略适用于缓存数据,可以保证缓存中的数据都是最近使用过的。
volatile-ttl:淘汰设置了过期时间的数据中,距离过期时间最近的数据。这种策略适用于一些临时性的数据,可以保证数据不会过期。
volatile-random:淘汰设置了过期时间的数据中,随机选择一个数据进行淘汰。
allkeys-lru:淘汰所有数据中,最近最少使用的数据。这种策略适用于缓存数据和持久化数据混合使用的情况。
allkeys-random:淘汰所有数据中,随机选择一个数据进行淘汰。
可以根据具体的业务需求和数据特性选择合适的淘汰策略。例如,对于一些重要的数据,可以采用 noeviction 策略,以保证数据的完整性;对于一些缓存数据,可以采用 volatile-lru 策略,以保证缓存的有效性
怎么实现? 自己去了解淘汰策略
定期删除
惰性删除
https://blog.csdn.net/wzngzaixiaomantou/article/details/125533413
面试题
内存占用飙升 内存碎片 https://cloud.tencent.com/developer/article/1977637
数据结构 淘汰机制
性能 阻塞 抖动 bigkey https://blog.csdn.net/Weixiaohuai/article/details/125391957
慢日志定位 https://www.jb51.net/database/29201207v.htm
AOF重写 RDB 数据结构 异步机制
主从 数据丢失 主从不一致
AOF 重写 RDB AOF 哨兵机制
分片 数据热点 秒杀
数据分布
缓存 污染 雪崩 穿透
淘汰机制
分布式锁
Gossip
https://zhuanlan.zhihu.com/p/591595985
通用解决方案
缓存雪崩
redis的数据大部分都失效了,然后直接打到了数据库,压力激增
限流 多线程能不能解决? 线程池来限流
缓存中大量数据同时过期?
别让他同时,随机
EXPIRE 设置过期时间
兜底 最后的解决方案
服务降级
非核心数据,返回一些预定义的数据,或者空值.
包含数据库,别给整死
限流
核心的组件 要限流
熔断 保险丝,太热的 流量太大,断掉
缓存穿透
数据不在缓存,数据库也没有
-1
恶意攻击 频繁范围 查询 一个不存在的数据
Bug
返回一个空值或者默认值
布隆过滤器 怎么实现的? 快速判断某个数据是否存在
网关 zuul spring-gateway
全局网关
业务区分 大交易网关
交易 商品,订单 支付 ...
鉴权 门户
Nginx
Lvs keep-lived
缓存击穿
某个访问非常频繁的热点数据 访问量激增
永久不失效
分布式锁 分段锁的概念
java中的锁
https://mp.weixin.qq.com/s?__biz=MzUzMDkxMjUwMg==&mid=2247484010&idx=1&sn=ec5aa8b0d15b69444f3d84bf8719d286&chksm=fa4bc7f3cd3c4ee571aadfc4f0213dc8f815e27ed742bd8f5cf93ef16118829fe4ecac5f1b07&scene=27
缓存一致性
缓存是删除还是更新 ?
删除 lazy 思想
删除还是更新缓存
删除缓存:数据写入数据存储,并从缓存删除
优点:简单
缺点:缓存增加一次miss,需要重新加载数据到缓存
更新缓存:数据写入数据存储,并更新缓存
优点:缓存不会增加一次miss,命中率高
缺点:更新缓存比淘汰缓存复杂
删除还是更新缓存主要取决于——更新缓存的复杂度,数据查询时间以及更新频率。
如果更新缓存复杂度低,从数据存储查询查询数据有比较耗时,更新频率又高,则为了保证缓存命中率,更新缓存比较适合。此外大大多数情景,都可以用删除缓存,来满足需求。
先更新数据库还是先操作缓存
此时如果缓存没有设置超时时间,则缓存里面的数据会一直都是旧的数据。
Cache Aside Pattern 里的原则之一 先更新数据库的情况
因为只有在第 2 步写数据库的请求比第 1 步查询数据的请求还快还会发生这种情况,由于数据库的特性,这种情况很少会存在,所以这种方案相对来说是比较可靠的。
命令有一个错了,就都不执行
Redis 是否提供了 回滚 ? Mysql rollback ?
Discard 放弃事务执行,把暂存的队列清空,起不到回滚目标 .
入队列就报错, 放弃事务执行,保证原子性 保证一致性
入队没报错, 执行的报错, 不能保证原子性 错误不执行,正确的执行 保证一致性
在执行的时候 redis出现故障了, 导致执行事务失败 保证一致性
AOF 重启 检查这个aof 里面的命令 把未完成的事务操作从aof文件中去掉, 恢复的时候不会再执行 保证了原子性
大部分保证原子性
隔离性
Watch 机制
执行事务之前 监控一个值或者多个值的变化 ,当执行 exec watch 会检查,如果发现别人修改了,放弃事务执行
持久性呢?
完全取决于 redis 持久的配置
总结 几乎不会用redis 搞这些事务性的操作 专业的人干专业的事 .
Transactional
https://www.shouxicto.com/article/1751.html
pub/sub
Reids 消息队列
https://zhuanlan.zhihu.com/p/343632121
分布式锁
Redis 分布式锁
1 怎么获取到这个值,判断这个值是否存在
redis怎么设置这个值0-->1 ,干活 释放 1-->0
加锁
原子性 Lua 脚本 redis能保证原子性
SETNX 判断键是否存在,不存在设置,存在不做任何设置 获取到锁
判断是否存在
T1 value= Get key 命令
If (value != null)
{
什么不干
} else {
设置 set 1 一个命令
}
T2 value= Get key 命令
If (value != null)
{
什么不干
} else {
设置 set 1 一个命令
}
EXPIRE/PEXPIRE EX / PX 设置过期时间 为什么需要过期时间?
使用带有EX选项或PX选项的SET命令除了可以减少命令的调用数量并 提升程序的执行速度之外,更重要的是保证了操作的原子性,使得“为 键设置值”和“为键设置生存时间”这两个操作可以一起执行。
区分来自不同客户端的锁操作
给每个客户端设置一个唯一的值
判断锁变量的值,是否等于执行释放锁的客户端的唯一标识
我加的锁,只能我来释放 ? 怎么搞?
Lua 来实现原子性
https://blog.csdn.net/wangshuai6707/article/details/131745530
存储这个变量值的共享系统,可靠性
A
B
C
Redis lock_xxx
A 如果这个lock_xxx 是0 ,我们设置为1 ,表示加锁成功.
B lock_xxx 是1 ,加锁失败
C lock_xxx 是1 ,加锁失败
Redis 会串行处理
释放锁
lock_xxx 设置为 0
Del
RedLock
全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁
1 客户端获取当前时间
2 客户端按顺序向 N个节点执行加锁 死锁
3 完成了所有节点的加锁操作 计算下总耗时
超过半数的节点上成功的获取到锁
总耗时没有超过锁的有效时间
效率不高
https://blog.csdn.net/aiwangtingyun/article/details/131252366 redlock
https://blog.csdn.net/qq_39350797/article/details/130226925 zk和redis 分布式锁的区别
Redisson
https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247545794&idx=2&sn=88a3b1c73372006b49a43a6c133a10c3&chksm=fbb1ba3cccc6332ae1f5e609ab5e37c32fe972b7ba3a18b1a92735c5f3e7c9300e2318ca2280&scene=27
https://www.processon.com/diagraming/5c6f8bbae4b07fada4ef81e4
数据倾斜
某些情况下 实例上的数据分布不均 某个实例上的数据特别多 slot 进行重平衡
数据相差不大,但是某个实例上是热点数据 (秒杀的上,热门商品) 访问非常频繁
Slot 分配不均 搞均匀了
hashTag 根据业务 放到一个集合,bigkey slow-log
bigkey 进行拆分 均匀分散
hash key field value
user_list 张三 15 全公司人员列表 好几千人 好几万人
Bigkey 集合类型 进行拆分 均匀分散
推荐书籍
Redis设计与实现
https://item.jd.com/10026483308952.html
https://jack-37.gitbook.io/gossip/