[{"content":"内核参数全景图 网络核心参数 # /etc/sysctl.d/99-network-tuning.conf # TCP 连接优化 net.ipv4.tcp_syncookies = 1 # 防 SYN Flood net.ipv4.tcp_max_syn_backlog = 65535 # SYN 队列长度 net.core.somaxconn = 65535 # 监听队列长度 net.ipv4.tcp_abort_on_overflow = 0 # 队列满时不直接拒绝 # 端口复用 net.ipv4.tcp_tw_reuse = 1 # TIME_WAIT 端口复用 net.ipv4.tcp_fin_timeout = 15 # FIN_WAIT2 超时时间 net.ipv4.tcp_max_tw_buckets = 65535 # TIME_WAIT 最大数量 # 缓冲区大小 net.core.rmem_max = 16777216 # 接收缓冲区最大值 net.core.wmem_max = 16777216 # 发送缓冲区最大值 net.core.rmem_default = 1048576 # 接收缓冲区默认值 net.core.wmem_default = 1048576 # 发送缓冲区默认值 net.ipv4.tcp_rmem = 4096 1048576 16777216 # TCP 接收缓冲区 net.ipv4.tcp_wmem = 4096 1048576 16777216 # TCP 发送缓冲区 # 连接追踪 net.netfilter.nf_conntrack_max = 262144 # 连接追踪表大小 net.netfilter.nf_conntrack_tcp_timeout_established = 7200 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30 # UDP 优化 net.ipv4.udp_rmem_min = 81920 net.ipv4.udp_wmem_min = 81920 # 路由优化 net.ipv4.conf.all.rp_filter = 1 # 反向路径过滤 net.ipv4.conf.default.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 # 忽略广播 ping net.ipv4.conf.all.accept_redirects = 0 # 拒绝 ICMP 重定向 net.ipv4.conf.all.send_redirects = 0 BBR 拥塞控制 # 检查可用算法 sysctl net.ipv4.tcp_available_congestion_control # 启用 BBR echo \u0026#34;net.core.default_qdisc=fq\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-network-tuning.conf echo \u0026#34;net.ipv4.tcp_congestion_control=bbr\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-network-tuning.conf sysctl -p # 验证 sysctl net.ipv4.tcp_congestion_control lsmod | grep bbr 内核网络模块 # 网络相关模块 modprobe tcp_bbr # BBR 拥塞控制 modprobe tcp_noha # NOHA 算法 modprobe nf_conntrack # 连接追踪 modprobe iptable_nat # NAT # 查看已加载模块 lsmod | grep -E \u0026#34;tcp|net|ip\u0026#34; # 开机自动加载 echo \u0026#34;tcp_bbr\u0026#34; \u0026gt;\u0026gt; /etc/modules-load.d/bbr.conf 网络性能压测 iperf3 带宽测试 # 服务端 iperf3 -s # 客户端 iperf3 -c server_ip # UDP 测试 iperf3 -c server_ip -u -b 100M # 并发测试 iperf3 -c server_ip -P 4 # 反向测试（服务端→客户端） iperf3 -c server_ip -R netperf 延迟测试 # 安装 apt install netperf # 服务端 netserver # 客户端 netperf -H server_ip -t TCP_RR # 请求响应延迟 netperf -H server_ip -t TCP_STREAM # 吞吐量 hping3 网络探测 # SYN 扫描 hping3 -S -p 80 server_ip # UDP 扫描 hping3 --udp -p 53 server_ip # ICMP 延迟测试 hping3 -1 server_ip # 带宽测试 hping3 -S -p 80 --flood server_ip ss 连接分析 # 查看所有连接 ss -s # 查看 TCP 连接 ss -tnp # 查看监听端口 ss -tlnp # 查看 UDP 连接 ss -unp # 查看状态统计 ss -ant | awk \u0026#39;{print $1}\u0026#39; | sort | uniq -c | sort -rn # 查看连接队列 ss -lntp | awk \u0026#39;{print $1, $2, $3, $4}\u0026#39; nstat 网络统计 # 实时统计 nstat # 关注指标 nstat -z | grep -E \u0026#34;TcpRetrans|TcpExtTCPTimeout|TcpExtTCPSynRetrans\u0026#34; 连接追踪优化 conntrack 表管理 # 查看当前连接数 cat /proc/sys/net/netfilter/nf_conntrack_count # 查看最大连接数 cat /proc/sys/net/netfilter/nf_conntrack_max # 查看连接追踪表 conntrack -L # 统计连接状态 conntrack -L -o extended | awk \u0026#39;{print $4}\u0026#39; | sort | uniq -c | sort -rn # 优化超时时间 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=15 常见问题排查 # SYN Flood 防护 dmesg | grep SYN netstat -s | grep SYN # 连接数过多 ss -s netstat -an | wc -l # TIME_WAIT 过多 netstat -an | grep TIME_WAIT | wc -l # 连接追踪表满 dmesg | grep conntrack 网络调试工具 tcpdump 抓包 # 基本抓包 tcpdump -i eth0 # 过滤主机 tcpdump -i eth0 host 192.168.1.1 # 过滤端口 tcpdump -i eth0 port 80 # 过滤协议 tcpdump -i eth0 tcp # 保存到文件 tcpdump -i eth0 -w capture.pcap # 读取文件 tcpdump -r capture.pcap # 常用过滤器 tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; tcp-syn != 0\u0026#39; # SYN 包 tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; tcp-rst != 0\u0026#39; # RST 包 mtr 路由追踪 # 基本使用 mtr server_ip # 报告模式 mtr -rw server_ip # 指定次数 mtr -c 100 server_ip ip 命令 # 查看网络接口 ip addr show ip link show # 查看路由 ip route show # 查看邻居表 ip neigh show # 配置接口 ip addr add 192.168.1.100/24 dev eth0 ip link set eth0 up # 路由操作 ip route add default via 192.168.1.1 ip route del 10.0.0.0/8 性能基准测试 网络吞吐量 # 使用 dd 测试 dd if=/dev/zero of=server_ip bs=1M count=1024 # 使用 netcat dd if=/dev/zero | nc server_ip 12345 nc -l 12345 \u0026gt; /dev/null 延迟测试 # ping 延迟 ping -c 100 server_ip # TCP 延迟 hping3 -S -p 80 -c 100 server_ip # HTTP 延迟 curl -o /dev/null -s -w \u0026#34;time_total: %{time_total}\\n\u0026#34; http://server_ip 面试常见问题 TCP 和 UDP 的区别？\nTCP: 可靠、有序、面向连接 UDP: 不可靠、无序、无连接 TCP 适合文件传输，UDP 适合实时应用 如何检测网络丢包？\nping: 检测 ICMP 丢包 mtr: 追踪路由并统计丢包 ss -s: 查看重传统计 TIME_WAIT 过多如何处理？\n开启 tcp_tw_reuse 减小 tcp_fin_timeout 使用长连接 如何优化高并发服务器？\n增大 somaxconn 开启 tcp_tw_reuse 调整连接追踪参数 使用 BBR 拥塞控制 实战: 网络性能分析脚本 #!/bin/bash echo \u0026#34;=== 网络性能分析 ===\u0026#34; echo \u0026#34;1. 连接状态:\u0026#34; ss -s echo \u0026#34;\u0026#34; echo \u0026#34;2. 重传统计:\u0026#34; nstat -z | grep -E \u0026#34;TcpRetrans|TcpExtTCPTimeout\u0026#34; | head -10 echo \u0026#34;\u0026#34; echo \u0026#34;3. 连接追踪:\u0026#34; echo \u0026#34;当前: $(cat /proc/sys/net/netfilter/nf_conntrack_count)\u0026#34; echo \u0026#34;最大: $(cat /proc/sys/net/netfilter/nf_conntrack_max)\u0026#34; echo \u0026#34;\u0026#34; echo \u0026#34;4. 端口监听:\u0026#34; ss -tlnp | head -10 echo \u0026#34;\u0026#34; echo \u0026#34;5. 网络接口:\u0026#34; ip -s link show eth0 ","permalink":"https://blog.geek.16775390.xyz/posts/linux-network-tuning-advanced/","summary":"深入解析 Linux 网络内核参数、BBR 拥塞控制、连接追踪、以及网络性能压测工具链。","title":"Linux 网络调优高级篇：内核参数与性能压测"},{"content":"基础语法 Shebang 和执行 #!/bin/bash # 或 #!/usr/bin/env bash # 执行方式 chmod +x script.sh ./script.sh # 或直接执行 bash script.sh 变量 # 赋值（等号两边不能有空格） name=\u0026#34;John\u0026#34; age=25 readonly PI=3.14 # 只读变量 # 使用变量 echo \u0026#34;Name: $name\u0026#34; echo \u0026#34;Name: ${name}\u0026#34; echo \u0026#34;Length: ${#name}\u0026#34; # 字符串长度 # 默认值 ${var:-default} # var 未定义或为空时使用 default ${var:=default} # var 未定义或为空时赋值为 default ${var:+value} # var 已定义且非空时使用 value ${var:?error msg} # var 未定义或为空时报错 # 字符串操作 ${string:offset:length} # 子串 ${string#pattern} # 删除左边最短匹配 ${string##pattern} # 删除左边最长匹配 ${string%pattern} # 删除右边最短匹配 ${string%%pattern} # 删除右边最长匹配 ${string/pattern/replacement} # 替换 数组 # 索引数组 arr=(apple banana cherry) arr[0]=\u0026#34;apple\u0026#34; arr[1]=\u0026#34;banana\u0026#34; # 访问 echo ${arr[0]} # 第一个元素 echo ${arr[@]} # 所有元素 echo ${#arr[@]} # 数组长度 echo ${arr[@]:1:2} # 从索引1开始取2个 # 关联数组 declare -A map map[name]=\u0026#34;John\u0026#34; map[age]=25 echo ${map[name]} echo ${!map[@]} # 所有键 echo ${map[@]} # 所有值 流程控制 条件判断 # if 语句 if [ condition ]; then # commands elif [ condition ]; then # commands else # commands fi # 常用条件 [ -f file ] # 文件存在且是普通文件 [ -d dir ] # 目录存在 [ -r file ] # 文件可读 [ -w file ] # 文件可写 [ -x file ] # 文件可执行 [ -s file ] # 文件非空 [ -z string ] # 字符串为空 [ -n string ] # 字符串非空 [ \u0026#34;$a\u0026#34; = \u0026#34;$b\u0026#34; ] # 字符串相等 [ \u0026#34;$a\u0026#34; != \u0026#34;$b\u0026#34; ] # 字符串不相等 [ $a -eq $b ] # 数值相等 [ $a -gt $b ] # 数值大于 [ $a -lt $b ] # 数值小于 [ $a -ge $b ] # 数值大于等于 [ $a -le $b ] # 数值小于等于 # [[ ]] 增强版（支持正则） [[ $string =~ pattern ]] # 正则匹配 [[ $a == $b ]] # 字符串比较 [[ $a -gt $b \u0026amp;\u0026amp; $c -lt $d ]] # 逻辑与 # case 语句 case $var in pattern1) # commands ;; pattern2) # commands ;; *) # default ;; esac 循环 # for 循环 for i in 1 2 3 4 5; do echo $i done # C 风格 for for ((i=0; i\u0026lt;10; i++)); do echo $i done # 范围 for i in {1..10}; do echo $i done # 带步长 for i in {0..100..5}; do echo $i done # 遍历文件 for file in /var/log/*.log; do echo \u0026#34;Processing: $file\u0026#34; done # while 循环 while [ condition ]; do # commands done # 读取文件 while IFS= read -r line; do echo \u0026#34;Line: $line\u0026#34; done \u0026lt; file.txt # 无限循环 while true; do # commands sleep 1 done # until 循环（条件为假时执行） until [ condition ]; do # commands done # break 和 continue for i in {1..10}; do if [ $i -eq 5 ]; then continue # 跳过本次 fi if [ $i -eq 8 ]; then break # 跳出循环 fi echo $i done 函数 # 定义函数 function greet() { echo \u0026#34;Hello, $1!\u0026#34; } # 或简写 greet() { echo \u0026#34;Hello, $1!\u0026#34; } # 调用 greet \u0026#34;John\u0026#34; # 返回值 add() { echo $(( $1 + $2 )) } result=$(add 3 5) # 返回状态码 check_file() { if [ -f \u0026#34;$1\u0026#34; ]; then return 0 # 成功 else return 1 # 失败 fi } if check_file \u0026#34;/etc/passwd\u0026#34;; then echo \u0026#34;File exists\u0026#34; fi # 局部变量 myfunc() { local var=\u0026#34;local\u0026#34; echo $var } 文本处理 grep # 基本搜索 grep \u0026#34;pattern\u0026#34; file.txt # 选项 -i # 忽略大小写 -r # 递归搜索 -n # 显示行号 -c # 只显示匹配数量 -l # 只显示文件名 -v # 反向匹配 -w # 全词匹配 -e # 多个模式 -E # 扩展正则 -P # Perl 正则 # 示例 grep -rn \u0026#34;error\u0026#34; /var/log/ grep -i \u0026#34;warning\u0026#34; *.log grep -E \u0026#34;^[0-9]{4}-[0-9]{2}\u0026#34; log.txt sed # 替换 sed \u0026#39;s/old/new/\u0026#39; file.txt sed \u0026#39;s/old/new/g\u0026#39; file.txt # 全局替换 sed -i \u0026#39;s/old/new/g\u0026#39; file.txt # 原地修改 # 删除 sed \u0026#39;/pattern/d\u0026#39; file.txt sed \u0026#39;1,5d\u0026#39; file.txt # 删除1-5行 # 插入 sed \u0026#39;3i\\new line\u0026#39; file.txt # 在第3行前插入 sed \u0026#39;3a\\new line\u0026#39; file.txt # 在第3行后插入 # 打印 sed -n \u0026#39;1,5p\u0026#39; file.txt # 打印1-5行 sed -n \u0026#39;/pattern/p\u0026#39; file.txt # 打印匹配行 # 常用示例 sed \u0026#39;s/[[:space:]]*$//\u0026#39; file.txt # 删除行尾空格 sed \u0026#39;/^$/d\u0026#39; file.txt # 删除空行 sed \u0026#39;s/^[[:space:]]*//\u0026#39; file.txt # 删除行首空格 awk # 基本语法 awk \u0026#39;{print $1, $3}\u0026#39; file.txt # 打印第1和第3列 # 条件过滤 awk \u0026#39;$3 \u0026gt; 100\u0026#39; file.txt awk \u0026#39;/pattern/ {print $1}\u0026#39; file.txt # 内置变量 NR # 当前行号 NF # 当前行字段数 $0 # 整行 $1-$n # 第1到第n个字段 # BEGIN/END awk \u0026#39;BEGIN {print \u0026#34;Start\u0026#34;} {print $1} END {print \u0026#34;End\u0026#34;}\u0026#39; file.txt # 计算 awk \u0026#39;{sum += $1} END {print sum}\u0026#39; file.txt awk \u0026#39;{avg += $1} END {print avg/NR}\u0026#39; file.txt # 格式化输出 awk \u0026#39;{printf \u0026#34;%-20s %10d\\n\u0026#34;, $1, $2}\u0026#39; file.txt # 字段分隔符 awk -F: \u0026#39;{print $1, $3}\u0026#39; /etc/passwd awk -F\u0026#39;,\u0026#39; \u0026#39;{print $1}\u0026#39; data.csv cut # 按字符 cut -c1-5 file.txt # 按字段 cut -d: -f1,3 /etc/passwd # 按字节 cut -b1-10 file.txt sort sort file.txt # 字母排序 sort -n file.txt # 数值排序 sort -r file.txt # 逆序 sort -k2 -t: file.txt # 按第2列排序，分隔符为: sort -u file.txt # 去重 sort -h file.txt # 人类可读排序（1K, 2M, 3G） uniq sort file.txt | uniq # 去重 sort file.txt | uniq -c # 计数 sort file.txt | uniq -d # 只显示重复行 sort file.txt | uniq -u # 只显示唯一行 高级特性 进程替换 # 比较两个命令的输出 diff \u0026lt;(ls /dir1) \u0026lt;(ls /dir2) # 同时读取多个文件 while read line1 \u0026lt;\u0026amp;3 \u0026amp;\u0026amp; read line2 \u0026lt;\u0026amp;4; do echo \u0026#34;File1: $line1, File2: $line2\u0026#34; done 3\u0026lt; file1.txt 4\u0026lt; file2.txt 陷阱处理 # 清理临时文件 cleanup() { rm -f \u0026#34;$tmpfile\u0026#34; echo \u0026#34;Cleaned up\u0026#34; } trap cleanup EXIT # 忽略信号 trap \u0026#39;\u0026#39; SIGINT SIGTERM # 捕获错误 trap \u0026#39;echo \u0026#34;Error on line $LINENO\u0026#34;\u0026#39; ERR Here Document # 基本用法 cat \u0026lt;\u0026lt; EOF This is a heredoc Variable: $name EOF # 不解析变量 cat \u0026lt;\u0026lt; \u0026#39;EOF\u0026#39; This is a heredoc Variable: $name will not be expanded EOF # 缩进 cat \u0026lt;\u0026lt;- EOF This heredoc allows tabs for indentation EOF 子 Shell # 在子 Shell 中执行 ( cd /tmp ls -la ) # 当前目录不变 # 命令组 { echo \u0026#34;Line 1\u0026#34; echo \u0026#34;Line 2\u0026#34; } \u0026gt; output.txt 实战案例 系统监控脚本 #!/bin/bash LOG_FILE=\u0026#34;/var/log/monitor.log\u0026#34; log() { echo \u0026#34;$(date \u0026#39;+%Y-%m-%d %H:%M:%S\u0026#39;) $1\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG_FILE\u0026#34; } check_disk() { usage=$(df -h / | awk \u0026#39;NR==2{print $5}\u0026#39; | tr -d \u0026#39;%\u0026#39;) if [ \u0026#34;$usage\u0026#34; -gt 80 ]; then log \u0026#34;WARNING: Disk usage is ${usage}%\u0026#34; fi } check_memory() { free -m | awk \u0026#39;NR==2{printf \u0026#34;Memory: %.1f%%\\n\u0026#34;, $3*100/$2}\u0026#39; } check_load() { load=$(uptime | awk -F\u0026#39;load average:\u0026#39; \u0026#39;{print $2}\u0026#39; | awk -F, \u0026#39;{print $1}\u0026#39;) if [ $(echo \u0026#34;$load \u0026gt; 2.0\u0026#34; | bc) -eq 1 ]; then log \u0026#34;WARNING: Load average is $load\u0026#34; fi } while true; do check_disk check_memory check_load sleep 60 done 自动备份脚本 #!/bin/bash BACKUP_DIR=\u0026#34;/backup\u0026#34; SOURCE_DIR=\u0026#34;/var/www\u0026#34; DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE=\u0026#34;$BACKUP_DIR/backup_$DATE.tar.gz\u0026#34; mkdir -p \u0026#34;$BACKUP_DIR\u0026#34; tar -czf \u0026#34;$BACKUP_FILE\u0026#34; \u0026#34;$SOURCE_DIR\u0026#34; # 保留最近7天的备份 find \u0026#34;$BACKUP_DIR\u0026#34; -name \u0026#34;backup_*.tar.gz\u0026#34; -mtime +7 -delete echo \u0026#34;Backup completed: $BACKUP_FILE\u0026#34; 批量重命名 #!/bin/bash # 批量添加前缀 for file in *.txt; do mv \u0026#34;$file\u0026#34; \u0026#34;prefix_$file\u0026#34; done # 批量修改扩展名 for file in *.jpeg; do mv \u0026#34;$file\u0026#34; \u0026#34;${file%.jpeg}.jpg\u0026#34; done # 批量重命名为序号 i=1 for file in *.jpg; do mv \u0026#34;$file\u0026#34; \u0026#34;$(printf \u0026#39;%03d\u0026#39; $i).jpg\u0026#34; ((i++)) done 日志分析 #!/bin/bash LOG_FILE=\u0026#34;/var/log/access.log\u0026#34; echo \u0026#34;=== 访问统计 ===\u0026#34; awk \u0026#39;{print $1}\u0026#39; \u0026#34;$LOG_FILE\u0026#34; | sort | uniq -c | sort -rn | head -10 echo \u0026#34;\u0026#34; echo \u0026#34;=== 错误统计 ===\u0026#34; grep -c \u0026#34;500\\|502\\|503\u0026#34; \u0026#34;$LOG_FILE\u0026#34; echo \u0026#34;\u0026#34; echo \u0026#34;=== 每小时访问量 ===\u0026#34; awk \u0026#39;{print $4}\u0026#39; \u0026#34;$LOG_FILE\u0026#34; | cut -d: -f2 | sort | uniq -c | sort -n 面试常见问题 $@ 和 $* 的区别？\n$@: 每个参数作为独立字符串 $*: 所有参数作为一个字符串 建议始终使用 \u0026quot;$@\u0026quot; [[ ]] 和 [ ] 的区别？\n[[ ]] 是 bash 增强版 支持正则、模式匹配 更安全，不需要引号 如何捕获命令输出？\nvar=$(command): 捕获标准输出 var=$(command 2\u0026gt;\u0026amp;1): 捕获所有输出 command | var: 管道捕获 如何调试 bash 脚本？\nbash -x script.sh: 显示执行过程 set -x: 在脚本中开启调试 set -e: 遇到错误立即退出 set -u: 使用未定义变量时报错 ","permalink":"https://blog.geek.16775390.xyz/posts/bash-scripting-bible/","summary":"全面覆盖 Bash 脚本编程：变量、流程控制、函数、数组、正则、文本处理、实战案例。","title":"Bash 脚本圣经：从入门到精通的完整指南"},{"content":"两大应用范式 大语言模型有两种主要的应用范式：\nRAG（检索增强生成）：让模型\u0026quot;查资料\u0026quot;后回答 Agent 系统：让模型\u0026quot;使用工具\u0026quot;完成任务 RAG 架构 核心思想 传统 LLM: 用户问题 → 模型 → 回答 (可能过时/幻觉) RAG: 用户问题 → 检索相关文档 → 模型 + 文档 → 回答 (准确/有据) 完整流程 RAG Pipeline: ┌─────────────────────────────────────┐ │ 索引阶段 │ │ 文档 → 分块 → 向量化 → 存储 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 检索阶段 │ │ 问题 → 向量化 → 相似度搜索 → Top-K │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 生成阶段 │ │ 问题 + 检索结果 → LLM → 回答 │ └─────────────────────────────────────┘ 文档分块策略 # 固定大小分块 def fixed_size_chunk(text, chunk_size=512, overlap=50): chunks = [] for i in range(0, len(text), chunk_size - overlap): chunks.append(text[i:i + chunk_size]) return chunks # 语义分块 def semantic_chunk(text, model): sentences = split_sentences(text) embeddings = model.encode(sentences) # 基于语义相似度分块 chunks = [] current_chunk = [sentences[0]] for i in range(1, len(sentences)): similarity = cosine_similarity( embeddings[i], embeddings[i-1] ) if similarity \u0026lt; 0.5: # 阈值 chunks.append(\u0026#39; \u0026#39;.join(current_chunk)) current_chunk = [sentences[i]] else: current_chunk.append(sentences[i]) return chunks 向量数据库 # Chroma (轻量级) import chromadb client = chromadb.Client() collection = client.create_collection(\u0026#34;docs\u0026#34;) # 添加文档 collection.add( documents=[\u0026#34;doc1\u0026#34;, \u0026#34;doc2\u0026#34;], ids=[\u0026#34;id1\u0026#34;, \u0026#34;id2\u0026#34;] ) # 查询 results = collection.query( query_texts=[\u0026#34;query\u0026#34;], n_results=5 ) # Pinecone (云服务) import pinecone pinecone.init(api_key=\u0026#34;xxx\u0026#34;) index = pinecone.Index(\u0026#34;my-index\u0026#34;) # 向量化并存储 vectors = model.encode(documents) index.upsert(vectors) # 查询 results = index.query(vector=query_embedding, top_k=5) 检索策略 1. 稠密检索 (Dense Retrieval): - 使用向量相似度（余弦、点积） - 捕捉语义相似性 - 例: \u0026#34;猫\u0026#34; 和 \u0026#34;小猫\u0026#34; 相似度高 2. 稀疏检索 (Sparse Retrieval): - 使用 BM25 等关键词匹配 - 精确匹配关键词 - 例: 搜索 \u0026#34;Python\u0026#34; 精确匹配 3. 混合检索 (Hybrid Retrieval): - 结合稠密和稀疏检索 - 取长补短，效果最好 - 例: 语义搜索 + 关键词过滤 重排序 # 检索后重排序 def rerank(query, documents, model): # 计算 query-document 相关性分数 scores = [] for doc in documents: score = model.score(query, doc) scores.append(score) # 按分数排序 ranked = sorted( zip(documents, scores), key=lambda x: x[1], reverse=True ) return ranked # 交叉编码器重排序 from sentence_transformers import CrossEncoder reranker = CrossEncoder(\u0026#39;cross-encoder/ms-marco-MiniLM-L-6-v2\u0026#39;) scores = reranker.predict([(query, doc) for doc in documents]) Agent 系统 核心思想 Agent = LLM + 工具 + 记忆 + 规划 用户任务 → Agent 规划 → 选择工具 → 执行 → 观察 → 调整 → 完成 架构设计 Agent 系统架构: ┌─────────────────────────────────────┐ │ 规划模块 │ │ 任务分解、策略选择、反思调整 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 执行模块 │ │ 工具调用、代码执行、API 调用 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 记忆模块 │ │ 短期记忆、长期记忆、工作记忆 │ └─────────────────────────────────────┘ ReAct 框架 ReAct (Reasoning + Acting): 思考 (Thought): 分析当前状态，决定下一步 行动 (Action): 选择并执行工具 观察 (Observation): 获取工具返回结果 循环直到完成 示例: Thought: 我需要查找今天的天气 Action: search_weather(\u0026#34;北京\u0026#34;) Observation: 北京今天晴，25°C Thought: 我已经获取了天气信息，可以回答用户 Action: respond(\u0026#34;北京今天晴，25°C\u0026#34;) 工具调用 # LangChain Agent 示例 from langchain.agents import initialize_agent from langchain.tools import Tool from langchain.llms import OpenAI # 定义工具 tools = [ Tool( name=\u0026#34;Search\u0026#34;, func=search_web, description=\u0026#34;搜索网页信息\u0026#34; ), Tool( name=\u0026#34;Calculator\u0026#34;, func=calculate, description=\u0026#34;数学计算\u0026#34; ) ] # 创建 Agent llm = OpenAI(temperature=0) agent = initialize_agent( tools, llm, agent=\u0026#34;react-docstore\u0026#34; ) # 执行任务 result = agent.run(\u0026#34;今天北京的天气怎么样？\u0026#34;) 多 Agent 协作 # AutoGen 多 Agent 示例 from autogen import AssistantAgent, UserProxyAgent # 创建 Agent assistant = AssistantAgent( name=\u0026#34;assistant\u0026#34;, llm_config={\u0026#34;model\u0026#34;: \u0026#34;gpt-4\u0026#34;} ) user_proxy = UserProxyAgent( name=\u0026#34;user_proxy\u0026#34;, human_input_mode=\u0026#34;NEVER\u0026#34; ) # 注册工具 user_proxy.register_for_execution( name=\u0026#34;search\u0026#34;, func=search_web ) # 对话 user_proxy.initiate_chat( assistant, message=\u0026#34;帮我分析这个数据集的趋势\u0026#34; ) RAG vs Agent 对比 特性 RAG Agent 核心能力 检索 + 生成 规划 + 工具使用 数据来源 预定义文档库 实时工具调用 可控性 高（基于文档） 中（依赖工具） 延迟 低（一次检索） 高（多轮交互） 适用场景 知识问答、文档检索 复杂任务、动态决策 混合架构 RAG + Agent: 1. Agent 规划阶段: - 分析任务需要什么信息 - 决定是否需要检索 2. RAG 检索阶段: - 检索相关文档 - 返回给 Agent 3. Agent 执行阶段: - 基于检索结果决策 - 可能调用其他工具 4. 迭代优化: - 如果信息不足，再次检索 - 直到任务完成 面试常见问题 RAG 如何处理幻觉问题？\n检索真实文档作为依据 要求模型引用来源 后处理验证事实性 Agent 如何处理工具调用失败？\n重试机制 备选工具 反思和调整策略 如何评估 RAG 系统？\n检索指标: Recall@K, MRR 生成指标: BLEU, ROUGE 端到端: 人工评估 多 Agent 协作的挑战？\n通信开销 决策一致性 错误传播 实战: 搭建 RAG 系统 from langchain.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings # 加载文档 loader = TextLoader(\u0026#34;docs.txt\u0026#34;) documents = loader.load() # 分块 splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50 ) chunks = splitter.split_documents(documents) # 向量化存储 embeddings = OpenAIEmbeddings() vectorstore = Chroma.from_documents( chunks, embeddings ) # 检索 query = \u0026#34;什么是 Transformer？\u0026#34; results = vectorstore.similarity_search(query, k=3) ","permalink":"https://blog.geek.16775390.xyz/posts/rag-agent-system/","summary":"深入解析 RAG（检索增强生成）和 Agent 系统的架构设计、实现方案、以及实际应用场景。","title":"RAG 与 Agent 系统：大模型应用的两大范式"},{"content":"Transformer 的诞生 2017 年，Google 发表了划时代论文《Attention Is All You Need》，提出了 Transformer 架构。它彻底改变了 NLP 领域，成为现代大语言模型的基石。\n核心思想：自注意力机制 传统 RNN 的问题 RNN 处理序列: h1 = f(x1, h0) h2 = f(x2, h1) h3 = f(x3, h2) ... hn = f(xn, hn-1) 问题: 1. 顺序计算，无法并行 2. 长距离依赖难以捕捉 3. 梯度消失/爆炸 自注意力机制 自注意力计算: Q = X * Wq (查询矩阵) K = X * Wk (键矩阵) V = X * Wv (值矩阵) Attention(Q, K, V) = softmax(Q * K^T / √dk) * V 示例: 输入: \u0026#34;我 爱 中国\u0026#34; Q: [0.2, 0.8, 0.1] ← 每个词对其他词的\u0026#34;关注度\u0026#34; K: [0.3, 0.6, 0.4] V: [0.1, 0.4, 0.2] 结果: 每个词都融合了整个序列的信息 多头注意力 多头注意力: Head 1: Attention(Q*W1, K*W1, V*W1) ← 关注语法 Head 2: Attention(Q*W2, K*W2, V*W2) ← 关注语义 Head 3: Attention(Q*W3, K*W3, V*W3) ← 关注上下文 ... Head h: Attention(Q*Wh, K*Wh, V*Wh) 输出: Concat(Head1, Head2, ..., Headh) * Wo Transformer 架构 编码器-解码器结构 Transformer: ┌─────────────────────────────────────┐ │ 解码器 (Decoder) │ │ ┌─────────────────────────────┐ │ │ │ 掩码多头注意力 │ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ 交叉注意力 │ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ 前馈网络 │ │ │ └─────────────────────────────┘ │ ├─────────────────────────────────────┤ │ 编码器 (Encoder) │ │ ┌─────────────────────────────┐ │ │ │ 多头注意力 │ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ 前馈网络 │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘ 位置编码 正弦位置编码: PE(pos, 2i) = sin(pos / 10000^(2i/d)) PE(pos, 2i+1) = cos(pos / 10000^(2i/d)) 示例 (d=4): 位置 0: [0, 1, 0, 1] 位置 1: [0.84, 0.54, 0.84, 0.54] 位置 2: [0.91, 0.41, 0.91, 0.41] 作用: 让模型知道每个词的位置 GPT 系列演进 GPT-1 (2018) 架构: - 12 层 Transformer 解码器 - 117M 参数 - 预训练 + 微调范式 训练: 1. 预训练: 在大规模语料上预测下一个词 2. 微调: 在特定任务上训练 局限: - 参数量小 - 通用能力有限 GPT-2 (2019) 架构: - 48 层 Transformer 解码器 - 1.5B 参数 - 零样本学习 创新: 1. 更大的模型容量 2. 证明了规模的重要性 3. 引发了 AI 安全讨论 GPT-3 (2020) 架构: - 96 层 Transformer 解码器 - 175B 参数 - 少样本学习 (In-Context Learning) 能力涌现: 1. 少样本学习: 只给几个示例就能完成任务 2. 零样本泛化: 不需要训练就能处理新任务 3. 涌现能力: 规模带来的质变 GPT-4 (2023) 特点: - 多模态: 支持图像和文本输入 - 更长上下文: 8K/32K/128K tokens - 更强推理: 改进的逻辑推理能力 - 更安全: 更好的对齐和安全控制 训练技术 预训练目标 因果语言建模 (Causal LM): 输入: \u0026#34;我 爱 中\u0026#34; 目标: \u0026#34;爱 中 国\u0026#34; 训练目标: P(爱|我) * P(中|我,爱) * P(国|我,爱,中) 损失函数: -log P(下一个词 | 上下文) 对齐技术 RLHF (人类反馈强化学习): 1. 监督微调 (SFT): 用人工标注数据训练 2. 奖励模型 (RM): 学习人类偏好 3. PPO 优化: 使用强化学习优化策略 示例: 人类标注: 回答A \u0026gt; 回答B 奖励模型: 学习这个偏好 PPO: 调整模型参数，生成更符合偏好的回答 推理优化 KV Cache 问题: 每个 token 都需要重新计算所有层的 K 和 V 计算复杂度: O(n²) 解决: 缓存已计算的 K 和 V 新 token 只需要计算自己的 Q 计算复杂度: O(n) 内存占用: 每层: 2 * seq_len * hidden_dim * precision 总内存: n_layers * 2 * seq_len * hidden_dim * precision 量化 FP32 → FP16: 内存减半，精度损失小 FP32 → INT8: 内存减 4 倍，需要校准 FP32 → INT4: 内存减 8 倍，精度损失较大 GPTQ/AWQ: 训练时量化，保持精度 面试常见问题 Transformer 为什么比 RNN 好？\n并行计算: 所有位置同时计算 长距离依赖: 自注意力直接连接任意位置 梯度稳定: 不存在梯度消失问题 自注意力的复杂度？\n时间复杂度: O(n² * d) 空间复杂度: O(n²) n 是序列长度，d 是隐藏维度 为什么 GPT 用解码器而不用编码器？\n解码器支持自回归生成 编码器用于理解，解码器用于生成 GPT 的目标是生成文本 涌现能力是什么？\n模型规模达到一定程度后突然出现的能力 小模型没有，大模型有 例: 少样本学习、复杂推理 实战: 使用 Transformers from transformers import AutoTokenizer, AutoModelForCausalLM # 加载模型 model_name = \u0026#34;gpt2\u0026#34; tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained(model_name) # 生成文本 input_text = \u0026#34;The future of AI is\u0026#34; inputs = tokenizer(input_text, return_tensors=\u0026#34;pt\u0026#34;) outputs = model.generate(**inputs, max_length=50) print(tokenizer.decode(outputs[0])) ","permalink":"https://blog.geek.16775390.xyz/posts/llm-transformer-architecture/","summary":"深入解析 Transformer 架构、自注意力机制、位置编码、以及从 GPT-1 到 GPT-4 的演进。","title":"大语言模型架构详解：从 Transformer 到 GPT"},{"content":"TLS 1.3 的革命性改进 TLS 1.3 是 TLS 协议的重大升级，主要改进：\n握手延迟降低：3-RTT → 1-RTT（首次），0-RTT（恢复） 移除不安全算法：RC4、3DES、CBC 模式、SHA-1 等 强制前向保密：所有密码套件都支持 PFS 简化密码套件：从 300+ 减少到 5 个 TLS 1.2 vs TLS 1.3 握手对比 TLS 1.2 握手 (2-RTT): 客户端 → 服务器: ClientHello (支持的密码套件列表) 服务器 → 客户端: ServerHello + Certificate + ServerKeyExchange + ServerHelloDone 客户端 → 服务器: ClientKeyExchange + ChangeCipherSpec + Finished 服务器 → 客户端: ChangeCipherSpec + Finished TLS 1.3 握手 (1-RTT): 客户端 → 服务器: ClientHello + KeyShare 服务器 → 服务器: ServerHello + KeyShare + Certificate + Finished 密码套件对比 TLS 1.2 密码套件 (部分): TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ... (300+ 种) TLS 1.3 密码套件 (全部): TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_CCM_SHA256 TLS_AES_128_CCM_8_SHA256 TLS 1.3 握手详解 完整握手流程 步骤 1: ClientHello ┌─────────────────────────────────────────┐ │ 协议版本: TLS 1.3 │ │ 随机数: 32 字节随机值 │ │ 密码套件: [TLS_AES_256_GCM_SHA384, ...] │ │ 扩展: │ │ - key_share: X25519 公钥 │ │ - supported_versions: TLS 1.3 │ │ - signature_algorithms: ecdsa_secp256 │ └─────────────────────────────────────────┘ 步骤 2: ServerHello ┌─────────────────────────────────────────┐ │ 协议版本: TLS 1.3 │ │ 随机数: 32 字节随机值 │ │ 密码套件: TLS_AES_256_GCM_SHA384 │ │ 扩展: │ │ - key_share: X25519 公钥 │ │ - encrypted_extensions: 加密扩展 │ │ - certificate: 服务器证书 │ │ - certificate_verify: 签名验证 │ │ - finished: HMAC 验证 │ └─────────────────────────────────────────┘ 步骤 3: 客户端验证 ┌─────────────────────────────────────────┐ │ 验证服务器证书 │ │ 验证签名 │ │ 生成会话密钥 │ │ 发送 Finished │ └─────────────────────────────────────────┘ 密钥交换 X25519 密钥交换: 客户端生成: a (私钥), A = a * G (公钥) 服务器生成: b (私钥), B = b * G (公钥) 共享密钥: S = a * B = b * A = a * b * G 前向保密: 即使服务器私钥泄露，过去的会话密钥也无法计算 前向保密（PFS） 什么是前向保密 无 PFS: 服务器私钥 → 解密所有历史会话 有 PFS: 服务器私钥 → 无法解密历史会话 每次会话使用临时密钥 → 密钥不重复使用 ECDHE 实现 ECDHE (Elliptic Curve Diffie-Hellman Ephemeral): 每次握手生成新的临时密钥对 会话密钥 = 私钥 * 对方公钥 私钥用完即丢弃 0-RTT 恢复 会话票据 首次连接: 客户端 → 服务器: ClientHello 服务器 → 客户端: ServerHello + NewSessionTicket 客户端保存: 会话票据 + PSK (预共享密钥) 恢复连接: 客户端 → 服务器: ClientHello + PSK + 0-RTT 数据 服务器 → 客户端: ServerHello + Finished + 0-RTT 数据 0-RTT 的安全风险 重放攻击: 攻击者截获 0-RTT 数据 → 重放给服务器 防御措施: 1. 只允许幂等请求（GET、HEAD） 2. 服务器维护 0-RTT 数据 nonce 池 3. 限制 0-RTT 数据大小 密码学基础 对称加密 AES-GCM: - 加密: AES-128/256-GCM - 认证: GCM 模式提供完整性 - 性能: 硬件加速（AES-NI） ChaCha20-Poly1305: - 加密: ChaCha20 流密码 - 认证: Poly1305 MAC - 优势: 无硬件加速时更快 非对称加密 ECDH 密钥交换: - 曲线: X25519、P-256、P-384 - 安全性: 基于椭圆曲线离散对数问题 - 性能: 比 RSA 快 10 倍以上 数字签名: - 算法: ECDSA、EdDSA - 用途: 验证证书真实性 实战配置 Nginx TLS 1.3 配置 server { listen 443 ssl; # TLS 版本 ssl_protocols TLSv1.3; # 密码套件 ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; # 证书 ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; # 会话配置 ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; } 证书生成 # 生成 ECC 密钥 openssl ecparam -genkey -name prime256v1 -out server.key # 生成 CSR openssl req -new -key server.key -out server.csr # 自签名证书 openssl req -x509 -nodes -days 365 -newkey ec:\u0026lt;(openssl ecparam -name prime256v1) \\ -keyout server.key -out server.crt 面试常见问题 TLS 1.3 为什么更快？\n减少握手轮次（1-RTT vs 2-RTT） 使用更快的密码算法（AES-NI、X25519） 支持 0-RTT 恢复 前向保密如何实现？\n使用临时密钥交换（ECDHE） 每次会话生成新密钥 私钥用完即丢弃 0-RTT 的局限性？\n可能被重放攻击 只能发送幂等请求 服务器需要额外验证 TLS 1.3 的密码套件为什么这么少？\n移除不安全算法 简化配置，减少错误 所有套件都支持 PFS 调试工具 # 测试 TLS 配置 openssl s_client -connect example.com:443 -tls1_3 # 查看证书链 openssl s_client -connect example.com:443 -showcerts # 测试密码套件 nmap --script ssl-enum-ciphers -p 443 example.com # 在线工具 # https://www.ssllabs.com/ssltest/ ","permalink":"https://blog.geek.16775390.xyz/posts/tls-13-handshake/","summary":"深入解析 TLS 1.3 握手过程、密码套件选择、前向保密原理，以及与 TLS 1.2 的对比。","title":"TLS 1.3 握手全流程：安全与性能的完美平衡"},{"content":"为什么需要 HTTP/3 HTTP/2 虽然引入了多路复用、头部压缩、服务器推送等优化，但仍存在根本性问题：\n队头阻塞（Head-of-Line Blocking）\nHTTP/2 over TCP: Stream 1: [Packet 1] [Packet 2] [Packet 3] ← 如果 Packet 2 丢失 Stream 2: [Packet 1] [Packet 2] [Packet 3] ← 整个连接被阻塞 Stream 3: [Packet 1] [Packet 2] [Packet 3] ← 必须等待重传 TCP 是字节流协议，它不理解 HTTP/2 的流概念。一个包丢失会导致整个 TCP 连接阻塞，所有流都受影响。\nQUIC 协议设计 核心特性 QUIC (Quick UDP Internet Connections): ┌─────────────────────────────────────────┐ │ QUIC 头部 │ │ Connection ID | Packet Number | Flags │ ├─────────────────────────────────────────┤ │ 加密载荷 │ │ (TLS 1.3 + 自定义加密) │ ├─────────────────────────────────────────┤ │ 流控制 │ │ Stream 1: 独立流控 │ │ Stream 2: 独立流控 │ │ Stream 3: 独立流控 │ └─────────────────────────────────────────┘ 0-RTT 连接建立 传统 TCP + TLS 1.3: 客户端 → 服务器: SYN 服务器 → 客户端: SYN-ACK 客户端 → 服务器: ACK + ClientHello 服务器 → 客户端: ServerHello + Finished 客户端 → 服务器: Finished 客户端 → 服务器: HTTP 请求 总延迟: 2-RTT (TCP) + 1-RTT (TLS) = 3-RTT QUIC: 客户端 → 服务器: Initial + ClientHello + HTTP 请求 服务器 → 客户端: ServerHello + Finished + HTTP 响应 总延迟: 1-RTT (首次) / 0-RTT (恢复) 连接迁移 TCP 连接由四元组标识：(源IP, 源端口, 目标IP, 目标端口)\nWiFi → 4G 切换: TCP: 四元组变化 → 连接断开 → 重新建立 QUIC: Connection ID 不变 → 无缝迁移 QUIC 使用 Connection ID 而非四元组标识连接，网络切换时连接不中断。\nHTTP/3 架构 HTTP/3 协议栈: ┌─────────────────────────────────────┐ │ HTTP/3 (应用层) │ ├─────────────────────────────────────┤ │ QUIC (传输层) │ ├─────────────────────────────────────┤ │ UDP │ ├─────────────────────────────────────┤ │ IP │ └─────────────────────────────────────┘ 流多路复用 QUIC 流复用: Stream 1: [Frame 1] [Frame 2] [Frame 3] ← 独立流控 Stream 2: [Frame 1] [Frame 2] [Frame 3] ← 独立流控 Stream 3: [Frame 1] [Frame 2] [Frame 3] ← 独立流控 一个流丢包 → 只影响该流，其他流继续传输 丢包恢复 TCP 丢包恢复: Packet 2 丢失 → 等待超时 → 重传 → 所有流阻塞 QUIC 丢包恢复: Packet 2 丢失 → 只重传 Stream 2 → 其他流不受影响 性能对比 延迟对比 场景 HTTP/1.1 HTTP/2 HTTP/3 首次连接 3-RTT 3-RTT 1-RTT 连接恢复 1-RTT 1-RTT 0-RTT 网络切换 断开重连 断开重连 无缝迁移 丢包恢复 全连接阻塞 全连接阻塞 单流恢复 带宽利用 HTTP/2 over TCP: - TCP 拥塞控制：全局共享 - 一个流慢 → 所有流受影响 - 无法充分利用带宽 HTTP/3 over QUIC: - 每个流独立拥塞控制 - 一个流慢 → 其他流不受影响 - 更好的带宽利用 实际部署 Nginx 配置 HTTP/3 server { listen 443 quic; listen 443 ssl; http2 on; # QUIC 参数 add_header Alt-Svc \u0026#39;h3=\u0026#34;:443\u0026#34;; ma=86400\u0026#39;; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; # TLS 1.3 配置 ssl_protocols TLSv1.3; ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; } 客户端支持 # Chrome/Edge: 自动支持 # Firefox: 需要手动启用 about:config → network.http.http3.enable = true # curl 测试 curl --http3 https://example.com QUIC 的挑战 UDP 限制 问题: 1. 部分运营商限制 UDP 流量 2. 企业防火墙可能阻止 UDP 3. 某些 NAT 设备对 UDP 支持不好 解决方案: 1. 使用 UDP 443 端口（最常用） 2. 降级到 TCP（回退机制） 3. 使用中间件代理 QUIC 流量 拥塞控制 QUIC 实现了多种拥塞控制算法：\n// Google BBR 拥塞控制 struct bbr { uint64_t bandwidth; // 带宽估计 uint64_t rtt; // 延迟估计 uint32_t cwnd; // 拥塞窗口 uint32_t pacing_rate; // 发送速率 }; 面试常见问题 HTTP/3 为什么基于 UDP？\nTCP 协议栈固化在内核中，难以修改 UDP 提供灵活的传输层，可以在用户态实现新特性 避免 TCP 的队头阻塞问题 QUIC 如何保证可靠性？\n在 UDP 上实现类似 TCP 的可靠性机制 使用 ACK 帧确认接收 实现超时重传和快速重传 0-RTT 的安全性？\n0-RTT 数据可能被重放攻击 只用于幂等请求（如 GET） 服务器可选择性接受 0-RTT 数据 HTTP/3 的缺点？\nUDP 可能被限制 实现复杂度高 调试工具支持有限 实战：QUIC 性能测试 # 安装 quic-trace go install github.com/marten-seemann/quic-trace@latest # 分析 QUIC 连接 quic-trace client www.example.com:443 # 使用 qvis 可视化 # https://qvis.quictools.info/ ","permalink":"https://blog.geek.16775390.xyz/posts/http3-quic-deep-dive/","summary":"深入解析 HTTP/3 和 QUIC 协议的设计原理、性能优势、以及与 HTTP/2 的对比分析。","title":"HTTP/3 与 QUIC 协议深度解析：下一代 Web 传输"},{"content":"DNS 的本质 DNS 本质上是一个分布式数据库，将人类可读的域名映射为机器可读的 IP 地址。它的设计目标是：去中心化、高可用、高性能。\n完整解析链路 当你在浏览器输入 www.google.com 时，DNS 解析经历以下步骤：\n浏览器缓存 → OS 缓存 → hosts 文件 → 本地 DNS 服务器 → 根DNS → 顶级域DNS → 权威DNS 第一步：本地缓存查询 1. 浏览器 DNS 缓存（Chrome: chrome://net-internals/#dns） 2. 操作系统缓存（Linux: /etc/nsswitch.conf 控制顺序） 3. /etc/hosts 文件 4. 本地 DNS 服务器缓存 第二步：递归查询 本地 DNS 服务器（如 223.5.5.5）代替客户端完成整个解析过程：\n客户端 → 本地DNS: \u0026#34;www.google.com 的 IP 是什么？\u0026#34; 本地DNS → 根DNS (.): \u0026#34;请问 .com 在哪？\u0026#34; 根DNS → 本地DNS: \u0026#34;去找 .com 顶级域服务器\u0026#34; 本地DNS → .com TLD: \u0026#34;www.google.com 在哪？\u0026#34; .com TLD → 本地DNS: \u0026#34;去找 google.com 权威DNS\u0026#34; 本地DNS → google.com 权威: \u0026#34;www.google.com 在哪？\u0026#34; google.com 权威 → 本地DNS: \u0026#34;142.250.80.46\u0026#34; 本地DNS → 客户端: \u0026#34;142.250.80.46（缓存TTL=300秒）\u0026#34; 第三步：迭代查询（权威 DNS 之间） 根 DNS、TLD DNS、权威 DNS 之间使用迭代查询——每个 DNS 服务器只告诉下一步该找谁，不代替你完成全部查询。\nDNS 记录类型 类型 用途 示例 A 域名 → IPv4 example.com → 93.184.216.34 AAAA 域名 → IPv6 example.com → 2606:2800:220:1::248 CNAME 域名别名 www.example.com → example.com MX 邮件服务器 example.com → mail.example.com TXT 文本记录 SPF、DKIM、域名验证 NS 域名服务器 example.com → ns1.example.com SOA 起始授权 包含序列号、刷新间隔等 PTR 反向解析 34.216.184.93 → example.com DNS 缓存与 TTL TTL（Time To Live） 每条 DNS 记录都有 TTL 值（秒），表示缓存有效期：\n# 查询 TTL dig example.com +ttlunits # 或 dig example.com | grep -A1 \u0026#34;ANSWER SECTION\u0026#34; # 输出示例 # example.com. 300 IN A 93.184.216.34 # ^^^^ TTL=300秒 缓存层级 浏览器缓存（几分钟） ↓ OS 缓存（TTL 值） ↓ 路由器缓存（几小时） ↓ ISP DNS 缓存（TTL 值） ↓ 公共 DNS 缓存（TTL 值） 缓存清除 # Linux sudo systemd-resolve --flush-caches # 或 sudo resolvectl flush-caches # macOS sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder # Windows ipconfig /flushdns DNS 劫持与防御 常见劫持方式 DNS 缓存投毒：向 DNS 服务器注入虚假记录 本地 hosts 篡改：修改 hosts 文件 ISP 劫持：运营商透明代理 DNS 请求 中间人攻击：拦截 DNS 查询并返回虚假响应 检测方法 # 对比不同 DNS 服务器的结果 dig @8.8.8.8 example.com dig @223.5.5.5 example.com dig @1.1.1.1 example.com # 如果结果不一致，可能存在劫持 防御手段 1. DoH（DNS over HTTPS） # 使用 DoH 查询 curl -H \u0026#39;accept: application/dns-json\u0026#39; \\ \u0026#39;https://cloudflare-dns.com/dns-query?name=example.com\u0026amp;type=A\u0026#39; DoH 的优势：\n流量加密，无法被中间人窃听 隐藏在 HTTPS 流量中，难以被识别和阻断 使用标准 443 端口，兼容性好 2. DoT（DNS over TLS） # 使用 DoT（端口 853） kdig -d example.com @1.1.1.1 +tls DoT 的特点：\n专用端口 853，容易被识别和封锁 加密效果与 DoH 相同 适合内网环境 3. 本地 DNS 加密 # 使用 dnscrypt-proxy apt install dnscrypt-proxy # 配置 /etc/dnscrypt-proxy/dnscrypt-proxy.toml DNS 性能优化 本地 DNS 缓存服务 # 使用 systemd-resolved sudo systemctl enable systemd-resolved sudo systemctl start systemd-resolved # 配置 /etc/systemd/resolved.conf [Resolve] DNS=223.5.5.5 119.29.29.29 FallbackDNS=8.8.8.8 Cache=yes DNSStubListener=yes DNS 预解析 \u0026lt;!-- 在 HTML 中预解析常用域名 --\u0026gt; \u0026lt;link rel=\u0026#34;dns-prefetch\u0026#34; href=\u0026#34;//www.google.com\u0026#34;\u0026gt; \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://www.google.com\u0026#34;\u0026gt; 缓存大小优化 # 查看 systemd-resolved 缓存状态 resolvectl statistics # 查看缓存命中率 resolvectl query example.com 面试常见问题 DNS 使用 TCP 还是 UDP？\n主要使用 UDP（响应快、开销小） 区域传送（AXFR）使用 TCP 响应超过 512 字节时切换到 TCP（EDNS0 可扩展到 4096） DNS 为什么不用 TCP？\nTCP 需要三次握手，延迟高 UDP 简单快速，适合短查询 DNS 查询通常很小，不需要 TCP 的可靠性保证 什么是 DNS 放大攻击？\n攻击者伪造源 IP 向开放 DNS 服务器发送查询 DNS 服务器将大量响应发送到受害者 IP 利用 DNS 响应比请求大的特点进行放大 什么是 EDNS0？\nDNS 扩展机制，支持更大的 UDP 包（最大 4096 字节） 支持 DNSSEC、DNS COOKIE 等新特性 实战：搭建本地加密 DNS # 安装 dnscrypt-proxy apt install dnscrypt-proxy # 配置 /etc/dnscrypt-proxy/dnscrypt-proxy.toml listen_addresses = [\u0026#39;127.0.0.1:53\u0026#39;] server_names = [\u0026#39;alidns\u0026#39;, \u0026#39;腾讯DNS\u0026#39;] max_clients = 250 ipv4_servers = true dnssec = true ","permalink":"https://blog.geek.16775390.xyz/posts/dns-deep-dive/","summary":"完整剖析 DNS 解析链路：递归/迭代查询、缓存机制、DNS 劫持防御、DoH/DoT 加密原理。","title":"DNS 深度解析：从递归查询到缓存策略的完整链路"},{"content":"TCP 报文结构回顾 在分析握手和挥手之前，先回顾 TCP 头部的关键字段：\n0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | |C|E|U|A|P|R|S|F| | | Hdr | Rsvd |W|C|R|C|S|S|Y|I| Window | | Len | |R|E|G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 其中 SYN、ACK、FIN、RST 是控制位，决定了报文的类型。\n三次握手详解 第一次握手：SYN 客户端 ──── SYN=1, seq=x ────\u0026gt; 服务器 客户端发送 SYN 报文，SYN 标志位置 1 序列号 seq=x（随机初始值，称为 ISN） 客户端进入 SYN_SENT 状态 第二次握手：SYN+ACK 客户端 \u0026lt;──── SYN=1, ACK=1, seq=y, ack=x+1 ──── 服务器 服务器收到 SYN，回复 SYN+ACK SYN=1 表示这是服务器的连接请求 ACK=1 表示确认号有效 seq=y（服务器的 ISN） ack=x+1 表示确认收到了客户端的 seq=x 服务器进入 SYN_RCVD 状态 第三次握手：ACK 客户端 ──── ACK=1, seq=x+1, ack=y+1 ────\u0026gt; 服务器 客户端发送 ACK 确认 seq=x+1（接上一次的序列号） ack=y+1（确认服务器的 seq=y） 双方进入 ESTABLISHED 状态 为什么是三次？ 核心原因：防止历史连接的初始化。\n如果只有两次握手，服务器无法确认客户端是否收到了自己的 SYN+ACK。三次握手的本质是双方各确认一次收发能力：\n握手 确认内容 第 1 次 服务器确认：客户端能发 第 2 次 客户端确认：服务器能收能发 第 3 次 服务器确认：客户端能收 三次握手同时也是最小的确认次数。\n四次挥手详解 为什么挥手是四次？ TCP 是全双工协议，每个方向的关闭需要独立进行。发送 FIN 只表示\u0026quot;我不会再发数据了\u0026quot;，但对方可能还有数据要发。\n挥手过程 主动关闭方 被动关闭方 │ │ │──── FIN=1, seq=u ────────\u0026gt; │ ① 主动方发送 FIN │ │ │ \u0026lt;──── ACK=1, ack=u+1 ─────│ ② 被动方确认 FIN │ │ │ （被动方继续发送剩余数据） │ ③ 半关闭状态 │ │ │ \u0026lt;──── FIN=1, seq=w ────────│ ④ 被动方发送 FIN │ │ │──── ACK=1, ack=w+1 ────────\u0026gt; │ ⑤ 主动方确认 FIN │ │ │ TIME_WAIT (2MSL) │ ⑥ 等待确认到达 │ │ 状态变迁 主动关闭方: ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED 被动关闭方: ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED 为什么需要 TIME_WAIT？ TIME_WAIT 持续 2MSL（Maximum Segment Lifetime），有两个作用：\n确保最后的 ACK 能到达：如果最后的 ACK 丢失，被动方会重发 FIN，主动方需要在 TIME_WAIT 状态重新发送 ACK 防止旧连接的报文干扰新连接：等待足够时间让网络中残留的报文消亡 抓包实战 使用 tcpdump 抓取握手过程：\n# 抓取 80 端口的 TCP 握手 tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; (tcp-syn|tcp-ack|tcp-fin) != 0\u0026#39; -nn -c 20 port 80 # 更详细的抓包 tcpdump -i eth0 -nn -S port 80 使用 Wireshark 过滤器：\ntcp.flags.syn == 1 \u0026amp;\u0026amp; tcp.flags.ack == 0 # 过滤 SYN tcp.flags.fin == 1 # 过滤 FIN tcp.flags.rst == 1 # 过滤 RST 常见问题排查 1. SYN_RCVD 状态堆积 # 查看 SYN_RCVD 连接数 ss -ant | grep SYN-RCVD | wc -l # 可能是 SYN Flood 攻击，启用 SYN Cookie sysctl -w net.ipv4.tcp_syncookies=1 2. TIME_WAIT 过多 # 查看 TIME_WAIT 数量 ss -ant | grep TIME-WAIT | wc -l # 启用 TIME_WAIT 复用 sysctl -w net.ipv4.tcp_tw_reuse=1 3. 连接超时排查 # 查看重传统计 netstat -s | grep -i retrans # 查看超时参数 sysctl net.ipv4.tcp_syn_retries sysctl net.ipv4.tcp_fin_timeout 总结 TCP 的握手和挥手是可靠的基石。理解报文级别的交互，对于排查网络问题、优化性能至关重要。\n","permalink":"https://blog.geek.16775390.xyz/posts/tcp-handshake-teardown/","summary":"从报文交互的角度，彻底理解 TCP 连接的建立与关闭过程，以及为什么挥手需要四次。","title":"TCP 三次握手与四次挥手：从报文层面彻底理解"},{"content":"UDP：极简的传输层 UDP（User Datagram Protocol）是传输层最简单的协议，只在 IP 之上加了最少的封装：\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 头部只有 8 字节，对比 TCP 的 20 字节起步，UDP 几乎没有开销。\nUDP 的特点 特性 UDP TCP 连接方式 无连接 面向连接 可靠性 不保证 保证 有序性 不保证 保证 流量控制 无 有 拥塞控制 无 有 头部开销 8 字节 20+ 字节 UDP 的应用场景 UDP 并非\u0026quot;不可靠\u0026quot;的代名词，它适合以下场景：\n实时音视频：延迟比完整性更重要（VoIP、直播） DNS 查询：单次请求-响应，不需要连接维护 游戏同步：状态更新频繁，旧数据无意义 物联网传感器：资源受限，简单通信 隧道协议：在 UDP 上构建自己的可靠性（QUIC、WireGuard） QUIC：在 UDP 上重建一切 QUIC（Quick UDP Internet Connections）由 Google 提出，现已成为 HTTP/3 的基础。它在 UDP 之上实现了 TCP 的大部分功能，同时解决了 TCP 的历史包袱。\nQUIC 解决了什么问题？ 1. TCP 队头阻塞 TCP 中，一个连接上的所有流共享同一个有序队列。如果某个流的包丢失，后续所有流都必须等待：\nTCP 连接上的流: Stream A: [1] [2] [3] [4] [5] Stream B: [1] [2] [3] [4] [5] 如果 Stream A 的第3个包丢失: Stream A: [1] [2] [X] [4] [5] ← 阻塞 Stream B: [1] [2] [3] [4] [5] ← 即使全部到达也被阻塞! QUIC 为每个流独立维护可靠性：\nQUIC 连接上的流: Stream A: [1] [2] [X] [4] [5] ← 只有这个流阻塞 Stream B: [1] [2] [3] [4] [5] ← 不受影响 2. 连接建立延迟 TCP + TLS 1.3: Client ──SYN──\u0026gt; Server (1 RTT) Client \u0026lt;──SYN+ACK── Server Client ──ACK + ClientHello──\u0026gt; (1 RTT) Client \u0026lt;──ServerHello── Server Client ──Finished──\u0026gt; (1 RTT) Client \u0026lt;──Finished── Server 总计: 2-3 RTT (TLS 1.3) 或 3-4 RTT (TLS 1.2) QUIC: Client ──Initial (ClientHello + 加密)──\u0026gt; Server (0-RTT 或 1 RTT) Client \u0026lt;──Initial (ServerHello + 加密)── Server 总计: 1 RTT (首次), 0-RTT (恢复) 3. 连接迁移 TCP 连接由四元组标识：(源IP, 源端口, 目标IP, 目标端口)\n当设备从 WiFi 切换到 4G，IP 地址变化，TCP 连接断开。\nQUIC 使用 Connection ID 标识连接，与 IP 无关：\nWiFi 环境: Connection ID=0xABC123, IP=192.168.1.100 → Server 切换到 4G: Connection ID=0xABC123, IP=10.0.0.50 → Server ← 同一个连接! QUIC 协议架构 ┌─────────────────────────────────────┐ │ Application │ │ (HTTP/3) │ ├─────────────────────────────────────┤ │ QUIC │ │ ┌─────────┐ ┌─────────┐ ┌──────┐│ │ │ Stream 1│ │ Stream 2│ │ ... ││ │ └─────────┘ └─────────┘ └──────┘│ ├─────────────────────────────────────┤ │ QUIC Transport │ │ (连接管理、拥塞控制、流控) │ ├─────────────────────────────────────┤ │ TLS 1.3 (内置) │ ├─────────────────────────────────────┤ │ UDP │ ├─────────────────────────────────────┤ │ IP │ └─────────────────────────────────────┘ 关键点：QUIC 将 TLS 1.3 集成到了传输层，握手和加密协商在同一个过程中完成。\n实际性能对比 在高延迟、高丢包环境下的测试（RTT=200ms, 丢包率=2%）：\n指标 TCP + TLS 1.3 QUIC 首字节延迟 ~600ms ~200ms 并发流吞吐 有队头阻塞 无队头阻塞 连接恢复 断开重连 无缝迁移 慢启动 从头开始 恢复到上次窗口 抓包分析 QUIC 使用 UDP 端口 443，抓包命令：\n# 抓取 QUIC 流量 tcpdump -i eth0 \u0026#39;udp port 443\u0026#39; -nn -w quic.pcap # 使用 Wireshark 分析 QUIC # 过滤器: quic # 可以看到 Initial、Handshake、1-RTT 等包类型 QUIC 包的 UDP 载荷通常远大于单个 MTU（会进行分片），观察时注意：\n# 查看 QUIC 连接的分片情况 tcpdump -i eth0 \u0026#39;udp port 443\u0026#39; -nn -v | grep \u0026#34;length\u0026#34; Linux 内核对 QUIC 的支持 从 Linux 6.0 开始，内核原生支持 QUIC（目前是实验性的）：\n# 查看内核 QUIC 模块 lsmod | grep quic # 加载模块（如果需要） modprobe quic # 使用内核 QUIC 的工具 apt install linux-tools-common 大多数用户态 QUIC 实现（如 quiche、msquic）仍然使用用户态 UDP socket，不依赖内核 QUIC 支持。\n总结 QUIC 并非要替代 UDP，而是利用 UDP 的简单性，在用户态实现了现代化的传输协议。理解 UDP 的本质，才能真正理解 QUIC 的设计哲学。\n","permalink":"https://blog.geek.16775390.xyz/posts/udp-and-quic-protocol/","summary":"理解 UDP 的本质特性，以及 QUIC 如何在 UDP 之上构建可靠的传输协议。","title":"UDP 协议与 QUIC：从无连接到可靠传输的演进"},{"content":"网络栈全景 Linux 内核的网络数据处理路径：\n网卡驱动 → SoftIRQ → Netfilter → Socket Buffer → 应用层 │ │ │ └── sk_buff 管理 └── Ring Buffer / NAPI 性能瓶颈可能出现在任何一层。调优的本质就是找到并消除这些瓶颈。\n第一层：网卡与 Ring Buffer 查看网卡信息 # 查看网卡型号和驱动 ethtool -i eth0 # 查看 Ring Buffer 大小 ethtool -g eth0 # 查看网卡统计（看是否有丢包） ethtool -S eth0 | grep -i drop 调整 Ring Buffer # 增大 Ring Buffer（单位: descriptor 数量） ethtool -G eth0 rx 4096 tx 4096 # 启用自适应中断 ethtool -C eth0 adaptive-rx on adaptive-tx on # 查看当前设置 ethtool -c eth0 多队列网卡 # 查看队列数 ethtool -l eth0 # 设置队列数（等于 CPU 核心数） ethtool -L eth0 combined 4 # 将队列绑定到 CPU # 中断号通过 /proc/interrupts 查找 echo 2 \u0026gt; /proc/irq/IRQ_NUM/smp_affinity # 绑定到 CPU1 第二层：SoftIRQ 与 NAPI SoftIRQ 处理网络收包。如果单个 CPU 核心处理不过来，就会成为瓶颈。\n监控 SoftIRQ # 查看 SoftIRQ 分布 cat /proc/softirqs | grep NET_RX # 查看是否有 CPU 瓶颈 mpstat -P ALL 1 调整 NAPI # 增加 NAPI 权重（让每个 SoftIRQ 处理更多包） sysctl -w net.core.netdev_budget=600 sysctl -w net.core.netdev_budget_usecs=8000 第三层：Socket 缓冲区 核心参数 # /etc/sysctl.d/99-network-tuning.conf # --- 接收缓冲区 --- # 最小值、默认值、最大值（字节） net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.udp_rmem_min = 8192 # --- 发送缓冲区 --- net.ipv4.tcp_wmem = 4096 65536 16777216 net.ipv4.udp_wmem_min = 8192 # --- 全局缓冲区 --- net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.rmem_default = 1048576 net.core.wmem_default = 1048576 net.core.optmem_max = 2048 理解自动调优 Linux 内核会根据拥塞窗口自动调整 TCP 缓冲区大小。设置的 min/max 定义了自动调优的范围：\n实际缓冲区 = clamp(自动调优值, min, max) 对于高带宽长距离连接（BDP 大），需要更大的缓冲区：\nBDP = Bandwidth × RTT 示例: 1Gbps × 100ms = 12.5MB 验证缓冲区使用 # 查看当前连接的缓冲区使用 ss -tm # ss 输出中的 skmem:(r0,rbX,t0,tbX) 表示接收/发送缓冲区 第四层：TCP 连接管理 连接队列 # SYN 半连接队列 net.ipv4.tcp_max_syn_backlog = 65536 # 已完成连接等待 accept 的队列 net.core.somaxconn = 65536 # 本地端口范围 net.ipv4.ip_local_port_range = 1024 65535 连接回收 # TIME_WAIT 复用 net.ipv4.tcp_tw_reuse = 1 # FIN-WAIT-2 超时（秒） net.ipv4.tcp_fin_timeout = 15 # Keepalive 参数 net.ipv4.tcp_keepalive_time = 600 # 空闲多久开始探测 net.ipv4.tcp_keepalive_intvl = 15 # 探测间隔 net.ipv4.tcp_keepalive_probes = 5 # 探测次数 SYN Flood 防护 # 启用 SYN Cookie（SYN 队列满时启用） net.ipv4.tcp_syncookies = 1 # SYN+ACK 重试次数 net.ipv4.tcp_synack_retries = 2 # SYN 重试次数 net.ipv4.tcp_syn_retries = 3 第五层：拥塞控制 BBR 算法 BBR（Bottleneck Bandwidth and Round-trip propagation time）是 Google 开发的拥塞控制算法，基于带宽和延迟建模，而非丢包：\n# 设置 BBR 为默认算法 sysctl -w net.core.default_qdisc=fq sysctl -w net.ipv4.tcp_congestion_control=bbr # 永久生效 cat \u0026gt;\u0026gt; /etc/sysctl.d/99-network-tuning.conf \u0026lt;\u0026lt; EOF net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr EOF sysctl -p /etc/sysctl.d/99-network-tuning.conf 验证 BBR 是否生效 # 查看当前拥塞控制算法 sysctl net.ipv4.tcp_congestion_control # 查看 BBR 统计 sysctl net.ipv4.tcp_bbr # 查看内核支持的算法 sysctl net.ipv4.tcp_available_congestion_control BBR v2 BBR v2 改善了与基于丢包的算法（如 Cubic）的共存性：\n# 如果内核支持 BBR v2 modprobe tcp_bbr2 sysctl -w net.ipv4.tcp_congestion_control=bbr2 第六层：其他优化 TCP Fast Open 允许在 SYN 报文中携带数据，减少一次 RTT：\n# 服务端启用 TFO net.ipv4.tcp_fastopen = 3 # 服务端 TFO 队列长度 net.ipv4.tcp_fastopen_key = random MTU 发现 # 启用路径 MTU 发现 net.ipv4.ip_no_pmtu_disc = 0 # 查看路径 MTU ip route get 8.8.8.8 ECN（显式拥塞通知） # 启用 ECN net.ipv4.tcp_ecn = 1 监控工具集 # 实时监控连接状态 watch -n1 \u0026#39;ss -ant | awk \u0026#34;{print \\$1}\u0026#34; | sort | uniq -c | sort -rn\u0026#39; # 网络流量监控 iftop -i eth0 # 连接追踪表 conntrack -L -o extended | head -20 # 内核网络统计 nstat -az | grep -i tcp # 完整的网络栈监控脚本 sar -n DEV 1 调优检查清单 参数 默认值 推荐值 说明 tcp_rmem 4096 131072 4096 87380 16777216 TCP 接收缓冲区 tcp_wmem 4096 16384 4096 65536 16777216 TCP 发送缓冲区 somaxconn 128 65536 监听队列 tcp_max_syn_backlog 256 65536 SYN 队列 tcp_tw_reuse 0 1 TIME_WAIT 复用 tcp_fin_timeout 60 15 FIN 超时 default_qdisc pfifo_fast fq 队列调度 congestion_control cubic bbr 拥塞控制 总结 网络调优不是堆参数，而是理解每一层的工作机制，根据实际场景做出针对性调整。先监控找到瓶颈，再调优验证效果。\n","permalink":"https://blog.geek.16775390.xyz/posts/linux-network-tuning/","summary":"系统性地介绍 Linux 网络栈的调优方法，涵盖缓冲区、队列、拥塞控制等关键维度。","title":"Linux 网络性能调优：从内核参数到 BBR 拥塞控制"},{"content":"Nginx 架构 Nginx 采用 master-worker 多进程模型：\nMaster Process (root) │ 读取配置、管理 worker │ ┌─────────┼─────────┐ │ │ │ Worker 1 Worker 2 Worker N (nginx) (nginx) (nginx) │ │ │ epoll epoll epoll │ │ │ 事件循环 事件循环 事件循环 每个 worker 是一个独立进程，处理所有连接。worker 数量建议等于 CPU 核心数。\nWorker 进程配置 # /etc/nginx/nginx.conf # 自动设置为 CPU 核心数 worker_processes auto; # 绑定到特定 CPU（可选） worker_cpu_affinity auto; # 每个 worker 的最大打开文件数 worker_rlimit_nofile 65535; # 错误日志级别 error_log /var/log/nginx/error.log warn; events { # 每个 worker 的最大连接数 worker_connections 10240; # 使用 epoll 事件模型（Linux） use epoll; # 一次接受多个新连接 multi_accept on; # 通知工作线程接受连接 accept_mutex off; } 负载均衡配置 upstream 配置 upstream backend { # 负载均衡算法 # least_conn; # 最少连接 # ip_hash; # IP 哈希 # hash $request_uri; # URI 哈希 # round-robin; # 轮询（默认） server 10.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s; server 10.0.0.2:8080 weight=2 max_fails=3 fail_timeout=30s; server 10.0.0.3:8080 backup; # 长连接池 keepalive 32; keepalive_timeout 60s; keepalive_requests 1000; } server { listen 80; location / { proxy_pass http://backend; # HTTP 头设置 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 超时设置 proxy_connect_timeout 5s; proxy_send_timeout 30s; proxy_read_timeout 30s; # 缓冲区设置 proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 16k; proxy_busy_buffers_size 32k; # HTTP 版本 proxy_http_version 1.1; proxy_set_header Connection \u0026#34;\u0026#34;; } } keepalive 的重要性 默认 Nginx 每次请求都会与上游建立新连接。启用 keepalive 后，可以复用连接：\n# 查看到上游的连接状态 ss -tnp | grep :8080 # 启用 keepalive 前: 每次请求都有 TIME_WAIT # 启用 keepalive 后: 连接复用，连接数大幅减少 缓冲区与缓存 代理缓冲区 location / { proxy_pass http://backend; # 启用缓冲（默认开启） proxy_buffering on; # 响应头缓冲区（存 headers） proxy_buffer_size 4k; # 响应体缓冲区（存 body） proxy_buffers 8 16k; proxy_busy_buffers_size 32k; # 临时文件 proxy_temp_file_write_size 64k; proxy_temp_path /var/cache/nginx/proxy_temp 1 2; } 缓存配置 # 定义缓存路径 proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=MY_CACHE:10m max_size=1g inactive=60m use_temp_path=off; server { location / { proxy_cache MY_CACHE; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; proxy_cache_key $scheme$proxy_host$request_uri; # 缓存状态 add_header X-Cache-Status $upstream_cache_status; proxy_pass http://backend; } } 查看缓存命中率：\n# X-Cache-Status 头: HIT, MISS, EXPIRED, STALE 等 curl -I http://example.com/ | grep X-Cache 限速配置 限制请求速率 # 定义限速区域 limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; server { # API 限速 location /api/ { limit_req zone=api burst=20 nodelay; proxy_pass http://backend; } # 登录接口严格限速 location /api/login { limit_req zone=login burst=5 nodelay; proxy_pass http://backend; } # 自定义限速返回码 limit_req_status 429; } 限制并发连接 limit_conn_zone $binary_remote_addr zone=addr:10m; server { location /download/ { limit_conn addr 5; # 每 IP 最多 5 个并发连接 limit_rate 500k; # 每连接限速 500KB/s limit_rate_after 10m; # 前 10MB 不限速 } } 性能调优总结 # 完整的性能优化配置 worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 10240; use epoll; multi_accept on; } http { # 基础优化 sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; keepalive_requests 1000; # 缓冲区 client_body_buffer_size 16k; client_header_buffer_size 1k; large_client_header_buffers 4 8k; client_max_body_size 100m; # Gzip gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 4; gzip_min_length 256; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; # 日志优化 access_log off; # 或使用缓冲写入 # access_log /var/log/nginx/access.log main buffer=32k flush=5s; } 监控与诊断 # 查看 Nginx 工作进程 ps aux | grep nginx # 查看连接数 ss -ant | grep :80 | wc -l # 查看 worker 连接使用情况 # 需要启用 stub_status 模块 curl http://localhost/nginx_status # 实时监控 watch -n1 \u0026#39;curl -s http://localhost/nginx_status\u0026#39; # 查看 Nginx 错误 tail -f /var/log/nginx/error.log 总结 Nginx 的性能调优是一个系统工程，需要从 worker 配置、连接管理、缓冲区、限速等多个维度综合考虑。关键是理解每个参数的含义，根据实际负载进行调整。\n","permalink":"https://blog.geek.16775390.xyz/posts/nginx-proxy-performance/","summary":"深入 Nginx 反向代理的性能调优，从 worker 进程到上游连接池的全方位优化。","title":"Nginx 反向代理性能优化：从 worker 到连接池"}]