云逸工作室 - 默认分类
type: channel
link: https://blog.hfyunyi.cn/index.php/category/default/
description: 只是一个默认分类
items: 告别运营商强制重拨导致的批量断网：RouterOS PPPoE 批量预重拨脚本实战
items: 📝 从零开始编写 TextFSM 模板：网络配置解析实战
items: 多网出口非抢占式vrrp 配置方案
items: ESXi 显卡直通完全指南：从核显屏蔽到性能调优
items: 使用 MikroTik RouterOS 搭建主备隧道（WireGuard + L2TP）并通过 VXLAN 实现二层桥接
items: MySQL 双主热备 + Keepalived 全自动切换方案
items: Win10 多用户远程登录指南：RDPWrap 组策略
items: Docker 在线安装
items: mikrotik 端口映射之原进原出

告别运营商强制重拨导致的批量断网：RouterOS PPPoE 批量预重拨脚本实战
type: item
date: 2026-06-16T10:58:57+08:00
description: 背景与痛点许多网络运维人员都遇到过这样的场景：使用 RouterOS 管理多条 PPPoE 宽带线路（例如多条 ADSL、光纤宽带聚合），运营商每隔固定周期（常见为 48 小时、72 小时或 4 天）会强制断开 PPPoE 会话并触发重拨。当几十甚至上百条 PPPoE 连接同时被运营商踢下线时，所有线路会一起进入重拨流程，导致整个网络在接下来 1~2 分钟内完全瘫痪——业务中断、游戏掉线、视频卡顿，用户投诉不断。更让人困惑的是：如果手动去重拨某一条线路（先禁用再启用），往往几秒钟就能重新获得 IP，几乎感觉不到断流。为什么运营商强制重拨就会导致长达 2 分钟的“集体罢工”？原因很简单：运营商侧的重拨通常会伴随着后台认证服务器的瞬时压力、或客户端同时发起大量并发请求造成的拥塞。而手动单条重拨则避开了“洪水式”并发，认证速度快，断线时间极短。解决思路既然运营商定期踢线无法改变，我们可以主动抢占先机：在运营商强制重拨之前，我们自己逐个、有序地重拨每一条 PPPoE 连接。只要重拨间隔足够分散（例如每隔 30 秒重拨一条），每条线路只会有几秒钟的短暂中断，且不同线路的中断时间错开，整体网络几乎不受影响。这就像火车站的检票口：如果几千人同时涌向一个入口，必然拥堵；如果安排多个入口并分批放行，队伍就顺畅得多。下面给出的 RouterOS 脚本，可以自动检查所有 PPPoE 客户端的运行时长，一旦超过设定阈值（比如 4 天），就逐个执行“禁用→启用”重拨，每次重拨后等待 30 秒再操作下一条。脚本详解# ========================================================= # PPPoE 批量重拨脚本 # 功能：检查所有 PPPoE 连接，运行时间超过 4 天的自动重拨 # 重拨间隔：每个连接重拨后等待 30 秒 # ========================================================= :local maxDays 4 :local delaySeconds 30 :local logPrefix "【PPPoE批量重拨】" :local thresholdSec ($maxDays * 86400) :local renewedCount 0 :local totalChecked 0 :local ifaceList [/interface pppoe-client find] :log info "$logPrefix 开始检查所有 PPPoE 连接（运行 > $maxDays 天则重拨）" :foreach iface in=$ifaceList do={ :local ifName [/interface pppoe-client get $iface name] :set totalChecked ($totalChecked + 1) :local uptimeStr ([/interface pppoe-client monitor $ifName once as-value]->"uptime") :if ([:len $uptimeStr] = 0) do={ :log info "$logPrefix $ifName 当前未连接，跳过" continue } :local uptimeSec [:totime $uptimeStr] :if ($uptimeSec > $thresholdSec) do={ :log info "$logPrefix $ifName 已运行 $uptimeStr（超过 $maxDays 天），正在重拨..." # 执行重拨 /interface pppoe-client disable [find name=$ifName] /interface pppoe-client enable [find name=$ifName] :set renewedCount ($renewedCount + 1) :if ($renewedCount < [:len $ifaceList]) do={ :delay $delaySeconds } } else={ :log info "$logPrefix $ifName 已运行 $uptimeStr（未超过 $maxDays 天），无需重拨" } } :log info "$logPrefix 执行完成。共检查 $totalChecked 个连接，实际重拨 $renewedCount 个。"关键参数说明参数默认值含义maxDays4连接运行超过此天数即触发重拨（建议小于运营商强制周期，比如运营商 5 天踢线就设为 4）delaySeconds30每重拨完一…

📝 从零开始编写 TextFSM 模板：网络配置解析实战
type: item
date: 2026-06-02T14:23:43+08:00
description: 让非结构化文本变成整齐的表格数据，TextFSM 是网络工程师的必备利器。一、什么是 TextFSM？TextFSM 是 Google 开源的一个 Python 库，专门用于将半结构化的文本（如路由器、交换机、防火墙的 CLI 输出）解析成表格形式的数据（列表嵌套列表或字典）。它通过一个模板文件来定义要提取的字段和匹配规则，非常适合网络自动化场景——例如批量采集设备信息、生成巡检报告、对接 Ansible 或 Nornir。二、模板的核心语法一个 TextFSM 模板由三个部分组成：Value 定义 – 声明要捕获的变量及其正则表达式。状态机 – 定义如何逐行扫描文本，通常包含 Start 状态和其他自定义状态。动作 – 匹配到某行后执行的动作：Record（保存当前记录）、Continue（继续匹配）、Clear（清空记录）、Error（报错）等。2.1 Value 语句Value 字段名 (正则表达式)字段名：通常大写，如 NAME、IP_ADDR。正则表达式：用括号括起来，支持 Python 正则语法。可选修饰符：Required（必须存在）、Filldown（下行未捕获时沿用上行值）、List（多个匹配值保存为列表）。示例：Value Required ID (\d+) Value NAME (\S+) Value STATUS (up|down) Value MAC ([0-9a-f]{2}(:[0-9a-f]{2}){5})2.2 状态与匹配行Start ^期望的正则表达式 -> 动作 [下一个状态]状态名：通常大写，Start 是起始状态。行匹配符：^ 行首，$$ 行尾（注意：TextFSM 中用 $$ 表示行尾，因为单个 $ 有特殊含义？实际是单 $ 即可，但历史版本有些差异，建议用 $。为保险可写 $$ 或 $，看引擎版本）。变量引用：${字段名}，用于在正则中引用已捕获的值。常见动作：动作含义-> Record保存当前所有 Value 值作为一条记录，然后清空（除非指定 Filldown）-> Continue继续匹配当前行的其他规则-> Clear清空当前已捕获的 Value，不保存-> Error模板解析错误，停止处理-> 状态名跳转到另一个状态三、编写第一个模板场景：解析 show interface brief 输出设备输出（Cisco 风格）：Interface IP-Address OK? Method Status Protocol GigabitEthernet0/0 192.168.1.1 YES manual up up GigabitEthernet0/1 unassigned YES unset administratively down down Loopback0 10.0.0.1 YES manual up up目标：提取接口名、IP 地址、状态、协议。模板 interface_brief.textfsm：Value INTF (\S+) Value IP (\S+) Value STATUS (up|down|administratively down) Value PROTO (up|down) Start # 跳过表头行 ^Interface ^\s*$$ # 匹配数据行 ^${INTF}\s+${IP}\s+\S+\s+\S+\s+${STATUS}\s+${PROTO}\s*$$ -> Record ^. -> ErrorPython 调用：import textfsm from io import StringIO with open('interface_brief.textfsm') as f: fsm = textfsm.TextFSM(f) output = """ Interface IP-Address OK? Method Status Protocol GigabitEthernet0/0 192.168.1.1 YES manual up up GigabitEthernet0/1 unassigned YES unset administratively down down Loopback0 10.0.0.1 YES manual up up """ result = fsm.ParseText(output) headers = fsm.header for row in result: print(dict(zip(headers, row)))输出：{'INTF': 'GigabitEthernet0/0', 'IP': '192.168.1.1', 'STATUS': 'up', 'PROTO': 'up'} {'INTF': 'Gig…

多网出口非抢占式vrrp 配置方案
type: item
date: 2026-05-31T20:49:00+08:00
description: 设计思路两台 MikroTik 路由器，各自有 6 条 PPPoE 线路（pppoe-out1~6）。要求：只有当本端 6 条 PPPoE 全部断开时，本机才放弃 VRRP Master 角色；当线路恢复后，本机恢复优先级，但 不自动抢回 Master（避免网络波动）。实现方法：VRRP 设置为 preemption-mode=no（非抢占）。通过脚本定期检测所有 6 条 PPPoE 接口的 running 状态。如果全部断开 → 将本机 VRRP priority 设为 0（立即放弃 Master）。如果至少一条恢复 → 将本机 VRRP priority 恢复为正常值（如 150 或 140），但不抢回 Master。脚本配置ROS1（正常优先级 150）:local pppoeList {"pppoe-out1";"pppoe-out2";"pppoe-out3";"pppoe-out4";"pppoe-out5";"pppoe-out6"} :local allDown true :foreach i in=$pppoeList do={ :if ([/interface get $i running]) do={ :set allDown false } } :if ($allDown) do={ /interface vrrp set [find name="vrrp1"] priority=0 } else={ :delay 10 /interface vrrp set [find name="vrrp1"] priority=150 }ROS2（正常优先级 140）:local pppoeList {"pppoe-out1";"pppoe-out2";"pppoe-out3";"pppoe-out4";"pppoe-out5";"pppoe-out6"} :local allDown true :foreach i in=$pppoeList do={ :if ([/interface get $i running]) do={ :set allDown false } } :if ($allDown) do={ /interface vrrp set [find name="vrrp1"] priority=0 } else={ :delay 10 /interface vrrp set [find name="vrrp1"] priority=140 } VRRP 基础配置ROS1（正常优先级 150）/interface vrrp add name=vrrp1 vrid=1 interface=bridge priority=150 preemption-mode=noROS2（正常优先级 140）/interface vrrp add name=vrrp1 vrid=1 interface=bridge priority=140 preemption-mode=no 最终效果：任意一台检测到自己的 6 条 PPPoE 全断 → priority=0 → 立即让出 Master。恢复后 priority 回到正常值，但因 preemption-mode=no 不会抢回。

ESXi 显卡直通完全指南：从核显屏蔽到性能调优
type: item
date: 2026-05-25T21:41:00+08:00
description: 在虚拟化环境中，将物理显卡直接分配给虚拟机（俗称“直通”）可以显著提升图形处理性能，适用于游戏串流、3D 渲染或机器学习等场景。本文将手把手教你如何在 ESXi 上完整配置显卡直通，并解决因屏蔽核显导致的管理界面丢失问题。⚠️ 适用环境：ESXi 6.7 / 7.0 / 8.0 ⚠️ 硬件要求：CPU 支持 VT-d / AMD-Vi，主板 BIOS 支持 Above 4G Decoding 及集显优先输出📋 准备工作确认你的独立显卡（NVIDIA/AMD）已正确安装在服务器上确保 ESXi 主机有 SSH 访问权限建议提前备份现有虚拟机配置1️⃣ BIOS 设置：强制优先使用集显在直通独立显卡前，必须让 BIOS 将集成显卡设为系统主显示输出。这样才能释放 PCI 通道的独显用于直通。操作步骤： 进入主板 BIOS → 找到 Primary Graphics Adapter 或 Init Display First → 选择 IGD（集成显卡）或 Internal VGA。 下图为典型 BIOS 设置界面示例：（不同主板界面略有差异，请以实际选项为准）保存设置并重启 ESXi 主机。2️⃣ Web 界面开启 PCI 设备直通登录 ESXi 主机 Web 管理界面，执行设备直通切换：导航至 管理 → 硬件 → PCI 设备找到你的独立显卡（通常包含 VGA 控制器 和 音频设备 两个功能）勾选这两个设备，点击 切换直通系统会要求重新启动主机使其生效💡 记得同时直通显卡上的 HDMI 音频设备，否则虚拟机可能无声音输出。3️⃣ 屏蔽 ESXi 对核显的占用（命令行关键步骤）默认情况下，ESXi 内核会占用核显作为控制台输出，导致核显无法直通给其他虚拟机。通过以下命令禁用 vga 模块，完全释放核显：# 屏蔽核显（禁止 ESXi 调用） esxcli system settings kernel set -s vga -v FALSE若未来需要恢复 ESXi 对核显的调用（例如故障排查），执行：# 恢复 ESXi 显卡调用 esxcli system settings kernel set -s vga -v TRUE4️⃣ 修改 passthru.map 添加设备 IDESXi 需要识别显卡的 PCI 设备 ID 才能正确直通。通过 SSH 连接主机，先获取显卡 ID：lspci -v在输出中找到你的显卡（例如 NVIDIA/AMD），记录下类似 XXXX:XX:XX.X 格式的 设备 ID 和括号中的 供应商 ID。![lspci 获取显卡设备 ID]][3]接着使用 vi 编辑配置文件：vi /etc/vmware/passthru.map根据显卡类型在文件末尾添加一行（示例为 NVIDIA 显卡）：# NVIDIA 显卡直通配置 10de XXXXX d3d0 false10de：NVIDIA 供应商 IDXXXXX：你的设备 IDd3d0：直通类型参数（常见为 d3d0 或 link）false：禁用 ACS 检查具体值请参考下图中的修改示例：保存并退出（:wq）。5️⃣ 修改 esx.conf 强制设置设备拥有者（高级操作）此步骤可确保 PCI 设备被正确标记为直通设备。使用 vi 编辑：vi /etc/vmware/esx.conf在文件末尾添加以下内容（将 0000:02:00.0 替换为你的显卡 PCI 设备 ID）：/device/0000:02:00.0/owner = "passthru"🔧 设备 ID 格式：通过 lspci 获得的完整 PCI 地址，例如 02:00.0 应写成 0000:02:00.0。如果你的显卡包含音频功能，需要为两个设备分别添加此条目。保存后重启主机：reboot6️⃣ 配置虚拟机高级参数（解决显卡识别与内存寻址）编辑虚拟机 .vmx 文件或 Web 界面添加参数在 Web 管理界面： 编辑目标虚拟机 → 虚拟机选项 → 高级 → 配置参数 → 添加参数。需手动添加以下三个关键参数：参数名值作用hypervisor.cpuid.v0FALSE隐藏虚拟机监控程序签名，解决 NVIDIA 消费级显卡的 Code 43 错误pciPassthru.use64bitMMIOTRUE启用 64 位 MMIO 内存映射，解决大显存显卡无法识别问题pciPassthru.64bitMMIOSizeGB64分配 MMIO 地址空间大小（必须为 2 的幂，如 64GB）下图展示了 Web 界面的添加示例：🧠 提示：对于显存超过 8GB 的显卡（如 RTX 3080 / RX 6800），建议将 64bitMMIOSizeGB 设为 64 或更高。🖥️ 管理替代方案：当 Web 管理界面无法显示时由…

使用 MikroTik RouterOS 搭建主备隧道（WireGuard + L2TP）并通过 VXLAN 实现二层桥接
type: item
date: 2026-05-21T22:51:00+08:00
description: 引言在企业网络或数据中心场景中，经常需要将两个不同地理位置的三层网络通过二层打通，使两端的设备像在同一个交换机下一样工作。同时，为了保障链路的可靠性，还需要建立主备隧道，当主隧道故障时业务能自动切换到备用隧道。本文将详细介绍如何在两台 MikroTik RouterOS 路由器上：建立 WireGuard 隧道作为主链路建立 L2TP/IPsec 隧道作为备份链路在两个隧道之上运行 VXLAN，并将两端的 ether3 物理接口桥接起来通过 Netwatch 实现隧道的主备自动切换拓扑规划假设两台路由器分别称为 Router-1（站点A） 和 Router-2（站点B）。它们各有至少一个公网接口（ether1）用于建立隧道，以及一个需要二层互通的本地接口 ether3。IP 地址规划角色Router-1Router-2公网 IP203.0.113.1（示例）203.0.113.2（示例）WireGuard 隧道 IP10.10.1.1/2410.10.1.2/24L2TP 隧道 IP10.10.2.1/24（作为服务器）10.10.2.2/24（作为客户端）VXLAN VNI100100VXLAN 底层端口8472（默认）8472前提条件两台 RouterOS 设备（建议 7.x 版本）至少一侧拥有固定的公网 IP（如果两端都有更好）防火墙已放行必要端口：WireGuard: UDP 51820L2TP/IPsec: UDP 500, 4500, IP 协议 50(ESP)VXLAN: UDP 8472确保两端 ether3 接口为空（未配置 IP 地址，准备加入桥）第一步：配置 WireGuard 主隧道WireGuard 配置简单、性能高，适合做主隧道。Router-1（站点A）# 生成密钥对（若未生成） /interface wireguard generate-seed # 创建 WireGuard 接口 /interface wireguard add name=wg-main mtu=1420 listen-port=51820 # 配置隧道 IP /ip address add address=10.10.1.1/24 interface=wg-main # 添加对端（Router-2） /interface wireguard peers add \ interface=wg-main \ public-key="<Router-2-Public-Key>" \ allowed-address=10.10.1.2/32Router-2（站点B）/interface wireguard add name=wg-main mtu=1420 listen-port=51820 /ip address add address=10.10.1.2/24 interface=wg-main /interface wireguard peers add \ interface=wg-main \ public-key="<Router-1-Public-Key>" \ allowed-address=10.10.1.1/32注意：<Router-X-Public-Key> 需要通过 /interface wireguard print 查看对方接口的公钥后填写。测试时可以用 ping 10.10.1.2 确认主隧道已通。第二步：配置 L2TP 备用隧道L2TP/IPsec 在 NAT 环境下表现良好，适合作为备用路径。Router-1（L2TP 服务器）# 开启 L2TP 服务器并设置 IPsec 共享密钥 /interface l2tp-server server set enabled=yes default-profile=default \ ipsec-secret=MySecretKey123 # 创建 L2TP 配置文件（分配隧道 IP） /ppp profile add name=l2tp-profile \ local-address=10.10.2.1 \ remote-address=10.10.2.10-10.10.2.20 # 创建 PPP 用户 /ppp secret add name=backup-user password=123456 \ profile=l2tp-profile service=l2tpRouter-2（L2TP 客户端）# 添加 L2TP 客户端接口，连接 Router-1 的公网 IP /interface l2tp-client add name=l2tp-backup \ connect-to=203.0.113.1 \ user=backup-user passwo…

使用 MikroTik RouterOS 搭建主备隧道（WireGuard + L2TP）并通过 VXLAN 实现二层桥接
type: item
date: 2026-05-21T22:51:00+08:00
description: 引言在企业网络或数据中心场景中，经常需要将两个不同地理位置的三层网络通过二层打通，使两端的设备像在同一个交换机下一样工作。同时，为了保障链路的可靠性，还需要建立主备隧道，当主隧道故障时业务能自动切换到备用隧道。本文将详细介绍如何在两台 MikroTik RouterOS 路由器上：建立 WireGuard 隧道作为主链路建立 L2TP/IPsec 隧道作为备份链路在两个隧道之上运行 VXLAN，并将两端的 ether3 物理接口桥接起来通过 Netwatch 实现隧道的主备自动切换重点：针对视频监控业务（UDP 大流量）进行 MTU 优化，解决花屏、卡顿问题拓扑规划假设两台路由器分别称为 Router-1（站点A） 和 Router-2（站点B）。它们各有至少一个公网接口（ether1）用于建立隧道，以及一个需要二层互通的本地接口 ether3。IP 地址规划角色Router-1Router-2公网 IP203.0.113.1（示例）203.0.113.2（示例）WireGuard 隧道 IP10.10.1.1/2410.10.1.2/24L2TP 隧道 IP10.10.2.1/24（作为服务器）10.10.2.2/24（作为客户端）VXLAN VNI100100VXLAN 底层端口8472（默认）8472前提条件两台 RouterOS 设备（建议 7.x 版本）至少一侧拥有固定的公网 IP（本文假设 Router-1 拥有静态公网 IP）防火墙已放行必要端口：WireGuard: UDP 51820L2TP/IPsec: UDP 500, 4500, IP 协议 50(ESP)VXLAN: UDP 8472确保两端 ether3 接口为空（未配置 IP 地址，准备加入桥）第一步：配置 WireGuard 主隧道WireGuard 配置简单、性能高，适合做主隧道。Router-1（站点A）# 生成密钥对（若未生成） /interface wireguard generate-seed # 创建 WireGuard 接口 /interface wireguard add name=wg-main mtu=1450 listen-port=51820 # 配置隧道 IP /ip address add address=10.10.1.1/24 interface=wg-main # 添加对端（Router-2） /interface wireguard peers add \ interface=wg-main \ public-key="<Router-2-Public-Key>" \ allowed-address=10.10.1.2/32Router-2（站点B）/interface wireguard add name=wg-main mtu=1450 listen-port=51820 /ip address add address=10.10.1.2/24 interface=wg-main /interface wireguard peers add \ interface=wg-main \ public-key="<Router-1-Public-Key>" \ allowed-address=10.10.1.1/32注意：此处 WireGuard 接口的 MTU 设为 1450，这是经过计算后针对视频监控优化的值，后面会详细解释。第二步：配置 L2TP 备用隧道L2TP/IPsec 在 NAT 环境下表现良好，适合作为备用路径。Router-1（L2TP 服务器）# 开启 L2TP 服务器并设置 IPsec 共享密钥 /interface l2tp-server server set enabled=yes default-profile=default \ ipsec-secret=MySecretKey123 # 创建 L2TP 配置文件（分配隧道 IP） /ppp profile add name=l2tp-profile \ local-address=10.10.2.1 \ remote-address=10.10.2.10-10.10.2.20 # 创建 PPP 用户 /ppp secret add name=backup-user password=123456 \ profile=l2tp-profile service=l2tpRouter-2（L2TP 客户端）# 添加 L2TP 客户端接口，连接 Router-1 的公网 IP /interface l2tp-client add name=l2tp-backup \ connect-to=203.0.113.1 \ user=backup…

MySQL 双主热备 + Keepalived 全自动切换方案
type: item
date: 2026-05-07T14:35:14+08:00
description: 纯热备场景下，用最少的组件（Keepalived + MySQL 原生复制）实现故障全自动切换、自动恢复、零数据丢失。兼容 MySQL 5.7 / 8.0 / MariaDB。一、设计思路1.1 核心问题在做这个方案之前，先想清楚三个问题：问题 1：为什么不用 MHA / ProxySQL？MHA 的 Manager 是单点，且切换后 Manager 自动退出，旧主恢复后仍需人工处理ProxySQL 功能强但引入了新的高可用问题（ProxySQL 本身也要做 HA），纯热备场景下得不偿失Keepalived 极其成熟，几万行 C 代码跑了二十年，比任何"智能"方案都可靠问题 2：为什么用双主而不是主从？传统主从 + VIP 的问题：切换后需要 CHANGE MASTER 反转拓扑。双主（互为主从）的好处是：不管 VIP 在哪台，另一台本来就是它的从库，切换时无需改复制拓扑，VIP 漂过去就能直接写。问题 3：如何防止恢复后 VIP 自动回切？这是整个方案最核心的设计点。来看看常规方案的问题：常规方案（仅用 priority + weight）： db-a priority=100 (主), db-b priority=90 (备) db-a 宕机 → db-a=80, db-b=90 → db-b 接管 ✓ db-a 恢复 → db-a=100, db-b=90 → db-a 抢回 ✗ （不必要的第二次中断！）如果加 nopreempt：nopreempt 只对 Keepalived 进程启动时的状态转换生效对 track_script 引起的动态权重变化不生效更糟的是，如果两台都加 nopreempt，连正常的故障切换都会被阻止本方案的解法：让 health check 脚本利用 MySQL 原生的复制 IO 线程状态来判断"主库是否还活着"：check_mysql.sh 逻辑： 1. MySQL 进程是否存活？→ 否 → exit 1（降权） 2. 我是只读（read_only=ON）吗？ - 是 → IO 线程是否在运行？ - 是 → 主库还活着，我安心当备机 → exit 1（降权，不抢占） - 否 → 主库挂了，我可以竞选 → exit 0 - 否 → 我已是主库 → exit 0这样恢复后的节点自动检测到当前主库还活着，主动降低优先级，不会抢占 VIP。1.2 方案架构应用 ──► VIP (192.168.7.33) ──► 当前主库 (read_only=OFF) └─► 备机 (read_only=ON) 双向复制 (GTID + 半同步) | check 脚本监控复制 IO 线程 判断主库是否存活 → 控制优先级1.3 故障切换时序正常状态： db-a (priority=100, read_only=OFF, IO-thread 活跃) db-b (priority=90, read_only=ON, IO-thread 活跃 → check 返回 1 → 实际=70) db-a 宕机后 8 秒内： db-a check 连续失败 2 次 → priority=80 db-b check 发现 IO 线程断开 → 返回 0 → priority=90 90 > 80 → db-b 接管 VIP notify_master 将 db-b read_only 关闭 db-a 恢复： MySQL 启动，read_only=ON（my.cnf 默认） IO 线程连上 db-b → 活跃 → check 返回 1 → priority=80 db-b 仍是 priority=90 80 < 90 → VIP 留在 db-b（不回切！）1.4 Priority 推演表场景db-a 状态db-a 实际 prioritydb-b 状态db-b 实际 priorityVIP 在初始正常read_only=OFF100read_only=ON, IO 活跃70 (90-20)db-adb-a 宕机MySQL 挂了80 (100-20)read_only=ON, IO 断开90db-bdb-a 恢复read_only=ON, IO 活跃80 (100-20)read_only=OFF90db-b（不回切）db-b 宕机read_only=ON, IO 断开100MySQL 挂了70 (90-20)db-a二、环境信息角色IP初始状态Keepalived prioritydb-a192.168.7.31read_only=ON，等 Keepalived 竞选100db-b192.168.7.32read_only=ON，等 Keepalived 竞选90VIP192.168.7.33——注意：两台 my.cnf 都配置 read…

Win10 多用户远程登录指南：RDPWrap 组策略
type: item
date: 2026-04-30T17:19:43+08:00
description: 1. 前言Windows 10 桌面版（专业版/企业版）默认只允许一个活跃的远程桌面会话。当你尝试让第二个用户通过远程桌面连接时，要么会把当前用户挤下线，要么会直接锁屏。这是因为微软在 termsrv.dll 文件中设置了硬编码的单用户限制。要突破这个限制，实现多人同时远程登录、互不影响，最常见的方式是使用开源工具 RDPWrap。本文将完整讲解从系统准备、安装破解到验证配置的全过程，并给出替代方案。2. 系统要求在开始之前，请确认你的系统满足以下条件：项目要求操作系统版本Windows 10 专业版、企业版或教育版（家庭版不支持远程桌面主机功能）远程桌面权限已在“设置 → 系统 → 远程桌面”中开启独立用户账户在“设置 → 账户 → 家庭和其他用户”中，为每位远程用户创建独立的本地账户，并添加到 Remote Desktop Users 组中github开源地址：https://github.com/stascorp/rdpwrap/releases/tag/v1.6.23. 使用 RDPWrap 破解多用户限制RDPWrap 是一个开源项目，通过封装和修补系统文件 termsrv.dll，在不对原始文件直接修改的情况下，让 Windows 桌面版支持多个并发远程桌面会话。⚠️ 重要：RDPWrap 原项目多年来已停止更新，但社区通过维护更新的 rdpwrap.ini 配置文件，使其能持续支持新版本的系统。3.1 详细操作步骤第一步：下载并安装从以下任一资源获取必要文件：官方原版（v1.6.2）：虽然原作者已停更，但安装器仍可正常使用。社区维护版：sebaxakerhtc/rdpwrap，持续更新 rdpwrap.ini 文件，支持更多新版本。推荐：下载社区维护版，直接解压即可使用，省去手动替换配置文件的步骤。以管理员身份运行 install.bat。脚本会自动将程序部署到 C:\Program Files\RDP Wrapper，并安装所需服务。第二步：更新配置文件（最关键的一步）如果用的是官方原版，需要手动替换新的配置文件：停止服务：以管理员身份运行命令 net stop termservice从 sebaxakerhtc/rdpwrap.ini 仓库下载最新的 rdpwrap.ini用下载的文件覆盖 C:\Program Files\RDP Wrapper\rdpwrap.ini启动服务：以管理员身份运行命令 net start termservice如果用的是社区维护版，通常已包含较新的配置文件，可直接进入验证步骤。若不成功，仍可参照上述方法更新。第三步：配置本地组策略按 Win+R 打开运行，输入 gpedit.msc 并回车。定位到：计算机配置 → 管理模板 → Windows 组件 → 远程桌面服务 → 远程桌面会话主机 → 连接。双击 “将远程桌面服务用户限制到单独的远程桌面服务会话”，设置为 “已禁用”。双击 “限制连接的数量”，设置为 “已启用”，并在选项中填入允许的最大并发连接数（例如 5 或 999999）。3.2 安装RDPwrap补丁防火墙会进行拦截3.3 如何验证是否成功？运行 C:\Program Files\RDP Wrapper 目录下的 RDPConf.exe，检查状态面板。如果 所有条目都显示为绿色，说明破解成功。你也可以运行 RDPCheck.exe 进行直观测试：如果能弹出一个新的远程桌面窗口，且没有挤掉当前会话，就说明多用户同时登录功能已生效。4. 常见问题与故障排查4.1 运行 RDPConf.exe 后出现红色或黄色警告这通常是因为 rdpwrap.ini 配置与当前系统版本不兼容。解决方法：按 Win+R，输入 winver 并回车，查看系统详细版本和 内部版本号（OS Build）。访问 sebaxakerhtc/rdpwrap.ini 的 GitHub 仓库，查找是否有针对你内部版本号的更新配置文件。下载该文件，覆盖到 C:\Program Files\RDP Wrapper\rdpwrap.ini。重启远程桌面服务或重启电脑。4.2 重启或系统更新后失效原因：系统大版本更新（如从 22H2 升级到 24H2）会替换部分系统文件，导致 RDPWrap 失效。解决方法：重新运行安装和配置文件更新步骤。

Docker 在线安装
type: item
date: 2026-04-21T15:17:00+08:00
description: 在云原生时代，Docker 已成为应用打包、交付和运行的事实标准。本文将以 CentOS 7 系统为例，详细介绍如何利用阿里云镜像站在线安装 Docker CE、配置国内镜像加速源、安装 Docker Compose，并演示一个典型的多服务容器化部署流程。一、安装 Docker CE（社区版）1.1 安装必要系统工具首先需要安装 yum-utils，它提供了 yum-config-manager 工具，方便我们管理软件源。sudo yum install -y yum-utils1.2 添加阿里云 Docker 软件源使用阿里云提供的官方仓库地址，能显著提升下载速度和稳定性。yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo1.3 安装 Docker 及相关组件执行以下命令安装 Docker 引擎、CLI 工具、容器运行时以及构建插件和 Compose 插件。sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y注：docker-compose-plugin 是 Docker Compose V2 的插件形式，若习惯使用 docker-compose 命令，也可以单独安装传统版本的 Compose（见后文）。1.4 启动 Docker 服务sudo systemctl enable --now docker1.5 校验安装查看 Docker 版本信息，确认安装成功。docker version如果正常显示客户端和服务端版本号，说明 Docker 已正确安装并运行。二、配置国内镜像加速源（重要）由于网络原因，直接从 Docker Hub 拉取镜像可能非常缓慢。通过配置国内镜像加速器，可以大幅提升拉取速度。2.1 创建/编辑 daemon.jsonvim /etc/docker/daemon.json2.2 写入以下内容{ "registry-mirrors": [ "https://51mbg7lq.mirror.aliyuncs.com", "https://9cpn8tt6.mirror.aliyuncs.com", "https://registry.docker-cn.com", "https://a0f4d5484dea442caf5d1193f09abdd4.mirror.swr.myhuaweicloud.com", "https://do.nark.eu.org", "https://dc.j8.work", "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.mirrors.ustc.edu.cn", "https://docker.nju.edu.cn", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com", "https://ccr.ccs.tencentyun.com" ] }说明：这里列出了多个国内常用镜像源（阿里云、华为云、中科大、南京大学、网易、百度、腾讯云等），按优先级排列。你可以根据实际网络情况增删。2.3 重新加载配置并重启 Dockersudo systemctl daemon-reload sudo systemctl restart docker2.4 设置开机自启sudo systemctl enable docker完成上述步骤后，Docker 的基础环境就准备好了。三、安装 Docker Compose（可选）如果你的项目需要使用 docker-compose.yml 进行多容器编排，建议安装 Docker Compose。 若已通过 docker-compose-plugin 安装了 V2 版本，可以直接使用 docker compose 命令（注意中间没有横线）。但传统 docker-compose 命令在很多教程中仍被广泛使用，因此下面也提供独立安装方法。3.1 下载稳定版二进制文件以 v2.5.1 为例（你也可以到 GitHub Releases 查看最新版本号）：sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/doc…

mikrotik 端口映射之原进原出
type: item
date: 2026-04-18T23:47:36+08:00
description: 具体来说，需要在 mangle 表中标记外部进入的连接，并在 route 表中为这些连接创建一个专属的、指定了源IP和网关的路由，从而强制回程流量从正确的接口出去。⚙️ 详细配置步骤基础网络设置确保所有WAN口已经正确配置了IP地址、网关，并确保网络通畅。标记连接进入 IP -> Firewall -> Mangle 标签页，为从每个公网IP进入的连接打上“连接标记”。Chain: preroutingSrc. Address: 留空（或填写特定公网IP）Dst. Address: 填写你要映射的公网IP地址，子网掩码为 /32In. Interface: 选择该公网IP所在的物理接口（如 ether1）Action: mark connectionNew Connection Mark: 为这个连接起一个名字，例如 conn_public_ip_1Passthrough: yes（必须选“是”，让标记继续传递）为其他公网IP，重复此步骤。标记路由在同一个 Mangle 表中，创建规则，将上一步的“连接标记”转换为“路由标记”。Chain: outputConnection Mark: 选择上一步创建的标记名，例如 conn_public_ip_1Action: mark routingNew Routing Mark: 为路由表起一个名字，例如 route_public_ip_1Passthrough: no为其他公网IP，重复此步骤。创建专属路由表进入 IP -> Routes 标签页，为每个公网IP创建一个新的路由表。Dst. Address: 0.0.0.0/0（默认路由）Gateway: 选择该公网IP对应的网关地址Routing Mark: 选择上一步创建的“路由标记”，例如 route_public_ip_1为其他公网IP，重复此步骤。配置端口映射最后，创建端口映射（dstnat）规则。Chain: dstnatDst. Address: 填写要映射的公网IP地址Protocol: 选择要映射的协议（如 tcp）Dst. Port: 填写要映射的端口号Action: dst-natTo Addresses: 填写内网服务器的IP地址To Ports: 填写内网服务器的端口号📝 完整配置脚本示例假设你有两条线路，线路A的接口是ether1，IP为203.0.113.1，网关203.0.113.254；线路B的接口是ether2，IP为198.51.100.1，网关198.51.100.254。你想把内网192.168.1.100的80端口分别映射到这两个公网IP的80端口上。你可以在New Terminal中执行以下脚本：# --- 1. 标记连接 (Mangle) --- /ip firewall mangle add chain=prerouting dst-address=203.0.113.1 in-interface=ether1 action=mark-connection new-connection-mark=conn_lineA passthrough=yes /ip firewall mangle add chain=prerouting dst-address=198.51.100.1 in-interface=ether2 action=mark-connection new-connection-mark=conn_lineB passthrough=yes # --- 2. 标记路由 (Mangle) --- /ip firewall mangle add chain=output connection-mark=conn_lineA action=mark-routing new-routing-mark=route_lineA passthrough=no /ip firewall mangle add chain=output connection-mark=conn_lineB action=mark-routing new-routing-mark=route_lineB passthrough=no # --- 3. 创建策略路由 (Routes) --- /ip route add dst-address=0.0.0.0/0 gateway=203.0.113.254 routing-mark=route_lineA /ip route add dst-address=0.0.0.0/0 gateway=198.51.100.254 routing-mark=route_lineB # --- 4. 端口映射 (NAT) --- /ip firewall nat add c…