今天要講的題目比較熱,但也比較「簡單」,由於有不少公司大型系統已經在用。個人演講內容包括兩個方面:一個是分佈式架構的實踐,另一個是服務體系中容器化怎麼作。docker
分佈式服務框架實踐數據庫
可能你們不少都聽過服務化,或者叫微服務,可是這個「微」字很難平衡,由於每一個人有每一個人的理解,咱們的理念仍是以簡單實用爲主,下面是惟品會 RPC 服務化框架的主要結構,proxy 層是咱們特別重要的一個環節,後面會詳細介紹。緩存
在展開以前,先介紹下惟品會作服務化的緣由,重要的有 5 點:網絡
-
服務複雜度高。你們知道惟品會作特賣的,裏面涉及到的大的系統比較多,包括庫存、訂單、支付等等。架構
-
團隊規模大,國內的大電商企業規模都是幾千人的技術規模,這是一個比較大的挑戰,不像咱們如今說有幾十我的的創業公司。幾千人的公司實際上推進一些公共技術架構比較困難。咱們有專門的運維部門、業務部門等。團隊越分越散,最後的結果很難協調一塊兒開發,這是咱們最大的問題。併發
-
彈性應對高併發能力,要有足夠的彈性,由於咱們有雙十一,12.8 日店慶,接下來立刻是 4.19 大促。業界競爭是咱們作大促的緣由,可是大促如今已經愈來愈爛了,包括京東、蘇寧易購,包括惟品會,一週一個大促,這個不能叫大促,只能叫「周促」。大促形成的流量的併發愈來愈凌亂,今天可能 10 點鐘很頻繁了,到 11 點鐘沒流量了,但到了晚上 8 點流量又上來了,這種無規律的突發流量,要好支撐以及運維高性價比是很困難的一件事情。框架
-
足夠的容錯和自愈能力,這是咱們作服務化最大的動力。整個的容錯體系,不能說今天死了,找一個運維人員從新找一個機器上切換 IP。固然,現實還有一部分系統作不到服務化,舊的體系依然還存在。運維
-
下降維護成本,出錯的話到底查仍是不查,須要查的成本很是低。否則的話,沒法把握下一次發生什麼事情。作開發的,有一大部分時間都是作查錯。異步
通常公司技術體系能夠分紅基礎層、業務層、接入層三層的劃分。基礎層技術團隊能作的很少,數據庫、緩存及文件系統都是標準化的組件。可是服務化是在作中間層及業務聚合層,再提供 API 出來給到上面有網站及 APP 使用,服務化怎麼作對整個架構以及全部技術團隊都有影響。分佈式
通過對服務化的思考與實踐,咱們主要目標是作好兩個事情,一個是整個體系的服務註冊與發現,第二個是服務治理。
服務註冊與發現
惟品會是本身構建的通訊框架,基於 Thrift RPC 的方式。整個 RPC 框架分紅三段:client、proxy,service。
咱們的作法是把 proxy 這一層獨立出來,經過 proxy 調用服務。
爲何這麼作?
當服務愈來愈多,會發現一個問題,A 部門今天升級,B 部門不升級,就會形成業務處理很混亂,路由和容錯都會很混亂。咱們很難強迫業務部門說今天必定要把業務用的框架升級,業務部門會反感這種自身沒有變動需求的被動升級。因此咱們會把服務治理功能獨立出來放在一個地方,就是這裏提的 proxy 端。
服務發現網上已經有不少選擇了,搭建不是太複雜,原理上只要把服務註冊到公共的地方,即把 IP + 端口註冊,而後 client 端獲取對應的 IP + 端口的列表就能夠了。有不少不一樣的技術實現服務發現。如 etcd、consul 及傳統的 DNS 方式。
服務治理
服務治理傳統你們用得多的是代理模式,使用治理功能的服務都須要流經它。考慮到這個遠程代理若是有什麼異常會影響總體服務質量,咱們把代理放到本地,沒用採用中心化的部署。
這是咱們實現分佈式服務總結的一個理念:儘可能讓全部的中心化功能都本地化,經過本地化的方式找到服務在哪裏,在本地完成治理。
當咱們須要升級時,只須要把本地代理升級換掉就能夠了。
如上圖所示,服務治理還作了不少事情,主要跟業務相關的,通用層面包括服務路由、流量控制等。
灰度流量控制
剛纔另一個朋友也講灰度,咱們叫 AB 測試,作法以下。
咱們能夠經過百分比的方式,在新上一個服務的時候,只放 1% 或者千分之一的流量來作灰度。
這樣的話,影響客戶量是最小的,否則的話,原來有 9 臺機,再上一臺可能有問題的機器,就有十分之一的機率出錯。
治理策略
服務治理方面還作了服務之間的隔離,防火牆的部署和鄰近機房路由等。
若是服務部署在異地多個機房,服務就會產生跨牆的問題,機房與機房最快也要三二十毫秒,須要充分考慮跨牆及延遲的特性。咱們還作了一些熔斷、限流的策略。
你們能夠對比一下 Dubbo,咱們沒有選擇它的緣由就是上述服務治理方面功能的需求。
對於 proxy 高可用,實際上咱們有一個災備,把一樣的 proxy 在中央找一個地方作容災,當你發現本地不通的時候能夠在遠端找到。這樣就能夠作災備,實現無縫升級。
另外咱們作的彈性路由,在不一樣的 IDC 機房間配不一樣的 IP 段之間路由的優先級,當優先級不一樣的時候優先選鄰近的機房的服務處理。
減化運維
另一個減化運維的需求,也是跟多機房有關。
若是有不少機房,有一個機房正好作支付,如今支付的要求比較高一些,全部的服務都會被保護起來,就會有一個問題,當找到那臺機器的 IP 時候,有可能發現這臺機器不通。
這是因爲咱們從註冊發現來找,有可能找到的是防火牆後面的那臺機器,這樣每次去申請支付的時候,就會出現一個問題,要求全部的客戶端的防火牆訪問策略都要被打開,而後才容許不一樣的客戶端進來。
但最大的問題是作支付服務的那我的根本不知道有多少人在用它。怎麼辦?咱們實際上經過判斷服務是否是個特定的服務,若是是把它所有繞到一個防火牆後面的遠程 Proxy,而後經過反向代理的方式進來,這樣的話,避免每次都須要作配置防火牆策略,只須要給(Proxy)獨立開一個對外的開放端口就能夠了。
中間聚合層
服務自己是零散化的東西,一般要接入的是中間層。實際上會在中間層作聚合,聚合層自己便可以作業務聚合,也能夠作中間層的聚合,每一層的聚合都要作異步調用的設計。同時要對接口進行抽取,這樣的話才能給 APP 使用。由於 APP 自己是沒有服務發現的。
RPC 性能
使用 RPC 有不少理由, 咱們這裏對比一下它的總體的性能(固然性能只是一方面,是否真的須要,取決於你到底用多少性能,latency 想要多少)。
這是咱們本身內部的一個簡單的對比。咱們會起用調用跟蹤、寫日誌等,大概咱們在 4.8 萬 TPS,用 Tomcat Rest 方式壓,能夠到 2.4 萬。
總結
整個服務化來講,不是純粹引入一個 RPC 框架來作這麼簡單,整個服務化是一個體系,它包括不少東西,服務框架只是其中一個面。服務離散化以後,在管控服務方面,須要付出的代價也會大,你們作服務化以前必定要想清楚。
其餘實踐總結
順帶提一下咱們的「黑科技」。
一、壓測時候須要把 JMeter 參數調好,否則的話,頗有可能不是的服務的問題,而是 JMeter 可能壓不到。
二、注意 Young GC 的次數。
三、ZooKeeper
咱們服務發現與治理用的 Zookeeper,Zookeeper 瓶頸很是多,如何在跨機房、大數據量狀況下若是用好 ZooKeeper?
首先整個系統設計,核心作選舉的三個節點必定要放在同一個數據中心部署。否則寫數據會形成整個 Zookeeper 集羣不穩定。另外全部的業務節點所有掛在觀察者模式上,讓觀察者模式不要影響全局。
容器化演進
下面分享一下咱們容器化的演進。
咱們運維思路遵循簡單原理,目前採用單進程部署,運維簡單也是爲了最大的容錯。
在物理機體系上,雖然私有云咱們也在作。可是要打造的體系比較大,運維難度也比較大。很多物理機CPU 才百分之幾。這是咱們爲何要作容器化的緣由。
容器化的選型,沒有說哪個對哪個錯,咱們選型充分考慮了本身的特性。
咱們容器化最後選擇 Marathon 和 Mesos,主要緣由是爲了適應物理層。
Kubernetes 尚未作物理機這一層管理。咱們須要方案有對整個體系後續的管理能力。K8S 裏面的細節我就不說了(最大到 1000個 節點),每一個人都有本身的喜愛及場景來選擇。
下面是整個容器平臺的概貌,左邊服務化體系和監控體系,最右邊是原有的物理機運維體系,這兩個均可以直接沿用以前的系統,不須要太多調整。
容器裏面是咱們主要提幾個東西,包括業務的服務、Flume Agent, cAdervisor 等,咱們仍是遵循容器單進程的理念。
整個容器化的發佈流程也比較簡單,從開發一直到運維,經過 Mesos + Marathon 作調度,用 Docker 運行,再作監控分析,還有一些輔助的系統,好比網絡和運維的工具等。
鏡像的發佈
從發佈的角度,要考慮怎麼簡單。咱們作的簡易化的發佈,直接用 Registry + Jenkins 實現。你們只要在 Jenkins 寫好腳本就能夠了,這是一個簡化的流程。不須要作代碼開發。
對於 Registry HA 方案,若是作一個相似於用分佈式軟件存儲的方式,我不肯定能不能作好管理。咱們仍是走最簡單的方式,在 Jenkins 裏面把它部署到多個 Registry 裏。前面配置反向代理,讓客戶端能夠訪問到,這樣容量就不會有問題。
網絡
默認無論用 NAT 的方式仍是 host 方式,它的管理始終是很麻煩。我仍是但願 Marathon + Mesos 的方式無論網絡,網絡交給咱們本身管。目前個人方式是每臺機器用 Linux VLan 的方式。但願後續 libnetwork 能夠支撐更好的 DHCP 的方式,目前還沒考慮引入。
VIP DCOS
你們都很熟悉 DCOS,咱們要作的事情就是基於 mesos + marathon 和 docker、cAdervisor 等組合成一個服務,包括實現咱們本身的監控體系,還有策略的管理,包括彈性伸縮調度的能力,而後作一些預警,這些組件整合在一塊兒,有一個獨立的入口。
業務部門始終都是比較厭煩繁雜的東西。所以提供了一些相對友好的一些界面。
資源共享
當公司大了以後,不一樣的部門有本身的運維,不一樣的部門有本身的機器。他不想與別人共享,整個雲化又是共享的概念,咱們針對這種方式作一個限制的資源池的隔離,好比購物車和下單隔離成兩組,本身的共享及彈性調度在本身的池裏去作。
固然當大促的時候,咱們會從公有池給它分額外的資源。未來繼續演進,若是須要咱們能夠把它升級到公有云,把公有云機器變成 Mesos 的 slave 機器,把它掛到本身的集羣裏面,它就能夠被調度了。
容器的「黑科技」
容器使用,咱們使用了一些「黑科技」。
首先,咱們在作容器化的時候調整了 Linux,在上面作一些額外的手腳。
內存策略:首先是主機 memory,一個是回收的策略的調整,一個是 swap 的調整,它是比較大的問題。默認的 memory 使用 60% 後就會使用 swap,可是最好的方式儘量用光 memory 再用 swap。
IO 優化:兩個 IO 比較關鍵,一個是磁盤 IO,一個是網絡 IO。由於容器多了以後,實際上一個物理機能支撐 log 輸出的磁盤 IO 是很是有限的。這樣的話,支撐不了幾個容器,因此 IO 是一個很大的影響。儘量在物理機上配多個磁盤,把不一樣的 log 文件用不一樣的磁盤隔離開。第二個手段是應用程序自己將 IO 作一個抽樣,不是全部的應用程序全部的 log 都要輸出,根據狀況作抽樣大多能夠知足須要。
磁盤 IO:再次,像咱們這樣的服務化體系,將 log 蒐集到中心地方,log 存到本地意義不大。這樣能夠用一塊內存磁盤方式先寫進來,避免磁盤 IO。
網絡 IO:建議最好用高性能萬兆網卡和交換機。若是沒有,則能夠用多個千兆卡把它bond在一塊兒。 今天講的大概這麼多,謝謝你們!