2013-07-17 11:58:36 hyl198611 阅读数 35
  • C++socket网络编程--http服务器(支持php)实战教学视频

    C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本课程会同时演示在linux和windows中的编程,课程中的线程和正则表达式都使用c++提供库。本课程包含了socket网络编程常用的所有特性,包括tcp、udp协议的基础编程,广播包,超时连接,多路复用,高并发的epoll多路复用,多线程的服务端。课程讲解理论与实践相结合,实践以代码延时讲解为主。

    21797 人正在学习 去看看 夏曹俊

/proc/sys/fs/file-max

fs.file-max = 999999 # 进程可以同时打开的最大句柄数

/etc/sysctl.conf

net.ipv4.tcp_tw_reuse = 1 # 重用 TIME_WAIT 状态的 socket

net.ipv4.tcp_keepalive_time = 600 # 当 keepalive 启用时,TCP 发送 keepalive 消息的频度

net.ipv4.tcp_fin_timeout = 30 # socket 保持在 FIN_WAIT_2 状态的最大时间

net.ipv4.tcp_max_tw_buckets = 5000 # 操作系统允许 TIME_WAIT socket 的最大数量

net.ipv4.ip_local_port_ tange = 1024 61000 # 定义在 UDP和 TCP 连接中本地端口的取值范围

net.ipv4.tcp_rmem = 4096 32768 262142 # TCP 接收缓存的最小值、默认值、最大值

net.ipv4.tcp_wmem = 4096 32768 262142 # TCP 发送缓存的最小值、默认值、最大值

net.core.netdev_max_backlog = 8096 # 当网卡接收数据包的速度大于内核处理的速度时,保存队列的最大值

net.core.rmem_default = 262144 # 内核 socket 接收缓存区默认的大小

net.core.wmem_default = 212144 # 内核 socket 发送缓存区默认的大小

net.core.rmem_max = 2097152 # 内核 socket 接收缓存区的最大大小

net.core.wmem_max = 2097152 # 内核 socket 发送缓存区的最大大小

net.ipv4.tcp_syncookies = 1 # 防止 TCP SYN 攻击

net.ipv4.tcp_max_syn.backlog = 1024 # TCP 三次握手建立阶段接收 SYN 请求队列的最大长度,默认为 1024

转自:http://www.moyan.tk/article/programming/server/17.html

2018-07-01 19:01:29 Dong_Alex 阅读数 834
  • C++socket网络编程--http服务器(支持php)实战教学视频

    C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本课程会同时演示在linux和windows中的编程,课程中的线程和正则表达式都使用c++提供库。本课程包含了socket网络编程常用的所有特性,包括tcp、udp协议的基础编程,广播包,超时连接,多路复用,高并发的epoll多路复用,多线程的服务端。课程讲解理论与实践相结合,实践以代码延时讲解为主。

    21797 人正在学习 去看看 夏曹俊
linux安装服务器压力测试工具siege

简介:
Siege是一个压力测试和评测工具,设计用于WEB开发这评估应用在压力下的承受能力:可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行。
Siege是一个多线程http负载测试基准测试工具。
Siege:这是Linux系统下的一个测试工具,完全使用C语言实现,可以对HTTP和FTP服务器进行负载和性能测试。通过使用Siege 提供的功能,可以很容易的制定测试计划:包括规定使用并发用户数、重复数量,从而可以模拟在服务器、网络或者其它对象上附加负载以测试他们提供服务的受压能力,方便的测试服务器的性能。最后,利用Siege提供的测试结果来分析性能指标或者分析他们提供的服务在不同负载条件下的性能情况,分析测试结果,找出影响系统性能的瓶颈。

我的环境: linux centos7.x

打开网页


点release, 从这里获取发行版下载地址


选择合适的版本, 在这我选择v4.0.4 , 复制 'tar.gz'的超链接地址

安装依赖
yum install autoconf libtool
# 安装依赖 libssl , 这个yum没有, 需要下载源码安装, 如果没有此依赖, 将无法测试https的地址
官网:https://www.openssl.org/;
下载页面:https://www.openssl.org/source/;
源码地址:https://www.openssl.org/source/openssl-1.0.1t.tar.gz ;
# 下载
wget https://www.openssl.org/source/openssl-1.0.1t.tar.gz
# 解压
tar zxvf openssl-1.0.1t.tar.gz
# 切换到目录
cd openssl-1.0.1t
# 配置 注意是config 不是Configure
./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl
# 编译安装
make && make install


# 使用wget 下载siege源码

# 解压
tar zxvf siege_v4.0.4

# 进入目录
cd siege-4.0.4/

# 重要提示, 如果下载的是github上的release版本, 那么是没有带configure 配置文件的, 需要自己生成, 如果是其它地方下载的可能已经是带有configure配置文件的, 就不需要再生成!

# 查看有没有带configure
ls
如下面是没有带configure的


# siege源码目录没有configure配置文件,生成configure 如果有就忽略生成configure这一步骤
utils/bootstrap

# 配置
./configure --prefix=/usr/local/siege_4.0.4

# 编译 安装
make && make install

如果上面操作没有出来error, 基本上说明安装成功了!
使用一下来证明:
# 切换到安装目录
cd /usr/local/siege_4.0.4/bin

# 测试百度首页 50并发, 执行两次
./siege -c 50 -r 2 https://www.baidu.com -i -b

虚拟机下linux测试


腾讯云服务器上测试


上面测试说明以腾讯云服务器上测试为准:
Transactions 900 hits // 一共访问900次
Availability 100.00% // 访问成功率100%
Elapsed time 9.98 // 测试一共用了9.98秒
Data transferred 23.47M //测试传输的数据量
Response time: 0.31 //平均响应时间0.31秒
Transaction rate 90.18 //每秒事务处理量 tps (Transactions /Elapsed time)
Throughput 2.35M/s // 每秒吞吐量 (Data transferred/Elapsed time)
Concurrency 27.96 //并发用户数 (900*0.31/9.98)
Successful transactions 900 //成功900
Failed transactions 0 //失败没有
Longest transaction 7.85 //最长响应时间7.85秒
Shortest transaction: 0.03 //最短响应时间0.03秒

参数说明:
输入名称
解释说明
-V, –version
打印版本信息
-h, –help
打印帮助信息
-C, –config
显示配置信息
-v, –verbose
打印冗余配置信息。
-g, –get
显示HTTP交易。
-c, –concurrent=NUM
设置并发用户数
-u, –url=”URL”
设置被测Web的URL
-i, –internet
用户模拟、随机访问URL
-b, –benchmark .
基准测试。
-t, –time=NUM
设置测试时间。
-r, –reps=NUM
设置测试次数
-f, –file=FILE
更改配置文件存档
-R, –rc=FILE
更改siegerc文件和环境变量
-l, –log
测试日志
-m, –mark=”text”
标记测试日志
-d, –delay=NUM
设置时间延迟
-H, –header=”text”
增加测试头文件
-A, –user-agent=”text”
设置代理测试请求


/END



2013-06-25 21:41:14 yifeixiang 阅读数 320
  • C++socket网络编程--http服务器(支持php)实战教学视频

    C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本课程会同时演示在linux和windows中的编程,课程中的线程和正则表达式都使用c++提供库。本课程包含了socket网络编程常用的所有特性,包括tcp、udp协议的基础编程,广播包,超时连接,多路复用,高并发的epoll多路复用,多线程的服务端。课程讲解理论与实践相结合,实践以代码延时讲解为主。

    21797 人正在学习 去看看 夏曹俊
软连接
ln -s /home/ictfmcg/data/photo /var/jtnd/data/photo


tomcat 6的Connector配置如下

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="800" acceptCount="1000"/>



其中最后两个参数意义如下:

maxThreads:tomcat起动的最大线程数,即同时处理的任务个数,默认值为200

acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100



这两个值如何起作用,请看下面三种情况

情况1:接受一个请求,此时tomcat起动的线程数没有到达maxThreads,tomcat会起动一个线程来处理此请求。

情况2:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,tomcat会把此请求放入等待队列,等待空闲线程。

情况3:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,等待队列中的请求个数也达到了acceptCount,此时tomcat会直接拒绝此次请求,返回connection refused

maxThreads如何配置

一般的服务器操作都包括量方面:1计算(主要消耗cpu),2等待(io、数据库等)

第一种极端情况,如果我们的操作是纯粹的计算,那么系统响应时间的主要限制就是cpu的运算能力,此时maxThreads应该尽量设的小,降低同一时间内争抢cpu的线程个数,可以提高计算效率,提高系统的整体处理能力。

第二种极端情况,如果我们的操作纯粹是IO或者数据库,那么响应时间的主要限制就变为等待外部资源,此时maxThreads应该尽量设的大,这样才能提高同时处理请求的个数,从而提高系统整体的处理能力。此情况下因为tomcat同时处理的请求量会比较大,所以需要关注一下tomcat的虚拟机内存设置和linux的open file限制。

我在测试时遇到一个问题,maxThreads我设置的比较大比如3000,当服务的线程数大到一定程度时,一般是2000出头,单次请求的响应时间就会急剧的增加,

百思不得其解这是为什么,四处寻求答案无果,最后我总结的原因可能是cpu在线程切换时消耗的时间随着线程数量的增加越来越大,

cpu把大多数时间都用来在这2000多个线程直接切换上了,当然cpu就没有时间来处理我们的程序了。

以前一直简单的认为多线程=高效率。。其实多线程本身并不能提高cpu效率,线程过多反而会降低cpu效率。

当cpu核心数<线程数时,cpu就需要在多个线程直接来回切换,以保证每个线程都会获得cpu时间,即通常我们说的并发执行。

所以maxThreads的配置绝对不是越大越好。

现实应用中,我们的操作都会包含以上两种类型(计算、等待),所以maxThreads的配置并没有一个最优值,一定要根据具体情况来配置。

最好的做法是:在不断测试的基础上,不断调整、优化,才能得到最合理的配置。

acceptCount的配置,我一般是设置的跟maxThreads一样大,这个值应该是主要根据应用的访问峰值与平均值来权衡配置的。

如果设的较小,可以保证接受的请求较快相应,但是超出的请求可能就直接被拒绝

如果设的较大,可能就会出现大量的请求超时的情况,因为我们系统的处理能力是一定的。
1、查看apache当前并发访问数: www.2cto.com
  
netstat -an | grep ESTABLISHED | wc -l
  
对比httpd.conf中MaxClients的数字差距多少。
  
2、查看有多少个进程数:
  
ps aux|grep httpd|wc -l

  
3、可以使用如下参数查看数据
  server-status?auto
  
#ps -ef|grep httpd|wc -l

  1388
  统计httpd进程数,连个请求会启动一个进程,使用于Apache服务器。
  表示Apache能够处理1388个并发请求,这个值Apache可根据负载情况自动调整。
  
#netstat -nat|grep -i "80"|wc -l

  4341
  netstat -an会打印系统当前网络链接状态,而grep -i "80"是用来提取与80端口有关的连接的,wc -l进行连接数统计。 www.2cto.com
  最终返回的数字就是当前所有80端口的请求总数。
  
#netstat -na|grep ESTABLISHED|wc -l

  376
  netstat -an会打印系统当前网络链接状态,而grep ESTABLISHED 提取出已建立连接的信息。 然后wc -l统计。
  最终返回的数字就是当前所有80端口的已建立连接的总数。
  
netstat -nat||grep ESTABLISHED|wc

- 可查看所有建立连接的详细记录

  查看Apache的并发请求数及其TCP连接状态:
  Linux命令:
  
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

  返回结果示例:
  LAST_ACK 5
  SYN_RECV 30
  ESTABLISHED 1597
  FIN_WAIT1 51
  FIN_WAIT2 504
  TIME_WAIT 1057
  其中的
  SYN_RECV表示正在等待处理的请求数;
  ESTABLISHED表示正常数据传输状态;
  TIME_WAIT表示处理完毕,等待超时结束的请求数。(这个参数还不太懂,为啥是等待超时结束,请大神指教)
2017-08-22 11:10:17 weixin_36088221 阅读数 326
  • C++socket网络编程--http服务器(支持php)实战教学视频

    C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本课程会同时演示在linux和windows中的编程,课程中的线程和正则表达式都使用c++提供库。本课程包含了socket网络编程常用的所有特性,包括tcp、udp协议的基础编程,广播包,超时连接,多路复用,高并发的epoll多路复用,多线程的服务端。课程讲解理论与实践相结合,实践以代码延时讲解为主。

    21797 人正在学习 去看看 夏曹俊

关于Niginx,还是推荐使用Linux版本,Windows版本太鸡肋,很多配置局限,请自行感受。

老样子,废话不多说,在我这里只有干货。


下面是一个简单的nginx 配置文件:
user www www;
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000
01000000;
error_log /www/log/nginx_error.log crit;
pid /usr/local/nginx/nginx.pid;
worker_rlimit_nofile 204800;
events
{
use epoll;
worker_connections 204800;
}
http
{
include mime.types;
default_type application/octet-stream;
charset utf-8;
server_names_hash_bucket_size 128;
client_header_buffer_size 2k;
large_client_header_buffers 4 4k;
client_max_body_size 8m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2
keys_zone=TEST:10m
inactive=5m;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 4k;
fastcgi_buffers 8 4k;
fastcgi_busy_buffers_size 8k;
fastcgi_temp_file_write_size 8k;
fastcgi_cache TEST;
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeout invalid_header http_500;
open_file_cache max=204800 inactive=20s;
open_file_cache_min_uses 1;
open_file_cache_valid 30s;
tcp_nodelay on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;
server
{
listen 8080;
server_name backup.aiju.com;
index index.php index.htm;
root /www/html/;
location /status
{
stub_status on;
}
location ~ .*\.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$
{
expires 30d;
}
log_format access '$remote_addr -- $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_for';
access_log /www/log/access.log access;
}
}
关于FastCGI 的几个指令:
fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=TEST:10minactive=5m;
这个指令为FastCGI 缓存指定一个路径,目录结构等级,关键字区域存储时间和非活动删除时间。
fastcgi_connect_timeout 300;
指定连接到后端FastCGI 的超时时间。
fastcgi_send_timeout 300;
向FastCGI 传送请求的超时时间,这个值是指已经完成两次握手后向FastCGI 传送请求的超时时间。
fastcgi_read_timeout 300;
接收FastCGI 应答的超时时间,这个值是指已经完成两次握手后接收FastCGI 应答的超时时间。
fastcgi_buffer_size 4k;
指定读取FastCGI 应答第一部分需要用多大的缓冲区,一般第一部分应答不会超过1k,由于页面大小为4k,所以这里设置为4k。
fastcgi_buffers 8 4k;
指定本地需要用多少和多大的缓冲区来缓冲FastCGI 的应答。
fastcgi_busy_buffers_size 8k;
这个指令我也不知道是做什么用,只知道默认值是fastcgi_buffers 的两倍。
fastcgi_temp_file_write_size 8k;
在写入fastcgi_temp_path 时将用多大的数据块,默认值是fastcgi_buffers 的两倍。
fastcgi_cache TEST
开启FastCGI 缓存并且为其制定一个名称。个人感觉开启缓存非常有用,可以有效降低CPU 负载,并且防止502 错误。
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
为指定的应答代码指定缓存时间,如上例中将200,302 应答缓存一小时,301 应答缓存1 天,其他为1 分钟。
fastcgi_cache_min_uses 1;
缓存在fastcgi_cache_path 指令inactive 参数值时间内的最少使用次数,如上例,如果在5 分钟内某文件1 次也没有被使用,那么这个文件将被移除。
fastcgi_cache_use_stale error timeout invalid_header http_500;
不知道这个参数的作用,猜想应该是让nginx 知道哪些类型的缓存是没用的。以上为nginx 中FastCGI 相关参数,另外,FastCGI 自身也有一些配置需要进行优化,如果你使用php-fpm 来管理FastCGI,可以修改配置文件中的以下值:
<value name="max_children">60</value>
同时处理的并发请求数,即它将开启最多60 个子线程来处理并发连接。
<value name="rlimit_files">102400</value>
最多打开文件数。
<value name="max_requests">204800</value>
每个进程在重置之前能够执行的最多请求数。


以上配置,请自行抛砖引玉,关于节点的介绍就不赘述了,官方文档很详细。

配置好Niginx还不够,并发依然上不来,原因是nginx所在服务器的限制,需要对linux内核进行调优。

传送门: 【干货】Linux服务器高并发调优实战

2015-01-13 11:40:28 weiqubo 阅读数 2789
  • C++socket网络编程--http服务器(支持php)实战教学视频

    C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本课程会同时演示在linux和windows中的编程,课程中的线程和正则表达式都使用c++提供库。本课程包含了socket网络编程常用的所有特性,包括tcp、udp协议的基础编程,广播包,超时连接,多路复用,高并发的epoll多路复用,多线程的服务端。课程讲解理论与实践相结合,实践以代码延时讲解为主。

    21797 人正在学习 去看看 夏曹俊

随着internet的发展,更高效率、更多并发连接数的服务已经成为当前迫切的需要。我们虽然可以采用UDP这样的无连接协议来解除连接限制(事实上这个限制也同样是存在的,尤其是当一个UDP处理需要占用不少CPU处理时间的情况下其上限也就越小),但是这样的方案并不能解决所有问题(例如从服务端发出给连接客户端的及时消息)。  

    解决这个问题的一种途径是线程池(Thread Pool),并在各个线程中运行单独的select()以实现对网络事件的多路分离。select其实的内部机制依赖于fd_set,说白了就是一个数组,select通过遍历这个数组中的所有socket handle,通过ioctl判断该handle是否被激活的socket事件。因此,我们可以对select得出两个结论: 
      1)select可以在多线程中分离使用,但是我们需要实现一个机制,以便在多个线程之间平均的划分socket handles,从而在各个线程之间平均分摊负载。 
      2)由于需要不停的(循环的)遍历一个fd_set数组,当这个数组变得很大的时候select就会显得效率低下(简直难以忍受,这就是为什么在windows中FD_SETSIZE的缺省大小为64的原因)  
      从以上的结论我们看到,采用select和线程池的方式解决以上问题应该是一种方法。但是我想这个问题还没完,因为这还不是我看来最有高效的解决方案。为什么这么说呢,首先select的选择能力有限,假设我们使用最大的FD_SETSIZE=1024,这样,我们需要10个左右不停循环的线程,由于每个线程每次遍历fd_set所花费的时间较长,10个不停循环的线程将很有可能使服务进程阻塞,占用大量的CPU资源,由于我们不是单纯的保持这些TCP连接就万事大吉了,我们还得对这些连接的请求进行处理,而服务器恐怕此时已经难以承担(当然,采用提高硬件配置、多CPU的方式可以有效解决这一问题,但这不是我们做软件的应该带给系统的其他成员的。如果采用FD_SETSIZE=64的方案呢?这样我们将在线程池中运行大约16*10=160个线程,考虑线程间切换和同步开销,该方案仍然是比较难忍受的。  
      如何解决这个问题?从目前的情况看,
问题主要还是存在于select这一古老socket api 函数的瓶颈上。(毕竟线程间切换和同步开销问题是无法解决的)。于是我们考虑是否可以用poll或epoll多路分离来解决这个瓶颈问题。poll和select其实是采用的同种机制,因此其效率不会比select高多少。epoll提供Edge Triggered ( ET ) 和Level Triggered ( LT )两种方式的多路事件分离方法,使用LT方式时,其效果与select和poll相似,顶多可以看成是一个更快的poll;但在使用ET方式时其效率在处理具有大量idle connection的时候明显高于select和poll,在处理always busy connection等情况时,效率与select和poll没有多大区别。(关于这些效能的比较可以参考[1]中的Fig5和Fig6)当然,epoll比起poll和select来说缺省的最大FD大小更大,不过这其实不是问题,因为我们都可以修改其水平边界的大小的。补充一点,由于epoll、poll和select都使用文件描述符fd作为数组的索引,而在普通系统中一个FD的定义是integer,也就是说它是存在上限的,在C中一个int通常是16位的,也就是说最大文件句柄数32768(不是65536哦;-)构成了单个fd_set的上限。见[2] 
      实际情况下,很少有服务的连接是always busy connection的,也就是说客户端一但建立和与服务端的TCP连接后,该连接在很多时侯是处于idle connection状态的,它只是在有数据需要传送的时候才处于busy connection状态的。换句话说,在实际服务情况下,使用ET模式的epoll(以下的epoll都是指在ET模式下的)比使用poll和select具有更高的效率。这样看来,使用epoll比使用select或poll在单线程中具有更高的处理效率和更大的处理连接数。它仅使用单个线程就已经能处理前面问题中所提到的并发10K连接数问题。          
      至此,前面提出的10K连接数问题已经基本解决。但是我认为这还只是个开始,我们常见一些服务能够支持1M以上的同时连接数。为达到这个目的,我们需要将线程池和epoll结合起来,即,在多个线程中使用epoll_wait[3]等待多个socket events的到达。这带来了另外一些深层次的问题: 
      1)socket descript的限制,在大多数系统中SOCKET对应的是integer,其连接数是有上限的;      

      2)线程间同步及流量分配问题,需要为每个线程合理的分配连接以达到负载平衡;       

      3)服务质量问题,防止出现饿死现象。  

1、修改用户进程可打开文件数限制

在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。可使用ulimit命令查看系统允许 当前用户进程打开的文件数限制:
[speng@as4 ~]$ ulimit -n
1024
这表示当前用户的每个进程最多允许同时打开1024个文件,这1024个文件中还得除去每个进程必然打开的标准输入,标准输出,标准错误,服务器监听 socket,进程间通讯的unix域socket等文件,那么剩下的可用于客户端socket连接的文件数就只有大概1024-10=1014个左右。 也就是说缺省情况下,基于Linux的通讯程序最多允许同时1014个TCP并发连接。

对于想支持更高数量的TCP并发连接的通讯处理程序,就必须修改Linux对当前用户的进程同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。其中软限制是指Linux在当前系统能够承受的范围内进一步限制用户同时打开的文件数;硬限制则是根据系统 硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。通常软限制小于或等于硬限制。

修改上述限制的最简单的办法就是使用ulimit命令:
[speng@as4 ~]$ ulimit -n <file_num>
上述命令中,在<file_num>中指定要设置的单一进程允许打开的最大文件数。如果系统回显类似于“Operation notpermitted”之类的话,说明上述限制修改失败,实际上是因为在<file_num>中指定的数值超过了Linux系统对该用户 打开文件数的软限制或硬限制。因此,就需要修改Linux系统对用户的关于打开文件数的软限制和硬限制。

第一步,修改/etc/security/limits.conf文件,在文件中添加如下行:
speng soft nofile 10240
speng hard nofile 10240
其中speng指定了要修改哪个用户的打开文件数限制,可用'*'号表示修改所有用户的限制;soft或hard指定要修改软限制还是硬限制;10240则指定了想要修改的新的限制值,即最大打开文件数(请注意软限制值要小于或等于硬限制)。修改完后保存文件。

第二步,修改/etc/pam.d/login文件,在文件中添加如下行:
session required /lib/security/pam_limits.so
这是告诉Linux在用户完成系统登录后,应该调用pam_limits.so模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开 的最大文件数限制),而pam_limits.so模块就会从/etc/security/limits.conf文件中读取配置来设置这些限制值。修改 完后保存此文件。

第三步,查看Linux系统级的最大打开文件数限制,使用如下命令:
[speng@as4 ~]$ cat /proc/sys/fs/file-max
12158
这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)12158个文件,是Linux系统级硬限制,所有用户级的打开文件数限制 都不应超过这个数值。通常这个系统级硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不 应该修改此限制,除非想为用户级打开文件数限制设置超过此限制的值。修改此硬限制的方法是修改/etc/rc.local脚本,在脚本中添加如下行:
echo 22158 > /proc/sys/fs/file-max
这是让Linux在启动完成后强行将系统级打开文件数硬限制设置为22158。修改完后保存此文件。

完成上述步骤后重启系统,一般情况下就可以将Linux系统对指定用户的单一进程允许同时打开的最大文件数限制设为指定的数值。如果重启后用 ulimit-n命令查看用户可打开文件数限制仍然低于上述步骤中设置的最大值,这可能是因为在用户登录脚本/etc/profile中使用 ulimit-n命令已经将用户可同时打开的文件数做了限制。由于通过ulimit-n修改系统对用户可同时打开文件的最大数限制时,新修改的值只能小于 或等于上次ulimit-n设置的值,因此想用此命令增大这个限制值是不可能的。所以,如果有上述问题存在,就只能去打开/etc/profile脚本文 件,在文件中查找是否使用了ulimit-n限制了用户可同时打开的最大文件数量,如果找到,则删除这行命令,或者将其设置的值改为合适的值,然后保存文 件,用户退出并重新登录系统即可。
通过上述步骤,就为支持高并发TCP连接处理的通讯处理程序解除关于打开文件数量方面的系统限制。

2、修改网络内核对TCP连接的有关限制

在Linux上编写支持高并发TCP连接的客户端通讯处理程序时,有时会发现尽管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接的现象。出现这种现在的原因有多种。

第一种原因可能是因为Linux网络内核对本地端口号范围有限制。此时,进一步分析为什么无法建立TCP连接,会发现问题出在connect()调用返 回失败,查看系统错误提示消息是“Can't assign requestedaddress”。同时,如果在此时用tcpdump工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况 说明问题在于本地Linux系统内核中有限制。其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如,内核限制本地端口号的范围为1024~32768之间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由于每 个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),如果现有的TCP客户端连接已将所有的本地端口号占满,则此 时就无法为新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can't assignrequested address”。有关这些控制逻辑可以查看Linux内核源代码,以linux2.6内核为例,可以查看tcp_ipv4.c文件中如下函数:
static int tcp_v4_hash_connect(struct sock *sk)
请注意上述函数中对变量sysctl_local_port_range的访问控制。变量sysctl_local_port_range的初始化则是在tcp.c文件中的如下函数中设置:
void __init tcp_init(void)
内核编译时默认设置的本地端口号范围可能太小,因此需要修改此本地端口范围限制。
第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
net.ipv4.ip_local_port_range = 1024 65000
这表明将系统对本地端口范围限制设置为1024~65000之间。请注意,本地端口范围的最小值必须大于或等于1024;而端口范围的最大值则应小于或等于65535。修改完后保存此文件。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明新的本地端口范围设置成功。如果按上述端口范围进行设置,则理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。

第二种无法建立TCP连接的原因可能是因为Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。此时程序会表现为在 connect()调用中阻塞,如同死机,如果用tcpdump工具监视网络,也会发现根本没有TCP连接时客户端发SYN包的网络流量。由于 IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位于内核内存中的conntrackdatabase中,这个数据库 的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法为新的TCP连接建立跟踪信息,于是表现为在connect()调用 中阻塞。此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:
第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
net.ipv4.ip_conntrack_max = 10240
这表明将系统对最大跟踪的TCP连接数限制设置为10240。请注意,此限制值要尽量小,以节省对内核内存的占用。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明系统对新的最大跟踪的TCP连接数限制修改成功。如果按上述参数进行设置,则理论上单独一个进程最多可以同时建立10000多个TCP客户端连接。

3、使用支持高并发网络I/O的编程技术

在Linux上编写高并发TCP连接应用程序时,必须使用合适的网络I/O技术和I/O事件分派机制。

可用的I/O技术有同步I/O,非阻塞式同步I/O(也称反应式I/O),以及异步I/O。在高TCP并发的情形下,如果使用同步I/O,这会严重阻塞 程序的运转,除非为每个TCP连接的I/O创建一个线程。但是,过多的线程又会因系统对线程的调度造成巨大开销。因此,在高TCP并发的情形下使用同步I /O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O。非阻塞式同步I/O的技术包括使用select(),poll(),epoll等机 制。异步I/O的技术就是使用AIO。

从I/O事件分派机制来看,使用select()是不合适的,因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能,poll()也是 不合适的,尽管它可以支持的较高的TCP并发数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在I/O事件分派不均,导致部 分TCP连接上的I/O出现“饥饿”现象。而如果使用epoll或AIO,则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个I /O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题。但在最新的Linux内核中,AIO的实现已经得到 改进)。

综上所述,在开发支持高并发TCP连接的Linux应用程序时,应尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证。

没有更多推荐了,返回首页