Redis 哨兵模式:告别手动故障转移!
目录
- 前言
- 一、 Redis哨兵模式是啥?🤔
- 二、 为什么需要哨兵模式?🤷♀️
- 三、 哨兵模式的原理是什么?🤝
- 1. 监控(Monitoring)
- 2. 信息共享与客观下线判断
- 3. 哨兵领导者选举
- 4. 故障转移
- 5. 通知
- 四、 如何搭建(1主2从3哨兵)?
- 步骤 1:创建项目目录和文件
- 步骤 2:创建哨兵配置文件 (sentinel_conf/sentinel.conf)
- 步骤 3:创建 Docker Compose 配置文件 (docker-compose.yml)
- 步骤 4:启动集群
- 步骤 5:验证集群状态
- 步骤 6:模拟故障并观察自动切换 🔄
- 五、 哨兵模式的优缺点是什么?
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 缓存雪崩、穿透、击穿 请看 : 缓存雪崩、穿透、击穿:别让你的数据库“压力山大”!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
前言
大家好!👋 在上一篇关于 《Redis主从复制:告别单身Redis!》 的分享中,我们一起探索了Redis主从复制的奥秘。通过主从架构,我们实现了数据的备份 💾,并通过读写分离显著提升了Redis的读取性能 🚀,为我们的应用带来了诸多益处。
然而,正如月有阴晴圆缺,主从复制架构也并非完美无瑕。细心的小伙伴们可能已经意识到一个关键问题:如果被所有从节点依赖的主节点(Master)突然宕机了怎么办? 😱
在单纯的主从架构下,这无疑是一个“灾难性”的场景:
- 写操作完全中断 🛑:没有Master,新的数据无法写入。
- 数据一致性风险 🤔:如果宕机前有部分数据还没来得及同步到所有Slave…
- 需要人工干预 🧑💻:运维同学需要手动介入,从众多Slave中挑选一个“幸运儿”执行
SLAVEOF NO ONE
,将其提升为新的Master,再让其他Slave指向这位新“老大”,最后还得通知所有应用程序:“嘿,换老板了,连接地址改一下!” 这个过程不仅 耗时 ⏳,容易 出错 ❌,更重要的是,在手动恢复完成之前,服务是 不可用 的!
对于需要高可用性、希望系统能尽可能“自愈”的关键业务来说,这种“手动挡”的故障恢复方式显然是难以接受的。我们渴望一种更智能、更自动化的机制来守护我们的Redis集群。
那么,有没有一种方法,能自动监控主节点的状态,并在它“倒下”时,自动推举出新的主节点,让整个切换过程尽可能平滑无感呢? 🤔
答案是肯定的! 这就是我们今天要深入探讨的主角—— Redis哨兵(Sentinel)模式 👮♂️✨。
哨兵模式,就像是为我们的Redis主从集群配备了一支 7x24小时在线的智能安保团队。它们时刻监控着集群的健康状况,一旦发现主节点失联,就能迅速、自动地完成故障发现、领导者选举、新主节点提升、从节点重定向以及通知客户端等一系列复杂操作,从而极大地提升了Redis集群的可用性,将单点故障的风险降到最低。
在本篇文章中,我们将:
- 深入理解哨兵模式的核心概念和它要解决的痛点 (Why Sentinel?)
- 揭秘哨兵模式自动化故障转移的工作原理 (How Sentinel Works?)
- 手把手带你使用 Docker 和 Docker Compose 在Linux上搭建一个一主二从三哨兵的典型架构 (Let’s Build It! 🛠️)
- 全面分析哨兵模式的优缺点 (Pros & Cons)
准备好了吗?让我们一起揭开Redis哨兵模式的神秘面纱,看看它是如何成为Redis高可用架构中不可或缺的一环吧!🚀
一、 Redis哨兵模式是啥?🤔
想象一下,你开了一个很火的店铺 🏪(这就是你的Redis主节点,Master),生意太好 🔥,一个人忙不过来,就找了几个学徒 🧑🎓(这就是Redis从节点,Slaves)。学徒跟着你学,你做啥他们也跟着做啥(数据复制 📜),这样客人来了,简单的活(读数据 📖)可以让学徒干,你就轻松多了(读写分离)。
但是,万一你这个主节点(老板 👨💼)突然生病请假 🤒 或者有事儿不在了(宕机 ❌),店就没人管了,学徒们也不知道谁该出来主持大局,生意就停摆了 🛑(服务不可用)。
哨兵模式(Sentinel) 就是为了解决这个问题而生的。它就像是你雇佣的一个或多个 特别靠谱的保安(哨兵) 👮♂️👮♀️。这些保安不干活(不存数据),他们的主要职责就是:
- 不停地盯着老板(Master)和学徒(Slaves) 👀,看他们是不是在正常工作 ✅。
- 互相通气 🗣️:保安之间会交流信息,确认老板是不是真的出事了,而不是某个保安眼花看错了 🤔。
- 紧急预案 🚨:一旦确认老板真的挂了,他们会按照预定规则(比如挑个最能干的学徒 💪)推举一个新的老板(Master) 出来主持大局。
- 通知大家 📢:选出新老板后,保安会 通知所有学徒:“以后跟他混!” 也会 通知所有客人(客户端):“现在新老板是这位,找他下单!”
- 老老板回来了咋办?:如果原来的老板回来了 🚶♂️,保安会告诉他:“现在店里有新老板了,你现在也变成学徒(Slave)吧。” (有点小委屈但为了店铺好嘛 😅)
总结: Redis哨兵模式是一套用于 监控 Redis主从集群、实现 自动故障转移(Failover 🛠️)和 通知 客户端新主节点地址的解决方案,核心目标是 提高Redis服务的可用性 ✨。
二、 为什么需要哨兵模式?🤷♀️
在只有主从复制(Master-Slave)的结构下:
- 优点:
- 数据备份: 从节点是主节点的热备份 💾。
- 读写分离: 主节点处理写操作和部分读操作,从节点处理大部分读操作,分担主节点压力,提高读取性能 🚀。
- 致命缺点:
- 单点故障(Single Point of Failure, SPOF): 主节点(Master)是整个系统的“命脉” ❤️🩹。一旦主节点宕机 ❌,写操作完全无法进行。虽然从节点有数据,但它们默认是只读的 🚫✍️,并且不会自动升级为新的主节点。
- 需要人工干预: 发现主节点宕机后,需要运维人员 🧑💻 手动选择一个从节点,执行
SLAVEOF NO ONE
命令使其成为新的主节点,再让其他从节点指向这个新主节点,最后还要通知所有应用程序修改连接配置 🤯。这个过程耗时、易出错,期间服务是中断的。
哨兵模式就是来解决这个“单点故障”和“手动恢复”问题的。 它引入了自动化的监控和故障转移机制,当主节点失效时,能自动完成一系列复杂的操作,快速恢复服务 ✅,大大减少了停机时间,保证了系统的高可用性 ✨。
三、 哨兵模式的原理是什么?🤝
哨兵模式的核心原理可以拆解为几个关键动作:
1. 监控(Monitoring)
- 每个哨兵进程会 定期(通常每秒)向它监控的所有Redis实例(包括主节点和从节点)发送
PING
命令 ,看对方是否正常响应PONG
✅。 - 如果一个实例在配置的
down-after-milliseconds
时间内没有有效回复 ⏳,这个哨兵就会 主观地 认为该实例 下线(Subjectively Down,简称 SDOWN) 🤔。这只是这个哨兵自己的判断,可能是网络抖动 🌐〰️ 或这个哨兵自身网络有问题。
2. 信息共享与客观下线判断
- 哨兵们不仅监控Redis实例,它们之间也会互相发送
PING
和订阅消息 📨,形成一个哨兵网络 🕸️。 - 当一个哨兵认为主节点 SDOWN 后,它会向其他哨兵发出
SENTINEL is-master-down-by-addr
命令,询问它们的看法:“嘿,哥们儿,你觉得老板挂了吗?” 🗣️。 - 如果 足够数量(达到预设的 Quorum 值,即法定人数 🗳️)的其他哨兵也认为该主节点 SDOWN,那么这个主节点就被 客观地 标记为 下线(Objectively Down,简称 ODOWN) 🧑⚖️。这个判断是集群共识,更可靠 👍。Quorum 的值通常设置为哨兵总数的一半加一 (
N/2 + 1
),防止网络分区导致的误判。
3. 哨兵领导者选举
- 一旦主节点被确认 ODOWN ❌,就需要一个哨兵来 负责执行 故障转移操作。不能所有哨兵都去操作,会乱套 🤪。
- 哨兵们会进行一次 领导者选举 👑。选举过程类似于 Raft 算法的一个简化版本:
- 发现 ODOWN 的哨兵会请求其他哨兵投票给自己成为领导者 🙋♂️。
- 每个哨兵在一个任期(epoch)内只能投一票 ☝️,并且会投给最先收到的请求。
- 获得超过半数(Quorum)选票的哨兵成为领导者(Leader)🎉。
- 如果没有选出领导者,会增加任期号,重新选举 🔄。
4. 故障转移
- 选出新主节点: 领导者哨兵 👑 会从所有状态正常的从节点中,按照一定的 优先级规则 🥇🥈🥉 挑选一个最合适的作为新的主节点:
- 优先级(
replica-priority
): 配置值越小,优先级越高。 - 复制偏移量(Replication Offset): 选择复制数据最新的(偏移量最大 📈)。
- 运行ID(Run ID): 选择运行ID最小的(通常意味着启动时间最早 ⏱️)。
- 优先级(
- 执行切换:
- 领导者向选中的从节点发送
SLAVEOF NO ONE
命令,使其升级为新的主节点 ✨👑。 - 领导者向其他所有从节点发送
SLAVEOF <new_master_ip> <new_master_port>
命令,让它们指向新的主节点 👉👑。 - (如果旧主节点恢复 ✅)领导者也会向恢复的旧主节点发送
SLAVEOF <new_master_ip> <new_master_port>
命令,使其降级为从节点 😅。
- 领导者向选中的从节点发送
- 更新配置: 哨兵会更新自身和其他哨兵关于
mymaster
的配置信息 📝,记录新的主节点地址。
5. 通知
- 整个过程中(SDOWN、ODOWN、选举、切换等),哨兵会通过 Redis 的 发布/订阅(Pub/Sub) 功能发布各种事件消息 📢 (如
+sdown
,+odown
,+failover-start
,+switch-master
等)。 - 客户端可以订阅这些频道 👂,实时获取状态变化信息,特别是
+switch-master
事件,客户端收到后就知道需要连接到新的主节点地址了 💡。很多 Redis 客户端库内置了对哨兵模式的支持,可以自动处理这个切换过程,非常方便 😊。
四、 如何搭建(1主2从3哨兵)?
假设你已经在Linux系统上安装好了 Docker 和 Docker Compose。
步骤 1:创建项目目录和文件
# 创建一个项目目录 📁
mkdir redis-sentinel-cluster
cd redis-sentinel-cluster# 创建用于存放哨兵配置文件的目录 📄
mkdir sentinel_conf
步骤 2:创建哨兵配置文件 (sentinel_conf/sentinel.conf)
# 哨兵监听的端口(每个哨兵实例在docker-compose中会映射到不同宿主机端口)
# port 26379 # 在compose中通过命令覆盖或让其动态发现,这里可以注释掉或保留默认# 监控名为 'mymaster' 的主节点,地址是 'redis-master' (docker内部服务名),端口 6379
# 最后的 '2' 是 quorum 值,表示至少需要2个哨兵同意,才能判定主节点 objectively down
sentinel monitor mymaster redis-master 6379 2# 主节点被判定为 SDOWN 的超时时间(毫秒)⏲️
sentinel down-after-milliseconds mymaster 5000# 故障转移的超时时间(毫秒),如果超过这个时间还没完成,认为失败 ⏳
sentinel failover-timeout mymaster 15000# 在执行故障转移时,最多可以有多少个从节点同时对新的主节点进行同步(1表示一次一个,更安全 👍)
sentinel parallel-syncs mymaster 1# (可选) 认证密码 🔑,如果你的Redis实例设置了密码
# sentinel auth-pass mymaster YourRedisPassword
重要 ❗️:
mymaster
是你给这个主从集群起的名字,可以自定义,但所有哨兵配置和客户端连接时都要用这个名字。redis-master
是后面docker-compose.yml
文件中定义的 Redis主节点的服务名。Docker Compose内部网络会自动解析这个名字到对应容器的IP。quorum
值设为2
,因为我们有3个哨兵,3 / 2 + 1 = 2.5
-> 需要2个哨兵同意。
步骤 3:创建 Docker Compose 配置文件 (docker-compose.yml)
services:redis-master: # 老板 👨💼image: redis:latest #选择最新的版本container_name: redis-mastercommand: redis-server --port 6379 # 可以省略,默认就是6379ports:- "6379:6379" # 映射主节点端口到宿主机networks:- redis-net# volumes: # 如果需要持久化数据 💾# - redis_master_data:/dataredis-slave-1: # 学徒 1 🧑🎓image: redis:latestcontainer_name: redis-slave-1command: redis-server --slaveof redis-master 6379 # 告诉他跟着谁混ports:- "6380:6379" # 映射从节点端口到宿主机不同端口depends_on:- redis-masternetworks:- redis-net# volumes:# - redis_slave1_data:/dataredis-slave-2: # 学徒 2 🧑🎓image: redis:latestcontainer_name: redis-slave-2command: redis-server --slaveof redis-master 6379 # 告诉他跟着谁混ports:- "6381:6379" # 映射从节点端口到宿主机不同端口depends_on:- redis-masternetworks:- redis-net# volumes:# - redis_slave2_data:/dataredis-sentinel-1: # 保安 1 👮♂️image: redis:latestcontainer_name: redis-sentinel-1# 增加启动延迟command: sh -c "sleep 15 && redis-sentinel /etc/redis/sentinel.conf --port 26379"volumes:- ./sentinel_conf/sentinel.conf:/etc/redis/sentinel.conf # 挂载配置文件 📄ports:- "26379:26379" # 映射哨兵端口depends_on: # 依赖所有 Redis 节点,确保它们先启动(虽然不完全保证启动完成😅)- redis-master- redis-slave-1- redis-slave-2networks:- redis-netredis-sentinel-2: # 保安 2 👮♀️image: redis:latestcontainer_name: redis-sentinel-2# 增加启动延迟command: sh -c "sleep 15 && redis-sentinel /etc/redis/sentinel.conf --port 26379" # 内部端口仍是26379,外部映射不同volumes:- ./sentinel_conf/sentinel.conf:/etc/redis/sentinel.confports:- "26380:26379" # 映射到宿主机 26380depends_on:- redis-master- redis-slave-1- redis-slave-2networks:- redis-netredis-sentinel-3: # 保安 3 👮♂️image: redis:latestcontainer_name: redis-sentinel-3# 增加启动延迟command: sh -c "sleep 15 && redis-sentinel /etc/redis/sentinel.conf --port 26379" # 内部端口仍是26379,外部映射不同volumes:- ./sentinel_conf/sentinel.conf:/etc/redis/sentinel.confports:- "26381:26379" # 映射到宿主机 26381depends_on:- redis-master- redis-slave-1- redis-slave-2networks:- redis-netnetworks:redis-net: # 定义一个网络 🌐,让所有容器可以互相通信driver: bridge # 使用默认的bridge驱动# volumes: # 如果需要持久化,需要定义volumes 💾
# redis_master_data:
# redis_slave1_data:
# redis_slave2_data:
注意:
- 我们为每个服务定义了
container_name
,方便识别。 - 所有服务都连接到同一个自定义网络
redis-net
,这样它们可以通过服务名(如redis-master
)互相访问。 - 从节点通过
command: redis-server --slaveof redis-master 6379
自动配置为主节点的从节点。 - 哨兵服务通过
command: redis-sentinel /etc/redis/sentinel.conf --port 26379
启动。我们挂载了同一个sentinel.conf
文件。重要的是,我们将每个哨兵容器的26379端口映射到了宿主机的不同端口(26379, 26380, 26381),以便从外部访问它们。 depends_on
有助于控制启动顺序,但并不保证服务完全就绪。哨兵有重试机制,最终会连上 💪。- 如果需要数据持久化,需要取消注释
volumes
部分。
步骤 4:启动集群
在 redis-sentinel-cluster
目录下,运行:
docker compose up -d
这会在后台启动所有容器 🚀。
步骤 5:验证集群状态
-
查看容器是否运行:
docker compose ps
应该能看到 1 个 master, 2 个 slave, 3 个 sentinel 都在运行 (Up) ✅。
-
连接到一个哨兵查看集群信息:
# 连接到第一个哨兵 (宿主机端口 26379) docker exec -it redis-sentinel-1 bash redis-cli -p 26379# 在 redis-cli 中执行哨兵命令: SENTINEL master mymaster # 查看 'mymaster' 的主节点信息 👨💼 SENTINEL slaves mymaster # 查看 'mymaster' 的从节点信息 🧑🎓🧑🎓 SENTINEL sentinels mymaster # 查看监控 'mymaster' 的其他哨兵信息 👮♂️👮♀️👮♂️
你应该能看到主节点是
redis-master:6379
,有两个从节点,并且有3个哨兵。 -
测试主节点连接和数据同步:
# 连接主节点 (宿主机端口 6379) docker exec -it redis-master bash redis-cli #进入主节点客户端 set mykey hello 👋 # 写入数据 exit# 连接一个从节点 (例如宿主机端口 6380) docker exec -it redis-slave-1 bash redis-cli #进入从节点 1 客户端 get mykey # 读取数据,应该能读到 "hello" 👋 # 尝试写入数据 (应该会报错 🚫,因为从节点默认只读) set anotherkey world # (error) READONLY You can't write against a read only replica. exit
步骤 6:模拟故障并观察自动切换 🔄
-
停止主节点容器(模拟老板跑路 🏃♂️💨):
docker compose stop redis-master
-
观察哨兵日志(可选,但推荐 👀):
打开一个新的终端,实时查看其中一个哨兵的日志:docker compose logs -f redis-sentinel-1
你会看到类似
+sdown master mymaster ...
(觉得老板不对劲 🤔),然后是+odown master mymaster ...
(确认老板真的挂了 ❌),接着是选举 (+vote-for-leader
🗳️),最后是+switch-master mymaster ...
(宣布新老板 🎉),显示新的主节点 IP 和端口(它会显示容器内部 IP,例如172.x.x.x
)。
-
再次查询哨兵确认新主节点:
等待一小会儿(根据配置,通常几秒到十几秒 ⏳),再次连接哨兵:docker exec -it redis-sentinel-1 bash redis-cli -p 26379 SENTINEL master mymaster
你会发现
master
的地址已经变成了之前某个从节点的地址(在Docker网络内的IP)。同时,num-slaves
可能暂时减少,或者显示旧主节点处于下线状态。 -
测试新主节点:
找到新主节点的宿主机映射端口(比如之前是 6380 或 6381 的那个),连接并尝试写入:# 根据上面克制,外部端口 6380 对应的从节点被提升了 👑 docker exec -it redis-slave-1 bash #进入到6380对于的从节点 redis-cli set newkey world 🌍 # 应该可以成功写入 ✅ get mykey # 应该还能读到之前的数据 "hello" 👋 exit
-
恢复旧主节点(老板回来了 😊):
docker compose start redis-master
-
再次观察哨兵日志或查询哨兵:
你会看到哨兵发现了旧主节点的恢复 ✅,并将其配置为新主节点的从节点(现在是学徒了 😅)。docker exec -it redis-sentinel-1 bash redis-cli -p 26379 SENTINEL slaves mymaster
现在应该能看到原来的
redis-master
容器作为从节点出现在列表里了。
五、 哨兵模式的优缺点是什么?
优点:
- 高可用性(High Availability)✨: 这是最核心的优点。主节点挂了能自动切换,服务中断时间大大缩短。就像有个备用老板随时待命!
- 自动故障转移(Automatic Failover)🤖: 无需人工干预 🧑💻❌,降低运维成本和出错风险。保安会自动处理紧急情况!
- 监控(Monitoring)👀: 不断检查主从节点状态,提供集群健康状况信息。时刻关注店铺运营!
- 通知(Notification)📢: 客户端或监控系统可以通过订阅哨兵消息,及时了解集群状态变化,自动更新连接。消息灵通!
- 配置提供者 🗺️: 客户端连接时可以先问哨兵:“老大(Master)是谁?”,哨兵会告知当前主节点的地址。像个问询处!
缺点:
- 配置相对复杂 🤔: 比单纯的主从复制多了一层哨兵的配置和管理。要多管理几个保安。
- 资源消耗 💸: 需要额外部署哨兵进程(至少3个以保证高可用),占用服务器资源(虽然哨兵本身资源消耗不大)。多雇几个人要多发点工资嘛。
- 故障转移有延迟 ⏳: 从发现主节点宕机到完成切换,整个过程需要时间(秒级),期间写服务是不可用的 🛑✍️。这个短暂的窗口期内可能会丢失少量写操作(取决于客户端重试策略和Redis持久化配置)。保安反应再快也需要一点点时间。
- 写能力没有扩展 📈❌: 任何时候都只有一个主节点处理写操作,哨兵模式不解决写性能瓶颈问题。店铺再大,能拍板下单的还是只有一个老板。如果需要扩展写能力,需要考虑 Redis Cluster。
- 判断主观下线(SDOWN)可能受网络影响 🌐❓: 单个哨兵的网络问题可能导致误判 SDOWN,但 ODOWN 判断机制(需要 Quorum)大大降低了误判的可能性 👍。
- 客户端需要支持哨兵 📱💡: 应用程序的客户端需要使用支持哨兵模式的库,或者通过代理来动态获取主节点地址。不能再傻傻地只认一个老板的地址了。
- 可能出现脑裂(Split-Brain)问题(理论上)🤯: 在极端复杂的网络分区情况下,如果 Quorum 设置不当,可能会导致两个独立的分区各自选出一个 Master。虽然哨兵机制设计上尽量避免这种情况,但理论风险存在。就像两个地方都以为自己是总部。
相关文章:
Redis 哨兵模式:告别手动故障转移!
目录 前言一、 Redis哨兵模式是啥?🤔二、 为什么需要哨兵模式?🤷♀️三、 哨兵模式的原理是什么?🤝1. 监控(Monitoring)2. 信息共享与客观下线判断3. 哨兵领导者选举4. 故障转移5.…...
地理数据输出
为了便于数据共享和交换,可以将地理数据库中的要素数据输出为Shapefiles或者Coverage,将相应的属性表输出为Info或者dBase格式的数据文件。 1.输出为 Shapefile (1)在AreCatalog目录树或者内容栏中,右键点击需要输出的地理要素类,…...
springboot + security + redis + jwt 实现验证登录上
前言: 通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往…...
SomeIP通讯机制
在SOME/IP协议中,通讯方式主要围绕服务的交互模式进行的设计,核心机制包括Event(时间)、Method(方法)以及其变种Fire-and-Forget(FF)。以下是SOME/IP中所有通信方式的总结࿱…...
线代第三课:n阶行列式
引言 行标取自然排列 不同行不同列的3个元素相乘 列标取排列的所有可能 列标排列的逆序数的奇偶性决定符号,- n阶行列式 第一种:按行展开 (1) 行标取自然排列 (2) 列标取排列的所有可能 (PS:可以理解为随意取) (3) 从…...
人工智能在高中教育中的应用现状剖析与挑战应对
第一章:绪论 1.1 研究背景与意义 随着全球化的加速和科技的飞速发展,高中教育在培养未来社会所需人才方面的重要性日益凸显。高中阶段是学生知识体系构建和思维能力发展的关键时期,然而,当前高中教育面临着诸多挑战,…...
如何在powerbi使用自定义SQL
我们在刚使用到powerbi的时候发现当直接连接到数据库的时候我们只能使用数据库中已存在的表,我们没有办法使用自定义SQL来准备数据,这给我们的开发造成很大的困扰;我目前使用的是vertica数据库,首先我们需要在本地有vertica的驱动…...
边缘计算盒子是什么?
边缘计算盒子是一种小型的硬件设备,通常集成了处理器、存储器和网络接口等关键组件,具备一定的计算能力和存储资源,并能够连接到网络。它与传统的云计算不同,数据处理和分析直接在设备本地完成,而不是上传到云端&#…...
【C++面向对象】封装(上):探寻构造函数的幽微之境
每文一诗 💪🏼 我本将心向明月,奈何明月照沟渠 —— 元/高明《琵琶记》 译文:我本是以真诚的心来对待你,就像明月一样纯洁无瑕;然而,你却像沟渠里的污水一样,对这份心意无动于衷&a…...
物联网|无人自助台球厅源码|哪些框架支持多设备连接?
在无人自助台球厅的智能化管理中,物联网(IoT)技术是核心支撑。如何实现不同设备(如智能门锁、环境传感器、支付终端、灯光控制系统等)的高效连接与协同工作,是系统开发的关键挑战。本文将带大家探讨支持多设…...
单旋翼无人机(直升机)和四旋翼无人机优势对比
以下是无人机直升机(单旋翼无人机)与四旋翼无人机的优势对比分析,分场景阐述两者的核心差异: 一、无人机直升机(单旋翼无人机)的优势 1. 高能量效率,长续航 动力设计:单…...
微服务之间调用外键“翻译”的方法概述
写在前面的话:减少strean流操作,减少多层嵌套for循环。使用普通for循环和map的方式进行转换, 第一步查询数据 List<Student> findList studentDao.findList(findMap); 第二步准备遍历和赋值 if(CollectionUtil.isNotEmpty(findLis…...
Java学习——day25(多线程基础与线程创建方式)
文章目录 1. 多线程基础1.1 线程的概念1.2 线程的生命周期 2. 创建线程的方式2.1 继承 Thread 类2.2 实现 Runnable 接口 3. 实践:编写简单多线程程序4. 总结与思考 1. 多线程基础 1.1 线程的概念 线程 (Thread): 程序执行的最小单元,一个进…...
2025前端面试题
Vue 3 比 Vue 2 更快的原因 Vue 3 使用 JavaScript 的 Proxy 替代了 Vue 2 中的 Object.defineProperty 来实现响应式系统。Proxy 可以拦截对象的所有操作,无需像 Object.defineProperty 那样单独定义每个属性的 getter 和 setterVue 3 还引入了静态树提升…...
2025-04-09 吴恩达机器学习6——神经网络(1):介绍
文章目录 1 神经网络介绍1.1 起源与发展1.2 生物神经元 vs. 人工神经元1.3 学习建议 2 案例:T 恤预测2.1 基础概念2.2 需求预测示例2.3 多隐藏层神经网络2.4 神经网络的优势 3 案例:图像感知3.1 计算机视觉任务3.2 神经网络架构 1 神经网络介绍 1.1 起源…...
Win11新功能更新:中文语音控制、游戏体验提升、锁屏更多广告
近日,微软在Windows 11发布预览版(Insider Release Preview Channel)中公布了即将正式推送的一系列新功能。这些更新体现了微软“持续创新”策略——不再依赖传统大型版本更新,而是以更高频率为用户带来功能改进。这一波新功能覆盖…...
Cursor编程-从入门到精通__0409
早期的Github Copilot 最近更新了,支持Agent编程,字节跳动Trae使用(免费),但成熟程度不如Cursor,Cursor前50次免费 Copilot VS Cursor*** 1,Cursor VSCode 二次开发,IDE级别 2&…...
【Leetcode-Hot100】移动零
题目 解答 首先,使用的解题思路是:使用两个指针,分别指向数组的第一个0元素位置,以该元素位置1为起始点寻找接下来第一个非0元素位置。二者确定后,对其进行交换。随后继续寻找下一个0元素位置。重复上述操作。 但第一…...
【力扣hot100题】(079)划分字母区间
感觉智商又回来了(松气)。 方法大概是先建立哈希表遍历数组记录每一个字母位置的跨度,然后再遍历数组,每次遇到跨度大于目前长度的字母,就将目前长度延申跨度的长度,然后继续遍历,知道位置已经…...
更改CMD背景图片
1.下载microsoft powershell 总之,电脑里面要有microsoft powershell这个应用 如下所示 进入界面后, 依次点击命令提示符和外观。 进入后,修改背景图片 2. 查看最终效果 最终我们打开CMD界面, 然后查看。 最终结果大功告成...
如何利用AI工具进行抠图
软件介绍 AIArty Image Matting是一款AI抠图软件,为了方便大家使用,我已经将软件所需的模型下载好。 首先要进行软件安装并运行,之后将“model”压缩包解压,把解压后的文件复制粘贴到“C:\ProgramData\Aiarty\ImageMatting”文件…...
一个很好用的vue2在线签名组件
在前端开发的日常工作中,我们常常会遇到需要用户进行在线签名的需求,比如电子合同签署、表单确认等场景。最近,我在项目里使用了一款极为好用的 Vue2 在线签名组件,今天就来和大家分享一下使用心得。 效果图 上代码 在 views 下…...
软考高级-系统架构设计师 案例题-软件架构设计
文章目录 软件架构设计质量属性效用树,质量属性判断必背概念架构风格对比MVC架构J2EE四层结构面向服务架构SOA企业服务总线ESB历年真题【问题1】 (12分)【问题2】(13分) 参考答案历年真题【问题1】(12分)【…...
计算机网络笔记-分组交换网中的时延
一、分组交换网络中的四种时延类型 1. 排队时延 在队列中,当分组在链路上等着被传输时的时延为排队时延,一个分组的排队时延长度取决于该分组前方等待传输的分组数量,如果排队队列为空,且没有正在传输的分组那么该分组的排队时延…...
数据结构与算法-图论-复习2(差分约束,强连通分量,二分图,LCA,拓扑排序,欧拉路径和欧拉回路)
7. 差分约束 原理 差分约束系统是一种特殊的不等式组,形如 xi−xj≤c。可以将其转化为图论中的最短路或最长路问题。 最短路求最大值:当我们要找出满足所有不等式的最大解时,使用最短路算法。对于不等式 xi−xj≤c,可以…...
git强制更新本地分支
你的需求是希望 自动拉取所有远程分支,并且在分支间存在冲突时 自动覆盖本地内容(不保留差异)。以下是优化后的解决方案: 最终解决方案(全自动强制覆盖) git fetch --all && for branch in $(git …...
PH热榜 | 2025-04-09
1. EZsite AI 标语:构建能够秒级产生收入的人工智能应用。 介绍:EZsite AI 让任何人都能轻松创建专业的网站和应用,不需要编写代码。它自动保存您的数据库信息,内置的 AI 聊天机器人能帮助您捕获潜在客户,并且通过 A…...
进度管理__制订进度计划_资源平衡和资源平滑
本文讲解的资源平衡与资源平滑,是制订进度计划的工具与技术的第3项: 资源优化。 1. 资源平衡 资源平衡是为了在资源需求与资源供给之间取得平等, 根据资源制约因素对开始日期和完成日期进行调整的一种技术。 如果共享资源或关键资源只在特定…...
【力扣hot100题】(080)爬楼梯
让我们掌声恭迎动态规划的始祖—— 最基础的动态规划,原始方法是维护一个数组,每次记录到该阶梯的方案数量,每次的数量是到上一个阶梯的方案数量加上到上上一阶梯的方案数量,因为只有两种走法。 进阶可以优化空间复杂度…...
redis_exporter服务安装并启动
redis_exporter服务安装并启动 1、介绍2、下载redis_exporter3、解压缩文件4、启动redis_exporter服务 1、介绍 Redis Exporter 是 Prometheus 官方推荐的 Redis 监控数据导出工具,用于将 Redis 实例的性能指标暴露为 Prometheus 可抓取的格式。 2、下载redis_exp…...
Spring Security 的核心配置项详解,涵盖认证、授权、过滤器链、HTTP安全设置等关键配置,结合 Spring Boot 3.x 版本最佳实践
以下是 Spring Security 的核心配置项详解,涵盖认证、授权、过滤器链、HTTP安全设置等关键配置,结合 Spring Boot 3.x 版本最佳实践: 1. 核心注解与配置类 (1) 启动安全配置 // 启动Web安全配置(推荐方式) Configura…...
Spring Boot 3.x 下 Spring Security 的执行流程、核心类和原理详解,结合用户描述的关键点展开说明,并以表格总结
以下是 Spring Boot 3.x 下 Spring Security 的执行流程、核心类和原理详解,结合用户描述的关键点展开说明,并以表格总结: 1. Spring Security 核心原理 Spring Security 通过 Filter 链 实现安全控制,其核心流程如下:…...
[leetcode]判断质数
一.判断质数 1.1 什么是质数 质数(素数)就是只可以被自己和1整除的数叫做素数/质数 1.2判断方法 #include<bits/stdc.h> using namespace std; bool isPrime(int num) { if(num < 1) { return false;//a number less of …...
【结肠息肉AI论文集】Cross-level Feature Aggregation Network for Polyp Segmentation
标注:同样是一期结肠息肉论文写作评鉴 摘要 从结肠镜图像中准确分割息肉在结直肠癌的诊断和治疗中起着关键作用。尽管在息肉分割领域已经取得了一定的成效,但仍存在诸多挑战。息肉通常具有多种大小和形状,并且息肉与其周围区域之间没有明显…...
Redis缓存之预热、击穿、穿透、雪崩
面试切入点 缓存预热 什么是预热? mysql假如新增100条记录,一般默认以mysql为准作为底单数据,如何同步到redis(布隆过滤器),这100条合法数据?? 为什么需要预热? mysql有100条新记录࿰…...
C++字符串复习
C字符串复习 前言 为了保证复习高效,以下不包括很简单的内容,例如cin。 C类型字符、字符串 输入方法 **char c getchar()**输入单个字符 string类型字符串 输入方法 getline(cin, str) 整行输入 常用方法 s.substr(pos, len):截取字…...
centos7安装mysql5.7.44
一、下载 下载地址:https://downloads.mysql.com/archives/community/ 二、安装 1、解压 tar -zxvf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz 2、创建mysql用户组和用户 # 创建mysql用户组 groupadd mysql# 创建用户并添加到mysql用户组中 useradd -r -g m…...
内存分配中的堆(Memory Heap)详解
在计算机科学中,"堆"这个术语确实容易让人混淆,因为它同时用于描述两种完全不同的概念:数据结构中的堆和内存管理中的堆。上次我们讨论了数据结构中的堆,今天我将详细解释内存分配中的堆(Memory Heap&#x…...
【大模型理论篇】关于生成式模型中联合分布概率学习必要性以及GPT是生成式模型的讨论
1. 背景 之前我们在《生成式模型与判别式模型对比(涉及VAE、CRF的数学原理详述)》以及《生成式模型算法原理深入浅出(涉及Stable Diffusion、生成对抗网络、高斯混合模型、隐马尔可夫模型、朴素贝叶斯等算法原理分析及生成式模型解释)》中,我…...
LeetCode738☞单调递增的数字
关联LeetCode题号738 本题特点 贪心,贪心在如果非单调递增,则想要保证数字整体最大,那低数位一定为9(所有数字中最大的) 本题思路 从后向前遍历,如果递增则 什么都不做如果非递增,增非递增位…...
本节课课堂总结
课堂总结: Spark运行架构: 运行架构: Spark 框架的核心是一个计算引擎,整体来说,它采用了标准 master-slave 的结构。 如下图所示,它展示了一个 Spark 执行时的基本结构。图形中的 Driver 表示 master&…...
MyBatis中特殊符号处理总结
前言 MyBatis 是一款流行的Java持久层框架,广泛应用于各种类型的项目中。因为我们在日常代码 MyBatis 动态拼接语句时,会经常使用到 大于(>,>)、小于(<,<)、不等于(<>、!)操作符号。由于此符号包含了尖括号,而 MyBatis 使用…...
【零基础实战】Ubuntu搭建DVWA漏洞靶场全流程详解(附渗透测试示例)
【零基础实战】Ubuntu搭建DVWA漏洞靶场全流程详解(附渗透测试示例) 一、DVWA靶场简介 DVWA(Damn Vulnerable Web Application)是专为网络安全学习者设计的漏洞演练平台,包含SQL注入、XSS、文件包含等10大Web漏洞模块&…...
若依前后端分离版本从mysql切换到postgresql数据库
一、修改依赖: 修改admin模块pom.xml中的依赖,屏蔽或删除mysql依赖,增加postgresql依赖。 <!-- Mysql驱动包 --> <!--<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> &l…...
【补题】Codeforces Round 974 (Div. 3) E. Rendez-vous de Marian et Robin
题意:给个图,两个人分别从点1和点n出发,问最早在哪个点可以相遇,其中某些点有马,骑上去之后可以在接下来剩余的时间内都可以将路程所需时间缩短一半。 关于题目数据见原题,这里说明太累了想偷懒Problem - 2…...
MySQL集群技术
当有数据时添加slave2 #从master节点备份数据 mysqldump -uroot -ptiminglee 1 > timinglee.sql 生产环境中备份时需要锁表,保证备份前后的数据一致 mysql> FLUSH TABLES WITH READ LOCK; 备份后再解锁 mysql> UNLOCK TABLES; mysqldump命令备份的数…...
Java 中的字节码
🔍 什么是 Java 字节码(Bytecode)? 字节码是 Java 源码(.java 文件)被编译后生成的中间代码(.class 文件),它不是机器码,而是一种 面向 JVM 的指令集。 可以…...
json 转 txt 用于 yolo 训练(可适用多边形标注框_python)
json 转 txt 用于 yolo 训练(可适用多边形标注框_python) import json import os import argparse from tqdm import tqdmdef convert_label_json(json_dir, save_dir, classes):json_paths os.listdir(json_dir)classes classes.split(,)for json_pa…...
SQL注入(SQL Injection)
目录 SQL注入(SQL Injection)是什么SQL注入的危害SQL注入的常见方式1. 经典注入(Error-Based Injection)2. 联合查询注入(Union-Based Injection)3. 时间盲注(Time-Based Blind Injection)4. 布尔盲注(Boolean-Based Blind Injection)5. 堆叠注入(Stacked Queries I…...
智慧厨房的秘密:当大模型遇见智能体
智慧厨房的秘密:当大模型遇见智能体 想象一下,一家餐厅里,顾客点了一份特别定制的菜肴。厨师不仅需要知道如何制作这道菜,还得根据当天的食材情况灵活调整配方,甚至考虑到顾客的口味偏好做出微调。这一切背后…...