服务器入坑指北:异地复制的积压与带宽换算

举报
Tulpartner 发表于 2026/11/14 09:17:15 2026/11/14
【摘要】 看到"延迟 3600 秒"就以为要赶 1 小时;不知道积压该看哪个数;限速值凭感觉拍。 在你动手去读之前,先把两条前提看清:① 延迟与积压不是一回事——延迟是时间(秒,而且可以是空值),积压是量(字节,两个位点相减);② 空值不等于零——把"量不出来"当 0,会得出"已经追平"这种反向结论。

看到"延迟 3600 秒"就以为要赶 1 小时;不知道积压该看哪个数;限速值凭感觉拍。
在你动手去读之前,先把两条前提看清:① 延迟与积压不是一回事——延迟是时间(秒,而且可以是空值),积压是量(字节,两个位点相减);② 空值不等于零——把"量不出来"当 0,会得出"已经追平"这种反向结论。
这篇给三段可直接粘贴的内容:读两类量 → 算两式 → 改与读回(最后一段改限速是写操作)。取值用占位符,字段名、参数名与路径照写,每个数字都连着单位;每条命令带它自己的环境前提。

积压和延迟不是一回事

延迟回答"慢了多久",积压回答"还欠多少":

  • 延迟:Seconds_Behind_Source——单位是秒,且可以为 NULL(空表示"当前量不出来",不是 0、也不是很大);
  • 积压:两个位点相减——Read_Source_Log_Pos 减去 Exec_Source_Log_Pos,单位是字节位点。
    判据:先问"我要的是等多久、还是欠多少"——拿秒数当积压,量纲从一开始就不成立(下面第二式会把它演示出来)。
    一处写法要标清:Seconds_Behind_Master 是旧名——官方文档说明该写法自 8.0.22 起改名、8.4 起不再接受旧别名(确切的版本与措辞以官方文档现读为准);看到它要标出"旧名",不要当可用写法引用。

积压怎么量

SHOW REPLICA STATUS\G                          # 第一现场:读复制状态的全部字段(需数据库客户端与权限;本机没有,未实跑)
mysql -u <用户名> -e 'SHOW REPLICA STATUS\G'     # 脚本化读法(需先装 mysql 客户端)
cat /proc/net/dev                              # 带宽读入口之一:这些字节数是自接口启动以来的累计值,不是速率
grep -E -e 'eth0' /proc/net/dev                 # 只看那一条接口的累计计数:这些字节数自接口启动以来一直累加,不是速率
ip -br link                                    # 先看本机接口叫什么(需先装 iproute2;接口名可能是 eth1 / ens5 / enp3s0)
grep -E -e 'eth0' /proc/net/dev                 # 占位写法:eth0 只是接口名占位,先按上面那行确认本机接口名;名字不对时它零输出、exit 1,不是"读不出来"
sar -n DEV <间隔> <次数>                        # 带宽读入口之二:判据列是 rxkB/s 与 txkB/s(已是每秒速率;需先装 sysstat)
ss -tnp                                        # 复制链路还连着吗(判"停了"还是"慢";需先装 iproute2)
date +%s                                       # 两次取值相减=Δ时间(秒)

判据(这个数是量还是时间、什么口径):

  • 位点:Read_Source_Log_Pos(已从主库读到的位点)与 Exec_Source_Log_Pos(已应用到从库的位点)——同为字节位点,相减就是积压;
  • 中继位点 Relay_Log_Pos:用来判**“卡在读还是卡在应用”**;
  • 累计:cat /proc/net/dev 的字节数自接口启动以来一直累加(要区间量就取两次差值再除间隔);
  • 速率:sar -n DEV <间隔> <次数> 的 rxkB/s / txkB/s 已经除过时间。
    限速参数名要写对:rsync 的限速参数名是 --bwlimit=<RATE>,它的单位是每秒千字节(换算成字节每秒要 ×1024);旧资料里常写成 --bwlimit=KBPS——那是把单位误当成了参数名,KBPS 不是参数名。
    三种读数读出来长这样(值用占位符):
Read_Source_Log_Pos:   <字节位点>
Exec_Source_Log_Pos:   <字节位点>
Seconds_Behind_Source: <秒 或 NULL>
eth0: <接收字节累计> ... <发送字节累计> ...      # /proc/net/dev:累计值,不是速率
... rxkB/s <值>  txkB/s <值> ...                 # sar -n DEV:已是每秒速率

"空"要单独判:Seconds_Behind_Source 取 NULL 的确切条件以官方文档现读为准(本机没有数据库客户端、我无法自证)——但读法不变:空不等于 0。

追赶时间怎么算

追赶时间 = 积压 / 可用带宽——两个量必须同单位、同一时间窗(积压用字节、带宽用字节每秒)。
算一遍(数值为演示值):Read_Source_Log_Pos 取 10737418240、Exec_Source_Log_Pos 取 1073741824 ⇒ 积压 = 10737418240 - 1073741824 = 9663676416(字节);限速 --bwlimit=<KB每秒> 取 8192(每秒千字节)⇒ 可用带宽 = 8192 * 1024 = 8388608(字节每秒)⇒ 追赶时间 = 9663676416 / 8388608 = 1152(秒,19.2 分钟)。
第二式(反例):为什么不能拿秒数当积压。
把秒数代进同一个式子:延迟按 3600 秒算 ⇒ 3600 / 8388608 ≈ 0.000429——这个数的量纲是"秒的平方每字节",它不是时间;换任何带宽进去,都得不到一个"追赶时间"。积压用字节位点差、带宽用字节每秒,两者才是可除的。
判据:先算这个数,再决定限速给多少——它比"延迟多少秒"更能指导动作。
再补一式:积压增长速度 = 产生速率 − 应用速率。

  • 产生速率 = Read_Source_Log_Pos 的两次差值 ÷ 间隔(主库产生日志的速度);
  • 应用速率 = Exec_Source_Log_Pos 的两次差值 ÷ 间隔(从库应用的速度)。
    算一遍(数值为演示值):产生速率 4194304(字节每秒)、应用速率 3145728(字节每秒)⇒ 积压增长速度 = 4194304 - 3145728 = 1048576(字节每秒,也就是 1 MiB 每秒)。
    判据:这个数为正 ⇒ 越欠越多——此时"追赶时间"那一式给不出有限值(限速放开多少都追不上,得先让应用速度提上来);为负 ⇒ 在追,再用第一式算"还要多久追平"。两式要一起用:先看积压是在涨还是在消,再谈限速给多少。
    判据:先算这个数,再决定限速给多少——它比"延迟多少秒"更能指导动作。

三个口径别混(位点 / 累计 / 速率)

三个口径量的不是一回事:位点(两个位置相减 = 积压,字节)· 累计计数器(/proc/net/dev 的字节数,自启动至今的总量)· 速率(sar -n DEV <间隔> <次数> 的 rxkB/s / txkB/s,已经除过时间)——三者的读入口与口径上面都逐条给过,这一节只留最值钱的一条:
混用的典型错数:拿累计值当速率用(或反过来),会得出"整个运转时长的平均吞吐"——那个数既不描述当下、也不描述区间。判据:先问"我要的是还欠多少、总量、还是当前速度";答错就一定会读到对不上的数(例如把 /proc/net/dev 的累计值直接当成"当前吞吐"报出去)。

取舍:限速保守还是激进

  • 限速低:对业务影响小;代价是追赶时间长、积压可能持续增长;
  • 限速高:追得快;代价是挤占业务带宽、可能影响在线请求;
  • 不限速:最快;代价是峰值期把链路打满。
    判据:先把"追赶时间"算出来,再看它是否落在你能接受的时间窗内——"还欠多少 ÷ 能给多少"这一步,比看延迟秒数更能定限速值。

改与读回

rsync --bwlimit=<KB每秒> <源> <目标>            # 限速侧:把可用带宽压到不影响业务(单位是每秒千字节;×1024 得字节每秒)
du -sb <目录>                                  # 待传量:-b 是表观字节数;du 默认按 inode 去重、硬链接只计一次(-l 才重复计)
sar -n DEV <间隔> <次数>                        # 读回:rxkB/s / txkB/s 是不是你限的那个量级(需先装 sysstat)
ss -tnp                                        # 读回:复制链路还在不在(需先装 iproute2)

先记原值(限速设定、现读位点各记一份),改完回读确认;改限速是写操作、需要相应权限,要跨重启就写进它的持久化落点(不是只改本次运行值)。

现象到动作的判定表

现象 结论 动作
延迟很大 先换算成积压再看 用两个位点相减得字节积压,再算追赶时间
延迟是空的 量不出来,不是 0 别当"已追平";改用位点差判断
两个地方吞吐对不上 累计对速率 要速率用 sar -n DEV,要区间量用两次差值 ÷ 间隔
积压一直不降 带宽不够 算追赶时间,再看限速能放到多少
改了限速没变化 可能改的不是当前生效的那一层 核限速的持久化落点与本次生效值

这篇不解决什么

  • 讲性能与掉电窗口的取舍的那篇管掉电窗口与性能的总取舍(积压在那里只是邻接词);本篇管积压与带宽的换算。判定入口:“掉电能丢多少、性能如何权衡”→ 那篇;“还欠多少、多久能追平”→ 本篇。
  • 讲网卡中断与软中断分布的那篇管中断分布与单核打满;本篇管应用层复制的积压——一个在链路层、一个在复制链路的两端。
  • 讲发送缓冲与背压的那篇管单连接的发送侧背压;本篇管跨站点复制的累计欠量。

踩坑清单

  • 拿延迟秒数当积压:量纲不成立。
  • 把 NULL 当 0:会得出"已经追平"的反向结论。
  • 用 Seconds_Behind_Master 这个已废弃写法:新版已改成 Source。
  • 拿 sar 的速率再除一次时间:rxkB/s/txkB/s 已经是速率。
  • 拿 /proc/net/dev 的累计当区间量:那是自接口启动以来的总量。
  • 只看延迟不看位点差:分不清"慢"和"欠"。
  • 在没装数据库客户端或 sysstat/iproute2 的环境上照敲:先装对应包。
  • 改了限速不写持久化:重启就回到原值。

改完怎么验证(命令 + 期望)

  • 重算一次积压:SHOW REPLICA STATUS\G 读两个位点 ⇒ 期望:Read_Source_Log_Pos 的数值与 Exec_Source_Log_Pos 可相减,差值即积压(若差为负,先怀疑读错了字段);
  • 核对带宽口径:sar -n DEV <间隔> <次数> 与 cat /proc/net/dev 各读一次 ⇒ 期望:前者是速率(数量级与链路容量同阶),后者是累计大数(隔几秒再看会变大);
  • 跑一次反例:把延迟秒数除以带宽字节每秒 ⇒ 期望:得到一个约 10⁻⁴ 量级的数,它不是时间(量纲不成立);
  • 看积压是在涨还是在消:两次位点差 ÷ 间隔各求一次 ⇒ 期望:两个速率相减得到积压增长速度,符号说明方向;
  • 看限速是否生效:改完限速后再读一次速率 ⇒ 期望:txkB/s 落回你限的那个值附近;
  • 回滚可用:按改前记下的原值改回 ⇒ 期望:限速值与生效口径都回到原样。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。