
把代码保存为tcp.sh文件,上传到root文件夹下。
!/usr/bin/env bash
set -euo pipefail
=========================================================
BBR+fq TCP 调优 + 冲突清理(/etc/sysctl.d 冲突文件直接删除版)
- 计算:BDP(bytes)=Mbps125ms;max = min(2*BDP, 3%RAM, 64MB);向下桶化至 {4,8,16,32,64}MB
- 写入:/etc/sysctl.d/999-net-bbr-fq.conf
- 清理:注释 /etc/sysctl.conf 的冲突键;直接删除 /etc/sysctl.d/*.conf 中含冲突键的旧文件
- 其他目录(/usr/lib|/lib|/usr/local/lib|/run/sysctl.d):仅提示不改
=========================================================
read -r -p "内存大小 (GiB) [默认 1] : " MEM_G_INPUT
read -r -p "带宽 (Mbps) [默认 1000] : " BW_Mbps_INPUT
read -r -p "往返延迟 RTT (ms) [默认 150] : " RTT_ms_INPUT
MEM_G="${MEM_G_INPUT:-1}"
BW_Mbps="${BW_Mbps_INPUT:-1000}"
RTT_ms="${RTT_ms_INPUT:-150}"
is_num() { [[ "${1:-}" =~ ^[0-9]+([.][0-9]+)?$ ]]; }
is_int() { [[ "${1:-}" =~ ^[0-9]+$ ]]; }
is_num "$MEM_G" || MEM_G=1
is_int "$BW_Mbps" || BW_Mbps=1000
is_num "$RTT_ms" || RTT_ms=150
SYSCTL_TARGET="/etc/sysctl.d/999-net-bbr-fq.conf"
KEY_REGEX='^(net.core.default_qdisc|net.core.rmem_max|net.core.wmem_max|net.core.rmem_default|net.core.wmem_default|net.ipv4.tcp_rmem|net.ipv4.tcp_wmem|net.ipv4.tcp_congestion_control)[[:space:]]*='
note() { echo -e "\033[1;34m[i]\033[0m $*"; }
ok() { echo -e "\033[1;32m[OK]\033[0m $*"; }
warn() { echo -e "\033[1;33m[!]\033[0m $*"; }
bad() { echo -e "\033[1;31m[!!]\033[0m $*"; }
require_root() { if [ "${EUID:-$(id -u)}" -ne 0 ]; then bad "请以 root 运行"; exit 1; fi; }
default_iface(){ ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -1 || true; }
---- 计算(逐步校验)----
BDP_BYTES=$(awk -v bw="$BW_Mbps" -v rtt="$RTT_ms" 'BEGIN{ printf "%.0f", bw125rtt }') # Mbps125ms (bytes)
MEM_BYTES=$(awk -v g="$MEM_G" 'BEGIN{ printf "%.0f", g10241024*1024 }')
TWO_BDP=$(( BDP_BYTES*2 ))
RAM3_BYTES=$(awk -v m="$MEM_BYTES" 'BEGIN{ printf "%.0f", m*0.03 }')
CAP64=$(( 6410241024 ))
MAX_NUM_BYTES=$(awk -v a="$TWO_BDP" -v b="$RAM3_BYTES" -v c="$CAP64" 'BEGIN{ m=a; if(b<m)m=b; if(c<m)m=c; printf "%.0f", m }')
bucket_le_mb() {
local mb="${1:-0}"
if [ "$mb" -ge 64 ]; then echo 64
elif [ "$mb" -ge 32 ]; then echo 32
elif [ "$mb" -ge 16 ]; then echo 16
elif [ "$mb" -ge 8 ]; then echo 8
elif [ "$mb" -ge 4 ]; then echo 4
else echo 4
fi
}
MAX_MB_NUM=$(( MAX_NUM_BYTES/1024/1024 ))
MAX_MB=$(bucket_le_mb "$MAX_MB_NUM")
MAX_BYTES=$(( MAX_MB10241024 ))
if [ "$MAX_MB" -ge 32 ]; then
DEF_R=262144; DEF_W=524288
elif [ "$MAX_MB" -ge 8 ]; then
DEF_R=131072; DEF_W=262144
else
DEF_R=131072; DEF_W=131072
fi
TCP_RMEM_MIN=4096; TCP_RMEM_DEF=87380; TCP_RMEM_MAX=$MAX_BYTES
TCP_WMEM_MIN=4096; TCP_WMEM_DEF=65536; TCP_WMEM_MAX=$MAX_BYTES
---- 冲突清理 ----
comment_conflicts_in_sysctl_conf() {
local f="/etc/sysctl.conf"
[ -f "$f" ] || { ok "/etc/sysctl.conf 不存在"; return 0; }
if grep -Eq "$KEY_REGEX" "$f"; then
note "注释 /etc/sysctl.conf 中的冲突键"
awk -v re="$KEY_REGEX" '
$0 ~ re && $0 !~ /^[[:space:]]*#/ { print "# " $0; next }
{ print $0 }
' "$f" > "${f}.tmp.$$"
install -m 0644 "${f}.tmp.$$" "$f"
rm -f "${f}.tmp.$$"
ok "已注释掉冲突键"else
ok "/etc/sysctl.conf 无冲突键"fi
}
delete_conflict_files_in_dir() {
local dir="$1"
[ -d "$dir" ] || { ok "$dir 不存在"; return 0; }
shopt -s nullglob
local removed=0
for f in "$dir"/*.conf; do
[ "$(readlink -f "$f")" = "$(readlink -f "$SYSCTL_TARGET")" ] && continue
if grep -Eq "$KEY_REGEX" "$f"; then
rm -f -- "$f"
note "已删除冲突文件:$f"
removed=1
fidone
shopt -u nullglob
[ "$removed" -eq 1 ] && ok "$dir 中的冲突文件已删除" || ok "$dir 无需处理"
}
scan_conflicts_ro() {
local dir="$1"
[ -d "$dir" ] || { ok "$dir 不存在"; return 0; }
if grep -RIlEq "$KEY_REGEX" "$dir" 2>/dev/null; then
warn "发现潜在冲突(只提示不改):$dir"
grep -RhnE "$KEY_REGEX" "$dir" 2>/dev/null || trueelse
ok "$dir 未发现冲突"fi
}
require_root
note "步骤A:注释 /etc/sysctl.conf 冲突键"
comment_conflicts_in_sysctl_conf
note "步骤B:删除 /etc/sysctl.d 下含冲突键的旧文件(不备份)"
delete_conflict_files_in_dir "/etc/sysctl.d"
note "步骤C:扫描其他目录(只读提示,不改)"
/usr/bin/true
scan_conflicts_ro "/usr/local/lib/sysctl.d"
scan_conflicts_ro "/usr/lib/sysctl.d"
scan_conflicts_ro "/lib/sysctl.d"
scan_conflicts_ro "/run/sysctl.d"
---- 启用 BBR 模块(若为内置则无影响)----
if command -v modprobe >/dev/null 2>&1; then modprobe tcp_bbr 2>/dev/null || true; fi
---- 写入并应用 ----
tmpf="$(mktemp)"
cat >"$tmpf" <<EOF
Auto-generated by net-tcp-tune (delete-conflicts)
Inputs: MEM_G=${MEM_G}GiB, BW=${BW_Mbps}Mbps, RTT=${RTT_ms}ms
BDP: ${BDP_BYTES} bytes (~$(awk -v b="$BDP_BYTES" 'BEGIN{ printf "%.2f", b/1024/1024 }') MB)
Caps: min(2*BDP, 3%RAM, 64MB) -> Bucket ${MAX_MB} MB
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.core.rmem_default = ${DEF_R}
net.core.wmem_default = ${DEF_W}
net.core.rmem_max = ${MAX_BYTES}
net.core.wmem_max = ${MAX_BYTES}
net.ipv4.tcp_rmem = ${TCP_RMEM_MIN} ${TCP_RMEM_DEF} ${TCP_RMEM_MAX}
net.ipv4.tcp_wmem = ${TCP_WMEM_MIN} ${TCP_WMEM_DEF} ${TCP_WMEM_MAX}
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fastopen = 3
EOF
install -m 0644 "$tmpf" "$SYSCTL_TARGET"
rm -f "$tmpf"
sysctl --system >/dev/null
IFACE="$(default_iface)"
if command -v tc >/dev/null 2>&1 && [ -n "${IFACE:-}" ]; then
tc qdisc replace dev "$IFACE" root fq 2>/dev/null || true
fi
echo "==== RESULT ===="
echo "内存: ${MEM_G} GiB, 带宽: ${BW_Mbps} Mbps, RTT: ${RTT_ms} ms"
echo "桶值: ${MAX_MB} MB"
sysctl -n net.ipv4.tcp_congestion_control
sysctl -n net.core.default_qdisc
sysctl -n net.core.rmem_max
sysctl -n net.core.wmem_max
sysctl -n net.ipv4.tcp_rmem
sysctl -n net.ipv4.tcp_wmem
if command -v tc >/dev/null 2>&1 && [ -n "${IFACE:-}" ]; then
echo "qdisc on ${IFACE}:"; tc qdisc show dev "$IFACE" || true
fi
echo "==============="
note "复核:查看加载顺序及最终值来源(只读)"
sysctl --system 2>&1 | grep -nE 'Applying|net.core.(rmem|wmem)|net.core.default_qdisc|net.ipv4.tcp_(rmem|wmem)|tcp_congestion_control' || true
执行:
删除文件中的 \r 字符
sed -i 's/\r$//' /root/tcp.sh
重新执行
chmod +x /root/tcp.sh
/root/tcp.sh