天天看點

架構基礎知識總結1

文章目錄

    • 一、nginx入門配置篇(初識核心功能)
      • 1.1、nginx配置檔案結構和核心功能
        • 1.1.1、nginx的配置檔案結構
        • 1.1.2、nginx核心功能
        • 1.1.3、nginx實作web功能(http)的核心子產品
    • 二、linux叢集
      • 2.1、叢集概述
        • 2.1.1、單台主機所面臨的問題和解決概述
        • 2.1.2、叢集面臨的問題和解決思路
      • 2.2、linux叢集類型
      • 2.3、linux叢集系統擴充方式
      • 2.4、linux叢集的排程方法
        • 2.4.1、靜态排程算法
        • 2.4.2、動态排程算法
    • 三、LVS應用
      • 3.1、lvs功能的實作
      • 3.2、lvs四種叢集優點和使用場景
      • 3.3、LVS-NAT和LVS-DR的原理和實作舉例,LVS-FUN和LVS-FULLNAT簡單圖解
        • 3.3.1、LVS的NAT類型
        • 3.3.2、LVS的DR類型
        • 3.3.3、LVS的tun類型簡單封包圖解(隧道)
        • 3.3.4、LVS的fullnat類型簡單封包圖解

感謝和參考:

PS:理論思想和實踐實驗步驟主要是來自于馬哥linux教育的學習,特此感謝,也感謝下面這些部落客精彩的博文,從中受益良多,有些比較精彩的部分有摘抄過來。

參考或摘抄博文連結:

http://www.linuxvirtualserver.org/zh/lvs4.html

https://www.cnblogs.com/wangshaojun/p/5149532.html

https://www.jianshu.com/p/2acab9134dbf

http://www.178linux.com/104977

https://www.jianshu.com/p/5184c6564ee2

https://www.jianshu.com/p/298a85b74abf

https://www.ibm.com/developerworks/cn/linux/l-cn-directio/

https://www.cnblogs.com/youngerchina/p/5624462.html

一、nginx入門配置篇(初識核心功能)

1.1、nginx配置檔案結構和核心功能

以下幾個nginx官方相關的連結可以經常去看看:

nginx 總官方首頁位址

nginx 文檔的api連結位址(簡單的官網)

nginx 的所有子產品文檔位址入口

nginx 所有變量索引目錄

nginx 所有指令索引目錄

1.1.1、nginx的配置檔案結構

官方位址:http://nginx.org/en/docs/beginners_guide.html

注解:

    nginx 由子產品組成,子產品由配置檔案中指定的指令控制。指令被分成兩種,包括簡單指令和塊指令。簡單指令由名字和參數組成,名字和參數之間以空格或空白隔開,然後指令結尾以分号結束。塊指令格式和簡單指令文法差不多,末尾分号去掉後,會使用一組花括号({})引起來。花括号内可以有其他指令包含在内,這個叫做上下文(比如:events,http,server以及location指令都是塊指令)。

    在任何上下文之外放置在配置檔案中的指令都被認為是在上下文中。nginx 分為主配置段(全局配置段),可以支援很多全局配置的指令,相關指令可以參考[nginx全局配置端指令(http://nginx.org/en/docs/ngx_core_module.html)。在主配置段中,可以包含 events塊,http塊。而server塊在http塊中,location塊在server中。在配置檔案中,以"#"開頭的都屬于注釋部分。

主配置檔案的配置指令用法總結:

普通指令:directive value [value2 …];

塊指令:directive{ … }

所有nginx支援的指令使用說明連結:http://nginx.org/en/docs/dirindex.html

普通指令必須以分号結束;在整個配置檔案中,允許智勇配置變量,配置變量主要分以下兩類:

(1) 内建變量

有nginx子產品引入,可直接使用。所有nginx子產品引入的變量使用說明連結:

http://nginx.org/en/docs/varindex.html

(2)自定義變量

由使用者使用set指令定義(set variable_name value;),引用變量方式:$variable_name

set除了可以做定義自定義變量,還可以修改内建變量的值。

大概的配置結構:

主配置檔案結構如下:
#main block:主配置段,也即全局配置段;
......  #簡單指令部分(全局的配置指令)
event {
    ......
} #事件驅動相關的配置;

http {
	......
} #http/https 協定相關的配置段;

mail {
	......
} #郵件協定相關配置段,這部分應用很少
stream {
	......
} #傳輸層代理配置段

http協定相關的配置結構:
http {
    ......
    ......  #各server的公共配置部分
    server {
        ...... 
    } #每個server用于定義一個虛拟主機

    server {
        ......
        listen
        server_name
        root
        alias
        location [OPERATOR] URL {
            .....
            If CONDITION {
                ......
            }
        }
    }
}

           

1.1.2、nginx核心功能

核心功能配置部分按照作用分為以下幾類:

1、正常運作必備的配置

2、優化性能相關的配置(其實談不上優化,而就是做參數調整而已,優化這個東西涉及知識點太廣)

3、用于調試及定位問題相關的配置

4、事件驅動相關的配置

下面的指令的官方文檔連結:http://nginx.org/en/docs/ngx_core_module.html

被nginx官方辨別為:Core functionality(核心功能)

  • 1、正常運作必備的配置

    (1) user指令

文法格式:user username [groupname]
預設值:user nobody nobody;
上下文:main
官網注解:Defines user and group credentials used by worker processes. 
If group is omitted, a group whose name equals that of user is used.

自己的注解:定義nginx工作程序啟動運作身份的使用者屬主和屬組。一般來說,建議worker是普通使用者,比如nginx,www,nobody等等。
如果省略組名,預設組會取和使用者名一樣的名字。(PS: 涉及nginx處理使用者請求,是worker程序來處理的,是以涉及到權限的東西,也是
工作程序運作使用者群組的程序安全上下文。)

重點補充:
安全上下文說明。
1、程序以某使用者的身份運作,程序就是發起此程序使用者的代理,是以以此使用者的身份和權限完成所有的操作。
2、權限比對模型(基本權限,不涉及特殊權限和通路控制清單)
a) 判斷程序的屬主是否為被通路的檔案的屬主:如果是,則應用屬主的權限,否則接着往下判斷;
b) 判斷程序的屬組是否屬于被通路的檔案屬組:如果是,則應用屬組的權限,否則接着往下判斷;
c) 如果上述兩種情況都沒有比對到權限,則應用other的權限,即檔案的其他者;

權限字元表示有兩個:r、w和x,分别代表讀,寫和執行權限;
基本權限相較于檔案而言:
	r:表示可擷取檔案的資料;
	w:表示可修改檔案的資料;
	x:表示可将此檔案發起運作為程序;

基本權限相對于目錄:
	r:可使用ls指令擷取其下的所有檔案清單;
	w:可修改此目錄下的檔案清單,即建立或删除檔案;
	x:可切換到此目錄中,且可使用ls -l來擷取所有檔案的詳細屬性資訊。

           

(2) pid指令

文法格式:pid file;
預設值:pid logs/nginx.pid;
上下文:main
官方注解:Defines a file that will store the process ID of the main process.

自己注解:定義用來存儲主程序的程序id的檔案,或者叫用來指明存儲nginx主程序程序号的檔案。
可以指定為這種格式便于了解:pid /PATH/TO/PID_FILE #可以是相對路徑,也可以是絕對路徑。如果是相對路徑值,是相對nginx編譯安裝(不管
是自己源碼包編譯安裝,還是自己根據spec檔案制作的rpm包手動使用rpm安裝或者是yum調用的nginx官方yum倉庫或者第三方yum倉庫安裝,
yum安裝也是安裝制作好的rpm包。都可以給nginx的主程式檔案傳一個選項-V來檢視編譯選項,其中一個--prefix=path,我們這裡的pid指定的如
果是相對目錄,就是相對這個選項的path路徑) 服務端檔案安裝根目錄。

           

(3) include指令

文法格式:include file | mask;
預設值:無
上下文:any #任意塊或段落中都可以使用該指令
官方注解:Includes another file, or files matching the specified mask, into configuration. Included files should consist of syntactically correct
 directives and blocks.
自己注解:包含其他檔案或者指定掩碼(通配符等,比如*.conf)比對的檔案加入到配置檔案中。包含進來的檔案中的指令和塊的文法要正确。
簡單概括一句話:用來指明包含進來的其他配置檔案片段;

           

(4) load_module指令

文法格式:load_module file;
預設值:無
上下文:main
官方注解:Loads a dynamic module.This directive appeared in version 1.9.11.

自己注解:指明要裝載的動态子產品。比如:load_module " /usr/lib64/nginx/modules/ngx_http_image_filter_module.so";
PS:前提是要裝載的子產品要編譯進來了,而且是支援動态裝解除安裝的子產品。nginx是1.9.11版本引入的動态子產品,1.9.11以及之後的版本才支援
load_module指令。現在預設epel倉庫預設版本已經是nginx-1.10.x,而且官方穩定版本更新到了1.14.x(2019年1月7日确認,最新穩定版本是
1.14.2)。

           
  • 2、性能優化相關的配置

    (1) worker_process指令

文法格式:worker_processes number | auto;
預設值:worker_processes 1;
上下文:main
官方注解:Defines the number of worker processes.
The optimal value depends on many factors including (but not limited to) the number of CPU cores, the number of hard disk drives that store
 data, and load pattern. When one is in doubt, setting it to the number of available CPU cores would be a good start (the value “auto” will try
  to autodetect it).
The auto parameter is supported starting from versions 1.3.8 and 1.2.5.
自己注解:
定義nginx的工作程序的數量。(建議設定為小于或等于目前主機的cpu的實體核心數)
最佳取值取決于居多因素,包括(但不僅限于)CPU的核心數,存取資料的硬碟驅動的數量以及負荷模型等。如果不确定如何設定,設定它的值為
cpu核心數是一個好的開端(如果設定為auto,會嘗試去自動檢測cpu核心數,并設定為檢測的實際值)。
auto參數是在nginx的 1.3.8版本和1.2.5版本引入。
PS:這裡設定為大于cpu的核心數沒有意義而且反而可能會有副作用,因為本身nginx的IO模型就是一個程序處理可以響應多個請求,如果我
實體伺服器性能名額能承受得住,我可以調整單個工作程序響應處理的請求數量。通常建議是實體cpu有幾個核心,我們設定的值應該小于或等
于這個核心數的值。為什麼不固定設定為1呢,因為為了更好的利用cpu的核心來工作。因為一個nginx工作程序在工作的時候必然是排程在一個
標明的或固定的實體cpu核心上,如果此時系統其他程序負載很小可以忽略不計,那麼如果我實體cpu核心數量不止1,其他cpu核心就處于空閑狀
态了。什麼情況下,至少要小于實體cpu核心數呢?就是系統上除了我們nginx程序之外,還有其他的程序,而且也有生産力,是以這種情況下建
議至少預留一個核心來排程其他程序。如果把這個參數的值設定大于實體cpu核心數,我們都知道nginx的工作程序如果有啟動,勢必要響應處理
請求,如果對于一個繁忙的web伺服器,如果設定的這個參數值大于實體cpu核心數,那麼多出來的部分,勢必就要做cpu按照時間分片技術調
度,排程就存在資源浪費(有人可能會說,我一台系統不可能不存在除了nginx之外的其他程序。話雖如此,其他程序相較繁忙的nginx的工作進
程,相對占用cpu時間也不會太長,負載可以忽略。但是對于繁忙的工作程序,cpu切換帶來開銷是挺大的,具體底層比較複雜。如果一定要計
算輕量負載的其他非nginx的程序cpu切換帶來的性能影響,可以考慮後邊cpu綁定設定)。

           

(2) worker_cpu_affinity_cpumask指令

文法格式:worker_cpu_affinity cpumask ...;
		  worker_cpu_affinity auto [cpumask];
預設值:無
上下文:main
官方注解:Binds worker processes to the sets of CPUs. Each CPU set is represented by a bitmask of allowed CPUs. There should be a 
separate set defined for each of the worker processes. By default, worker processes are not bound to any specific CPUs.
自己的注解:
将工作程序綁定在CPU集上。每個CPU集由允許的CPU的位掩碼所表示。應該為每一個工作程序定義一個單獨的集。預設,工作程序不綁定在任
何的cpu上。(綁定隻是一種簡單的優化邏輯。每一個程序在運作時候都有它自己的資料加載,而為了能夠加速這個資料處理過程,我們cpu有設
計1級緩存,2級緩存,3級緩存等。如果把一個程序綁定在cpu上,它的緩存始終會命中。如果不綁定,cpu在做處理程序切換的時候,緩存項可
能就會失效了,因為除了nginx本身的程序之外,還會有系統程序。如果當時工作程序1被配置設定到了cpu核心1上,工作程序2被配置設定到了cpu核心2
上,那麼這兩個cpu就有可能分别緩存了工作程序1和2的資料。當處理nginx程序之外的其他系統程序需要使用cpu的時候,可能會把cpu核心1和
cpu核心2都排程切換,回頭再次排程到工作程序1和工作程序2的時候有可能工作程序1被配置設定到了cpu核心2,工作程序2被配置設定到了cpu核心1,
這樣之前工作程序在cpu的緩存資料勢必就失效了。
還有一種比較複雜的設定,比如我系統有4個cpu核心。如果系統上處理nginx,其他程序幾乎沒有負載,可以實作,把nginx的3個工作程序直接
綁定到4個cpu核心中的3個,然後通過某些技術屏蔽掉這3個綁定的cpu,讓它們隻給其各自綁定的nginx的工作程序服務,剩下的1個cpu核心,
用于排程系統的其他程序任務。也就是說綁定的3個cpu核心數不再參與系統其他程序的排程任務。這個就是與之前的綁定的差別。不過這個功
能需要系統在啟動的時候,單獨隔離這3個綁定的cpu,比如麻煩。)
例如:
worker_processes    4;
worker_cpu_affinity 0001 0010 0100 1000;
設定工作程序為4個,并分别把每個工作程序綁定到每個分離的cpu上。0001表示第0号cpu(第一個cpu核心),0010表示第1号cpu(第二個cpu核
心),0100表示第2号cpu(第三個cpu核心),1000表示第3号cpu。這裡之是以是4為二進制,因為實體cpu核心總共才8個。如果有8核心,位掩碼
一共要有8位才對。
例如:
worker_processes    2;
worker_cpu_affinity 0101 1010;
綁定第一個工作程序在CPU0和CPU2上(0101可以拆分為0001和0100),因為有可能多核新是超線程實作的多核。比如我實際隻有兩顆實體
cpu,而且每顆實體cpu分别有一個核,然後cpu通過超線程技術支援,然每顆實體cpu支援2核,是以這樣通過超線程實作的多核cpu(4核)實際真
正的實體核心數應該隻有2。
綁定的二個工作程序在CPU1和CPU3上(1010可以拆分為0010和1000).這第二個示例對于适用于超線程。

例如:
worker_processes auto;
worker_cpu_affinity auto;
這種情況,就是工作程序設定的是auto,綁定也支援的是auto。對于一個系統專門隻提供nginx業務的,而且其他系統程序負載很輕的情況下,
可以這樣做。如果還提供其他業務,比如mysql等,建議不要綁定。

例如:
worker_cpu_affinity auto 01010101;
可選參數mask可以用來限定可以自動綁定的cpu。
           

(3) worker_priority指令

文法格式:worker_priority number;
預設值:worker_priority 0;
上下文:main
官方注解:Defines the scheduling priority for worker processes like it is done by the nice command: a negative number means higher 
priority. Allowed range normally varies from -20 to 20.
自己的注解:為工作程序定義排程的優先級,就像由nice執行指令一樣。通常我們也說指定worker程序的nice值,設定woker程序優先級:負數
意味着優先級高。允許使用的預設範圍為:-20到20。什麼場景,這樣使用呢?就是當一個業務系統,nginx作為一個比較核心的業務的時候,然
後有其他業務程序會和它競争資源,可以把nginx的工作程序的程序優先級條高一點。
小技巧:ps如何檢視nice值,ps axo comm,pid,psr,ni
例如:
worker_priority -10;

           

(4) worker_priority指令

文法格式:worker_rlimit_nofile number;
預設值:無
上下文:main
官方注解:Changes the limit on the maximum number of open files (RLIMIT_NOFILE) for worker processes. Used to increase the limit without 
restarting the main process.
自己注解:改變所有worker程序所允許打開的最大檔案數量限制(即所有worker程序所能夠打開的檔案上限)。增加這個限制,不需要重新開機nginx的
管理程序。因為worker程序打開一個連接配接就需要維持一個套接字,如果worker能夠支援的最大并發為1024,就表示需要打開1024個套接字件,
還姑且不說其他檔案。如果我們要提高這個值的話,還受制于worker程序對應系統使用者所能打開的程序數,否則它無法建立這麼多的連接配接數量。
切記這個是定義所有worker程序所允許打開的最大檔案數量。這個值應該大于或等于後面介紹的event塊中的worker_connections參數設定的值
與worker_processes設定值。公式:
worker_rlimit_nofile >= worker_processes* worker_connections

           
  • 3、調試、定位問題

    (1) daemon指令

文法格式:daemon on | off;
預設值:daemon on;
上下文:main
官方注解:Determines whether nginx should become a daemon. Mainly used during development.
自己注解:是否以守護程序方式運作nginx。

           

(2) master_process指令

文法格式:master_process on | off;
預設值:master_process on;
上下文:main
官方注解:Determines whether worker processes are started. This directive is intended for nginx developers.
自己注解:是否以master/worker模型運作nginx; 

           

(3) error_log指令

文法格式:error_log file [level];
預設值:error_log logs/error.log error;
上下文:main,http,mail,stream,server,location
官方注解:官方注解比較長,請自行參考:http://nginx.org/en/docs/ngx_core_module.html#error_log
自己注解:這個指令用來配置日志日志記錄資訊的,是我們常說的錯誤日志和調試日志。指令的第一個參數file表示用來指明定義一個檔案用來
存儲日志,可以是一個相對路徑也可以是一個絕對路徑。指定檔案權限要nginx的工作程序使用者要對這個檔案有讀寫的權限。從1.7.11版本開始,
error_log可以在stream中用;從1.9.0開始,error_log可以在mail中有。

日志級别可選值有,debug,info,notice,warn,error,crit,alert以及emerg。一般生成環境使用warn或notice就行。

           
  • 4、事件驅動相關的配置

    事件驅動相關的配置通常在下面這個語句塊中:

events {
    ......
}

           

(1) worker_connections指令

文法格式:worker_connections number;
預設值:worker_connections 512;
上下文:events
官方注解:Sets the maximum number of simultaneous connections that can be opened by a worker process.
It should be kept in mind that this number includes all connections (e.g. connections with proxied servers, among others), not only 
connections with clients. Another consideration is that the actual number of simultaneous connections cannot exceed the current 
limit on the maximum number of open files, which can be changed by worker_rlimit_nofile.
自己注解:設定被單個工作程序(worker process)所能同時打開的最大并發連接配接數。要牢記一點,這個連接配接不僅僅隻指用戶端的連接配接,而是所有
的連接配接(比如,被代理伺服器的連接配接也包含在内)。設定這個值的時候還要考慮實際允許并發的連接配接數不能超過最大的檔案打開限制,可以改變
worker_rlimit_nofile這個值來調整。

           

(2) use指令

文法格式:use method;
預設值:無
上下文:events
官方注解:Specifies the connection processing method to use. There is normally no need to specify it explicitly, because nginx will by default 
use the most efficient method。
關于連接配接處理的方法可以參考:http://nginx.org/en/docs/events.html

自己注解:指明并發連接配接請求的處理方法。紅帽發型版本一般推薦使用epoll,隻要linux核心是2.6之後的版本。關于nginx所支援的連接配接方法說
明,可以參考上面的連結。

           

(3) accept_mutex指令

文法格式:accept_mutex on | off;
預設值:accept_mutex off;
上下文:events
官方注解:If accept_mutex is enabled, worker processes will accept new connections by turn. Otherwise, all worker processes will be notified 
about new connections, and if volume of new connections is low, some of the worker processes may just waste system resources.
There is no need to enable accept_mutex on systems that support the EPOLLEXCLUSIVE flag (1.11.3) or when using reuseport.
Prior to version 1.11.3, the default value was on.
自己注解:處理新的連接配接請求方法;on意味着由各worker輪流處理請求,off意味着每個新請求的到達都會通知所有的worker程序;這是一種互
斥鎖機制。設定啟用這種機制,表示起點公平,比如現在有100個請求過來,有啟動4個worker程序,每個程序配置設定25個。如果設定為off,意味着
結果公平,就是來了請求,所有的worker程序會去競争響應,可想而知,對于比較空閑的工作程序能競争到的機率就要高一點。是以從大局來
看,所有的工作程序所配置設定到的請求的數量應該是平均的。從我個人的了解來看,對于繁忙的業務系統,可以開啟這個。對于空閑的業務系統或
者說新的連接配接數很少,如果所有的工作程序都去響應每一次的請求,勢必會有一些資源浪費。

           

1.1.3、nginx實作web功能(http)的核心子產品

與http相關的子產品文檔位址:http://nginx.org/en/docs/

    下面部分涉及的指令99%都是來自于http協定功能的核心子產品,ngx_http_core_module,部分1到2個不屬于此http協定的核心子產品功能,會在講解指令的時候特殊說明。http功能的核心子產品官方文檔連結為:

http://nginx.org/en/docs/http/ngx_http_core_module.html

本部配置設定置大概架構:

http {
	... ...
	server {
		...
		server_name
		root
		location [OPERATOR] /uri/ {
			...
		}
	}
	server {
		...
	}
}

           

說明:從這部分開始,後續講解的指令由于官方文檔涉及全部用法非常複雜,是以後續講解,不會把官方文檔的所有部分都貼

出,隻會選取比較重要的部分說明。如果有些沒有提到後續又要用,請自行參考官方文檔對應功能子產品的對應指令的詳細用法。

  • 1、與套接字相關的配置

    (1) server指令

文法:server { ... }
預設值:無
上下文:http
注解:
配置虛拟主機。基于IP和基于主機名的虛拟主機并沒有清晰的差別。(主機名最終還是會通過DNS解析成IP,是以并沒有大的差別)。在server指
令定義的虛拟主機配置段中,可以使用listen指令指明該虛拟主機接受連接配接涉及到的所有位址和端口資訊。server_name指令用來列出虛拟主機
的所有主機名稱。

官方有個說明引導,關于如何配置的:
http://nginx.org/en/docs/http/request_processing.html

           

(2) listen指令

文法(基于官方精簡版):listen port | address[:port] | unix:/PATH/TO/SOCKET_FILE
listen address[:port] [default_server] [ssl] [http2 | spdy] [backlog=number] [rcvbuf=size] [sndbuf=size]
預設值:listen *:80 | *:8000;
上下文:server

default_server:設定預設虛拟主機;
ssl:限制僅能夠通過ssl連接配接提供服務;
backlog=number:後援隊列長度;(超過最大并發連接配接後,排隊的隊列的長度)
rcvbuf=size:接受緩沖區大小;
sndbuf=size:發送緩沖區大小;
說明:在接收請求的虛拟主機中可以使用address和port指明對應虛拟主機的監聽位址和端口或者使用unix套接字用來指明本地通信的一個套接
字檔案。可以同時指明address和port或者隻給定address或隻給定port。其中的address可以是一個主機名。例如:
listen 127.0.0.1:8000;
listen 127.0.0.1;
listen 8000;
listen *:8000;
listen localhost:8000;
#ipv6 ,nginx 0.7.36版本之後可以使用
#UNIX-domain套接字,nginx0.8.21版本之後可以使用,要指明"unix:"字首
listen unix:/var/run/nginx.sock;

重點:如果隻給定了address,預設http協定使用的是80端口,配合ssl後使用的是443。
如果指令address沒有給定,如果nginx服務是以管理者權限使用者啟動(就是nginx的管理程序的啟動使用者是管理者使用者),預設是用*:80,如果
nginx服務是以非管理者權限使用者啟動,預設是用*:8000。
如果有多個虛拟主機,預設多個虛拟主機都沒有指定default_server,那麼第一個虛拟主機會作為預設的虛拟主機。如果在啟動一個或者多個虛
拟主機中使用了(通常應該隻會指定一個,或者把要當作的預設虛拟主機放在第一個) default_server指令,那麼這個虛拟主機會作為預設的虛拟
主機。如果給定了ssl參數,表示所有連接配接請求都應該以SSL模式,即使我指定的監聽端口是80,連接配接也應該以SSL模式工作,比如:
listen 80;
差別于
listen 80 ssl;

有時候為了讓HTTP和HTTPS協定都能使用,可以這樣指定:
listen 80;
listen 443 ssl;

           

(3) server_name指令

文法結構:server_name name ...;
預設:server "";
上下文:server
注解:指明虛拟主機的主機名稱;後可跟多個由空白字元分隔的字元串;
支援*通配比對任意長度的任意字元:server_name *.yanhui.com www.yanhui.*
支援~起始的字元做正規表達式模式比對:server_name ~^www\d+\.yanhui\.com$
比對機制:
	(a) 首先比對字元串精确的比對;
	(b) 左側*通配符;
	(c) 右側*通配符;
	(d) 正規表達式;

           

(4) tcp_nodelay指令

文法結構: tcp_nodelay on | off;
預設值: tcp_nodelay on;
上下文:	http, server, location
注解:在keepalived模式下的連接配接是否啟用TCP_NODELAY選項。
對于一個要發送的資料,以TCP/IP4層結構來說,在每一層要加上對應的首部。如果要發送的資料的位元組數比較小,有可能資料封包的首部的大
小要大于要發送的實際的内容的位元組數。這樣的一次發送請求,對于開銷來說未免有些浪費,有一種思路就是我可以把小的内容先攢着,然後集
中發送,這樣就會有一個問題,對于用戶端來講,接受就會有延遲。為什麼說nodelay要運作于保持連接配接模式呢,因為非保持連接配接模式,用戶端
每一次請求連接配接都是3次握手4次揮手的過程,如果是保持連接配接,可以一次會話的建立,會有多個請求在一次會話中進行。這個tcp_nodelay啟用
後表示,不延遲到達,每一次請求都會及時發送,使用者體驗方面會好一點,不過每一次及時發送,小資源的封包未免會浪費帶寬等資源。

           

(5) tcp_nopush指令

文法結構:tcp_nopush on | off;
預設值:tcp_nopush off;
上下文:http,server,location
注解:在sendfile模式下,是否啟用TCP_CORK選項;啟動此選項可以實作的功能:
	(a) 響應封包首部和整個檔案的起始内容放在一個封包中發送。
	(b) 利用完整的封包發送一個檔案,不會把檔案分開來發送。

使用sendfile機制的話,可以基于内容把檔案發過去了,但是應用層首部呢?核心無法生成應用層首部資訊(tcp首部可以生成),因為它不了解應
用層協定。比如封裝http協定的應用層首部,隻有nginx或者httpd才有權限封裝。sendfile的機制就是檔案内容先發送,然後應用層首部随後到
達。使用tcpnopush,等使用者空間的應用層首部發送過來,然後核心打包成一個封包然後發送。sendfile啟用的優勢是整個檔案的内容直接在内
核空間生成封裝的内容,而不需要經過使用者空間後然後再到核心空間。

           

(6) sendfile指令

文法結構:sendfile on | off;
預設值:sendfile off;
上下文:http,server,location,if in location
注解:Enables or disables the use of sendfile().
sendfile這個功能已經在多處提到。大概功能就是,外部用戶端請求服務端的内容後,請求的内容可能在磁盤上,預設工作模式是從磁盤加載數
據到核心的記憶體空間(因為對磁盤的操作是特權的操作,隻有核心才能完成),然後從核心的記憶體空間加載到web服務的程序的記憶體空間。而且以
TCP/IP 4層或者5層模型來看,封包要封裝,每一層都要封裝一層首部,實作封包的傳輸和拆解。啟動sendfile的好處就在于,除了應用層首部的
封包的封裝之外,磁盤加載的檔案的内容不會發送給使用者空間,而是直接存儲在核心空間的記憶體中,封裝成封包發送,對于檔案傳輸内容很大的
情況下,這種sendfile是很大的優化點。(解釋可能不夠精細,重點在于通俗)

           
  • 2、定義路徑相關的配置

    (1) root指令

文法結構:root path;
預設值:root html;
上下文:http,server,location,if in location
注解:設定web資源路徑映射;用于指明使用者請求的url所對應本地檔案系統上的文檔所在目錄路徑;
指令的路徑參數可以包含變量,有兩個變量比較特殊,不能使用,它們是:$document_root和$realpath_root,$document_root表示root或者
alias指令的值,如果通路路徑涉及符号連結,會使用符号連結;$realpath_root表示root或alias指令的值,與之前$document_root的差別在于,
如果對應目錄中有符号連結,會把真正的連結給出來。
例如:
location /i/ {
    root /data/w3;
}
比如我請求/i/top.gif,實際對應檔案系統路徑的内容為:/data/w3/i/top.gif

           

(2) location指令

文法結構:location [ = | ~ | ~* | ^~ ] uri { ... }
預設值:
上下文:server,location
注解:根據請求的URI來設定配置屬性。location中就是用來做nginx屬性設定相關的。在一個server中location配置段可存在多個,用于實作從uri
到文系統的路徑映射;nginx會根據使用者請求的URI來檢查定義的所有的location,并找出一個最佳比對,而後應用其配置。

=:表示對URI做精确比對,例如:http://www.yanhui.com/, http://www.yanhui.com/index.html
	location = / {
        ......
    }
	#上面這種形式,第一個連結可以被比對,第二個不行,因為第一個是/,第二個是/index.html
	
~:對URI做正規表達式模式比對,區分字元大小寫;
~*:對URI做正規表達式模式比對,不區分字元大小寫;
^~:對URI的左半部分做比對檢查,不區分字元大小寫;
不帶符号:比對起始于此uri的所有的url;
比對優先級:(從高到低)
	=
    ^~
    ~和~*是同級
    不帶符号

官方有個例子比較全面,就直接粘貼過來了:
location = / {
    [ configuration A ]
}

location / {
    [ configuration B ]
}

location /documents/ {
    [ configuration C ]
}

location ^~ /images/ {
    [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}

The “/” request will match configuration A, the “/index.html” request will match configuration B, the “/documents/document.html” request will 
match configuration C, the “/images/1.gif” request will match configuration D, and the “/documents/1.jpg” request will match configuration E.

           

(3) alias指令

文法結構:alias path;
預設值:無
上下文:location
說明:定義路徑别名,文檔映射的另一種機制;
注意:location中使用root指令和alias指令的意義不同(下面的差別描述不一定精确,但是可以這麼了解)
    (a) root,給定的路徑對應于location中的/uri/左側的/;
	(b)alias,給定的路徑對應于location中的/uri/ 右側的/;
由于這個東西比較重要,我舉幾個例子:
location /i/ {
    alias /data/w3/images/;
    #root /data/w3/images/;
}
請求/i/top.gif,檔案系統路徑對應會去找:/data/w3/images/top.gif
如果把上面的alias換成root,檔案系統路徑會去找:/data/w3/images/i/top.gif

有一種情況,就是圖檔資源和其他資源是分目錄存儲,通路的時候,比如:
location /images/ {
    alias /data/w3/images/;
}
請求/images/123.jpg,檔案系統路徑對應會去找: /data/w3/images/123.jpg。這樣就會給人一種誤解,兩個都有images字元串。是以建議配置成以下這種格式:
location /images/ {
    root /data/w3;
}
上面這種情況是定義location後邊的path與指令alias指令值的末尾部分一緻的時候,建議把alias換成root,并把原本alias的值中與location相同的部分去掉。

           

(4) index指令

特殊保護說明:屬于ngx_http_index_module子產品。這裡之是以放在這裡,是因為這個指令也比較常用。
文法結構:index file ...;
預設值:index index.html;
上下文:http, server, location
官方說明:Defines files that will be used as an index. The last element of the list can be a file with an absolute path.
自己注解:定義預設首頁檔案,或者叫預設的索引檔案。指定參數值可以包含變量,多個參數之間以空白分隔開,參數值清單的最後一個值可以
是一個絕對路徑。例如:index index.$geo.html index.0.html /index.html;檢測順序是從左到右的順序。

           

(5) error_page指令

文法結構:error_page code ... [=[response]] uri;
預設值:無
上下文:http, server, location, if in location
注解:Defines the URI that will be shown for the specified errors
自定義指定錯誤先調用顯示的頁面。比如指定404狀态的,自定義500,502,503,504等異常狀态顯示的錯誤頁面。而且可以指定調用後錯誤頁面
的狀态碼,可以改成正常的。

           

(6) try_files指令

文法結構:try_files file ... uri;
		   try_files file ... =code;
預設值:無
上下文:server,location
說明:按照指定順序分别檢查檔案是否存在,并使用找到的第一個檔案進行請求處理。檢查處理是在目前上下文中進行的。根據root和alias指令
指向的檔案系統路徑去查找檔案。如果要檢查目錄是否存在,可以在名稱的尾部加上左斜線(/)字尾,例如:"$uri/"。如果前邊所有的檔案都沒有被
找到,會以檔案參數清單的最後一個參數指向的路徑指定的URI來進行重定向。

           
  • 3、定義用戶端請求的相關配置

    (1) keepalive_timeout指令

文法結構:keepalive_timeout timeout [header_timeout]
預設值:keepalive_timeout 75s;
上下文:http,server,location
注解:如果第一個參數timeout設定為0表示關閉保持連接配接功能。設定為非0表示啟動保持連接配接。這裡和httpd不一樣,沒有單獨的關閉或打開保持
連接配接的開關按鈕。可選參數第二個,可以用來設定相應封包首的"Keep-Alive:timeout=time"的值。在Mozilla 火狐浏覽器和Konqueror浏覽器可以
識别這個"Keep-Alive: timeout=time";IE浏覽器使用自己預設的60s,不受到這個參數控制(沒有測試過)。

           

(2) keepalive_requests指令

文法結構:keepalive_requests number;
預設值:keepalive_requests 100;
上下文:http,server,location
注解:指令從0.8.0版本引入。在一次長連接配接上所允許請求的資源的最大數量,生産環境就可以使用預設值;
這個參數生效的前提是保持連接配接功能要開啟的。

           

(3) keepalive_disable指令

文法結構:keepalive_disable none | browser ...;
預設值:keepalive_disable msie6;
上下文:http,server,location
注解:對哪種浏覽器禁用長連接配接;

           

(4) send_timeout指令

文法結構:send_timeout time;
預設值:send_timeout 60s;
上下文:http,server,location
注解:向用戶端發送響應封包的逾時時長,此處,是指兩次成功的寫操作之間的間隔時長;用戶端向服務端發送請求封包後,服務端會建構響應
封包給用戶端發過去。如果用戶端發送請求封包之後,突然離線或者其他原因導緻網絡異常,收不到服務端的響應封包。這個發送響應封包會有
一個逾時時間,這個值就是用來設定這個逾時時間。如果用戶端在給定的逾時時間内收不到響應封包,連接配接将會被關閉。

           

(5) client_body_buffer_size指令

文法結構:client_body_buffer_size size;
預設值:client_body_buffer_size 8k|16k;
上下文:http, server, location
注解:用于接收用戶端請求封包的body部分的緩沖區大小;
預設,緩存區大小是2倍的記憶體頁(4k)。如果是x86以及其他32位的平台,預設值為8K。如果是x86-64以及其他的64位平台,預設值為16K;超
出此大小時,其将被暫存到磁盤上的由client_body_temp_path指令所定義的位置(存磁盤性能就會受到影響了);
現在一般都是64位的平台。對于論壇或者允許使用者上傳的業務站點(允許使用者上傳巨大的内容或者允許使用者使用PUT方法上傳檔案時),而且站點
所在伺服器記憶體允許的話,這個值如果調大會提高站點性能。對于一個電商站點,可能POST方法送出的資訊很少,注冊送出的資訊也很少,使
用預設值16K足以。

           

(6) client_body_temp_path指令

文法結構:client_body_temp_path path [level1 [level2 [level3]]];
預設值:client_body_temp_path client_body_temp;
上下文:http, server, location
注解:設定用于存儲用戶端請求封包的body部分的臨時存儲路徑及子目錄結構和數量;
請求并發很大,如果每個請求都允許上傳資源,這個量級是很大的。是以無法用平面存儲的思路,而是采取的分層存儲機制。level1表示定義1
級子目錄使用的16進制字元數量。1為表示16個1級子目錄,2表示256個1級子目錄。level2表示二級子目錄使用的16進制字元數量。level3表示
3級子目錄使用的16進制字元數量。

比如請求為:http://www.yanhui.com/images/default.jpg,對其做md5
執行指令:echo -n 'http://www.yanhui.com/images/day.jp'|md5sum,結果為32位16進制字元:
1abb41e927569466f4bec3575a08f2b6

md5算法為128位,上面32個字元為二進制的16進制表示形式,每個字元可以由4位二進制所表示。
正是這種機制,存儲在磁盤上的檔案是每一個連接配接請求的md5值。

比如設定:client_body_temp_path path 1 2 2;
上面案例表示的含義為,使用1位字元表示一級子目錄,是以數量為2^4(2^3+2^2+2^1+2^0=15,二進制是1111,由于從0開始,是以結果要加1)=16個。使用2位字元表示二級子目錄,也就是每一個一級子目錄下面會建立256個二級子目錄,是以此時擁有的所有二級子目錄數量為
256*16=4096個。使用2位字元表示三級子目錄,也就是每一個二級子目錄下面會建立256個三級子目錄,是以此時擁有的所有三級子目錄數量為256*256*16=10485676(百萬級别的了)。如果超過百萬級别,可以把一級子目錄數量設定為256位,是以三級子目錄數量為256*256*256= 16777216(1千6百多萬了)
以本例為例,臨時檔案存儲可能是:/spool/nginx/client_temp/7/45/f2/ 00000123457
可以這樣映射,不止nginx會這樣做,其他類似的也會這樣做:
16進制的數字;
client_body_temp_path   /var/tmp/client_body  2 1 1 
	1:表示用一位16進制數字表示一級子目錄;0-f
	2:表示用2位16程序數字表示二級子目錄:00-ff
	2:表示用2位16程序數字表示三級子目錄:00-ff

           

(7) types_hash_max_size指令

文法結構:types_hash_max_size size;
預設值:types_hash_max_size 1024;
上下文:http,server,location
注解:設定nginx記憶體中開辟的類型hash表的大小。
資源類型,内容類型(有個檔案叫mime.types),nginx為了加速對某些内容的通路,mime.types的内容是直接被轉入到記憶體中的,當用戶端請求
一個資源之後,本地加載之後要立即分析這是什麼資源類型,要怎麼比對,在記憶體中就知道這些内容類型了。我們要如何比較呢,難道一個一個
字元的比較嗎?并不是,為了效率,記憶體中存儲的是類型hash之後的結果。每次比較的時候,會把内容hash後與之前存儲的hash内容做比較,
這種速度是非常快的。在記憶體中配置設定多少記憶體來儲存這些hash值,這個types_hash_max_size就是用來定義這個大小。這裡機關是否為位元組或者項,不太确認,留個疑問,等将來學習深入後給出解答?

關于nginx的設定hash表的說明連結:
http://nginx.org/en/docs/hash.html

           
  • 4、對用戶端進行限制的相關配置

    (1) limit_rate指令

文法結構:limit_rate rate;
預設值:limit_rate 0;
上下文:http, server, location, if in location
注解:限制響應給用戶端的傳輸速率,機關值bytes/second(位元組每秒)。值0表示無限制。這裡要注意的是,限制是對每一個請求來限制的,
如果一個用戶端同時打開了兩個連結,總速率會是限制速率的2倍。也可以使用$limit_rate變量來指定限制的速率,在條件判斷中可能用得到。
有個"X-Accel-Limit-Rate"首部值與速率限制相關。

           

(2) limit_except指令

文法結構:limit_except method ... { ... };
預設值:無
上下文:location
注解:限制用戶端使用除了指定方法之外的方法;
支援的方法可以有:GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK, 或
PATCH
(在ngx_http_access_http,ngx_http_auth_basic_module,ngx_http_auth_jwt_module子產品中還支援其他方法)。GET方法會隐式允許HEAD方法。
案例:
limit_except GET {
    allow 192.168.1.0/32;
    deny  all;
}
除GET和HEAD方法之外的方法,隻允許192.168.1.0/32網段中的客戶度端來使用,其他網段的用戶端都不允許使用。
           
  • 5、檔案操作優化的配置

    (1) aio指令

文法結構:aio on | off | threads[=poll];
預設值:aio off;
上下文:http, server, location
說明:是否啟用aio功能。建議開啟,可以減少我們通路檔案被阻塞到io上的可能。可以通過threads來指定多少個線程池來配合
使用AIO功能,使用預設值就行。

           

(2) directio指令

文法結構:directio size | off;
預設值:directio off;
上下文:http, server, location
官方注解:
Enables the use of the O_DIRECT flag (FreeBSD, Linux), the F_NOCACHE flag (macOS), or the directio() function (Solaris), when reading 
files that are larger than or equal to the specified size. The directive automatically disables (0.7.15) the use of sendfile for a given request. 
It can be useful for serving large files:  
directio 4m;
or when using aio on Linux.

當讀取檔案大于或等于(directio)指定的大小的時候。對于給定的請求,directive會自動關閉sendfile的功能。
這個部分,有人建議不要用。有人建議與aio一起使用,由于本身學術有限,不深入挖掘,待後續深入學習後回來補充。
可以參考:

https://www.cnblogs.com/youngerchina/p/5624462.html
https://yq.aliyun.com/articles/11243
https://www.ibm.com/developerworks/cn/linux/l-cn-directio/
https://blog.csdn.net/zhangxinrun/article/details/6874143
           

(3) open_file_cache指令

文法結構:open_file_cache off;
預設值:open_file_cache off;
上下文:http, server, location
說明:對于站點有大量檔案被頻繁範圍,可以把檔案的中繼資料資訊存儲到緩存中。此選項就是控制緩存檔案中繼資料的。nginx可以緩存以下三種
資訊:
(1) 檔案的描述符,檔案大小和最近一次的修改事件;
(2) 打開的目錄結構;
(3) 檔案查找錯誤,比如沒有找到或者沒有權限通路的檔案的相關資訊等。
該指令支援參數值可以有:max,inactive,off
max:可緩存項上限;這個值不能随意設定,要看自己記憶體允許不允許。達到上限後會使用LRU算法實作緩存管理;當緩存移除,就是超過這個
值的時候,LRU(the least recently used,最近最少使用)算法會把最近最少使用的緩存項删除。
inactive:緩存項的非活動時長,在此處指定的時長内(預設值60秒)未被命中的或命中的次數少于open_file_cache_min_uses指令所指定的次數
的緩存項即為非活動項;特别說明,非活動項的清理在緩存空間滿之前會進行。
off:關閉緩存檔案中繼資料的功能。

           

(4) open_file_cache_valid指令

文法結構:open_file_cache_valid time;
預設值:open_file_cache_valid 60s;
上下文:http, server, location
注解:緩存項有效性的檢查頻率;如果又想啟用這種緩存的功能,記憶體空間又不夠用,可以把這個檢查的頻率設定的快一點,即這個時間設定短
一點。

           

(5) open_file_cache_min_uses指令

文法結構:open_file_cache_min_uses number;
預設值:open_file_cache_min_uses 1;
上下文:http, server, location
注解:在open_file_cache指令的inactive參數指定的時長内,至少應該被命中多少次方可被歸類為活動項;

           

(6) open_file_cache_errors指令

文法結構:open_file_cache_errors on | off;
預設值:open_file_cache_errors off;
上下文:http, server, location
注解:是否緩存查找時發生錯誤的檔案一類的資訊。例如第一次請求的文檔為/images/hi/a.png,因為hi目錄不存在,是以此資源查找失敗,這個檔案查找失敗被緩存下來了。

           

說明:至于nginx的上面常見配置項涉及的舉例,以及nginx的其他非核心子產品(比如實作基于使用者認證的通路控制,基于ip的

通路控制,nginx的狀态頁資訊,nginx的通路日志控制設定,資源壓縮控制、https協定實作、重寫實作、防盜鍊實作等功能

子產品),包括nginx的代理功能的實作子產品(比如反代http,反代fastcgi),還包括代理4層協定以及負載均衡等功能,會在架構

基礎知識總結2中詳細注解。

二、linux叢集

2.1、叢集概述

2.1.1、單台主機所面臨的問題和解決概述

    不管是多麼複雜的叢集或者架構,無非都是從單台主機演變而來。單台計算機受限于本地的計算資源和存儲資源以及IO資源等。以并發通路服務的模型來舉例,單台主機所支援的并發數是有效的,這種有限性不僅僅受限于我們主機的硬體資源,而且還受限于并發服務程式設計模型當中所實作的機制。如果有基礎的人,可能了解過IO模型的select,poll等阻塞的模型以及基于事件驅動模型實作的epoll模型。epoll這種可以實作單程序響應多個使用者請求,進而大大解決了所謂的每一個請求都得需要一個程序來響應導緻資源消耗比較大的應用場景。

    對于磁盤IO來講,可以使用AIO(異步IO),來讓程序的請求發出以後直到對方準備并複制完成資料以後再接管資源,是以在磁盤IO方面又進一步解脫了并發服務程式設計模型當中的程序所需要承載的任務。即便如此,受限于我們的硬體,軟體等資源,單台伺服器的響應能力依然是有限的。比如基于httpd的prefork模型,單台主機的并發通路能力支援并發到1000或2000個,以及後邊引入的更好的,更新設計的nginx,支援并發服務請求到1萬或2萬個。但是,一旦并發連接配接請求依然超過這個數值之後要如何處理,對于我們的應用來講,無非就是這樣的模型或模式,一旦我們的業務需求所依賴到的硬體資源超過我們的硬體資源所承載的能力,我們通常會遵循以下幾個思路來考慮:

思路一:

    這種思路主要是對機器所處環境或者應用相關的參數做調整;對單台主機的請求做優化。比如增加相關的空間,調整核心中相關的參數、并發連接配接數、核心記憶體資源的使用量等。但是記憶體資源總會有一個限制,也總有耗盡的一刻,一旦資源枯竭,我們也不能通過調整的手段來解決或來擷取性能上的提升的之後,那就隻有下面的另外兩種方案來解決了。

思路二:

    這種思路主要是靠提高主機配置或者新增主機來完成;這種思路也有兩個方案,分别是:

    方案a:換更好性能,更好配置的計算機。比如原來2萬塊錢一台的主機,現在花20萬塊錢來買一台更好的替代。應用主機的向上擴充(scale up)。

    方案b:如果單台主機的并發處理及響應能力不夠或不足以支撐使用者請求的時候,如果這些使用者請求是可以并行隔離的,彼此間沒有什麼關系,那就意味着一台主機的壓力可以被分散出去,不是一個大請求的很多子任務而是各自都是獨立的請求,各自都是獨立的需求,那這種情況之下,我們可以把它分隔或分散開來。于是,可以多加一台或多加幾台主機來實作,這種應用實作叫做應用主機的向外擴充(scale out)。這種向外擴充的思想是組合多台主機來完成一個任務。這一個任務其實是可以被分隔或分散成許多個任務的任務。是以這種解決方案,就叫做計算機的cluster(群集,叢集),表示聚集在一起的一類事物統稱為cluster。

2.1.2、叢集面臨的問題和解決思路

    多台主機會把任務分隔或分散出去,這種叢集通常稱為負載均衡叢集,簡稱LB Cluster(load balancing cluster).

    我們考慮考慮一個主要的問題,當我們把使用者的請求給分散開來的時候,看上去是一件容易的事,我們可能一直假設有一個前提,這多個請求或者我們要處理的事情可以被分散或者分割成許多小請求來處理。對于我們的web服務來講,的的确确每個請求都是獨立的,這沒有問題。對于我們其他的服務,比如openssh,mysql等等也沒有問題,每一次的請求都是一個獨立的可分割的請求。事實上也是能夠分散的。

  • 問題1引入

        但是這裡會有一個問題,如果說分散使用者請求容易而且沒有問題或者這個問題容易解決。但是要考慮另一個問題,有些應用是需要追蹤使用者的狀态資訊的,比如現在各種的動态的站點,一個電商站點或者其他類似站點,一個使用者在我們的站點浏覽了哪些網頁或者浏覽了哪些商品,在使用者下次來通路時,我們期望在那個欄上顯示使用者已浏覽的商品。還有使用者向購物車添加了哪些商品,希望在使用者重新整理以後或者使用者重新登入或者使用者隔幾分鐘或者隔很長時間以後再來通路的時候,使用者要依然能看到使用者此前加入購物車中的商品。有些人可能會好奇,這種問題還是一個問題嗎,這個居然會成為問題嗎,答案是會成為一個問題;

  • 使用者session

        對于隻有單台伺服器時,一般來講,我們動态應用程式,比如像jsp或php,它們是需要去追蹤使用者身份。追蹤完以後,能夠把每一個使用者加入到目前主機上的活動,通過一個記憶體中的記錄資訊-(會話),來記錄它,這個通常稱為使用者的session,是一個很小的資料結構,它裡面記錄了一個使用者在此站點上所作出的活動,比如像浏覽的商品,加入購物車中的商品,收藏的商品等等,都應該予以記錄的。進而能使得,當使用者向購物車中加入多個商品并點選付款的時候,這個商品還都在這台主機之上,這沒有任何問題,因為我們隻有單台主機。

        如果這個事情被分散或分隔到多台主機了,問題所在呢。http請求,即便我們使用長連接配接,它的有效時長通常也隻不過是幾十秒的時間,當使用者第一次送出請求的,碰巧我們給它分散到了第一台主機之上,過了幾分鐘以後,使用者才看完整個商品,看完之後,使用者決定要加入購物車之後,依然在這台主機之上,這是OK的。再過了幾分鐘,觀看另外一件商品的時候,很有可能,這個使用者的請求被分發給另外一台主機的,之是以如此,我們剛才說明http協定本身是無狀态的,而第二,我們有多台主機的叢集是需要把每一個使用者的請求分散到多台不同的主機之上去的,那麼這個使用者的身份将難以被追蹤。是以即便請求本身可以被分割成多個任務,那麼來自于同一個使用者的多個請求是依然有可能需要被伺服器追蹤識别才可以。這是現代站點所面臨的必然問題。這也隻是其中的問題之一。

  • 問題2引入

        再想一個問題,有經驗或者有自己測試過的人可能曾經部署wordpress了,如果部署過wordpress,假設第一個站點使用的是wordpress,現在面臨請求難以在單台主機上處理,于是分散到第二台主機之上,第二台主機之上也有一個wordpress。wordpress是允許使用者上傳圖檔的,這個圖檔上傳之後儲存在什麼地方呢。一般來講,在wordpress裡面有一個upload這樣的一個路徑,用來專門儲存使用者上傳的圖檔資源并在于本地生成一個URL,作為它的單一通路路徑資源擷取節點。想象一下,如果使用者第一次登入的時候,被分發到第一台主機之上,并上傳了圖檔。第二次再次請求檢視這麼一個文章時,它的請求卻被分發到第二台主機之上,那麼他的資訊還有嗎?很顯然,資訊就沒了。是以你會發現,即便我們的請求是分離的,但是對于我們的業務本身來講,考慮到我們的請求是允許寫操作的,那麼很有可能某一次的使用者請求的寫會被某個伺服器本地所承載,這樣就會導緻同叢集中的承載同類任務的其他節點擷取不到這樣的請求了或者無法提供此種資源,那麼這依然會是一個問題。那麼怎麼解決?我們隻能用多台伺服器都通同時通路到的共享機制來解決,比如nis中的實作通路,NFS,CIFS。

  • 問題2解決分析

        可以讓兩個wordpress對應的上傳(圖檔)資源的目錄路徑是一個挂載的共享的後端的NFS或CIFS存儲,那麼是以使用者通過第一台伺服器上傳的,通過第二台伺服器也可以看到。這是一種解決思路。還有一種解決思路,假設有多個使用者請求,雖然說每一個請求都可以孤立,可以隔離開來,但是考慮到同一個使用者的請求,我們可以需要反複被追蹤被識别,我們應該實作的是,對同一個使用者的請求,我們始終給它發往同一個主機。對于同一個使用者請求發往同一個主機,但是還是那句話,這最終隻能解決使用者自己上傳的内容被自己看到。當其他的使用者被配置設定到另外一個主機之上,那麼另外的使用者就看不到使用者發的文章,會造成有一部分使用者看得見,一部分使用者看不見。為了避免這個問題,共享存儲也依然是必須的。

  • 其他問題引入和解決:

        對于我們的wordpress來講,它所需要存儲的資料不隻有我們上傳的圖檔,我們上傳的文章中的那些标題,正文的文字放哪兒去了呢,一般是存在mysql或mariadb這樣的db中去了,而這個db是不是應該是某一台主機本地的呢,如果是依然面臨我們剛才上文所說的那個問題。使用者發這個文章,圖檔的問題解決了。當使用者被配置設定到第二伺服器,圖檔的問題解決了,使用者卻看不到之前使用者發的文章。因為按照這個設想,文章内容被存在第一台伺服器的資料庫當中的。好在,資料庫本來就是用來提供資料共享存儲服務的,是以對于通路的文章的标題,正文等,也應該被放在一個共享的存儲當中,這個共享儲存設備,就是我們的資料庫管理系統。

  • 圖檔問題

    好像對于一個圖檔,我們重來都沒有做過或者想不通怎麼做,才能把它存儲到我們這個資料庫管理系統當中,能不能做呢。可以這樣實作,存圖檔的二進制編碼,問題是存進去之後如何取出來呢,更何況的很多檢視圖檔的工具,它沒辦法去聯系資料庫。

  • 資料的組織方式

    通俗來講,資料的組織方式有以下三種:

    (1) 結構化的

    (2) 半結構化的

    (3) 非結構化的

結構化資料:

    一般而言,對于結構化的并要求資料強一緻的資料,它們通常放在關系型資料庫并支援事務的存儲引擎上,例如mariadb的innodb存儲引擎。那麼,如果是存儲檔案的,比如圖檔,MP3等音樂檔案,我們一般把它們放在檔案系統的結構之上,它們一定是檔案系統結構而不能被進一步抽象成為所謂的資料管理模型自己專有的結構;

半結構化的資料:

    半結構化的資料,一般放在noSQL中或檔案系統之上。比如json格式的資料,通常被組織成document storage(文檔存儲),比如ELK中的Elasticsearch ,它是一個著名的分布式的document storage(文檔存儲),它們基于json格式去組織格式。json是一種著名的輕量化的半結構化資料的存儲邏輯。

非結構化的資料,就不說了。

  • web服務的三個層面

        突然發現,按照上面分析提到的,這樣會多了許多需求。這個需求以web服務來講,它分散于三個層面:

    第一:

        使用者的活動資訊,自己的活動資訊。在這個層面上,多台主機如果都能夠處理使用者需要的話,一個使用者的活動在第一台主機上活動一部分,在另外一台主機上活動一部分,那麼我們的伺服器将可能很難完全或完整的追蹤一個使用者的活動資訊或整體活動資訊。比如他浏覽了哪些網頁,他加入到購物車中的商品有哪些等等;

    第二:

        如果伺服器允許寫操作,它不僅僅能浏覽網頁,還能發起交易,付款等。比如我們提到的文章類的站點,比如wordpress,使用者有可能是需要發表文章的,文章中可能還要插入圖檔的,對于這種應用,它所帶來的不關是交易本身了,甚至可能是生成我們服務上所展示的内容的或者所展示的頁面的。那麼對于這種需求來講,我們如果允許使用者上傳時,存儲在伺服器主機的單台伺服器的主機本地,勢必會導緻使用者通過其他主機看不到,不關是無法追蹤使用者活動的問題了。連請求的同一個内容,你隻能在不同的伺服器上所看見,那麼這樣的負載均衡事實上 是不成立的。伺服器不一樣,均衡到不同的主機之上能得到的是不同的内容,這事實上對于使用者來講是有失公允的。那麼後兩個問題,我們已經有了簡單解決方案,比如如果允許使用者寫操作,檔案類的内容可以放在共享的存儲NFS或者CIFS之上。如果是所謂的結構化的資料,我們可以把它放在mariadb這樣的關系型資料庫存儲系統之上。

  • cookie解決思路的引入

        上面分析的過程,我們之前提到的第一個問題還沒有解決。剛才說過了,使用者的活動身份行為怎麼處理。第一個使用者在第一台伺服器上浏覽了網頁,使用者的活動行為是臨時産生,也通常是臨時有效,不會永久有效,而且這種活動行為也不會生成網頁資料本身,隻是作為一個簡單的活動評判或者叫使用者行為的追蹤。一般來講,我們不可能把它存儲在檔案系統之上或者關系型資料庫當中。是以,既然如此,每一台伺服器是如何追蹤使用者身份呢? 我們可以基于cookie機制來追蹤。

        一個使用者第一次來通路我們的伺服器的時候,比如把它分發到第一台伺服器上,這個伺服器會給它生成一個随機的,唯一的ID,并把它發給用戶端。用戶端會把它儲存在浏覽器的緩存路徑下或者存儲路徑下。這個内容會儲存在一個檔案中,這個檔案有它的适用範圍,比如它隻适用于通路某個域名下的哪一個URL時來使用。通常還有它的有效期,這就叫使用者的cookie。那麼使用者随後再一次的通路這個伺服器或者這個域名時,都會加上這個身份,都會自動帶上這麼一個資料。是以伺服器一看到它帶上這個資料,就會識别這個使用者的身份了。但是,隻識别它的身份,它還不能追蹤使用者的活動。比如使用者在目前伺服器上浏覽過多少商品,如何追蹤?

  • 胖cookie和瘦cookie

        傳統方式,每一個使用者在每一個站點上通路的所有行為,都一 一被記錄在這個cookie檔案中,當用戶端本地儲存,而後用戶端每一次通路的時候,都會帶着這個資訊去服務端。這是一種胖cookie機制(fat cookie)。但是fat cookie會有很大的風險,我們的單台主機之上,都有所謂的打着各種名義的或者以安全為名的軟體程式,它擁有你整個系統的最高控制權限,它可以輕易的掃描你的浏覽器下的每一個cookie上的所有資料,進而獲知使用者的通路行為。是以說胖cookie這種機制有可能會洩露使用者的隐私的。而且更重要的是,有些站點不希望去洩露使用者的隐私。比如某東的站點不希望使用者浏覽商品的行為被某寶的軟體擷取了,很顯然,對于大家來講可能是一種損失。是以,他們也不期望把這種使用者的行為記錄到用戶端,避免别人來擷取到這些資訊。是以現在都不再基于胖cookie來實作,而是每一個cookie僅用于追中使用者的身份。

        對于使用者的所有的行為,在站點上,對應站點應用程式的程序的内部,都會有自己的記憶體使用空間。會在這個程序的記憶體空間的區域中為每一個使用者配置設定一個資料結構,通常是hash類型的。每一個使用者在目前站點上做了什麼樣的通路行為,它都會有一個單獨的資料記錄位置。這裡記錄使用者的通路,并且記錄了是哪一個使用者的通路,它會和你cookie的值所綁定一起。是以使用者此後再通路,隻要帶來了cookie,我們識别了這個使用者,就會把這個使用者關聯到對應的資料結構的資料記錄之上,這個資料記錄,通常叫做session,服務端的session,服務端的會話。那麼,對于一個繁忙的站點來講,服務端的session可能會很多個。比如3千個并發可能是10萬個使用者發起的,那麼這裡有可能需要記錄10萬個session。

  • session 以及session的解決方案

        這樣一來,使用者第一請求,被配置設定到第一台伺服器上,session中記錄了使用者的行為,這個session資料儲存在第一台伺服器上,那麼使用者再請求,如果被分發到第二台伺服器上,那麼他的session資訊就沒了。第二台伺服器上是沒有這個使用者的配置相關的這些資料的。雖然你能看見那個網頁,看見那個商品,我們也能夠往購物車中加入,但是此前你加入的那個行為卻追蹤不到了。這對于使用者來講,可能會覺得莫名其妙,這對于負載均衡來講,這種機制就成為有狀态的了。我們需要去追蹤并記住使用者的狀态。這個該如何解決呢?一般而言,這種記錄會有三種方式。

    (1) 方法一,session粘性(會話粘性)

        做使用者綁定,隻要來自于同一個使用者的通路,始終發給同一台伺服器,不往其他伺服器上發。但是DNS好像沒有這種能力,DNS的A記錄是一個域名對應一條記錄,并且是輪循發送的。對于同一個域名來講,如果有多條A記錄,它是沒辦法始終把同一個使用者的請求綁定到某台主機之上,但有些是可以實作。那麼該如何識别一個請求是來自于同一個使用者呢,有兩個方案。

    方案一,根據網絡層的IP位址來識别,隻要來源的IP都相同,我們就當這是同一個使用者;

    方案二,對于web服務來講,可以使用cookie來識别,使用者的請求中隐含了cookie,隻要他的請求是明文的,我們就能看到他的cookie,甚至是密文的也沒關系,在負載均衡器上,我們可以解除安裝ssl請求,也能做到看見那個cookie。隻要cookie是同一個,我們就可以當作它是同一個使用者的請求。

    簡單的可以分析一下,方案二控制更加精準。對于方案一而言,對于有過網絡基礎的人可能知道,SNAT是網絡源位址轉換。對于大部分公司請求網際網路,可能都是通過同一個ip位址去請求通路網際網路,但是我們伺服器端如果基于方案一來判斷使用者,就隻能把它識别成同一個使用者,事實上,壓根不是同一個使用者。如果我們能基于cookie來識别的話,無論你的源IP是什麼,隻要你的cookie不同,都被識别成不同的使用者。是以方案二的粒度更加精細更加精準了。不管怎麼來講,這種方法都叫做會話粘性,由于實作把一個會話綁定在一個主機之上的的實作方式。

        但是這個方法(session 粘性) 有一個缺陷,如果把一個使用者的請求始終綁定到一台主機之上就意味着一組會話在單獨一台伺服器上了,一旦這個伺服器挂了,除非做了會話持久,等我們的伺服器啟動,這個使用者還能通路,這可能是3或5分鐘之後的事情了,這個使用者的請求并不能夠通過被分發到其他主機之上以解決使用者等待的問題,那麼這依然會是一個比較大的缺陷,于是就有了方法二來實作;

(2)方法二, session複制叢集(會話複制叢集)

    每一個主機的記憶體中都維持一組會話資訊。那麼,每一個伺服器的本地會話資訊都傳給其他伺服器一份,那麼叢集中的每一台伺服器就都擁有一個完整的會話。可以把兩台伺服器建構成一個會話叢集,進而讓每一台主機的每一個本地的會話都傳遞給同叢集中的其他主機。這個時候都不用綁定使用者身份了,主機可以随意被排程,随意被輪詢。這裡依然會有一個很重大的問題,每一台伺服器都儲存了整個叢集中所有會話的資訊。假設你叢集有10萬個使用者通路,每一台伺服器上都要儲存10萬個session,這得需要多大的資源空間,更重要的是,如果你的伺服器本身很繁忙,session會經常因為使用者的活動行為而被更新,大量的session資訊會在叢集中傳來傳去,那麼伺服器的帶寬就消耗的差不多了,如果有專用接口了的話,伺服器的資源也會被消耗的差不多。是以這種方法不适用于太大規模的叢集。因為這個方法二,有缺陷,是以有來方法三;

(3) 方法三,共享存儲(session server,會話伺服器)

    每一台伺服器所生成的session不儲存在自己的記憶體空間而儲存在一個記憶體伺服器中。為什麼不儲存在自己的記憶體空間中而儲存在記憶體伺服器,是因為要考慮到性能的問題。記憶體存儲伺服器能夠實作基于記憶體向其他伺服器提供所謂的存儲功能,是以每一台伺服器上的程序需要儲存會話和使用會話時,都到這個記憶體存儲伺服器上去擷取,每一次更新也都給你更新到這個記憶體存儲服務上去。那麼,大家通路的是同一組記憶體存儲伺服器,所得到的内容都應該是一樣的。這個機制叫session server,session伺服器。

PS:上面每一個環節可能解決起來很爽快,但是每一個節點都可能事關全局。比如我們的檔案節點挂了,得不到圖檔資料;mysql挂了,通過任何一個伺服器都得不到這個存儲的資料;session也一樣。通常把這些事關全局的,一台主機,一個服務,一個節點,一個事物故障會導緻整個叢集服務不可用的硬節點稱作為單點故障所在(Single Point Of Failure,SPoF).既然是單點故障,我們就要對它做其他的解決方案。

2.2、linux叢集類型

  • 何為叢集?

    通俗來講,為計算機集合,為解決某個特定問題組合起來形成的單個系統。也可以了解為叢集(cluster)表示聚集在一起的一類事物統稱。

  • linux叢集類型?

    (1) 負載均衡叢集

        負載均衡叢集的英文表示為 Load Balancing,簡稱為LB。是以我們通常會把負載均衡叢集叫做LB叢集或者LB cluster。LB 叢集主要提供和節點個數成正比的負載能力,這種叢集很适合提供大通路量的Web服務。負載均衡叢集往往也具有一定的高可用性特點。

    常見硬體實作有:F5 Big-IP,Citrix Netscaler,A10等;

    常見軟體實作有:LVS,nginx,haproxy,ats,perlbal,pound等;

    (2) 高可用叢集

        高可用叢集的英文表示為High Availiablity ,簡稱HA。是以我們通常會把負載均衡叢集叫做HA叢集或HA cluster。HA叢集一般是指當叢集中有某個節點失效的情況下,其上的任務會自動轉移到其他正常的節點上。還指可以将叢集中的某節點進行離線維護再上線,該過程并不影響整個叢集的運作。設計思想就是要最大限度地減少服務中斷時間。

    高可用叢集一般是通過系統的可靠性(reliability)和系統的可維護性(maintainability)來衡量的。通常用平均無故障時間(MTTF)來衡量系統的可靠性,用平均維護時間(MTTR)來衡量系統的可維護性。是以,一個高可用叢集服務可以這樣來定義:

    A=MTBF/(MTBF+MTTR)

    公式涉及的結果和簡稱說明:

MTTF(Average fault-free time):平均無故障時間;
MTBF(Mean Time Between Failure):平均故障間隔時間;
MTTR(Mean Time to Repair):平均恢複時間;
A表示這個結果,A的值在區間(0,1)之間。幾乎不可能有值為1的叢集,而且如果值為0,叢集将無任何意義。
(0,1):90%, 95%, 99%, 99.5%,  99.9%, 99.99%, 99.999%, 99.9999%
一般高可用叢集的标準有如下幾種:
99%:表示 一年不線上時間不超過87小時;
99.9% :表示一年不線上時間不超過8.7小時;
99.99%: 表示一年不線上時間不超過1小時;
99.999% :表示一年不線上時間不超過3-5分鐘;
大部分的叢集,多數控制在3個9或者4個9。
           

(3) 高性能叢集

高性能叢集英文為High Performance,簡稱為HP叢集或HP cluster。比如使用超級計算機或超算計算機這樣的應用。利用分布式系統來組織(包括分布式存儲和分布式計算)。這一類一般是科學研究或者極大規模才用得到,我們這裡了解一下即可。

2.3、linux叢集系統擴充方式

linux叢集系統擴充的兩個大的方向分為縱向擴充和橫向擴充:

Scale UP:縱向擴充或者叫向上擴充(用性能更好的主機),在我們第一章的概述部分就有提到這個概念;

Scale Out:橫向擴充或者叫向外擴充(組合多台主機來完成單個任務,将任務分散處理,簡單地說就是加機器),在我們第一章的概述部分就有提到這個概念;

PS:一般網際網路企業都是通過橫向擴充的思路來解決問題,當然也可能有部分解決思路是使用的第一種。我們上面一小節中提到的高性能叢集就是上述的第一種擴充。

2.4、linux叢集的排程方法

2.4.1、靜态排程算法

靜态排程算法,僅根據算法本身進行排程。包括:

(1) 輪詢(RR)

輪詢(roundrobin),簡單來說就是排程器将外部請求輪流配置設定到叢集中的節點中;

(2) 權重輪詢(WRR)

權重輪詢(Weighted RR),排程器根據事先設定的權重來配置設定外部請求到叢集中的節點。

(3) 原位址哈希(SH)

原位址哈希(Source Hashing),主要是實作會話粘性(session sticky),是基于原IP位址哈希。将來自于同一個IP位址的請求始終發往第一次挑中的後端real server(RS),進而實作會話綁定。

(4) 目标位址哈希(DH)

目标位址哈希(Destination Hashing),将發往同一個目标位址的請求始終轉發至第一次挑中的RS,典型使用場景是正向代理緩存場景中的負載均衡.

2.4.2、動态排程算法

動态排程算法,主要根據每後端real server 目前的負載狀态及排程算法進行排程。

(1) 最少連接配接(least connections,LC)

    排程器通過“最少連接配接”排程算法動态的将網絡請求排程到已經建立連接配接最少的伺服器上,如果叢集的真實伺服器具有相近的系統性能,采用“最小連接配接”排程算法可以更好地均衡負載。負載滿足以下公式:

Overhead=activeconns*256+inactiveconns
           

(2) 權重最少連接配接(Weighted least connections,WLC)

    在叢集系統中的伺服器性能差異較大的情況下,排程器采用權重最小連接配接的排程算法來優化負載均衡,具有較高權值的伺服器将承受較大比例的活動負載連接配接。負載滿足以下公式:

Overhead=(activeconns*256+inactiveconns)/weight
           

(3) 最短延遲排程(Shortest Expection Delay,SED)

    在WCL的基礎上改進,Overhead=(ACTIVE+1)*256/權重,不再考慮非活動狀态,把目前處于活動狀态的數目+1來實作,數目最小的接受下次請求,+1的目的是為為了考慮權重的時候,非活動連接配接過多的缺陷,當權限過大的時候,會導緻空閑伺服器一直處于無連接配接的狀态。負載滿足以下公式:

Overhead=(activeconns+1)*256/weight
           

(4) 用不排隊/最少隊列排程(Never Queue,NQ)

    無需列隊,如果有台real server的連接配接數為0,就直接就配置設定過去,不需要進行sed運算,保證不會有一個主機很空閑,在SED的基礎上不論增加幾個,第二次一定排程到下一台real server,不考慮非活動連接配接,才會用NQ,SED要考慮活動狀态連接配接,對于DNS的UDP不需要考慮非活動連接配接,而http的處于保持狀态就需要考慮非活動連接配接給伺服器的壓力。

(5) 基于局部的最少連接配接(Locality-Based Least connections,LBLC)

    基于局部性的最少連接配接排程算法是針對目标IP位址的負載均衡,目前主要運作在Cache叢集系統。該算法根據請求的目标IP位址找出該目标IP位址最近使用的伺服器,若該伺服器是可用而且沒有超載,将請求發送到該伺服器,若該伺服器不存在,或者該伺服器超載且有伺服器處于一半的工作負載,則用最少連接配接的原則選出一個可用的伺服器,将請求發送到該伺服器。

(6) 帶複制的基于局部性最少連接配接(LBLC with Replication)

    帶複制性的基于局部性最少連接配接排程算法也是針對目标IP位址的負載均衡,目前主要用在Cache叢集系統。它和LBLC算法不同的是它要維護從一個目标IP位址到一組伺服器的映射,而LBLC算法維護從一個目标IP到一台伺服器的映射,該算法根據一請求的目标IP位址找出該目标IP位址對應的伺服器組,按照最小連接配接原則伺服器組中選一台伺服器,若伺服器沒有超載,将請求發送到該伺服器,若伺服器超載,則按照最小連接配接原則從這個叢集中選出一台伺服器,将該伺服器加到服務組中,将請求發送到該伺服器,同時當該組伺服器有一段時間沒有被修改,将最忙的伺服器從服務組删除,以降低複制的程度。

三、LVS應用

3.1、lvs功能的實作

    lvs是附加在netfilter的input鈎子上的一段程式實作,簡單了解就是工作在INPUT鍊上,lvs的工作也是基于規則來實作的,由ipvsadm工具來配置政策或規則。下圖是基于之前iptables架構圖的幾個工作鍊的實作邏輯,然後配合上lvs部分。由于netfilter的過濾功能要經過INPUT鍊,是以lvs和這個是沖突的,比如你把通過INPUT鍊的封包先通過INPUT鍊上的規則DROP掉後,lvs上定義的叢集服務規則是無法有效工作的,一般如果要想使用lvs,不會配合netfilter防火牆的過濾功能。

架構基礎知識總結1

圖上标記含義:

a:PREROUTING鍊或prerouting鈎子
b:INPUT鍊或input鈎子
c:FORWARD鍊或forward鈎子
d:INPUT或input鈎子
e:POSTROUTING或postrouting鈎子
x:路由标志;
y:路由标志;
L:lvs程式附加處理;
           
  • lvs的ipvs和ipvsadm:

        lvs的實作邏輯由兩部分組成,一個是ipvs,一個是ipvsadm。其中ipvs是工作于核心空間的netfilter的input鈎子之上的架構,而ipvsadm是使用者空間的指令行工具,規則管理器,用于管理叢集服務及real server。

  • ipvsadm指令行工具用法
ipvsadm用法:
ipvsadm主要管理兩類事務,一類是叢集服務,一類是叢集服務上的realserver;
先定義叢集服務,也就是虛拟(叢集)服務,以後我們就叫叢集服務。然後支援對這個添加的叢集服務删、改以及
查詢,而且叢集服務可以定義多個。
先定義了叢集服務,然後我們可以在叢集服務的基礎上新增各real server,然後可以對對應叢集服務增、删、
改、查各realserver。

[[email protected] ~]$ sudo ipvsadm --help
ipvsadm v1.27 2008/5/15 (compiled with popt and IPVS v1.2.1)
Usage:
  ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine] [-b sched-flags]
  
  
  ipvsadm -D -t|u|f service-address
  ipvsadm -C
  ipvsadm -R
  ipvsadm -S [-n]
  ipvsadm -a|e -t|u|f service-address -r server-address [options]
  ipvsadm -d -t|u|f service-address -r server-address
  ipvsadm -L|l [options]
  ipvsadm -Z [-t|u|f service-address]
  ipvsadm --set tcp tcpfin udp
  ipvsadm --start-daemon state [--mcast-interface interface] [--syncid sid]
  ipvsadm --stop-daemon state
  ipvsadm -h
  
Commands:  #指令
Either long or short options are allowed.
  --add-service     -A        add virtual service with options,#新增一個叢集服務
  --edit-service    -E        edit virtual service with options,#修改一個叢集服務
  --delete-service  -D        delete virtual service,#删除一個叢集服務
  --clear           -C        clear the whole table  #清空所有
  --restore         -R        restore rules from stdin  #從标準輸入中恢複(叢集)規則,可以利用bash重定向特性把一個儲存了叢集規則的檔案加載到記憶體中
  --save            -S        save rules to stdout		#儲存(叢集)規則到标準輸出,可以利用bash重定向特性寫入到一個檔案
  --add-server      -a        add real server with options  #新增real server
  --edit-server     -e        edit real server with options #修改real server
  --delete-server   -d        delete real server #删除real server
  --list            -L|-l     list the table  #檢視叢集服務和檢視real server
  --zero            -Z        zero counters in a service or all services
  --set tcp tcpfin udp        set connection timeout values
  --start-daemon              start connection sync daemon
  --stop-daemon               stop connection sync daemon
  --help            -h        display this help message


Options:  #選項
  --tcp-service  -t service-address   service-address is host[:port]   #定義tcp協定叢集服務或real server的服務位址(host加端口);
  --udp-service  -u service-address   service-address is host[:port]   #定義udpp協定叢集服務或real server的服務位址(host加端口);
  --fwmark-service  -f fwmark         fwmark is an integer greater than zero #防火牆标記,它是一個大于0的整數;
  --ipv6         -6                   fwmark entry uses IPv6
  --scheduler    -s scheduler         one of rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq,  #定義叢集服務的排程方法。rr輪詢;wrr權重輪詢。
                                      the default scheduler is wlc.
  --pe            engine              alternate persistence engine may be sip,
                                      not set by default.
  --persistent   -p [timeout]         persistent service #設定持久連接配接逾時時長
  --netmask      -M netmask           persistent granularity mask
  --real-server  -r server-address    server-address is host (and port)
  --gatewaying   -g                   gatewaying (direct routing) (default)  預設值。表示dr類型(gateway)。
  --ipip         -i                   ipip encapsulation (tunneling) ipip,tun類型
  --masquerading -m                   masquerading (NAT)  位址僞裝,nat類型
  --weight       -w weight            capacity of real server  #設定rs伺服器的權重值
  --u-threshold  -x uthreshold        upper threshold of connections
  --l-threshold  -y lthreshold        lower threshold of connections
  --mcast-interface interface         multicast interface for connection sync
  --syncid sid                        syncid for connection sync (default=255)
  --connection   -c                   output of current IPVS connections #輸出目前IPVS的活動連結狀态
  --timeout                           output of timeout (tcp tcpfin udp)
  --daemon                            output of daemon information
  --stats                             output of statistics information #輸出統計資料
  --rate                              output of rate information #顯示速率資料
  --exact                             expand numbers (display exact values) #精确顯示計數器的值
  --thresholds                        output of thresholds information
  --persistent-conn                   output of persistent connection info
  --nosort                            disable sorting output of service/server entries
  --sort                              does nothing, for backwards compatibility
  --ops          -o                   one-packet scheduling
  --numeric      -n                   numeric output of addresses and ports  #數字格式顯示位址和端口,不會反解(反解ip會解析成主機名,ip會解析成協定或服務)
  --sched-flags  -b flags             scheduler flags (comma-separated)
           

核心中已經編譯進來ipvs的功能子產品,簡單檢視一下:

[[email protected] ~]$ ls -l /boot/config-3.10.0-229.el7.x86_64 
-rw-r--r--. 1 root root 123838 Mar  6  2015 /boot/config-3.10.0-229.el7.x86_64
[[email protected] ~]$ grep -i 'ipvs' -C 5 /boot/config-3.10.0-229.el7.x86_64 
......省略
CONFIG_NETFILTER_XT_MATCH_IPVS=m
......省略
# IPVS transport protocol load balancing support #IPVS支援的協定
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y
#
# IPVS scheduler #IPVS排程方法
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
--
CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
#
# IPVS SH scheduler
#
CONFIG_IP_VS_SH_TAB_BITS=8

#
# IPVS application helper
#
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PE_SIP=m
           

在要模拟成director主機上安裝ipvsadm即可:

[[email protected] ~]$ sudo yum info ipvsadm
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.cn99.com
 * epel: mirrors.tuna.tsinghua.edu.cn
 * extras: mirrors.shu.edu.cn
 * updates: centos.ustc.edu.cn
Installed Packages
Name        : ipvsadm
Arch        : x86_64
Version     : 1.27
Release     : 7.el7
Size        : 75 k
Repo        : installed  #我這裡是已經安裝了的
From repo   : base
Summary     : Utility to administer the Linux Virtual Server
URL         : https://kernel.org/pub/linux/utils/kernel/ipvsadm/
License     : GPLv2+
Description : ipvsadm is used to setup, maintain, and inspect the virtual server
            : table in the Linux kernel. The Linux Virtual Server can be used to
            : build scalable network services based on a cluster of two or more
            : nodes. The active node of the cluster redirects service requests to a
            : collection of server hosts that will actually perform the
            : services. Supported Features include:
            :   - two transport layer (layer-4) protocols (TCP and UDP)
            :   - three packet-forwarding methods (NAT, tunneling, and direct routing)
            :   - eight load balancing algorithms (round robin, weighted round robin,
            :     least-connection, weighted least-connection, locality-based
            :     least-connection, locality-based least-connection with
            :     replication, destination-hashing, and source-hashing)
如果沒有安裝,執行yum安裝以下即可:
sudo yum install ipvsadm
           

3.2、lvs四種叢集優點和使用場景

為了更好的了解lvs叢集,需要了解一下關鍵的術語:

vs:Virtual Server, Director, Dispatcher, Balancer。排程器,負載均衡器,分發器或者叫虛拟伺服器;
rs:Real Server, upstream server, backend server。真實伺服器、負載均衡伺服器,後端伺服器
CIP:Client IP, VIP: Virtual serve IP, RIP: Real server IP, DIP: Director IP。用戶端IP,虛拟IP,真實IP,排程器IP。
CIP <--> VIP == DIP <--> RIP 

請求用戶端ip,我們叫用戶端主機,用戶端主機的接口叫用戶端ip(簡稱CIP);
虛拟伺服器面向用戶端一側的接口叫虛拟伺服器ip(簡稱VIP)。Director主機用于與後端主機通信的,
此時,它就扮演了一個排程器,面向RS一側的接口叫排程器ip(簡稱DIP);
每一個Real Server的IP簡稱RIP。

           

如圖所示:

架構基礎知識總結1

lvs叢集的可以分為以下四類:(比較重要,要能通俗講解)

lvs-nat:修改請求封包的目标IP(和目标端口);多目标IP的DNAT;

lvs-dr:操縱封裝新的MAC位址;(不會修改請求封包的源IP,目标IP,源端口以及目标端口)

lvs-tun:在原請求IP封包之外新加一個IP首部;(原來的一級源IP,目标IP。現在加了一級,實作了兩級IP首部,這種叫基于IP來運載IP,是以和隧道很相似,是以叫隧道模型)

lvs-fullnat:修改請求封包的源和目标IP(以及源端口和目标端口);

如果按照請求封包和響應封包經過director分類:

  • 請求封包和響應封包都經過Director

    lvs-nat和lvs-fullnat

    lvs-nat:關鍵要點,RIP的網關要指向DIP;

    lvs-fullnat:關鍵要點,RIP和DIP未必在同一個網絡,但是要能通信;

  • 請求封包要經過Director,但響應封包由RS直接發往client

    lvs-dr和lvs-tun

    lvs-dr:關鍵要點,通過封裝新的MAC首部實作,通過MAC網絡轉發;

    lvs-tun:關鍵要點,通過在原IP封包之外封裝新的IP封包實作轉發,支援遠距離通信。

(1) lvs-nat

特性:
多目标IP的DNAT,通過将請求封包中的目标位址和目标端口修改為某挑出的RS的RIP和PORT實作轉發
(1)RIP和DIP必須在同一個IP網絡,且應該使用私網位址;RS的網關要指向DIP;
(2)請求封包和響應封包都必須經由Director轉發;Director易于成為系統瓶頸;(請求封包通過以GET方法居多
是以請求封包一般很小。但是響應封包要附帶請求的資料,是以會很大)
(3)支援端口映射,可修改請求封包的目标PORT;
(4)vs必須是Linux系統,rs可以是任意系統;

優點:配置簡單,且節省IP。隻需要在排程器上配置一個公網IP即可。支援端口映射,即使用者請求的端口和RS端
口可以不一緻;

缺點:所有請求和響應都要經由排程器,并發量大時會成為叢集瓶頸。一般後端RS節點保持在10-20個(沒有實際
測試過,具體不知道。對于超大并發的場景,lvs的nat模型結構可想而知前段排程器壓力);

使用場景:由于配置簡單,節省IP的特點,一般用在并發量不大的中小企業。
           

(2) lvs-dr

Direct Routing,直接路由;

通過為請求封包重新封裝一個MAC首部進行轉發,源MAC是DIP所在的接口的MAC,目标MAC是某挑選出的RS的RIP所在接口的MAC位址;源IP/PORT,以及目标IP/PORT均保持不變(不支援端口映射);

Director和各RS都得配置使用VIP;

(1) 確定前端路由器将目标IP為VIP的請求封包發往Director:
	(a) 在前端網關做靜态綁定;(不适用)
	(b) 在RS上使用arptables;
	(c) 在RS上修改核心參數以限制arp通告及應答級别;
		arp_announce
		arp_ignore
(2) RS的RIP可以使用私網位址,也可以是公網位址;RIP與DIP在同一IP網絡;RIP的網關不能指向DIP,以確定響應封包不會經由Director;
(3) RS跟Director要在同一個實體網絡(要基于MAC位址進行封包轉發,是以不能經過路由器,經過交換機可以);
(4) 請求封包要經由Director,但響應不能經由Director,而是由RS直接發往Client;
(5) 不支援端口映射;

優點:RS處理完請求後是直接響應給客戶主機的,不會經由排程器,進而大大減輕了排程器的負擔,增加了叢集
的并發請求處理量;

缺點:配置較複雜,需要在所有RS上配置VIP并修改核心參數。DR類型是通過重新封裝請求封包的標頭檔案的
MAC位址來實作轉發的,是以排程器和RS隻能在一個區域網路内(無法實作後端的RS異地災備)。DR類型相對于NAT類型需要消耗更多的公網IP;

使用場景:并發量非常大的情況下會用到此類型,DR模型的并發處理量能達到硬體級别的能力。
           

(3) lvs-tun

lvs-tun:
	轉發方式:不修改請求封包的IP首部(源IP為CIP,目标IP為VIP),而是在原IP封包之外再封裝一個IP首部(源IP是DIP,目标IP是RIP),将封包發往挑選出的目标RS;RS直接響應給用戶端(源IP是VIP,目标IP是CIP);
	
	(1) DIP, VIP, RIP都應該是公網位址;
	(2) RS的網關不能,也不可能指向DIP;
	(3) 請求封包要經由Director,但響應不能經由Director;
	(4) 不支援端口映射;
	(5) RS的OS得支援隧道功能;

優點:解決了DR類型下RS與排程器必須在同一區域網路的限制;

缺點:配置繁瑣,應用場景少;而且由于要額外給請求封包封裝一層IP封包,是以對于請求封包攜帶較多資料
的場景(雖然這種場景少,但是也不是沒有。比如請求向資料庫寫入一大串字元串),會導緻請求封包大小超過
MTU預設大小。會有巨型幀的概念(指有效負載超過IEEE 802.3标準所限制的1500位元組的以太網幀),有巨型
幀會導緻每一次請求封包會被切片,造成效率不高的問題。

使用場景:如果環境要求DIP與RIP不在同一實體網絡(如災備)時,就需要用到lvs-tun模型。
           

(4) lvs-fullnat

通過同時修改請求封包的源IP位址和目标IP位址進行轉發;
	CIP <--> DIP 
	VIP <--> RIP 

(1) VIP是公網位址,RIP和DIP是私網位址,且通常不在同一IP網絡;是以,RIP的網關一般不會指向DIP;
(2) RS收到的請求封包源位址是DIP,是以,隻能響應給DIP;但Director還要将其發往Client;
(3) 請求和響應封包都經由Director;
(4) 支援端口映射;

優點:相比于NAT的區域網路,FULLNAT是相對于沒有那麼局限,它是限制在内網中的。對于運維比較友善。
(解決了lvs-tun類型的笨重,因為做異地災備的還是挺少的。一般是在大的辦公大樓,不同機房。)也支援端口
映射。

缺點:請求封包和響應封包都要經過director,director壓力過大。
配置複雜。而且還不是LVS标準類型,如果要用。還要有自定義的能力,比如打更新檔等。
而且ipvsadm也不支援這種類型,要自己寫工具實作。

使用場景:人比較少,肯投了的場景。(俗稱人少錢多)

注意:此類型預設不支援。要想時要此功能,要編譯核心打更新檔,比較複雜。屬于理論類型,
沒有能力一般實作不了。沒有被收錄進LVS官方标準類型。

           

3.3、LVS-NAT和LVS-DR的原理和實作舉例,LVS-FUN和LVS-FULLNAT簡單圖解

3.3.1、LVS的NAT類型

LVS的NAT類型滿足以下概要說明概要說明的特點:

實作:多目标IP的DNAT,通過将請求封包中的目标位址和目标端口修改為某挑出的RS的RIP和PORT實作轉發;
(1) RIP和DIP必須在同一個IP網絡,且應該使用私網位址;RS的網關要指向DIP;
(2) 請求封包和響應封包都必須經由Director轉發;Director易于成為系統瓶頸;
(3) 支援端口映射,可修改請求封包的目标PORT;
(4) vs必須是Linux系統,rs可以是任意系統;

           

lvs-nat模式的請求封包和響應封包圖解:

架構基礎知識總結1

工作邏輯簡述:

lvs的nat模型有點類似于之前iptables中講到的DNAT(目标位址轉換),和DNAT幾乎一樣。
不同的是,LVS的nat模型中後端主機有多個,而且實作方式不在iptables的PREROUTING鍊上,而是在iptables
的INPUT鍊上(是以要想用lvs,就不能用到iptables的INPUT鍊的功能)。當使用者請求達到時,在INPUT鍊上的規則
監控到了這個叢集服務,會把請求封包的目标IP改成後端某一個被挑選出來的主機的RIP位址。并強行把封包送
到POSTROUTING鍊上後離開本機,然後到對應的RS上去了。
不管後端排程的是哪一台RS,用戶端發往VIP的請求封包,收到的都是VIP的響應封包。這種節奏不能變。如上
圖解請求封包的目标ip被改變了,而響應封包的源IP被改變了。請求封包的目标IP是如何改的,此前說的DNAT,是需要我們手動指定要修改的目标IP。有了LVS之後,請求封包到底被發往哪一個後端主機,我們自己是不能定
義的,是由排程器根據排程算法從後端多個可用的RIP中挑選出來的,而非固定的。這種被挑選就是通過排程算
法來控制的。
VIP應該是一個公網位址。DIP應該是一個私網位址。各後端主機為了達到隐藏的目的,要和DIP一樣,都應該是
一個私網位址。而且為了讓響應封包的源IP是VIP,必須要把各後端的RIP的網關指向DIP。

           

實驗環境說明:

用戶端主機:172.16.0.88
排程器主機:
    VIP:172.16.0.61
    DIP:192.168.10.254
後端主機1:192.168.10.11
後端主機2:192.168.10.12
虛拟機環境說明:172.16.0.0/16網段是我家庭網絡的橋接網段。我要把這個網段模拟成外網環境,實際并不是。
為了減少實驗難度,就讓用戶端主機和排程器主機在同一個網絡。實際應用場景,VIP和CIP都是真實的外網環
境,而且CIP請求VIP可能要經過層層路由而到達。後端主機的RIP是一個僅主機模式的接口,它們的網關配置
指向了排程器的DIP(192.168.10.254)。排程器要想中轉封包,要開啟防火牆的核心轉發功能。

排程器的yum倉庫可用epel和base,而且可以指向網際網路,是以這個沒必要說,它自己的時鐘同步指向網際網路。
通過chronyd來同步。它自己本身也是一個時鐘伺服器,可以被後端的RS同步使用。
各RS的時鐘不同指向DIP,通過chronyd來同步。

排程器主機上有安裝ipvsadm軟體包,這個用來編寫lvs規則用的。然後防火牆示範lvs的nat模式沒有開啟。預設我
關閉來selinux,firewalld。iptables政策就算INPUT有規則,也無法功能。
RS上安裝了nginx,httpd,telnet-server等伺服器,為的的示範需要。為了需要,我給它們挂載來CD光牒,然後配置
了yum指向自己配置的CD光牒。

           

實驗環境圖:

架構基礎知識總結1

實驗環境簡單檢視:

#director有兩塊網卡,eno16777736是VIP,eno33554984是DIP
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.61  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:febb:6862  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:bb:68:62  txqueuelen 1000  (Ethernet)
        RX packets 1506671  bytes 1072035825 (1022.3 MiB)
        RX errors 0  dropped 11  overruns 0  frame 0
        TX packets 997524  bytes 88755408 (84.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eno33554984: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.254  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::20c:29ff:febb:686c  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:bb:68:6c  txqueuelen 1000  (Ethernet)
        RX packets 41  bytes 5420 (5.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 25  bytes 1818 (1.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 149  bytes 13112 (12.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 149  bytes 13112 (12.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

後端RS1:rip1是eno16777736,其ip為192.168.10.11,網關指向DIP,192.168.10.254
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.11  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::20c:29ff:fe18:8676  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:18:86:76  txqueuelen 1000  (Ethernet)
        RX packets 532600  bytes 52940708 (50.4 MiB)
        RX errors 0  dropped 11  overruns 0  frame 0
        TX packets 770085  bytes 567926043 (541.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 83  bytes 5282 (5.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 83  bytes 5282 (5.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[[email protected] ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.10.254  0.0.0.0         UG    100    0        0 eno16777736
192.168.10.0    0.0.0.0         255.255.255.0   U     100    0        0 eno16777736

後端RS2:rip2是eno16777736,其ip為192.168.10.12,網關指向DIP,192.168.10.254
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.12  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::20c:29ff:fe99:19a4  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:99:19:a4  txqueuelen 1000  (Ethernet)
        RX packets 536180  bytes 53205796 (50.7 MiB)
        RX errors 0  dropped 11  overruns 0  frame 0
        TX packets 771806  bytes 568494213 (542.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 85  bytes 5414 (5.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 85  bytes 5414 (5.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

配置RS1上nginx的測試通路站點檔案:
[[email protected] ~]$ sudo vim /usr/share/nginx/html/test1.html 
[[email protected] ~]$ cat /usr/share/nginx/html/test1.html
<h1>RS1,192.168.10.11 </h1>
[[email protected] ~]$ sudo systemctl start nginx.service 
[[email protected] ~]$ ps aux|grep nginx
root       8868  0.0  0.9 124976  2116 ?        Ss   00:18   0:00 nginx: master process /usr/sbin/nginx
nginx      8869  0.0  1.3 125364  3144 ?        S    00:18   0:00 nginx: worker process

配置RS2上nginx的測試通路站點檔案:
[[email protected] ~]$ sudo vim /usr/share/nginx/html/test1.html 
[[email protected] ~]$ cat /usr/share/nginx/html/test1.html
<h1>RS2,192.168.10.12 </h1>
[[email protected] ~]$ sudo systemctl start nginx.service
[[email protected] ~]$ ps aux|grep nginx
root       8763  0.0  0.9 124976  2112 ?        Ss   00:18   0:00 nginx: master process /usr/sbin/nginx
nginx      8764  0.0  1.3 125364  3140 ?        S    00:18   0:00 nginx: worker process
yanhui     8766  0.0  0.4 112640   960 pts/1    S+   00:18   0:00 grep --color=auto nginx

先在排程器上簡單通路一下:
[[email protected] ~]$ curl http://192.168.10.11/test1.html
<h1>RS1,192.168.10.11 </h1>
[[email protected] ~]$ curl http://192.168.10.12/test1.html
<h1>RS2,192.168.10.12 </h1>
#vs,rs1,rs2要時間同步,沒有誤差。可以自行配置實作。這裡就省略啦。簡單看看時間是同步的:
[[email protected] ~]$ date
Tue Jan 15 00:23:13 CST 2019
[[email protected] ~]$ date
Tue Jan 15 00:23:18 CST 2019
[[email protected] ~]$ date
Tue Jan 15 00:23:23 CST 2019

#打開排程器的伺服器核心轉發功能
[[email protected] ~]$ sudo sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
[[email protected] ~]$ cat /proc/sys/net/ipv4/ip_forward
1

配置叢集服務1(把tcp協定的80端口定義為一個叢集服務,然後使用輪詢排程方法):
[[email protected] ~]$ sudo ipvsadm -A -t 172.16.0.61:80 -s rr 
[[email protected] ~]$ sudo ipvsadm -Ln #-L要在-n前邊,不能使用-nL組合
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 rr

向剛才定義的tcp的80端口的叢集服務添加後端real server:
[[email protected] ~]$ sudo ipvsadm -a -t 172.16.0.61:80 -r 192.168.10.11 -m
[[email protected] ~]$ sudo ipvsadm -a -t 172.16.0.61:80 -r 192.168.10.12 -m
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 rr
  -> 192.168.10.11:80             Masq    1      0          0         
  -> 192.168.10.12:80             Masq    1      0          0    

用戶端上測試叢集通路:
#如果不能通路,請确認一下你Director主機的核心轉發功能是否有開啟
[[email protected] ~]$ for i in {1..10};do
> curl http://172.16.0.61/test1.html
> done
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
#可以仔細觀察上面的叢集伺服器響應主機的結果,是按照後端主機輪詢的方式響應的


修改後端被排程主機的權重值:
[[email protected] ~]$ sudo ipvsadm -e -t 172.16.0.61:80 -r 192.168.10.11 -m -w 2 
[[email protected] ~]$ sudo ipvsadm -e -t 172.16.0.61:80 -r 192.168.10.12 -m -w 3
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 rr
  -> 192.168.10.11:80             Masq    2      0          0         
  -> 192.168.10.12:80             Masq    3      0          0 
#預設輪詢rr排程方法,後端主機的權重即使不一樣,也沒有效果,現在我們還要把叢集服務的排程方法修改成wrr

修改叢集服務的排程方法為權重輪詢:
[[email protected] ~]$ sudo ipvsadm -E -t 172.16.0.61:80 -s wrr
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 wrr
  -> 192.168.10.11:80             Masq    2      0          0         
  -> 192.168.10.12:80             Masq    3      0          0   


用戶端測試叢集通路情況:
[[email protected] ~]$ for i in {1..10};do curl http://172.16.0.61/test1.html; done
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
[[email protected] ~]$ for i in {1..10};do curl http://172.16.0.61/test1.html; done
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS1,192.168.10.11 </h1>
#從結果來看,雖然不是一直3比1,但是有個規則,先2:1,然後1:1,然後2:1,然後1:1,如此反複。總結果就是
3:2

讓一個後端RS不再接受請求的方式有兩種:設定它的權重為0;把它從叢集中删除或移除;
(1) 設定權重為0就是修改
[[email protected] ~]$ sudo ipvsadm -e -t 172.16.0.61:80 -r 192.168.10.11 -m -w 0
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 wrr
  -> 192.168.10.11:80             Masq    0      0          0         
  -> 192.168.10.12:80             Masq    3      0          0   
測試用戶端通路結果:
[[email protected] ~]$ for i in {1..10};do curl http://172.16.0.61/test1.html; done
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>
<h1>RS2,192.168.10.12 </h1>

(2) 從叢集服務中移除RS
[[email protected] ~]$ sudo ipvsadm -d -t 172.16.0.61:80 -r 192.168.10.11 
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.61:80 wrr
  -> 192.168.10.12:80             Masq    3      0          30   

#其他的就不示範了。LVS負載均衡叢集服務中有後端RS異常,叢集服務本身不能做到移除這個RS,還是會排程
請求到異常的後端主機上去。此時,就需要借助其他輔助程式來配合使用,而實際使用場景中,Director要做高可
用叢集,有些高可用叢集實作程式本身就支援這種後端RS監控狀态監測機制,可以實作把後端異常的主機移除,
修複後可以自動上線等等。
           

3.3.2、LVS的DR類型

LVS的DR類型滿足以下概要說明的特點:

Direct Routing,直接路由;
通過為請求封包重新封裝一個MAC首部進行轉發,源MAC是DIP所在的接口的MAC,目标MAC是某挑選出的RS
的RIP所在接口的MAC位址;源IP/PORT,以及目标IP/PORT均保持不變;
Director和各RS都得配置使用VIP;

(1) 確定前端路由器将目标IP為VIP的請求封包發往Director:
	(a) 在前端網關做靜态綁定;
	(b) 在RS上使用arptables;
	(c) 在RS上修改核心參數以限制arp通告及應答級别;
		arp_announce
		arp_ignore
(2) RS的RIP可以使用私網位址,也可以是公網位址;RIP與DIP在同一IP網絡;RIP的網關不能指向DIP,以確定響應封包不會經由Director;
(3) RS跟Director要在同一個實體網絡;
(4) 請求封包要經由Director,但響應不能經由Director,而是由RS直接發往Client;

           

lvs-dr模式的請求封包和響應封包的圖解:

架構基礎知識總結1
架構基礎知識總結1

實驗環境說明:

用戶端主機:172.16.0.88
排程器主機:
    VIP:172.16.0.61
    DIP:192.168.10.254(假設這個ip我們就不禁止,就當做内網ip)
後端主機1:172.16.0.62。lo網卡接口位址别名(lo:0)上配置來vip,為了是先讓交換機丢過來的請求封包經過lo接
口;為了是讓從RS出去的響應封包的原位址是lo:0上的VIP。因為linux核心有個特點,先經過那個網卡的封包,
出去的封包的原位址就是誰。(還要通過arptables或者通過核心參數,控制lo:0接口的arp廣播和arp廣播通告)
後端主機2:172.16.0.63。lo網卡接口位址别名(lo:0)上配置了vip;為了是先讓交換機丢過來的請求封包經過lo接口;
虛拟機環境說明:172.16.0.0/16網段是我家庭網絡的橋接網段。假設這個網段是模拟的外網網段。

排程器的yum倉庫可用epel和base,而且可以指向網際網路,是以這個沒必要說,它自己的時鐘同步指向網際網路。
通過chronyd來同步。它自己本身也是一個時鐘伺服器,可以被後端的RS同步使用。
各RS的時鐘不同指向DIP,通過chronyd來同步。

排程器主機上有安裝ipvsadm軟體包,這個用來編寫lvs規則用的。然後防火牆示範lvs的nat模式沒有開啟。預設我
關閉來selinux,firewalld。iptables政策就算INPUT有規則,也無法功能。
RS上安裝了nginx,httpd,telnet-server等伺服器,為的的示範需要。

解決位址沖突配置說明:
dr模型中,各主機上均需要配置VIP,解決位址沖突的方式有三種:
	(1) 在前端網關做靜态綁定;(不适合)
	(2) 在各RS使用arptables;(需要額外安裝和使用arptables,可以實作)
	(3) 在各RS修改核心參數,來限制arp響應和通告的級别;(可以實作,較第二種方法簡單)
		限制響應級别:arp_ignore
			0:預設值,表示可使用本地任意接口上配置的任意位址進行響應;
			1: 僅在請求的目标IP配置在本地主機的接收到請求封包接口上時,才給予響應;
		限制通告級别:arp_announce
			0:預設值,把本機上的所有接口的所有資訊向每個接口上的網絡進行通告;
			1:盡量避免向非直接連接配接網絡進行通告;
			2:必須避免向非本網絡通告;

           
架構基礎知識總結1

通告和響應簡述:

假設A主機有三個網絡接口,分别是B,C,D。B所在網絡為2.1,C所在網絡為3.1,D所在網絡為1.1。
預設主機A的行為,在網絡領域有一個通告和響應的概念。B,C,D三個網絡接口都對應一個MAC,假設
分别為B-MAC,C-MAC,D-MAC。與D直連網絡是1.0,其中網絡中一個一個主機是s1,對應ip是1.2,mac是
s1-mac。與B直連網絡是2.0,其中網絡中一個主機是s2,對應ip是2.3,mac是s2-mac.C直連的網絡是3.0,對應
網絡中有一個主機是s3,對應ip是3.2。

預設行為是A主機會通告給1.0網絡,2.0網絡,3.0網絡,它的三個接口B,C,D的資訊,包括IP和MAC位址。
D的直連網絡是1.0,B的直連網絡是2.0,C的直連網絡是3.0.由于這種預設行為,如果有一天有台2.2的機器去請
求D接口,并告知,我需要和2.3主機通信,請告訴我2.3主機的MAC位址,經過arp廣播後,A主機會告知它自己
B接口,并知道B接口所在網絡的s2主機的mac位址的,這種屬于arp響應,每個接口所在網絡都知道A主機的三個
接口的資訊,這個是A主機預設通告行為促成。
           

實驗環境簡單配置:

(1) director初始狀态:(相比nat,這裡隻需要一個接口,如果是配置VIP,可以配置一個别名即可)
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.61  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:febb:6862  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:bb:68:62  txqueuelen 1000  (Ethernet)
        RX packets 84368  bytes 60108647 (57.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 55860  bytes 4974867 (4.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

(2) RS1初始狀态(還未配置lo:0的vip位址)
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.62  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:fe18:8676  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:18:86:76  txqueuelen 1000  (Ethernet)
        RX packets 52285  bytes 9958142 (9.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 58891  bytes 36026131 (34.3 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 42  bytes 2792 (2.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 42  bytes 2792 (2.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
(3) RS2初始狀态(還未配置lo:0的vip位址)
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.63  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:fe99:19a4  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:99:19:a4  txqueuelen 1000  (Ethernet)
        RX packets 55280  bytes 10185276 (9.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 60633  bytes 36617412 (34.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 49  bytes 3376 (3.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 49  bytes 3376 (3.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
PS:時間,yum倉庫,實驗服務我就不說了,這些都是基礎,還有配置首頁什麼的,也不提供了。
簡單看看:
RS1站點的測試的靜态資源和測試的動态資源:
[[email protected] ~]$ cat /var/www/html/phpinfo.php 
<h1>RS1</h2>
<?php
    phpinfo();
?>
[[email protected] ~]$ cat /var/www/html/test1.html 
<h1>RS1,172.16.0.62</h1>

RS2的httpd站點的測試的靜态資源和測試的動态資源:(為了看出效果,這裡有意把資源内容定義不一樣,實際
生産應用要一樣的)
[[email protected] ~]$ cat /var/www/html/phpinfo.php 
<h1>RS2</h2>
<?php
    phpinfo();
?>
[[email protected] ~]$ cat /var/www/html/test1.html 
<h1>RS2,172.16.0.63</h1>

配置arp通告和arp響應的簡單檢視:
[[email protected] ~]$ ls -l /proc/sys/net/ipv4/conf/
total 0
dr-xr-xr-x 1 root root 0 Jan 12 23:43 all
dr-xr-xr-x 1 root root 0 Jan 14 01:15 default
dr-xr-xr-x 1 root root 0 Jan 14 01:15 eno16777736
dr-xr-xr-x 1 root root 0 Jan 12 23:43 lo
#all表示所有,lo和eno16777736表示指定單個接口。

這裡有個實作禁止通告和響應的功能以及配置lo:0接口vip位址的功能的bash腳本;
[[email protected] ~]$ pwd
/home/yanhui
[[email protected] ~]$ ls -l nomal_setparam.sh 
-rw-r--r-- 1 root root 795 Jan 12 23:58 nomal_setparam.sh
[[email protected] ~]$ cat nomal_setparam.sh 
#! /bin/bash

vip=172.16.0.199
mask=255.255.255.255 #為了讓它自己和自己在一個網絡,也隻廣播給自己,是以這樣定義
i

case $1 in
start)
    echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 1 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_ignore
    echo 2 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce
    echo 2 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_announce
    
    ifconfig $iface $vip netmask $mask broadcast $vip up
    route add -host $vip dev $iface
    ;;
stop)
    
    ifconfig $iface down
    echo 0 | sudo tee  /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 0 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_ignore
    echo 0 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce
    echo 0 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_announce
    ;;
*)
    echo "Usage: $(basename $0) start|stop"
    exit 1
    ;;
esac

RS1上執行這個腳本:
[[email protected] ~]$ sudo bash nomal_setparam.sh start
1
1
2
2
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.62  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:fe18:8676  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:18:86:76  txqueuelen 1000  (Ethernet)
        RX packets 56198  bytes 10306939 (9.8 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 64372  bytes 40006574 (38.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 42  bytes 2792 (2.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 42  bytes 2792 (2.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 172.16.0.199  netmask 255.255.255.255
        loop  txqueuelen 0  (Local Loopback)
[[email protected] ~]$ cat /proc/sys/net/ipv4/conf/{all,lo}/{arp_announce,arp_ignore} 
2
1
2
1

RS2上執行這個腳本:
[[email protected] ~]$ sudo bash nomal_setparam.sh start
1
1
2
2
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.63  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:fe99:19a4  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:99:19:a4  txqueuelen 1000  (Ethernet)
        RX packets 59542  bytes 10566445 (10.0 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 66675  bytes 40996952 (39.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 49  bytes 3376 (3.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 49  bytes 3376 (3.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 172.16.0.199  netmask 255.255.255.255
        loop  txqueuelen 0  (Local Loopback)

[[email protected] ~]$ cat /proc/sys/net/ipv4/conf/{all,lo}/{arp_announce,arp_ignore} 
2
1
2
1

#為了讓封包先從RS的lo:0進來,我們需要給每個後端的RS添加一個主機路由條目,下面是單獨執行的過程。
如果內建到了腳本中,就可以忽略了,我上面給的腳本內建了,這裡隻是簡單示範添加和删除路由。
我執行腳本後有添加上這個主機路由,然後為了示範,特意删除了的。
RS1:
[[email protected] ~]$ sudo route del -host 172.16.0.199 #純粹為了示範增删路由
[[email protected] ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.1      0.0.0.0         UG    100    0        0 eno16777736
172.16.0.0      0.0.0.0         255.255.0.0     U     100    0        0 eno16777736
[[email protected] ~]$ sudo route add -host 172.16.0.199 dev lo:0
[[email protected] ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.1      0.0.0.0         UG    100    0        0 eno16777736
172.16.0.0      0.0.0.0         255.255.0.0     U     100    0        0 eno16777736
172.16.0.199    0.0.0.0         255.255.255.255 UH    0      0        0 lo

RS2:
[[email protected] ~]$ sudo route del -host 172.16.0.199
[[email protected] ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.1      0.0.0.0         UG    100    0        0 eno16777736
172.16.0.0      0.0.0.0         255.255.0.0     U     100    0        0 eno16777736
[[email protected] ~]$ sudo route add -host 172.16.0.199 dev lo:0
[[email protected] ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.1      0.0.0.0         UG    100    0        0 eno16777736
172.16.0.0      0.0.0.0         255.255.0.0     U     100    0        0 eno16777736
172.16.0.199    0.0.0.0         255.255.255.255 UH    0      0        0 lo


RS1啟動httpd服務:
[[email protected] ~]$ sudo systemctl start httpd.service
[[email protected] ~]$ ps aux|grep httpd
root       5529  1.2  6.1 404100 14012 ?        Ss   01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5531  0.0  3.3 404232  7744 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5532  0.0  3.3 404232  7744 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5533  0.0  3.3 404232  7744 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5534  0.0  3.3 404232  7744 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5535  0.0  3.3 404232  7744 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
yanhui     5537  0.0  0.4 112640   956 pts/0    R+   01:30   0:00 grep --color=auto httpd

RS2啟動httpd服務:
[[email protected] ~]$ sudo systemctl start httpd.service
[[email protected] ~]$ ps aux|grep httpd
root       5481  2.0  6.1 404100 14012 ?        Ss   01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5483  0.0  3.3 404232  7740 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5484  0.0  3.3 404232  7740 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5485  0.0  3.3 404232  7740 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5486  0.0  2.9 404232  6760 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache     5487  0.0  3.2 404232  7508 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
yanhui     5489  0.0  0.4 112640   960 pts/0    S+   01:30   0:00 grep --color=auto httpd

在前端主機(director主機)上直接請求測試一下這兩台RS的RIP接口的80通路情況:
[[email protected] ~]$ curl http://172.16.0.62/test1.html
<h1>RS1,172.16.0.62</h1>
[[email protected] ~]$ curl http://172.16.0.63/test1.html
<h1>RS2,172.16.0.63</h1>
[[email protected] ~]$ curl -I http://172.16.0.62/phpinfo.php
HTTP/1.1 200 OK
Date: Sun, 13 Jan 2019 17:32:04 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
X-Powered-By: PHP/5.4.16
Content-Type: text/html; charset=UTF-8

[[email protected] ~]$ curl -I http://172.16.0.63/phpinfo.php
HTTP/1.1 200 OK
Date: Sun, 13 Jan 2019 17:32:15 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
X-Powered-By: PHP/5.4.16
Content-Type: text/html; charset=UTF-8

在Director上配置VIP位址(172.16.0.199),因為要通過實體網卡eno16777736接進來請求封包,并通過實體網卡
轉發封包給交換機。是以VIP也要配置到實體網卡上,我們可以配置網卡别名來實作:
[[email protected] ~]$ sudo ifconfig eno16777736:0 172.16.0.199 netmask 255.255.255.255 broadcast 172.16.0.199 up
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.61  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:febb:6862  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:bb:68:62  txqueuelen 1000  (Ethernet)
        RX packets 113955  bytes 80856593 (77.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 76000  bytes 6823007 (6.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eno16777736:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.199  netmask 255.255.255.255  broadcast 172.16.0.199
        ether 00:0c:29:bb:68:62  txqueuelen 1000  (Ethernet)

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

           

叢集定義和測試:

#确認一下ipvsadm工具是否有安裝:
[[email protected] ~]$ rpm -q ipvsadm
ipvsadm-1.27-7.el7.x86_64

#定義叢集(叢集排程方法為輪詢 rr)
[[email protected] ~]$ sudo ipvsadm -A -t 172.16.0.199:80 -s rr
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.199:80 rr
FWM  3 rr
  -> 127.0.0.1:80                 Route   1      0          0  

#添加後端主機(-g是預設類型dr的選項。)
[[email protected] ~]$ sudo ipvsadm -a -t 172.16.0.199:80 -r 172.16.0.62 -g 
[[email protected] ~]$ sudo ipvsadm -a -t 172.16.0.199:80 -r 172.16.0.63 -g 
[[email protected] ~]$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.199:80 rr
  -> 172.16.0.62:80               Route   1      0          0         
  -> 172.16.0.63:80               Route   1      0          0         
FWM  3 rr
  -> 127.0.0.1:80                 Route   1      0          0   

用戶端環境:
[[email protected] ~]$ ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.88  netmask 255.255.0.0  broadcast 172.16.255.255
        inet6 fe80::20c:29ff:feae:a6bf  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:ae:a6:bf  txqueuelen 1000  (Ethernet)
        RX packets 70376  bytes 8727803 (8.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 92011  bytes 8177456 (7.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 35  bytes 2486 (2.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 35  bytes 2486 (2.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
通路測試叢集:(結果是否符合輪詢,要簡單核對一下)
[[email protected] ~]$ for i in {1..10};do
> curl http://172.16.0.199/test1.html
> done
<h1>RS2,172.16.0.63</h1>
<h1>RS1,172.16.0.62</h1>
<h1>RS2,172.16.0.63</h1>
<h1>RS1,172.16.0.62</h1>
<h1>RS2,172.16.0.63</h1>
<h1>RS1,172.16.0.62</h1>
<h1>RS2,172.16.0.63</h1>
<h1>RS1,172.16.0.62</h1>
<h1>RS2,172.16.0.63</h1>
<h1>RS1,172.16.0.62</h1>

關于動态資源,可以在浏覽器上簡單測試一下。,我可以用curl -I選項簡單測試兩次:
[[email protected] ~]$ curl -I http://172.16.0.199/phpinfo.php
HTTP/1.1 200 OK
Date: Sun, 13 Jan 2019 17:43:14 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
X-Powered-By: PHP/5.4.16
Content-Type: text/html; charset=UTF-8

[[email protected] ~]$ curl -I http://172.16.0.199/phpinfo.php
HTTP/1.1 200 OK
Date: Sun, 13 Jan 2019 17:43:14 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
X-Powered-By: PHP/5.4.16
Content-Type: text/html; charset=UTF-8
           
架構基礎知識總結1
架構基礎知識總結1

可以看看172.16.0.199的mac位址是否為Director的VIP:

[[email protected] ~]$ arp -a

director (172.16.0.61) at 00:0c:29:bb:68:62 [ether] on eno16777736

? (172.16.0.14) at d4:81:d7:87:2f:21 [ether] on eno16777736

www.yanhui.com (172.16.0.199) at 00:0c:29:bb:68:62 [ether] on eno16777736

? (172.16.0.62) at 00:0c:29:18:86:76 [ether] on eno16777736

? (172.16.0.63) at 00:0c:29:99:19:a4 [ether] on eno16777736

? (172.16.0.1) at dc:fe:18:b4:bc:79 [ether] on eno16777736

[[email protected] ~]$ ifconfig eno16777736:0

eno16777736:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500

inet 172.16.0.199 netmask 255.255.255.255 broadcast 172.16.0.199

ether 00:0c:29:bb:68:62 txqueuelen 1000 (Ethernet)

#可以看出廣播的172.16.0.199的mac位址是Director的實體接口别名網卡en016777736:0的mac位址。

3.3.3、LVS的tun類型簡單封包圖解(隧道)

架構基礎知識總結1

3.3.4、LVS的fullnat類型簡單封包圖解

架構基礎知識總結1