內容來源:2017 年 9 月 9 日,前同程藝龍架構師謝康在「ArchData技術大會上海站」進行《同程微服務從1到1w的旅程》演講分享。IT 大咖說(微信id:itdakashuo)做爲獨家視頻合做方,經主辦方和講者審閱受權發佈。linux
閱讀字數:4418 | 12分鐘閱讀git
本次演講主要介紹同程微服務的演化進程,如何經過各方面的升級讓微服務架構趨於完善,以及在大規模微服務化過程當中總結的一些經驗教訓。windows
在12年到14年之間因與其餘同行的激烈競爭,致使咱們的系統變的臃腫不堪,所以迫切須要一個新的服務化平臺。這個平臺須要具有這幾點要求,首先要簡潔、高效、可靠,其實可以跨語言、跨平臺,最後還要可以快速實現,對開發者友好。安全
爲了實現這些要求,咱們開始研究關於微服務的相關方案,最終實現了上圖這樣的服務系統。整個架構簡單來講就是一套協議,兩個容器,三個服務。微信
由於微服務比較推崇輕量級的通訊協議,因此咱們就選擇了HTTP2,基於該協議提供兩個平臺。因爲時間和人力上的關係,要想作全部的平臺仍是不太現實,所以咱們決定先搞定最核心的兩個平臺,分別是基於.Net和Java的輕量級容器。在此之上就是微服務核心的幾個部分,服務註冊,服務發現和服務狀態。最後經過服務將數據上報到zookeeper,經過Zookeeper做爲配置和調度中心將整個系統做爲分佈式集羣給管理起來。架構
2015年12月份咱們正式上線了一個服務Demo,正當要鬆一口氣的時候,問題出現了。最大的問題在於團隊人員對微服務不瞭解,面對這種狀況,咱們在半年內組織了40多場關於微服務的分享培訓,不只僅是讓你們瞭解微服務,更多的是統一對它的認識,只有認知達成一致才能真正的去應用。框架
雖然作了這麼多的努力,可是等到2016年7月整個平臺系統上也只有600個服務在運行。這明顯不符合預期,相對於SOA治理咱們提供了不少的工具,讓開發變的便捷簡單,只須要將服務代碼提交到git後續的步驟都會自動化完成,那麼問題到底出在哪呢?後來發現仍是由於前面提到的緣由,你們對這套新的東西並非很放心。運維
拋開研發層面,運維也存在着問題。爲了前面提到的600個服務,運維方面已是疲於應對了。首先是Docker,虛擬機分配任務翻倍,這是因爲平臺中服務耗盡的時候會觸發一系列的機制申請新的資源,而這些資源都須要運維人員check以後才能分配。其次是發佈量的問題,原來的平臺中不少項目都是一週或兩週發佈一次,如今微服務以後甚至多是天天屢次,發佈的時候還要保證平滑,讓前面的業務無感。另外故障排除的時間也延遲了一倍,原先只有一個服務的狀況下排查還相對簡單,微服務之一次調用被拆成了多個服務,很難去判斷哪一個節點出現了問題。這些不協調的因素集合在一塊兒以後,報警量固然也會隨之增多,運維人員處理起來力不從心,疲於奔命。分佈式
針對上述狀況咱們仔細分析了一下,發現了幾個問題。首先是運維體系跟不上,之前那種手動寫腳本的方式已經沒法應對當下的場景。其次由於微服務的發佈頻率很高,因此測試的自動化也要跟上。還有包括之前的持續集成和底層服務編排也再也不適用。微服務
因此在推行微服務的過程當中,運維繫統也要進行全面的升級。首先在源頭上要有一個一站式的工單系統,經過這樣的一站式運維平臺進行整合而後交給運維處理。因爲服務發佈頻率很是高,因此咱們聯合了自動化測試小組開發了一個集成測試化環境——天鏡,將全部的case和單元測試集成起來,在上線以前就可以生成一份測試報告,判斷是否可以發佈。一旦判斷爲能夠發佈就先作持續集成開始發佈,最後到底層的PaaS平臺分配資源。
整個流程看起來和微服務關係不大,可是微服務對底層的PaaS平臺有很強的依賴,若是沒有這一系列的步驟就很難去實施微服務。因此這裏給你們一個建議,在底層的基礎設施還不夠完善的時候,不要貿然去推微服務。
通過一系列的升級,到2017年2月的時候平臺中的服務終於達到了5400多個。這時運維是沒什麼問題了,不過研發方面又出了新的難題。一方面有大量的新老員工對微服務開始感興趣,過來諮詢如何進行遷移。另外一方面隨着服務量的增多,出現了各類罕見的故障。簡單說個你們不常碰到的問題,由於有着跨平臺的需求,因此咱們常常要從windows向linux發包,有一段時間出現過發送的包所有丟失的狀況,最後通過與運維人員的配合才發現是linux內核中的參數出現了問題。
服務化做爲整個業務體系中最核心部分,一旦業務研發人員發現問題首先想到的就是向咱們反饋求助。這種狀況的出現致使咱們的諮詢量暴增,且很難對全部的問題做出應對。
咱們的整個升級方案中,前一階段解決的只是DevOps中的運維部分,Dev尚未一個很完善的解決方式。在反思了這一問題以後,咱們開始着手完善DevOps的整個流程問題。最終實現了在開發人員寫第一行代碼以前就已開始介入,不管是Java仍是.Net或者Go咱們都能提供一致的項目模板或腳手架,安裝完成以後就能享受所帶來的便利。同時考慮到多語言多平臺的現狀,咱們還作了一個通用平臺,這樣開發者在不一樣語言之間進行遷移的時候也能得到一致的體驗。
到了測試聯調階段,咱們也進行了相應的改進。使得代碼在編譯的時候只要有一個良好風格的註釋,剩下的就能夠交由組件處理。好比將全部的註釋和接口抽取出來作數據契約和接口契約生成wiki文檔,在調試的時候該文檔就會生成,它給聯調帶來了極大的便利,發佈以後的迴歸測試也可以用到。
DevOps做爲一個龐大的平臺,必定要有一整套的OpenAPI機制,保留足夠的透明化,讓用戶可以知道系統運行的時候到底發生了什麼。咱們有一個完善的監控系統讓每一步調用,每一個接口的響應時間都能經過OpenAPI機制讓用戶獲取到。必要的時候,還會開放一部分的運維權限給開發,由於只有開發人員纔會知道系統出現的問題該如何維護。
以上就是咱們目前所提供的DevOps工具,相對來講仍是有所不足,由於當出現新的工具的時候,研發人員總會指望有更好的工具,因此咱們仍是會進行不斷的演化升級。
前面分享的都是同程兩年的微服務歷程,在這個過程當中咱們也總結了不少經驗。好比你們最關係的服務粒度問題,微服務如何拆分,分到多少粒度才合適。
在談具體的拆分方式以前,先來了解下康維定律和領域建模。康維定律簡單來講就是系統設計(產品結構)等同組織形式,每一個設計系統的組織,其產生的設計等同於組織之間的溝通結構。同程就是一種典型的樹形結構,底層會有一些高頻的互訪,最終咱們的微服務架構也是相似於這種結構。
上面這兩個概念相對來講比較寬泛,這裏說下咱們的具體方案。
第一是按照團隊組織結構切分,明確服務的歸屬,切勿出現跨組的服務,這樣物理上的切分可以讓服務得到更好的內聚性。
第二個是按服務的發佈升級頻率分,咱們剛開始作的時候,常常會出現一個有多個接口微服務中,僅有一兩個接口是高頻的,剩下90%只有少許的訪問,可是每次發佈時這些接口都須要所有帶上,測試的時候也都須要再跑一遍,形成很大的資源浪費。所以咱們推薦將哪些特別高頻的服務接口單獨剝離出來。
第三是按服務調用數量級分,通常使用Restful風格設計的接口,update和inset應該是放在一塊兒的,可是update和inset之間若是有一個訪問頻率遠遠高出的狀況下,就有必要考慮將它分離出來。
最後就是按照數據的讀寫分離劃分,以前咱們的不少設計都是基於增刪改查,可是這種設計大部分狀況下查詢都會高出幾個數量級。這時候咱們推薦採用CQLRS模式,將冪等操做和會致使數據變動的操做分開,也就是常說的讀寫分離。
在一開始只有600多個服務的時候版本問題還不明顯,當達到5000多個時就給咱們形成了很大的困擾。以前剛開始用服務的時候你們都沒有定義版本,一直的都是1.0,致使服務內的接口不斷增多。這主要是因爲服務的開發人員不敢隨意的對代碼作修改,怕服務下線後引發服務的宕機,因此只能不斷的增長接口。
爲了解決版本問題,咱們開始使用標準的語義化版本。版本號有4位,前兩位是大版本號,後面是小版本號。在修改或刪除原先的接口後,須要升級大版本號顯示的告知調用者該服務作了不兼容的升級。若是隻是優化了邏輯或者新增接口的狀況下,則要升級小版本號。
這種方案在剛開始推行的時候也出現了不少問題,有的團隊是不知道如何寫,有的則是一味的升級小版本,畢竟這樣安全些。這個問題也是微服務治理的一個重要方面,就是微服務平臺要可以評判服務的質量。在咱們的平臺中有一整套的中臺機制,在服務註冊的時候不光會上傳服務的節點、IP、端口,同時還會上傳全部的接口和數據契約。也就是說它會解析包的原數據,將對方須要知道的數據都抽取出來,甚至包括註釋,它的好處在於服務發佈的時候可以知道是否有不兼容的升級,調用方也能知道服務升級具體作了那些事情。
咱們對版本號的機制作了屢次迭代。第一代版本號是固定的,調用方調用的時候也要經過該版本號,只要有了服務名和版本號就能幫開發者進行服務查詢和調用。這一代的問題在於天天都要更新屢次版本,很是麻煩,爲此提出的妥協方案是直接讓開發者將版本號寫在配置中。到了第二代就有了統一的向前/後兼容的策略,和明確的不兼容策略。只要接口沒有發生改變形成不兼容,咱們都可以找到,即便接口所在的項目包發生了屢次升級。
最後也是最難的一步就是從如何單體架構過渡到微服務,過渡的時候不只對業務研發有要求,對整個的微服務平臺也有着要求。微服務框架要有良好的兼容性,讓研發人員可以平滑的進行過渡。咱們剛開始的方案是讓開發者直接將代碼打包接到平臺中,而後經過服務治理系統進行拆分。
接下來就要講到絞殺者模式和監獄模式。絞殺者模式很常見,就是將單體架構向微服務演化的時候,首先要保證單體架構不會繼續增大,對於新的功能和模塊要獨立開來,原來的項目直接凍結,再把原先有的功能慢慢剝離出來。若是有些功能很難進行剝離的話,那麼就要用到監獄模式。先作一個微代理的微服務項目,接入真正項目打包後的接口,何時接入的項目可以轉換成微服務,就將微代理給去除掉。
雖然上面講到了不少解決方案,可是還有一點須要提醒你們,「微服務不是銀彈,不要過分微服務」。由於多一層調用勢必會影響一些性能,總體的複雜度也會增長,運維和測試成本也會上升。所以那些對性能特別敏感或有高頻運算的項目就不適合去作微服務。