Nginx + IIS 負載均衡實現過程詳解

焰尾迭發表於2015-09-22

最近在研究分散式系統架構方面的知識,包括負載均衡,資料庫讀寫分離,分散式快取redis等。本篇先從負載均衡服務架構入手,關於負載均衡百度百科的定義如下:負載均衡,英文名稱為Load Balance,其意思就是分攤到多個操作單元上進行執行,例如Web伺服器、FTP伺服器、企業關鍵應用伺服器和其它關鍵任務伺服器等,從而共同完成工作任務。

我的解釋:一項任務交由一個開發人員處理總會有上限處理能力,這時可以考慮增加開發人員來共同處理這項任務,多人處理同一項任務時就會涉及到排程問題,即任務分配,這和多執行緒理念是一致的。nginx在這裡的角色相當於任務分配者。

Nginx安裝

Nginx是一款輕量級的Web 伺服器/反向代理伺服器及電子郵件(IMAP/POP3)代理伺服器,並在一個BSD-like 協議下發行。由俄羅斯的程式設計師Igor Sysoev所開發,供俄國大型的入口網站及搜尋引擎Rambler(俄文:Рамблер)使用。其特點是佔有記憶體少,併發能力強,事實上nginx的併發能力確實在同型別的網頁伺服器中表現較好,中國大陸使用nginx網站使用者有:百度、新浪、網易、騰訊等。

最新版本的nginx版本為1.9.3,我這下載的是window版本的,一般實際場景都是安裝在linux系統下的,由於linux系統目前正在摸索中這裡就不介紹。官方下載地址:nginx-1.9.3.zip 部落格園下載地址:nginx-1.9.3.zip 。下載完成之後解壓執行nginx.exe就啟動了nginx了,啟動後會在程式裡面看到nginx。

要實現負載均衡需要修改conf/nginx.conf的配置資訊,修改配置資訊之後重新啟動nginx服務,可以通過nginx -s reload指令實現。這裡我們使用 Ants 提供的一個批處理來操作。

將nginx.bat檔案放到nginx.exe相同資料夾下,直接執行就行了。文章結尾會提供本文用到的所有檔案。

站點搭建及配置

1.搭建兩個iis站點

站點下只有一個簡單的index頁面,用來輸出當前伺服器資訊。由於我沒有兩臺機器,所以將兩個站點都部署到本機了,分別繫結了8082和9000兩個埠。

protected void Page_Load(object sender, EventArgs e)
        {
            Label0.Text = "請求開始時間:"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            Label1.Text = "伺服器名稱:" + Server.MachineName;//伺服器名稱  
            Label2.Text = "伺服器IP地址:" + Request.ServerVariables["LOCAL_ADDR"];//伺服器IP地址  
            Label3.Text = "HTTP訪問埠:" + Request.ServerVariables["SERVER_PORT"];//HTTP訪問埠"
            Label4.Text = ".NET解釋引擎版本:" + ".NET CLR" + Environment.Version.Major + "." + Environment.Version.Minor + "quot;." + Environment.Version.Build + "." + Environment.Version.Revision;//.NET解釋引擎版本  
            Label5.Text = "伺服器作業系統版本:" + Environment.OSVersion.ToString();//伺服器作業系統版本  
            Label6.Text = "伺服器IIS版本:" + Request.ServerVariables["SERVER_SOFTWARE"];//伺服器IIS版本  
            Label7.Text = "伺服器域名:" + Request.ServerVariables["SERVER_NAME"];//伺服器域名  
            Label8.Text = "虛擬目錄的絕對路徑:" + Request.ServerVariables["APPL_RHYSICAL_PATH"];//虛擬目錄的絕對路徑  
            Label9.Text = "執行檔案的絕對路徑:" + Request.ServerVariables["PATH_TRANSLATED"];//執行檔案的絕對路徑  
            Label10.Text = "虛擬目錄Session總數:" + Session.Contents.Count.ToString();//虛擬目錄Session總數  
            Label11.Text = "虛擬目錄Application總數:" + Application.Contents.Count.ToString();//虛擬目錄Application總數  
            Label12.Text = "域名主機:" + Request.ServerVariables["HTTP_HOST"];//域名主機  
            Label13.Text = "伺服器區域語言:" + Request.ServerVariables["HTTP_ACCEPT_LANGUAGE"];//伺服器區域語言  
            Label14.Text = "使用者資訊:" + Request.ServerVariables["HTTP_USER_AGENT"];
            Label14.Text = "CPU個數:" + Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");//CPU個數  
            Label15.Text = "CPU型別:" + Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER");//CPU型別  
            Label16.Text = "請求來源地址:" + Request.Headers["X-Real-IP"];
        }

2.修改nginx配置資訊

修改nginx監聽埠,修改http server下的listen節點值,由於本機80埠已經被佔用,我改為監聽8083埠。

listen 8083;

在http節點下新增upstream(伺服器叢集),server設定的是叢集伺服器的資訊,我這裡搭建了兩個站點,配置了兩條資訊。

#伺服器叢集名稱為Jq_one
upstream Jq_one {
  server 127.0.0.1:9000; 
  server 127.0.0.1:8082; 
}

在http節點下找到location節點修改

 location / {
            root   html;
            index  index.aspx index.html index.htm; #修改主頁為index.aspx
     #其中jq_one 對應著upstream設定的叢集名稱
     proxy_pass         http://Jq_one; 
     #設定主機頭和客戶端真實地址,以便伺服器獲取客戶端真實IP
     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服務,最終完整配置檔案資訊如下

3.執行結果

訪問http://127.0.0.1:8083/index.aspx ,多訪問幾次,著重關注標紅部分。

可以看到,我們的請求被分發到了8082站點和9000站點,並且第一次是8082站點第二次9000。出現這樣的結果證明我們負載均衡搭建成功了。 嘗試關閉其中的9000站點,然後重新整理頁面發現輸出的http埠一直是8082,也就是說其中一個站點掛了,只要還有一個站點是好的,我們的還是可以服務。

問題分析

雖然我們搭建好了負載均衡站點,但是還存在以下問題。

1.如果站點使用了session,請求平均分配到兩個站點,那麼必然存在session共享問題,該如何解決?

  • 使用資料庫儲存session資訊
  • 使用nginx將同一ip的請求分配到固定伺服器,修改如下。ip_hash會計算ip對應hash值,然後分配到固定伺服器
 upstream Jq_one{
    server 127.0.0.1:8082 ;
    server 127.0.0.1:9000 ;
     ip_hash;
  }
  • 搭建一臺Redis伺服器,對session的讀取都從該Redis伺服器上讀取。後面的文章將介紹分散式快取Redis的使用

2.管理員更新站點檔案,該怎麼操作,現在還只有兩臺伺服器,可以手工將檔案更新到兩臺伺服器,如果是10臺呢,那麼手工操作必然是不可行的

多伺服器站點更新可以使用GoodSync 檔案同步程式,會自動檢測檔案的修改新增,然後同步到其它伺服器上。在linux下可以使用rsync

3.站點中的檔案上傳功能會將檔案分配到不同的伺服器,檔案共享問題如何解決。

使用檔案伺服器將所有檔案儲存到該伺服器上,檔案操作讀取寫入都在該伺服器上。這裡同樣會存在一個問題,檔案伺服器存在讀寫上限。

4.負載的伺服器配置不一樣,有的高有的低可不可以讓配置高的伺服器處理請求多一些

這裡講一下,負載均衡有好幾種演算法 輪轉法,雜湊法, 最少連線法,最低缺失法,最快響應法,加權法。我們這裡可以使用加權法來分配請求。

upstream Jq_one{
  server 127.0.0.1:8082 weight=4;
  server 127.0.0.1:9000 weight=1;
}

通過weight設定每臺伺服器分配請求站的權重,值越高分配的越多。

5.由於請求是經過nginx轉發過來的,可以在程式碼裡面獲取到使用者請求的實際ip地址嗎?

答案是肯定的,在localtion節點設定如下請求頭資訊

#設定主機頭和客戶端真實地址,以便伺服器獲取客戶端真實IP
proxy_set_header Host $host; 
proxy_set_header X-Real-IP $remote_addr; 
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

程式碼裡面通過Request.Headers["X-Real-IP"],就能獲取到真實ip

6.nginx實現靜態檔案(image,js,css)快取

在server節點下新增新的localtion

#靜態資源快取設定
location ~ \.(jpg|png|jpeg|bmp|gif|swf|css)$
{ 
expires 30d;
root /nginx-1.9.3/html;#root: #靜態檔案存在地址,這裡設定在/nginx-1.9.3/html下
break;
}

這是index頁面的程式碼 <li><img src=”/images/1.jpg”/></li>

總結

通過nginx我們實現了一個簡單的負載均衡,實際情況比這複雜很多。比如nginx伺服器掛了,那我們的站點就直接掛了,正確的通過keepalived元件來搭建多臺nginx服務提供服務。本篇只做為分散式系統的開篇,後續會陸續推出Redis快取,資料庫實現分散式架構的文章,敬請期待!希望能夠得到部落格園分散式大牛的指導。

本篇文章用到的資源打包下載地址:nginx_iis

相關文章