Nginx 单机百万QPS环境搭建
一、背景
最近公司在做一些物联网产品,物物通信用的是MQTT协议,内部权限与内部关系等业务逻辑准备用HTTP实现。leader要求在本地测试中要模拟出百万用户同时在线的需求。虽然该产品最后不一定有这么多,但是既然要求到了就要模拟出来。MQTT用的是erlang的emqtt,这个已经有同事测试在本机可以百万用户在线了。不过HTTP服务器就一直很难。
所以这篇博客准备介绍如何在本地模拟一台支持百万qps的HTTP服务器。简单说一下,MQTT的百万在线是指支持百万TCP连接,连接后,只要保持心跳包就可以了,这个比较简单,一般稍微调整一下Linux一些系统参数就可以了。而HTTP的百万在线不一样。HTTP是发送一个连接请求后获得数据然后就关闭连接,百万并发就比较麻烦,而且这个概念用在这里不是很合适。现在比较通用的一种参考值是每秒处理的并发数。就是QPS。(这一点就很多人不理解。包括我leader,这个要在接下来慢慢解释给他听)
二、准备
我以前也没有搞过高并发的网络,最近看了一些博客文章,准备用一个最简单的模型来实现这个百万QPS的模拟。后台我是用Java写的,Tomcat服务器。这种带业务的请求,单机绝对不可能到达百万QPS(1m-qps)。网上所说的1m-qps测试环境是一个静态的网页来测试的。既然带业务的http单机不能达到要求,那就需要用到集群了。就我目前所学到的知识,基本就只会搭建下面如图所示的集群架构了。
一台性能比较好的机器按照nginx作为负载均衡,剩下的一些普通的机器就在后面。数据库目前只用到一个,后续如何优化和扩展不在本次讨论。
如果使用上面的架构,出去数据库后,整个HTTP的性能瓶颈就在最前面的Nginx负载均衡上了。其他的HTTP-jsp-tomcat机器如果性能不够,可以通过多加几台机器进行水平扩展。而最前面的Nginx就不行了。所以本次所要测试的就是如何让nginx支持1m-qps,并且机器正常工作。nginx只是做数据转发而已。
硬件:服务器88核、128G内存
软件:Debian 8, Nginx 1.11, wrk压力测试工具
三、操作
1. 首先设置一些Linux系统参数 在/etc/sysctl.conf 中增加如下配置
vm.swappiness =
net.ipv4.neigh.default.gc_stale_time=
net.ipv4.conf.all.rp_filter=
net.ipv4.conf.default.rp_filter=
net.ipv4.conf.default.arp_announce =
net.ipv4.conf.all.arp_announce=
net.ipv4.tcp_max_tw_buckets =
net.ipv4.tcp_syncookies =
net.ipv4.tcp_max_syn_backlog =
net.ipv4.tcp_window_scaling =
#net.ipv4.tcp_keepalive_time =
net.ipv4.tcp_synack_retries =
net.ipv6.conf.all.disable_ipv6 =
net.ipv6.conf.default.disable_ipv6 =
net.ipv6.conf.lo.disable_ipv6 =
net.ipv4.conf.lo.arp_announce=
fs.file-max =
fs.nr_open =
net.ipv4.tcp_tw_reuse =
net.ipv4.tcp_tw_recycle =
net.ipv4.tcp_keepalive_time =
net.ipv4.tcp_keepalive_intvl =
net.ipv4.tcp_keepalive_probes = net.ipv4.tcp_fin_timeout =
net.ipv4.tcp_mem =
net.ipv4.tcp_rmem =
net.ipv4.tcp_wmem =
net.core.somaxconn =
net.ipv4.ip_local_port_range =
net.core.wmem_default =
net.core.rmem_default =
net.core.rmem_max =
net.core.wmem_max =
net.core.netdev_max_backlog =
kernel.sem=
kernel.shmmni =
kernel.shmmax =
kerntl.shmall =
kernel.msgmni =
kernel.msgmax =
kernel.msgmnb = net.netfilter.nf_conntrack_max=
net.nf_conntrack_max=
net.ipv4.netfilter.ip_conntrack_max=
kernel.perf_cpu_time_max_percent=
kernel.perf_event_max_sample_rate= net.ipv4.tcp_max_orphans=
kernel.sched_migration_cost_ns=
net.core.optmem_max = kernel.sem=
还有在命令行中输入 ulimit -n 20000500
上面的所有参数,这里就不多讲了,具体想要了解的可以上网找资料
2.Nginx 安装 及其配置
nginx用最简单的apt-get 也可以,用源码按照也可以。没有什么特殊要求。下面的配置就有点要求了。 $NGINX/conf/nginx.conf (/etc/nginx/conf/nginx.conf)
worker_processes ; #这个根据硬件有多少核CPU而定
pid logs/nginx.pid; events {
worker_connections ;
} http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; keepalive_timeout ; gzip off;
access_log off; #日志功能要关闭 server {
listen backlog=;
server_name localhost;
root /dev/shm/;
} }
上面这个是最简单的配置,具体的Nginx还有很多可以调优的,还有nginx负载均衡配置,请参考我的另外一片博客<Nginx + Tomcat 动静分离实现负载均衡 http://www.cnblogs.com/wunaozai/p/5001742.html>
worker_processes ; error_log /var/log/nginx/error.log info; pid /var/run/nginx.pid; events{
use epoll;
worker_connections ;
multi_accept on;
accept_mutex off;
} http{
sendfile on;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max= inactive=200s;
open_file_cache_valid 300s;
open_file_cache_min_uses ;
keepalive_timeout ;
keepalive_requests ;
client_header_timeout ;
client_body_timeout ;
reset_timedout_connection on;
send_timeout ; #日志
access_log off;
#access_log /var/log/nginx/access.log;
#error_log /var/log/nginx/error.log;
#gzip 压缩传输
gzip off;
#最小1K
#gzip_min_length 1k;
#gzip_buffers 64K;
#gzip_http_version 1.1;
#gzip_comp_level ;
#gzip_types text/plain application/x-javascript text/css application/xml application/javascript;
#gzip_vary on;
#负载均衡组
#静态服务器组
#upstream static.zh-jieli.com {
# server 127.0.0.1: weight=;
#}
#动态服务器组
upstream zh-jieli.com {
server 127.0.0.1:;
}
#配置代理参数
#proxy_redirect off;
#proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#client_max_body_size 10m;
#client_body_buffer_size 128k;
#proxy_connect_timeout ;
#proxy_send_timeout ;
#proxy_read_timeout ;
#proxy_buffer_size 4k;
#proxy_buffers 32k;
#proxy_busy_buffers_size 64k;
#缓存配置
#proxy_cache_key '$host:$server_port$request_uri';
#proxy_temp_file_write_size 64k;
##proxy_temp_path /dev/shm/JieLiERP/proxy_temp_path;
##proxy_cache_path /dev/shm/JieLiERP/proxy_cache_path levels=: keys_zone=cache_one:200m inactive=5d max_size=1g;
#proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie; server{
listen backlog=;
server_name test2;
root /dev/shm/;
} server {
listen ssl;
server_name test;
location / {
index index;
} location ~ .*$ {
index index;
proxy_pass http://zh-jieli.com;
}
ssl on;
ssl_certificate keys/client.pem;
ssl_certificate_key keys/client.key.unsecure;
}
}
3. 创建一个简单的html文件
看到 root /dev/shm/ 了吗, 这个就是http服务器根目录了。 echo "a" > /dev/shm/a.html
4. 安装wrk
git clone https://github.com/wg/wrk.git 然后 make
四、运行
启动nginx
启动wrk 进行并发请求测试
./wrk -t88 -c10000 -d20s "http://127.0.0.1:888/a.html"
top结果图
wrk 结果图
基本在120万QPS。nginx设置一些调优参数,加上如果不在本机上运行wrk的话,150万QPS基本是没有问题的。
五、要达到1m-qps需要注意
Linux 参数一定要进行调整 (坑: 这个坑是比较小的,基本提到高并发Linux,就会有提到要修改这些参数了)
Nginx 里 access_log off; 日志功能一定要关闭 (坑: 这个影响还是比较大的,由于Nginx日志是写在磁盘的,而我服务器的磁盘是普通的磁盘,所以这里会成为磁盘IO瓶颈,所以一开始用最简单的配置,然后根据硬件的不同修改参数。有些参数在其他机器很快,在我的机器就很慢)
测试并发工具最好用我上面的wrk进行测试 (坑: 一开始用apache的ab进行测试,后面发现ab测试高性能时不行,最后使用wrk工具)
最好在本机测试wrk (坑: 从上面的wrk图可以看到,传输的数据在每秒262MB左右,普通的100M网卡是远远达不到的。虽然我的a.html只有一个字节,但是http头部信息太多了。这里还有一个小坑,就是我的服务器是有千兆网卡的,但是我用另外一台测试机也是千兆网卡,但是中间的交换机或者路由器或者网线都达不到要求,所以这里会成为网络瓶颈)
上面那几个就是我遇到的坑了,特别是最后两个,一度还怀疑nginx性能问题。因为网上很多评测都说Nginx做代理可以达到百万QPS,我总是测试不到,基本在2~3万QPS而已。最后发现是测试工具和网卡原因。
六、最后多说两句
其实整个安装搭建测试环境都比较简单,这篇博客最主要的点还是最后的几点注意,由于以前没有搞过这方面,所以没有经验,这里记录下来,以后提醒自己。前端的负载均衡器保证没有问题后,接下来的问题是后面的HTTP服务集群了。我现在的Java功能后台一台普通的服务器(Tomcat)就只能支持一万多的简单请求(因为jvm和web框架等种种原因),然后如果是那种需要简单查询数据库的功能API就只有2~3K的QPS,最后那些需要事务操作的一台服务器仅仅只能支持120~150QPS。第一个还好,通过加机器就可以水平扩展,但是后面那两个跟数据库相关的就比较麻烦了,各种新的名词(NoSQL、缓存、读写分离、分库分表、索引、优化SQL语句等)都来了。能力有限,后续要学的东西太多了。
---- 2016-11-22 19:27:18 增加-----
单机进行测试的时候好多配置都没有用到,原因是,所有的请求和应答基本都是在内存处理的,没有创建socket连接,没有经过网卡网线路由器交换机等。这两天测试发现经过nginx代理后连接并发数上不去,查了一天,发现问题是nginx的keepalive参数没有打开。这个参数没有打开的话, 会造成每次代理,都会创建一个http-socket,处理完就关闭,这样会比较占用资源,同时连接数上不去。加上keepalive参数后,外网的N个并发请求就可以通过一条socket发送多次请求。(这个描述比较不清楚, 如果对http1.0 http1.1 http2.0 里面的关于HTTP协议连接问题了解的话, 上面的描述就不难理解。)
集群的upstream设置为
# 这里要设置keepalive 表示本机与后端机器的连接数
# 同时这里还有一些其他设置,如权重,负载类型等
upstream wunaozai.cnblogs.com {
server 192.168.25.106:;
server 192.168.25.100:;
server 192.168.9.201:;
keepalive ;
}
server代理设置为
server {
listen backlog=;
server_name localhost2;
location ~ .*$ {
index index;
proxy_pass http://wunaozai.cnblogs.com;
proxy_set_header Connection "keep-alive";
proxy_http_version 1.1;
proxy_ignore_client_abort on;
#下面的timeout跟自己的业务相关设置对应的timeout
proxy_connect_timeout ;
proxy_read_timeout ;
proxy_send_timeout ;
}
}
参考资料:
http://datacratic.com/site/blog/1m-qps-nginx-and-ubuntu-1204-ec2
http://serverfault.com/questions/408546/how-to-achieve-500k-requests-per-second-on-my-webserver
https://lowlatencyweb.wordpress.com/2012/03/20/500000-requestssec-modern-http-servers-are-fast/
http://blog.jobbole.com/87531/
Nginx 单机百万QPS环境搭建的更多相关文章
- 分布式搜索ElasticSearch单机与服务器环境搭建
从上方插件官网中下载适合的dist包,然后解压.进入bin目录,可以看到一堆sh脚本.在bin目录下创建一个test.sh: bin=/home/csonezp/Dev/elasticsearch-j ...
- nginx+uwsgi+django开发环境搭建
Nginx+uWSGI+Djangoi开发环境搭建 Django简介,环境搭建 uWSGI简介,安装与配置 Nginx安装与配置 Nginx+uWSGI+Django原理解析 1.django简介,环 ...
- Hadoop单机Hadoop测试环境搭建
Hadoop单机Hadoop测试环境搭建: 1. 安装jdk,并配置环境变量,配置ssh免密码登录 2. 下载安装包hadoop-2.7.3.tar.gz 3. 配置/etc/hosts 127.0. ...
- nginx 与 lua 开发环境搭建
首先下载最新版的 相关软件 的安装文件. nginx: http://nginx.org/en/download.html LuaJIT: http://luajit.org/download.htm ...
- CentOS 7 yum nginx MySQL PHP 简易环境搭建
用centos自带的yum源来安装nginx,mysql和php,超级方便,省去编译的麻烦,省去自己配置的麻烦,还能节省非常多的时间. 我们先把yum源换成国内的阿里云镜像源(当然不换也可以),先备份 ...
- CentOS 7 yum nginx MySQL PHP7 简易环境搭建(精)
用centos自带的yum源来安装nginx,mysql和php,超级方便,省去编译的麻烦,省去自己配置的麻烦,还能节省非常多的时间. 我们先把yum源换成国内的阿里云镜像源(当然不换也可以),先备份 ...
- redis之单机和主从环境搭建
单机环境搭建 官网http://redis.io/download下载xxx.tar.gz二进制压缩包,注意下载2.8+版本,2.8之前的版本之前从服务器不支持部分重复制,2.6之前的版本不支持set ...
- hbase 单机+伪分布环境搭建学习-1
1.单机模式: (1)编辑hbase-env.sh user@EBJ1023.local:/usr/local/flume_kafka_stom/hbase_1.1.2> vim conf/hb ...
- linux下nginx+php+mysql 自助环境搭建
++++++++++++++++++++++++++++++++++++++++++++++linux下nginx+php+mysql环境搭建+++++++++++++++++++++++++++++ ...
随机推荐
- duilib进阶教程 -- 设置资源路径 (15)
在前面的教程里,虽然图片都放到了skin文件夹里,但是XML却都在外面,当XML比较多时,就不太好看啦,如下图: 所以需要整理一下,将XML也放入skin文件夹,这样exe的目录就简洁多了: 将XML ...
- 更新日志 - fir.im 新版管理后台邀请内测
上周,我们对fir.im 新版管理后台的页面结构和样式进行了优化,现在新版的管理后台开始邀请内测,感兴趣的伙伴可以发邮件到 **beta@fir.im** 申请.为了保证服务质量和对问题进行有效追踪, ...
- iOS开发---集成百度地图完善版
一.成为百度的开发者.创建应用 http://developer.baidu.com/map/index.php?title=首页 (鼠标移向 然后选择你的项目需要的功能 你可以在里面了解到你想要使用 ...
- 安装Vmware workstation虚拟机(含软件和注册码)
1:虚拟机的安装步骤,包含软件包和注册码.本博客所使用的虚拟机版本是vmware-workstation_11.1.0版本,注意不是最新版本, 软件包:http://pan.baidu.com/s/1 ...
- Eclipse崩溃后无法启动的问题解决
一次Eclipse发生内存溢出(ADT环境,多打开几个xml文件内存占用就会飚升),强制结束任务,再次启动Eclipse发现闪退.查看workspace/.metadata/.log文件发现如下错误信 ...
- struts2从2.2.3升级到2.3.15.1步骤
1. 删除以下jar包 asm-3.1.jar asm-commons-3.1.jar commons-beanutils-1.7.0.jar commons-fileupload-1.2.2.jar ...
- C++/Php/Python/Shell 程序按行读取文件或者控制台
写程序经常需要用到从文件或者标准输入中按行读取信息,这里汇总一下.方便使用 1. C++ 读取文件 #include<stdio.h> #include<string.h> i ...
- find the peak value
A peak element is an element that is greater than its neighbors. Given an input array where num[i] ≠ ...
- “Adobe Flash Player因过期而遭到阻止”的解决办法
谷歌浏览器总是提示“Adobe Flash Player因过期而遭到阻止”,然后点进去,又更新不了,因为伟大的TC已经把谷歌屏蔽了. 解决办法就是到flash官网更新到最新的Flash https:/ ...
- Python从内存中使用编译后的模块
在Windows编程的时候,有些时候,我们经常会要使用一些非常规的方法,比如说从内存中加载DLL,然后使用DLL中的函数.于是就思索在用Python的时候是否能够将几个编译好的Pyc合并成一个,然后使 ...