微服務是一個比較大的話題,基於個人過往經歷,本文將以 Netflix 爲例,分享一個大型互聯網公司如何從一個 Monolithic 的 APP 成功轉型到微服務。文章主要涉及微服務的產生歷史,應用場景,與單片服務區別,微服務帶來的技術、企業組織結構等方面挑戰,以及如何合理地選擇單片服務構架和微服務構架等內容。前端
以下圖,是微服務在 Google 的搜索結果:數據庫
自 2014 年以來,微服務開始被關注,搜索的人愈來愈多,並在 2016 年左右達到頂峯。從地域來看,不少國家都在關注,如印度,歐洲等等,而且不少公司在使用微服務構架。如下以 Netflix 爲例來分享微服務的演變過程以及帶來的挑戰。編程
我 2012 年加入Netflix,從中瞭解到:後端
Netflix 從 2008 到 2009 年就開始在自有數據中心作單片的 Web 應用,那個時期是很龐大的 Java 包,無數的程序寫在其中,形成不少問題。服務器
2010 年開始把重量級的部分轉出。網絡
2013 到 2014 年,其餘的模塊也陸續轉出,併發布不少 Open Source 的微服務工具,在硅谷及全球受到不少人的關注。架構
直至 2015 年左右,Netflix 基本完成向微服務的轉型,也完全從自有數據中心,轉移到亞馬遜的雲平臺。併發
以下,是微服務示意圖:負載均衡
微服務看上去很複雜,其實它是一個個服務器組成的,這些服務器之間相互鏈接。框架
以下圖,是 Netflix 在微服務方面的使用狀況:
從時間點看,Netflix 是硅谷採用微服務比較早的公司,在採用過程當中也受到不少質疑,特別是傳統公司,從數據中心遷到雲上,須要時間來慢慢接受。
以下,是很廣泛的 Monolithic APP 示意圖:
從 powser 到各類公司的 Apache,造成一個包含各類功能的 WAR 包,最後是一個 MySQL 的存儲層。這樣的方式,比較易於測試,部署方面也很簡單。
Monolithic APP 的優勢以下:
易於開發。不少 IDE 和框架都支持,好比 Sprint MVC、Ruby Rails、Python Django 等。
易於測試。能夠經過簡單啓動應用程序並使用 Selenium 測試 UI 來實現端到端測試。
易於部署。只需將打包的應用程序複製到服務器。
易於擴展。經過在負載平衡器後運行多個副本,能夠輕鬆地水平擴展。
DevOps 比較簡單。一支專門 DevOps 團隊負責便可。
Monolithic APP 的缺點以下:
應用程序太大且複雜,很難徹底理解並快速正確地進行更改。
應用程序會越變越大,可能會減慢啓動時間。
必須在每次更新時從新部署整個應用程序。
若是代碼庫有新的變化,變化的影響一般不是很清楚,這致使普遍的手動測試。
連續部署很困難。
當不一樣模塊具備衝突的資源需求時,單片應用也可能難以擴展。
可靠性差。任何模塊中的錯誤(例如內存泄漏)均可能會致使整個網站宕機。此外,因爲應用程序的全部實例是相同的,該錯誤將影響整個應用程序的可用性。
採用新技術或框架很困難。因爲框架或語言的變化將影響整個應用程序,所以在時間和成本上都是很是昂貴的。
隨着代碼庫,組件和團隊規模增加,各類問題相繼出現。
主要歸納爲以下幾點:
原代碼太大,IDE 打不開了。
單機的內存不夠,無法編譯和跑代碼。
部署一次要花很長時間。
開發速度跟不上產品的需求,一個小小的變化須要整個源代碼從新編譯。
某一個模塊裏的一個小錯誤,可能致使整個網站宕機。
隨着組織的成長,功能的增多以及技術棧的瓶頸出現,須要有新的變革。但面對如此龐大的視頻網站,有的程序都是用的 Java 包,自有數據中心,當時尚未微服務的概念,但已經有了把內容拆分出來的意識。
「微」是指團隊、代碼行數或 API 端口的數目等指標的大小?都不是,不一樣人對微服務有不一樣定義。
我的比較贊同這個描述:Loosely coupled service orientedarchitecture with bounded contexts。
關鍵是 LOOSELY COUPLED和BOUNDED TEXT,LOOSELY COUPLED 意味着每一個服務能夠獨立更新,BOUNDED TEXT 意味着一個服務只要作本身的事情,外界以API等接口。
也就是微服務要實現獨立部署,擁有獨立技術棧、界定上下文,明確的全部權等特色。
以下,是微服務與單片服務很形象的對比圖:
單片服務是把全部的東西放在一個大盒子裏,這個大盒子裏什麼都有。微服務更像是車廂,每一個箱子裏包含特定的功能模塊和物品,全部東西能夠很靈活地拆分出來。
也就是說,在 Monolithic APP 中,全部的部件都在一個巨大的軟件包中。在微服務的構建下,有不少獨立存在的小服務,經過 API 接口鏈接成大的系統。
以下圖,是 Monolithic APP 的架構:
Netflix 會支撐不少設備,最初是全部設備經過一個負載均衡器到一個碩大的、什麼都包含的程序中,最後會成爲一個碩大的 Oracle 數據中心。這樣一來,會產生很大問題,你們都很反感。
以下圖,是微服務的架構:
上圖能夠看出每一個服務均可拆分,自有數據源,不必定是 Oracle,可根據業務場景用不一樣的數據庫,徹底由各個團隊本身決定。
綜上是從技術角度分析 Netflix 爲何選擇微服務,從商業角度來看 Netflix 選擇微服務的緣由以下。
有三點緣由:
可用性(Availability)。24 x 7 防止單點失敗(single point of failure)。在巨大的 CODEBASE 狀況下,常常一個小小的錯誤好比代碼中多加了一個冒號就會致使整個程序編譯不了甚至引發整個網站宕機。對於大型互聯網公司而言,必定要避免單片服務致使的宕機。
可拓展性。Netflix 當時流量佔到美國三分之一,超過 9000W 的付費用戶且增加很是快。一旦某部件達到瓶頸時要有迅速可拓展的能力,通常就是添加新機器讓它運轉。但在傳統單片服務上,整個部分綁定在一塊兒,擴展很是困難。
速度。對互聯網公司,特別是 ToC 須要快速推出,速度很重要。速度在互聯網時代是致勝的關鍵。
大型互聯網公司推行微服務,一旦須要新功能,可當即新開一個微服務,或在幾個有限的微服務中進行改動,不須要像原來基於巨大的數據庫來改動。
軟件構架從單片服務向微服務轉型過程當中帶來了很大的技術挑戰。下面選取自認爲比較關鍵的內容進行分享。
主要涉及如下幾方面的挑戰:
服務發現(Service discovery)。傳統單片服務相對簡單,但微服務有幾百上千的服務器,對用戶來說,服務器的選擇是個問題。
運維複雜度增長 – DevOps。
分佈式系統本質上帶來的複雜度。
網絡延遲,容錯。
服務接口版本控制,存在不匹配。
測試(須要整個生態系統來測試)。
FAN OUT - >增長網絡流量。
面對這些方面的挑戰,分享一些關鍵技術,如 Service discovery、服務註冊、服務註冊模式、瓶頸/熱點、熔斷器和測試等。
對用戶而言,最難抉擇的是去哪一個服務器上取數據,解決方案有客戶端發現和服務器端發現兩種。
以下圖,是客戶端發現:
客戶端發現,就是客戶端佈設 Service Instance,存放全部地址、各類信息。客戶端接收到數據以後,可自行判斷去哪臺服務器上獲取信息。
以下圖,是服務端發現:
客戶端不須要寫不少程序,而是經過 Load Balancer 把信息轉到某個服務器。
服務註冊表是服務發現的關鍵部分,是一個包含服務實例的網絡位置的數據庫,須要高度可用且是最新的。
服務註冊必定不能宕機,一旦出現問題,恢復很是困難。服務註冊和發現部分,Netflix 採用的是自研 Eureka 組件。
服務註冊模式分爲自註冊和第三方註冊兩種:
自注冊模式。這種方法的一個很好的例子是 NetflixOSS Eureka 客戶端。Eureka 客戶端處理服務實例註冊和註銷的全部方面。
Spring Cloud 項目實現了各類模式,包括服務發現,能夠輕鬆地使用 Eureka 自動註冊服務實例,只需使用 @EnableEurekaClient 註釋註釋您的 Java 配置類。
服務註冊模式相對簡單,而且不須要任何其餘系統組件。但它將服務實例耦合到服務註冊表。您必須在您的服務使用的每種編程語言和框架中實現註冊碼。
以下圖,是第三方註冊模式:
開源註冊器項目—經 Registrator,會自動註冊和註銷部署爲 Docker 容器的服務實例,支持多個服務註冊表,包括 etcd 和 Consul。
NetflixOSS Prana 主要用於以非 JVM 語言編寫的服務,它是與服務實例並行運行的邊路應用程序。 Prana 使用 Netflix Eureka 註冊和註銷服務實例。
Registrator 的優勢是服務與服務註冊表斷開鏈接,不須要爲開發人員使用的每種編程語言和框架實現服務註冊邏輯。
相反,在專用服務內以集中方式處理服務實例註冊。缺點是除非它內置在部署環境中,它是另外一個高可用性的系統組件,須要設置和管理。
以下圖所示,單片服務裏請求只有一個,而微服務裏不少時候客戶端必須經過不一樣的微服務器才能把數據所有收集起來,請求繁多。
以下圖所示,解決的方法就是 Cache:
儘可能把已經擁有的數據 Cache 起來,當訪問時,優先於 Cache,沒有再選擇其餘部分。
以下圖,當遇到整個服務中某個變成瓶頸的狀況,就會調用 X,X 要從用戶賬戶裏拿數據。X 調用 Y,Y 也要從用戶賬戶裏拿數據。
這樣一來,用戶服務會變成一個大大的瓶頸,一旦宕機,最前端的APP必定拿不到數據。
處理方法以下圖所示:
Netflix 用的比較多的方法是針對一些共用的數據不進行反覆調用,可採用 HTTP HEADER 傳遞數據。
微服務並不必定能保證可用性,甚至有時微服務作很差更容易宕機,因此必定要採用一些好的容錯機制。
所謂容錯,原則上說就是當錯誤發生,儘量讓一臺服務器宕機。常見的解決方式有 Time out、Circuit peaker(熔斷器)和 Bulkheads (艙壁)-Reject new request 三種。
熔斷器在 Netflix 用的比較多,以下兩圖所示,爲熔斷流程:
熔斷器主要應用在當一個服務去它的下游服務拿數據時,不該該直接拿,要經過一個熔斷程序。
當下遊服務出現錯誤,或延時很長時間,熔斷器就中止再到下游服務拿數據,直接返回。熔斷器也會不斷進行判斷,服務是否恢復,恢復以後纔會繼續拿取數據。
這樣一來,問題就會在某個地方被阻擋,不會出現服務接連問題,致使微服務出現大規模崩潰的現象。
測試是比較頭疼的環節,特別是微服務架構端到端變得特別困難,主要緣由是幾百個服務隸屬於不一樣的團隊。
我的比較推薦單元測試(Unit Test)、服務測試(Service Test)。而端對端測試(End to End Test)要儘可能避免,能夠經過一些監控工具來完成。
還有 Netflix 採用 ChaosMonkey 工具來對延遲和服務可靠性進行測試。這裏值得注意的是,每一個微服務至少要有三個實時備份,以避免宕機後沒法恢復。
之因此分享微服務帶來的企業組織結構挑戰,是由於歸根結底仍是人在作事。微服務是去中心化,讓每一個服務有獨立權,這樣會致使組織結構發生很大的變化。
企業的組織構架每每會反映在技術構架中,微服務在企業內部是否可以成功,很大程度上取決於企業的組織構架和技術構架是否可以匹配。
以 Netflix 爲例,分享在向微服務構架轉變的過程當中對團隊和企業構架帶來的挑戰。
優化速度,而不是效率
Netflix 在考量以速度仍是以效率爲優化核心,最終選擇了速度。由於速度是贏得市場最重要的因素,速度意味着瞭解客戶需求,並以比競爭對手更快的速度給予他們想要的東西。在競爭對手準備跟進的時候,已經轉到下一組改進。
速度和效率是什麼關係呢?強調效率一般意味着試圖控制開發過程的總體流程,以消除重複的工做並避免錯誤的同時注意下降成本。
常見的結果是,注重節流,而不是開源。若是你說「我這樣作是由於它更有效率」,那麼這個意想不到的結果就是讓你慢下來。
這不是鼓勵浪費和重複開發,可是應該先優化速度,效率成爲次要。提升效率不是一個企業的終極目標,提升效率要以業務增加更快爲結果。
以結果爲導向,減小沒必要要流程
儘可能增長每一個微服務團隊的自由度,如開發工具,開發流程等方面,而後以結果爲導向。
Netflix 有三個框架,其中 Java 佔主流,每一個團隊可根據自身狀況選擇技術構架,甚至數據庫也可選擇 MySQL 或者 NoSQL。
儘可能減小流程,爲何有流程呢?流程每每是對過去的事情的總結,如對一些錯誤,經驗總結,以後用這個進行流程控制。
但過多的流程會減慢對新生事物和突發狀況的反映速度。還有要明確每一個團隊的目標,減小互相依賴關係。
以下圖,是傳統公司的產品開發流程:
大多數軟件開發團隊呈孤島狀,他們之間沒有人員重疊。軟件開發項目的標準過程從與用戶體驗和開發組的產品經理召開會議開始,一塊討論新功能的想法。
在代碼中實現該思想以後,代碼被傳遞給質量保證(QA)和數據庫管理團隊,常常須要進行不少溝通。與系統、網絡和SAN管理員的溝通每每是經過內部的 TICKET 系統,致使整個過程很是緩慢。
有些公司試圖用初創公司的形式開發產品,但初創公司開發團隊並不必定是微服務開發團隊。公司雖會有不少個小的初創公司形式的小團隊,可是每一個團隊內部結構仍是和傳統公司的團隊結構同樣。
以下圖,是微服務產品研發團隊:
微服務產品研發團隊沒有不一樣的產品經理、UX 經理、開發經理等,在其孤島中向下管理。
每一個產品功能(實現爲微服務)都有一名經理,他負責監督一個團隊,從構思到部署來處理各個方面微服務的軟件開發。
平臺團隊提供產品團隊經過 API 訪問的基礎架構支持,在整個過程當中,都採用 DeVop 形式發佈和維護產品。
並非全部的場景都適合微服務,要根據實際狀況,選擇微服務或單片服務:
微服務適用於巨大流量、系統有必定複雜性、須要快速開發出新的產品、用戶數量增加迅速以及絕大多數 TOC 的互聯網公司。
單片服務的應用場景通常是流量比較小、功能單一或很是簡單、不會快速迭代以及企業內部工具,POC 工具或網站。
前樂視美國視頻平臺技術總監以及Netflix 視頻內容平臺技術負責人。有 15 年以上互聯網公司(LinkedIn、樂視、Netflix 以及 PayPal)技術開發、構架以及團隊管理的經驗。主要負責的領域是高併發後端服務構架、微服務構架、大數據平臺構架等,以及端對端的整個產品開發。感興趣的領域是視頻,支付,互聯網金融以及電商領域。
以上內容根據羅軼民老師在 WOTA2017 「微服務架構」專場的演講內容整理。