nginx動態配置及服務發現那些事


Reference: http://xiaorui.cc/2016/10/16/nginx%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE%E5%8F%8A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E9%82%A3%E4%BA%9B%E4%BA%8B/

 

次的准備閑聊關於nginx服務發現的話題,  按照我以往寫文章的性子,估計會遷移一些主題.  畢竟單純聊nginx和動態服務發現沒啥意思,因我以前的文章有大量的涉及到。

 

 

該文章寫的有些亂,歡迎來噴 ! 另外文章后續不斷更新中,請到原文地址查看更新.    http://xiaorui.cc/?p=3855

 

nginx upstream相關

我這里就不再精細的講述nginx的源碼, 畢竟我自己也只是粗略看了點nginx的底層代碼.  nginx的動態配置肯定是繞不過upstream模塊的運作了,他主要的驅動是xxx_pass,比如最常用的proxy_pass, uwsgi_pass。upstream相關配置結構的建立,並不一定是非要配置upstream這個指令才會去做,有時proxy_pass直接就是跟一個ip地址或域名, 他其實隱式的調用upstream 。

 

那么一個具體的request過程如何跟upstream配置怎么關聯起來的?

首先是通過peer.init函數指針初始化,然后根據round robbin算法選擇ngx_http_upstream_init_round_robin_peer,每種算法鎖出發的函數不一樣,這是廢話。 從配置上看,凡是請求到location /xxx的request請求,他們都關聯到同一個upstream配置,但是既然大家公用一個結構,那么需不需要互斥呢?如果大家都要修改其中的某個成員…    

實際上,nginx中一個請求不會中多個進程中同時處理,一個request生老病死都在一個worker內。  每個nginx worker都會監聽自己相關的epoll fd事件。 當一個worker爭取到了nginx listen fd accept的鎖,那么他就可以接收新的request請求,這個請求的創建出的fd會壓到他本進程的事件里。 我想說的是,他不會逃到worker里, 因為也沒這個必要這么實現,跨多進程傳遞socket本身是個很蛋疼的實現.

nginx relaod相關

那么nginx upstrem闡述完了,我們再聊聊nginx -s reload.   

當你增刪改upstream配置的時候,如何讓nginx不停服務的重載配置? nginx -s reload.  reload的實現相對好理解,-s的作用是向master進程發送信號。 其實是SIGHUP信號的封裝,也就是說我們可以直接通過kill向nginx的pid發送SIGHUP信號來完成reload操作。 
master通過ngx_signal_handler處理信號,見到reload就重置ngx_reconfigure = 1.

 

 

這樣當ngx_master_process_cycle的for循環中檢測到ngx_reconfigure ==1,就開始做重加載配置的操作,通過ngx_start_worker_processes開啟新進程,而之前的進程則通過ngx_signal_worker_processes來發送信號進行“優雅”的關閉.  所謂優雅的關閉, 就是讓當前真正處理請求的進程等到處理完之后再退出,當然進程不能再次參與accept鎖的爭奪了.  這樣新的請求會拿到listen accept鎖,可建立reqeust連接.

如何保證已經建連的連接 ?   

如果是短連接,那么在請求完之后,worker會主動發送close(),后面就把fd事件給踢掉。  

那么長連接會怎么辦?  這個時候長連接是有兩種的, 前者是是client 跟 nginx proxy的連接,后者是proxy跟后端服務的連接,比如nginx –> tornado 就屬於后者.

 

nginx proxy主要就是給client提供服務,在對外請求完畢的情況下,右面的連接可有可無了,  當然我們還是操作proxy給后端服務發送close()關閉連接 。 如果發生異常進程退出,后端經過keepalive timeout后進行回收資源. 

前者的連接就有點意思了,  當你的請求是http1.1長連接時候,不管是單次請求或者是stream這種流式請求,都會在請求完之后退出。 那么對於客戶端有什么影響?  客戶端會收到fin的tcp關閉請求,配合nginx關閉連接之后. 當你再次訪問nginx的時候,才會重建一個連接… 

 

什么是nginx的動態配置?

到此為止, nginx reload 和 upstream 都過了一遍.  那么動態配置又是什么? 我們什么時候需要動態配置?  

我認為nginx的動態配置可以有這么幾種方法.

一種是dns動態解析 ,一種是模板渲染, 一種服務發現動態配置重載.   

碰巧,這幾種配置我都有在線上用過,我不會單純的說誰更好,誰更差,因為每個動態配置方法都有他的應用場景.  比如dns動態解析非常適合依賴域名來辨識主機的集群服務,多用在類aws、阿里雲這樣的雲服務.   模板動態配置方法更適合那種大型的運維平台管理體系.    服務發現配置適合那種docker化的服務, 或者類似的微服務框架體系.

第一種, dns動態解析

我們通常在配置nginx upstream的時候都會使用ip地址. 對於那種依賴域名的集群服務,非常適合這樣的配置.  因為你修改了一組域名的配置,你如果nginx域名來解析, 就不再重新配置了。 這個dns服務器肯定不能是公網. 內網必須配置一個高性能的dns服務,比如dnsmasq, bind. 另外我們需要注意dns緩存的問題, nginx默認會根據dns server返回的ttl來設置記錄的失效時間, 推薦配置成5s .  如果ttl太小,dns也會成為一個瓶頸點. 

dns的缺點也明顯,那就是ip級別,很多時候一台服務器我們會開N個port,  動態的域名只能跟蹤ip的級別, 這樣顯得很不靈活。  由於nginx dns動態解析多適用於雲主機環境,雲主機一般是一兩個核,所以這是可以接受的. 

如果你使用skydns的化,也可以實現我們后面講述的動態服務發現. 

我們可以簡單的配置dns模式.:

 

也可以配置更加的豐富.   我這邊用的是tengine。

 

 

 

nginx plus版的配置.  相對來說,nginx plus的功能更加豐富點,但是需要收費,我在free期間測試過該功能,通過. 

 

 

另外可以使用nginx的dns加強版插件. https://github.com/GUI/nginx-upstream-dynamic-servers

 

第二種,動態模板解析

我在上面有說過動態模板解析的場景一般是那種運維平台系統, 我曾經在全網集群調度平台,智能dns管理系統中使用過這種方法, 他的優點在於系統的集中式管理,本身來說這種管理方式只是把手動的操作變成自動化而已,但這種配置方式相當的穩定,只是每次渲染模板后都需要nginx -s reload.   

另外他的開發成本還是不低的,小公司hold不住的,一般各大公司的運維平台多使用這種方式.  

簡單說下他的實現,比如python語言,我們可以使用jinja2、mako的模板引擎,動態的根據你提供變量渲染配置. 

 

第三種,服務發現模式.

服務發現是這次的重點,博客里有聊過etcd、zookeeper、consul 這三種服務發現的使用及坑.   那么跟nginx是怎么實現的動態加載配置? 他跟nginx -s reload不一樣, reload會重新開一組進程來接收請求,讓老進程完事后再退出.    切記,如果你線上流量較大,不要頻繁的reload,   因為nginx新老配置交替的時候會掉15%左右的qps .

 

     其實並不一定要按照reload的路子走,我們可以針對nginx進行改造。 讓他可以主動去拉取最新的服務發現里的主機.  在github中的不少nginx服務發現的實現,他們不會新開進程,而是在在master進程中注冊一個定時器,該事件會觸發watch,當發現version的版本號發生變更時,就知道主機列表發生了變化,進而重載配置.   那么如何讓worker進程也使用新的配置?  這時候可能不會使用共享變量,因為讀寫都要加鎖,及其影響速度.  所以每個worker都會緩存一份location upstream的配置,每個worker也會有個定時器,他的事件共享內存的upstream有無變化…   

 

優點是什么?  服務發現模式特別適合微服務,更片面的說 docker服務化.    因為docker可以更加彈性的擴展縮減集群的計算架構.    當docker容器起來后,直接給consul注冊一個槽位,間隔性的發送健康心跳.  我們不需要管nginx的配置,nginx會自己動態的重載最新的配置.     當我們把docker容器干掉了,由於consul有配置過期自動清理記錄,很大程度保證consul服務發現列表的 “純潔性” .  

 

一個nginx consul的場景圖:

 

 

下圖是etcd的服務發現流程.   服務的提供者會注冊到服務注冊中心上,請求者在請求之前會訪問一次注冊中心,從里面取出主機記錄才會進一步訪問. 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM