經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

內容來源:2017 年 9 月 9 日,前同程藝龍架構師謝康在“ArchData技術大會上海站”進行《同程微服務從1到1w的旅程》演講分享。IT 大咖說作為獨家視頻合作方,經主辦方和講者審閱授權發佈。

閱讀字數:4418 | 12分鐘閱讀

嘉賓演講視頻回放及PPT,請複製鏈接:http://t.cn/RgaI9PG,粘貼至瀏覽器地址欄即可。

經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

摘要

本次演講主要介紹同程微服務的演化進程,如何通過各方面的升級讓微服務架構趨於完善,以及在大規模微服務化過程中總結的一些經驗教訓。

同程微服務起源

在12年到14年之間因與其他同行的激烈競爭,導致我們的系統變的臃腫不堪,因此迫切需要一個新的服務化平臺。這個平臺需要具備這幾點要求,首先要簡潔、高效、可靠,其實能夠跨語言、跨平臺,最後還要能夠快速實現,對開發者友好。

經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

為了實現這些要求,我們開始研究關於微服務的相關方案,最終實現了上圖這樣的服務系統。整個架構簡單來說就是一套協議,兩個容器,三個服務

因為微服務比較推崇輕量級的通信協議,所以我們就選擇了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工具

經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

我們的整個升級方案中,前一階段解決的只是DevOps中的運維部分,Dev還沒有一個很完善的解決方式。在反思了這一問題之後,我們開始著手完善DevOps的整個流程問題。最終實現了在開發人員寫第一行代碼之前就已開始介入,無論是Java還是.Net或者Go我們都能提供一致的項目模板或腳手架,安裝完成之後就能享受所帶來的便利。同時考慮到多語言多平臺的現狀,我們還做了一個通用平臺,這樣開發者在不同語言之間進行遷移的時候也能獲得一致的體驗。

到了測試聯調階段,我們也進行了相應的改進。使得代碼在編譯的時候只要有一個良好風格的註釋,剩下的就可以交由組件處理。比如將所有的註釋和接口抽取出來做數據契約和接口契約生成wiki文檔,在調試的時候該文檔就會生成,它給聯調帶來了極大的便利,發佈之後的迴歸測試也能夠用到。

DevOps作為一個龐大的平臺,一定要有一整套的OpenAPI機制,保留足夠的透明化,讓用戶能夠知道系統運行的時候到底發生了什麼。我們有一個完善的監控系統讓每一步調用,每個接口的響應時間都能通過OpenAPI機制讓用戶獲取到。必要的時候,還會開放一部分的運維權限給開發,因為只有開發人員才會知道系統出現的問題該如何維護。

以上就是我們目前所提供的DevOps工具,相對來說還是有所不足,因為當出現新的工具的時候,研發人員總會期望有更好的工具,所以我們還是會進行不斷的演化升級。

關於服務粒度

前面分享的都是同程兩年的微服務歷程,在這個過程中我們也總結了很多經驗。比如大家最關係的服務粒度問題,微服務如何拆分,分到多少粒度才合適。

經歷了研發困局、運維之痛,同程微服務從1到1w的旅程

在談具體的拆分方式之前,先來了解下康維定律和領域建模。康維定律簡單來說就是系統設計(產品結構)等同組織形式,每個設計系統的組織,其產生的設計等同於組織之間的溝通結構。同程就是一種典型的樹形結構,底層會有一些高頻的互訪,最終我們的微服務架構也是類似於這種結構。

上面這兩個概念相對來說比較寬泛,這裡說下我們的具體方案。

第一是按照團隊組織結構切分,明確服務的歸屬,切勿出現跨組的服務,這樣物理上的切分能夠讓服務獲得更好的內聚性。

第二個是按服務的發佈升級頻率分,我們剛開始做的時候,經常會出現一個有多個接口微服務中,僅有一兩個接口是高頻的,剩下90%只有少量的訪問,但是每次發佈時這些接口都需要全部帶上,測試的時候也都需要再跑一遍,造成很大的資源浪費。因此我們推薦將哪些特別高頻的服務接口單獨剝離出來。

第三是按服務調用數量級分,一般使用Restful風格設計的接口,update和inset應該是放在一起的,但是update和inset之間如果有一個訪問頻率遠遠高出的情況下,就有必要考慮將它分離出來。

最後就是按照數據的讀寫分離劃分,之前我們的很多設計都是基於增刪改查,但是這種設計大部分情況下查詢都會高出幾個數量級。這時候我們推薦採用CQLRS模式,將冪等操作和會導致數據變更的操作分開,也就是常說的讀寫分離。

關於服務版本

在一開始只有600多個服務的時候版本問題還不明顯,當達到5000多個時就給我們造成了很大的困擾。之前剛開始用服務的時候大家都沒有定義版本,一直的都是1.0,導致服務內的接口不斷增多。這主要是由於服務的開發人員不敢隨意的對代碼做修改,怕服務下線後引起服務的宕機,所以只能不斷的增加接口。

為了解決版本問題,我們開始使用標準的語義化版本。版本號有4位,前兩位是大版本號,後面是小版本號。在修改或刪除原先的接口後,需要升級大版本號顯示的告知調用者該服務做了不兼容的升級。如果只是優化了邏輯或者新增接口的情況下,則要升級小版本號。

這種方案在剛開始推行的時候也出現了很多問題,有的團隊是不知道如何寫,有的則是一味的升級小版本,畢竟這樣安全些。這個問題也是微服務治理的一個重要方面,就是微服務平臺要能夠評判服務的質量。在我們的平臺中有一整套的中臺機制,在服務註冊的時候不光會上傳服務的節點、IP、端口,同時還會上傳所有的接口和數據契約。也就是說它會解析包的原數據,將對方需要知道的數據都抽取出來,甚至包括註釋,它的好處在於服務發佈的時候能夠知道是否有不兼容的升級,調用方也能知道服務升級具體做了那些事情。

我們對版本號的機制做了多次迭代。第一代版本號是固定的,調用方調用的時候也要通過該版本號,只要有了服務名和版本號就能幫開發者進行服務查詢和調用。這一代的問題在於每天都要更新多次版本,非常麻煩,為此提出的妥協方案是直接讓開發者將版本號寫在配置中。到了第二代就有了統一的向前/後兼容的策略,和明確的不兼容策略。只要接口沒有發生改變造成不兼容,我們都能夠找到,即使接口所在的項目包發生了多次升級。

關於過渡到微服務

最後也是最難的一步就是從如何單體架構過渡到微服務,過渡的時候不僅對業務研發有要求,對整個的微服務平臺也有著要求。微服務框架要有良好的兼容性,讓研發人員能夠平滑的進行過渡。我們剛開始的方案是讓開發者直接將代碼打包接到平臺中,然後通過服務治理系統進行拆分。

接下來就要講到絞殺者模式和監獄模式。絞殺者模式很常見,就是將單體架構向微服務演化的時候,首先要保證單體架構不會繼續增大,對於新的功能和模塊要獨立開來,原來的項目直接凍結,再把原先有的功能慢慢剝離出來。如果有些功能很難進行剝離的話,那麼就要用到監獄模式。先做一個微代理的微服務項目,接入真正項目打包後的接口,什麼時候接入的項目能夠轉換成微服務,就將微代理給去除掉。

雖然上面講到了很多解決方案,但是還有一點需要提醒大家,“微服務不是銀彈,不要過度微服務”。因為多一層調用勢必會影響一些性能,整體的複雜度也會增加,運維和測試成本也會上升。因此那些對性能特別敏感或有高頻運算的項目就不適合去做微服務。

以上為今天的全部分享內容,謝謝大家!


分享到:


相關文章: