我们先复习一下Nat的知识,Nat是一种网络地址转换的方式,可以修改一个IP包的原地址和目标地址
Nat基本可以分为SNAT DNAT 双向地址转换
转换的流程,基本如下所示
那么,如何实现的NAT我们也简单回顾一下
给予Netfilter这个框架,给予了对网络包修改,即NAT的能力,并在此之上,发展出了iptables等工具,方便管理NAT和防火墙等规则
在整个iptables中,存在多条链,有关的有
PREOUTING 路由判断前的执行操作,比如DNAT
POSTROUTING 路由判断后的操作,比如SNAT
对应的配置方法,
对于SNAT,可以在nat表中的POSTROUTING中配置,
先是统一的配置SNAT
iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -j MASQUERADE
或者为指定的IP配置SNAT,指定转换后的原地址
iptables-t nat -A POSTROUTING -s 192.168.0.2 -j SNAT –to source 100.100.100.100
DNAT,我们去查看nat表中的PREROTING或者OUTPUT链中配置
$ iptables -t nat -A PREROUTING -d 100.100.100.100 -j DNAT –to-destination 192.168.0.2
最后就是开启NAT的同时,需要开启IP转发功能
执行如下的命令,查看功能是否开启,输出的结果是1,就说明开启了IP转发
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
开启的方法是写入 /etc/sysctl.conf文件
net.ipv4.ip_forward=1
接下来我们看一下NAT相关的案例
这次,我们需要用到一个内核相关的工具,SystemTap
一个Linux的动态追踪框架,将用户提供的脚本,转换为内核模块执行,监测和跟踪内核的行为
# CentOS
yum install systemtap kernel-devel yum-utils kernel stab-prep |
我们利用一台Nginx相关镜像进行讲解
我们首先测试一下直接物理启动Nginx的性能,可以达到
每秒请求数 6576
平均延迟 760ms
然后启动一个docker镜像
将其进行了端口映射 -p 8080:8080
$ docker run –name nginx –privileged -p 8080:8080 -itd feisky/nginx:nat
在启动之后,执行iptables命令,确定DNAT规则
$ iptables -nL -t nat
Chain PREROUTING (policy ACCEPT) target prot opt source destination DOCKER all — 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL … Chain DOCKER (2 references) target prot opt source destination RETURN all — 0.0.0.0/0 0.0.0.0/0 DNAT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:8080 |
Docker的链中,会将本地的请求转到自己上,其中呢,则是将目标端口8080的tcp请求,DNAT到172.17.0.2的8080端口
接下来,测试ab工具
# -c表示并发请求数为5000,-n表示总的请求数为10万
# -r表示套接字接收错误时仍然继续执行,-s表示设置每个请求的超时时间为2s
$ ab -c 5000 -n 100000 -r -s 2 http://192.168.0.30:8080/
…
apr_pollset_poll: The timeout specified has expired (70007)
Total of 5602 requests completed
上面报了连接操作的错误
即使放大了超时时间,减少了测试次数
也会得到结果输出为
每秒请求数为76
每个请求的延迟为65s
接下来,我们尝试查询Netfilter相关的问题
利用动态追踪工具SystemTap来试试,这个工具需要配合对应的脚本文件
#! /usr/bin/env stap
############################################################ # Dropwatch.stp # Author: Neil Horman <nhorman@redhat.com> # An example script to mimic the behavior of the dropwatch utility # http://fedorahosted.org/dropwatch ############################################################ # Array to hold the list of drop points we find global locations # Note when we turn the monitor on and off probe begin { printf(“Monitoring for dropped packets\n”) } probe end { printf(“Stopping dropped packet monitor\n”) } # increment a drop counter for every location we drop at probe kernel.trace(“kfree_skb”) { locations[$location] <<< 1 } # Every 5 seconds report our drop locations probe timer.sec(5) { printf(“\n”) foreach (l in locations-) { printf(“%d packets dropped at %s\n”, @count(locations[l]), symname(l)) } delete locations } |
跟踪kfre_skb()调用,统计丢包的位置,文件保存后,
运行丢包跟踪脚本
stap –all-moudles dropwatch stp
然后进行ab命令的查询
ab -c 5000 -n 10000 -r -s 30 http://192.168.0.39:8080
在stap的输出中,大量的丢包存在于nf_hook_slow这个位置,这是不是钩子函数产生了丢包问题,
进行跟踪nf_hook_slow的执行过程,可以通过perf完成
在ab的时候,进行perf record 和perf report命令
perf record -a -g –sleep 30
perf report -g graph,0
找到对应的nf_hook_slow,展开调用栈
nf_hook_slow进行调用的比较多的,是ipv4_conntrack_in,br_nf_pre_routing,iptable_nat_ipv4_in
进行接收网络包的时候产生新的连接分配
Linux中转发包
接收网络包的时候,执行DNAT
在这三个源头中,我们查找对应的优化机制
我可以利用proc sys文件系统进行查看系统配置,并利用sysctl修改内核配置
DNAT对应的conntrack,对应的sysctl有
sysctl -a | grep conntrack
得到了几个指标
net.netfilter.nf_conntrack_count 当前连接数
net.netfilter.nf_conntrack_max 最大连接数
net.netfilter.nf_conntrack_buckets 连接表的大小
最大连接数只有1000个,看起来就不够
而且在内核中,已经报了异常信息到日志中了,在ab测试中,内核爆出了 nf_conntrack:table full
dmesg命令就可以进行获取
如果将nf_conntrack_max调大一倍,改为buckets的2倍
重新执行ab,可以获取到Nginx相关的返回
每秒的请求数为6315,每个请求的延迟是791ms
最后,我们看下跟踪表中的内容,利用conntrack命令行工具
# -L表示列表,-o表示以扩展格式显示
$ conntrack -L -o extended | head ipv4 2 tcp 6 7 TIME_WAIT src=192.168.0.2 dst=192.168.0.96 sport=51744 dport=8080 src=172.17.0.2 dst=192.168.0.2 sport=8080 dport=51744 [ASSURED] mark=0 use=1 ipv4 2 tcp 6 6 TIME_WAIT src=192.168.0.2 dst=192.168.0.96 sport=51524 dport=8080 src=172.17.0.2 dst=192.168.0.2 sport=8080 dport=51524 [ASSURED] mark=0 use=1 |
内部包含了协议,连接状态,源IP,源端口 目的IP 目的端口,跟踪状态
那么总结一下
首先,我们说了NAT的基本概念,和iptables的基本配置
然后是NAT的典型问题,我们在分析NAT问题的时候,先从conntrack角度来分析,比如systemtap perf等
分析内核中conntrack的行文
Linux维护这种连接跟踪机制的NAT,称为有状态的NAT,维护有一定的成本