1.1 nginx基本介紹
1、nginx高並發原理( 多進程+epoll實現高並發 )
1. Nginx 在啟動后,會有一個 master 進程和多個相互獨立的 worker 進程。
2. 每個子進程只有一個線程(協程),采用的 IO多路復用模型epoll,實現高並發。
2、epoll能實現高並發原理
1. epoll() 中內核則維護一個鏈表,epoll_wait 方法可以獲取到鏈表長度,不為0就知道文件描述符准備好了。
2. 在內核實現中 epoll 是根據每個 sockfd 上面的與設備驅動程序建立起來的回調函數實現的。
3. 某個 sockfd 上的事件發生時,與它對應的回調函數就會被調用,來把這個 sockfd 加入鏈表,其他處於“空閑的”狀態的則不會。
4. epoll上面鏈表中獲取文件描述,這里使用內存映射(mmap)技術, 避免了復制大量文件描述符帶來的開銷
內存映射(mmap):內存映射文件,是由一個文件到一塊內存的映射,將不必再對文件執行I/O操作
3、nginx和apache比較
1)nginx相對於apache的優點
1. 輕量級,同樣起web 服務,比apache 占用更少的內存及資源
2. 抗並發,nginx 處理請求是異步非阻塞的,而apache 則是阻塞型的,在高並發下nginx 能保持低資源低消耗高性能
3. 高度模塊化的設計,編寫模塊相對簡單,社區活躍,各種高性能模塊出品迅速啊
2)apache 相對於nginx 的優點
1. apache 更為成熟,少 bug ,穩定性好
2. rewrite ,比nginx 的rewrite 強大
3. 模塊超多,基本想到的都可以找到
1.2 nginx正向代理 & 反向代理
1、正向代理
1. 我訪問不了某網站,但是我能訪問一個代理服務器,這個代理服務器呢,他能訪問那個我不能訪問的網站
2. 於是我先連上代理服務器,告訴他我需要那個無法訪問網站的內容,代理服務器去取回來,然后返回給我。
3. 客戶端必須設置正向代理服務器,當然前提是要知道正向代理服務器的IP地址,還有代理程序的端口。
4. 例如之前使用過這類軟件例如CCproxy,http://www.ccproxy.com/ 需要在瀏覽器中配置代理的地址。
正向代理作用:
1)訪問原來無法訪問的資源,如google
2) 可以做緩存,加速訪問資源
3)對客戶端訪問授權,上網進行認證
4)代理可以記錄用戶訪問記錄(上網行為管理),對外隱藏用戶信息
2、反向代理
1. 反向代理對用戶透明,客戶端無需任何配置即可訪問服務。
2. 實際運行方式是指以代理服務器來接受internet上的連接請求,然后將請求轉發給內部網絡上的服務器。
3. 並將從服務器上得到的結果返回給internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器。
3、反向代理使用場景
1)保證內網的安全,可以使用反向代理提供WAF功能,阻止web攻擊
例:大型網站,通常將反向代理作為公網訪問地址,Web服務器是內網
2)負載均衡,通過反向代理服務器來優化網站的負載
1.3 nginx常用配置
1、nginx配置文件注釋

#運行用戶 user nobody; #啟動進程,通常設置成和cpu的數量相等 worker_processes 1; #全局錯誤日志及PID文件 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; #工作模式及連接數上限 events { #epoll是多路復用IO(I/O Multiplexing)中的一種方式, #僅用於linux2.6以上內核,可以大大提高nginx的性能 use epoll; #單個后台worker process進程的最大並發鏈接數 worker_connections 1024; # 並發總數是 worker_processes 和 worker_connections 的乘積 # 即 max_clients = worker_processes * worker_connections # 在設置了反向代理的情況下,max_clients = worker_processes * worker_connections / 4 為什么 # 為什么上面反向代理要除以4,應該說是一個經驗值 # 根據以上條件,正常情況下的Nginx Server可以應付的最大連接數為:4 * 8000 = 32000 # worker_connections 值的設置跟物理內存大小有關 # 因為並發受IO約束,max_clients的值須小於系統可以打開的最大文件數 # 而系統可以打開的最大文件數和內存大小成正比,一般1GB內存的機器上可以打開的文件數大約是10萬左右 # 我們來看看360M內存的VPS可以打開的文件句柄數是多少: # $ cat /proc/sys/fs/file-max # 輸出 34336 # 32000 < 34336,即並發連接總數小於系統可以打開的文件句柄總數,這樣就在操作系統可以承受的范圍之內 # 所以,worker_connections 的值需根據 worker_processes 進程數目和系統可以打開的最大文件總數進行適當地進行設置 # 使得並發總數小於操作系統可以打開的最大文件數目 # 其實質也就是根據主機的物理CPU和內存進行配置 # 當然,理論上的並發總數可能會和實際有所偏差,因為主機還有其他的工作進程需要消耗系統資源。 # ulimit -SHn 65535 } http { #設定mime類型,類型由mime.type文件定義 include mime.types; default_type application/octet-stream; #設定日志格式 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; #sendfile 指令指定 nginx 是否調用 sendfile 函數(zero copy 方式)來輸出文件, #對於普通應用,必須設為 on, #如果用來進行下載等應用磁盤IO重負載應用,可設置為 off, #以平衡磁盤與網絡I/O處理速度,降低系統的uptime. sendfile on; #tcp_nopush on; #連接超時時間 #keepalive_timeout 0; keepalive_timeout 65; tcp_nodelay on; #開啟gzip壓縮 gzip on; gzip_disable "MSIE [1-6]."; #設定請求緩沖 client_header_buffer_size 128k; large_client_header_buffers 4 128k; #設定虛擬主機配置 server { #偵聽80端口 listen 80; #定義使用 www.nginx.cn訪問 server_name www.nginx.cn; #定義服務器的默認網站根目錄位置 root html; #設定本虛擬主機的訪問日志 access_log logs/nginx.access.log main; #默認請求 location / { #定義首頁索引文件的名稱 index index.php index.html index.htm; } # 定義錯誤提示頁面 error_page 500 502 503 504 /50x.html; location = /50x.html { } #靜態文件,nginx自己處理 location ~ ^/(images|javascript|js|css|flash|media|static)/ { #過期30天,靜態文件不怎么更新,過期可以設大一點, #如果頻繁更新,則可以設置得小一點。 expires 30d; } #PHP 腳本請求全部轉發到 FastCGI處理. 使用FastCGI默認配置. location ~ .php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } #禁止訪問 .htxxx 文件 location ~ /.ht { deny all; } } }
2、nginx配置舉例

user work; worker_processes 8; worker_rlimit_nofile 65535; error_log logs/error.log warn; #error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; events { use epoll; worker_connections 65535; } # load modules compiled as Dynamic Shared Object (DSO) # #dso { # load ngx_http_fastcgi_module.so; # load ngx_http_rewrite_module.so; #} http { include mime.types; default_type application/octet-stream; server_names_hash_bucket_size 128; sendfile on; tcp_nopush on; tcp_nodelay on; fastcgi_connect_timeout 5; fastcgi_send_timeout 10; fastcgi_read_timeout 10; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 128k; #keepalive_timeout 0; keepalive_timeout 60; keepalive_requests 1024; client_header_buffer_size 4k; large_client_header_buffers 4 32k; client_max_body_size 10m; client_body_buffer_size 512k; client_body_timeout 600; client_header_timeout 600; send_timeout 600; proxy_connect_timeout 1000ms; proxy_send_timeout 2000000ms; proxy_read_timeout 2000000ms; proxy_buffers 64 8k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 64k; proxy_redirect off; #proxy_next_upstream off ; 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; add_header X-Frame-Options "ALLOW-FROM http://cloud.njsig.cn"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_cookie" "$http_user_agent" ' '$request_time $remote_addr $server_addr $upstream_addr $host ' '"$http_x_forwarded_for" $upstream_response_time'; set_real_ip_from 10.0.0.0/8; real_ip_header X-Real-IP; #example # server { # listen 8000; # server_name www; # access_log logs/access.log main; # location / { # proxy_pass http://127.0.0.1:8001; # } # # # } include vhosts/*.conf; } #####

server { listen 80; server_name aaa.test.com bbb.test.com; access_log /home/work/nginx/logs/opwf_access.log main; location / { proxy_pass http://127.0.0.1:8001; } }

server { listen 80; server_name ccc.test.com; access_log /home/work/nginx/logs/nj1_access.log main; root /home/work/project/frontopwf/dist; location / { try_files $uri $uri/ @router; } location @router { rewrite ^.*$ /index.html last; } }
1.4 nginx負載均衡配置
1、搭建實驗環境(使用docker部署兩台nginx容器)
1)使用搭建第一台nginx服務
[root@linux-node4 ~]# docker container run -d --name web01 -p 81:80 nginx 測試訪問:http://192.168.56.14:81/ root@c58a7f1fb89d:/# docker exec -it web01 bash root@c58a7f1fb89d:/# echo web01 > /usr/share/nginx/html/index.html
2)使用docker搭建第二台nginx服務
[root@linux-node4 ~]# docker container run -d --name web02 -p 82:80 nginx 測試訪問:http://192.168.56.14:82/ root@a3440d30f27c:/# docker exec -it web02 bash root@a3440d30f27c:/# echo web02 > /usr/share/nginx/html/index.html
2、法1:默認輪訓(在真實主機中安裝nginx並配置負載均衡)
輪訓:每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器down掉,能自動剔除。
[root@linux-node4 ~]# yum -y install nginx [root@linux-node4 ~]# vim /etc/nginx/nginx.conf #### 修改nginx.conf 默認是輪訓 ####
''' # 1. upstream是自己寫的,一定要放在server外面 upstream myservers { server 192.168.56.14:81; server 192.168.56.14:82; } # 2. server其實默認已經有一個,只需要修改location中配置,指定轉發代理即可 server { location / { proxy_pass http://myservers; } } ''' [root@linux-node4 nginx]# systemctl start nginx
3、負載均衡常用配置梳理
1、輪詢(默認) 每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器down掉,能自動剔除。 upstream backserver { server 192.168.0.14; server 192.168.0.15; } 2、權重 weight 指定輪詢幾率,weight和訪問比率成正比,用於后端服務器性能不均的情況。 upstream backserver { server 192.168.0.14 weight=3; server 192.168.0.15 weight=7; } 3、ip_hash( IP綁定) 上述方式存在一個問題就是說,在負載均衡系統中,假如用戶在某台服務器上登錄了,那么該用戶第二次請求的時候,因為我們是負載均衡系統,
每次請求都會重新定位到服務器集群中的某一個,那么已經登錄某一個服務器的用戶再重新定位到另一個服務器,其登錄信息將會丟失,這樣顯然是不妥的。 我們可以采用ip_hash指令解決這個問題,如果客戶已經訪問了某個服務器,當用戶再次訪問時,會將該請求通過哈希算法,自動定位到該服務器。 每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器,可以解決session的問題。 upstream backserver { ip_hash; server 192.168.0.14:88; server 192.168.0.15:80; } 4、fair(第三方插件) 按后端服務器的響應時間來分配請求,響應時間短的優先分配。 upstream backserver { server server1; server server2; fair; } 5、url_hash(第三方插件) 按訪問url的hash結果來分配請求,使每個url定向到同一個后端服務器,后端服務器為緩存時比較有效。 upstream backserver { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }