2.1 Redis的应用场景
- 缓存:用作缓存层,减少数据库负载,提高数据读取速度
- 实时系统:redis支持快速的数据写入和读取,非常适合实时分析
- 消息队列:利用Redis的list和pub/sub,可以实现轻量级的消息队列
- 分布式锁:Redis可以用作分布式锁的实现,确保在分布式系统中资源的安全访问,避免竟态条件
- 计数器:Redis的原子性操作非常适合用作计数器
2.2 内存存储
2.2.1 redis为什么这么快
- reids将数据存储在内存中,提供那个快速的读写速度,相比传统的磁盘数据库,内存访问速度快很多
- redis使用单线程事件驱动模型结合I/O多路复用,提高了并发效率(6.0引入多线程:随着数据规模的增长,请求量的增加,redis的执行瓶颈主要在于网络I/O,引入多线程处理可以提高网络I/O的处理效率,减少阻塞)
- 提供了多种高效数据结构
2.2.2 内存淘汰机制
redis的内存淘汰策略一共由8种
- 不淘汰数据(默认):
- noeviction:当运行内存超过最大设置内存的时候,不会淘汰数据,而是直接返回报错禁止写入
- 设置了过期事件的数据淘汰
- volatile_random:随机淘汰掉设置了过期时间的key
- volatile-ttl:优先淘汰掉较早过期的key
- volatile-lfu(3.0之前默认策略):淘汰掉所有设置了过期时间的,然后醉酒未使用的key
- volatile-lfu(4.0后新增):与上面类似,淘汰掉最少使用的key
- 所有数据的数据淘汰:
- allkeys-random:随机淘汰掉任意的key
- allkeys-lru:淘汰掉缓存中最久没有使用的key
- allkeys-lfu(4.0后新增):淘汰掉缓存中最少使用的key
2.2.3 过期删除机制
- 定期删除(每隔一段时间(默认100毫秒)随机检查一定数量的键,如果发现过期键则删除)
- 惰性删除:只有查询到相关数据才执行检查和删除操作,容易造成内存泄漏
2.2.4 内存碎片化
redis的内存碎片化是指内存使用中出现小块空间被闲置,无法被有效利用
- redis默认使用jemalloc作为内存分配器,它是按照固定大小来分配内存的
- INFO memory:可以通过INFO memory来查看内存碎片率(mem_fragmentation_ratio)
# Memory
used_memory:1000000 ## 实际申请的内存空间
used_memory_human:977.54K
used_memory_rss:1200000 ##表示实际占用的物理内存空间(含内存碎片)
used_memory_rss_human:1.14M
mem_fragmentation_ratio:1.20
ratio大于1证明存在内存碎片(过大需要清理),小于一说明已经使用swap用上磁盘空间了。
- 可以通过重启,重新分配内存解决,或者MEMORY PURGE
2.2.5 虚拟内存(VM)机制
Redis的VM机制曾经是redis早期版本(2.0之前)的一部分,用于将部分数据存储到磁盘,以扩展内存数据库的容量,当内存不足时,redis将冷数据(不经常访问的数据)移到磁盘,并将热数据(经常访问的数据)保留到内存中
- VM机制虽然使能使用的数据变多了,但也降低了高并发的性能,所以2.0之后不在使用
2.2.6 缓存和数据库的数据一致性
- 先更新缓存,再更新数据库
- 先更新数据库存,再更新缓存
- 先删除缓存,再更新数据库,后续等查询把数据库的数据回种到缓存中
- 先更新数据库,再删除缓存,后续查询把数据库的数据回种到缓存中
- 缓存双删策略,更新数据库之前,删除一次 缓存,更新完数据库之后,再进行一次延迟删除
- 使用binlog异步更新缓存,监听数据库的binlog变化,通过异步方式更新redis缓存
2.2.7 缓存穿透,缓存击穿,缓存雪崩
- 缓存穿透
- 概述:查询不存在的数据,导致请求直接打到数据库。
- 原因:用户请求的 key 不在缓存中,攻击者使用大量不存在的 key。
- 解决方案:使用布隆过滤器、缓存空值、请求限流(对异常流量进行限流和监控。)。
- 缓存击穿
- 概述:热点 key 缓存过期,瞬间大量请求直接访问数据库。
- 原因:热点数据的缓存过期,导致短时间内大量请求。
- 解决方案:加互斥锁、预加载数据(在缓存即将过期之前,提前更新缓存,确保热点数据一直有效)、热点数据永不过期。
- 缓存雪崩
- 概述:大量缓存同时过期,导致数据库压力激增。
- 原因:缓存系统重启或多个 key 同时过期。
- 解决方案:分散过期时间(为不同的缓存 key 设置不同的过期时间,避免集中失效。)、双缓存策略,将数据同时存储在两层缓存中
2.2.7.1 如何使用redis快速实现布隆过滤器
布隆过滤器是一种高效的概率数据结构,常用于检测一个 元素是否在一个集合中,可以有效减少数据库的查询次数,解决缓存穿透等问题 **1.可以使用位图来实现布隆过滤器
- 使用位图的setbit和getbit操作来实现布隆过滤器,位图本质上是一个比特数组,用于标识元素是否存在
- 对于给定的数据,通过多个哈希函数计算位置索引,将位图中响应位置设置为1,表示该元素可能存在 2.可以使用redisbloom模块
- redis提供了官方模块redisbloom,封装了哈希函数、位图大小等操作,可以直接用于创建和管理布隆过滤器
- 使用BF.ADD来向布隆过滤器添加元素,使用BF.EXISTS来检查某个元素是否可能存在
2.3 数据结构
2.3.1 常见数据类型
-
String (存储任意类型数据,最大长度512MB)(用于缓存和计数器,分布式锁,分布式session) 底层:基于SDS(simple dynamic string简单动态字符串)结构 并结合int、embstr、raw等不同的编码方式进行优化存储,SDS:使用len字段存储当前字符串的长度,因此可以在O(1)的时间复杂度下获取字符串长度 字符串长度小于44字节使用embs存储:redis使用jemalloc作为内存分配器,它以64字节作为内存单位进行内存分配,如果超过64字节,就超过了一个内存单位使用raw编码,而redis的字符串由redisobject和sdshdr这两个部分组成,redisobject大小为16字节,sdshdr(字符数组加上额外三字节存储信息,同时字符数组内还有’/0’)最后能用的只有44字节
-
List(任务调度和消息传递) 常用命令:lpush,rpush,lpop,rpop,lrange,lindex,llen,lset,lrem,ltrim 底层数据结构:linked list,ziplist(数据较少时使用)
-
Hash(快速检索) 一种键值对集合,适合存储对象类型的数据,适合小数据,增删查改效率高
- redis6之前底层式ziplist+hashtable,redis7之后是Listpack+hashtable
-
Set(无序,使用哈希表实现,支持快速查找和去重操作)(标签系统,唯一用户集合)
-
Sorted set 又称Zset(每个元素都有一个score用于排序,底层使用跳表实现)(排行榜,任务调度) 跳表:使用 多层链表实现,底层保留所有元素,而每一层链表都死下一层的子集,(插入,删除,查找都是从最高层逐层查找,更新) 四种高级数据类型
-
BitMap
-
HyperLogLog:基数估计算法,可用于快速计算一个集合中的不同元素数量的近似值(可以用来统计页面uv,比如将访问者ip地址作为元素加入到hyperloglog中)(无论集合有多少元素,hyperloglog结构的大小固定为12kb,这种内存效率使他非常适合处理大数据集的基数估计)(标准误差是0.81%) 原理: 1. 哈希函数 2. 前导零计数 3. 存储最大值 4. 基数估计
-
GEO(geolocation的缩写,地理坐标)底层使用sorted set 结合了geohash编码算法
-
Stream
2.3.2 redis如何实现队列和栈
- 可以通过List类型来实现队列和栈
- 队列使用LPUSH和RPOP
- 栈使用LPUSH和LPOP
2.3.3 redis如何快速实现排行榜
使用sorted set
- 使用sorted set存储分数和成员(Zadd命令)
- 获取排名(zrank)
- 获取前N名(Zrevrange)
2.3.3 Ziplist ,QuickList,listpack
-
ziplist存储在单个连续的内存块中,十分节省空间(存储元素可以是字符串或整数) ![[Pasted image 20241017175959.png]]
-
quicklist结合了ziplist和双端链表的优点,每个quicklist节点都是一个ziplist他限制了单个ziplist的大小,降低了级联更新产生的影响 ![[Pasted image 20241017181033.png]]
-
listpack是一种紧凑的序列化数据结构,用来替代ziplist(6.0引入,在list、hash、zset的内部实现中使用)(本质是字节数组)(因为ziplist的每个entry会记录之前entry的长度,所以会导致连锁更新,而listpack仅记录自己的长度)
2.4 持久化
2.4.1 RDB
- (redis database backup)快照: rdb是通过生成某个时刻的数据快照来实现持久化的,可以在特定时间间隔内保存数据的快照,适合灾难恢复和备份,能生成紧凑的二进制文件,但可能会在崩溃丢失最后一次快照之后的数据 持久化命令 save:在主线程生成RDB文件,因此生成期间,主程序无法执行官读写命令 bgsave:利用fork操作得到子线程,在子线程执行RDB生成,不会阻塞主进程,默认使用bgsave
2.4.1.1 生成rdb文件时如何处理请求
在redis生成rdb文件是异步的(使用bgsave)使用子线程执行rdb的生成过程,主线程继续处理客户端请求(如果此时主线程需要修改数据,则通过写时复制,让主线程对复制的副本进行修改)
2.4.2 AOP
- AOP(append only file) 日志(更可靠,每次写操作命令执行执行完毕后都会落盘存储,但恢复起来更耗时)(AOP机制生生成的AOP文件比RDB文件更大): aop通过每个写操作追加到日志文件中实现持久化,支持将所有写操作记录下来以便恢复,数据恢复更为精确,但文件体积较大,重写时可能会消耗更多的资源 redis4.0新增了rdb和aop的混合持久机制
2.4.2.1 写回策略
- always:每次写操作后立刻调用fsync,将数据同步到磁盘
- everysec:每秒调用一次fsync,将数据同步到磁盘
- no:有操作系统决定何时将数据写入磁盘,通常,磁盘会在一定时间后或缓冲区满时同步数据到磁盘
- 即使是always也可能会导致数据丢失,因为redis是先执行命令,再写入aof
2.4.2.2 重写机制
- aof文件随着写操作的增加会不断变大,过大的aof文件会导致恢复速度变慢,并消耗大量磁盘空间,所以,redis提供了aof重写机制,挤兑aof文件进行压缩,通过最少的命令来重新生成一个等效的aof文件
- aof重写可以通过手动触发或自动触发
- 手动使用BGREWRITEAOF来触发
- 自动触发:通过配置文件中的参数控制自动触发条件 auto-aof-rewrite-min-size auto-aof-rewrite-percentage
2.4.2.3 AOF文件恢复
如果aof文件因系统崩溃等原因损坏,可以使用redis-check-aof工具修复,该工具会阶段文件中的不完整命令,使其恢复到一致状态
2.4.3 混合机制
- rdb记录当前时间的数据快照,aof记录增量数据操作,恢复时先加载rdb快照,在加载aop来执行指令来恢复
2.5 事务
redis支持事务,但它的事务与MySQL的事务有所不同,MyAQL中的事务主要支持ACID的特性,而redis中的事务主要保证 的是多个命令执行的原子性,及所有的命令在一个原子操作中执行,不会被打断
- MySQL中的事务是支持回滚的,而redis中的事务不支持回滚的
- 命令
- MULTI:开始事务,命令开始排队
- 添加命令
- EXEC:执行队列中的所有命令,确保原子性
- DISCARD:放弃事务,清空命令队列
- WATCH(实现乐观锁):使用watch命令可以监视一个或多个键,如果在事务执行前这些键被修改,则exex将不会执行,确保数据一致性;
2.5.1 redis事务与关系型数据库事务的主要区别
- 原子性:redis提供部分原子性,因为如果一个命令执行失败,其他命令仍继续执行,事务不会自动回滚
- 一致性:无法回滚,所以无法保证一致性
- 隔离性:redis采用的单线程模型,在执行事务的过程中其他命令不会插入到事务执行的过程中,但无法设置不同隔离级别
- 持久性:redis事务的持久性依赖于配置(如rdb和aop)但理论上依然会丢失数据
2.6 集群
2.6.1 实现原理
- redis集群通过多个redis实例组哼,每个实例存储部分的数据(每个实例之间的数据是不重复的)
- 具体是采用哈希槽(通常是一个简单的数组,主要用于映射,其中每个索引对应一个槽,而哈希桶通常是链表红黑树和其他动态数据结构组成)(hashslot)机制来分配数据,将整个空间划分为16384个槽,每个实例负责一定范围的哈希槽,数据的key经过哈希函数计算后对16384取余即可定位到响应节点 即使用hashslot对数据进行分片(每个片可以包含一个主节点和多个从节点)
- 客户端发送请求时,会通过任意节点进行连接,存储则返回,反之则根据哈希槽机制确定节点后,路由到响应节点
- 每个节点都会保存集群的完整拓扑信息,包括每个节点的IP,ID,端口,负责的哈希槽范围
- 使用gossip协议:
特点:
- 分布式信息传播:每个节点定期向其他节点发送其状态信息(通过发送心跳数据包实现)
- 低延迟和高效率:设计为轻量级的通信方式,能够快速传播信息,减少单点故障带来的风险
- 去中心化:没有中心节点,所有节点平等的参与信息传播
2.6.1.1 为什么哈希槽节点数为16384
- 二的幂次:16384是2的14次方,这使得在计算哈希槽时(如取模运算)非常高效,因为可以使用位运算来加速计算。
- 消息大小:心跳数据包中有一条
发送节点负责的槽信息
,myslots[sluster_slots/6]
,这个是最占空间的,如果奥=槽位是16384,这块的大小是2kb,再大就会占用更多空间, ping心跳包是消头就太大了,浪费带宽, - 集群规模,集群不太可能会扩展超过1000个节点,16384够用且能使每个分片下的槽又不会太少
2.6.2 主从复制
redis的主从复制是指一个redis实例(主节点)可以将数据复制到一个或多个从节点,从节点从主节点获取数据并保持同步 复制流程:
- 连接:从节点向主节点发送psync命令建立连接
- 全量复制:如果第一次连接或者之前的连接失效,从节点会请求全量复制,主节点将当前数据快照(rdb文件)发送给从文件(runid没值会触发,因为从节点第一次发送psync ? -1,?证明从节点不知道主节点的runid,-1为offset,表示复制进度)(主节点rdb文件生成过程中收到的写入命令会存储到replication buffer中,从节点先清空数据,在加载rdb,加载完毕后主节点才会把replication buffer发给从节点)
- 增量复制:全量复制完毕后,主从之间会保持一个长连接,主节点会通过这个连接将后续的写操作传递到从节点执行,来保证数据的一致性
replication buffer和repl_backlog_buffer
- 大小和数量:因为不同从节点同步速度不一样,主节点会为每个从节点都创建一个replication buffer,它用于实时传输写命令,大小是动态的,没有大小限制,可以通过client-output-buffer-limit简介控制缓冲区大小(当缓冲区大小超出限制,就会断开与客户端的连接) repl_backlog_buffer在主节点只有一个,是一个环形缓冲区,大小只有1m,超过时则会被覆盖,可以使用从节点的offset来判断当前命令是否在repl_backlog_buffer,从而执行增量查询,否则不行
- 用处: Replication Buffer:用于实时接收并缓存来自主节点的命令。 Repl Backlog Buffer:用于存储已经发送但尚未确认的命令,以便在从节点断开后重新连接时进行增量复制。
2.6.2.1 主从复制常见拓扑结构
- 一主多从:最基本的拓扑结构,包括一个主节点和多个从节点,所有写操作在主节点上执行,而读操作可以在从节点上进行,以提高读取速度和负载均衡
- 树状主从结构(级联):从节点可以作为其他从节点的主节点,这样就形成了一个层次结构,主节点负责写操作,而从节点负责读操作,并将数据再次复制到更下一级的从节点,
- 因为主从复制对主节点有压力,所以这样的结构可以减轻主节点的压力
- 主主结构(双主或多主):有两个或多个主节点,它们之间互相复制数据,这种结构提高了系统的写能力和容错性,但需要处理多节点之间的数据同步和冲突解决,管理复杂度高,redis默认不支持主主复制
2.6.2.2 redis复制延迟的常见原因
redis的复制延迟是指从节点同步主节点数据时可能出现时间延迟,在读写分离场景下,这个延迟会导致明明写入了数据,但是去从节点查的时候没查到
- 网络原因
- 网络延迟(Latency):
- 概念:数据从发送端到达接收端所需的时间,通常以毫秒(ms)为单位。
- 影响:延迟越高,主节点与从节点之间的同步速度越慢,可能导致从节点数据滞后。
- 带宽不足(Bandwidth Insufficiency):
- 概念:单位时间内可以传输的最大数据量,带宽不足时传输速率变慢。
- 影响:如果带宽不足,大量数据传输需要更多时间,从节点无法及时接收到主节点的数据,导致同步延迟。
- 丢包(Packet Loss):
- 概念:数据包在网络传输过程中丢失,通常需要重传。
- 影响:丢包增加传输时间,影响从节点数据同步的及时性,可能导致更大的延迟甚至数据丢失。
- 网络抖动(Jitter):
- 概念:数据包传输时间的波动,即数据包到达时间不一致。
- 影响:抖动会导致数据传输不稳定,需要额外的重传或重排序,从而影响从节点同步数据的稳定性,增加延迟。
- 主节点负载过高
- 复制缓存区溢出
- 主节点持久化,无法及时响应复制请求
- 从节点配置太差
2.6.2.3 哨兵机制
redis的哨兵机制是一种高可用性解决方案,用于监控redis主从集群,自动完成主从切换,以实现故障自动恢复和通知。 主要功能:
- 监控:哨兵不断监控redis主节点和从节点的运行状态,定期发送ping请求检查节点是否正常
- 自动故障转移:当主节点发生故障时,哨兵会选举一个从节点提升为新的主节点,并通知客户端更新主节点的地址,从而实现高可用
- 通知:哨兵可以向系统管理员或其他服务发送通知,以便快速处理redis实例的状态变化
哨兵机制数据结构
- 哈希表(Hash Table)
- 功能:存储主节点、从节点和哨兵节点的状态信息,包括节点地址、端口、故障检测状态等。
- 作用:哨兵使用哈希表快速查找和更新节点状态,便于监控节点的健康状况。
- 发布/订阅(Pub/Sub)机制
- 功能:实现哨兵节点之间的通信,发送心跳包、通知主节点故障和选举结果。
- 作用:确保哨兵节点可以互相同步状态信息,及时响应主节点的故障,并选举新主节点。
- 列表(List)
- 功能:存储选举过程中产生的投票信息。
- 作用:在主从切换时,记录哨兵节点之间的投票顺序和结果,确保选举过程的有序性。
- 集合(Set)
- 功能:管理参与监控的哨兵节点、主节点、从节点的列表。
- 作用:确保哨兵节点能跟踪所有被监控的节点信息,并避免重复监控。
- 跳表(Skip List)
- 功能:管理时间敏感的任务,如定期的健康检查。
- 作用:跳表结构支持高效的排序和查找,便于管理周期性事件,例如定期对主从节点的健康检查。
- 队列(Queue)
- 功能:管理异步任务和事件。
- 作用:用于管理待处理的任务,比如检测到故障后,处理主从切换的各个步骤。
2.6.2.4 订阅发布功能(publish/subscibe)
订阅发布功能是一种消息通信机制,用于在不同客户端之间实现消息的实时传递和广播,使用pub/sub模型,客户端可以订阅一个或多个频道,当有其他客户端向这些频道发步消息时,所有订阅该频道的客户端都会立即受到消息
- 发布
- 订阅 ![[Pasted image 20241020110343.png]]订阅发布机制不会存储消息(rdb和aof都不会存储数据),实际上是维护了一个映射关系,当生产者往队列里发送一条消息,redis不做任何存储动作,立即查找映射关系,立马转发给具有映射关系的消费者
- 所以分布订阅模型的缺点:会丢数据
2.6.3 脑裂问题
集群存在脑裂问题的风险,特别是在网络分区的情况下,可能会导致同一集群内出现多个主节点节点,导致数据不一致
- 可以通过设置两个参数来减少脑裂的发生
- min-slaves-to-write
- min-slaves-max-lag
2.7 批处理
2.7.1 MSET/MGET(原生批处理命令)
- MSET/MGET是redis提供的原生批处理命令,用于批量设置和获取多个键值
- 它们是单个命令,可以一次操作多个键值对,因此只需要一次网络往返
MSET key1 value1 key2 value2 key3 value3
MGET key1 key2 key3
- 无法处理其他类型的redis操作
2.7.2 pipeline
pipeline是redis的一种机制,允许客户端一次发送多个命令,redis会批量处理这些命令,然后将结果依次返回,可以大幅度减少网络延迟
- 无法保证原子性
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
public class RedisPipelineExample {
public static void main(String[] args) {
// 创建 Redis 连接
Jedis jedis = new Jedis("localhost", 6379);
// 开始 Pipeline
Pipeline pipeline = jedis.pipelined();
// 批量设置键值对
for (int i = 0; i < 1000; i++) {
pipeline.set("key" + i, "value" + i);
}
// 执行所有命令
pipeline.sync();
// 关闭连接
jedis.close();
}
}
2.7.3 Lua脚本
- Lua是一种轻量级的嵌入式脚本语言,通常用于嵌入到其他应用中。它设计得非常简洁,执行效率高。
- Lua 脚本是在 Redis 服务器内部执行的,这意味着所有操作都在服务器上处理,减少了网络延迟。 redis的Lua脚本功能允许用户在redis在redis服务器执行自定义的Lua脚本,以实现原子操作和复杂逻辑: 其核心点包括
- 原子性:本身不具备原子性,但redis的命令是单线程执行的
- 减少网络往返次数:通过在服务器执行脚本,减少了客户端和服务器之间的网络往返次数,提高了性能
- 复杂操作:可以在Lua脚本中执行复杂的逻辑,比如批量更新、条件更新等,超过了单个redis命令的能力 基本结构:
- 调用redis命令:使用redis.call调用redis原生命令,使用redis.pcall进行安全调用,如果脚本中的某些命令失败,可以捕获错误,而不是直接中断执行,这样剋在脚本内处理错误
- 参数传递: keys:表示传入的键名数组 argv:表示传入的参数数组
EVAL
"local value = redis.call('GET', KEYS[1])
if not value then redis.call('SET', KEYS[1], ARGV[1])
end
return value" 1 mykey "default_value"
2.8 分布式锁
redisson是基于redis实现的分布式锁,实际上是使用redis的原子操作来确保多线程、多进程或多节点系统中,只有一个线程能获得锁,避免并发操作导致的数据不一致问题
- 锁的获取:redisson使用Lua脚本,利用exists+hexists(Hash Exists)+hincrby(Hash Increment By)命令来保证只有一个线程能成功设置键(表示获得锁),pexpire设置锁过期时间
- 锁的续期:为了防止锁持有过程中过期导致其他线程抢占锁,redisson实现了锁自动续期,即更新锁的过期时间,确保任务没有完成时锁不会失效
- 锁的释放:锁释放时,redisson也是通过Lua脚本保证释放操作的原子性,利用del确保只有持有锁的线程才能释放锁,防止五释放锁的情况;Lua同时利用publish名令,广播唤醒其他等待的线程。
- 可重入锁:redisson支持可重如锁,持有锁的线程可以多次获取同一把锁而不被阻塞,具体是利用redis中的哈希结构,哈希中的key为线程ID,如果重入则value+1,如果释放则value-1,减到0则说明锁被释放,则del锁
<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
return commandExecutor.syncedEval(getRawName(), LongCodec.INSTANCE, command,
"if ((redis.call('exists', KEYS[1]) == 0) " +
"or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.singletonList(getRawName()), unit.toMillis(leaseTime), getLockName(threadId));
}
2.8.1 redis如何实现分布式锁
在redis中实现分布式锁的常见方法是通过set ex(expire)(过期) nx(Not exists)命令+lua脚本组合使用,确保多个客户端不会获得同一个资源锁的同时,也保证了安全解锁和意外情况下锁的自动释放 一般业务使用主从+哨兵来实现分布式锁
2.8.2 redlock
redlock是redis官方推荐的一种实现分布式锁的算法,适用于集群环境下 基本思想:
- 部署多个redis实例(通常为5个)
- 客户端在大多数实例(至少3个)上请求锁,并在一定时间内获得成功,表示加锁成功
- 适用redlock可以提供更高的容错性,即使部分redis实例故障,仍然可以获得锁 缺点:需要多个redis实例,时间同步依赖,不适合高并发,锁的续期问题
2.9 问题
bigkey 热点key