主頁 > 後端開發 > Nginx 【介紹】

Nginx 【介紹】

2020-10-22 09:05:45 後端開發

前言

Nginx是一款自由的、開源的、高性能的HTTP服務器和 反向代理 服務器;同時也是一個IMAP、POP3、SMTP代理服務器;Nginx可以作為一個HTTP服務器進行網站的發布處理,另外Nginx可以作為反向代理進行負載均衡的實作,

  • Nginx使用基于事件驅動架構,使得其可以支持數以百萬級別的TCP連接
  • 高度的模塊化和自由軟體許可證使得第三方模塊層出不窮(開源)
  • Nginx是一個跨平臺服務器,可以運行在Linux,Windows,FreeBSD,Solaris,AIX,Mac OS等作業系統上
  • 穩定性極高

Nginx 解決高并發

  • Nginx高并發原理( 多行程+epoll實作高并發 )
  • Nginx 在啟動后,會有一個 master 行程和多個相互獨立的 worker 行程,
  • 每個子行程只有一個執行緒(協程),采用的 IO多路復用模型epoll,實作高并發,

epoll能實作高并發原理

  • epoll() 中內核則維護一個鏈表,epoll_wait 方法可以獲取到鏈表長度,不為0就知道檔案描述符準備好了,
  • 在內核實作中 epoll 是根據每個 sockfd 上面的與設備驅動程式建立起來的回呼函式實作的,
  • 某個 sockfd 上的事件發生時,與它對應的回呼函式就會被呼叫,來把這個 sockfd 加入鏈表,其他處于“空閑的”狀態的則不會,
  • epoll上面鏈表中獲取檔案描述,這里使用記憶體映射(mmap)技術, 避免了復制大量檔案描述符帶來的開銷

記憶體映射(mmap):記憶體映射檔案,是由一個檔案到一塊記憶體的映射,將不必再對檔案執行I/O操作

nginx和apache比較

  nginx相對于apache的優點

  • 輕量級,同樣起web 服務,比apache 占用更少的記憶體及資源
  • 抗并發,nginx 處理請求是異步非阻塞的,而apache 則是阻塞型的,在高并發下nginx 能保持低資源低消耗高性能
  • 高度模塊化的設計,撰寫模塊相對簡單,社區活躍,各種高性能模塊出品迅速啊

  apache 相對于nginx 的優點

  • apache 更為成熟,少 bug ,穩定性好
  • rewrite ,比nginx 的rewrite 強大
  • 模塊超多,基本想到的都可以找到

Nginx 代理

  • 說到代理,首先我們要明確一個概念,所謂代理就是一個代表、一個渠道此時就涉及到兩個角色,一個是被代理角色 (A_),一個是目標角色 (B_),A_ 通過這個代理訪問 B_ 完成一些任務的程序稱為代理 (C_) 操作程序;比如客人去買雙鞋,這個店鋪就是 (C_),(A_) 就是廠家,(B_) 就是用戶,代理呢又分為正向代理和反向代理

正向代理:

  • 首先我們先舉個例子:比如說我們在 YouTob 上查找學習資料,大家會發現很慢;這個時候就會需要到正向代理,最明顯的例子(1FQ),FQ的方式主要是找到一個可以訪問國外網站的代理服務器,我們將請求發送給代理服務器,代理服務器去訪問國外的網站,然后將訪問到的資料傳遞給我們
  • 這就是正向代理,正向代理最大的特點是客戶端非常明確要訪問的服務器地址;服務器只清楚請求來自哪個代理服務器,而不清楚來自哪個具體的客戶端;正向代理模式屏蔽或者隱藏了真實客戶端資訊,
  • 總結來說:正向代理,“它代理的是客戶端,代客戶端發出請求”,是一個位于客戶端和原始服務器(origin server)之間的服務器,為了從原始服務器取得內容,客戶端向代理發送一個請求并指定目標(原始服務器),然后代理向原始服務器轉交請求并將獲得的內容回傳給客戶端,客戶端必須要進行一些特別的設定才能使用正向代理,

正向代理的用途:

  • 訪問原來無法訪問的資源,如Google
  • 可以做快取,加速訪問資源
  • 對客戶端訪問授權,上網進行認證
  • 代理可以記錄用戶訪問記錄(上網行為管理),對外隱藏用戶資訊

正向代理配置:

  • 現在的網站基本上都是https,要解決既能訪問http80埠也能訪問https443埠的網站,需要配置兩個SERVER節點,一個處理HTTP轉發,另一個處理HTTPS轉發,而客戶端都通過HTTP來訪問代理,通過訪問代理不同的埠,來區分HTTP和HTTPS請求,

環境介紹:

  • 代理服務器系統環境為:centos
  • nginx代理服務器為:192.168.10.10
  • 測驗客戶端為局域網內任意windows電腦或Linux電腦
[root@localhost ~] vim /usr/local/nginx-1.12.1/conf/nginx.conf
server {
resolver 114.114.114.114; #指定DNS服務器IP地址 
listen 80;
location / {
proxy_pass http://$host$request_uri; #設定代理服務器的協議和地址 
proxy_set_header HOST $host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
   }
}
server {
resolver 114.114.114.114; #指定DNS服務器IP地址 
listen 443;
location / {
proxy_pass https://$host$request_uri; #設定代理服務器的協議和地址 
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
   }
}
[root@localhost ~] /usr/local/nginx-1.12.1/sbin/nginx -s reload

Linux客戶端訪問測驗:

[root@localhost ~] curl -I --proxy 192.168.10.10:80 www.baidu.com
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Mon, 11 Jun 2018 15:37:47 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Thu, 31 May 2018 09:28:16 GMT
Connection: keep-alive
ETag: "5b0fc030-264"
Accept-Ranges: bytes
https的訪問測驗

[root@localhost ~] curl -I --proxy 192.168.10.10:443 www.baidu.com
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Mon, 11 Jun 2018 15:38:07 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Etag: "575e1f5c-115"
Last-Modified: Mon, 13 Jun 2016 02:50:04 GMT
Pragma: no-cache

設定Linux客戶端全域代理:

[root@localhost ~] vim /etc/profile
export http_proxy='192.168.10.10:80'
export http_proxy='192.168.10.10:443'
export ftp_proxy='192.168.10.10:80'

[root@localhost ~] source /etc/profile

[root@localhost ~] curl -I www.baidu.com:80
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Mon, 11 Jun 2018 16:10:18 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Etag: "575e1f5c-115"
Last-Modified: Mon, 13 Jun 2016 02:50:04 GMT
Pragma: no-cache
[root@localhost ~]# curl -I www.baidu.com:443
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Mon, 11 Jun 2018 16:10:27 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Etag: "575e1f59-115"
Last-Modified: Mon, 13 Jun 2016 02:50:01 GMT
Pragma: no-cache

上面結果就說明我們的服務端nginx正向代理和客戶端使用nginx做為全域代理設定成功,

反向代理:

  • 舉例:我國的某寶網站,每天同時連接到網站的訪問人數已經爆表,單個服務器遠遠不能滿足用戶訪問量了,此時就出現了分布式部署;也就是通過部署多臺服務器來解決訪問人數限制的問題;某寶網站中大部分功能也是直接使用Nginx進行反向代理實作的,并且通過封裝Nginx和其他的組件之后起了個高大上的名字:Tengine,有興趣的童鞋可以訪問Tengine的官網查看具體的資訊http://tengine.taobao.org/,
  • 多個客戶端給服務器發送的請求,Nginx服務器接收到之后,按照一定的規則分發給了后端的業務處理服務器進行處理了, 此時~請求的來源也就是客戶端是明確的,但是請求具體由哪臺服務器處理的并不明確了,Nginx扮演的就是一個反向代理角色,
  • 客戶端是無感知代理的存在的,反向代理對外都是透明的,訪問者并不知道自己訪問的是一個代理, 因為客戶端不需要任何配置就可以訪問,
  • 反向代理,“它代理的是服務端,代服務端接收請求”,主要用于服務器集群分布式部署的情況下,反向代理隱藏了服務器的資訊,

反向代理的作用:

  • 保證內網的安全,通常將反向代理作為公網訪問地址,Web服務器是內網
  • 負載均衡,通過反向代理服務器來優化網站的負載

反向代理配置:

  • 本文主要配置Nginx的反向代理,及公司有多臺服務器都需要公司一臺主Nginx代理配置,使用Nginx+Tomcat實作此專案的反向代理,至于Nginx,tomcat如何搭建百度一大把,此案例是在一臺服務器上面實作,一臺虛擬機安裝了兩個tomcat,

虛擬機環境介紹:

  • 服務器ip:192.168.161.189
  • Nginx埠:80
  • Tomcat1埠:8070
  • Tomcat2埠:8080
  • 一臺服務器安裝了兩個Tomcat,使用不同埠實作,

測驗搭建的nginx,tomcat是否正常訪問:
先測驗一下訪問搭建好的nginx有沒有問題,

Nginx訪問正常,
測驗一下搭建的tomcat,(自己編輯了一個用于測驗的簡單頁面,埠是8070)

配置反向代理:

[root@localhost conf] vim Nginx.conf

在server段里面的location加上proxy_pass http://ip:埠

server{
listen 80;
server_name 192.168.161.189;

# charset koi8-r;
# access_log logs/host.access.log main;

location / {

proxy_pass http://192.168.161.189:8070; `注意這里`
root html;
idnex index.html index.htm;
  }
}

Nginx配置完成后重啟一下nginx:

# 命令大全
1、查找nginx路徑:whereis nginx

2、啟動 service nginx start

3、查看Nginx的版本號:nginx -V

4、停止 nginx -s stop

5、退出 nginx -s quit

6、重啟加載配置 nginx -s reload 
/etc/init.d/nginx -s reload 也可以

重啟沒報錯說明組態檔沒問題:

使用瀏覽器進行訪問

簡單的反向代理已經完成

配置代理多個網站及服務:

[root@localhost conf] vim Nginx.conf

配置多個反向代理實作方式,是通過不同的埠代理訪問,這里復制一個server段,將兩個server段nginx的埠更改,使用nginx的不同埠訪問,

第一個server段配置tomcat1(192.168.161.189:8070)

第二個server段配置(192.168.161.189:8080)

配置完成后,重啟nginx代理,

[root@localhost conf] /etc/init.d/nginx -s reload

先訪問nginx代理的第一個tomcat1,(通過nginx的8081代理的tomcat1,)

訪問nginx代理的第二個tomcat2,(通過nginx的8082代理的tomcat2,)

總結:

  • 以上配置就是通過nginx的不同埠代理多個地址,若還要代理更多通過nginx的不同埠,增加server段即可,訪問量大的網站不建議代理太多,
  • 正向代理是代理客戶端,為客戶端收發請求,使真實客戶端對服務器不可見;而反向代理是代理服務器端,為服務器收發請求,使真實服務器對客戶端不可見,

基于上文的一些簡單配置,大概能知道Nginx的一個流程,我們繼續往下看:

  • 在B/S應用中,頁面快取技術是提升服務能力的重要手段,頁面快取又分為瀏覽器快取和服務端快取兩類,本文僅討論Nginx服務器的頁面快取,Nginx服務快取的基本原理是對客戶請求過的資源建立本地副本,在一段合理時期內任何用戶再次請求該資源時,Nginx服務器無需要再次向后端服務器發出請求,而是直接應答快取的副本,因此,快取技術可以明顯降低后端服務器的負載,減輕網路傳輸負擔,極大地提升回應速度,

tornado的吞吐能力

我們用一個最簡單的例子,測驗一下tornado的吞吐能力:

# -*- coding: utf-8 -*-

import os
import sys
import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import parse_command_line

class Handler(tornado.web.RequestHandler):
def get(self):
self.write('我是tornado,我夠快!')

class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", Handler)
]

settings = dict(
title='壓力測驗',
debug=True,
)

tornado.web.Application.__init__(self, handlers, **settings)

parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True, max_buffer_size=504857600)
http_server.listen(80)

print('Web server is started')
tornado.ioloop.IOLoop.instance().start()

啟動該腳本后,使用瀏覽器訪問127.0.0.1,頁面顯示“我是tornado,我夠快!”,這個例子沒有使用檔案讀寫、資料庫讀寫等耗時的操作,更能反應出tornado本身的吞吐能力,

壓力測驗通常使用Apache自帶的ab.exe,ab的使用方法為:

ab -n 請求數 -c 并發數 URL

下面是并發10個請求共計100個請求的壓力測驗:

ab -n 100 -c 10 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
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).....done


Server Software: TornadoServer/6.0.3
Server Hostname: 127.0.0.1
Server Port: 9001

Document Path: /
Document Length: 22 bytes

Concurrency Level: 10
Time taken for tests: 0.107 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 21700 bytes
HTML transferred: 2200 bytes
Requests per second: 937.09 [#/sec] (mean)
Time per request: 10.671 [ms] (mean)
Time per request: 1.067 [ms] (mean, across all concurrent requests)
Transfer rate: 198.58 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.6 0 2
Processing: 4 9 3.0 9 18
Waiting: 2 9 3.2 8 18
Total: 4 10 3.1 9 19
WARNING: The median and mean for the initial connection time are not within a normal deviation
These results are probably not that reliable.

Percentage of the requests served within a certain time (ms)
50% 9
66% 10
75% 13
80% 14
90% 15
95% 15
98% 18
99% 19
100% 19 (longest request)

它的輸出中有以下關鍵資訊:

  • Concurrency Level: 并發數,使用-c引數指定的數量
  • Time taken for tests: 測驗用共用時長
  • Complete requests: 完成的請求數
  • Failed requests: 失敗的請求數
  • Total transferred: 共傳輸的資料量
  • HTML transferred: 頁面傳輸的資料量
  • Requests per second: 平均每秒回應的請求數(吞吐量)
  • Time per request: 用戶平均請求等待時間 [ms]
  • Time per request: 服務器平均處理時間 [ms]
  • Transfer rate: 輸入速率

我們發送10000次請求,用不同的并發數,多次進行測驗,得到的結果如下表所示:

從資料中可以看出,隨著并發數量的增加,服務器平均處理時間和用戶平均請求等待時間都在增加;并發小于100時,服務器還沒有飽和,吞吐量還在增加;并發大于100后,服務器的處理能力開始受到影響,吞吐量開始下降,

我使用windows平臺,在我的測驗條件下,tornado每秒最多回應1305次請求,Linux平臺上,tornado的表現要比windows平臺好得多,

Nginx 反向代理

  • 代理服務器是架設在客戶端和服務器之間的中間服務器,我們一般所說的代理是正向代理,正向代理是客戶端的出口,客戶端將請求發送給正向代理服務器,告訴正向代理服務器我要訪問哪個服務器,然后正向代理服務器向目標服務器發送請求,并將回應回傳給客戶端,從服務器的角度看,它并不知道真正的請求是哪個客戶端發出來的,有幾個客戶端,只從代理服務器接受請求,
  • 與正向代理相反,反向代理是服務器的入口,客戶端并不知道真正的服務器是哪個,有幾個服務器,只知道反向代理服務器是哪個,它向反向代理服務器發送請求,反向代理服務器會有選擇的把請求發送到其中的一臺服務器,并將服務器的回應回傳給客戶端,
  • 反向代理使服務器由一個變為多個,并為多個服務器提供統一的入口,可根據每個服務器的負載向負載最輕的服務器轉發請求,這就是負載均衡,
  • nginx是一款優秀的反向代理服務器,可以從官網下載壓縮包,解壓后直接使用,

首先,我們修改一下服務器的代碼,使之可以同時啟動多個行程:

# -*- coding: utf-8 -*-

import os
import sys
import multiprocessing
import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import parse_command_line

# 頁面句柄
class Handler(tornado.web.RequestHandler):
def get(self):
self.write('我是tornado,我夠快!')

class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", Handler),
]

settings = dict(
title='壓力測驗',
debug=True,
)

tornado.web.Application.__init__(self, handlers, **settings)

# 啟動服務器
def start_web_server(port):
parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True, max_buffer_size=504857600)
http_server.listen(port)

print('Web server is started on port %d.' % port)
tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
if len(sys.argv) == 1:
start_web_server(80)
else:
try:
ports = [int(port) for port in sys.argv[1].split(',')]
except:
try:
a, b = sys.argv[1].split('-')
ports = range(int(a), int(b) + 1)
except:
ports = list()
print ('Parameter error.')

multiprocessing.freeze_support()
for port in ports:
p = multiprocessing.Process(target=start_web_server, args=(port,))
p.start()

在命令列中輸入如下命令,啟動兩個服務器行程,每個行程使用不同的埠

python server.py 9001-9002

接下來,配置ngnix,nginx的配置并不復雜,可以復制解壓目錄下的conf/ngnix.conf,進行修改即可,
在http部分中添加upstream,語法為:

http {
upstream 名稱 {
負載均衡策略
server IP地址:埠 其它引數;
  }
}

其中可選的負載均衡策略有:

  • ip_hash: 這種策略會把某一ip映射到一個固定的服務器,其優點是容易保持session的一致性,缺點是當該服務器負載過重后,也不能分流到其他服務器
  • least_conn: 這種策略根據服務器連接的數量,選擇連接數量最小的服務器,同一客戶端不同的請求有可能會進入不同的服務器
  • least_time: 這種策略計算每個服務器的回應時間,選擇回應時間小短的服務器,同一客戶端不同的請求有可能會進入不同的服務器

我選擇least_time,配置如下:

upstream serv {
least_conn;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
}

將原來的location /的內容修改為如下內容:

proxy_pass http://serv$request_uri;

#以下三行,目的是將代理服務器收到的用戶的資訊傳到真實服務器上
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

其中proxy_pass后面的http://serv$request_uri中,serv為剛才配置的upstream的名稱,
修改并洗掉了原來組態檔中的注釋會,組態檔如下:

worker_processes 1;

events {
worker_connections 1024;
}


http {
sendfile on;
keepalive_timeout 65;

upstream serv {
least_conn;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
}

server {
listen 80;
server_name localhost;

location / {
proxy_pass http://serv$request_uri;

#以下三行,目的是將代理服務器收到的用戶的資訊傳到真實服務器上
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
}

啟動tornado,并進入組態檔的目錄,使用如下命令啟動nginx:

nginx -c nginx.conf

OK,反向代理配置完成,再次用ab進行壓力測驗, 結果并不像我們期望的那樣,吞吐量成倍增長,這是因為tornado的IO幾乎已經做到了極致,幾乎比肩nginx,wondows平臺上單臺PC的吞吐量大致也就如此了,當tornado需要進行檔案讀寫、資料庫讀寫等耗時的操作時,多行程的反向代理才能體現出優勢,

 

使用快取技術

除了反向代理,nginx還可以啟用快取技術,進一步提高服務能力,當客戶端第一次請求某url時,nginx將請求轉發給服務器,服務器回傳后,nginx在本地創建快取,在快取未失效前,nginx不再轉發請求,而是直接將快取的內容回傳給客戶端,服務器的負載被轉嫁到nginx上,而nginx的性能是非常出色的,
在nginx組態檔中設定快取,語法為:

http {
proxy_cache_path 快取路徑 keys_zone=快取名稱:快取大小 levels=一級快取名長度:二級快取名長度 inactive=失活時間 max_size=最大大小;

server {
location url {
proxy_cache 快取名稱;
proxy_cache_min_uses 訪問次數(url被訪問多少次后進行快取);
proxy_cache_valid any 有效期;
    }
  }
}

修改后nginx的組態檔為:

worker_processes 1;

events {
worker_connections 1024;
}

http {
sendfile on;
keepalive_timeout 65;

upstream serv {
least_conn;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
server 127.0.0.1:9003;
server 127.0.0.1:9004;
}

# 設定快取路徑
proxy_cache_path cache keys_zone=CACHE:10m levels=1:4 inactive=1m max_size=1g;

server {
listen 80;
server_name localhost;

location / {
proxy_pass http://serv$request_uri;

#以下三行,目的是將代理服務器收到的用戶的資訊傳到真實服務器上
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# 快取
proxy_cache CACHE;
proxy_cache_min_uses 1;
proxy_cache_valid any 1m;
    }
  }
}

重啟nginx,此時使用瀏覽器訪問127.0.0.1,第一次nginx沒有快取,服務器端列印出了訪問日志,再以后的訪問,服務器不再列印日志,說明nginx快取起到了作用,

我們在tornado服務器的代碼中加入100毫秒的sleep,來模擬訪問資料庫的操作,對不啟用快取和啟用快取進行壓力測驗:

可以看出,快取技術對吞吐量的提升非常有效!

 

快取的副作用及解決方案

快取,意味著不是最新的,如果某頁面的內容的變化很快,使用快取技術將導致客戶端接收到錯誤的結果,如我增加一個url,輸出服務器當前的時間:

# -*- coding: utf-8 -*-

import os
import sys
import time
import datetime
import multiprocessing
import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import parse_command_line

# 頁面句柄
class StaticHandler(tornado.web.RequestHandler):
def get(self):
time.sleep(0.1)
self.write('我是tornado,我夠快!')

class VariableHandler(tornado.web.RequestHandler):
def get(self):
now = datetime.datetime.now()
self.write(now.strftime("%Y-%m-%d %H:%M:%S"))


class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", StaticHandler), # 可以快取的頁面
(r"/variable", VariableHandler), # 禁止快取的頁面
]

settings = dict(
title='壓力測驗',
debug=True,
)

tornado.web.Application.__init__(self, handlers, **settings)

# 啟動服務器
def start_web_server(port):
parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True, max_buffer_size=504857600)
http_server.listen(port)

print('Web server is started on port %d.' % port)
tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
if len(sys.argv) == 1:
start_web_server(80)
else:
try:
ports = [int(port) for port in sys.argv[1].split(',')]
except:
try:
a, b = sys.argv[1].split('-')
ports = range(int(a), int(b) + 1)
except:
ports = list()
print ('Parameter error.')

multiprocessing.freeze_support()
for port in ports:
p = multiprocessing.Process(target=start_web_server, args=(port,))
p.start()

此時瀏覽器訪問127.0.0.1/variable,第一次出現了正確的時間,以后的1分鐘以內,時間不再變化,等1分鐘以后快取過期,再訪問出能得到新的時間,為了解決這個問題,可以在nginx配置中添加多個location,分別指定是否啟用快取即可:

worker_processes 1;

events {
worker_connections 1024;
}


http {
sendfile on;
keepalive_timeout 65;

upstream serv {
least_conn;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
server 127.0.0.1:9003;
server 127.0.0.1:9004;
}

proxy_cache_path cache keys_zone=CACHE:1m levels=1:2 inactive=1m max_size=1g;

server {
listen 80;
server_name localhost;

location / {
proxy_pass http://serv$request_uri;

#以下三行,目的是將代理服務器收到的用戶的資訊傳到真實服務器上
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# 快取
proxy_cache CACHE;
proxy_cache_min_uses 1;
proxy_cache_valid any 1m;
}

# 只轉發請求,不進行快取
location /variable {
proxy_pass http://serv$request_uri;

#以下三行,目的是將代理服務器收到的用戶的資訊傳到真實服務器上
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }  
  }
}

重啟nginx后,再訪問127.0.0.1/variable,每次都可以得到最新的時間,

 

負載均衡

  • 負載均衡也是Nginx常用的一個功能,負載均衡其意思就是分攤到多個操作單元上進行執行,例如Web服務器、FTP服務器、企業關鍵應用服務器和其它關鍵任務服務器等,從而共同完成作業任務,
  • 簡單而言就是當有2臺或以上服務器時,根據規則隨機的將請求分發到指定的服務器上處理,負載均衡配置一般都需要同時配置反向代理,通過反向代理跳轉到負載均衡,而Nginx目前支持自帶3種負載均衡策略,還有2種常用的第三方策略,

RR(默認)

每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器down掉,能自動剔除,

簡單配置:

upstream test {
        server localhost:8080;
        server localhost:8081;
    }
    server {
        listen       81;
        server_name  localhost;
        client_max_body_size 1024M;

        location / {
            proxy_pass http://test;
            proxy_set_header Host $host:$server_port;
        }
    }

負載均衡的核心代碼為:

upstream test {
        server localhost:8080;
        server localhost:8081;
    }

這里我配置了2臺服務器,當然實際上是一臺,只是埠不一樣而已,而8081的服務器是不存在的,也就是說訪問不到,但是我們訪問http://localhost 的時候,也不會有問題,會默認跳轉到http://localhost:8080

具體是因為Nginx會自動判斷服務器的狀態,如果服務器處于不能訪問(服務器掛了),就不會跳轉到這臺服務器,所以也避免了一臺服務器掛了影響使用的情況,由于Nginx默認是RR策略,所以我們不需要其他更多的設定,

權重

指定輪詢幾率,weight和訪問比率成正比,用于后端服務器性能不均的情況,例如

upstream test {
        server localhost:8080 weight=9;
        server localhost:8081 weight=1;
    }

那么10次一般只會有1次會訪問到8081,而有9次會訪問到8080

ip_hash

上面的2種方式都有一個問題,那就是下一個請求來的時候請求可能分發到另外一個服務器,當我們的程式不是無狀態的時候(采用了session保存資料),這時候就有一個很大的很問題了,比如把登錄資訊保存到了session中,那么跳轉到另外一臺服務器的時候就需要重新登錄了,所以很多時候我們需要一個客戶只訪問一個服務器,那么就需要用iphash了,iphash的每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器,可以解決session的問題,

upstream test {
        ip_hash;
        server localhost:8080;
        server localhost:8081;
    }

fair(第三方)

按后端服務器的回應時間來分配請求,回應時間短的優先分配,

upstream backend {
        fair;
        server localhost:8080;
        server localhost:8081;
    }

url_hash(第三方)

按訪問url的hash結果來分配請求,使每個url定向到同一個后端服務器,后端服務器為快取時比較有效,在upstream中加入hash陳述句,server陳述句中不能寫入weight等其他的引數,hash_method是使用的hash演算法

upstream backend {
        hash $request_uri;
        hash_method crc32;
        server localhost:8080;
        server localhost:8081;
    }

以上5種負載均衡各自適用不同情況下使用,所以可以根據實際情況選擇使用哪種策略模式,不過fair和url_hash需要安裝第三方模塊才能使用,由于本文主要介紹Nginx能做的事情,所以Nginx安裝第三方模塊不會再本文介紹

 

HTTP服務器

Nginx本身也是一個靜態資源的服務器,當只有靜態資源的時候,就可以使用Nginx來做服務器,同時現在也很流行動靜分離,就可以通過Nginx來實作,首先看看Nginx做靜態資源服務器

server {
        listen       80;
        server_name  localhost;
        client_max_body_size 1024M;


        location / {
               root   e:\wwwroot;
               index  index.html;
           }
    }

這樣如果訪問http://localhost 就會默認訪問到E盤wwwroot目錄下面的index.html,如果一個網站只是靜態頁面的話,那么就可以通過這種方式來實作部署,

動靜分離

動靜分離是讓動態網站里的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以后,我們就可以根據靜態資源的特點將其做快取操作,這就是網站靜態化處理的核心思路

upstream test{
       server localhost:8080;
       server localhost:8081;
    }

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   e:\wwwroot;
            index  index.html;
        }

        # 所有靜態請求都由nginx處理,存放目錄為html
        location ~ \.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
            root    e:\wwwroot;
        }

        # 所有動態請求都轉發給tomcat處理
        location ~ \.(jsp|do)$ {
            proxy_pass  http://test;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   e:\wwwroot;
        }
    }

這樣我們就可以吧HTML以及圖片和css以及js放到wwwroot目錄下,而tomcat只負責處理jsp和請求,例如當我們后綴為gif的時候,Nginx默認會從wwwroot獲取到當前請求的動態圖檔案回傳,當然這里的靜態檔案跟Nginx是同一臺服務器,我們也可以在另外一臺服務器,然后通過反向代理和負載均衡配置過去就好了,只要搞清楚了最基本的流程,很多配置就很簡單了,另外localtion后面其實是一個正則運算式,所以非常靈活

總結

Nginx是支持熱啟動的,也就是說當我們修改組態檔后,不用關閉Nginx,就可以實作讓配置生效,當然我并不知道多少人知道這個,反正我一開始并不知道,導致經常殺死了Nginx執行緒再來啟動…..Nginx重新讀取配置的命令是

nginx -s reload

windows下面就是:

nginx.exe -s reload

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/185246.html

標籤:Python

上一篇:django-blog:多對多查詢

下一篇:Python - AI自動摳圖

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more