一文帶你瞭解Nginx基礎知識 | 建議收藏

1. 概述

不少人可能或多或少了解過nginx,即便沒有使用過nginx,可是可能用Apache搭建過簡單的web服務器,用tomcat寫過一些簡單的動態頁面,其實這些功能nginx均可以實現。javascript

nginx最重要的三個使用場景我的認爲是靜態資源服務反向代理服務api服務css

web請求走進服務之後會先通過nginx再到應用服務,而後再去訪問redis或者mysql提供基本的數據功能。html

這就有個問題,應用服務由於要求開發效率高,因此他的運行效率是很低的,他的qbstps併發都是受限的,因此就須要把不少的應用服務組成集羣,向用戶提供高可用性。java

不少服務構成集羣的時候,須要nginx具備反向代理的功能,能夠把動態請求傳導給對應的應用服務。服務集羣必定會帶來兩個需求,動態的擴容和容災。mysql

反向代理必須具有負載均衡的功能,其次在鏈路中,nginx是處在企業內網的邊緣節點,隨着網絡鏈路的增加,用戶體驗到的時延會增長。linux

把一些全部用戶看起來不變的,或者在一段時間內看起來不變的動態內容緩存在nginx部分,由nginx直接向用戶提供訪問,用戶的時延就會減小不少。nginx

反向代理衍生出另外的功能叫緩存,他可以加速訪問,而不少時候在訪問像cssjs文件又或者一些小圖片是沒有必要由應用服務來訪問的,他只須要直接由nginx提供訪問就能夠了這就是nginx的靜態資源功能。web

應用服務它自己的性能有很大的問題,數據庫服務要比應用服務好的多,緣由是數據庫他的業務場景比較簡單,併發性能和tps都要遠高於應用服務。由nginx直接去訪問數據庫或者redis也是不錯的選擇。正則表達式

還能夠利用nginx強大的併發性能,實現如web防火牆的一些業務功能,這就要求nginx服務有很是強大的業務處理功能,openRestynginx集成了一些工具庫來實現此功能。redis

2. 歷史背景

全球化和物聯網的快速發展,致使接入互聯網中的人與設備的數量都在快速的上升,數據的快速爆炸,對硬件性能提出很高的要求。

摩爾定律代表以前服務跑在1GHZCPU上的服務更新到2GHZCPU時服務會有兩倍的性能提高。

可是到了本世紀初,摩爾定律在單顆CPU的頻率上已經失效了,CPU開始向着多核方向發展,當服務器如今是跑在8CPU上時,一年半之後換到了16核的CPU,服務的性能一般是不會有一倍的提高的。

這些性能主要損耗在操做系統和大量的軟件沒有作好服務於多核架構的準備,好比說像Apache是低效的,由於他的架構模型裏一個進程同一時間,只會處理一個鏈接,一個請求。只有在這個請求處理完之後纔會去處理下一個請求。

它實際上在使用操做系統的進程間切換的特性,由於操做系統微觀上是有限的CPU,可是操做系統被設計爲同時服務於數百甚至上千的進程。

Apache一個進程只能服務於一個鏈接,這種模式會致使當Apache須要面對幾十萬,幾百萬鏈接的時候,他沒有辦法去開幾百萬的進程,而進程間切換的代價成本又過高啦。

當併發的鏈接數越多,這種無謂的進程間切換引起的性能消耗又會越大。

nginx是專門爲了這種應用場景而生的,能夠處理數百萬甚至上千萬的併發鏈接,nginx目前在web市場份額中排行第二,在過去幾年他增加極度迅速,在不久的未來nginxweb端的應用將遠遠超過其餘服務器。

3. nginx的優勢

大部分的程序和服務器隨着併發鏈接數的上升他的RPS數會急劇的降低,這裏的原理就像以前所說過的,他的設計架構是有問題的。

nginx的第一個優勢就是高併發和高性能同時具有的,每每高併發只須要對每個鏈接所使用的內存儘可能的少就能夠達到。

而具備高併發的同時達到高性能,每每須要很是好的設計,那nginx能夠達到什麼樣的標準呢?

好比說如今主流的一些服務器3264G的內存能夠輕鬆達到數千萬的併發連接,若是是處理一些簡單的靜態資源請求,能夠達到一百萬的RPS這種級別。

其次nginx的可擴展性很是好,主要在於他的模塊化設計很是的穩定,並且nginx的第三方模塊的生態圈很是的豐富。甚至於有像TNG,openRestry這種第三方插件。豐富的生態圈爲nginx豐富的功能提供了保證。

第三個優勢是它的高可靠性,所謂的高可靠性是指nginx能夠在服務器上持續不間斷的運行數年,而不少web服務器每每運行幾周或者幾個月就須要作一次重啓。

對於nginx這種高併發高性能的反向代理服務器而言,他每每運行在企業內網的邊緣節點上,若是企業想提供4個95個9,甚至更高的高可用性時,對於nginx持續運行可以down機的時間一年可能只能以秒來計。因此在這種角色中,nginx的高可靠性給提供了很是好的保證。

第四個優勢熱部署,是指能夠在不中止服務的狀況下升級nginx,這對於nginx來講很是的重要,由於在nginx可能跑了數百萬的併發鏈接。

若是是普通的服務可能只需kill掉進程再重啓的方式就能夠處理好,可是對於nginx而言,由於killnginx進程,會致使操做系統爲全部的已經創建鏈接的客戶端發送一個tcp中的reset報文。而不少客戶端是沒有辦法很好的處理請求的。

在大併發場景下,一些偶然事件就會致使必然的惡性結果,因此熱部署是很是有必要的。

第五個優勢是BSD許可證,BSD Listens是指nginx不只是開源的免費的,並且能夠在有定製須要的場景下,去修改nginx源代碼,再運行在商業場景下,這是合法的。

以上的優勢是nginx最核心的特性。

4. 主要組成部分

首先是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去定位根本性的問題。

5. 版本規則

nginx每發佈一個版本的時候會有三個特性,一個是feature,就是他新增了哪些功能,bugfix表示他修復了哪些bugchange表示作了哪些重構。

每個版本都有mainline主幹版本和stable穩定版本。

nginx的官網點擊右下角的download,就能夠看到版本號列表,單數版本表示主幹版本,會新增不少功能,但不必定穩定。雙數版本是穩定版本。

CHANGES文件中能夠看到每個版本含有的新增功能,修復的bug,以及作了哪些小的重構。

大概在2009年之後nginxbugfix數量已經大幅度減小,因此nginx相對已經很穩定了。

nginx的開發時間是在2002年,可是他在2004104日推出了第一個版本,在2005年曾經作過一次大的重構。

由於nginx優秀的設計,使得他的生態圈極爲豐富,模塊的設計,架構的設計都沒有再作過大的變更。

2009nginx開始支持windows操做系統,20111.0正式版本發佈,同時nginx的商業公司nginx Plus也成立了,在2015nginx發佈了幾個重要的功能。

其中提供stream四層反向代理,他在功能上徹底能夠替代傳統使用的LVS, 而且具備更豐富的功能。

6. 版本選擇

免費開源: nginx.org

商業版本: nginx.com

開源免費的nginx2002年開始開發,到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是一個很好的選擇。

7. 編譯配置

安裝nginx有兩種方法,除了編譯外,還能夠直接用操做系統上自帶的一些工具,好比說yumapt-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
複製代碼

其中會有featurebugfixchange三種特性在裏面。

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文件裏則是Linuxnginx的幫助文件,裏面標識了最基本的nginx幫助和配置。

src目錄是nginx的核心源碼。

8. 開始編譯

編譯前能夠先看一下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.logerror.loglog文件夾下。

能夠看到在conf目錄下全部文件就是在源代碼中conf目錄copy過來的,其中的內容也是徹底相同的。

9. 配置語法

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中也放置了listenlimit_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模塊,好比說像streammime是沒有辦法去解析指令的。

upstream表示上游服務,當nginx須要與Tomcat等企業內網的其它服務交互的時候呢,能夠定義一個upstream

server對應的一個或一組域名,locationurl表達式。

10. 重載,熱部署,日誌切割

須要幫助的時候能夠用-? 或者 -h獲取幫助信息。

nginx -?
nginx -h
複製代碼

默認狀況下編譯出來的nginx會尋找執行configure命令時指定的配置文件。在命令行中能夠指定另外一個配置文件用-c 路徑

還能指定一些配置用-g,指令就是在nginxconfigure目錄裏的指令。

nginx操做運行中的進程通常是經過發送信號,能夠經過linuxkill命令也能夠用nginx -s子命令,子命令後能夠用stopquitreloadreopen

nginx -s stop # 中止nginx服務
nginx -s quit # 優雅的中止nginx服務
nginx -s reload # 重載配置文件
nginx -s reopen # 從新開始記錄日誌文件。
複製代碼

-t能夠測試一下配置文件是否合法問題。

-V是在編譯時用configure腳本執行所加的全部參數。

1. 重載配置文件

修改nginx配置文件中的一些值,好比說conf/nginx.conf文件中,打開tcp_nopush

當修改完配置文件之後,能夠直接執行nginx -s reload命令nginx是在不中止對客戶服務的狀況下使用了tcp_nopush新的配置項,很是的簡單。

2. 熱部署

nginx在運行的狀況下想更換最新版本的nginx,根據以前所說的,nginx編譯方法下載一個新的nginx

把最新版本的nginx編譯後的可執行文件nginxcopy到目錄中替換掉正在運行的nginx文件。copy完成須要給正在運行的nginxmaster進程發送一個信號,告訴他開始進行熱部署作一次版本升級,給nginxmaster進程發送一個信號,USR2信號。

kill -USR2 進程號(13195)
複製代碼

nginx會新啓一個master進程使用的正式剛剛複製過來的最新的nginx二進制文件。

舊的worker也在運行,新的master會生成新的worker,他們會平滑的把全部的請求過渡到新的進程中。

新的請求新的鏈接會進入新的nginx進程中,這時須要向老的nginx進程發送一個信號叫作WINCH,告訴他優雅的關閉全部進程。

kill -WINCH 13195
複製代碼

這時老的worker進程會優雅的退出,可是老的master進程還在,只是是沒有worker進程了。

這說明全部的請求已經所有切換到新的nginx中了,若是須要把新版本退回到老版本,能夠向老的進程發送reload命令,讓他從新把worker進程拉起來。再把新版本關掉。因此保留master是爲了容許作版本回退。

3. 日誌切割

好比說當前的日誌已經很大了。須要把之前的日誌備份到另一個文件中,可是nginx仍是正常運行的。

這就要經過reopen命令來作,首先須要把當前正在使用的日誌copy一份放在另外的位置.

mv access_log bak.log
複製代碼

接着執行命令reopen

nginx -s reopen
複製代碼

就從新生成了一個access.log, 本來的log備份成了bak.log,就實現了日誌切割。

固然這種方法會很是很差用,實際上每每是每一天,或者是每一週執行一第二天至切割,能夠先寫成一個bash腳本。

bash腳本中首先把文件複製一下,再執行-s reopen命令,最後把腳本放在crontab中。

11. 靜態資源Web服務器

編輯conf/nginx.conf文件找到server代碼塊中,listen配置監聽端8080端口,而後須要配置一個location,使用/讓全部的請求都訪問到www文件夾。

這裏須要指定url的後綴與文件的後綴一一對應,有兩種用法,rootaliasroot是系統的跟目錄,因此一般使用aliasaliasnginx的安裝目錄。

server {
    listen 8080;
    ...
    location / {
        alias www/;
        ...
    }
    ...
}
複製代碼

作完配置以後啓動nginx在瀏覽器中訪問localhost:8080就能夠了。

nginx -s reload
複製代碼

1. 開啓gzip

作完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服務傳輸效率會高不少。

2. 打開目錄結構

nginx給提供了一個官方模塊叫作autoindex,他能夠提供當訪問以/結尾的url時,顯示目錄的結構。使用方法也特別簡單,就是autoindex on加入一個指令就能夠了。

location / {
    autoindex on;
}
複製代碼

他會把所訪問的文件夾內全部文件列出來,當打開一個目錄時,能夠繼續顯示目錄中的文件,這是一個很好的靜態資源幫助功能。

3. 網速限制

好比公網帶寬是有限的,當有不少併發用戶使用帶寬時,他們會造成一個爭搶關係,可讓用戶訪問某些大文件的時候來限制他的速度,節省足夠的帶寬給用戶訪問一些必要的小文件。

就可使用set命令,配合一些內置的變量實現這種功能,好比說加上set $limit_rate 1k,限制nginx向客戶瀏覽器發送響應的一個速度。意思是每秒傳輸多少數據到瀏覽器中。

location / {
    set $limit_rate 1k;
}
複製代碼

4. 日誌

首先須要設置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中查看每一條都是設置的格式。

12. 反向代理服務

因爲上游服務要處理很是複雜的業務邏輯並且強調開發效率,因此他的性能並不怎麼樣,使用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找到。

1. 緩存

這裏有個很重要的特性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;
}
複製代碼

加完這些參數之後,能夠嘗試停掉上游服務,而後訪問站點,能夠發現站點仍然是能夠訪問的。就是由於被緩存了。

13. 監控access日誌

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.log統計信息上的變遷,對分析網站的運營狀況很是有幫助,能夠看到每一個時間點,每一週每一天,甚至不一樣的國家地區使用不一樣瀏覽器和操做系統的人使用站點的一個比例和分佈。

14. SSL安全協議

SSL的全稱是Secure Sockets Layer,如今不少時候使用的是TLS也就是Transport Layer Security。能夠將TLS看作是SSL的升級版。

SSL是網景公司在1995年推出的,後來由於微軟把本身的IE瀏覽器捆綁windows一塊兒賣出致使網景遇到很大的發展困境,網景把SSL協議交給IETF組織。

1999年,應微軟的要求IETFSSL改名爲TLS1.0,在06082018TLS分別發佈了1.11.21.3協議。

那麼TLS協議到底是怎樣保證http的明文消息被加密的呢?

ISO/OSI七層模型中,應用層是http協議,在應用層之下,表示層也就是TLS所發揮做用的這一層,經過握手交換密鑰告警對稱加密的方式使http層沒有感知的狀況下作到了數據的安全加密。

當抓包或者觀察服務端配置時,能夠看到安全密碼的配置,安全密碼的配置決定了TLS協議是怎樣保證實文被加密的。這裏大概有四個組成部分。

第一個組成部分叫作密鑰交換,也就是ECDHE,這其實是一個橢圓曲線加密算法的表達,密鑰交換是爲了讓瀏覽器和服務器之間怎樣各自獨立的生成密鑰,數據傳輸時他們會用密鑰去加密數據。加解密是須要使用到對方的密鑰的因此須要進行交換。

在密鑰交換過程當中,須要讓瀏覽器和服務器各自去驗證對方的身份,而驗證身份是須要一個算法的,叫作RSA

進行數據加密,解密這種通信的時候,須要用到對稱加密算法AES_128——GCM,其中第一個部分AES表達了是怎樣一種算法,128表示了AES算法裏支持了3種加密強度,使用128位這種一個加密強度。AES中有不少分組模式GCM是一種比較新的分組模式,能夠提升多核CPU狀況下加密和解密的一個性能。

SHA_256是摘要算法,他用來把不定長度的字符串生成固定長度的更短的摘要。

15. 對稱加密、非對稱加密

在對稱加密場景中,兩個想通信的人張三和李四,他們共同持有同一把密鑰,張三能夠把原始明文的文檔,經過這一把密鑰加密生成一個密文文檔,而李四拿到文檔之後呢,他能夠用這把密鑰還原轉換爲原始的明文文檔,而中間的任何人若是沒有持有這把密鑰,即便他知道了對稱加密的算法他也沒有辦法把密文還原成原始文檔。

那麼對稱加密究竟的實現能夠以RC4對稱加密的序列算法來描述。

使用異或(xor)操做, 他是一個位操做,好比10進行異或獲得101也獲得了1,那麼相同的11或者00進行異或操做都會獲得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 # 明文
複製代碼

密文能夠用同一把密鑰徹底還原成了明文,因此對稱加密有一個最大的優勢就是他的性能很是的好,他只要遍歷一次就能夠獲得最終的密文,解密的過程也是同樣,而非對稱加密他的性能就會差不少。

非對稱加密根據一個數學原理,他會生成一對密鑰,這一對密鑰中若是稱其中一個叫作公開鑰匙(公鑰),那麼另外一個就叫作私有鑰匙(私鑰)。

公鑰和私鑰做用就是同一份命名文檔若是用公鑰加密了那麼只有用對應的私鑰才能把它解密,一樣道理,若是文檔用私鑰加密了用公鑰才能解密。

好比說李四他有一對公鑰和私鑰,那麼他就能夠把他的公鑰發佈給你們,好比張三是其中的一我的,他拿到了李四的公鑰,加密操做是怎麼作的呢?

張三若是想傳遞一份原始文檔給李四,那麼張三就能夠拿着李四的公鑰對原始文檔進行加密,把密文再發送給李四,李四用本身的私鑰才能進行解密,其餘人即便獲得了這份文檔也沒有辦法進行解密。

----------                ----------                  ----------  
|  ------  |  李四的公鑰    |  ------  |   李四的私鑰     |  ------ | 
|  ------  | -----------> |  -- 密 -- |  ----------->  |  ------ |
|  ------  |    加密       |  ------  |     解密        |  ------ |
 ----------                ----------                  ----------
   原始文檔                    加密文檔                     原始文檔 
複製代碼

公鑰和私鑰還有第二種用途,就是身份驗證,好比如今有一段信息李四用它的私鑰進行了加密,而後把密文發給了張三,只要張三若是可使用李四的公鑰解開這份文檔,那麼就證實這段密文確實是由李四發出的。由於只有李四有本身的加密私鑰,若是是王五加密的文檔張三用李四的公鑰是解不開的,只有用李四私鑰加密的使用李四的公鑰才能解開。

16. SSL證書的公信力

這裏其實還有個問題,李四怎麼就知道消息真的是張三發過來的。這裏面涉及到一個新的概念叫公信機構。在多方通訊的過程當中必須有一個公信機構CA,負責頒發證書和把證書過時的。

做爲站點的維護者就是證書的訂閱人,首先必須申請一個證書,申請證書可能須要登記是誰,屬於什麼組織,想作什麼。

登記機構經過CSR發給CACA中心經過後會生成一對公鑰和私鑰,公鑰在CA保存着,公鑰私鑰證書訂閱人拿到以後就會把它部署到本身的web服務器,當瀏覽器訪問站點的時候,服務器會把公鑰證書發給瀏覽器,瀏覽器須要向CA驗證證書是否合法和有效的。若是有效就證實沒有被篡改。

因爲CA會把過時的證書放在CRL服務器裏,服務器會把全部過時的證書造成一條鏈條因此他的性能很是的差,後來又推出了OCSP程序能夠就一個證書去查詢是否過時,因此瀏覽器是能夠直接去查詢OCSP響應程序的,但OCSP響應程序性能還不是很高。

nginx會有一個OCSP的開關,當打開開關之後會由nginx主動的去OCSP去查詢,大量的客戶端直接從nginx就能夠獲取到證書是否有效。

證書一共有3種類型。

第一種叫作域名驗證DV證書,也就是說證書只會去驗證域名的歸屬是否正確,申請證書的時候只要域名指向的服務器是正在申請證書的服務器,就能夠成功的申請到證書。

第二種證書叫作組織驗證OV證書,組織驗證就是在申請證書的時候會去驗證填寫的機構,企業名稱是不是正確的,申請OV證書每每須要幾天的時間,不像DV證書,基本上實時就能夠獲取到,OV證書的價格遠遠高於DV證書,DV證書不少都是免費的。

OV證書作更嚴格的是EV證書,大部分瀏覽器對EV證書顯示的很是友好,他會把證書申請時所填寫的機構名稱在瀏覽器的地址欄中顯示出來。

瀏覽器在安全角度對DVOV,,EV證書他的效果是同樣的。惟一驗證的就是證書鏈。

若是你點擊網站地址欄中的鎖頭標誌,打開證書鏈的時候,能夠發現存在三個級別,目前全部主證書都是由根證書、二級證書、主證書三個證書構成的。

之因此須要三級機構是由於根證書的驗證是很是謹慎的,如windows,安卓等操做系統每年以上纔會去更新一次根證書庫,因此一個新的根證書CA機構是很難快速的加入到操做系統或者瀏覽器中的。

大部分瀏覽器他使用的是操做系統的證書庫,只有像firefox這種瀏覽器會維護本身的根證書庫,因此瀏覽器在驗證證書是否有效時,除了驗證有沒有過時之外,最主要就是在驗證根證書是否是有效的,是否是被跟證書庫所承認的。

nginx在向瀏覽器發送證書的時候須要發送兩個證書,根證書是被操做系統或者瀏覽器內置的並不須要發送。首先發送站點的主證書,接着會發送二級證書,瀏覽器會自動去認證二級證書的簽發機構,根證書是否是有效的。

瀏覽器和服務器之間通訊時確認對方是信賴的人其實就是驗證給站點頒發根證書的發行者是否是有效的。

17. SSL協議握手時nginx的性能瓶頸

TLS的通訊過程主要想完成四個目的。

1. 驗證對方身份

瀏覽器會向服務器發送一個client hello消息。有一瀏覽器很是多樣化,並且版本在不停的變動。因此不一樣的瀏覽器所支持的安全套件,加密算法都是不一樣的。這一步主要是告訴服務器,瀏覽器支持哪些加密算法。

2. 對安全套件達成共識

nginx有本身可以支持的加密算法列表,以及他傾向於使用的哪個加密算法套件,nginx會選擇一套他最喜歡的加密套件發送給客戶端。

若是想複用session,也就是說nginx打開了session cache,但願在一天內斷開連接的客戶端不用再次協商密鑰,能夠直接去複用以前的密鑰。

server hello信息中主要會發送究竟選擇哪個安全套件。

3. 傳遞並生成密鑰

nginx會把本身的公鑰證書發送給瀏覽器,公鑰證書中包含證書鏈,瀏覽器能夠找到本身的根證書庫,去驗證證書是不是有效。

4. 對數據進行加密通信

服務器會發送server hello done,若是以前協商的安全套件是橢圓曲線算法,這時會把橢圓曲線的參數發送給客戶端。客戶端須要根據橢圓曲線的公共參數,生成本身的私鑰後再把公鑰發送給服務器。

服務器有了本身的私鑰,會把公鑰發送給客戶端,服務端能夠根據本身的私鑰和客戶端的私鑰,共同生成雙方加密的密鑰。

客戶端根據服務器發來的公鑰和他本身的私鑰也能夠生成一個密鑰。

服務器和客戶端各自生成的密鑰是相同的,是由非對稱加密算法保證的。接着能夠用生成的密鑰進行數據加密,進行通訊。

TLS通訊主要在作兩件事,第一個是交換密鑰,第二個是加密數據,主要的性能消耗也是這兩點。

nginx在這裏是有性能優化的,主要是他的算法性能,對於小文件,握手是影響QPS性能的主要指標,對於大文件而言,主要考慮對稱加密算法的性能好比AES,對稱加密算法雖然性能很好,可是對很是大的一個文件,測吞吐量時仍是AES的性能比較好的。

當以小文件爲主時主要考驗的是nginx的非對稱加密的性能,好比說RSA,當主要處理大文件時主要考驗的是對稱加密算法的性能,好比說AES

面對的場景是小文件比較多時重點應該優化橢圓曲線算法的一些密碼強度,看是否是有所下降,當主要面對大的文件處理的時候須要考慮AES算法是否是能夠替換爲更有效的算法,或者把密碼強度調得更小一些。

18. 用免費SSL證書實現一個HTTPS站點

首先須要有一個域名好比說yindong.zhiqianduan.com他是一個http的網址。

接着開始安裝工具,必須的工具。

若是系統是CentOS,可使用yum安裝,優班圖系統可使用wget工具下載。

yum install pthon2-certbot-nginx
複製代碼

安裝好會提供certbot命令,當後綴加上--nginx的時候就開始爲nginxconf自動執行相應的修改。一般他會默認修改/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的訪問302https從而禁掉不安全的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是表示加密的時候使用怎樣的參數,這些參數會決定網絡安全的加密強度。

19. 基於OpenResty用Lua語言實現簡單服務

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
複製代碼

經過幫助文件能夠看到OpenRestynginx基本沒有太大的不一樣,只不過OpenResty他集成了不少第三方模塊,好比http_echo, http_xss等等,這些在nginx的官方版本中是沒有的。這些模塊不少是OpenResty的做者寫的。

最核心的lua_module核心模塊一般是不能移除來的,移除來以後整個lua就不能運行了。其餘的配置項和官方的nginx基本上是同樣的。

./configure

make install
複製代碼

要將lua代碼添加到OpenResty當中首先打開OpenRestyconf文件,在文件中是能夠直接添加lua代碼的,可是不能直接的把lua的語法放在conf中,由於nginx的解析器配置語法和lua代碼是不相同的。

OpenRestynginx_lua_module中提供了幾條指令,其中有一條叫作content_by_lua, 是在http請求處理的內容生成階段用lua代碼來處理。

增長一個location,當輸入/lua的時候,使用lua代碼進行處理, 爲了使輸出的文本可以以瀏覽器直接顯示文本的方式顯示,添加一個default_type text/html,在content_by_lua中加一些最簡單的命令來演示lua是怎麼生效的。

OpenRestylua模塊中提供了一些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就能夠看到效果了。

經過OpenRestynginx_lua_http模塊能夠用它提供的API完成不少功能,能夠用lua語言自己的一些工具庫,把lua語言添加進來參與響應的過程。

能夠用lua語言以及相應的提供的工具庫直接訪問redismysql或者tomcat等服務,而後把不一樣的響應經過程序邏輯組合成相應的內容返回給用戶。

相關文章
相關標籤/搜索