今天主要分享下微服務中的Auto Scale,豆瓣2005年3月上線,是一家歷史比較悠久的互聯網公司,主要覆蓋文化綜合領域的Web、APP等各類產品,如今有豆瓣讀書、豆瓣電影、豆瓣音樂等等。數據庫
在技術方面,豆瓣主要的開發語言是Python和Golang,豆瓣擁有自研私有云平臺Douban App Engine(如下簡稱「DAE」),上面託管豆瓣網全部應用使用配置來描述應用:應用依賴MQ、Daemon,以及Cron,這樣開發者使用一個配置文件就能夠描述對資源的全部需求,平臺拿到描述文件後能夠在上面作須要的資源管配。服務器
在DAE上會統一調度全部資源,產品開發人員沒必要關心具體的機器設備,好比無需關心某個業務線須要配備多少臺物理機器,全部資源由平臺統一調配,全部開發流程,從提交PR到測試,上線是一套統一流程。運維
豆瓣從2012年開始作服務化,主要由於隨着產品線愈來愈多,單體應用已經沒法知足豆瓣對開發效率的需求,所以,2012年起逐步開始拆分整個網站,截止2016年末,90%以上的產品已經完成產品服務化,因爲前期準備充分,這個過程當中整個網站性能沒有發生變化,沒有由於作了服務化致使性能上的降低,全棧可用性獲得提高,不會由於新入職同事作了一個不太成功的提交,而致使全棧掛掉,發佈也由每日發佈變爲按需隨時發佈,服務化後,全部上線流程由各個業務線自行控制。微服務
迴歸今天的主題,爲何豆瓣要作Auto Scale,作了微服務的公司內部各個系統之間會造成很是多的依賴,微服務化以後,整個系統結構很難用層次化的模型來描述,呈現出來的是一個複雜的網狀依賴關係,大量應用相互之間有交錯的依賴。工具
這裏有個問題,單體應用時,運維人員部署應用其實很是簡單,在一臺機器上將應用部署完畢,按照機器的性能部署相應的進程,當請求過來處理能力不足時,直接加服務器。oop
微服務化以後,運維人員手裏有大量的微服務,每一個服務的請求量和性能都不一樣,運維很難手工維持每一個具體的應用須要多少計算資源,這就帶來一個問題:怎樣可以讓應用既能跑得好又跑的省,若是每一個應用都給予足夠多的資源,這顯然不是一個經濟的方式,迫切須要一個既能提升服務器利用率,又能提升自動化的方式。性能
豆瓣微服務的時間起始於2013年12月,由於過早,如今流行的一些開源技術當時尚未用到,2014年2月,開始進行簡單的場內線上應用,3月,已經能夠接管部署在平臺上的140多個應用。公司處在服務化進程中,當時只有一小部分應用部署了微服務享受到Auto Scale帶來的好處。測試
14年3月,Docker還沒出來,豆瓣此時是一家純Python的公司,用Python作應用打包,2014年下半年,開始發現Docker的巨大優點,因而作了整個平臺的Docker改造,2015年Q2完成總體Docker化改造。優化
整個AutoScale的發展是從前面提到的140個應用開始,隨着服務化推薦,持續優化性能,提升穩定性,目前整個平臺上500個託管應用都在Auto Scale之下。網站
一個Git Repo映射到DAE平臺上的資源分配、調度、計費和邏輯集合,每一個應用全局惟一且相互獨立,經過thrift/pidl/http RPC相互調用,對於Web和Service服務,豆瓣支持Multi-instances,好比一個應用既須要有Web頁面,也須要Thrift服務,能夠用一份代碼起兩個不一樣服務,其中Web服務主要服務天天來自外部用戶的訪問,Thrift Service是內部調用,量級比外部訪問大很得多,Auto Scale提供一個機制,經過配置把兩個Instance分拆開,Austo Scale提供一直機制,經過配置將兩個Instance分拆開,分別作Scale。
DAE Scale是多進程模型,每一個請求由一個進程來處理,整個系統能夠理解爲Worker的總數和應用服務處理能力直接相關,Node是物理機,有些Node會部署一個應用,有的部署若干個應用,從平臺資源調度來看,全部無狀態節點都是均等的,差異主要在CPU和Mem方面,Node和APP之間是多對多的關係,每一個APP在每一個Node裏面有多少Worker(工做進程),是Auto Scale的關鍵,會放到數據庫裏。
從理論上來講,全部應用都是平等的,但有些應用相比其餘應用重要度更低,須要物理層面的硬隔離,Pool就是一組節點,在被分隔開的若干個Pool中,有的Pool是公司內部的小應用,只需作有限支持,計算資源很是受限,對外較重要的應用分紅兩級,Production Pool和Stable Pool以及一些很是重要的應用,是公司的核心產品,它們會單獨用本身的資源,另外,有些部門有本身的計算資源,但願用到平臺調動的機制,這種狀況部門能夠將本身的計算資源貢獻出來單獨有一個Pool。
上圖是整個Auto Scale結構,最下面的節點上有Monitor,會採集借點上面各類性能指標,包括Memory、CPU、Load、當前進程的繁忙程度,採集以後發到若干地方,主要用來給監控人員查看,在Auto Scale的應用中,其實它的性能還不夠好,因此通常會存一份數據Redis裏面,到了Redis以後,整合的數據稱做Bridge,在Bridge節點上面採集的數據進一步加工封裝出一些API,包括關於APP、Node、以及Pool的API。全部應用Scale各類策略的配置都在這個應用裏作。
真正作Auto Scale策略的應用是DAE Scale,Scale這一塊會有若干個Cron Job,作相應的事情,好比APP的Auto Scale,Web Auto Scale、真正去Scale他們的Worker,裏面會配置一系列的策略,對於Pool,豆瓣最核心的幾個應用,計算資源也是共享的,Movie、Group和SNS是豆瓣最核心的三個業務,會獨佔一個Pool,但天天須要Pool中的多少節點,是一個動態調整的過程,會有專門的Pool作彈性伸縮。
在Scale裏作完運算,下一步要麼Scale UP到某一個APP,要麼Scale Down某個APP,或把一個APP從一個節點挪到另外一個節點,或者把一個APP在某個節點上放上去或拿掉,Scale產生這些行爲,最後落地又回到節點上,節點上面有一些工具暴露API,讓Scale回到節點上面來,這樣將整個流程串起來。
外部應用更新完畢後,會更改Nginx的配置,不一樣節點同一應用的觸點不一樣,配置反應不一樣的權重,處理能力強的節點拿到的請求更多,能力弱的節點拿到的請求少一些,這就是Scale總體的結構。
關於採集數據,豆瓣是多進程模型,怎麼去判斷這個進程在工做沒有呢?是去數,每一個進程在運行以前會作一個標記,完成後這個標記會刪掉,Monitor會到這個機器上數,這臺機器上有多少個Worker,多少標記,標書就是正在忙的節點,正在忙的進程,這裏有一個小技巧,標記放在內存盤上,它的系統上就看不到了。
整個APP Scale有兩種策略,一是每一個應用Instance如今有多少個進程在忙,須要有一個策略來計算,到底須要多少進程,豆瓣嘗試過若干策略,好比Noop,有的應用不須要Scale,配幾個進程就夠了,不須要Scale,不須要干涉,但busy_ratio_mark_cnt是須要干涉的,rps_ratio能夠根據應用的具體請求量和響應時間計算出來,當前應該還需多少個Worker。
還有一個Ondemand_rps進程,Auto Scale基於的假設是,全部請求都是一個逐步增加和減小過程,但有特例,好比APP作一次大規模推送,或上一個廣告,這時有預期推送後或廣告放出去後,會有大量的回放上來,此時Auto Scale的曲線型就會比較明顯,由於它沒辦法與指導RPS陡然的上漲,豆瓣處理方式是給Scale提供一個API,將主動權交回給應用開發者,讓他按照推送的規模,估計大概的規模,平均回訪率,反饋到Scale後,Scale會作一個快速拉起動做,立刻將須要的進程漲上去維持一段時間,等待請求過來,而後隨着請求過去再慢慢Down下去。
Ondemand_rps還有一點經驗,就是須要有一個大概預估的時間,Scale上去後,若是請求還沒來,那麼Auto Scale會很快介入,若是仍是沒有足夠請求它會開始往下Down,好比保持半個小時,這是一個產品經驗值,若是半小時請求還沒來,可能此次就不會有那麼強的請求了。
關於哪些節點加進程,有兩個策略:一個是徹底equal,好比某個應用在5個節點上須要20個進程,每一個節點作4個,絕對均衡,有的應用要求每一個節點處理能力是至關的,可是,更多的節點容許不一樣的節點上處理能力不同,這個前提下會稍微保證節點之間不要差的太多,某些處理能力強的節點也不會拿到太多進程,好比將80%的請求都放在一個節點,若是那個節點有問題,就會都有問題,而應該是當某個節點宕掉,當期那的冗餘度可以Cover宕掉的問題。
每一個應用會作一個配置,這個應用最小須要多少節點,各個應用不同,有大的需求得更高,好比至少10個節點,有的應用兩個節點就能夠了,這也是經過Scale確保上面作這些操做不會破壞掉最低的要求。
因此整個Scale核心訴求是,調整總Worker以及到每一個節點上面去調進程,在工程上有時會將VIP和普通分開,若是某一次Scale卡住,好比遲早高峯,會有相應的報警,若是那個時候沒有把處理能力加上去,極可能會出大面積的問題。
Scale一些基本的策略,在加Worker時必定要快,請求來的時候要很是快的響應,但減的時候須要慢,若是很快減掉了,可能系統會顛簸比較厲害,另外,節點之間分配杜絕過於不均,後期簡單算一下各個節點之間的標準差距,看是否是差的太遠。
還有一個維度,從節點的角度看,須要同一個Pool裏面平衡各個節點的負載,在同一個Pool的節點之間作均衡,平衡主要看CPU、存儲、能夠優先把Worker較小的應用拿掉,留下一些比較大的Worker,過一段時間Scale趨於穩定後,會發現有些訪問量很大,一些應用慢慢會獨佔一些節點,這也是IT人員但願看到的狀況。
對於VIP的Pool,它們會有一個彈性池子的概念,也有一個Freed Pool,咱們目前閒置的資源都是Free Pool裏,當VIP Pool有資源的需求的話它會從Free Pool裏面拿,Load下去以後它會還回去,在這幾個大的VIPPool之間,實際上是共享整個計算資源的,主要的考慮也是各個產品用戶訪問Pattern不太有同樣,有的產品白天訪問量比較高,晚上比較低,有的則反之,同一組機器其實經過機制調度可以用的更充分一些。
Auto Scale是一個完整自動化的工具,豆瓣圍繞它作了不少監控,網站全部的資源調配都交給Auto Scale來管理,一旦Auto Scale出現任何卡頓,或其餘狀況,會產生很是大地問題,因此會有大量報警去看相關的事情,另外,Scale應用是5分鐘作一個,頻率更高意義並不大,會致使整個系統顛簸的太厲害,還須要提供足夠的手工工具,當Auto Scale自己出現情況時,須要給運維人員提供充分的腳本,若是自動系統出現情況而不能人工干預是一件很是要命的事情。
有一些典型的狀況,好比網站被DDOS,整個網站訪問量直接Down到底,全部Worker都閒下來,這時Auto Scale開始介入工做,會逐漸把Worker往下調,DDOS過去以後這些Worker是不夠的,因此當出現相似情況時,用手工的開關把它停掉,同時也須要強勁的LOG,這樣在後續查找問題能夠快速定位。
作完App Auto Scale後推而廣之發現,豆瓣有大量離線MQ Consumer,以前是產品開發人員來調配,應該調到多少是比較難以把控的,MQ的Auto Scale作下來發現和外部請求類不太同樣,外部請求來了以後,不管響應與否,它很快就走掉了,但MQ來了以後就不會走,它會一直在那裏,MQ可能會愈來愈長,還有一個以前作APP沒有關注到的點——排隊,隊列在這時很是重要,須要看看隊列是否是在增加,若是增加須要快速把Consumer加上來。