不少人可能或多或少了解過nginx
,即便沒有使用過nginx
,可是可能用Apache
搭建過簡單的web
服務器,用tomcat
寫過一些簡單的動態頁面,其實這些功能nginx均可以實現。javascript
nginx
最重要的三個使用場景我的認爲是靜態資源服務
、反向代理服務
和api服務
。css
web
請求走進服務之後會先通過nginx
再到應用服務,而後再去訪問redis
或者mysql
提供基本的數據功能。html
這就有個問題,應用服務由於要求開發效率高,因此他的運行效率是很低的,他的qbs
,tps
併發都是受限的,因此就須要把不少的應用服務組成集羣,向用戶提供高可用性。java
不少服務構成集羣的時候,須要nginx
具備反向代理的功能,能夠把動態請求傳導給對應的應用服務。服務集羣必定會帶來兩個需求,動態的擴容和容災。mysql
反向代理必須具有負載均衡的功能,其次在鏈路中,nginx
是處在企業內網的邊緣節點,隨着網絡鏈路的增加,用戶體驗到的時延會增長。linux
把一些全部用戶看起來不變的,或者在一段時間內看起來不變的動態內容緩存在nginx
部分,由nginx
直接向用戶提供訪問,用戶的時延就會減小不少。nginx
反向代理衍生出另外的功能叫緩存,他可以加速訪問,而不少時候在訪問像css
或js
文件又或者一些小圖片是沒有必要由應用服務來訪問的,他只須要直接由nginx
提供訪問就能夠了這就是nginx
的靜態資源功能。web
應用服務它自己的性能有很大的問題,數據庫服務要比應用服務好的多,緣由是數據庫他的業務場景比較簡單,併發性能和tps
都要遠高於應用服務。由nginx
直接去訪問數據庫或者redis
也是不錯的選擇。正則表達式
還能夠利用nginx
強大的併發性能,實現如web
防火牆的一些業務功能,這就要求nginx
服務有很是強大的業務處理功能,openResty
和nginx
集成了一些工具庫來實現此功能。redis
全球化和物聯網的快速發展,致使接入互聯網中的人與設備的數量都在快速的上升,數據的快速爆炸,對硬件性能提出很高的要求。
摩爾定律代表以前服務跑在1GHZ
的CPU
上的服務更新到2GHZ
的CPU
時服務會有兩倍的性能提高。
可是到了本世紀初,摩爾定律在單顆CPU
的頻率上已經失效了,CPU
開始向着多核方向發展,當服務器如今是跑在8
核CPU
上時,一年半之後換到了16
核的CPU
,服務的性能一般是不會有一倍的提高的。
這些性能主要損耗在操做系統和大量的軟件沒有作好服務於多核架構的準備,好比說像Apache
是低效的,由於他的架構模型裏一個進程同一時間,只會處理一個鏈接,一個請求。只有在這個請求處理完之後纔會去處理下一個請求。
它實際上在使用操做系統的進程間切換的特性,由於操做系統微觀上是有限的CPU
,可是操做系統被設計爲同時服務於數百甚至上千的進程。
Apache
一個進程只能服務於一個鏈接,這種模式會致使當Apache
須要面對幾十萬,幾百萬鏈接的時候,他沒有辦法去開幾百萬的進程,而進程間切換的代價成本又過高啦。
當併發的鏈接數越多,這種無謂的進程間切換引起的性能消耗又會越大。
nginx
是專門爲了這種應用場景而生的,能夠處理數百萬甚至上千萬的併發鏈接,nginx
目前在web
市場份額中排行第二,在過去幾年他增加極度迅速,在不久的未來nginx
在web
端的應用將遠遠超過其餘服務器。
大部分的程序和服務器隨着併發鏈接數的上升他的RPS
數會急劇的降低,這裏的原理就像以前所說過的,他的設計架構是有問題的。
nginx
的第一個優勢就是高併發和高性能同時具有的,每每高併發只須要對每個鏈接所使用的內存儘可能的少就能夠達到。
而具備高併發的同時達到高性能,每每須要很是好的設計,那nginx
能夠達到什麼樣的標準呢?
好比說如今主流的一些服務器32
核64G
的內存能夠輕鬆達到數千萬的併發連接,若是是處理一些簡單的靜態資源請求,能夠達到一百萬的RPS
這種級別。
其次nginx
的可擴展性很是好,主要在於他的模塊化設計很是的穩定,並且nginx
的第三方模塊的生態圈很是的豐富。甚至於有像TNG
,openRestry
這種第三方插件。豐富的生態圈爲nginx
豐富的功能提供了保證。
第三個優勢是它的高可靠性,所謂的高可靠性是指nginx
能夠在服務器上持續不間斷的運行數年,而不少web
服務器每每運行幾周或者幾個月就須要作一次重啓。
對於nginx
這種高併發高性能的反向代理服務器而言,他每每運行在企業內網的邊緣節點上,若是企業想提供4個9
,5個9
,甚至更高的高可用性時,對於nginx
持續運行可以down
機的時間一年可能只能以秒來計。因此在這種角色中,nginx
的高可靠性給提供了很是好的保證。
第四個優勢熱部署,是指能夠在不中止服務的狀況下升級nginx
,這對於nginx
來講很是的重要,由於在nginx
可能跑了數百萬的併發鏈接。
若是是普通的服務可能只需kill
掉進程再重啓的方式就能夠處理好,可是對於nginx
而言,由於kill
掉nginx
進程,會致使操做系統爲全部的已經創建鏈接的客戶端發送一個tcp
中的reset
報文。而不少客戶端是沒有辦法很好的處理請求的。
在大併發場景下,一些偶然事件就會致使必然的惡性結果,因此熱部署是很是有必要的。
第五個優勢是BSD
許可證,BSD Listens
是指nginx
不只是開源的免費的,並且能夠在有定製須要的場景下,去修改nginx
源代碼,再運行在商業場景下,這是合法的。
以上的優勢是nginx
最核心的特性。
首先是nginx
的可執行文件,它是由nginx
自身的框架、官方模塊以及各類第三方模塊共同構建的文件。他有完整的系統,全部的功能都由他提供。
第二個部分是nginx.conf
配置文件,相似於騎車的駕駛員,雖然可執行文件已經提供了許多功能,但這些功能有沒有開啓,或者開啓了之後定義了怎樣的行爲處理請求,都是由nginx.conf
配置文件決定的。
nginx
的第三個組成部分叫作access.log
訪問日誌,access.log
會記錄下每一條nginx
處理過的http
請求信息與響應信息。
第四個組成部分是error.log
錯誤日誌,當出現了一些不可預期的問題時,能夠經過error.log
去把問題定位出來。
這四個部分是相輔相成的。
nginx
的可執行文件和nginx.conf
定義了處理請求的方式。若是想對web服務,作一些運營或者運維的分析,須要對access.log
作進一步的分析。若是出現了任何未知的錯誤,或者與預期的行爲不一致時,應該經過error.log
去定位根本性的問題。
nginx
每發佈一個版本的時候會有三個特性,一個是feature
,就是他新增了哪些功能,bugfix
表示他修復了哪些bug
,change
表示作了哪些重構。
每個版本都有mainline
主幹版本和stable
穩定版本。
在nginx
的官網點擊右下角的download
,就能夠看到版本號列表,單數版本表示主幹版本,會新增不少功能,但不必定穩定。雙數版本是穩定版本。
CHANGES
文件中能夠看到每個版本含有的新增功能,修復的bug
,以及作了哪些小的重構。
大概在2009
年之後nginx
的bugfix
數量已經大幅度減小,因此nginx
相對已經很穩定了。
nginx
的開發時間是在2002
年,可是他在2004
年10
月4
日推出了第一個版本,在2005年
曾經作過一次大的重構。
由於nginx
優秀的設計,使得他的生態圈極爲豐富,模塊的設計,架構的設計都沒有再作過大的變更。
在2009
年nginx
開始支持windows
操做系統,2011
年1.0
正式版本發佈,同時nginx
的商業公司nginx Plus
也成立了,在2015
年nginx
發佈了幾個重要的功能。
其中提供stream
,四層反向代理
,他在功能上徹底能夠替代傳統使用的LVS
, 而且具備更豐富的功能。
免費開源: nginx.org
商業版本: nginx.com
開源免費的nginx
在2002
年開始開發,到2004
年發佈第一個版本,2011
年開源版的nginx
發佈了1.0
穩定版,同年nginx
的做者成立了一家商業公司,開始推出nginx Plus
商業版的nginx
。
商業版的nginx
在整合第三方模塊上還有運營監控以及技術支持上有不少優勢,但他有個最大的缺點就是不開源,因此一般在國內會使用nginx.org
開源版的。
阿里巴巴也推出了Tengine
版本,Tengine
的優勢就是在阿里巴巴生態下他經歷了很是嚴苛的考驗,Tengine
之因此會存在也是由於他的不少特性領先於nginx
的官方版本。
因此Tengine
其實是修改了nginx
官網版本的主幹代碼,固然框架被修改之後Tengine
就遇到了一個明顯的問題,沒有辦法跟着nginx
的官方版本同步的升級。Tengine
也可使用nginx
的第三方模塊。
OpenResty
的做者章亦春在阿里巴巴的時候開發了Lua
語言版本的openResty
,由於nginx
的第三方模塊開發的難度至關大,章亦春把nginx
非阻塞事件的一種框架以Lua
語言的方式提供給了廣大開發者。
OenRestry
兼具了高性能,以及開發效率高的特色,OpenResty
一樣有開源版和商業版,目前多使用openresty.org
站點下的開源版本。商業版OpenRestry
的主要特色是技術支持相對比較好不少。
若是你沒有太多的業務訴求,那麼使用開源版的nginx
就足夠了,若是你須要開發Api
服務器,或者須要開發web
防火牆,openrestry
是一個很好的選擇。
安裝nginx
有兩種方法,除了編譯外,還能夠直接用操做系統上自帶的一些工具,好比說yum
,apt-get
,直接去安裝nginx
。
可是直接安裝nginx
有個問題,就是nginx
的二進制文件不會把模塊直接編譯進來,畢竟nginx
的官方模塊,並非每個默認都會開啓的。
若是想添加第三方的nginx
模塊,就必須經過編譯nginx
的方式。
編譯nginx
主要分爲六個部分,首先須要下載nginx
,從nginx.org
網站上直接下載就能夠。
打開nginx.org
在頁面中找到右下角donwload
,選擇Stable
版本的下來連接,右鍵複製連接地址便可,進入到Linux
中使用wget
進行下載
cd /home/nginx
wget http://nginx.org/download/nginx-1.18.0.tar.gz
複製代碼
下載完nginx
壓縮包之後首先解壓壓縮包。
tar -xzf nginx-1.18.0.tar.gz
複製代碼
接着進入解壓後的目錄經過ll
命令查看全部文件。
cd nginx-1.18.0
ll
複製代碼
第一個目錄叫auto
目錄。
cd auto
複製代碼
auto
目錄裏面有四個子目錄,cc
是用於編譯的,lib
庫和對操做系統的判斷在os
裏面,其餘全部的文件都是爲了輔助config
腳本執行的時候斷定nginx
支持哪些模塊以及當前的操做系統有什麼樣的特性能夠供給nginx
使用。
CHANGES文
件標記了nginx
每個版本中提供了哪些特性和bugfix
。
cat ../CHANGES
複製代碼
其中會有feature
,bugfix
,change
三種特性在裏面。
CHANGES.ru
文件是俄羅斯語言的CHANGES
文件,可能由於做者是個俄羅斯人。
conf
文件是一個示例文件,就是把nginx
安裝好之後,爲了方便運維配置,會把config
裏面的示例文件copy
到安裝目錄。
configure
腳本用來生成中間文件,執行編譯前的一個一些配置,也就是記錄編譯前的設定信息,編譯時使用。
contrib
目錄提供了兩個腳本和vim
工具,也就是讓vim
打開config
配置文件時支持代碼高亮。
把contrib
目錄下vim
的全部文件copy
到本身的目錄中
cp -r contrib/vim/* ~/.vim/
複製代碼
就能夠把nginx
語言的語法高亮顯示在vim中
了。
html
目錄裏面提供了兩個標準的HTML
文件,一個是發現500
錯誤的時候能夠重定向到的文件,另外一個是默認的nginx
的歡迎界面index.html
。
man
文件裏則是Linux
對nginx
的幫助文件,裏面標識了最基本的nginx
幫助和配置。
src
目錄是nginx
的核心源碼。
編譯前能夠先看一下configure
支持哪些參數。
./configure --help | more
複製代碼
首先就是肯定nginx
執行中會去找哪些目錄下的文件做爲輔助文件。好比用動態模塊時--modules-path
就會產生做用。--lock-path
肯定nginx.lock
文件放在哪裏等。
若是沒有任何變更的話只須要指定--prefix=PATH
就能夠了,設定一個安裝目錄。
第二類參數主要是用來肯定使用哪些模塊和不使用哪些模塊的,前綴一般是--with
和--without
。
好比說--with-http_ssl_module
或者--with-http_v2_module
一般須要主動加--with
的時候,意味着模塊默認是不會編譯進nginx
的。
而模塊中顯示--without
好比說--without-http_charset_module
意味着默認他會編譯進nginx
中,加了參數是把他移除默認的nginx
的模塊中。
第三類參數中指定nginx
編譯須要的一些特殊的參數,好比說用cc
編譯的時候須要加一些什麼樣的優化參數,或者說要打印debug
級別的日誌(--with-debug
)以及須要加一些第三方的模塊(--with-zlib-asm=CPU
)
這裏指定的nginx
的安裝目錄是在/home/nginx
目錄下。
./configure --prefix=/home/nginx/nginx/
複製代碼
若是沒有任何報錯nginx
就已經編譯成功了,全部nginx
的配置特性以及nginx
運行時的目錄都會列在最下方。
在config
執行完以後,會看到生成了一些中間文件。中間文件會放在objs
文件夾下。最重要的是會生成一個文件叫作ngx_modules.c
他決定了接下來執行編譯時哪些模塊會被編譯進nginx
。能夠打開看一下全部被編譯進nginx
的模塊都會列在這裏,他們最後會造成一個叫作ngx_modules
的數組。
執行make
編譯。
make
複製代碼
編譯完成之後若是沒有任何錯誤,就能夠看見生成了大量的中間文件,以及最終的nginx
二進制文件。
cd objs/
ll
複製代碼
最後進行make install
。
make install
複製代碼
安裝完成以後在--prefix
指定的安裝目錄中能夠看到不少目錄,nginx
的執行文件就在sbin
目錄下。
決定nginx
功能的配置文件在conf
下,access.log
和error.log
在log
文件夾下。
能夠看到在conf
目錄下全部文件就是在源代碼中conf
目錄copy過來的,其中的內容也是徹底相同的。
nginx
可執行文件中已經指定了他包含了哪些模塊,但每個模塊都會提供獨一無二的配置語法。
這些全部的配置語法,會遵循一樣的語法規則。
nginx
的配置文件是一個ascii
的文本文件,主要有兩部分組成,指令
和指令快
。
http {
include mime.types;
upstream thwp {
server 127.0.0.1:8000;
}
server {
listen 443 http2;
# nginx配置語法
limit_req_zone $binary_remote_addr zone=one:10 rate=1r/s;
location ~* \.(gif|jpg|jpeg)$ {
proxy_cache my_cache;
expires 3m;
}
}
}
複製代碼
上面http
就是一個指令快,include mime.types;
就是一條指令。
每條指令以分號結尾,指令和參數間以空格分隔。include mime.types;
中include
是一個指令名,mime.types
是參數中間能夠用一個或多個空格分隔。參數能夠有多個,好比下面的limit_req_zone
有三個參數,多個參數之間也是用空格分隔。
兩條指令間是以;
做爲分隔符的,兩條指令放在一行中寫也是沒有問題的。只不過可讀性會變得不好。
第三個指令塊是以 {}
組成的,他會將多條指令組織到一塊兒,好比upstream
,他把一條指令server
放在了thwp
指令塊下面。
server
中也放置了listen
,limit_req_zone
這些指令,他也能夠包含其餘的指令塊,好比說location
。
有些指令能夠有名字,好比upstream
,後面有個thwp
做爲他的名字。
具體什麼樣的指令有名字什麼樣的指令沒有名字是由提供指令塊的nginx
模塊來決定的,他也能夠決定指令塊後面有一個或者說多個參數,或者說沒有參數。
include
語句容許引入多個配置文件以提高可維護性。在例子中mime.types
文件中其實裏面是含有不少條不一樣的文件的後綴名與http
協議中mime
格式的對照關係表。
include
是導入其餘配置模塊的意思。
#
符號能夠添加註釋,提高可讀性,好比在listen後面加了一個nginx
配置語法的註釋,以描述下面一些配置的表達。
使用$
符號可使用變量,能夠看下limit_req_zone
這裏用了一個參數叫作$binary_remote_addr
,這是一個變量描述的是遠端的地址。
部分指令的參數是支持正則表達式的,好比location
後面能夠看到,他能夠支持很是複雜的正則表達式,並且能夠把正則表達式括號裏的內容經過$1
,$2
,$3
的方式取出來。
在nginx
的配置文件中當涉及到時間的時候,還有許多表達方式,好比下面的方式:
ms -> 毫秒
s -> 秒
m -> 分鐘
h -> 小時
d -> 天
w -> 周
M -> 月
y -> 年
複製代碼
好比location
中的expires 3m;
就表示3分鐘
後但願cache
刷新。
空間也是有單位的,當後面不加任何後綴名時表示字節bytes
,加了k
或者K
表示千字節,m
表示兆字節,g
表示G
字節。
http
大括號裏面全部的指令都是由http
模塊去解析和執行的,非http
模塊,好比說像stream
或mime
是沒有辦法去解析指令的。
upstream
表示上游服務,當nginx
須要與Tomcat
等企業內網的其它服務交互的時候呢,能夠定義一個upstream
。
server
對應的一個或一組域名,location
是url
表達式。
須要幫助的時候能夠用-?
或者 -h
獲取幫助信息。
nginx -?
nginx -h
複製代碼
默認狀況下編譯出來的nginx
會尋找執行configure
命令時指定的配置文件。在命令行中能夠指定另外一個配置文件用-c 路徑
。
還能指定一些配置用-g
,指令就是在nginx
的configure
目錄裏的指令。
nginx
操做運行中的進程通常是經過發送信號,能夠經過linux
的kill
命令也能夠用nginx -s
子命令,子命令後能夠用stop
,quit
,reload
,reopen
。
nginx -s stop # 中止nginx服務
nginx -s quit # 優雅的中止nginx服務
nginx -s reload # 重載配置文件
nginx -s reopen # 從新開始記錄日誌文件。
複製代碼
-t
能夠測試一下配置文件是否合法問題。
-V
是在編譯時用configure
腳本執行所加的全部參數。
修改nginx
配置文件中的一些值,好比說conf/nginx.conf
文件中,打開tcp_nopush
。
當修改完配置文件之後,能夠直接執行nginx -s reload
命令nginx
是在不中止對客戶服務的狀況下使用了tcp_nopush
新的配置項,很是的簡單。
nginx
在運行的狀況下想更換最新版本的nginx
,根據以前所說的,nginx
編譯方法下載一個新的nginx
。
把最新版本的nginx
編譯後的可執行文件nginx
,copy
到目錄中替換掉正在運行的nginx
文件。copy
完成須要給正在運行的nginx
的master
進程發送一個信號,告訴他開始進行熱部署作一次版本升級,給nginx
的master
進程發送一個信號,USR2
信號。
kill -USR2 進程號(13195)
複製代碼
nginx
會新啓一個master
進程使用的正式剛剛複製過來的最新的nginx
二進制文件。
舊的worker
也在運行,新的master會生成新的worker
,他們會平滑的把全部的請求過渡到新的進程中。
新的請求新的鏈接會進入新的nginx
進程中,這時須要向老的nginx
進程發送一個信號叫作WINCH
,告訴他優雅的關閉全部進程。
kill -WINCH 13195
複製代碼
這時老的worker
進程會優雅的退出,可是老的master
進程還在,只是是沒有worker
進程了。
這說明全部的請求已經所有切換到新的nginx
中了,若是須要把新版本退回到老版本,能夠向老的進程發送reload
命令,讓他從新把worker
進程拉起來。再把新版本關掉。因此保留master
是爲了容許作版本回退。
好比說當前的日誌已經很大了。須要把之前的日誌備份到另一個文件中,可是nginx
仍是正常運行的。
這就要經過reopen
命令來作,首先須要把當前正在使用的日誌copy
一份放在另外的位置.
mv access_log bak.log
複製代碼
接着執行命令reopen
。
nginx -s reopen
複製代碼
就從新生成了一個access.log
, 本來的log
備份成了bak.log
,就實現了日誌切割。
固然這種方法會很是很差用,實際上每每是每一天,或者是每一週執行一第二天至切割,能夠先寫成一個bash
腳本。
在bash
腳本中首先把文件複製一下,再執行-s reopen
命令,最後把腳本放在crontab
中。
編輯conf/nginx.conf
文件找到server
代碼塊中,listen
配置監聽端8080
端口,而後須要配置一個location
,使用/
讓全部的請求都訪問到www
文件夾。
這裏須要指定url
的後綴與文件的後綴一一對應,有兩種用法,root
和alias
,root
是系統的跟目錄,因此一般使用alias
,alias
是nginx
的安裝目錄。
server {
listen 8080;
...
location / {
alias www/;
...
}
...
}
複製代碼
作完配置以後啓動nginx
在瀏覽器中訪問localhost:8080
就能夠了。
nginx -s reload
複製代碼
作完gzip
壓縮傳輸的字節數會大幅度減小,因此一般會打開gzip
。
首先打開nginx.conf
文件,找到http
代碼塊中的gzip
相關選項,打開gzip(off -> on)
, gzip_min_length
是小於多少字節再也不執行壓縮,由於小於必定的字節http
傳輸直接就能夠發送了,壓縮反而消耗cpu
性能,gzip_comp_level
表明壓縮級別,gzip_types
是針對某些類型的文件才作gzip
壓縮。
http {
...
gzip on;
gzip_min_length 1;
gzip_comp_level 2;
gzip_types text/plain applicaton/x-javascript text/css image/png;
...
}
複製代碼
配置好後重啓nginx
, 瀏覽器中查看就會發現,傳輸的文件已經減小了不少,響應頭中多出了Content-encoding: gzip
。使用gzip
之後整個web
服務傳輸效率會高不少。
nginx
給提供了一個官方模塊叫作autoindex
,他能夠提供當訪問以/
結尾的url
時,顯示目錄的結構。使用方法也特別簡單,就是autoindex on
加入一個指令就能夠了。
location / {
autoindex on;
}
複製代碼
他會把所訪問的文件夾內全部文件列出來,當打開一個目錄時,能夠繼續顯示目錄中的文件,這是一個很好的靜態資源幫助功能。
好比公網帶寬是有限的,當有不少併發用戶使用帶寬時,他們會造成一個爭搶關係,可讓用戶訪問某些大文件的時候來限制他的速度,節省足夠的帶寬給用戶訪問一些必要的小文件。
就可使用set
命令,配合一些內置的變量實現這種功能,好比說加上set $limit_rate 1k
,限制nginx
向客戶瀏覽器發送響應的一個速度。意思是每秒傳輸多少數據到瀏覽器中。
location / {
set $limit_rate 1k;
}
複製代碼
首先須要設置access
日誌格式,找到一個指令叫作log_format
, 他用來定義日誌的格式,這裏可使用變量。
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
}
複製代碼
$remote_addr
爲遠端的地址,也就是瀏覽器客戶端的ip
地址,$time_local
表示當時的時間。$status
是返回的狀態碼。格式定義好以後須要定義一個名字,這裏是main
。
不一樣的名字能夠對不一樣的域名下,作不一樣格式的日誌記錄,或者對不一樣的url
記錄不一樣日誌格式。
配置好log_format
以後,就能夠用access_log
指令,配置日誌了。access_log
所在的代碼塊決定了日誌的位置好比access_log
這裏放在了server
下,也就是全部請求這個路徑和端口的請求日誌,都會記錄到logs/yindong.log
文件中,使用的格式就是main
。
server {
listen 8080;
access_log logs/yindong.log main;
location / {
alias dlib;
}
}
複製代碼
配置好yindong.log
後,全部的請求在完成以後都會記錄下一條日誌,能夠進入logs/yindong.log中查看每一條都是設置的格式。
因爲上游服務要處理很是複雜的業務邏輯並且強調開發效率,因此他的性能並不怎麼樣,使用nginx
做爲反向代理之後,能夠由一臺nginx
把請求按照負載均衡算法代理分配給多臺上游服務器工做。
這就實現了水平擴展的可能,在用戶無感知的狀況下,添加更多的上游服務器,來提高處理性能,而當上遊服務器出現問題的時候,nginx
能夠自動的把請求從有問題的服務器,轉交給正常的服務器。
反向代理須要添加一個upstream
,就是上游服務server
,訪問地址是127.0.0.1:8080
若是有不少臺上遊服務能夠依次的放在這裏。
upstream
設置的一批服務叫local
。對全部的請求使用proxy_pass
一條指令,代理到local裏。
upstream local{
server 127.0.0.1:8080;
}
server {
server_name yindong.com;
listen 80;
location / {
proxy_set_header Host $host;
proxt_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 反向代理轉發
proxy_pass http://local;
}
}
複製代碼
由於反向代理的緣由,真實的服務器拿到的信息是通過nginx
代理服務器轉發的,因此不少信息都不是真實的,好比說域名
,ip
都是代理服務器發送過來的,因此須要在location
中作一些配置處理。
經過proxy_set_header
能夠把有一些值添加一條新的header
發送到上游,好比說叫x-real-ip
,而後把他的值設爲從tcp
連接裏面拿到的遠端ip
地址。
$host
也是一樣的由於用戶直接訪問的域名,是他在瀏覽器輸入的,既可讓他在上游服務器能夠處理域名,也能夠由反向代理來處理。
全部這些配置特性均可以在官網中的http_proxy_module
找到。
這裏有個很重要的特性proxy_cache
, 由於當nginx
做爲反向代理時,一般只有動態的請求,也就是不一樣的用戶訪問同一個url
看到的內容是不一樣的,纔會交由上游服務處理。
可是有一些內容多是一段時間不會發生變化的,爲了減輕上游服務器的壓力,就會讓nginx
把上游服務返回的內容緩存一段時間,好比緩存一天,在一天以內即便上游服務器對內容的響應發生了變化,也無論,只會去拿緩存住的這段內容向瀏覽器作出響應。
由於nginx
的性能遠遠領先於上游服務器的性能。因此使用一個特性後,對一些小的站點會有很是大的性能提高。
配置緩存服務器首先要去經過proxy_cache_path
這條指令去設置緩存文件寫在哪一個目錄下。
好比這裏是/tmp/nginxcache
, 以及這些文件的命名方式,這些文件的關鍵詞key
,要放在共享內存中的。這裏開了10MB
的共享內存,命名爲my_cache
。
proxy_cache_patj /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path_off;
複製代碼
緩存的使用方法就是在須要作緩存的url
路徑下,添加proxy_cache
, 後面所跟的參數就是剛剛開闢的那個共享內存,在共享內存中所設置的key
就是同一個url
訪問時對不一樣的用戶可能展現的東西是不同的,因此用戶這個變量就要放在key
中。
這裏作一個很是簡單的key
,好比說訪問的host url
可能加了一些參數,這些參數可能已經指明瞭是哪一個用戶哪一個資源,$host$uri$is_args$args;
這些做爲一個總體的key
。
location / {
proxy_cache my_cache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 302 1d;
}
複製代碼
加完這些參數之後,能夠嘗試停掉上游服務,而後訪問站點,能夠發現站點仍然是能夠訪問的。就是由於被緩存了。
Access
日誌記錄了nginx
很是重要的信息,能夠用日誌來分析定位問題,也能夠用它來分析用戶的運營數據,可是若是想實時分析Access.log
相對來講還比較困難。
有一款工具叫GoAccess
能夠以圖形化的方式,經過websocket
協議實時的把Access.log
的變遷反應到瀏覽器中,方便分析問題。
GoAccess
的站點是 https://goaccess.io
, 以一種很是友好的圖形化方式顯示。
GoAccess
使用-o
參數生成新的html
文件,把當前access.log
文件中的內容以html圖表的方式展現出來,當access.log
變遷的時候GoAccess
會新起一個socket進程,經過端口的方式把新的access.log
推送到客戶端。
goaccess access.log -o report.html --log-format=COMBINED
複製代碼
首先制定access.log
程序制定的位置(yindong.log
), 把它輸出到../html/report.html
文件中,使用的是--real-time-html
就是實時更新頁面的方式,時間格式--time-format='%H:%M:%S'
, 日期格式--date-format='%d/%b/%Y'
, 以及日誌格式--log-format=COMBINED
。
cd logs
goaccess yindong.log -o ../html/report.html --real-time-html --time-format='%H:%M:%S' --date-format='%d/%b/%Y' --log-format=COMBINED
複製代碼
GoAccess
的安裝能夠用yum
或者wget
,也能夠下載源碼進行編譯。
啓動完成以後能夠看到一條log
叫作 WebSocket server ready to accept new client connections
, 也就是他已經打開了一個新的websocket
監口,當訪問report.html
的時候,會向進程發起鏈接, 由進程給推送最新的log
變動。
接下來還要在nginx.conf
中添加location
,當訪問/report.html
時候用alias
重定向到report.html
。
server {
...
location /report.html {
alias /usr/local/openresty/nginx/html/report.html;
}
...
}
複製代碼
打開localhost:8080/report.html
就能夠看到效果了。
使用GoAccess.log
能夠很是直觀的看到access.lo
g統計信息上的變遷,對分析網站的運營狀況很是有幫助,能夠看到每一個時間點,每一週每一天,甚至不一樣的國家地區使用不一樣瀏覽器和操做系統的人使用站點的一個比例和分佈。
SSL
的全稱是Secure Sockets Layer
,如今不少時候使用的是TLS
也就是Transport Layer Security
。能夠將TLS
看作是SSL
的升級版。
SSL
是網景公司在1995
年推出的,後來由於微軟把本身的IE瀏覽器
捆綁windows
一塊兒賣出致使網景遇到很大的發展困境,網景把SSL
協議交給IETF
組織。
在1999
年,應微軟的要求IETF
把SSL
改名爲TLS1.0
,在06
,08
到2018
年TLS
分別發佈了1.1
,1.2
和1.3
協議。
那麼TLS
協議到底是怎樣保證http
的明文消息被加密的呢?
在ISO/OSI
七層模型中,應用層是http
協議,在應用層之下,表示層也就是TLS
所發揮做用的這一層,經過握手
,交換密鑰
,告警
,對稱加密
的方式使http
層沒有感知的狀況下作到了數據的安全加密。
當抓包或者觀察服務端配置時,能夠看到安全密碼的配置,安全密碼的配置決定了TLS
協議是怎樣保證實文被加密的。這裏大概有四個組成部分。
第一個組成部分叫作密鑰交換,也就是ECDHE
,這其實是一個橢圓曲線加密算法的表達,密鑰交換是爲了讓瀏覽器和服務器之間怎樣各自獨立的生成密鑰,數據傳輸時他們會用密鑰去加密數據。加解密是須要使用到對方的密鑰的因此須要進行交換。
在密鑰交換過程當中,須要讓瀏覽器和服務器各自去驗證對方的身份,而驗證身份是須要一個算法的,叫作RSA
。
進行數據加密,解密這種通信的時候,須要用到對稱加密算法AES_128——GCM
,其中第一個部分AES
表達了是怎樣一種算法,128
表示了AES
算法裏支持了3
種加密強度,使用128
位這種一個加密強度。AES
中有不少分組模式GCM
是一種比較新的分組模式,能夠提升多核CPU
狀況下加密和解密的一個性能。
SHA_256
是摘要算法,他用來把不定長度的字符串生成固定長度的更短的摘要。
在對稱加密場景中,兩個想通信的人張三和李四,他們共同持有同一把密鑰,張三能夠把原始明文的文檔,經過這一把密鑰加密生成一個密文文檔,而李四拿到文檔之後呢,他能夠用這把密鑰還原轉換爲原始的明文文檔,而中間的任何人若是沒有持有這把密鑰,即便他知道了對稱加密的算法他也沒有辦法把密文還原成原始文檔。
那麼對稱加密究竟的實現能夠以RC4
對稱加密的序列算法來描述。
使用異或(xor
)操做, 他是一個位操做,好比1
和0
進行異或獲得1
,0
和1
也獲得了1
,那麼相同的1
和1
或者0
和0
進行異或操做都會獲得0
。
在一個場景下1010
是共同持有的密鑰,0110
是明文,張三執行加密的時候就會獲得密文1100
。
1 0 1 0 # 密鑰
xor # 異或操做
0 1 1 0 # 明文
| | # 輸出
1 1 0 0 # 密文
複製代碼
異或有一個對稱的特性,就是把密文與密鑰一樣的作異或操做能夠獲得明文。
1 0 1 0 # 密鑰
xor # 異或操做
1 1 0 0 # 密文
| | # 輸出
0 1 1 0 # 明文
複製代碼
密文能夠用同一把密鑰徹底還原成了明文,因此對稱加密有一個最大的優勢就是他的性能很是的好,他只要遍歷一次就能夠獲得最終的密文,解密的過程也是同樣,而非對稱加密他的性能就會差不少。
非對稱加密根據一個數學原理,他會生成一對密鑰,這一對密鑰中若是稱其中一個叫作公開鑰匙(公鑰
),那麼另外一個就叫作私有鑰匙(私鑰
)。
公鑰和私鑰做用就是同一份命名文檔若是用公鑰加密了那麼只有用對應的私鑰才能把它解密,一樣道理,若是文檔用私鑰加密了用公鑰才能解密。
好比說李四他有一對公鑰和私鑰,那麼他就能夠把他的公鑰發佈給你們,好比張三是其中的一我的,他拿到了李四的公鑰,加密操做是怎麼作的呢?
張三若是想傳遞一份原始文檔給李四,那麼張三就能夠拿着李四的公鑰對原始文檔進行加密,把密文再發送給李四,李四用本身的私鑰才能進行解密,其餘人即便獲得了這份文檔也沒有辦法進行解密。
---------- ---------- ----------
| ------ | 李四的公鑰 | ------ | 李四的私鑰 | ------ |
| ------ | -----------> | -- 密 -- | -----------> | ------ |
| ------ | 加密 | ------ | 解密 | ------ |
---------- ---------- ----------
原始文檔 加密文檔 原始文檔
複製代碼
公鑰和私鑰還有第二種用途,就是身份驗證,好比如今有一段信息李四用它的私鑰進行了加密,而後把密文發給了張三,只要張三若是可使用李四的公鑰解開這份文檔,那麼就證實這段密文確實是由李四發出的。由於只有李四有本身的加密私鑰,若是是王五加密的文檔張三用李四的公鑰是解不開的,只有用李四私鑰加密的使用李四的公鑰才能解開。
這裏其實還有個問題,李四怎麼就知道消息真的是張三發過來的。這裏面涉及到一個新的概念叫公信機構。在多方通訊的過程當中必須有一個公信機構CA,負責頒發證書和把證書過時的。
做爲站點的維護者就是證書的訂閱人,首先必須申請一個證書,申請證書可能須要登記是誰,屬於什麼組織,想作什麼。
登記機構經過CSR
發給CA
,CA
中心經過後會生成一對公鑰和私鑰,公鑰在CA
保存着,公鑰私鑰證書訂閱人拿到以後就會把它部署到本身的web
服務器,當瀏覽器訪問站點的時候,服務器會把公鑰證書發給瀏覽器,瀏覽器須要向CA
驗證證書是否合法和有效的。若是有效就證實沒有被篡改。
因爲CA
會把過時的證書放在CRL
服務器裏,服務器會把全部過時的證書造成一條鏈條因此他的性能很是的差,後來又推出了OCSP
程序能夠就一個證書去查詢是否過時,因此瀏覽器是能夠直接去查詢OCSP
響應程序的,但OCSP
響應程序性能還不是很高。
nginx會有一個OCSP
的開關,當打開開關之後會由nginx
主動的去OCSP
去查詢,大量的客戶端直接從nginx
就能夠獲取到證書是否有效。
證書一共有3
種類型。
第一種叫作域名驗證DV
證書,也就是說證書只會去驗證域名的歸屬是否正確,申請證書的時候只要域名指向的服務器是正在申請證書的服務器,就能夠成功的申請到證書。
第二種證書叫作組織驗證OV
證書,組織驗證就是在申請證書的時候會去驗證填寫的機構,企業名稱是不是正確的,申請OV
證書每每須要幾天的時間,不像DV
證書,基本上實時就能夠獲取到,OV
證書的價格遠遠高於DV
證書,DV
證書不少都是免費的。
比OV
證書作更嚴格的是EV
證書,大部分瀏覽器對EV
證書顯示的很是友好,他會把證書申請時所填寫的機構名稱在瀏覽器的地址欄中顯示出來。
瀏覽器在安全角度對DV
,OV
,,EV
證書他的效果是同樣的。惟一驗證的就是證書鏈。
若是你點擊網站地址欄中的鎖頭標誌,打開證書鏈的時候,能夠發現存在三個級別,目前全部主證書都是由根證書、二級證書、主證書三個證書構成的。
之因此須要三級機構是由於根證書的驗證是很是謹慎的,如windows
,安卓等操做系統每年以上纔會去更新一次根證書庫,因此一個新的根證書CA
機構是很難快速的加入到操做系統或者瀏覽器中的。
大部分瀏覽器他使用的是操做系統的證書庫,只有像firefox
這種瀏覽器會維護本身的根證書庫,因此瀏覽器在驗證證書是否有效時,除了驗證有沒有過時之外,最主要就是在驗證根證書是否是有效的,是否是被跟證書庫所承認的。
nginx
在向瀏覽器發送證書的時候須要發送兩個證書,根證書是被操做系統或者瀏覽器內置的並不須要發送。首先發送站點的主證書,接着會發送二級證書,瀏覽器會自動去認證二級證書的簽發機構,根證書是否是有效的。
瀏覽器和服務器之間通訊時確認對方是信賴的人其實就是驗證給站點頒發根證書的發行者是否是有效的。
TLS的通訊過程主要想完成四個目的。
瀏覽器會向服務器發送一個client hello
消息。有一瀏覽器很是多樣化,並且版本在不停的變動。因此不一樣的瀏覽器所支持的安全套件,加密算法都是不一樣的。這一步主要是告訴服務器,瀏覽器支持哪些加密算法。
nginx
有本身可以支持的加密算法列表,以及他傾向於使用的哪個加密算法套件,nginx
會選擇一套他最喜歡的加密套件發送給客戶端。
若是想複用session
,也就是說nginx
打開了session cache
,但願在一天內斷開連接的客戶端不用再次協商密鑰,能夠直接去複用以前的密鑰。
server hello
信息中主要會發送究竟選擇哪個安全套件。
nginx
會把本身的公鑰證書發送給瀏覽器,公鑰證書中包含證書鏈,瀏覽器能夠找到本身的根證書庫,去驗證證書是不是有效。
服務器會發送server hello done
,若是以前協商的安全套件是橢圓曲線算法,這時會把橢圓曲線的參數發送給客戶端。客戶端須要根據橢圓曲線的公共參數,生成本身的私鑰後再把公鑰發送給服務器。
服務器有了本身的私鑰,會把公鑰發送給客戶端,服務端能夠根據本身的私鑰和客戶端的私鑰,共同生成雙方加密的密鑰。
客戶端根據服務器發來的公鑰和他本身的私鑰也能夠生成一個密鑰。
服務器和客戶端各自生成的密鑰是相同的,是由非對稱加密算法保證的。接着能夠用生成的密鑰進行數據加密,進行通訊。
TLS
通訊主要在作兩件事,第一個是交換密鑰,第二個是加密數據,主要的性能消耗也是這兩點。
nginx在這裏是有性能優化的,主要是他的算法性能,對於小文件,握手是影響QPS
性能的主要指標,對於大文件而言,主要考慮對稱加密算法的性能好比AES
,對稱加密算法雖然性能很好,可是對很是大的一個文件,測吞吐量時仍是AES
的性能比較好的。
當以小文件爲主時主要考驗的是nginx
的非對稱加密的性能,好比說RSA
,當主要處理大文件時主要考驗的是對稱加密算法的性能,好比說AES
。
面對的場景是小文件比較多時重點應該優化橢圓曲線算法的一些密碼強度,看是否是有所下降,當主要面對大的文件處理的時候須要考慮AES
算法是否是能夠替換爲更有效的算法,或者把密碼強度調得更小一些。
首先須要有一個域名好比說yindong.zhiqianduan.com
他是一個http
的網址。
接着開始安裝工具,必須的工具。
若是系統是CentOS
,可使用yum
安裝,優班圖系統可使用wget
工具下載。
yum install pthon2-certbot-nginx
複製代碼
安裝好會提供certbot
命令,當後綴加上--nginx
的時候就開始爲nginx
的conf
自動執行相應的修改。一般他會默認修改/usr/local/
目錄下的nginx
配置。能夠經過--nginx-server-root
指定nginx.conf
所在的路徑。
使用-d
指定須要申請證書的域名,好比說yindong.zhiqianduan.com
。
certbot --nginx --nginx-server-root=/usr/local/nginx/conf/ -d yindong.zhiqianduan.com
複製代碼
首先他會去獲取一個證書,接着會等待驗證,而後把證書部署到nginx.conf
文件中。最後提示兩個選擇,第一不要作任何的重定向,第二作重定向。重定向就是將http
的訪問302
到https
從而禁掉不安全的http
訪問。
選擇以後就可使用https
訪問yindong.zhiqianduan.com
域名了。https://yindong.zhiqianduan.com
他是在在server
指令塊中增長了443
端口,讓後將公鑰證書和私鑰證書部署好,並把一些通用的參數經過include
加入到配置文件中。
由於ssl
中最消耗性能是的握手,因此爲了下降握手增長了sessin_cache
, 設置1m
,能夠爲大約4000
個連接創建服務。也就是說每一個http
連接握手創建第一次之後若是斷開了再次連接,那麼在session_timeout
時間之內是不用進行再次握手的。能夠複用以前的密鑰,session_timeout
設置了1440m
,也就是一天。
ssl_protocols
表示https
支持哪些版本的TLS
協議,ssl_prefer_server_ciphers
表示nginx
開始決定使用哪些協議與瀏覽器進行通訊,他是經過ssl_ciphers
中的安全套件,全部的安全套件以分號分隔,是有順序的,排在前面的會優先被使用。
最後server
中的ssl_dhparam
是表示加密的時候使用怎樣的參數,這些參數會決定網絡安全的加密強度。
在openresty
的站點(openresty.org)下載,在源碼發佈中找到最新版本,複製他的下載連接進行下載。
wget http://openresty.org/download/openresty-1.13.6.2.tar.gz
複製代碼
下載完成之後解壓壓縮包,而後進入到源代碼目錄,能夠發現openresty
目錄和nginx
的源代碼目錄相比少了不少東西,少的這些東西都在bundle
目錄下,build
目錄是編譯之後生成的一些中間目標文件。
在bundle
目錄中有不少模塊,最核心的是nginx
的源代碼,也就說當前的OpenResty
是基於對應的nginx
版本進行的二次開發。
全部nginx
對應版本中沒有的特性都不可能出如今OpenResty
的版本中。
其餘的目錄又分爲兩類,第一類是nginx
的第三方模塊,都是一些C
模塊,一般會以ngx
開頭。第二類模塊是LUA
模塊,是lua
代碼寫就的,他須要使用剛剛那些C
模塊提供的各類功能,在編譯的時候主要是在編譯C
模塊。
./configure --help | more
複製代碼
經過幫助文件能夠看到OpenResty
和nginx
基本沒有太大的不一樣,只不過OpenResty
他集成了不少第三方模塊,好比http_echo
, http_xss
等等,這些在nginx
的官方版本中是沒有的。這些模塊不少是OpenResty
的做者寫的。
最核心的lua_module
核心模塊一般是不能移除來的,移除來以後整個lua
就不能運行了。其餘的配置項和官方的nginx
基本上是同樣的。
./configure
make install
複製代碼
要將lua
代碼添加到OpenResty
當中首先打開OpenResty
的conf
文件,在文件中是能夠直接添加lua
代碼的,可是不能直接的把lua
的語法放在conf
中,由於nginx
的解析器配置語法和lua
代碼是不相同的。
在OpenResty
的nginx_lua_module
中提供了幾條指令,其中有一條叫作content_by_lua
, 是在http
請求處理的內容生成階段用lua
代碼來處理。
增長一個location
,當輸入/lua
的時候,使用lua
代碼進行處理, 爲了使輸出的文本可以以瀏覽器直接顯示文本的方式顯示,添加一個default_type text/html
,在content_by_lua
中加一些最簡單的命令來演示lua是怎麼生效的。
在OpenResty
的lua
模塊中提供了一些API
,好比說ngx.say
會生成http
響應,他是放在http
請求的body
中的,並非放在header
中的。
能夠經過ngx.say
語法將內容添加到body
中的文本中。這裏經過ngx.req.get_headers
把用戶請求時的http
頭取出來,而後找出UA
,把值返回給瀏覽器。
server {
server_name yindong.com;
listen 80;
location /lua {
default_type text/html;
content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])';
}
location / {
alias html/yindong/;
}
}
複製代碼
訪問/lua
就能夠看到效果了。
經過OpenResty
的nginx_lua_http
模塊能夠用它提供的API
完成不少功能,能夠用lua
語言自己的一些工具庫,把lua
語言添加進來參與響應的過程。
能夠用lua
語言以及相應的提供的工具庫直接訪問redis
,mysql
或者tomcat
等服務,而後把不一樣的響應經過程序邏輯組合成相應的內容返回給用戶。