Nginx 單機百萬QPS環境搭建

來源:互聯網
上載者:User

一、背景

  最近公司在做一些物聯網產品,物物通訊用的是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 = 0net.ipv4.neigh.default.gc_stale_time=120net.ipv4.conf.all.rp_filter=0net.ipv4.conf.default.rp_filter=0net.ipv4.conf.default.arp_announce = 2net.ipv4.conf.all.arp_announce=2net.ipv4.tcp_max_tw_buckets = 100net.ipv4.tcp_syncookies = 0net.ipv4.tcp_max_syn_backlog = 3240000net.ipv4.tcp_window_scaling = 1#net.ipv4.tcp_keepalive_time = 60net.ipv4.tcp_synack_retries = 2net.ipv6.conf.all.disable_ipv6 = 1net.ipv6.conf.default.disable_ipv6 = 1net.ipv6.conf.lo.disable_ipv6 = 1net.ipv4.conf.lo.arp_announce=2fs.file-max = 40000500fs.nr_open = 40000500net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_keepalive_time = 1net.ipv4.tcp_keepalive_intvl = 15net.ipv4.tcp_keepalive_probes = 3net.ipv4.tcp_fin_timeout = 5net.ipv4.tcp_mem = 768432 2097152 15242880net.ipv4.tcp_rmem = 4096 4096 33554432net.ipv4.tcp_wmem = 4096 4096 33554432net.core.somaxconn = 6553600net.ipv4.ip_local_port_range = 2048 64500net.core.wmem_default = 183888608net.core.rmem_default = 183888608net.core.rmem_max = 33554432net.core.wmem_max = 33554432net.core.netdev_max_backlog = 2621244kernel.sem=250 65536 100 2048kernel.shmmni = 655360kernel.shmmax = 34359738368kerntl.shmall = 4194304kernel.msgmni = 65535kernel.msgmax = 65536kernel.msgmnb = 65536net.netfilter.nf_conntrack_max=1000000net.nf_conntrack_max=1000000net.ipv4.netfilter.ip_conntrack_max=1000000kernel.perf_cpu_time_max_percent=60kernel.perf_event_max_sample_rate=6250net.ipv4.tcp_max_orphans=1048576kernel.sched_migration_cost_ns=5000000net.core.optmem_max = 25165824kernel.sem=10000 2560000 10000 256


還有在命令列中輸入 ulimit -n 20000500 

上面的所有參數,這裡就不多講了,具體想要瞭解的可以上網找資料

2.Nginx 安裝 及其配置

nginx用最簡單的apt-get 也可以,用源碼按照也可以。沒有什麼特殊要求。下面的配置就有點要求了。 $NGINX/conf/nginx.conf (/etc/nginx/conf/nginx.conf)

worker_processes  88;  #這個根據硬體有多少核CPU而定pid        logs/nginx.pid;events {    worker_connections  1024;}http {    include       mime.types;    default_type  application/octet-stream;    sendfile        on;    tcp_nopush     on;    keepalive_timeout  65;    gzip  off;    access_log off;   #日誌功能要關閉    server {        listen       888 backlog=168888;        server_name  localhost;      root /dev/shm/;    }}


 上面這個是最簡單的配置,具體的Nginx還有很多可以調優的,還有nginx負載平衡配置,請參考我的另外一片部落格<Nginx + Tomcat 動靜分離實現負載平衡>

worker_processes 4;error_log /var/log/nginx/error.log info;pid /var/run/nginx.pid;events{    use epoll;    worker_connections 409600;    multi_accept on;    accept_mutex off;}http{    sendfile on;    tcp_nopush on;    tcp_nodelay on;    open_file_cache max=200000 inactive=200s;    open_file_cache_valid 300s;    open_file_cache_min_uses 2;    keepalive_timeout 5;    keepalive_requests 20000000;    client_header_timeout 5;    client_body_timeout 5;    reset_timedout_connection on;    send_timeout 5;    #日誌    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 16 64K;    #gzip_http_version 1.1;    #gzip_comp_level 6;    #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:808 weight=1;    #}    #動態伺服器組    upstream zh-jieli.com {        server 127.0.0.1:8080;    }    #配置代理參數    #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 65;    #proxy_send_timeout 65;    #proxy_read_timeout 65;    #proxy_buffer_size 4k;    #proxy_buffers 4 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=1:2 keys_zone=cache_one:200m inactive=5d max_size=1g;    #proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;        server{        listen 88 backlog=163840;        server_name test2;        root /dev/shm/;    }    server {        listen 443 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:888;    server 192.168.25.100:888;    server 192.168.9.201:888;    keepalive 1000;}

 server代理設定為

server {    listen 88 backlog=168888;    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 600;        proxy_read_timeout 600;        proxy_send_timeout 600;    }}


參考資料:

  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/

  https://github.com/wg/wrk 

作者:無腦仔的小明 
出處:http://www.cnblogs.com/wunaozai/p/6073731.html
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。 
如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.