CentOS 7.x下用Docker与Shell脚本一键部署Redis Cluster集群

发布时间:2026/10/13 1:09:45

CentOS 7.x下用Docker与Shell脚本一键部署Redis Cluster集群 简介一套基于Docker的Redis集群一键部署Shell脚本针对CentOS 7.x环境设计面向运维工程师、后端开发及需要快速搭建Redis集群的测试人员解决手动逐节点初始化配置繁琐、易出错的问题。压缩包共6个文件整体大小22.46MB包含3个Shell脚本自动部署、辅助构建、卸载清理、1个Redis配置模板、1个Docker镜像离线tar包和1份Markdown说明文档脚本与配置文件分离便于按需调整参数。该方案已有1055人学习下载作者标明亲测可用具备一定实践参考价值。使用时仅需按说明传入集群相关参数脚本会自动完成镜像加载、容器创建与集群组建离线镜像包避免了网络拉取失败卸载脚本可一键清理环境。README提供了清晰的参数说明与执行流程适合CentOS 7.x服务器上快速复现和排错也便于后续扩容与故障演练。1. CentOS 7.x 上想用 Docker 一键拉起 Redis 集群这套 Shell 脚本值得先拆一遍如果你和我一样给测试环境或小规模生产环境搭过 Redis 集群大概率记得那些手动敲命令的深夜三台机器、六个节点、主从关系、槽位分配再加一个 docker run 都要带四五个参数。这套脚本就是把 CentOS 7.x 上「Docker Redis Cluster Shell」三者串起来的一次完整落地自动检查环境、生成 redis.conf、用 for 循环启动节点、再调用 redis-cli 自动握手建集群。它解决的不是“能不能跑”而是“怎么稳定地一键跑完”。适合三类人被手动部署折磨过的运维、需要在本地复现集群环境的后端开发以及想借真实脚本入门 shell 编程的容器学习者。下面我按拆项目的方式把脚本的设计逻辑、用法和五个高频坑一次讲透。2. Redis Cluster 与 Docker 部署选型为什么是这三件套2.1 先想清楚哨兵模式和 Redis Cluster脚本为什么选后者Redis 的高可用方案常见有两套。一套是哨兵模式负责监控主节点、自动故障转移但数据分片还是得靠业务方自己处理另一套就是 Redis Cluster从 3.0 开始引入内置 16384 个哈希槽靠槽位把 key 分散到多个主节点上每个主节点可以挂副本。两者最大的区别在于哨兵模式解决的只是“主挂了怎么办”Redis Cluster 解决的是“数据放不下、写不进去怎么办”。这套脚本选择搭 Cluster核心原因就是目标场景需要多写多读。六个节点组成三主三从三个主节点分别承担一部分槽位写入压力被分散三个从节点各自复制主节点数据主节点故障时从节点自动提升。如果你只是单机 Redis 加个哨兵那根本不需要走集群这条路。反过来说一旦决定用 Cluster就要面对端口规划、总线端口、节点握手这些手动操作容易翻车的地方——这正是脚本存在的意义。2.2 为什么用 Docker 而不是直接在宿主机上装 Redis在 CentOS 7.x 上直接yum install redis也能装但版本往往停留在 3.x而 Redis Cluster 在 5.x 之后才算成熟槽位迁移、集群缩扩容都有明显改进。用 Docker 的好处一是版本可控镜像指定 redis:7.0.15 就用 7.0.15不会出现 yum 源升级后 Redis 小版本跳动导致集群行为不一致的问题二是环境隔离redis.conf、数据目录、日志全部挂在宿主机的 /opt/redis-cluster 下想清理环境直接docker rm再删目录不留残留。还有一个实际好处是故障恢复。手动部署的 Redis 进程如果崩了systemd 不一定帮你拉起来而容器可以设置--restart unless-stopped宿主机重启后 Docker 服务一启动容器自动跟着起来集群恢复的成本低很多。对运维来说这种“重启后不用人工干预”的能力比什么都实在。2.3 host 网络还是 bridge 网络脚本为什么选 host这是拆这套脚本时最需要理解的一个选型。Docker 默认的 bridge 网络会把容器隔离在一个内部网段里容器之间通过网桥互通。但如果 Redis Cluster 跨了三台宿主机bridge 模式下要么做端口映射要么配置 docker 的 overlay 网络前者在遇到 Cluster 总线端口时特别容易漏映射后者需要额外的 key-value 存储和网络初始化复杂度直接上一截。对比下来host 网络模式是最省事的选择容器直接复用宿主机网络栈监听端口就是宿主机端口不需要 -p 映射也不需要配置跨主机网络。Redis Cluster 的节点之间除了业务端口 6379/6380还会用“业务端口 10000”的端口做集群总线通信比如 6379 对应 16379。host 模式下这个总线端口天然可达配合防火墙放行端口段即可。对比项bridge 模式host 模式脚本选用端口映射每个容器都要配置 -p无需映射监听即宿主机端口跨主机通信需要 overlay 网络或手动路由天然互通走宿主机网络集群总线端口容易漏映射导致节点握手失败自动可达只需放行防火墙适用场景单机多容器、端口需要隔离跨主机 Redis Cluster 部署脚本放弃 docker-compose 也是出于同样的务实考虑。CentOS 7.x 的默认 yum 源里 docker-compose 版本往往偏老装完可能遇到 Python 依赖问题而一个纯 Shell 脚本零额外依赖只要宿主机有 docker 和 redis-cli 就能跑。对想理解部署逻辑的人来说脚本里的 for 循环和参数处理比 compose 文件更能看清每一步在做什么。3. 一键脚本的核心逻辑从环境检查到集群锁定3.1 脚本的整体结构与配置变量拆这套脚本先从头部配置入手。脚本把所有需要按机器实际情况改的参数集中在开头一段而不是散落在函数里。我用注释把关键参数标一下#!/bin/bash # redis-cluster-deploy.sh # 适用环境CentOS 7.x / Docker / 三台宿主机 # 用法bash redis-cluster-deploy.sh set -euo pipefail # 按你的实际环境修改 MASTER_HOSTS(192.168.1.10 192.168.1.11 192.168.1.12) # 宿主机 IP 列表 NODE_PER_HOST2 # 每台宿主机跑几个 redis 节点 START_PORT6379 # 起始 redis 端口每台机器递增 REPLICAS1 # 每个主节点挂几个从节点 REDIS_IMAGEredis:7.0.15 # 镜像版本建议固定 tag REDIS_BASE_DIR/opt/redis-cluster # 配置与数据挂载根目录 CLUSTER_NETredis-cluster-net # 自定义 docker 网络名这段配置看着简单但每个变量都直接影响集群拓扑。MASTER_HOSTS这个数组决定了集群分布在哪些机器上脚本后续的 for 循环就是遍历它NODE_PER_HOST为 2 时三台机器共产生六个节点正好组成三主三从START_PORT是从 6379 开始递增每台机器上的两个节点分别用 6379 和 6380。REPLICAS1表示每个主节点挂一个从节点最终三个主、三个从。REDIS_IMAGE必须固定具体版本号不要用redis:latest否则哪天镜像更新了集群里的节点版本不一致槽位迁移时可能出现意想不到的行为。set -euo pipefail这一行是脚本稳定性的关键-e让脚本在任意命令失败时立即退出-u防止未定义变量导致静默错误pipefail让管道中第一个失败的命令被视为整个管道失败。对部署脚本来说尽早失败比带着错误配置继续跑完更友好。3.2 环境检查与公共配置生成脚本进入正题前会做一轮环境检查这一步往往被手动部署的人忽略但恰恰是集群建不起来的常见原因。逻辑上分三块检查 docker 命令是否存在、检查 redis-cli 是否可用、创建统一的配置目录。# 1. 检查基础命令 command -v docker /dev/null 21 || { echo docker 未安装或不在 PATH 中; exit 1; } command -v redis-cli /dev/null 21 || { echo redis-cli 未安装请先安装 redis-tools; exit 1; } # 2. 检查 docker 服务是否在运行 if ! docker info /dev/null 21; then echo docker 服务未运行尝试启动... systemctl start docker systemctl enable docker fi # 3. 创建统一挂载目录避免权限混乱 mkdir -p ${REDIS_BASE_DIR}/{data,conf}这里用command -v而不是which是因为which在部分 CentOS 7.x 最小安装里可能不存在而command -v是 Shell 内建命令更稳妥。docker info判断服务是否可用比systemctl status docker更直接因为即使服务起来了Docker 守护进程也可能因为权限或内核问题无法响应。目录规划上data和conf分开挂在宿主机是为了后续备份和排查方便。如果所有文件堆在一个目录里时间长了你自己都分不清哪个文件属于哪个容器。3.3 节点启动与自动集群握手节点启动是整个脚本的核心它用双层 for 循环遍历「宿主机 IP × 节点序号」对每个组合生成独立端口和独立 redis.conf然后启动容器。这里直接体现 shell 脚本 for 循环在批量操作上的优势# 为每台机器上的每个节点生成配置并启动容器 INDEX0 for HOST_IP in ${MASTER_HOSTS[]}; do for SLOT in $(seq 1 ${NODE_PER_HOST}); do PORT$((START_PORT SLOT - 1)) # 生成独立 redis.conf cat ${REDIS_BASE_DIR}/conf/redis-${PORT}.conf EOF port ${PORT} cluster-enabled yes cluster-config-file nodes-${PORT}.conf cluster-node-timeout 5000 appendonly yes appendfsync everysec daemonize no protected-mode no bind 0.0.0.0 dir /data logfile EOF # 启动容器host 网络 统一挂载 docker run -d --name redis-${HOST_IP}-${PORT} \ --network host \ --restart unless-stopped \ -v ${REDIS_BASE_DIR}/conf/redis-${PORT}.conf:/etc/redis/redis.conf:ro \ -v ${REDIS_BASE_DIR}/data/redis-${PORT}:/data \ ${REDIS_IMAGE} \ redis-server /etc/redis/redis.conf # 组装节点地址列表 NODE_LIST${NODE_LIST} ${HOST_IP}:${PORT} done done这段有几个参数必须说清楚。cluster-enabled yes是节点进入集群模式的开关不开启的话 redis-cli --cluster create 会直接拒绝这个节点cluster-config-file指定节点保存集群状态的文件名每个节点必须独立否则多个容器共享同一个 nodes.conf 会互相覆盖daemonize no是因为容器里 redis 必须以前台进程运行否则 Docker 会认为容器没事干就把它退出bind 0.0.0.0配合protected-mode no是跨主机访问的前提如果 bind 只写 127.0.0.1其他机器上的节点握手永远不可能成功。--network host这个参数前面已经解释过这里补充一点host 模式下端口是直接占用的脚本里PORT$((START_PORT SLOT - 1))的计算必须保证同一台机器上的端口不冲突。比如 NODE_PER_HOST 为 2 时第一台机器用 6379 和 6380第二台、第三台同样复用这两个端口——因为 host 网络下端口是绑在各自宿主机上的不同机器之间可以安全复用。容器启动完后脚本还不能马上建集群。Redis 节点从启动到进入可握手状态需要几秒钟直接执行 cluster create 大概率遇到连接拒绝。脚本这里会做一个轮询等待循环执行redis-cli -p PORT ping直到所有节点都返回 PONG# 等待所有节点进入就绪状态 for NODE in ${NODE_LIST}; do IP_PORT(${NODE//:/ }) IP${IP_PORT[0]} PORT${IP_PORT[1]} for TRY in {1..30}; do if redis-cli -h ${IP} -p ${PORT} ping /dev/null 21; then break fi sleep 2 if [ ${TRY} -eq 30 ]; then echo 节点 ${NODE} 30 秒内未就绪请检查容器日志 exit 1 fi done done等待逻辑里的 30 次重试、每次间隔 2 秒是最多 60 秒的容忍窗口。如果 60 秒后节点还 ping 不通脚本直接退出同时提示查看容器日志避免后续 cluster create 卡在令人费解的 waiting 状态。这里的IP_PORT(${NODE//:/ })是 Shell 字符串替换加上数组拆分的写法把 192.168.1.10:6379 拆成 IP 和端口两个独立变量。最后一步是组建集群。脚本优先使用redis-cli --cluster create因为它会帮我们处理节点握手、槽位分配和副本绑定比手动CLUSTER MEET安全得多# 组建集群自动分配槽位并绑定副本 echo 开始创建集群... redis-cli --cluster create ${NODE_LIST} \ --cluster-replicas ${REPLICAS} \ --cluster-yes # 输出集群状态 redis-cli -h ${MASTER_HOSTS[0]} -p ${START_PORT} cluster info | head -10--cluster-replicas 1的意思是每个主节点自动挂一个从节点脚本会按照节点列表顺序尽量把主从分布在不同宿主机上避免同一台机器既是主又是它的副本。--cluster-yes跳过交互确认否则 cluster create 会停下来问你 Can I set the above configuration?一键部署就成了半自动。集群创建后cluster info的前几行会显示cluster_state:ok和槽位分配情况一眼就能判断建集群是否成功。4. 部署实操CentOS 7.x 上把几个变量换成你的 IP 就能跑4.1 部署前准备镜像、防火墙、内核参数一个都别漏拿到脚本别急着跑先把宿主机环境过一遍。CentOS 7.x 上我一般会先确认 Docker 版本能正常启动然后处理三个高概率拦路的地方防火墙、SELinux、内核内存参数。第一步安装并启动 Docker如果已经装好可以跳过# 安装 DockerCentOS 7.x 常见做法 yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum install -y docker-ce systemctl start docker systemctl enable docker # 拉取 Redis 镜像固定版本号 docker pull redis:7.0.15systemctl enable docker这步很容易被忽略。不加的话宿主机重启后 Docker 服务不会自动启动容器全部处于 exited 状态集群直接瘫痪。镜像下载这一步单独执行还有个好处部署时脚本不会因为网络问题卡在拉镜像阶段节省排错时间。然后是防火墙。host 网络模式下Redis 的业务端口和 Cluster 总线端口都直接暴露在宿主机网络上firewalld 如果不放行节点之间握手会失败。常见做法是放行固定端口段而不是直接关防火墙# 放行 Redis 业务端口和 cluster bus 端口6379-6380 和 16379-16380 firewall-cmd --permanent --add-port6379-6380/tcp firewall-cmd --permanent --add-port16379-16380/tcp firewall-cmd --reload # 确认放行结果 firewall-cmd --list-ports这里特别强调 Cluster 总线端口业务端口 10000。很多人只放行了 6379/6380结果集群创建时节点之间能连上业务端口但总线端口不通日志里反复出现 Waiting for the cluster to join这个问题非常难排查因为表面看端口没毛病。至于 SELinux如果之前没改过策略最简单的做法是保持默认并确认 Docker 工作正常如果遇到了诡异的权限问题可以检查/var/log/audit/audit.log再决定。内核参数vm.overcommit_memory是 Redis 在 fork 子进程做持久化时的内存分配策略。默认值 0 在内存压力稍大时可能导致 fork 失败建议写入 sysctl 配置# 设置内存分配策略并使其持久化 echo vm.overcommit_memory 1 /etc/sysctl.conf sysctl -p4.2 执行脚本并理解每一段输出环境准备完就正式执行。脚本输出的每一段都要能看懂这样失败时能快速定位在哪一步# 给脚本加执行权限并运行 chmod x redis-cluster-deploy.sh bash redis-cluster-deploy.sh正常执行时会依次看到环境检查通过、六个容器逐个启动每启动一个输出一行的容器 ID、等待节点就绪期间没有报错然后看到 Performing hash slots allocation on 6 nodes...这样的创建日志最后 cluster info 输出cluster_state:ok。看到cluster_state:ok不代表全流程完事了我一般会等几秒再手动执行一次redis-cli --cluster check这能确认槽位分配和副本关系都符合预期。脚本把cluster info的输出打印出来就是这个目的——把验证步骤内置到部署里而不是部署完再手工敲验证命令。特别要留意的输出是cluster_state:fail这说明槽位没分配完整或者主节点之间失去联络需要结合后面的避坑章节逐条排查。4.3 脚本重复执行的幂等设计一键脚本最怕跑第二次的时候把已有集群搞乱。常见做法是在脚本里加三重幂等保护文件锁防止并发执行、容器存在性检查避免重复创建、集群状态检查避免对已存在的集群二次初始化。# 第一重文件锁防止脚本并发执行 exec 9/tmp/redis-cluster-deploy.lock if ! flock -n 9; then echo 另一个部署脚本正在运行请稍后再试 exit 1 fi # 第二重检查是否已有 redis 容器存在 if docker ps -a --format {{.Names}} | grep -q ^redis-; then echo 检测到已有 redis 容器跳过容器创建步骤 SKIP_CREATE1 fi # 第三重检查是否已是集群状态 if redis-cli -h ${MASTER_HOSTS[0]} -p ${START_PORT} cluster info 2/dev/null | grep -q cluster_state:ok; then echo 集群已存在跳过 cluster create 步骤 SKIP_CLUSTER_CREATE1 fiflock -n的意思是拿锁失败就立即退出而不是等待这样能防止两个运维同事同时在两台终端上执行脚本。容器存在性检查通过docker ps -a检索名字前缀有容器就跳过创建避免重名冲突导致 Docker 报错。集群状态检查用实际命令验证而不是简单看容器是否运行——容器在跑但集群没建成功的情况并不少见这时候应该补救而不是傻等。有了这三重保护脚本可以安全地重复执行。以前手动部署时最怕“跑一半失败了重跑要先把旧容器删干净”现在脚本自己判断哪些步骤要跳过、哪些要补做容错性完全不一样。5. 避坑排查五条拿掉之后集群才真正稳下来5.1 现象一cluster create 一直停在 waiting for the cluster to join这是我见过最多的问题。六个容器都起来了redis-cli ping 也都通但redis-cli --cluster create卡在 Waiting for the cluster to join超过 30 秒最后超时失败。根本原因是 Redis Cluster 节点之间除了业务端口还要通过总线端口业务端口 10000交换 PING/PONG 消息。CentOS 7.x 的 firewalld 默认只放行了 6379 端口16379/16380 被静默拦截节点互相收不到总线消息自然永远等不到集群握手成功。解决方法是先把防火墙放行端口段firewall-cmd --permanent --add-port6379-6380/tcp --add-port16379-16380/tcp然后 reload。如果用的是云主机安全组还要去控制台放行对应端口范围。放行后再跑一次 cluster create通常几秒内就能完成槽位分配。5.2 现象二宿主机重启后容器全起来了但集群节点状态变成 fail现象是重启后docker ps看到所有容器都在运行但cluster info显示cluster_state:failcluster nodes里每个节点都标记为 fail。原因一般有两个。一是容器没有设置--restart unless-stopped重启后部分容器没自动拉起二是 redis 容器虽然起来了但持久化数据目录里保留了旧的 nodes.conf节点重启后拿着旧集群状态去和自己已经变化的总线端口通信。第二个原因更容易被忽略。解决方法是先保证容器带重启策略脚本里的--restart unless-stopped不能删这是宿主机重启后容器能自动归位的底线。然后清理持久化数据里的旧节点信息把cluster-config-file指向的nodes-*.conf文件删掉再重启容器让节点以干净状态重新握手。5.3 现象三docker ps 全正常但 redis-cli -h 宿主机IP -p 6379 连不上部署完在宿主机上执行redis-cli -h 127.0.0.1 -p 6379 ping能通换成其他机器的 IP 就连不上或者业务代码里通过容器 IP 访问报连接超时。原因是 redis.conf 里bind配置成了 127.0.0.1或者protected-mode没关闭。bind 决定了 Redis 监听在哪个网络接口上只写本地回环地址的话其他机器的请求根本到不了 Redis 进程protected-mode 开启时如果 Redis 没有密码且 bind 的不是本机地址也会拒绝连接。解决方法是把 redis.conf 中的bind改为0.0.0.0同时设置protected-mode no。脚本里生成的配置默认就是这两项如果你是自己手写 redis.conf特别容易漏掉。改完配置后要重启对应容器而不是只 reload 配置。5.4 现象四docker 命令显示系统找不到 docker 服务在 CentOS 7.x 最小化安装环境上执行systemctl start docker提示Unit docker.service not found。原因是没安装 Docker 或者装的是 docker-io 老版本。CentOS 7.x 的默认源里不带 docker-ce需要先配置 Docker 官方或阿里云镜像源再安装 docker-ce 和配套组件。这个坑多发于刚拿到一台新采购的服务器、以为系统自带 Docker 的情况。解决方法在 4.1 节已经覆盖使用yum-config-manager添加 docker-ce 的 yum 源然后yum install -y docker-ce。装完记得systemctl enable docker否则下次重启又要手动拉起。5.5 现象五脚本跑第二遍节点全部变成孤立的单点第一遍部署成功后来因为环境调整把脚本再跑一遍结果所有容器都是新建的集群状态反而没了节点各自为政。原因是脚本第二遍跳过了容器创建和 cluster create但清理逻辑没做完整或者持久化目录里残留了一堆 old nodes.conf新旧节点文件互相干扰集群状态无法正确恢复。解决方法是脚本里补充一个显式的清理函数用环境变量控制执行——比如CLEAN1 bash redis-cluster-deploy.sh时先删除所有 redis- 前缀容器和整个/opt/redis-cluster配置目录再从零开始部署。我在实际工作中踩过一次后就把清理逻辑单独拆成一个函数绝不让“重跑脚本”这个动作模糊不清。重跑前先想清楚是补数据还是从零开始两者处理方式完全不同。6. 验证是最后一公里cluster 状态、扩容与备份习惯6.1 用 redis-cli 做三层健康检查集群建完不是终点我习惯做三层验证。第一层看cluster info的cluster_state是否为 ok同时确认cluster_slots_assigned等于 16384第二层看cluster nodes的每个节点角色和连接状态确认三个主节点、三个从节点且没有节点被标记为 fail第三层是实际写入和读取验证写入一个 key 到集群看它是否被均匀分不到不同节点。# 第三层验证简单写入与读取 redis-cli -h 192.168.1.10 -p 6379 -c set deploy-check:001 hello redis-cli -h 192.168.1.11 -p 6379 -c get deploy-check:001-c参数是集群模式的关键它让 redis-cli 自动跟随槽位重定向。如果没有加-c访问不在当前节点负责的槽位时会报MOVED错误新手经常被这个误导以为集群有问题。6.2 扩容方向先 add-node 再 reshard脚本解决的是“从零建集群”集群建好后的扩容是另一个话题。真要加一台机器时主流做法是先启动新节点容器然后用redis-cli --cluster add-node把它加入集群最后reshard迁移槽位。这个方向比改脚本重跑更安全因为不会触动已有节点的数据。如果你希望脚本也支持扩容可以在现有框架上扩展把新机器 IP 追加进MASTER_HOSTS数组然后单独写一个 add-node 的步骤注意这一步必须手动确认槽位迁移策略不要全自动一把梭。6.3 备份习惯与最终建议Redis Cluster 的持久化文件不能直接拍脑袋复制因为 RDB 和 AOF 文件可能与集群状态不一致。我一般会在每个宿主机上对/opt/redis-cluster/data目录做定时快照且备份前先CLUSTER SETSLOT进入维护模式再执行BGSAVE保证数据一致。这个习惯救过我一次测试环境集群数据全丢了靠快照恢复后才发现备份脚本里少了维护模式这一步。从那以后我每次用这类一键部署脚本都会强制自己先跑一遍环境检查确认防火墙端口段、SELinux 状态和内核 overcommit 参数再执行脚本重跑前也会刻意想清楚会不会伤害已有数据。这套脚本最大的价值不是省去几分钟的手动操作而是把容易犯错的部署路径压缩成一条稳定可重放的路希望你也能从中拿走自己用得上的部分。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/13 1:09:45

AI芯片软硬件协同优化实战:寄存器可配置化设计方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:45

C#虚属性与抽象属性重写详解:以Label控件为例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:45

NFine框架登录流程源码深度解析:从MVC分层到权限体系实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 2:14:48

LeetCode 19:删除链表倒数第 N 个节点,双指针与虚拟头节点详解

LeetBook 上这道删除链表倒数第 N 个结点的题,我前前后后教过不少人和自己重写过好几遍,看着简单,其实特别容易在边界条件上翻车。写这篇东西的目的很纯粹:把这道题的前因后果、两种主流解法、还有我踩过的坑全部摊开来聊一遍&…

2026/10/13 2:14:48

Spring Boot Starter实现Jackson @JsonView分页字段过滤

1. 为什么我非要做一个 View Extension Starter做后端接口的人基本都经历过这么个事:同一个用户对象,列表接口只想给 App 返回 id、name、avatar,管理后台接口却要把 email、手机号、角色全带上。最粗暴的做法是写两个 DTO、两套 Service、两…

2026/10/13 2:14:48

Win11下西门子工业以太网卡导致无法关机?排查与解决指南

做自动化改造的同行应该都有体会,设备能正常跑不等于系统健康,真正折磨人的往往是那些不影响生产、但能让你反复纠结的系统级小毛病。前两天我就遇到一台装有西门子工业以太网通讯网卡的工控机,系统是 Windows 11 专业版,生产用的…

2026/10/13 2:14:48

Oracle rownum与rowid原理、陷阱及分页优化实战

1. 为什么刚学Oracle的人总在rownum上栽跟头&#xff1f;我带过不少刚从MySQL或PostgreSQL转过来的开发者&#xff0c;他们第一次写分页SQL时&#xff0c;几乎无一例外地写出这样的语句&#xff1a;SELECT * FROM employees WHERE rownum < 10 ORDER BY salary DESC;然后一脸…

2026/10/13 2:14:48

Socket网络编程从入门到实战:TCP/UDP原理、粘包半包与高并发调优

做网络编程&#xff0c;第一关一定是Socket。不管你是写Web服务、IM聊天工具&#xff0c;还是搞设备接入、数据采集&#xff0c;Socket就是那层绕不开的底子。我最早碰Socket是在调一个局域网传输工具的收发速度问题&#xff0c;那时对着报错一头雾水&#xff0c;后来把协议栈、…

2026/10/13 2:09:48

一文讲透Markdown代码语法:行内代码、代码块与渲染生态

1. 行内代码与代码块&#xff1a;先搞清楚你写的到底是哪种"代码"很多人以为 Markdown 的代码语法就是"打三个反引号"&#xff0c;结果真到写技术文档、配置说明、公众号排版的时候&#xff0c;一粘贴就露馅&#xff1a;反引号失效、高亮乱七八糟、代码块里…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”&#xff0c;而是它给出一段看起来合理的说明&#xff0c;程序却从中猜错优先级。通俗做法是&#xff1a;要求模型只交 JSON&#xff08;JavaScript Object Notation&#xff0c;轻量数据格式&#xff09;&#xff0c;再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里&#xff0c;有A同学跑来问我&#xff1a;选什么毕设题目最稳妥&#xff0c;既能让评审老师觉得工作量够&#xff0c;又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友&#xff0c;在看完一堆“Hello World”和基础组件之后&#xff0c;大概率都会撞上同一堵墙&#xff1a;StatefulWidget 里那堆 initState、build、dispose 方法&#xff0c;到底什么时候被调用&#xff1f;为什么顺序是那样&#xff1f;在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介&#xff1a;这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师&#xff0c;聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案&#xff0c;解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件&#xff0c;约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型&#xff0c;最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支&#xff0c;让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图&#xff0c;十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑