nginx原始碼學習 非http伺服器的負載均衡實現

2021-07-27 05:34:13 字數 3731 閱讀 5494

負載均衡 

說明:這裡只分析原始碼,具體每種模式工作原理網上有很詳細的解釋。這裡沒有分析http容器的負載均衡,只分析了upstream的負載均衡,二者有些許不同。

nginx支援四種複雜均衡模式,與實現檔案對應如下:

round robin模式:即迴圈模式,對應檔案ngx_stream_upstream_round_robin.c/.h

least conn模式:即最少連線模式,對應檔案ngx_stream_upstream_least_conn_module.c

hash模式:就是雜湊模式,對應檔案ngx_stream_upstream_hash_module.c

zone模式:域模式,對應檔案ngx_stream_upstream_zone_module.c(未完全實現)

只有round robin有標頭檔案,它是最基本的模式。

下面分析各個模式的實現:

1、round robin

ngx_int_t ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, ngx_stream_upstream_srv_conf_t *us);

這是系統預設的負載均衡模式,其他模式都是基於該模式實現,預設配置檔案沒有引數指明其他模式時,就採用該模式。在ngx_stream_upstream_init_main_conf(ngx_stream_upstream.c 695行)呼叫。

0)給us.peer.init賦值函式ngx_stream_upstream_init_round_robin_peer,在ngx_stream_proxy_handler(ngx_stream_proxy_module.c 349行)和ngx_http_upstream_init_request(ngx_http_upstream.c 524行)呼叫;

1)ngx_stream_upstream_server_t陣列是否已經建立好;

2)是,取出陣列server,遍歷它,統計其中非備份服務端數量(n)和權重總和(w);

3)如果n===0,說明沒有server,退出;

4)建立ngx_stream_upstream_rr_peers_t結構體peers,儲存服務端統計資訊,它的peer屬性儲存了下一步要建立的n個peer的鍊錶;

5)建立n個ngx_stream_upstream_rr_peer_t結構體peer,遍歷server,儲存每個服務端的詳細資訊到每個peer;

6)把賦值好的peers儲存到入參us中的peer.data屬性;

7)遍歷server,統計備份服務端,執行類似的4)5)6)步;

9)如果第二步是否,說明server陣列沒有建立好,那麼proxy_pass隱式建立乙個server陣列給us;隱式建立的server不包含備份服務端;

10)根據us儲存的host和port,解析網域名稱得到若干個服務端位址,執行類似的4)5)6)步;

11)返回成功。

ngx_int_t ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s,

ngx_stream_upstream_resolved_t *ur);

在ngx_stream_proxy_handler(ngx_stream_proxy_module.c 349行)中呼叫

根據ngx_stream_upstream_resolved_t *ur,即主機名解析結果,建立resolved的peers鍊錶,過程和上乙個函式基本類似。

ngx_int_t

ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data);

取乙個服務端點。在多個地方都有呼叫,就不一一枚舉了。主要作用是遍歷data(其實是ngx_stream_upstream_rr_peer_data_t *rrp),取出乙個可以做負載均衡的服務端(呼叫ngx_stream_upstream_get_peer)的位址和名字屬性,賦值給pc對應屬性,由pc負責具體的連線工作。

static ngx_stream_upstream_rr_peer_t *

ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp)

取出rrp中的乙個服務端。

1)獲取當前時間,now = ngx_time();

2)遍歷rrp中的peer結點

3)測試該peer結點是否tried==1,是則跳過,意思是該結點已經被獲取過;

4)測試peer.down,是則跳過,代表該結點已停止服務;

5)測試peer.max_fails peer.fails peer.checked peer.fail_timeout,是則跳過,代表該結點傳送錯誤已達上限,或該結點響應超時;

6)測試peer.max_conns,是則跳過,代表該結點連線已達上限;

7)累加peer權重,即peer->current_weight += peer->effective_weight;如果effective_weightconns * best->weight < best->conns * peer->weight則為最佳結點,即當前peer的已連線數乘以當前最佳結點的權重,小於當前最佳結點的已連線數乘以當前peer的權重,也就是取結果小者,也即連線數最少模式(其實是加權最少)如果是相等,則many為1,表示有多個合適的結點。如果沒有設定權重,即weight=0,則必然竟然many=1的判斷。

迴圈結束後,如果many=1,則回到第一種方式,按權重最大者為最佳結點。

3、hash模式

static ngx_int_t

ngx_stream_upstream_init_hash(ngx_conf_t *cf,

ngx_stream_upstream_srv_conf_t *us)

和上乙個模式相同。

static ngx_int_t

ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s,

ngx_stream_upstream_srv_conf_t *us)

和前兩個模式不同的地方是,需要建立ngx_stream_upstream_hash_peer_data_t hp結點,用於儲存hash值。初始化時hash和rehash都是0。通過ngx_stream_complex_value初始化hp.key,也就是hash的key。

static ngx_int_t

ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)

本模式返回結點的核心方法。本函式hash值計算和http中不同。

data其實是ngx_stream_upstream_hash_peer_data_t *hp。

1)初始化變數hash值,ngx_crc32_init(hash);初始化後,hash=0xffffffff

2)如果rehash>0,呼叫ngx_crc32_update更新hash值

3)用hp->key更新hash值

4)ngx_crc32_final(hash)結束hash計算

5)hash = (hash >> 16) & 0x7fff;最終hash值

6)累加當前hp.hash += hash;

7)累加hp.rehash++

8)根據當前hp.hash和總權重,計算權重w

9)遍歷hp的伺服器結點,找到權重比w大的結點作為當前結點

以上就是三種模式(非http服務)的工作流程。

nginx原始碼學習

nginx原始碼學習是乙個痛苦又快樂的過程,下面列出了一些nginx的學習資源。看了nginx原始碼,發現這是乙份完全沒有注釋,完全沒有配置文件的 這份注釋版原始碼會不斷進行更新的 好了,第乙個問題,nginx的main函式在 呢?src core nginx.c 第二個問題,nginx啟動的時候都...

Nginx原始碼分析之http架構

1.初步認識nginx的http架構一些概念 關於nginx的http架構主要分為5個模組 handler模組,filter模組,upstream模組,event模組,loadbalance模組 event模組 事件模組 什麼是事件?fd可讀可寫,定時器都叫做事件。為什麼要做成模組呢?為了跨平台,可...

nginx原始碼學習資源

nginx原始碼學習是乙個痛苦又快樂的過程,下面列出了一些nginx的學習資源。看了nginx原始碼,發現這是乙份完全沒有注釋,完全沒有配置文件的 這份注釋版原始碼會不斷進行更新的 好了,第乙個問題,nginx的main函式在 呢?src core nginx.c 第二個問題,nginx啟動的時候都...