我們如何成功實現微服務遷移?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Picnic前一段時間進行了微服務遷移。遷移與技術團隊的成長几乎同時發生,以前的單一技術團隊被分成了專門的產品團隊。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事實上,在我們的案例中有以下三方面改變:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"員工被重新組織到不同產品團隊中"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼被分割到不同的 git 倉庫中"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用部署的粒度更細"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遷移後一開始,每個產品團隊維護大約一個微服務。但公司一直在成長,隨着成長業務範圍也越來越廣。因此,我們開始發現更多的業務分解機會。我們自己的Jakob"},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/from-monolith-to-microservices-9b2ef44401e3","title":"","type":null},"content":[{"type":"text","text":"曾經寫過涉及到的原則"}]},{"type":"text","text":",但是這個過程看起來是什麼樣的呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"定義用例"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們的研究案例是Picnic的"},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/react-native-at-picnic-eff17e8c51d5","title":"","type":null},"content":[{"type":"text","text":"Runner應用"}]},{"type":"text","text":",我們的駕駛員在旅途中使用它來接收導航指令,管理從客戶那裏取到的可回收物品,此外它爲我們的客戶提供ETA等附加功能。應用程序開發工作始於2018年,自此以後,“附加功能”部分顯著增長,其中一個值得注意的附加功能是一項"},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/programming-a-safer-drive-a41550575c8b","title":"","type":null},"content":[{"type":"text","text":"安全功能"}]},{"type":"text","text":",我們從我們的Runners(送貨車輛駕駛員)那裏收集GPS和加速度數據,並據此爲他們提供駕駛反饋。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過審視Runner應用程序的後端架構,我們意識到我們原本簡潔的服務現在有了另外一個功能。一方面,我們實現了最初的功能,即"},{"type":"text","marks":[{"type":"italic"}],"text":"旅途狀態"},{"type":"text","text":"管理和用戶交互管理。另一方面,我們圍繞各種傳感器數據開發了一些重要的功能,這些功能統稱爲“遙測”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用程序有兩個不同部分,並不意味着我們必須引入一個新的服務,事實上我們有很多理由不採用微服務。事實上,"},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/cultivating-microservices-b28403be8138","title":"","type":null},"content":[{"type":"text","text":"在遷移過程中,我們花了一段"}]},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/cultivating-microservices-b28403be8138","title":"","type":null},"content":[{"type":"text","text":"時間準備,然後才能正常開始工作。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管如此,我們還是編寫了一個內部RFC。在這個RFC中,我們詳細描述了計劃,考慮了各種選擇,並得出了一個結論:我們需要另一個單獨的服務。讓我們一起來看看我們的理由。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"行爲特徵"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用程序兩個部分的行爲方式並不相同。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"管理行程狀態是一個相對繁重的事務性過程。向後端發出的請求相對較少,因爲我們主要是在追蹤駕駛員執行的具體操作。每個請求都極其重要,必須對其完整性進行驗證——失敗對客戶和駕駛員都意味着業務被立即中斷。在這裏,我們大量使用我們的"},{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/open-sourcing-jolo-87cea6079108","title":"","type":null},"content":[{"type":"text","text":"開源Jolo庫"}]},{"type":"text","text":"來實例化對象圖,這意味着我們有很多內存操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與此同時,處理實時傳感器數據是完全不同的。它們會導致較爲頻繁的請求,但每個請求的處理都是短暫的且不太可能被單獨跟蹤,涉及的數據類型雖然很多,但也相對簡單。在這裏,我們可以更廣泛地使用流處理,充分利用"},{"type":"link","attrs":{"href":"https:\/\/spring.io\/reactive","title":"","type":null},"content":[{"type":"text","text":"reactive Spring技術棧"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這不僅僅是後端實現的簡單區別,這意味着需要使用不同的應用程序框架。因此這就意味着需要拆分應用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"數據庫很重要"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據庫很少出現在微服務相關的討論中,這類討論更多的是關於服務本身的結構、它們如何通信以及如何確保性能。數據庫相關討論的缺失讓我感到很喫驚。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"單體應用往往調用優化良好的數據庫層,而獨立部署微服務意味着其會調用網絡中的其他服務來獲取數據,而這類網絡調用往往是非常困難的。在這種情況下,確定我們可以在數據庫級別上拆分應用程序,而不會破壞我們在網絡請求方面的現有行爲是決定新服務邊界在何處的關鍵。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一個需要考慮的問題是,不同的數據模型可能需要使用不同的持久性策略。最初的服務是建立在Postgres上的,但是新的獨立服務的流特性使得響應式MongoDB和地理空間查詢成爲一個很好的備選方案。最後,我們沒有想出一個可以信賴的MongoDB文檔結構,所以我們繼續使用值得信賴的Postgres + Postgis。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我認爲數據庫設計是設計和確定微服務範圍的一個重要部分。如果要考慮分割微服務,一個好的出發點是考慮如何分割數據庫。如果功能不能在數據庫級別上分割,那麼在應用程序級別上分割代碼能獲得多少好處呢?事實上,我建議將數據庫分割作爲必要的第一步。如果我現在設計一個新系統,並且希望獲得鬆散耦合和接口隔離等經典微服務優勢,而不需要觸及它們的所有困難,我將研究一個帶有多數據庫設置的模塊化應用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"獨立失效"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"微型服務有點像貓。它們有時會讓你的生活更艱難,但一旦你擁有了它們,你就難以想象沒有它們的生活了。它們的行爲很難預測。互聯網上討論這些問題的內容非常多。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/6b\/06\/6b6fa771f258ef026e1yy2066f038306.jpg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我心愛的貓有不同的大小,就像我的微服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然而,與我的貓不同的是,我不需要同等地對待我所有的微服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果Runner應用程序後端的遙測收集功能出現故障,這對我們的司機來說只會帶來些微不便。但是,如果管理行程狀態的服務出現哪怕一個小問題,它就會使我們的司機完全無法工作,並且毀掉我們的客戶的一天。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們真的不希望“有則更好”的功能破壞那些操作上至關重要的“必須有”功能。而這正是獨立運行的微服務能夠帶給我們的,而單體部署無法做到的一點。所有的服務都可能宕機,但是對於微服務,我們有一個工具可以進行優雅地降級。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"這就是全部"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們認爲這是充分的。注意,在做出這個決定時,我們並沒有遵循獨立的部署流程、開發工作流或代碼存儲庫。我們仍然是一個團隊,在一個發佈週期內致力於一個產品。在團隊中,新分離的微服務只是技術實現的一個方面。我們不會從獨立管理依賴關係、版本聲明或拆分代碼庫中獲得其他任何好處,所以我們根本沒有觸及那些方面。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果您打算採用微服務體系結構,我建議您仔細考慮您實際想要的和需要從中得到的東西,而不是將自己束縛在其他人關於“正確的”微服務設置的概念中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"成功原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是一個成功的案例,此時產品團隊已經通過採用微服務模式獲得了我們所想要的一切。它有可能會向另一個糟糕方向發展,如果那樣的話這會是一篇“爲什麼我們放棄微服務”的文章。相反我們獲得了成功,下面是一些我認爲有助於成功的主要因素。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"沒有急劇轉變"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊不僅將遙測功能和行程狀態功能拆分爲單獨的微服務。實際上,到目前爲止,團隊管理着四個不同的微服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們只是在權衡和考慮我們的選擇時才添加微服務。我們沒有例行公事地增加服務作爲我們增長的一部分。我們可以擴大現有的服務,但公司的增長並不需要進行新的部署。只有在應用程序需要時,我們才增加我們微服務的數量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"任務決定技術"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將原來的應用替換爲分佈式應用意味着您現在有一大堆新問題需要處理。您不僅僅是用HTTP調用替換了數據庫調用,這對您所開發的應用程序的類型有着深遠的影響。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幸運的是,在最初的微服務遷移過程中,我們已經在Picnic中解決了這些問題。我們有一個內部的Kubernetes集羣,我們搭建了一個消息隊列並準備就緒,部署流水線很順暢,身份驗證系統可以處理分佈式系統。這些都需要大量汗水和淚水才能運行成功。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對技術進行投資,使微服務能夠實際使用,這將成爲您的技術團隊將承擔的最耗費人力的項目。確保你有充足的理由這樣做。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發佈和依賴管理的複雜性並未增加"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很容易發現自己處在這樣一種情況中,即花費大量時間進行繁瑣的多步驟部署,必須處理依賴版本,併爲實現單個功能而在多個代碼庫中工作。微服務意味着技術上更復雜的系統,但這並不意味着開發人員的日常工作流會受到影響。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在大多數情況下,這是一個以適合開發人員的方式構建項目的問題,這個話題與微服務本身無關。更新您的部署流程,對依賴項進行邏輯分層,根據工作流程的需要將代碼拆分爲多個倉庫。在邁向微服務模式時,請不要忽視單體應用程序中那些非常方便的特性,有可能您可以保留其優秀的方面。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"下一步"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏討論的軟件仍在發展,任務仍然存在。我們的測試可以改進,在代碼庫的這一部分中,我們有自動化的單元測試、集成測試和組件測試,但是端到端測試尚未開始。客戶希望與之交互的服務數量使我們開始研究API網關和通過GraphQL進行跨服務數據聚合。我還不知道這個微服務的故事將如何結束,但是隻要我們不斷仔細地反覆研究並保持清醒,我相信這個故事將有一個圓滿的結局!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/blog.picnic.nl\/a-microservice-success-story-fb29aa059caa","title":"xxx","type":null},"content":[{"type":"text","text":"A Microservice Success Story"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章