[文章作者:曾庆华 转载请注明原文链接:http://linscora.cublog.cn]
1、简化我们的传输模型
什么是BDP
Bandwidth delay product 是用来调节TCP一次性传输数据的大小。当一次性传输的数据包大小越大的时候,就会越省系统资源。当也不是越大越好,
因为当网络拥塞的时候。网络上的带宽就会处理不过来。就会增加队列的长度。所以适当的数据量才能更加优化网络。这就是为什么我们要对网络进行调优的原因之一。
BDP(bytes)=Bandwitdth(bytes/s)*Delaytime(second)
假如100M的局域网,ping的平均延时为3s,那么这个网络的理想BDP为(它是网络上所有的buffers,包括tcp,udp)
L(pipe) = Bandwidth * Delay(RTT) = A * W
100Mi * 1/8 * 3s * 2^20 = 39321600 bytes
因为系统缺省是自动调节BDP的大小的。开始它是慢慢增大的。最后到达一个平衡的值。
当网络之间传输数据的时候,
1)、发送端开始往puffers里写数据(而不是我们想像的发送就应该直接读我本地的数据,这里的buffers都是指内核的。我们要明白,为什么我们4G的内存只能使用3G呢?因为有1G是给内核用的。我们看到的是我们应用程序可以直接使用的。)
2)、然后数据在puffers通过网络协议在里面进行封装。
3)、然后封装好的协议数据单元(pdu)传送到单一的设备上。最后pdu传输到了网卡。
2、简化我们的接收模型
DMA 直接内存访问
1)、但网卡接收到数据帧时。网卡的DMA会直接把帧发到pufffers区里面。首先在puffers对数据进行解封装。然后是本机硬盘读puffers里的数据。
2)、网卡会增加CPU的中断号。 (cpu的中断号越高。说明cpu会优先处理这个程序,而把原来的数据放到内存,再到了硬盘,它越不容易中断。)
3)、而内核又会去处理我会早期的中断,就是中断号更底的那些。
Kernel socket buffers:有四种:
UDP: core read and write buffers
TCP: core + TCP read and write buffers
Fragmentation buffers:会话的碎片 这个功能就为了使用TCP重传时,产生的碎片在一定的时间内对它处理。
DMA: 直接内存访问
处理网络的那些buffers,首先是非使用的页面,其次它是在ZONE_NORMAL里面的,最后,我们接收的流量的控制是基于buffers空间的大小的。
100Mi * 1/8 * 3s * 2^20 = 39321600 bytes 从这里来看,延时越大。我的bdp就越大。那么为什么网络越忙,要发出去的数据包越多呢?
其实这是有一个基准线的。当我们的网络延时越大的时候。如果这个网络可以承受的数据为10000bytes。如果我每次只发1000bytes。我就要发10次。那么如果延时很大呢?
这十次的数据要30秒才等于我一次发10000bytes一秒的数据。但是这个值也不是无穷大的。如果无穷大的话。时间也就无穷大了。还不如每次一点一点来传。所以这个公司
是计算这个基准线的最优情况的。
如果我们机器有两个网卡的话。计算出来的值还要除以2。就是单一网卡的bdp值了。
当L一定时。就是队列一定的:
连接数越小的话。BDP的值越大。buffers也越大。
连接数越大的话。BDP的值越小。buffers也越小。
理解了上面的,下面开始调整参数了。
1、调整核心的buffers大小。
input/reader in bytes: net.core.rmem_default
net.core.rmem_max 这个值就是我们用公式算出来的。
output/writer in bytes: net.core.wmem_default39321600
net.core.wmem_max
上面四个参数只是调到的是udp的数据包。
sysctl -p
2、调整TCP的buffers的大小。
overall TCP memery in pages: 总体TCP的页面数。
net.ipv4.tcp_mem 注意这个单位为页,每个页为4kib。上面这总情况为:39321600 bytes / 1024 /4 = 9600
input/reader in bytes: 发送的TCP的字节数 单位Kib
net.ipv4.tcp_rmem
output/writer in bytes: 接收的TCP的字节数
net.ipv4.tcp_wmem
[root@linscora ~]# /sbin/sysctl -a |/bin/grep tcp |/bin/grep --color mem
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_mem = 98304 131072 196608
最小的 合理的 最大的
****比如:一个带宽也1.5M的网络。它的延时为500ms。那么合理的tcp传输时,buffers值为多少?假设它的最大值为它的合理值的1.5倍。****
1.5*0.5*2^20/8 = 98304 bytes
systcl -w net.ipv4.tcp_rmem=96 96 144
systcl -w net.ipv4.tcp_wmem=96 96 144
systcl -w net.ipv4.tcp_mem=24 36 36
实验验证:
rpm -ivh bdp-lab-0.1-01.norach.rpm ##这是红帽开发的一个测试的包。一定要运行在xen的环境下。
续:
3、DMA直接内存的访问。
这是一个硬件的高调优。而不是系统的。
alias eth e1000
options eth0 RxDescriptors=1024 TxDescriptors=512
发数据buffers的大小 接收数据buffers的大小。
它取自于整个系统的25%。
[root@linscora ~]# /sbin/modinfo -p e1000
debug:Debug level (0=none,...,16=all)
copybreak:Maximum size of packet that is copied to a new buffer on receive
KumeranLockLoss:Enable Kumeran lock loss workaround
SmartPowerDownEnable:Enable PHY smart power down
InterruptThrottleRate:Interrupt Throttling Rate
RxAbsIntDelay:Receive Absolute Interrupt Delay
RxIntDelay:Receive Interrupt Delay
TxAbsIntDelay:Transmit Absolute Interrupt Delay
TxIntDelay:Transmit Interrupt Delay
XsumRX:Disable or enable Receive Checksum offload
FlowControl:Flow Control setting
AutoNeg:Advertised auto-negotiation setting
Duplex:Duplex setting
Speed:Speed setting
RxDescriptors:Number of receive descriptors
TxDescPower:Binary exponential size (2^X) of each transmit descriptor
TxDescriptors:Number of transmit descriptors
[root@linscora ~]# /sbin/modinfo -p st
try_wdio:Try direct write i/o when possible
try_rdio:Try direct read i/o when possible
try_direct_io:Try direct I/O between user buffer and tape drive (1)
max_sg_segs:Maximum number of scatter/gather segments to use (256)
buffer_kbs:Default driver buffer size for fixed block mode (KB; 32)
****调一个scsi设备的buffers的大小******
首先加载模块:
1、[root@linscora ~]# /sbin/modprobe st
2、[root@linscora ~]# /bin/cat /sys/bus/scsi/drivers/st/fixed_buffer_size
32768
3、[root@linscora ~]# /sbin/modinfo st |grep --color buffer
parm: buffer_kbs:Default driver buffer size for fixed block mode (KB; 32) (int)
parm: try_direct_io:Try direct I/O between user buffer and tape drive (1) (int)
[root@linscora ~]# /bin/echo "options st buffer_kbs=128" >> /etc/modprobe.conf
[root@linscora ~]# /bin/cat /etc/modprobe.conf
alias eth0 e1000
alias scsi_hostadapter ata_piix
alias snd-card-0 snd-intel8x0
options snd-card-0 index=0
options snd-intel8x0 index=0
remove snd-intel8x0 { /usr/sbin/alsactl store 0 >/dev/null 2>&1 || : ; }; /sbin/modprobe -r --ignore-remove snd-intel8x0
options st buffer_kbs=128
4、[root@linscora ~]# /sbin/modprobe -r st
[root@linscora ~]# /sbin/modprobe st
5、[root@linscora ~]# /bin/cat /sys/bus/scsi/drivers/st/fixed_buffer_size
131072
6、[root@linscora ~]# /bin/echo "/sbin/modprobe st" >> /etc/rc.d/rc.local
[root@linscora ~]# /bin/cat /etc/rc.d/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
/sbin/modprobe st
4、数据包碎片的调优:
查看:
[root@linscora ~]# /bin/cat /proc/net/snmp
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 2 64 40298 0 237 0 0 0 16283 16424 0 0 0 0 0 0 0 0 0
Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 0 0 0 0 0 0 0 0 0 0 0 0 0 34 0 30 0 0 0 0 4 0 0 0 0 0
IcmpMsg: OutType3 OutType8
IcmpMsg: 30 4
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts
Tcp: 1 200 120000 -1 590 1 122 30 30 15767 15388 473 0 338
Udp: InDatagrams NoPorts InErrors OutDatagrams
Udp: 478 29 0 519
[root@linscora ~]# /bin/cat /proc/net/snmp |grep '^Ip:' |cut -f17 -d' '
ReasmFails
0
[root@linscora ~]# /bin/netstat -s
Ip:
40996 total packets received
237 with invalid addresses
0 forwarded
0 incoming packets discarded
16945 incoming packets delivered
17083 requests sent out
Icmp:
0 ICMP messages received
0 input ICMP message failed.
ICMP input histogram:
34 ICMP messages sent
0 ICMP messages failed
ICMP output histogram:
destination unreachable: 30
echo request: 4
IcmpMsg:
OutType3: 30
OutType8: 4
Tcp:
604 active connections openings
1 passive connection openings
122 failed connection attempts
30 connection resets received
29 connections established
16429 segments received
16030 segments send out
490 segments retransmited
0 bad segments received.
338 resets sent
Udp:
478 packets received
29 packets to unknown port received.
0 packet receive errors
519 packets sent
TcpExt:
1 packets pruned from receive queue because of socket buffer overrun
50 TCP sockets finished time wait in fast timer
1124 delayed acks sent
Quick ack mode was activated 516 times
4 packets directly queued to recvmsg prequeue.
1 packets directly received from prequeue
7589 packets header predicted
1029 acknowledgments not containing data received
762 predicted acknowledgments
TCPDSACKUndo: 5
165 congestion windows recovered after partial ack
0 TCP data loss events
7 timeouts after SACK recovery
263 other TCP timeouts
34 packets collapsed in receive queue due to low socket buffer
518 DSACKs sent for old packets
50 DSACKs received
31 connections reset due to unexpected data
1 connections reset due to early user close
24 connections aborted due to timeout
IpExt:
InMcastPkts: 98
OutMcastPkts: 101
InBcastPkts: 2963
分析:当一个TCP的数据包没有成功的时候,或不完整。它就会产生碎片。而碎片首先将会在buffers区里。然后内核会去它进行重新组装。再次重新发送。
如果反复几次都没有成功的话。是不是一直重组呢?这将消耗系统资源。所以要对它进行处理。
[root@linscora ~]# /sbin/sysctl -a |grep ipfrag |grep high
net.ipv4.ipfrag_high_thresh = 262144 单位为bytes
[root@linscora ~]# /sbin/sysctl -a |grep ipfrag |grep low
net.ipv4.ipfrag_low_thresh = 196608
[root@linscora ~]# /sbin/sysctl -a |grep ipfrag |grep time
net.ipv4.ipfrag_time = 30
当碎片在buffers区里面达到net.ipv4.ipfrag_high_thresh设定的这个值时,这个碎片就直接被丢了。
当碎片在buffers区里面达到net.ipv4.ipfrag_low_thresh设定的这个值时,这个碎片就会重新组装。
而所有的碎片在buffers区里面的存活时间为net.ipv4.ipfrag_time秒。如每30秒碎片没有组装成功。就被丢弃了。
网络中断处理:
网络中断的处理总是优先于进的队列。
就是中断的优先级高于进和的优先级。
查看软中断:
[root@linscora ~]# /bin/ps axo pid,comm,util |grep softirq
3 ksoftirqd/0 0
调优中断处理:
[root@linscora ~]# /bin/ps axo pid,comm,util |grep softirq
3 ksoftirqd/0 0
[root@linscora ~]# /usr/bin/vim /etc/modprobe.conf
[root@linscora ~]# /bin/cat /etc/modprobe.conf
alias eth0 e1000
alias scsi_hostadapter ata_piix
options e1000 InterruptThrottleRate=1,3000
alias snd-card-0 snd-intel8x0
options snd-card-0 index=0
options snd-intel8x0 index=0
remove snd-intel8x0 { /usr/sbin/alsactl store 0 >/dev/null 2>&1 || : ; }; /sbin/modprobe -r --ignore-remove snd-intel8x0
options st buffer_kbs=128
options e1000 InterruptThrottleRate=1,3000 这里的1表示根据网络流量来处理中断信号、0表示这个功能关闭了、3表示一个保守的处理方法。
每一个网络连接我们可以把它看到一个虚拟的文件对待,当传一个数据就相当于写一个虚拟文件,
当接收一个数据就相当于读这个虚拟文件。当连接完成就相当于把这个虚拟文件删除了。
查看计算机中活动的连接:
[root@linscora ~]# sar -n SOCK
Linux 2.6.18-164.el5 (linscora) 2010年03月28日
00时00分01秒 totsck tcpsck udpsck rawsck ip-frag
00时10分02秒 349 12 8 1 0
00时20分01秒 349 12 8 1 0
00时30分01秒 349 12 8 1 0
00时40分01秒 349 12 8 1 0
00时50分01秒 349 12 8 1 0
01时00分01秒 349 12 8 1 0
01时10分01秒 349 12 8 1 0
01时20分01秒 325 3 8 1 0
01时30分01秒 325 3 8 1 0
01时40分01秒 325 3 8 1 0
01时50分01秒 325 3 8 1 0
02时00分01秒 325 3 8 1 0
02时10分01秒 325 3 8 1 0
02时20分01秒 325 3 8 1 0
02时30分01秒 325 3 8 1 0
02时40分01秒 325 3 8 1 0
02时50分01秒 325 3 8 1 0
03时00分01秒 326 3 8 1 0
03时10分01秒 326 3 8 1 0
03时20分01秒 334 4 8 1 0
03时30分02秒 339 9 8 1 0
03时40分01秒 335 5 8 1 0
03时50分02秒 334 4 8 1 0
04时00分01秒 333 4 8 1 0
04时10分02秒 335 5 8 1 0
04时20分01秒 342 12 8 1 0
04时30分01秒 334 4 8 1 0
04时40分01秒 343 14 8 1 0
04时50分01秒 333 3 8 1 0
Average: 335 6 8 1 0
查看半连接半关闭状态的连接。说明这个连接超时了。在重试:
[root@linscora ~]# /bin/netstat -tapn |grep TIME_WAIT
tcp 0 0 192.168.128.22:45332 74.206.177.197:80 TIME_WAIT -
查看系统中正在被打开的进程和服务:
[root@linscora ~]# /usr/sbin/lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
portmap 2645 rpc 3u IPv4 8408 UDP *:sunrpc
portmap 2645 rpc 4u IPv4 8409 TCP *:sunrpc (LISTEN)
rpc.statd 2677 root 3u IPv4 8601 UDP *:736
rpc.statd 2677 root 6u IPv4 8517 UDP *:733
rpc.statd 2677 root 7u IPv4 8604 TCP *:739 (LISTEN)
sshd 3535 root 3u IPv6 11058 TCP *:ssh (LISTEN)
cupsd 3544 root 4u IPv4 11101 TCP localhost.localdomain:ipp (LISTEN)
cupsd 3544 root 6u IPv4 11104 UDP *:ipp
xinetd 3558 root 5u IPv4 11379 UDP *:tftp
avahi-dae 3668 avahi 13u IPv4 11759 UDP *:mdns
avahi-dae 3668 avahi 14u IPv6 11760 UDP *:mdns
avahi-dae 3668 avahi 15u IPv4 11761 UDP *:can-ferret-ssl
avahi-dae 3668 avahi 16u IPv6 11762 UDP *:50759
firefox 6168 linscora 82u IPv4 55388 TCP 192.168.128.22:60682-> (ESTABLISHED)
dhclient 6524 root 5u IPv4 21263 UDP *:bootpc
调优TCP连接的参数:
tcp在syn连接的时候会默认重新连接5次
net.ipv4.tcp_syn_retries
[root@linscora ~]# /sbin/sysctl -a |grep syn
net.ipv6.conf.eth1.max_desync_factor = 600
net.ipv6.conf.vmnet8.max_desync_factor = 600
net.ipv6.conf.vmnet1.max_desync_factor = 600
net.ipv6.conf.eth0.max_desync_factor = 600
net.ipv6.conf.default.max_desync_factor = 600
net.ipv6.conf.all.max_desync_factor = 600
net.ipv6.conf.lo.max_desync_factor = 600
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent = 120
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_syn_retries = 5
fs.quota.syncs = 26
没有成功的连接在队列里的长度:
net.ipv4.tcp_max_syn_backlog
是否同意重新连接TIME_WAIT状态的连接
net.ipv4.tcp_tw_recycle
TCP的存活时间:
[root@linscora ~]# /sbin/sysctl -a |grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200 单位秒
当一个连接保持了两个小时,内核发起查看这个会话是否连接成功。连续重试9次。每次间隔75秒。如果7200+9*75 秒还不成功。内核将中断连接。
阅读(3204) | 评论(0) | 转发(0) |