导图社区 Redis三高及新版本特性
"Redis三高架构与新版本黑科技,解锁大厂实战秘籍! 内容亮点: 1. 深度解析Redis高可用(哨兵/Cluster)、高扩展及性能调优核心策略 2 揭秘微博亿级流量下的缓存实践与监控体系化方案 3. 新版本特性全览:多线程IO、Stream类型、ACL安全防护等 4 避坑指南:缓存击穿/雪崩、bigkey、内存碎片等高频问题解决方案 5. 从Redis4到6的演进路径与未来模块化生态展望。
编辑于2025-06-11 16:40:16正则表达式:文本处理的万能钥匙!一、基础概念:用模式描述字符串规则,掌握元字符、量词、分组即可入门二、核心语法:从简单匹配到复杂逻辑,精准控制文本三、高级特性:零宽断言等技巧解决棘手问题,注意不同语言引擎差异四、应用场景:格式验证、日志分析、批量替换,覆盖编程语言(Python/Java)、编辑器(VS Code)、数据库(MySQL)等附赠工具:regex101在线调试,regexr可视化学习,助你快速上手!
G1垃圾回收器:高效分代式内存管理的革新者! G1(GarbageFirst)是面向多核大内存的垃圾回收器,通过分区模型(Region)和分代设计实现低延迟。其核心包括内存模型(分区、分代、收集集合CSet)和活动周期:RSet维护、并发标记(初始标记→根扫描→并发标记→重新标记→清除)、混合收集(转移失败触发Full GC)以及年轻代收集(动态调整GC线程)。G1以可预测停顿为目标,平衡吞吐量与响应速度,适合现代Java应用。
"Redis三高架构与新版本黑科技,解锁大厂实战秘籍! 内容亮点: 1. 深度解析Redis高可用(哨兵/Cluster)、高扩展及性能调优核心策略 2 揭秘微博亿级流量下的缓存实践与监控体系化方案 3. 新版本特性全览:多线程IO、Stream类型、ACL安全防护等 4 避坑指南:缓存击穿/雪崩、bigkey、内存碎片等高频问题解决方案 5. 从Redis4到6的演进路径与未来模块化生态展望。
社区模板帮助中心,点此进入>>
正则表达式:文本处理的万能钥匙!一、基础概念:用模式描述字符串规则,掌握元字符、量词、分组即可入门二、核心语法:从简单匹配到复杂逻辑,精准控制文本三、高级特性:零宽断言等技巧解决棘手问题,注意不同语言引擎差异四、应用场景:格式验证、日志分析、批量替换,覆盖编程语言(Python/Java)、编辑器(VS Code)、数据库(MySQL)等附赠工具:regex101在线调试,regexr可视化学习,助你快速上手!
G1垃圾回收器:高效分代式内存管理的革新者! G1(GarbageFirst)是面向多核大内存的垃圾回收器,通过分区模型(Region)和分代设计实现低延迟。其核心包括内存模型(分区、分代、收集集合CSet)和活动周期:RSet维护、并发标记(初始标记→根扫描→并发标记→重新标记→清除)、混合收集(转移失败触发Full GC)以及年轻代收集(动态调整GC线程)。G1以可预测停顿为目标,平衡吞吐量与响应速度,适合现代Java应用。
"Redis三高架构与新版本黑科技,解锁大厂实战秘籍! 内容亮点: 1. 深度解析Redis高可用(哨兵/Cluster)、高扩展及性能调优核心策略 2 揭秘微博亿级流量下的缓存实践与监控体系化方案 3. 新版本特性全览:多线程IO、Stream类型、ACL安全防护等 4 避坑指南:缓存击穿/雪崩、bigkey、内存碎片等高频问题解决方案 5. 从Redis4到6的演进路径与未来模块化生态展望。
Redis三高及新版本特性
高可用
主从复制概述
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。 主要作用是: 
数据冗余
主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
故障恢复
当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
负载均衡
在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
高可用基石
除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。 主从库之间采用的是读写分离的方式。
主从复制原理
注意:在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制: 全量(同步)复制:比如第一次同步时 增量(同步)复制:只会把主从库网络断连期间主库收到的命令,同步给从库
全量复制
确立主从关系
例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据: replicaof 172.16.19.3 6379
全量复制的三个阶段

第一阶段
主从库间建立连接、协商同步的过程,主要是为全量复制做准备。在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。 具体来说,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset,此时设为 -1,表示第一次复制。主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。这里有个地方需要注意,FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。
第二阶段
主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。这个过程依赖于内存快照生成的 RDB 文件。 具体来说,主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。
第三阶段
主库会把第二阶段执行过程中新收到的写命令,再发送给从库。 具体的操作是,当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。
增量复制
为什么设计增量复制
如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步
增量复制流程
 repl_backlog_buffer:它是为了从库断开之后,如何找到主从差异数据而设计的环形缓冲区,从而避免全量复制带来的性能开销。 如果从库断开时间太久,repl_backlog_buffer环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能乖乖地进行一次全量复制,所以repl_backlog_buffer配置尽量大一些,可以降低主从断开后全量复制的概率。 而在repl_backlog_buffer中找主从差异的数据后,如何发给从库呢?这就用到了replication buffer。 replication buffer:Redis和客户端通信也好,和从库通信也好,Redis都需要给分配一个 内存buffer进行数据交互,客户端是一个client,从库也是一个client,我们每个client连上Redis后,Redis都会分配一个client buffer,所有数据交互都是通过这个buffer进行的:Redis先把数据写到这个buffer中,然后再把buffer中的数据发到client socket中再通过网络发送出去,这样就完成了数据交互。所以主从在增量同步时,从库作为一个client,也会分配一个buffer,只不过这个buffer专门用来传播用户的写命令到从库,保证主从数据一致,我们通常把它叫做replication buffer。
更深入理解
当主服务器不进行持久化时复制的安全性
在进行主从复制设置时,强烈建议在主服务器上开启持久化,当不能这么做时,比如考虑到延迟的问题,应该将实例配置为避免自动重启。 为什么不持久化的主服务器自动重启非常危险呢? 我们设置节点A为主服务器,关闭持久化,节点B和C从节点A复制数据。 这时出现了一个崩溃,但Redis具有自动重启系统,重启了进程,因为关闭了持久化,节点重启后只有一个空的数据集。 节点B和C从节点A进行复制,现在节点A是空的,所以节点B和C上的复制数据也会被删除。 当在高可用系统中使用Redis Sentinel,关闭了主服务器的持久化,并且允许自动重启,这种情况是很危险的。比如主服务器可能在很短的时间就完成了重启,以至于Sentinel都无法检测到这次失败,那么上面说的这种失败的情况就发生了。
为什么主从全量复制使用RDB而不使用AOF?
1、RDB文件内容是经过压缩的二进制数据(不同数据类型数据做了针对性优化),文件很小。 而AOF文件记录的是每一次写操作的命令,写操作越多文件会变得很大,其中还包括很多对同一个key的多次冗余操作。 在主从全量数据同步时,传输RDB文件可以尽量降低对主库机器网络带宽的消耗,从库在加载RDB文件时,一是文件小,读取整个文件的速度会很快,二是因为RDB文件存储的都是二进制数据,从库直接按照RDB协议解析还原数据即可,速度会非常快, 而AOF需要依次重放每个写命令,这个过程会经历冗长的处理逻辑,恢复速度相比RDB会慢得多,所以使用RDB进行主从全量复制的成本最低。 2、假设要使用AOF做全量复制,意味着必须打开AOF功能,打开AOF就要选择文件刷盘的策略,选择不当会严重影响Redis性能。而RDB只有在需要定时备份和主从全量复制数据时才会触发生成一次快照。而在很多丢失数据不敏感的业务场景,其实是不需要开启AOF的。
为什么还有无磁盘复制模式?
Redis 默认是磁盘复制,但是如果使用比较低速的磁盘,这种操作会给主服务器带来较大的压力。Redis从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储。 无磁盘复制模式:master创建一个新进程直接dump RDB到slave的socket,不经过主进程,不经过硬盘。适用于disk较慢,并且网络较快的时候。 使用repl-diskless-sync配置参数来启动无磁盘复制。 使用repl-diskless-sync-delay 参数来配置传输开始的延迟时间;master等待一个repl-diskless-sync-delay的秒数,如果没slave来的话,就直接传,后来的得排队等了; 否则就可以一起传。
为什么还会有从库的从库的设计?
通过分析主从库间第一次数据同步的过程,你可以看到,一次全量复制中,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件。 如果从库数量很多,而且都要和主库进行全量复制的话,就会导致主库忙于 fork 子进程生成 RDB 文件,进行数据全量复制。fork 这个操作会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢。此外,传输 RDB 文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力。那么,有没有好的解决方法可以分担主库压力呢? 其实是有的,这就是“主 - 从 - 从”模式。 在刚才介绍的主从库模式中,所有的从库都是和主库连接,所有的全量复制也都是和主库进行的。现在,我们可以通过“主 - 从 - 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。 简单来说,我们在部署主从集群的时候,可以手动选择一个从库(比如选择内存资源配置较高的从库),用于级联其他的从库。然后,我们可以再选择一些从库(例如三分之一的从库),在这些从库上执行如下命令,让它们和刚才所选的从库,建立起主从关系。  级联的“主-从-从”模式好了,到这里,我们了解了主从库间通过全量复制实现数据同步的过程,以及通过“主 - 从 - 从”模式分担主库压力的方式。那么,一旦主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,可以避免频繁建立连接的开销。
读写分离及其中的问题
在主从复制基础上实现的读写分离,可以实现Redis的读负载均衡:由主节点提供写服务,由一个或多个从节点提供读服务(多个从节点既可以提高数据冗余程度,也可以最大化读负载能力);在读负载较大的应用场景下,可以大大提高Redis服务器的并发量。下面介绍在使用Redis读写分离时,需要注意的问题。 延迟与不一致问题 前面已经讲到,由于主从复制的命令传播是异步的,延迟与数据的不一致不可避免。如果应用对数据不一致的接受程度程度较低,可能的优化措施包括:优化主从节点之间的网络环境(如在同机房部署);监控主从节点延迟(通过offset)判断,如果从节点延迟过大,通知应用不再通过该从节点读取数据;使用集群同时扩展写负载和读负载等。 在命令传播阶段以外的其他情况下,从节点的数据不一致可能更加严重,例如连接在数据同步阶段,或从节点失去与主节点的连接时等。从节点的slave-serve-stale-data参数便与此有关:它控制这种情况下从节点的表现;如果为yes(默认值),则从节点仍能够响应客户端的命令,如果为no,则从节点只能响应info、slaveof等少数命令。该参数的设置与应用对数据一致性的要求有关;如果对数据一致性要求很高,则应设置为no。 数据过期问题 在单机版Redis中,存在两种删除策略: 惰性删除:服务器不会主动删除数据,只有当客户端查询某个数据时,服务器判断该数据是否过期,如果过期则删除。 定期删除:服务器执行定时任务删除过期数据,但是考虑到内存和CPU的折中(删除会释放内存,但是频繁的删除操作对CPU不友好),该删除的频率和执行时间都受到了限制。 在主从复制场景下,为了主从节点的数据一致性,从节点不会主动删除数据,而是由主节点控制从节点中过期数据的删除。由于主节点的惰性删除和定期删除策略,都不能保证主节点及时对过期数据执行删除操作,因此,当客户端通过Redis从节点读取数据时,很容易读取到已经过期的数据。 Redis 3.2中,从节点在读取数据时,增加了对数据是否过期的判断:如果该数据已过期,则不返回给客户端;将Redis升级到3.2可以解决数据过期问题。 故障切换问题 在没有使用哨兵的读写分离场景下,应用针对读和写分别连接不同的Redis节点;当主节点或从节点出现问题而发生更改时,需要及时修改应用程序读写Redis数据的连接;连接的切换可以手动进行,或者自己写监控程序进行切换,但前者响应慢、容易出错,后者实现复杂,成本都不算低。 总结 在使用读写分离之前,可以考虑其他方法增加Redis的读负载能力:如尽量优化主节点(减少慢查询、减少持久化等其他情况带来的阻塞等)提高负载能力;使用Redis集群同时提高读负载能力和写负载能力等。如果使用读写分离,可以使用哨兵,使主从节点的故障切换尽可能自动化,并减少对应用程序的侵入。
哨兵机制
Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移  哨兵实现了什么功能呢? 监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。 自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。 通知(Notification):哨兵可以将故障转移的结果发送给客户端。
哨兵集群的组建
哨兵监控Redis库
主库下线的判定
哨兵集群的选举
新主库的选出
故障的转移
高可扩展
分片技术(Redis Cluster)
Redis Cluster 是 Redis 的一种分布式部署方式,它的目的是提高 Redis 的可用性和水平扩展能力。Redis Cluster 通过对数据进行分片,将数据存储在多个 Redis 节点上,并提供跨节点的数据复制功能来保证数据的高可用性
Redis集群的设计目标
redis分配目标
高性能可线性扩展至最多1000节点。集群中没有代理,(集群节点间)使用异步复制,没有归并操作(merge operations on values) 可接受的写入安全:系统尝试(采用best-effort方式)保留所有连接到master节点的client发起的写操作。通常会有一个小的时间窗,时间窗内的已确认写操作可能丢失(即,在发生failover之前的小段时间窗内的写操作可能在failover中丢失)。而在(网络)分区故障下,对少数派master的写入,发生写丢失的时间窗会很大。 可用性:Redis Cluster在以下场景下集群总是可用:大部分master节点可用,并且对少部分不可用的master,每一个master至少有一个当前可用的slave。更进一步,通过使用 replicas migration 技术,当前没有slave的master会从当前拥有多个slave的master接受到一个新slave来确保可用性
Redis集群协议中的master和slave角色
Redis Cluster的节点负责维护数据,和获取集群状态,这包括将keys映射到正确的节点。集群节点同样可以自动发现其他节点、检测不工作节点、以及在发现故障发生时晋升slave节点到master 所有集群节点通过由TCP和二进制协议组成的称为 Redis Cluster Bus 的方式来实现集群的节点自动发现、故障节点探测、slave升级为master等任务。每个节点通过cluster bus连接所有其他节点。节点间使用gossip协议进行集群信息传播,以此来实现新节点发现,发送ping包以确认对端工作正常,以及发送cluster消息用来标记特定状态。cluster bus还被用来在集群中创博Pub/Sub消息,以及在接收到用户请求后编排手动failover。
安全写入
可用性(Availability)
性能(Performance)
避免合并(merge)操作
Redis Cluster设计上避免了在多个拥有相同key-value对的节点上的版本冲突(及合并/merge),因为在redis数据模型下这是不需要的。 Redis的值同时都非常大;一个拥有数百万元素的list或sorted set是很常见的。同样,数据类型的语义也很复杂。 传输和合并这类值将会产生明显的瓶颈,并可能需要对应用侧的逻辑做明显的修改,比如需要更多的内存来保存meta-data等。 这里(【译注】刻意避免了merge)并没有严格的技术限制。CRDTs或同步复制状态机可以塑造与redis类似的复杂的数据类型。然而,这类系统运行时的行为与Redis Cluster其实是不一样的。Redis Cluster被设计用来支持非集群redis版本无法支持的一些额外的场景
主要模块介绍
哈希槽(Hash Slot)
Redis-cluster没有使用一致性hash,而是引入了哈希槽的概念。 Redis-cluster中有16384(即2的14次方)个哈希槽,每个key通过CRC16校验后对16383取模来决定放置哪个槽。Cluster中的每个节点负责一部分hash槽(hash slot)。 比如集群中存在三个节点,则可能存在的一种分配如下: 节点A包含0到5500号哈希槽; 节点B包含5501到11000号哈希槽; 节点C包含11001 到 16384号哈希槽。
Keys hash tags
Hash tags提供了一种途径,用来将多个(相关的)key分配到相同的hash slot中。这时Redis Cluster中实现multi-key操作的基础。 hash tag规则如下,如果满足如下规则,{和}之间的字符将用来计算HASH_SLOT,以保证这样的key保存在同一个slot中。 key包含一个{字符 并且 如果在这个{的右面有一个}字符 并且 如果在{和}之间存在至少一个字符 例如: {user1000}.following和{user1000}.followers这两个key会被hash到相同的hash slot中,因为只有user1000会被用来计算hash slot值。 foo{}{bar}这个key不会启用hash tag因为第一个{和}之间没有字符。 foozap这个key中的{bar部分会被用来计算hash slot foo{bar}{zap}这个key中的bar会被用来计算计算hash slot,而zap不会
Cluster nodes属性
每个节点在cluster中有一个唯一的名字。这个名字由160bit随机十六进制数字表示,并在节点启动时第一次获得(通常通过/dev/urandom)。节点在配置文件中保留它的ID,并永远地使用这个ID,直到被管理员使用CLUSTER RESET HARD命令hard reset这个节点。 节点ID被用来在整个cluster中标识每个节点。一个节点可以修改自己的IP地址而不需要修改自己的ID。Cluster可以检测到IP /port的改动并通过运行在cluster bus上的gossip协议重新配置该节点。 节点ID不是唯一与节点绑定的信息,但是他是唯一的一个总是保持全局一致的字段。每个节点都拥有一系列相关的信息。一些信息时关于本节点在集群中配置细节,并最终在cluster内部保持一致的。而其他信息,比如节点最后被ping的时间,是节点的本地信息。 每个节点维护着集群内其他节点的以下信息:node id, 节点的IP和port,节点标签,master node id(如果这是一个slave节点),最后被挂起的ping的发送时间(如果没有挂起的ping则为0),最后一次收到pong的时间,当前的节点configuration epoch ,链接状态,以及最后是该节点服务的hash slots。
Cluster总线
每个Redis Cluster节点有一个额外的TCP端口用来接受其他节点的连接。这个端口与用来接收client命令的普通TCP端口有一个固定的offset。该端口等于普通命令端口加上10000.例如,一个Redis街道口在端口6379坚挺客户端连接,那么它的集群总线端口16379也会被打开。 节点到节点的通讯只使用集群总线,同时使用集群总线协议:有不同的类型和大小的帧组成的二进制协议。集群总线的二进制协议没有被公开文档话,因为他不希望被外部软件设备用来预计群姐点进行对话。
集群拓扑
Redis Cluster是一张全网拓扑,节点与其他每个节点之间都保持着TCP连接。 在一个拥有N个节点的集群中,每个节点由N-1个TCP传出连接,和N-1个TCP传入连接。 这些TCP连接总是保持活性(be kept alive)。当一个节点在集群总线上发送了ping请求并期待对方回复pong,(如果没有得到回复)在等待足够成时间以便将对方标记为不可达之前,它将先尝试重新连接对方以刷新与对方的连接。 而在全网拓扑中的Redis Cluster节点,节点使用gossip协议和配置更新机制来避免在正常情况下节点之间交换过多的消息,因此集群内交换的消息数目(相对节点数目)不是指数级的
节点握手
请求重定向
Moved 重定向
ASK 重定向
smart客户端
状态检测及维护
Gossip协议
通讯状态和维护
故障恢复(Failover)
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave。Failover的过程需要经过类Raft协议的过程在整个集群内达到一致, 其过程如下: 1.slave发现自己的master变为FAIL 2.将自己记录的集群currentEpoch加1,并广播Failover Request信息 3.其他节点收到该信息,只有master响应,判断请求者的合法性,并发送 FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack 4.尝试failover的slave收集FAILOVER_AUTH_ACK 5. 超过半数后变成新Master 6.广播Pong通知其他集群节点
扩容&缩容
扩容
当集群出现容量限制或者其他一些原因需要扩容时,redis cluster提供了比较优雅的集群扩容方案。 1.首先将新节点加入到集群中,可以通过在集群中任何一个客户端执行cluster meet 新节点ip:端口,或者通过redis-trib add node添加,新添加的节点默认在集群中都是主节点。 2.迁移数据的大致流程是,首先需要确定哪些槽需要被迁移到目标节点,然后获取槽中key,将槽中的key全部迁移到目标节点,然后向集群所有主节点广播槽(数据)全部迁移到了目标节点。直接通过redis-trib工具做数据迁移很方便。 现在假设将节点A的槽10迁移到B节点,过程如下:
缩容
缩容的大致过程与扩容一致,需要判断下线的节点是否是主节点,以及主节点上是否有槽,若主节点上有槽,需要将槽迁移到集群中其他主节点,槽迁移完成之后,需要向其他节点广播该节点准备下线(cluster forget nodeId)。最后需要将该下线主节点的从节点指向其他主节点,当然最好是先将从节点下线
更深入理解
我们知道一致性hash算法是2的16次方,为什么hash slot是2的14次方呢? 在redis节点发送心跳包时需要把所有的槽放到这个心跳包里,以便让节点知道当前集群信息,16384=16k,在发送心跳包时使用char进行bitmap压缩后是2k(2 * 8 (8 bit) * 1024(1k) = 16K),也就是说使用2k的空间创建了16k的槽数。 虽然使用CRC16算法最多可以分配65535(2^16-1)个槽位,65535=65k,压缩后就是8k(8 * 8 (8 bit) * 1024(1k) =65K),也就是说需要需要8k的心跳包,作者认为这样做不太值得;并且一般情况下一个redis集群不会有超过1000个master节点,所以16k的槽位是个比较合适的选择。 为什么Redis Cluster中不建议使用发布订阅呢? 在集群模式下,所有的publish命令都会向所有节点(包括从节点)进行广播,造成每条publish数据都会在集群内所有节点传播一次,加重了带宽负担,对于在有大量节点的集群中频繁使用pub,会严重消耗带宽,不建议使用。(虽然官网上讲有时候可以使用Bloom过滤器或其他算法进行优化的)
其它常见方案
新版本特性
Redis 4
模块系统
PSYNC 2.0
缓存驱逐策略优化
Lazy Free
在 Redis 4.0 之前, 用户在使用 DEL命令删除体积较大的键, 又或者在使用 FLUSHDB 和 FLUSHALL删除包含大量键的数据库时, 都可能会造成服务器阻塞。 为了解决以上问题, Redis 4.0 新添加了UNLINK命令, 这个命令是DEL命令的异步版本, 它可以将删除指定键的操作放在后台线程里面执行, 从而尽可能地避免服务器阻塞: redis> UNLINK fruits (integer) 1 因为一些历史原因, 执行同步删除操作的DEL命令将会继续保留。此外, Redis 4.0 中的FLUSHDB和FLUSHALL这两个命令都新添加了ASYNC选项, 带有这个选项的数据库删除操作将在后台线程进行: redis> FLUSHDB ASYNC OK redis> FLUSHALL ASYNC OK 还有,执行rename oldkey newkey时,如果newkey已经存在,Redis会先删除已经存在的newkey,这也会引发上面提到的删除大key问题。如果想让Redis在这种场景下也使用lazyfree的方式来删除,可以按如下配置: lazyfree-lazy-server-del yes
交换数据库
混合持久化
内存命令
兼容NAT和Docker
其他
Redis 5
Stream类型
新的Redis模块API
集群管理器更改
Lua改进
RDB格式变化
动态HZ
ZPOPMIN&ZPOPMAX命令
CLIENT新增命令
Redis 6
多线程IO
Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。 所以我们不需要去考虑控制 key、lua、事务,LPUSH/LPOP 等等的并发及线程安全问题。 Redis6.0的多线程默认是禁用的,只使用主线程。如需开启需要修改redis.conf配置文件:io-threads-do-reads yes。开启多线程后,还需要设置线程数,否则是不生效的。修改redis.conf配置文件:io-threads ,关于线程数的设置,官方有一个建议:4核的机器建议设置为2或3个线程,8核的建议设置为6个线程,线程数一定要小于机器核数。还需要注意的是,线程数并不是越大越好,官方认为超过了8个基本就没什么意义了。
SSL支持
连接支持SSL协议,更加安全。 SSL(Secure Sockets Layer 安全套接层协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。
ACL支持
在之前的版本中,Redis都会有这样的问题:用户执行FLUSHAL,现在整个数据库就空了在以前解决这个问题的办法可能是在Redis配置中将危险命令进行rename,这样将命令更名为随机字符串或者直接屏蔽掉,以满足需要。当有了ACL之后,你就可以控制比如:这个连接只允许使用RPOP,LPUSH这些命令,其他命令都无法调用。 Redis ACL是Access Control List(访问控制列表)的缩写,该功能允许根据可以执行的命令和可以访问的键来限制某些连接。它的工作方式是:在客户端连接之后,需要客户端进行身份验证,以提供用户名和有效密码:如果身份验证阶段成功,则将连接与指定用户关联,并且该用户具有指定的限制。可以对Redis进行配置,使新连接通过“默认”用户进行身份验证(这是默认配置),但是只能提供特定的功能子集 在默认配置中,Redis 6(第一个具有ACL的版本)的工作方式与Redis的旧版本完全相同,也就是说,每个新连接都能够调用每个可能的命令并访问每个键,因此ACL功能对于客户端和应用程序与旧版本向后兼容。同样,使用requirepass配置指令配置密码的旧方法仍然可以按预期工作,但是现在它的作用只是为默认用户设置密码。
RESP3
RESP(Redis Serialization Protocol)是 Redis 服务端与客户端之间通信的协议。Redis 6之前使用的是 RESP2,而Redis 6开始在兼容RESP2的基础上,开始支持RESP3。在Redis 6中我们可以使用HELLO命令在RESP2和RESP3协议之间进行切换 推出RESP3的目的:一是因为希望能为客户端提供更多的语义化响应(semantical replies),降低客户端的复杂性,以开发使用旧协议难以实现的功能;另一个原因是为了实现 Client side caching(客户端缓存)功能。详细见:https://github.com/antirez/RESP3/blob/master/spec.md
客户端缓存
基于 RESP3 协议实现的客户端缓存功能。为了进一步提升缓存的性能,将客户端经常访问的数据cache到客户端。减少TCP网络交互。不过该特性目前合并到了unstable 分支,作者说等6.0 GA版本之前,还要修改很多。 客户端缓存的功能是该版本的全新特性,服务端能够支持让客户端缓存values,Redis作为一个本身作为一个缓存数据库,自身的性能是非常出色的,但是如果可以在Redis客户端再增加一层缓存结果,那么性能会更加的出色。Redis实现的是一个服务端协助的客户端缓存,叫做tracking。 当tracking开启时, Redis会"记住"每个客户端请求的key,当key的值发现变化时会发送失效信息给客户端。失效信息可以通过 RESP3 协议发送给请求的客户端,或者转发给一个不同的连接(支持RESP2+ Pub/Sub)。
集群代理
因为 Redis Cluster 内部使用的是P2P中的Gossip协议,每个节点既可以从其他节点得到服务,也可以向其他节点提供服务,没有中心的概念,通过一个节点可以获取到整个集群的所有信息。 所以如果应用连接Redis Cluster可以配置一个节点地址,也可以配置多个节点地址。但需要注意如果集群进行了上下节点的的操作,其应用也需要进行修改,这样会导致需要重启应用,非常的不友好。 从Redis 6.0开始支持了Prxoy,可以直接用Proxy来管理各个集群节点。 本文来介绍下如何使用官方自带的proxy:redis-cluster-proxy 通过使用 redis-cluster-proxy 可以与组成Redis集群的一组实例进行通讯,就像是单个实例一样。Redis群集代理是多线程的,使用多路复用通信模型,因此每个线程都有自己的与群集的连接,该连接由属于该线程本身的所有客户端共享。 在某些特殊情况下(例如MULTI事务或阻塞命令),多路复用将被禁用;并且客户端将拥有自己的集群连接。这样客户端仅发送诸如GET和SET之类的简单命令就不需要Redis集群的专有连接。 redis-cluster-proxy的主要功能特点: 路由:每个查询都会自动路由到集群的正确节点 多线程 支持多路复用和专用连接模型 在多路复用上下文中,可以确保查询执行和答复顺序 发生ASK | MOVED错误后自动更新集群的配置:当答复中发生此类错误时,代理通过获取集群的更新配置并重新映射所有插槽来自动更新集群。 更新完成后所有查询将重新执行,因此,从客户端的角度来看,一切正常进行(客户端将不会收到ASK | MOVED错误:他们将在收到请求后直接收到预期的回复) 群集配置已更新)。 跨槽/跨节点查询:支持许多命令,这些命令涉及属于不同插槽(甚至不同集群节点)的多个键。这些命令会将查询分为多个查询,这些查询将被路由到不同的插槽/节点。 这些命令的回复处理是特定于命令的。 某些命令(例如MGET)将合并所有答复,就好像它们是单个答复一样。 其他命令(例如MSET或DEL)将汇总所有答复的结果。 由于这些查询实际上破坏了命令的原子性,因此它们的用法是可选的(默认情况下禁用)。 一些没有特定节点/插槽的命令(例如DBSIZE)将传递到所有节点,并且将对映射的回复进行映射缩减,以便得出所有回复中包含的所有值的总和。 可用于执行某些特定于代理的操作的附加PROXY命令
Disque module
这个本来是作者几年前开发的一个基于 Redis 的消息队列工具,但多年来作者发现 Redis 在持续开发时,他也要持续把新的功能合并到这个Disque 项目里面,这里有大量无用的工作。因此这次他在 Redis 的基础上通过 Modules 功能实现 Disque。 如果业务并不需要保持严格消息的顺序,这个 Disque 能提供足够简单和快速的消息队列功能
其他
新的Expire算法:用于定期删除过期key的函数activeExpireCycle被重写,以便更快地收回已经过期的key; 提供了许多新的Module API; 从服务器也支持无盘复制:在用户可以配置的特定条件下,从服务器现在可以在第一次同步时直接从套接字加载RDB到内存; SRANDMEMBER命令和类似的命令优化,使其结果具有更好的分布; 重写了Systemd支持; 官方redis-benchmark工具支持cluster模式; 提升了RDB日志加载速度;
应用实践
缓存问题
缓存穿透
缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。  通过布隆器来解决
缓存击穿
缓存击穿,是指一个key非常热点,被经常访问,当时在一个节点突然失效了。 续的大并发就穿破缓存,直接请求数据库 1.设置缓存永不过期 2.加锁,放一个线程去重建缓存,其他的正常流程
缓存雪崩
缓存雪崩,是指在某一个时间段,缓存集中过期失效。 1.redis4.0以上的版本开启lazy-free机制 2.在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源。 
缓存污染(或满了)
数据库和缓存一致性
性能调优
Redis真的变慢了吗?
使用复杂度过高的命令
操作bigkey
集中过期
实例内存达到上限
fork耗时严重
开启内存大页
开启AOF
绑定CPU
使用Swap
碎片整理
网络带宽过载
其他原因
运维监控
如何理解Redis监控呢
如何理解Redis监控呢
Redis可视化监控工具
Redis监控体系
监控体系化包含哪些维度?
具体的监控指标有哪些呢?
Redis大厂经验
Redis在微博的应用场景
Redis在微博的优化
未来展望