银川市网站建设_网站建设公司_代码压缩_seo优化
2026/1/16 20:28:57 网站建设 项目流程

黑马点评

分布式缓存

Redis集群

image-20260116121018031

image-20260116121040838

image-20260116121056587

image-20260116121220557

image-20260116121406406

image-20260116121419319

Redis持久化(RDB和AOF)

image-20260116121820487

配置的redis文件位置

/usr/local/src/redis-6.2.6/redis.conf

image-20260116124050432

默认停机的时候执行一次rdb持久化方案

知识点(RDB、AOF、两者混合的工业应用)

  1. fork 主进程就是指:主进程(父进程)通过调用 fork() 系统调用,创建一个与其几乎完全一样的副本,即“子进程”。fork过程中主进程阻塞。

  2. 1. RDB (Redis Database)

    RDB 主要有两种触发方式,它们的同步/异步表现完全不同:

    • SAVE 命令:同步(阻塞)

      这是同步执行的。Redis 主进程会停止处理任何客户端命令,直到 RDB 文件生成完毕。这在生产环境中是非常危险的,因为它会导致服务瞬间“卡死”。

    • BGSAVE 命令:异步(非阻塞)

      这是 Redis 默认和常用的方式。

      • 原理:主进程会 fork() 出一个子进程。
      • 表现:由子进程负责将内存数据写入磁盘生成 RDB 文件,而主进程继续处理客户端的读写请求。
      • 注意:虽然写入磁盘是异步的,但 fork() 那个瞬间是同步的,如果内存特别大,可能会有毫秒级的卡顿。

    2. AOF (Append Only File)

    AOF 的“异步性”取决于 appendfsync 参数的设置,它决定了数据从 内存缓冲区 刷到 磁盘文件 的频率:

    配置项 是否异步 说明
    always 同步 每执行一个写命令就执行一次 fsync 刷盘。最安全但最慢,主线程会被阻塞直到磁盘写入完成。
    everysec 异步 (默认) 每秒执行一次刷盘。Redis 会创建一个 后台线程 专门负责 fsync,主线程只管写内存缓冲区,所以是异步的。
    no 由系统决定 Redis 只负责把数据写进操作系统的缓冲区,什么时候真写到磁盘由操作系统(OS)说了算(通常 30 秒)。
  3. 在工业界,这种结合不仅存在,而且已经是 Redis 4.0 版本之后的标准配置。它被称为 “混合持久化” (Hybrid Persistence)

    以前,开发者常陷入两难:

    • 只用 RDB:恢复快,但两次快照间会丢失较多数据。
    • 只用 AOF:数据安全,但日志文件巨大,重启恢复慢得要命(需要重放成千上万条命令)。

    1. 它是如何结合的?

    在 Redis 4.0 及以上版本,你可以通过配置开启混合持久化: aof-use-rdb-preamble yes

    它的工作流程如下:

    1. 定期“拍快照”:当 AOF 文件触发重写(Rewrite)时,Redis 不再单纯地把内存命令转成文本,而是先将当前的内存数据以 RDB 的二进制格式 写入 AOF 文件的开头。
    2. 增量“记日志”:在重写期间发生的新的写命令,依然以 AOF 文本格式 追加到文件的末尾。

    2. 文件的结构

    最终生成的 appendonly.aof 文件长这样:

    • [前半部分]:二进制内容(RDB 格式,代表某个时间点的全量数据)。
    • [后半部分]:文本命令(AOF 格式,代表快照之后的增量操作)。

    3. 混合持久化的优势

    这是目前工业界(如阿里云、腾讯云的 Redis 服务)的首选方案:

    • 重启速度极快:加载前半部分的 RDB 就像直接拷贝内存镜像,比逐条执行 AOF 命令快得多。
    • 安全性高:后半部分的 AOF 保证了即使在两次快照之间宕机,也只丢失极少(通常 1 秒内)的数据。
    • 文件更小:二进制的 RDB 头部比等效的 AOF 命令文本要精简得多,节省磁盘空间。

    总结:工业界的最佳实践

    目前绝大多数互联网公司的生产环境配置建议是:

    1. 开启混合持久化
    2. AOF 设置为 everysec(每秒异步刷盘),兼顾性能与安全。
    3. 主节点 (Master) 负责响应请求,从节点 (Slave) 负责开启备份任务,防止 fork 时的性能抖动影响业务。

image-20260116132901050

image-20260116133137648

image-20260116133341612

image-20260116133646347

image-20260116134240005

image-20260116135230005

image-20260116135312989

Redis主从

image-20260116141433895

主从Redis配置

批量拷贝

echo /tmp/7001/ /tmp/7002/ /tmp/7003/ | xargs -n 1 cp /usr/local/src/redis-6.2.6/redis.conf

实例配置:修改端口和dir文件

sed -i -e 's/6379/7001/g' -e 's/dir .//dir /tmp/7001//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .//dir /tmp/7002//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .//dir /tmp/7003//g' 7003/redis.conf

批量为每个redis绑定ip

逐一执行

进入你存放 7001-7003 的目录下执行

sed -i 's/192.168.150.101/192.168.100.128/g' 7001/redis.conf
sed -i 's/192.168.150.101/192.168.100.128/g' 7002/redis.conf
sed -i 's/192.168.150.101/192.168.100.128/g' 7003/redis.conf

或者一键修改

printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf

分别启动

[root@bogon ~]# cd /tmp/
[root@bogon tmp]# redis-server 7001/redis.conf

[root@bogon ~]# cd /tmp/
[root@bogon tmp]# redis-server 7002/redis.conf

[root@bogon ~]# cd /tmp/
[root@bogon tmp]# redis-server 7003/redis.conf

开启主从

[root@bogon src]# redis-cli -p 7002
127.0.0.1:7002> ping
(error) NOAUTH Authentication required.
127.0.0.1:7002> auth 123321
OK
127.0.0.1:7002> BGREWRITEAOF
Background append only file rewriting started
127.0.0.1:7002> ping
PONG
127.0.0.1:7002> SLAVEOF 192.168.150.101 7001

或者

[root@bogon src]# redis-cli -p 7003 -a 123321
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7003> REPLICAOF 192.168.150.101 7001
OK
127.0.0.1:7003>

但是如果主节点有密码,需要先在redis-cli -p 7002之后先确认主节点密码

image-20260116150424429

[root@bogon src]# redis-cli -p 7002 -a 123321
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7002> config set masterauth 123321
OK
127.0.0.1:7002> SLAVEOF 192.168.150.101 7001
OK Already connected to specified master

总结

[root@bogon src]# redis-cli -p 7003 -a 123321
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7003> config set masterauth 123321
OK
127.0.0.1:7003> SLAVEOF 192.168.100.128 7001
OK
127.0.0.1:7003>
[root@bogon src]# redis-cli -p 7002 -a 123321
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7002> config set masterauth 123321
OK
127.0.0.1:7002> SLAVEOF 192.168.100.128 7001
OK
127.0.0.1:7002>
[root@bogon src]# redis-cli -p 7001 -a 123321
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7001> info replication

Replication

role:master
connected_slaves:2
slave0:ip=192.168.150.101,port=7003,state=online,offset=28,lag=1
slave1:ip=192.168.150.101,port=7002,state=online,offset=28,lag=0
master_failover_state:no-failover
master_replid:85dcb5138efcd395d3e10c0cea559641aff72efe
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28

主节点可读可写,从节点只能读

image-20260116151602309

主从Redis原理(全量同步和增量同步)

image-20260116152250565

image-20260116152734491

image-20260116152901563

如果id一致,第一次来就全量同步;如果id不一致,不是第一次来就增量同步

image-20260116153150940

repl_baklog本质是环形数组(会覆盖原来,所以超过上限可能丢失数据;所以超过之后执行全量同步)

image-20260116153806511

主从同步优化

优化全量同步性能

无盘模式

正常全量同步是在磁盘(不是内存)中生成一个rdb文件,然后通过网络把磁盘里面这个rdb文件发送

repl-diskless-sync

无盘模式(repl-diskless-sync yes

  1. 主节点直接 Fork 一个子进程。
  2. 子进程直接扫描内存
  3. 子进程一边扫描,一边把数据按照 RDB 的格式转换成二进制流
  4. 这个流直接通过网络 Socket 发送给从节点,中间不落盘,也不在主节点内存里缓存整个文件。

这种模式主要针对以下特殊场景:

  • 磁盘很慢但网络很快:比如你的磁盘是老旧的 HDD,或者是云服务器上性能较差的云盘,但你拥有万兆(10Gbps)带宽。
  • 减少损耗:频繁的磁盘写入(特别是 SSD)会减少硬件寿命。

这里有一个细节:主节点虽然“无盘”了,但从节点默认还是“有盘”的。

  • 主节点:不写磁盘,直接发流。
  • 从节点:接收到这个流后,通常会先把它存到自己本地的磁盘上(生成 dump.rdb),然后再加载到内存里。

(注:从节点也可以通过设置 repl-diskless-load 来实现完全不写磁盘,直接在内存中解析,但这会有一定的风险,因为一旦解析失败,从节点原来的旧数据已经删了,新数据又没载入成功。)

控制redis单节点内存上限,少一点内存,减少rdb
提高repl_baklog大小
发现slave宕机就尽快鼓掌恢复,尽可能避免全量同步
主-从-从链式结构,限制一个主节点上的从节点的个数

image-20260116154826152

image-20260116154901619

1. 正常状态下:命令传播 (Command Propagation)

当你看到数据“一改就立刻更新”时,它在 Redis 术语里叫 “命令传播”

  • 本质:它是基于长连接的 实时流式同步
  • 过程:主节点每执行一条写命令(如 SETDEL),就会实时把这条命令打包发给 Slave。
  • 特点:Slave 像“复读机”一样,主节点做什么,它就跟着做一遍。这种方式效率极高,因为它不需要重新生成 RDB,也不涉及复杂的对比。

2. 异常状态下:真正的“增量同步” (PSYNC)

你提到的“本质也是增量同步”在 连接闪断 这种场景下体现得最明显。 假设你的主从连接因为网络抖动断开了 10 秒,这 10 秒内主节点又写了 100 条数据。

以前的版本(Redis 2.8 之前): Slave 一重连,主节点就必须执行 BGSAVE 发送完整的 RDB 过来。即便只差一条数据,也要全量同步,非常低效。

现在的版本(Redis 2.8+): 主从利用 PSYNC 命令 实现真正的增量同步。它依赖三个核心要素:

  1. 复制偏移量 (Offset):主节点和从节点各自记录一个数字,代表同步到了第几个字节。
  2. 主节点运行 ID (RunID):Slave 记得主节点的身份,防止重连后认错人。
  3. 复制积压缓冲区 (Replication Backlog Buffer)
    • 主节点内存中有一个环形缓冲区(默认 1MB)。
    • 主节点在发送命令给 Slave 的同时,也会把命令存进这个缓冲区。
    • Slave 重连后:它会对主节点说:“我的 Offset 是 1000,你那现在是多少?”
    • 主节点判断:如果主节点的 Offset 是 1100,且多出来的这 100 字节还在缓冲区里,主节点就只发这 100 字节给 Slave。

这就是你理解的本质上的增量同步(部分重同步)。

3.总结一下

• 平时连接好时:是“命令传播”(像直播,实时发数据)。
• 断开重连且数据量不大时:是“增量同步”(补发缓冲区里漏掉的那段)。
• 断开太久,缓冲区被覆盖了:只能降级为“全量同步”(重新发 RDB)。

💡 一个有趣的细节

你可以通过命令观察这个“缓冲区”: 在主节点输入 INFO Replication,你会看到:
• repl_backlog_size: 缓冲区总大小。
• repl_backlog_histlen: 当前缓冲区里存了多少数据。
如果你的主从连接经常断开并导致全量同步(你可以看日志里有没有写 RDB),那就说明你的 repl_backlog_size 设小了,需要调大。

image-20260116155232225

哨兵机制

image-20260116155322637

image-20260116155559638

image-20260116155728321

image-20260116155913300

image-20260116160044778

image-20260116160054805

image-20260116160150543

哨兵机制搭建

  1. 在/tmp/下 mkdir s1 s2 s3

  2. 在s1目录下创建一个sentinel.conf文件 vi s1/sentinel.conf,添加下面的内容:

    rt 27001
    sentinel announce-ip 192.168.100.128
    sentinel monitor mymaster 192.168.100.128 7001 2
    sentinel down-after-milliseconds mymaster 5000
    sentinel failover-timeout mymaster 60000
    dir "/tmp/s1"
    

    解读:

    • port 27001:是当前sentinel实例的端口
    • sentinel monitor mymaster 192.168.150.101 7001 2:指定主节点信息
      • mymaster:主节点名称,自定义,任意写
      • 192.168.150.101 7001:主节点的ip和端口
      • 2:选举master时的quorum值
  3. 拷贝配置文件

    echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf

  4. 修改s2和s3中配置文件的端口

    sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
    sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf

  5. 启动

​ 第1个

​ redis-sentinel s1/sentinel.conf

​ 第2个

​ redis-sentinel s2/sentinel.conf

​ 第3个

​ redis-sentinel s3/sentinel.conf

  1. 停机测试,关停7001

    redis-cli -p 7001 -a 123321 shutdown

注意

  1. slave7002和7003要配置

replicaof 192.168.100.128 7001
masterauth 123321
replica-announce-ip 192.168.100.128

  1. 如果哨兵s2和s3的配置文件是复制的,且复制之前s1已经运行过,id会重复,需要全都删除,再重新启动就会自动生成三个不同的id
  2. 所以即使一开始是主节点也要配置

[root@bogon tmp]# redis-cli -p 7001 -a 123321 config set masterauth 123321因为有可能待会就宕机变成从节点

RedisTemplate的哨兵模式

image-20260116170735479

打开文件

image-20260116170913065

image-20260116171011931

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:redis:sentinel:master: mymasternodes:- 192.168.100.128:27001- 192.168.100.128:27002- 192.168.100.128:27003password: 123321

image-20260116171111660

简化为

技术栈:

  1. return一个抽象接口时需要用匿名内部类来重写其中方法;建议用lamda表达式优化。

  2. customize 是 Spring Boot 提供的一个“插队”方法(或者叫钩子函数)。

    在 Spring Boot 框架里,它的名字已经说明了一切:Customize = “按需定制”。

1.return一个抽象接口时需要用匿名内部类来重写其中方法;建议用lamda表达式优化。
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){return clientConfigurationBuilder -> {//优先从从节点读clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);};
}
2.customize 是 Spring Boot 提供的一个“插队”方法(或者叫钩子函数)。

在 Spring Boot 框架里,它的名字已经说明了一切:Customize = “按需定制”。

package cn.itcast.redisdemo;import io.lettuce.core.ReadFrom;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;@SpringBootApplication
public class RedisDemoApplication {public static void main(String[] args) {SpringApplication.run(RedisDemoApplication.class, args);}@Beanpublic LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){return clientConfigurationBuilder -> {//优先从从节点读clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);};}
}

总结

先尝试连接哨兵,发现多个哨兵,选一个哨兵建议连接;

订阅dispatching command SubscriptionCommand,获取redis集群的真实地址;

订阅之后哨兵就会把这个精确信息发给客户端,先得到master的redis的信息,再得到一个数组,封装了从节点salve的信息

同时连接主从节点

查询:连接从节点

如果:master宕机,切换;java客户端会再次尝试连接哨兵集群,通过哨兵重新连接redis集群

增删改:交给主节点

Redis分片集群

image-20260116183712588

步骤

  1. 进入/tmp目录

    cd /tmp

    删除旧的,避免配置干扰

    rm -rf 7001 7002 7003

    创建目录

    mkdir 7001 7002 7003 8001 8002 8003

  2. 在/tmp下准备一个新的redis.conf文件,内容如下:

    port 6379

    开启集群功能

    cluster-enabled yes

    集群的配置文件名称,不需要我们创建,由redis自己维护

    cluster-config-file /tmp/6379/nodes.conf

    节点心跳失败的超时时间

    cluster-node-timeout 5000

    持久化文件存放目录

    dir /tmp/6379

    绑定地址

    bind 0.0.0.0

    让redis后台运行

    daemonize yes

    注册的实例ip

    replica-announce-ip 192.168.150.101

    保护模式

    protected-mode no

    数据库数量

    databases 1

    日志

    logfile /tmp/6379/run.log

  3. 将这个文件拷贝到每个目录下:

    echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf

  4. 修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf

  5. 一键启动

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf

  6. 查看状态

    ps -ef | grep redis

  7. 关闭所有进程

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown

  8. 进入redis的src目录

    创建集群

    redis-cli --cluster create --cluster-replicas 1 192.168.100.128:7001 192.168.100.128:7002 192.168.100.128:7003 192.168.100.128:8001 192.168.100.128:8002 192.168.100.128:8003

命令说明:

  • redis-cli --cluster或者./redis-trib.rb:代表集群操作命令
  • create:代表是创建集群
  • --replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
  1. 查看集群状态

    redis-cli -p 7001 cluster nodes

    Redis 节点的端口分配有一个固定的规则:总线端口 = 数据端口 + 10000。
    • 数据端口 (7002):这是我们平时使用的端口,用来读写数据、处理 redis-cli 的请求。
    • 总线端口 (17002):这是 Redis 节点之间“私聊”用的端口。

散列插槽

image-20260116192744712

集群模式下启动

redis-cli -c -p 7001要加上-c进入控制台,-c表示可以重定向

image-20260116193236279

image-20260116193337034

集群伸缩

image-20260116194016582

添加节点到集群

redis-cli --cluster add-node 192.168.100.128:7004 192.168.100.128:7001

转移插槽分配

redis-cli --cluster reshard 192.168.100.128:7001

[root@bogon tmp]# redis-cli -p 7004 cluster nodes
e8b585d5e95575db3e1bc4bc825f796f9b0827dd 192.168.100.128:7004@17004 myself,master - 0 1768564434000 7 connected 0-2999
a9566a4d801ca50585f62f606729da8c3b415a18 192.168.100.128:7002@17002 master - 0 1768564436000 2 connected 5461-10922
1bde8c3b9570df77f4f3ed1b9458796c5a9ae77d 192.168.100.128:8001@18001 slave e4d7b85516173e6e6604eee9fbf0aeec0f990ebd 0 1768564434644 1 connected
e4d7b85516173e6e6604eee9fbf0aeec0f990ebd 192.168.100.128:7001@17001 master - 0 1768564435000 1 connected 3000-5460
449e7b0b76e71149611d7c36d25fffbb291d6758 192.168.100.128:8003@18003 slave 0c5b13b6228708c5c8b7bfb9c2cfd01734f2bd93 0 1768564436559 3 connected
02104f52a720282377b68352e0b088ecc330b1e6 192.168.100.128:8002@18002 slave a9566a4d801ca50585f62f606729da8c3b415a18 0 1768564435955 2 connected
0c5b13b6228708c5c8b7bfb9c2cfd01734f2bd93 192.168.100.128:7003@17003 master - 0 1768564436000 3 connected 10923-16383
[root@bogon tmp]# redis-cli -c -p 7001
127.0.0.1:7001> get num
-> Redirected to slot [2765] located at 192.168.100.128:7004
"123"
192.168.100.128:7004> set num 10
OK

删除集群中的节点

删除一个带槽节点的标准流程分为两步:迁移槽位(Reshard) 和 正式删除(Del-node)。

第一步:迁移槽位 (Resharding)
你需要把 7004 拥有的 0-2999 槽位平摊给其他 Master 节点(比如 7001, 7002, 7003)。

  1. 执行迁移命令:
    Bash
    Copy code
    redis-cli --cluster reshard 192.168.100.128:7001
    注意:IP 端口可以是集群中任何一个存活的节点。
  2. 按照提示输入参数:
    • How many slots do you want to move? 输入 3000 (你要迁出的槽位总数)。
    • What is the receiving node ID? 输入目标节点的 ID(例如 7001 的 ID)。你想把这 3000 个槽给谁,就填谁的 ID。
    • Source node IDs? 输入 7004 的节点 ID。
    • Done? 输入 done。
  3. 确认迁移: 输入 yes。Redis 会开始把数据从 7004 搬运到目标节点。

    第二步:删除节点 (Del-node)
    当 7004 变成一个“空节点”(不再持有任何槽位)后,你就可以安全地把它踢出集群了。
  4. 执行删除命令:
    Bash
    Copy code

格式:redis-cli --cluster del-node <集群中任意IP:PORT> <要删除的节点ID>

redis-cli --cluster del-node 192.168.100.128:7001 <7004的Node_ID>

  1. 验证结果:
    Bash
    Copy code
    redis-cli -c -p 7001 cluster nodes
    此时你应该看不到 7004 节点了,且原有的 0-2999 槽位已经转移到了你指定的接收节点上。

故障转移

image-20260116200922722

image-20260116201220795

一般就用默认这个

主变从,从变主

[root@bogon tmp]# redis-cli -c -p 7002
127.0.0.1:7002> cluster failover

RedisTemplate 访问分片集群

image-20260116201651761

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询