高并发探寻之路

  • TCP连接数
  • IO多复用

系统层
fs.file-max = 40000500
fs.nr_open = 40000500
# apr_socket_recv这个是操作系统内核的一个参数,在高并发的情况下,内核会认为系统受到了SYN flood攻击,
# 会发送cookies(possible SYN flooding on port 80. Sending cookies),这样会减慢影响请求的速度,所以在应用服务武# 器上设置下这个参数为0禁用系统保护(此参数是为了防止洪水攻击的,但对于大并发系统,要禁用此设置)
net.ipv4.tcp_syncookies = 0
# 参数决定了SYN_RECV状态队列的数量,一般默认值为512或者1024,即超过这个数量,
# 系统将不再接受新的TCP连接请求,一定程度上可以防止系统资源耗尽。
# 可根据情况增加该值以接受更多的连接请求。
net.ipv4.tcp_max_syn_backlog 


echo 20000 65535 > /proc/sys/net/ipv4/ip_local_port_range
echo 20000 > /proc/sys/net/ipv4/tcp_max_tw_buckets
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
// 单个进程能够打开的最大文件句柄数量,缺省值是1024
ulimit -n 20000500

root用户可以任意调高资源限额,整个系统的总体限制是/proc/sys/fs/file-max里的数字,root用户的进程依然会受到ulimit -n的数字的限制,但root用户可以在程序运行之前,调用ulimit -n命令来修改这个限制(有些init_scripts就是这样做的),也可以在进程内部通过set_limit系统调用来提高上限。相比之下,普通用户也可通过这两种方式修改限制,但有上限即hard limit(默认一般是4096),而root可以无限提高这个限制。

nginx层
// 同时进行工作的**进程**数量,建议与系统CPU核数一致。
worker_processes auto;
// 是一个工作进程最多可以打开多少个文件句柄。
worker_rlimit_nofile 65535;
events {
	user epoll;
	worker_connections 2048000;
}

worker_processes

工作进程是单线程进程。 如果Nginx正在进行CPU密集型工作(如SSL或gzipping),并且您有2个或更多CPU /核心,则可以将worker_processes设置为等于CPU或核心数。 如果您提供大量静态文件并且文件的总大小大于可用内存,那么您可以增加worker_processes以充分利用磁盘带宽。默认值为等于CPU或核心数。

worker_connections

main部分中的worker_connections和worker_processes允许您计算可以处理的最大客户端:

> max clients = worker_processes * worker_connections
> ```



既然**ulimit** **-n**默认是1024,为何很多进程打开的文件句柄数还会超过1024达到好几万呢?

### 压测

ab -n100000 -c20000 http://127.0.0.1/

This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient) socket: Too many open files (24)


> 出现这个问题是,是由于当前终端不支持同时打开如此多的文件描述符句柄。可以采用`ulimit -a`查看`-n`的值为多少:
>
> ```
> ulimit -a
> ...
> open files                      (-n) 1024
> ...
> ```
>
> 我们可以选择将ab中的参数 -c 调整为1024,也可以通过`ulimit -n 20000`调整,需要注意的是本次调整只对当前终端有效,当关闭终端重新打开时,需要重新设置。 

### 监控方法

#### 命令形式

统计 TCP连接数 命令:

netstat -an |grep ‘ESTABLISHED’ |grep ‘tcp’ |wc -l


> LISTEN:侦听来自远方的TCP端口的连接请求;
> SYN-SENT:在发送连接请求后等待匹配的连接请求;
> SYN-RECEIVED:在收到和发送一个连接请求后等待对方对连接请求的确认;
> ESTABLISHED:代表一个打开的连接,我们常用此作为并发连接数;
> FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认;
> FIN-WAIT-2:从远程TCP等待连接中断请求;
> CLOSE-WAIT:等待从本地用户发来的连接中断请求;
> CLOSING:等待远程TCP对连接中断的确认;
> LAST-ACK:等待原来发向远程TCP的连接中断的确认;
> TIME-WAIT:等待足够的时间以确保远程TCP连接收到中断请求的确认;
> CLOSED:没有任何连接状态;

#### WEB形式

在nginx配置文件中加入

location /ngx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }


>```
>Active connections: 2 
>server accepts handled requests
> 10223 10223 10266 
>Reading: 0 Writing: 1 Waiting: 1 
>```

### 结果

#### Widows

> AMD 3900X 24核32G

ab -n100000 -c10000 http://127.0.0.1/ This is ApacheBench, Version 2.3 <$Revision: 1879490 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient) Completed 10000 requests Completed 20000 requests Completed 30000 requests Completed 40000 requests Completed 50000 requests Completed 60000 requests Completed 70000 requests Completed 80000 requests Completed 90000 requests Completed 100000 requests Finished 100000 requests

Server Software: nginx/1.21.3 Server Hostname: 127.0.0.1 Server Port: 80

Document Path: / Document Length: 2 bytes

Concurrency Level: 10000 Time taken for tests: 49.107 seconds Complete requests: 100000 Failed requests: 0 Total transferred: 14300000 bytes HTML transferred: 200000 bytes Requests per second: 2036.37 #/sec Time per request: 4910.687 ms Time per request: 0.491 ms Transfer rate: 284.38 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.4 0 3 Processing: 1639 4703 604.8 4914 5059 Waiting: 0 2441 1242.2 2414 4756 Total: 1639 4703 604.8 4914 5059

Percentage of the requests served within a certain time (ms) 50% 4914 66% 4945 75% 4962 80% 4968 90% 4988 95% 5010 98% 5040 99% 5048 100% 5059 (longest request)


#### centos

> 4核8G 虚拟机

./wrk -c10000 -d20 -t100 http://127.0.0.1/

Running 20s test @ http://127.0.0.1/ 100 threads and 10000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 401.08ms 351.67ms 2.00s 78.45% Req/Sec 29.58 25.96 436.00 86.21% 119953 requests in 20.36s, 16.93MB read Socket errors: connect 0, read 77, write 0, timeout 1171 Requests/sec: 5890.46 Transfer/sec: 851.35KB


#### Mac

> 8核16G

#wrk -t88 -d20s -c100 "http://127.0.0.1/" Running 20s test @ http://127.0.0.1/ 88 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 814.56us 57.93us 2.66ms 90.27% Req/Sec 1.23k 28.16 1.45k 79.98% 2161706 requests in 20.10s, 315.42MB read Requests/sec: 107551.54 Transfer/sec: 15.69MB ```