我们先复习一下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,维护有一定的成本

发表评论

邮箱地址不会被公开。 必填项已用*标注