寻觅生命中的那一片浅草......

文章属于类别 性能

lsiutil设置磁盘带宽

1. 问题

DELL R410自带RAID卡是SAS6IR,机械盘接上去带宽是3G,而SSD,无论是三星还是闪迪,都只有1.5G,查看指令

./lsiutil -p1 -a 69,8,21,4,0,0

有问题的结果,其中1.5处为接SSD的端口

SAS1068E's links are 3.0 G, 3.0 G, 3.0 G, 1.5 G, off, off, off, off

2. 解决

2.1 方法一

换个RAID卡,如 PERC 6i或者H700,贵

2.2 方法二

换pcie口的SSD,价格是sata口的两倍,贵

2.3 方法三

可以通过lsiutil(要求Version 1.62或以上)设置磁盘的带宽,此机接了4个盘,所以,具体设置,请根据实际情况选择

[root@localhost src]# ./lsiutil -p1 -a 69

LSI Logic MPT Configuration Utility, Version 1.63, June 4, 2009

1 MPT Port found

     Port Name         Chip Vendor/Type/Rev    MPT Rev  Firmware Rev  IOC
 1.  /proc/mpt/ioc0    LSI Logic SAS1068E B3     105      00192f00     0

Main menu, select an option:  [1-99 or e/p/w or 0 to quit] 69

Seg/Bus/Dev/Fun    Board Name       Board Assembly   Board Tracer
 0   2   0   0     SAS6IR                                            

# 输入13进行操作
Main menu, select an option:  [1-99 or e/p/w or 0 to quit] 13  

# 以下3行,直接回车即可
SATA Maximum Queue Depth:  [0 to 255, default is 8] 
Device Missing Report Delay:  [0 to 2047, default is 0] 
Device Missing I/O Delay:  [0 to 255, default is 0] 

PhyNum  Link      MinRate  MaxRate  Initiator  Target    Port
   0    Enabled     1.5      3.0    Enabled    Disabled  Auto
   1    Enabled     1.5      3.0    Enabled    Disabled  Auto
   2    Enabled     1.5      3.0    Enabled    Disabled  Auto
   3    Enabled     1.5      3.0    Enabled    Disabled  Auto
   4    Disabled    1.5      3.0    Enabled    Disabled  Auto
   5    Disabled    1.5      3.0    Enabled    Disabled  Auto
   6    Disabled    1.5      3.0    Enabled    Disabled  Auto
   7    Disabled    1.5      3.0    Enabled    Disabled  Auto

# 此处选择3,是我们接SSD的位置
Select a Phy:  [0-7, 8=AllPhys, RETURN to quit] 3
# 直接回车
Link:  [0=Disabled, 1=Enabled, default is 1] 
# 设置最小带宽,关键操作,选择1
MinRate:  [0=1.5 Gbps, 1=3.0 Gbps, default is 0] 1
# 以下4行,直接回车
MaxRate:  [0=1.5 Gbps, 1=3.0 Gbps, default is 1] 
Initiator:  [0=Disabled, 1=Enabled, default is 1] 
Target:  [0=Disabled, 1=Enabled, default is 0] 
Port:  [0 to 7 for manual config, 8 for auto config, default is 8] 

PhyNum  Link      MinRate  MaxRate  Initiator  Target    Port
   0    Enabled     1.5      3.0    Enabled    Disabled  Auto
   1    Enabled     1.5      3.0    Enabled    Disabled  Auto
   2    Enabled     1.5      3.0    Enabled    Disabled  Auto
   # 注意看下面一行,MinRate为3.0代表设置正确
   3    Enabled     3.0      3.0    Enabled    Disabled  Auto
   4    Disabled    1.5      3.0    Enabled    Disabled  Auto
   5    Disabled    1.5      3.0    Enabled    Disabled  Auto
   6    Disabled    1.5      3.0    Enabled    Disabled  Auto
   7    Disabled    1.5      3.0    Enabled    Disabled  Auto

# 以下4行,直接回车
Select a Phy:  [0-7, 8=AllPhys, RETURN to quit] 
Persistence:  [0=Disabled, 1=Enabled, default is 1] 
Physical mapping:  [0=None, 1=DirectAttach, 2=EnclosureSlot, default is 2] 
Number of Target IDs to reserve:  [0 to 32, default is 8] 

# 输入0退出设置
Main menu, select an option:  [1-99 or e/p/w or 0 to quit] 0

经过以上设置,重启系统,再次确认,带宽已经变为3,cp大量小文件,性能也提升了50%

参考资料

zz:开启TCP BBR拥塞控制算法

网络加速,类似第三方软件:锐速(serverSpeeder)

而BBR则是内核级支持,由Google贡献的代码,详细请打开:开启TCP BBR拥塞控制算法

zz:Linux内核分析:页回收导致的cpu load瞬间飙高的问题分析与思考

看方法、思路,还有了解CPU和内存的运作方式

Linux内核分析:页回收导致的cpu load瞬间飙高的问题分析与思考

TCP的全连接队列和半连接队列

TCP连接的处理能力

最近某平台出现了白屏,黑屏的问题,查了下tcp方面的东西,目前来说,这些知识并没有解决问题,但总结下来,学习下。一个tcp连接进来,是否能连,是否能够被处理,是由系统和具体的应用程序来决定的。

系统层面

主要由2个内核参数,也就是2个队列决定,这是全局的,这里先解释下backlog这个单词的意思,就是堆积的作业,这里就是堆积的连接。

半连接

net.ipv4.tcp_max_syn_backlog 这个是半连接的队列长度,所谓半连接就是还没有完成3次握手的,状态是SYN_RECV

全连接

net.core.somaxconn 这个是一个socket的全连接队列长度,就是完成了3次握手但还没交给应用程序的队列长度,默认是128,状态是ESTABLISHED,需要注意,这个值,是基于socket的,例如socket1的队列不会影响到socket2的队列长度

在繁忙的系统,128这个值明显是不够的,如何判断somaxconn是否足够呢?可以用下面的命令,如果数字在不断增长,则应该增大somaxconn

netstat -s |grep listen

上面写的状态,可以用下面的命令看到

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

应用层序层面

在应用程序层面,则是在开启socket监听的时候,用listen(backlog)来设置,下面是我们的演示程序tcp_listen.py,88就是指可以有88个连接等待

import time
import socket
import struct

HOST = 'localhost'
PORT = 8000

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(88)

# /usr/include/linux/tcp.h
struct_tcp_info = struct.Struct('7B 24I')

while True:
    buf = s.getsockopt(socket.IPPROTO_TCP,
                       socket.TCP_INFO,
                       1024)
    tcp_info = struct_tcp_info.unpack(buf)
    tcpi_unacked, tcpi_sacked = tcp_info[11:13]
         
    print 'tcpi_unacked:', tcpi_unacked,\
        'tcpi_sacked:', tcpi_sacked

    time.sleep(1)

全连接中系统设置和应用设置的优先级

以下均是论述全连接backlog意思是堆积的作业数量

系统设置了tcp全连接的backlog,应用程序的listen又设置了backlog,那到底用那个?系统会对比2个backlog,取较小的一个,当系统设置net.core.somaxconn是128,而应用设置是listen(511),min(128,511),则是128

验证优先级

我们用tcp_listen.py来测试

CentOS 5.5

在CentOS 5.5上,很奇怪,执行后,print出来的一直都是0

tcpi_unacked: 0 tcpi_sacked: 0

如果要在CentOS5.5上测试,需要借助Systemtap来做检测,而不是看上面脚本print出来的值,安装Systemtap的过程略过(其实安装过程比较复杂)

probe begin {
 
  printf("inet listen Monitoring Started...\n")
 
}
 
  
 
probe kernel.function("inet_listen").return
 
{
 
    accept_backlog = $backlog
 
    recvq_backlog = @cast($sock->sk, "inet_connection_sock")->icsk_accept_queue->
 
            listen_opt->nr_table_entries
 
    printf("%-20s:accept backlog is %d, syn backlog is %d.\n", execname(),accept_backlog, recvq_backlog)
 
}

设置系统的backlog为1

sysctl -w net.core.somaxconn=1

程序设置,上面tcp_listen.py的值是88

s.listen(88)

我们开2个窗口,运行程序

stap listen.stp
python tcp_listen.py

可以看到 listen.stp的输出

python     :accept backlog is 1, syn backlog is 512.

看到了,程序是88,系统是1,最后取较小值,就是1,后面的512是半连接队列的长度

openSUSE 12.3 64bit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在这个系统上tcplisten.py打印就正常,同样按照上面CentOS,设置系统的backlog的值为1,tcplisten.py的listen不变,执行tcp_listen.py,输出是::

tcpi_unacked: 0 tcpi_sacked: 1

上面的输出,0可以理解为半连接的队列长度,后面的1可以认为是全连接的队列长度

TCP状态转换

TCP状态转换图

tcp_status

上图是TCP的状态转换,我们来验证下tcp的连接处理过程

连接处理过程

当 tcp 建立连接的 3 次握手完成后,将连接置入 ESTABLISHED 状态并交付给应用程序的 backlog 队列时,会检查 backlog 队列是否已满。若已满,通常行为是将连接还原至 SYNRECV 状态,也就是把它放到半连接队列里,保持上文提到的tcplisten.py里的listen为88,net.core.somaxconn = 1,运行tcp_listen.py,再开2个tab,telnet 8000端口,就是有2个telnet连接到8000端口::

telnet localhost 8000

此时通过

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

看到的都是ESTABLISHED状态的连接,此时,再开一个tab,同样执行telnet,并执行上面的netstat命令,则会看到

SYN_RECV 1

由此,验证了上面的连接处理过程中的半连接和全连接过程。

我们的全连接队列长度是1,但为什么上面一共是telnet了3次,才会出现SYN_RECV呢?我个人理解是第一个直接交给程序处理了,第二个是放在全连接队列,第三个才是放到半连接队列

关于net.ipv4.tcp_abort_on_overflow

关于白屏问题,我以为是上面的值引起的,上面的值,默认是0的,看了下系统的配置,也是0,而且白屏的时候,还没去到游戏连接哪里呢,估计还在某平台那里。

那么这个值是做什么的呢?上面的实验可以看到,我们全连接的队列满了,还可以进入半连接队列,如果将net.ipv4.tcp_abort_on_overflow设置为1,如果全连接队列满了,则服务器直接发送RST给客户端,用tcpdump可以看到,客户端如果要连接,则需要重头发起连接。

命令

sysctl -w net.ipv4.tcp_abort_on_overflow=1

开3个tab进行telnet,可以看到进行到底三个的时候,就提示

telnet: connect to address 127.0.0.1: Connection reset by peer
telnet: Unable to connect to remote host: Connection reset by peer

同时,用netstat命令看,也不会有SYN_RECV状态的连接

结论

根据观察,net.core.somaxconn的值设置为1024比较合适,像静态资源机,如果没有使用cdn,则需要设置为2048,如果是跨服机,最好也设置为2048

20141226补充

最后解决黑屏和白屏、延迟5000ms的问题,是以下这个参数

echo 1 > /proc/sys/net/ipv4/tcp_sack

当时还设置了另外一个参数::

echo 1 > /proc/sys/net/ipv4/tcp_window_scaling

但查资料,这个参数在内核2.6.8开始,默认就是1了,所以这个对黑屏、白屏是没有影响的

最后,设置sack,虽然减轻了网络传输的压力,但对客户端造成了一定的性能损耗,见tcp_sack

zz:TCP和Nginx性能调优

绝对干货,沿用文中所说,当别人贴出优化配置的时候,并没有告诉你为什么要这么优化,也没有贴出具体的场景,而这2篇,除了告诉你优化了什么,还说明了为什么要这么做:

Part 1: Lessons learned tuning TCP and Nginx in EC2

Part 2: Lessons learned tuning TCP and Nginx in EC2

 

2024年三月
« 5月    
 123
45678910
11121314151617
18192021222324
25262728293031