從Nginx談開去

Nginx是使用異步事件驅動的網頁服務器,也可用做反向代理,負載均衡器和http緩存。相比Apache具備佔用內存少、穩定性高的優勢。php

Nginx的做用

在搭建一個web服務中,nginx所處的位置是在server的最前端,其接受http鏈接、進行gzip壓縮、管理tsl、管理緩存。基本上全部與業務無關而與http服務自己有關的工做都在Nginx身上。前端

沒有接觸過php等語言,而是一開始就從nodejs入手接觸服務端開發的同窗可能並不清楚nginx的定位,由於nodejs自己自帶http模塊,並不必定須要nginx配合。而以php舉例則更爲明白,每一個php文件都是一個接口的入口,其中書寫業務邏輯、鏈接數據庫等,而什麼樣的路徑指派給哪一個php文件是nginx作的工做。node

可是即便在使用nodejs或者tomcat等工具時,仍是會有不少企業級應用會在最前端配上nginx,用來作負載均衡、緩存、反向代理靜態文件等工做。linux

nginx與nodejs性能對比

上圖是stackoverflow上的一個插圖,經過ab工具測試靜態文件讀取的性能。即便配置了nodejs cluster,仍是抵不過nginx。nginx

配置Nginx

nginx因爲使用了epoll模型(linux 下的一個I/O多路複用模型),要求linux內核版本必須在2.6以上。其默認配置文件在/usr/local/nginx/conf中。 web

nginx配置文件
上圖是一個nginx配置文件,其主要結構以下:

baseconfig:進程數、日誌位置等基本信息
	events:採用epoll事件模型,若是linux版本低會下降爲select模型
	http:設置超時、壓縮等信息,引入各類模塊
		upstream:設置反向代理
		server:一個服務,對應一個端口
		server
			location:一個url,指派到不一樣的cgi或者反向代理
			location
複製代碼

負載均衡與反向代理

  • 負載均衡:公司用於多個服務器組成的集羣,當一個請求到來時,將其指派到某個具體的服務器,以求達到各個服務器資源佔用均衡。
  • 反向代理:與正向代理相對,正向代理是在client一端通過一個代理再到server,而反向代理是請求到達server一端,這個直接接收請求的機器自己是一個代理,轉發給其餘server處理,其細節對client不可知。負載均衡就是利用了反向代理。

在nginx配置中,負載均衡是經過upstream模塊,反向代理是經過proxy_pass實現。redis

http {
    upstream firstdemo {
        server 39.106.145.33;
        server 47.93.6.93;
    }
    server {
        listen 8080;
        location / {
            proxy_pass http://firstdemo;
        }
    }
}
複製代碼

如此一來,全部從8080端口的根目錄下的請求都被均衡的轉發到兩個具體的server上。可是這裏的均衡並不是等分,nginx會考慮到連接數量、資源使用等。數據庫

可是負載均衡存在一個問題,就是登錄態的保存。正常狀況下登錄態是保存在每一個server內部,但每一個用戶請求均可能被髮送到任意一個server,剛纔server A上進行了登錄結果到了server B上又沒了權限。對於這個問題,大體有兩類解決方案:一是經過各類hash將同一個用戶的請求發送到同一個server上,好比經過用戶ip判斷;另外一種是將登錄態從server中提出來,保存在公共的如redis這種內存數據庫中。apache

對於nginx,在upstream中設置ip_hash就能夠了。編程

Nginx的優點

nginx與apache等相比,最主要的特色有三個:

  1. 輕量化
  2. 模塊化
  3. 異步驅動

前兩個暫且不談,異步驅動指什麼呢?

在老版本(pre-worker模型)的apache中,每個新的鏈接都要對應一個進程,而新建一個進程的消耗顯然很大。nginx使用epoll(BSD下則是類似的kqueue)模型,一個進程對應多個鏈接。

IO多路複用

IO多路複用指經過一種機制,能夠監視多個描述符,一旦某個描述符就緒(通常是讀就緒或者寫就緒),可以通知程序進行相應的讀寫操做。 linux下有三種IO多路複用模型:select、poll、epoll。

  • select :它僅僅知道了,有I/O事件發生了,卻並不知道是哪幾個流(可能有一個,多個,甚至所有),咱們只能無差異輪詢全部流,找出能讀出數據,或者寫入數據的流,對他們進行操做。因此select具備O(n)的無差異輪詢複雜度,同時處理的流越多,無差異輪詢時間就越長。單個進程最多監聽1024個描述符。
  • poll: 與select相似,可是它沒有最大鏈接數的限制,緣由是它是基於鏈表來存儲的。
  • epoll:epoll會把哪一個流發生了怎樣的I/O事件通知咱們。因此咱們說epoll其實是事件驅動。epoll內核中實現是根據每一個fd上的callback函數來實現的,只有活躍的socket纔會主動調用callback。

簡單點理解,select與poll都是輪詢socket獲取狀態,而epoll是基於回調,性能天然要好一些。

FastCGI

通用網關接口(CGI)可讓一個客戶端從瀏覽器向服務器上的程序請求數據,CGI描述了服務器和請求處理程序之間傳輸數據的一種標準。

CGI的工做方式,從Web服務器的角度看,是在特定的位置定義了能夠運行CGI程序。當收到一個匹配URL的請求,相應的程序就會被調用,並將客戶端發送的數據做爲輸入。程序的輸出會由Web服務器收集,並加上合適的檔頭,再發送回客戶端。

CGI程序運行在獨立的進程中,並對每一個Web請求建立一個進程,這種方法很是容易實現,但效率不好,難以擴展。面對大量請求,進程的大量建立和消亡使操做系統性能大大降低。此外,因爲地址空間沒法共享,也限制了資源重用。

CGI的工做方式大體能夠描述爲:

  • Step0 普通用戶經過瀏覽器(或者是表單提交、或者是直接訪問URL)發送請求給Web服務器
  • Step1 Web服務器接收到請求後,啓動CGI程序,經過環境變量、標準輸入等傳遞數據,將請求轉交給對應的CGI進程
  • Step2 CGI進程啓動解析器,或者訪問數據庫、或者完成相關計算、或者與其它第三方進行交互
  • Step3 在CGI程序處理完成後,經過標準輸出將處理結果返回給Web服務器
  • Step4 Web服務器收到結果後,構建Response返回給客戶端,並殺死CGI進程

與CGI「fork-and-execute」的工做模式不一樣,FastCGI像是一個常駐型的CGI,它使用持續的進程來處理一連串的請求。這些進程由FastCGI進程管理器管理,而不是Web服務器。當進來一個請求時,Web服務器把環境變量和這個頁面請求經過一個unix domain socket(好比FastCGI進程與Web服務器都位於本地)或者一個TCP鏈接(FastCGI進程部署在遠端)傳遞給FastCGI進程。

FastCGI實際上就是一個master/worker模型。

FastCGI的工做方式大體能夠描述爲:

  • Step1 Web服務器啓動時,初始化FastCGI執行環境,例如apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi
  • Step2 FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程並等待來自Web服務器的鏈接
  • Step3 當客戶端請求到達Web服務器時,Web服務器將請求經過socket方式轉發到FastCGI主進程,主進程選擇並鏈接到一個CGI解釋器。Web服務器將CGI環境變量和標準輸入發送到FastCGI子進程
  • Step4 FastCGI子進程完成處理後,將標準輸出和錯誤信息經過同一socket返回給Web服務器,並關閉鏈接
  • Step5 FastCGI子進程接着等待下一個新的鏈接

master/worker模型

Nodejs cluster與pm2

nodejs是單線程的,爲了應對高併發的狀況,其經過包裝child_process引入了cluster模塊,其本質上就是master/worker模型,一個主master進程fork若干個worker進程,以充分利用多核cpu。在高版本的nodejs中已經引入了多線程,有興趣的同窗能夠看看。

通常nodejs服務並不經過cluster實現集羣,而是藉助pm2等相似工具,pm2能夠啓動多個實例,由pm2來進行負載均衡,進程守護、平滑重啓等工做。

localhost等本地地址

以上是在網絡編程中經常使用的表示本機地址的三種方式,其區別到底在哪裏?

localhost是127.0.0.1的一個綁定,在linux中其默認地被寫入系統的hosts文件,與127.0.0.1沒什麼區別。固然你能夠手動修改hosts文件。

127.0.0.1是一個虛擬地址,通過本地的lo迴環,走的是這個虛擬網卡,不須要聯網,沒有真實地進行網絡傳輸。

0.0.0.0是本地全部網卡地址的統一,若是本地有多張網卡好比無線網卡和有線網卡,他們各自都會有本身的ip地址,0.0.0.0是他們的統一。

各個網卡的IP,在0.0.0.0中已經說到了。

壓力測試

對nodejs進行接口壓力測試可使用autoconn。

autoconn使用
主要信息分爲三類:延遲、處理請求數、處理字節數。
相關文章
相關標籤/搜索