国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從單體系統到微服務的正確打開方式

n7then / 2784人閱讀

摘要:從單體系統到微服務的正確打開方式原文標題原文鏈接注每一段譯文后跟作者原文,原文中可能包含著作者所提到的內容的跳轉超鏈接。從一整塊單體系統遷移到微服務生態系統簡直是一段史詩般的旅程。

從單體系統到微服務的正確打開方式
原文標題:How to break a Monolith into Microservices
原文鏈接:https://martinfowler.com/arti...
注:每一段譯文后跟作者原文,原文中可能包含著作者所提到的內容的跳轉超鏈接。
解耦目標和解耦時機

隨著整個系統變得過于龐大而難以應對,許多企業開始傾向于將其分解開來,轉變為微服務架構。這是一個很有價值的旅程,但也并不是一件很容易完成的事。我們了解到,為了實現這個目標,需要從一個簡單的服務開始,然后根據各部分的垂直業務功能,不斷抽出對于系統業務來說至關重要并需要經常變更的各種服務。在最初階段,這些服務應該會很大,并且最好不依賴于尚未分離的大型單體系統本體。我們應該確保每一步遷移都是對整個架構的原子性演進。

As monolithic systems become too large to deal with, many enterprises are drawn to breaking them down into the microservices architectural style. It is a worthwhile journey, but not an easy one. We"ve learned that to do this well, we need to start with a simple service, but then draw out services that are based on vertical capabilities that are important to the business and subject to frequent change. These services should be large at first and preferably not dependent upon the remaining monolith. We should ensure that each step of migration represents an atomic improvement to the overall architecture.

從一整塊單體系統遷移到微服務生態系統簡直是一段史詩般的旅程。走上這條征途的人們期望能擴張業務規模,加快改變步伐,并且避免高成本的變革。他們希望擴張團隊的數量,并且使各個團隊能夠并行且獨立地產出價值。他們希望快速對其核心業務功能點進行嘗試,并更快地產生價值。 他們也希望擺脫與修改和維護現有大型單體系統相關的高成本。

Migrating a monolithic system to an ecosystem of microservices is an epic journey. The ones who embark on this journey have aspirations such as increasing the scale of operation, accelerating the pace of change and escaping the high cost of change. They want to grow their number of teams while enabling them to deliver value in parallel and independently of each other. They want to rapidly experiment with their business"s core capabilities and deliver value faster. They also want to escape the high cost associated with making changes to their existing monolithic systems.

在向微服務架構遷移的過程中,決定在什么時候以什么樣的方式進行增量遷移是一個架構上的挑戰。 在這篇文章中,我將分享一些技巧,可以指導交付團隊(包括開發人員、架構師和技術經理 )做出這些決定。

Deciding what capability to decouple when and how to migrate incrementally are some of the architectural challenges of decomposing a monolith to an ecosystem of microservices. In this write-up, I share a few techniques that can guide the delivery teams - developers, architects, technical managers - to make these decomposition decisions along the journey.

為了闡述本文所關注的技術,我將以一個三層架構的在線零售系統為例,這個系統的UI層、業務邏輯層和數據層緊緊地耦合在了一起。我選擇它的原因,是因為這個架構具有很多企業正在運營的大型單體系統的代表性,并且其所采用的技術棧足夠現代,可以說明我們應該對其解耦,而不是重寫或者直接替換。

To clarify the techniques I use a multitier online retail application. This application tightly couples user facing, business logic and data layer. The reason I have chosen this example is that its architecture has the characteristics of monolithic applications that many businesses run and its technology stack is modern enough to justify decomposition instead of a complete rewrite and replacement.

微服務生態系統的目標

在我們開始之前,每個人都對微服務生態系統有一個共同的理解是很重要的。所謂微服務生態系統,是指封裝了各個業務功能的服務平臺。而所謂業務功能,是指企業在特定領域為實現特定目標和責任所做的事情。每個微服務都將公開一個API,開發人員可以以"自助"的方式發現和使用這些API。微服務具有獨立的生命周期,開發人員們可以獨立構建、測試和發布各個微服務。在微服務生態系統的組織結構內,各個團隊都是獨立并長期負責一個或多個服務的。與普遍認知的微服務的“微”字可能不同的是,各個服務的規??赡芤蚪M織的運營成熟度而異。正如Martin Fowler所說,“微服務是一種標簽,而不是描述”。

Before embarking, it is critical that everyone has a common understanding of a microservices ecosystem. Microservices ecosystem is a platform of services each encapsulating a business capability. A business capability represents what a business does in a particular domain to fulfill its objectives and responsibilities. Each microservice expose an API that developers can discover and use in a self-serve manner. Microservices have independent lifecycle. Developers can build, test and release each microservice independently. The microservices ecosystem enforces an organizational structure of autonomous long standing teams, each responsible for one or multiple services. Contrary to general perception and ‘micro’ in microservices, the size of each service matters least and may vary depending on the operational maturity of the organization. As Martin Fowler puts it, "microservices is a label and not the description".

圖1:服務封裝了業務功能,并通過自助的服務API公開數據和功能

Figure 1: Services encapsulate business capabilities, expose data and functionality through self-serve APIs

旅途指南

在深入研究之前,重要的是要知道將現有系統分解為微服務可能會帶來很高的總體成本,并且可能需要經過很多次迭代才能實現。 開發人員和架構師必須仔細評估是否應該對當前系統進行分解,以及判斷對于當前系統來說微服務本身是否是正確的發展方向。在想清楚這個問題之后,咱們開始吧。

Before diving into the guide, it is important to know that there is a high overall cost associated with decomposing an existing system to microservices and it may take many iterations. It is necessary for developers and architects to closely evaluate whether the decomposition of an existing monolith is the right path, and whether the microservices itself is the right destination. Having cleared that out, let’s go through the guide.

從簡單而基礎的功能點開始熱身吧

只要開始了微服務,就至少需要有最低水平的運維。這需要部署按需訪問的環境、需要構建新的持續集成系統以實現服務的獨立構建、測試和部署,以及需要一個安全的、可調試的、可監控的分布式體系結構。無論我們正在構建新的服務,還是在對現行系統進行解耦,對于運維能力都是有要求的。有關這一點的更多信息,請參閱Martin Fowler關于微服務的先決條件的文章。好消息是,自從Martin撰文以來,微服務架構的運維技術有了迅速發展,其中包括創建被稱為“服務網絡”(Service Mesh)的專用基礎設施層,可以運行快速、可靠和安全的微服務網絡,可以創建提供更高級別的基礎設施抽象的“容器編排系統"、以及諸如GoCD等在容器中構建、測試和部署微服務的持續集成系統的發展。

Starting down a microservices path requires a minimum level of operational readiness. It requires on demand access to deployment environment, building new kinds of continuous delivery pipelines to independently build, test, and deploy executable services, and the ability to secure, debug and monitor a distributed architecture. Operational readiness maturity is required whether we are building greenfield services or decomposing an existing system. For more on this operational readiness see Martin Fowler’s article on Microservices prerequisites. The good news is that since Martin’s article, the technology to operate a microservices architecture has evolved rapidly. This includes creation of Service Mesh, a dedicated infrastructure layer to run fast, reliable and secure network of microservices, container orchestration systems to provide a higher level of deployment infrastructure abstraction, and evolution of continuous delivery systems such as GoCD to build, test and deploy microservices as containers.

我的建議是,開發人員和運維團隊首先可以從微服務的底層基礎設施,諸如持續集成系統和API管理系統開始構建。從這些與老系統分離的功能點開始構建微服務,不需要對當前正在運行的面向用戶的業務進行更改,甚至可能都不需要進行數據存儲。對于交付團隊來說,此時需要不斷優化的是對他們的交付方法進行驗證、對團隊成員能力進行提升、構建出最基本的可以獨立部署的安全服務的基礎設施,從而可以對外公開服務的API。例如對于在線零售系統來說,首先可以從老系統中分離出來的是用戶認證鑒權服務,以及對于新的客戶程序來說可以提供更好的直觀展現的“客戶信息”服務。

My suggestion is for developers and operation teams to build out the underlying infrastructure, continuous delivery pipelines and the API management system with the first and second service that they decompose or build new. Start with capabilities that are fairly decoupled from the monolith, they don’t require changes to many client facing applications that are currently using the monolith and possibly don’t need a data store. What the delivery teams are optimizing for at the point is validating their delivery approaches, upskilling the team members, and building out minimum infrastructure needed to deliver independently deployable secure services that expose self-serve APIs. As an example, for an online retail application, the first service can be the ‘end user authentication’ service that the monolith could call to authenticate the end users, and the second service could be the ‘customer profile’ service, a facade service providing a better view of the customers for new client applications.

首先,我建議從簡單的邊緣服務開始解耦。在此之后,再采用不同的方法深入單體系統解耦其余功能。我建議先做邊緣服務開始的原因,是因為在剛開始時,交付團隊的最大風險是無法正確地掌握微服務的運維。因此,為了掌握必須的“運維先決條件”,從邊緣服務開始練手是一個很好的選擇。而 一旦這個問題得到解決,剩下的問題就可以迎刃而解。

First I recommended decoupling simple edge services. Next we take a different approach decoupling capabilities deeply embedded in the monolithic system. I advise doing edge services first because at the beginning of the journey, the delivery teams" biggest risk is failing to operate the microservices properly. So it’s good to use the edge services to practice the operational prerequisites they need. Once they have addressed that, they can then address the key problem of splitting the monolith.

圖2:從簡單功能開始鍛煉運維能力

Figure 2: Warming up with a simple capability that has a small radius of change to build our operational readiness

減少對老系統的依賴

將新的微服務系統與老系統之間的依賴關系最小化是一個基本原則。微服務的一個主要優點是具有快速和獨立的發布周期。一旦與老系統之間有任何依賴,如數據、邏輯或API,都將導致微服務系統與老系統的發布周期相耦合,從而使得微服務的發布優勢不復存在。通常,擺脫老系統的主要動機就是其成本之高昂,以及深鎖于其中的業務功能的更新之緩慢。所以,我們希望逐步通過減少對老系統的依賴關系的方式,將核心業務解耦。如果團隊能夠遵循這些原則,將業務功能寫進自己的服務中,依賴關系就能從對單體系統的依賴轉變為對微服務的依賴。這是一個理想的依賴方向,因為它將不會拖慢新服務的更新速度。

As a founding principle the delivery teams need to minimize the dependencies of newly formed microservices to the monolith. A major benefit of microservices is to have a fast and independent release cycle. Having dependencies to the monolith - data, logic, APIs - couples the service to the monolith"s release cycle, prohibiting this benefit. Often the main motivation for moving away from the monolith is the high cost and slow pace of change of the capabilities locked in it, so we want to progressively move in a direction that decouples these core capabilities by removing dependencies to the monolith. If the teams follow this guideline as they build out capabilities into their own services, what they find is instead, dependencies in the reverse direction, from the monolith to the services. This is a desired dependency direction as it does not slow down the pace of change for new services.

在在線零售系統中,購買和促銷是核心功能。購買功能將在結算過程中使用促銷功能,為顧客提供他們可以獲得的最佳促銷方案,并給他們所購買的商品。如果我們需要決定在這兩種功能之中哪一個先解耦,我的建議是先解耦促銷,再解耦購買。因為通過這個順序,我們可以減少對老系統的依賴。在這個順序中,購買功能將會先被鎖定在整體結構中,并依賴于新的促銷微服務。

Consider in a retail online system, where ‘buy’ and ‘promotions’ are core capabilities. ‘buy’ uses ‘promotions’ during the checkout process to offer the customers the best promotions that they qualify for, given the items they are buying. If we need to decide which of these two capabilities to decouple next, I suggest to start with decoupling ‘promotions’ first and then "buy". Because in this order we reduce the dependencies back to the monolith. In this order ‘buy’ first remains locked in the monolith with a dependency out to the new ‘promotions’ microservice.

下一條準則提供了另一些方法來決定服務的解耦順序。這意味著,可能并不是總能找到一個可以徹底避免對老系統的依賴的方案。如果新服務最終依然還是調用到了老系統,我建議在老系統中開發新的API,并通過新服務的防腐層來訪問這些API,以確保老系統中的概念不會直接暴露出來。就算老系統的內部可能實現并不是這樣的,也應該致力于定義一個能夠反應領域的明確概念和其結構的API。在這種不幸的情況下,交付團隊可能需要直面困難,承擔修改老系統的成本,進行測試和發布與老系統耦合在一起的新服務。

Next guidelines offer other ways for deciding the order in which developers decouple services. This means that they may not be always able to avoid dependencies back to the monolith. In cases where a new service ends up with a call back to the monolith, I suggest to expose a new API from the monolith, and access the API through an anti-corruption layer in the new service to make sure that the monolith concepts do not leak out. Strive to define the API reflecting the well defined domain concepts and structures, even though the monolith’s internal implementation might be otherwise. In this unfortunate case the delivery teams will be bearing the cost and difficulty of changing the monolith, testing and releasing the new services coupled with the monolith release.

圖3:解耦沒有依賴關系的服務,并盡量減少對老系統的修改

Figure 3: Decouple the service that doesn’t require a dependency back to the monolith first and minimize changes to the monolith

盡早解耦粘性功能

首先我們假設,交付團隊樂意于構建微服務,并準備解決遇到的棘手的問題。然而,交付團隊很可能會發現自己缺乏將服務解耦到對老系統不再有依賴關系的能力。造成這種情況的根本原因,往往是因為在整體架構中的某個功能模塊的設計上存在問題,沒有被很好地定義為領域概念,導致系統中大量的功能都依賴于它。為了能夠將解耦進行下去,開發人員需要識別出這些“粘性功能(Sticky Capabilities)”,將其解構為擁有良好定義的領域概念,并將這些領域概念轉化為多帶帶的服務。

I am assuming that at this point the delivery teams are comfortable with building microservices and ready to attack the sticky problems. However they may find themselves limited with the capabilities that they can decouple next without a dependency back to the monolith. The root cause of this, is often a capability within the monolith that is leaky, not well defined as a domain concept, with many of the monolith capabilities depending on it. In order to be able to progress, the developers need to identify the sticky capability, deconstruct it into well defined domain concepts and then reify those domain concepts into separate services.

比如在一個網站的單體系統中,會話(Session)是最常見的耦合因素之一。在在線零售系統的示例中,Session中通常存放著許多東西,從跨越了多個域邊界的用戶偏好(比如物流和支付的偏好設置)到用戶的意圖和用戶交互(比如最近訪問的頁面,瀏覽過的產品和愿望清單)。如果我們不進行解耦、重構當前的會話概念,我們將很難解耦剩下的更多功能,因為它們通過四處彌漫著的Session與老系統緊緊地耦合在了一起。 同時,我也不鼓勵在整體框架之外另外創建一個“會話”服務,因為它只會導致類似的強耦合。相比之下,目前這種耦合關系僅存在于整體的業務流程之中,更糟糕的是,讓它散布到業務流程之外乃至整個網絡中。

For example in a web based monolith, the notion of ‘(web) session’ is one of those most common coupling factors. In the online retail example, the session is often a bucket for many attributes ranging from user preferences across different domain boundaries such as shipping and payment preferences, to user intentions and interactions such as recently visited pages, clicked products, and wish list. Unless we tackle decoupling, deconstructing and reifying the current notion of ‘session’, we will struggle to decouple many of the future capabilities as they will be entangled with the monolith through the leaky session concepts. I also discourage creating a ‘session’ service outside of the monolith, as it will just result in a similar tight coupling that currently exist within the monolith process, only worse, out of process and across the network.

開發人員可以逐步地從粘性功能中將微服務提取出來,即一次只提供一個服務。例如,首先重構“愿望清單”并將其提取到新服務中,然后將“默認付款方式”重構為另一個微服務,并以此類推。

Developers can incrementally extract microservices from the sticky capability, one service at time. As an example, refactor "customer wish list" first and extract that into a new service, then refactor "customer payment preferences" into another microservice and repeat.

圖4:找到最多的耦合概念并將其解耦重構為具體的領域服務

Figure 4: Identify the most coupling concept and decouple, deconstruct and reify into concrete domain services

使用依賴性和結構化代碼分析工具(如Structure101)來確定整體結構中最具耦合性和約束性的業務功能。

Use dependency and structural code analysis tools such as Structure101 to identify the most coupling and constraining factor capabilities in the monolith.

垂直解耦并且提前發布數據

解耦業務功能的主要驅動力就是讓它們可以獨立發布。它作為第一原則,指導開發人員如何進行解耦的每一個決定。單體系統通常由多個緊密集成的層結構甚至是多個子系統組成,而這些系統需要一起發布,并且具有很脆弱的相互依賴性。例如,一個在線零售系統可能由若干個的直接面向客戶的前端應用程序,和一個實現了許多業務功能的集中式數據存儲的后端系統組成。

The main driver for decoupling capabilities out of a monolith is to be able to release them independently. This first principle should guide every decision that developers make around how to perform the decoupling. A monolithic system often is composed of tightly integrated layers or even multiple systems that need to be released together and have brittle interdependencies. For example, in an online retail system, the monolith composed of one or multiple customer facing online shopping applications, a back-end system implementing many of the business capabilities with a centrally integrated data store to hold state.

大多數的所謂解耦嘗試,只是試圖將一些面向用戶的組件分離出來,并通過外觀模式為前端提供易于使用的API,而數據依然被深鎖于單體系統之中。這種方法雖然能快速取得一些成效,比如使得系統可以更頻繁地更改UI,但是一旦涉及到系統的核心功能,更新速度便立刻受限于整個系統中更新最慢的部分——單體系統本身及它的數據存儲。簡而言之,沒有對數據本身進行分離的架構并不是微服務。把所有數據都存儲在一起的思想本身就與微服務的“分布式數據管理”思想相悖。

Most decoupling attempts start with extracting the user facing components and a few facade services to provide developer friendly APIs for the modern UIs, while the data remains locked in one schema and storage system. Though this approach gives some quick wins such as changing the UI more frequently, when it comes to core capabilities the delivery teams can only move as fast as the slowest part, the monolith and its monolithic data store. Simply put, without decoupling the data, the architecture is not microservices. Keeping all the data in the same data store is counter to the Decentralized Data Management characteristic of microservices.

解決方案:垂直地分離各個業務功能,連業務邏輯帶數據一起進行解耦,并且各個前端應用的調用重定向到新的API上。

The strategy is to move out capabilities vertically, decouple the core capability with its data and redirect all front-end applications to the new APIs.

對于這種數據加服務一起解耦的方法而言,其解耦過程中的主要障礙就是那些需要對集中存儲的共享數據進行并發讀寫的各個應用程序。針對這種情況,交付團隊需要提供合適的數據遷移策略,具體取決于他們能否在同時對所有數據的讀寫做重定向和遷移。Stripe所寫的“數據遷移的四階段策略”適用于許多需要進行數據增量遷移的環境,并且可以保證所有正在進行遷移的系統可以不中斷地運作。

Having multiple applications writing and reading to and from the centrally shared data is the main blocker to decoupling the data along with the service. The delivery teams need to incorporate a data migration strategy that suits their environment depending on whether they are able to redirect and migrate all the data readers/writers at the same time or not. Stripe’s four phase data migration strategy is one that applies to many environments that require to incrementally migrate the applications that integrate through the database, while all the systems under change need to run continuously.

圖5:將數據和服務遷移到微服務中,并將所有調用方調整和重定向至新API

Figure 5: Decouple capability with its data to a microservice exposing a new interface, modify and redirect consumers to the new API

避免只解耦調用接口或后端服務而不解耦數據的反模式

Avoid the anti pattern of only decoupling facades, only decoupling the backend service and never decoupling data.

解耦重要而易變的業務功能

從單體系統中將業務功能解耦出來是一件很難的事情。我聽說,Neal Ford將其比作“一臺小心翼翼的器官手術”。從在線零售系統中提取業務功能時,需要仔細地將業務邏輯、數據、UI組件提取出來并將它們重定向到新服務。因為其所需的工作量不是一點兩點,所以開發者們需要不斷地評估進行解耦的成本與其能夠帶來的好處,比如,是想要追求更快的開發速度,還是要追求規模上的成長。舉個例子,如果交付團隊的目標是想在修改單體系統中的現有業務功能時耗時更少,那么他們必須找到修改最耗時的業務功能并將其分離。把代碼中不斷發生變化的部分多帶帶分離出來,可以從開發人員那里得到很多的愛,還可以讓他們可以最快速地產出價值。交付團隊還可以通過對代碼的提交記錄做分析,找到那些變化得最多的部分,并將其與產品路線圖、產品組合一起分析,以確定在將來最期望的功能,并將其分離出來。他們需要與業務經理、產品經理一起交談,以了解對他們而言真正重要的差異化能力。

Decoupling capabilities from the monolith is hard. I’ve heard Neal Ford use the analogy of a careful organ surgery. In the online retail application, extracting a capability involves carefully extracting the capability’s data, logic, user facing components and redirecting them to the new service. Because this is a non-trivial amount of work, the developers need to continuously evaluate the cost of decoupling against the benefits that they get, e.g. going faster or growing in scale. For example, if the delivery teams" objective is to accelerate the modifications to existing capabilities locked in a monolith, then they must identify the capability that is being modified the most to take out. Decouple parts of the code that are continuously undergoing change and getting a lot of love from the developers and are constraining them most to deliver value fast. The delivery teams can analyse the code commit patterns to find out what has historically changed most, and overlay that with the product roadmap and portfolio to understand the most desired capabilities that will be getting attention in near future. They need to talk to the business and product managers to understand the differentiating capabilities that really matter to them.

例如,在一個在線零售系統中,“客戶個性化”是一項為了提供最佳用戶體驗的、經過了大量實驗的功能。因為它是一項事關客戶體驗的非常重要的業務功能,并且經常需要修改,所以它是一個進行解耦的良好目標。

For example in an online retail system, ‘customer personalization’ is a capability that goes under a lot of experimentation to provide the best experience to the customer and is a good candidate for decoupling. It is a capability that matters to business a lot, customer experience, and gets modified frequently.

圖6:找到最重要的業務功能并解耦:在定期迭代中創建最多的業務和用戶價值

Figure 6: Identify and decouple the capability that matters most: creates most value for business and customer, while changing regularly.

利用社交代碼分析工具(如CodeScene)來查找代碼中最活躍更改的組件。如果自動構建系統會在每次提交時觸發或自動生成代碼,請確保過濾掉這些噪聲。將經常發生更改的代碼與產品路線圖上預計進行的更改疊加,并找到進行解耦的交點。

Use social code analysis tools such as CodeScene to find the most lively components. Make sure to filter signal from the noise if the build system happens to touch or auto-generate code on every commit. Overlay the frequently changed code with the product roadmap upcoming changes and find the intersection to decouple.

解耦業務功能,不是解耦業務代碼

無論何時,只要開發人員想要從系統中解耦一項服務出來,他們都有兩種可行的辦法:提取代碼,或是直接重寫。

Whenever developers want to extract a service out of an existing system, they have two ways to go about it: extract code or rewrite capability.

一般來說,服務的提取,或是單體系統的解構都默認被設想為是通過重用現有的實現方案并將其提取到多帶帶的服務中來實現。其中的部分原因是因為,我們對我們所親自設計和編寫的出來的代碼有著認知偏好。對于我們所辛苦付出了勞動而收獲的結果,無論過程有多么痛苦,結果有多么不完善,我們都會懷有熱愛。這實際上被稱為“宜家效應”。不幸的是,這種認知偏好會阻礙我們在分解單體系統所付出的努力。它使得開發人員和更重要的技術管理人員忽略了提取和重用現有代碼的高成本和低價值。

Often by default the service extraction or monolith decomposition is imagined as a case of reusing the existing implementation as-is and extracting it into a separate service. Partly because we have a cognitive bias towards the code we design and write. The labor of building, no matter how painful the process or imperfect the result, make us grow love for it. This is in fact known as the IKEA Effect. Unfortunately this bias is going to hold the monolith decomposition effort back. It causes the developers and more importantly technical managers to disregard the high cost and low value of extracting and reusing the code.

比如說,在零售系統中,“定價和促銷”功能是一段相當復雜的高難度代碼,它可以動態地配置和應用促銷規則,并且根據各種參數(例如客戶行為,忠誠度,產品捆綁等)提供折扣和優惠。

For example in the retail system, the ‘pricing and promotion’ capability is an intellectually complex piece of code. It enables dynamic configuration and application of pricing and promotion rules, providing discounts and offers based on a variety of parameters such as customer behavior, loyalty, product bundles, etc.

像“定價和促銷”這樣的業務功能,就是進行“重用及提取”的完美選擇。而相比之下,“客戶信息”就是一個很簡單的CRUD功能點,主要也就包括序列化、數據存儲以及相關配置之類的一些模板功能,因此,它是進行“重寫和淘汰”的理想對象。

This capability is arguably a good candidate for reuse and extraction. In contrast, ‘customer profile’ is a simple CRUD capability that is mostly composed of boilerplate code for serialization, handling storage and configuration, hence, it is a good candidate for rewrite and retire.

根據我的經驗,在大多數系統解構的情況中,考慮到重用的高成本和低價值,交付團隊應當將業務功能重寫為新的服務并淘汰掉舊代碼。理由如下:

老代碼中存在大量的“模板代碼”,用于處理一些諸如“在運行時獲取應用程序配置”、“訪問數據存儲”、“數據緩存”之類的環境依賴,并且這些代碼還都是用的老框架寫的。而大部分的這些模板代碼,都需要重寫。承載微服務的新基礎架構與這些跑了好幾十年的老代碼有很大不同,并且需要相差甚遠的新的模板代碼來做這些事。

現有的業務功能,很有可能并不是圍繞著一個清晰的領域概念而構建的。這導致了進行傳輸和存儲的數據結構并不能直接反映新的領域模型,并且需要進行徹底的重構。

經歷了許多變化和迭代而長期存在的遺留代碼,很有可能具有很高的“代碼毒性”,并且重用價值很低。

In my experience, in majority of the decomposition scenarios, the teams are better off to rewrite the capability as a new service and retire the old code. This is considering the high cost and low value of reuse, due to reasons such as below:

There is a large amount of boilerplate code that deals with environmental dependencies, such as accessing application configuration at runtime, accessing data stores, caching, and is built with old frameworks. Most of this boilerplate code needs to be rewritten. The new infrastructure to host a microservice is very different from the decades old application runtime and will require a very different kind of boilerplate code.

It is very likely that the existing capabilities are not built around clear domain concepts. This results in transporting or storing data structures that are not reflecting the new domain models and require undergoing a big restructuring.

A long lived legacy code that has gone through many iterations of change could have a high code toxicity level and low value for reuse.

除非待解耦的業務功能與清晰的領域概念相一致,并且邏輯精巧復雜,否則我強烈建議進行重寫,并淘汰老代碼。

Unless the capability is relevant, aligned with a clear domain concept and has high intellectual property, I strongly recommend a rewrite and retiring of the old code.

圖7:重用和提取低毒性的高價值代碼,重寫和淘汰高毒性的低價值代碼

Figure 7: Reuse and Extract high value code with low toxicity, Rewrite and Retire low value code with high toxicity

使用代碼毒性分析工具(如CheckStyle)來做出關于重寫與重用的決策。

Use code toxicity analysis tools such as CheckStyle to make decisions around rewrite vs. reuse.

先宏觀,再微觀

從遺留單體系統中尋找領域邊界,既是一門藝術,又是一門科學。而作為一個具有普適性的規則,利用領域驅動設計的概念來尋找“上下文邊界”來定義微服務的邊界是一個很好的開始。我承認,我經??吹揭恍﹩误w系統的解耦在粒度上“矯枉過正”,將一個過大的系統切分為了過小的服務,而這些過小的服務常常是從現有數據的視角上出發的。而這種的微服務識別方法,幾乎總是會導致大量與資源的CURD直接相關的貧血服務的“寒武紀生物大爆發”。對于新的微服務架構來說,這將創建一個高度摩擦的環境,并且最終無法獨立發布測試,也無法提供服務。這種方式創建了一個難以調試的分布式系統,一個跨越事務邊界的分布式系統,因此很難保持一致,這一切對于運維來說,太復雜了。盡管存在一些關于微服務粒度的“啟發方法”,諸如團隊大小,重寫服務的時間,必須包括多少行為等等,我的建議是,微服務的規模將取決于運維團隊可以獨立發布、監控和運營的服務數量。首先,圍繞領域概念構建一個大型服務,待團隊的微服務運維能力提升之后再將其分解為多個小服務。

Finding the domain boundaries in a legacy monolith is both an art and science. As a general rule applying domain driven design techniques to find the bounded contexts defining microservices boundaries is a good place to start. I admit, far too often I see an overcorrection from large monolith to really small services, really small services whose design is inspired and driven by the existing normalized view of the data. This approach to identifying service boundaries almost always leads to a cambrian explosion of large number of anemic services for CRUD resources. For many new to the microservices architecture, this creates a high friction environment that ultimately fails the test of independent release and execution of the services. It creates a distributed system that is hard to debug, a distributed system that is broken across transactional boundaries and hence difficult to keep consistent, a system that is too complex for the operational maturity of the organization. Though there are some heuristics on how ‘micro’ should be the microservice: the size of the team, the time to rewrite the service, how much behavior it must encapsulate, etc. My advice is that the size depends on how many services the delivery and operation teams can independently release, monitor and operate. Start with larger services around a logical domain concept, and break the service down into multiple services when the teams are operationally ready.

例如,在解耦零售系統的過程中,開發者可以從“購買”服務開始解耦?!百徺I”服務內封裝了“購物袋”的功能,還封裝了購買一個真正的購物袋的功能,即“結賬”。而隨著他們組建團隊并發布更多服務的能力不斷增強,他們可以將“購物袋”功能從“結賬”中解耦出來,成為一個多帶帶的服務。

For example, on the journey decoupling the retail system, developers may start with one service ‘buy’ that encapsulates both the content of a ‘shopping bag’ as well as capability of buying the shopping bag, i.e ‘check out’. As their ability to form smaller teams and release larger number of services grows then they can decouple ‘shopping bag’ from ‘check out’ into a separate service.

圖8:圍繞豐富的領域概念從宏觀角度上進行解耦,在準備就緒后,將服務細分為更小的領域概念

Figure 8: Decouple macro services around rich domain concepts and when ready, breakdown services to smaller domain concepts

使用Richardson L3成熟度模型和超鏈接,可以在不影響調用方的情況下實現未來的服務分離,即調用方可以發現如何結賬,并且需要提前知道。

Use Richardson Maturity Model L3 and hyperlinks to enable future decoupling of services without impacting callers, i.e. caller discovers how to checkout and does not know in advanced.

原子性地按步遷移

想直接將一個巨型單體系統解構成一個精心設計的微服務系統,從而讓其在空氣中消失,是一件是不可能的事。任何一個經驗豐富的工程師都可以分享一些關于嘗試進行遺留系統的升級和遷移的故事。而這些嘗試,在最開始都是以非常樂觀的方式被計劃和啟動的,然而它們最好的結局一般都是“在一個足夠好的時間點被及時放棄”。由于一個宏觀條件的變化,這些系統遷移的長期計劃會被放棄,比如項目資金耗盡、高層的關注重點轉移,或者支持這個項目的領導走人了。所以,現實是,團隊應該如何做規劃,來開始這場龐大的微服務解耦之旅。這種方法,我稱之為“架構演進的原子性按步遷移”。遷移的每一步,都應使架構更接近其目標狀態。而每一次的架構演進,都應該是原子性的——無論是一個小步驟還是一個大飛躍,要么完成,要么回滾。這是非常重要的,因為我們正在采取迭代和漸進的方法來改進整體架構和進行服務解耦。就完成架構目標而言,每個改變都必須讓我們處于更好的位置。使用“演進架構”的適應度函數進行隱喻的話,演進的每個原子步驟之后的架構適應度函數都應該對架構的目標產生更高價值。

The idea of vanishing a legacy monolith into thin air by decoupling it into beautifully designed microservices is somewhat of a myth and arguably undesirable. Any seasoned engineer can share stories of legacy migration and modernization attempts that got planned and initiated with over optimism of total completion, and at best got abandoned at a good enough point in time. Long term plans of such endeavors get abandoned because the macro conditions change: the program runs out of money, the organization pivots its focus to something else or leadership in support of it leaves. So this reality should be designed in how the teams approach the monolith to microservices journey. I call this approach "migration in atomic steps of architecture evolution", where every step of the migration should take the architecture closer to its target state. Each unit of evolution might be a small step or a large leap but is atomic, either completes or reverts. This is specially important as we are taking an iterative and incremental approach to improving the overall architecture and decoupling services. Every increment must leave us in a better place in terms of the architecture goal. Using the evolutionary architecturefitness function metaphor, the architecture fitness function after every atomic step of migration should generate a closer value to the architecture’s goal.

讓我舉一個例子來說明這一點。 想象一下,微服務架構的目標是提高開發人員的修改系統以提供價值的速度。團隊決定將最終用戶身份驗證解耦為一個基于OAuth 2.0協議的多帶帶服務。此服務旨在替代現有老架構中的用戶身份驗證系統,并以微服務的新體系結構來進行身份驗證。 我們將這種增量改變稱為“導入鑒權服務”。導入這項新服務的一種方法是:

(1)構建鑒權服務,實現OAuth 2.0協議。

(2)在老系統后端添加一個新的認證路徑,以調用鑒權服務來認證最終用戶。

Let me illustrate this point with an example. Imagine the microservice architecture goal is to increase the speed of developers modifying the overall system to deliver value. The team decides to decouple the end user authentication into a separate service based on OAuth 2.0 protocol. This service is intended to both replace how the existing (old architecture) client application authenticates the end user, as well as new architecture microservices validate the end user. Let"s call this increment in the evolution, ‘Auth service introduction’. One way to introduce the new service is to go through these steps first:

(1) Build the Auth service, implementing OAuth 2.0 protocol.

(2) Add a new authentication path in the monolith back end to call Auth service for authenticating the end user on whose behalf it is processing a request.

如果團隊至此而止,轉而去開發一些其他服務或功能的話,他們會將整體架構置于熵增狀態。因為在此狀態下,有兩種實現用戶身份驗證的方式,即新的OAuth 2.0路徑和舊客戶端的基于密碼/會話的路徑。在這一點上,團隊實際上遠離了實現更快更改的總體目標。對于新來的老系統開發人員來說,現在需要處理兩條代碼路徑了。這實際上增加了熟悉代碼的工作量,還導致更改和測試代碼的過程變得更慢了。

If the team stops here and pivots into building some other service or feature, they leave the overall architecture in a state of increased entropy. In this state there are two ways of authenticating the user, the new OAuth 2.0 base path, and old client’s password/session based path. At this point the teams are actually further away from their overall goal of making changes faster. Any new developer to the monolith code needs to deal with two code paths, increased cognitive load of understanding the code, and slower process of changing and testing it.

相反,團隊可以在我們的原子演進單元中包含以下步驟:

(3)將舊客戶端的基于密碼/會話的身份驗證替換為OAuth 2.0路徑

(4)從老系統中刪除舊的驗證路徑

Instead the team can include the following steps in our atomic unit of evolution:

(3) Replace old client’s password/session based authentication with OAuth 2.0 path

(4) Retire the old authentication code path from the monolith

在這一點上,我們可以爭辯說,在這一點上,團隊已經接近目標架構。

At this point we can argue that the teams have gotten closer to the target architecture.

圖9:使用原子演進步驟將體系結構演進為微服務。即使中間代碼更改可能會導致其遠離其目標,但每步完成后,整體體系結構都朝向目標方向改進

Figure 9: Evolve the architecture towards microservices with atomic steps of architecture evolution where after each step the overall architecture is improved towards its goal even though intermediary code changes might take it further away from its fitness objective

單體系統解構的原子單元包括:

解耦新服務

將調用方重定向至新服務

從單體系統中刪除老代碼

反模式:解耦新服務給新的調用方調用,但是卻不淘汰舊服務

The atomic unit of monolith decomposition includes:

Decouple the new service

Redirect all consumers to new service

Retire the old code path in the monolith.

The anti-pattern: Decouple the new service, use for new consumers and never retire the old.

我經常發現,團隊完成了一個業務功能的遷移,并且在新的業務功能建立之后立即宣告勝利,而不淘汰舊的代碼路徑,即上述的反模式。論其主要原因,一是注重引入新功能帶來的短期收益,二為淘汰舊實現所需的總體工作量,同時還面臨著開發新功能的優先級競爭。為了做正確的事情,我們需要使演進的原子步驟盡可能小。

I often find teams end migration of a capability out of the monolith and claim victory as soon as the new capability is built without retiring the old code path, the anti-pattern described above. The main reasons for this are (a) the focus on short-term benefits of introducing a new capability and (b) the total amount of effort required to retire the old implementations while facing competing priorities for building new features. In order to do the right thing, we need to strive for making the atomic steps as small as possible.

通過這種方式進行遷移,我們可以在解耦的旅途中小憩,也可以安全地停下來休養生息,并在這漫長的旅程中幸存下來,徹底消滅舊系統。

Migrating with this approach we can break up the journey to shorter trips. We can safely stop, revive and survive this long journey, slaying the monolith.

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11868.html

相關文章

  • 單體系統到微服務正確打開方式

    摘要:從單體系統到微服務的正確打開方式原文標題原文鏈接注每一段譯文后跟作者原文,原文中可能包含著作者所提到的內容的跳轉超鏈接。從一整塊單體系統遷移到微服務生態系統簡直是一段史詩般的旅程。 從單體系統到微服務的正確打開方式 原文標題:How to break a Monolith into Microservices原文鏈接:https://martinfowler.com/arti...注:...

    tunny 評論0 收藏0
  • 小強開飯店-單體應用到微服務

    摘要:本篇博客通過小強開飯店的通俗易懂的故事,帶你了解后端服務是如果從單體應用演變到微服務的。小強開飯店有一天,小強為了早日奔赴小康生活,打算開一個飯店來幫他快速的實現這個目標。于是小強開始給服務盡量的無狀態化,然后在一個服務器上啟動了幾個實例。 本篇博客通過小強開飯店的通俗易懂的故事,帶你了解后端服務是如果從單體應用演變到微服務的。如果有說的不對的地方,歡迎各位大佬強勢懟。 小強開飯店 有...

    shengguo 評論0 收藏0
  • 一文讀懂微服務架構重構策略

    摘要:相反,它由單體中的適配器和使用一個或多個進程間通信機制的服務組成。因為微服務架構的本質是一組圍繞業務功能組織的松耦合服務。如果你嘗試將此類功能實現為服務,則通常會發現,由于過多的進程間通信而導致性能下降。這是快速展示微服務架構價值的好方法。你很有可能正在處理大型復雜的單體應用程序,每天開發和部署應用程序的經歷都很緩慢而且很痛苦。微服務看起來非常適合你的應用程序,但它也更像是一項遙不可及的必殺...

    jaysun 評論0 收藏0
  • 聊聊微服務集群當中自動化工具

    摘要:本篇博客主要介紹了自動化工具這個概念,在微服務集群當中的作用,算拋磚引玉,歡迎大家提出自己的見解。而在微服務中,單個服務重新部署的代價明顯要小的多。 本篇博客主要介紹了自動化工具這個概念,在微服務集群當中的作用,算拋磚引玉,歡迎大家提出自己的見解。 寫在前面 在了解自動化工具的概念之前,我們先了解一下微服務和集群的概念。 什么是微服務 這個概念其實有些廣泛,而我的知識廣度也有限,我會盡...

    Hancock_Xu 評論0 收藏0
  • 7個 Javascript 面試題及回答策略

    摘要:使用異步編程,有一個事件循環。它作為面向對象編程的替代方案,其中應用狀態通常與對象中的方法搭配并共享。在用面向對象編程時遇到不同的組件競爭相同的資源的時候,更是如此。 翻譯:瘋狂的技術宅原文:https://www.indeed.com/hire/i... 本文首發微信公眾號:jingchengyideng歡迎關注,每天都給你推送新鮮的前端技術文章 不管你是面試官還是求職者,里面...

    李義 評論0 收藏0

發表評論

0條評論

n7then

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<