原文出自:http://nginx.com/blog/introduction-to-microservices 。我在其中加入了簡單的翻譯和本身的一些見解。
html
This is a guest post by Chris Richardson. Chris is the founder of the original CloudFoundry.com, an early Java PaaS (Platform-as-a-Service) for Amazon EC2. He now consults with organizations to improve how they develop and deploy applications. He also blogs regularly about microservices at http://microservices.io.nginx
==============程序員
Microservices are currently getting a lot of attention: articles, blogs, discussions on social media, and conference presentations. 微服務是最近一兩年在架構領域很是流行的一個話題。They are rapidly heading towards the peak of inflated expectations on the Gartner Hype cycle. At the same time, there are skeptics in the software community who dismiss microservices as nothing new. Naysayers claim that the idea is just a rebranding of SOA. 反對者說微服務只是 SOA 的一個翻版。However, despite both the hype and the skepticism, the Microservice architecture pattern has significant benefits – especially when it comes to enabling the agile development and delivery of complex enterprise applications. 當採用敏捷開發和交付複雜的企業應用時,微服務更能體現出它的優勢。web
This blog post is the first in a 7-part series about designing, building, and deploying microservices. You will learn about the approach and how it compares to the more traditional Monolithic architecture pattern. This series will describe the various elements of the Microservice architecture. You will learn about the benefits and drawbacks of the Microservice architecture pattern, whether it makes sense for your project, and how to apply it.數據庫
Let’s first look at why you should consider using microservices.apache
Let’s imagine that you were starting to build a brand new taxi-hailing application intended to compete with Uber and Hailo. 舉個例子,構建一個滴滴、快的這樣的打車軟件 After some preliminary meetings and requirements gathering, you would create a new project either manually or by using a generator that comes with Rails, Spring Boot, Play, or Maven. This new application would have a modular hexagonal architecture, like in the following diagram:後端
At the core of the application is the business logic, which is implemented by modules that define services, domain objects, and events. Surrounding the core are adapters that interface with the external world. Examples of adapters include database access components, messaging components that produce and consume messages, and web components that either expose APIs or implement a UI. 描述了這個網站的核心業務要包含哪些元素(服務、實體、事件),提供哪些功能(REST API、界面、數據庫訪問、訪問第三方服務等等)api
Despite having a logically modular architecture, the application is packaged and deployed as a monolith. 儘管有邏輯的模塊,但這個應用確實按照一個總體打包部署。The actual format depends on the application’s language and framework. For example, many Java applications are packaged as WAR files and deployed on application servers such as Tomcat or Jetty. Other Java applications are packaged as self-contained executable JARs. Similarly, Rails and Node.js applications are packaged as a directory hierarchy.promise
Applications written in this style are extremely common. They are simple to develop since our IDEs and other tools are focused on building a single application. These kinds of applications are also simple to test. You can implement end-to-end testing by simply launching the application and testing the UI with Selenium. Monolithic applications are also simple to deploy. You just have to copy the packaged application to a server. You can also scale the application by running multiple copies behind a load balancer. In the early stages of the project it works well. 在項目早期階段,這樣的應用開發簡單、測試簡單、部署簡單、伸縮簡單。緩存
Unfortunately, this simple approach has a huge limitation. Successful applications have a habit of growing over time and eventually becoming huge. 成功的應用總會不斷地成長,最終變得巨大。During each sprint, your development team implements a few more stories, which, of course, means adding many lines of code. After a few years, your small, simple application will have grown into a monstrous monolith. To give an extreme example, I recently spoke to a developer who was writing a tool to analyze the dependencies between the thousands of JARs in their multi-million line of code (LOC) application. I’m sure it took the concerted effort of a large number of developers over many years to create such a beast.
Once your application has become a large, complex monolith, your development organization is probably in a world of pain. 一旦你的應用變成巨大複雜的單體應用,你的開發團隊將飽嘗痛苦。Any attempts at agile development and delivery will flounder. 任何在敏捷開發部署上的嘗試都變得舉步維艱。One major problem is that the application is overwhelmingly complex. 一個主要緣由是你的應用過分複雜。It’s simply too large for any single developer to fully understand. As a result, fixing bugs and implementing new features correctly becomes difficult and time consuming. 你的應用將過於龐大,任何一個程序員都難以徹底理解。這致使修改 bug 和正確地開發新功能都變得困難和耗時。 What’s more, this tends to be a downwards spiral. If the codebase is difficult to understand, then changes won’t be made correctly. You will end up with a monstrous, incomprehensible big ball of mud.
The sheer size of the application will also slow down development. The larger the application, the longer the start-up time is. For example, in a recent survey some developers reported start-up times as long as 12 minutes. I’ve also heard anecdotes of applications taking as long as 40 minutes to start up. If developers regularly have to restart the application server, then a large part of their day will be spent waiting around and their productivity will suffer. 編譯啓動的時間也會變長
Another problem with a large, complex monolithic application is that it is an obstacle to continuous deployment. Today, the state of the art for SaaS applications is to push changes into production many times a day. This is extremely difficult to do with a complex monolith since you must redeploy the entire application in order to update any one part of it. The lengthy start-up times that I mentioned earlier won’t help either. Also, since the impact of a change is usually not very well understood, it is likely that you have to do extensive manual testing. Consequently, continuous deployment is next to impossible to do. 持續部署將變得困難
Monolithic applications can also be difficult to scale when different modules have conflicting resource requirements. For example, one module might implement CPU-intensive image processing logic and would ideally be deployed in AWS EC2 Compute Optimized instances. Another module might be an in-memory database and best suited forEC2 Memory-optimized instances. However, because these modules are deployed together you have to compromise on the choice of hardware. 伸縮性將變差
Another problem with monolithic applications is reliability. Because all modules are running within the same process, a bug in any module, such as a memory leak, can potentially bring down the entire process. Moreover, since all instances of the application are identical, that bug will impact the availability of the entire application. 可靠性變得不好,不一樣功能將相互影響。一個模塊中的 bug,例如內存溢出等問題將拖垮整個應用。
Last but not least, monolithic applications make it extremely difficult to adopt new frameworks and languages. For example, let’s imagine that you have 2 million lines of code written using the XYZ framework. It would be extremely expensive (in both time and cost) to rewrite the entire application to use the newer ABC framework, even if that framework was considerably better. As a result, there is a huge barrier to adopting new technologies. You are stuck with whatever technology choices you made at the start of the project. 最後,採用新語言和新技術將變得很是困難。
To summarize: you have a successful business-critical application that has grown into a monstrous monolith that very few, if any, developers understand. It is written using obsolete, unproductive technology that makes hiring talented developers difficult. The application is difficult to scale and is unreliable. As a result, agile development and delivery of applications is impossible.
So what can you do about it?
Many organizations, such as Amazon, eBay, and Netflix, have solved this problem by adopting what is now known as the Microservice architecture pattern. Instead of building a single monstrous, monolithic application, the idea is to split your application into set of smaller, interconnected services. 不少組織採用了微服務
A service typically implements a set of distinct features or functionality, such as order management, customer management, etc. Each microservice is a mini-application that has its own hexagonal architecture consisting of business logic along with various adapters. Some microservices would expose an API that’s consumed by other microservices or by the application’s clients. Other microservices might implement a web UI. At runtime, each instance is often a cloud VM or a Docker container. 每一個服務實現一組特定的功能,例如訂單管理、客戶管理。每一個微服務暴露本身的 API 給其它微服務或者客戶端使用。運行時,每一個實例是一個虛擬機或者 Docker 容器。
For example, a possible decomposition of the system described earlier is shown in the following diagram:
Each functional area of the application is now implemented by its own microservice. Moreover, the web application is split into a set of simpler web applications (such as one for passengers and one for drivers in our taxi-hailing example). This makes it easier to deploy distinct experiences for specific users, devices, or specialized use cases.
Each back-end service exposes a REST API and most services consume APIs provided by other services. For example, Driver Management uses the Notification server to tell an available driver about a potential trip. The UI services invoke the other services in order to render web pages. Services might also use asynchronous, message-based communication. Inter-service communication will be covered in more detail later in this series.每一個後端服務暴露 REST API(也能夠是其它形式的 API,好比基於 TCP/UDP 的遠程調用)。服務也可以使用異步的,基於消息的通信。服務間通信將在後續章節詳細介紹。
Some REST APIs are also exposed to the mobile apps used by the drivers and passengers. The apps don’t, however, have direct access to the back-end services. Instead, communication is mediated by an intermediary known as an API Gateway. The API Gateway is responsible for tasks such as load balancing, caching, access control, API metering, and monitoring, and can be implemented effectively using NGINX. Later articles in the series will cover the API Gateway. 一些 REST API 是提供給移動應用的。可是移動應用並非直接訪問後端服務,而是經過一個能夠被認爲是 API 網關的中介去實現。這個 API 網關提供了例如負載均衡、訪問控制、緩存、API 監控等功能(一個更重要的功能是整合 API 調用請求,使其更適合移動網絡環境。在服務間調用中,有時也須要負載均衡等功能)
The Microservice architecture pattern corresponds to the Y-axis scaling of the Scale Cube, which is a 3D model of scalability from the excellent book The Art of Scalability. The other two scaling axes are X-axis scaling, which consists of running multiple identical copies of the application behind a load balancer, and Z-axis scaling (or data partitioning), where an attribute of the request (for example, the primary key of a row or identity of a customer) is used to route the request to a particular server.
Applications typically use the three types of scaling together. Y-axis scaling decomposes the application into microservices as shown above in the first figure in this section. At runtime, X-axis scaling runs multiple instances of each service behind a load balancer for throughput and availability. Some applications might also use Z-axis scaling to partition the services. The following diagram shows how the Trip Management service might be deployed with Docker running on AWS EC2. 系統伸縮性的三個方向,微服務對應於 Y 軸
At runtime, the Trip Management service consists of multiple service instances. Each service instance is a Docker container. In order to be highly available, the containers are running on multiple Cloud VMs. In front of the service instances is a load balancer such as NGINX that distributes requests across the instances. The load balancer might also handle other concerns such as caching, access control, API metering, and monitoring.
The Microservice architecture pattern significantly impacts the relationship between the application and the database. Rather than sharing a single database schema with other services, each service has its own database schema. On the one hand, this approach is at odds with the idea of an enterprise-wide data model. Also, it often results in duplication of some data. However, having a database schema per service is essential if you want to benefit from microservices, because it ensures loose coupling. The following diagram shows the database architecture for the example application. 微服務架構將顯著影響應用和數據庫之間的關係。每一個服務將有本身的數據庫,而不是通向同一個數據庫。(注意數據庫和數據庫服務器的不一樣)。固然,這會致使一些重複數據,可是每一個服務使用獨立的數據庫是必要的。由於微服務強調解耦。(而共享數據庫將使微服務之間創建一種強大緊密的關聯關係)
Each of the services has its own database. Moreover, a service can use a type of database that is best suited to its needs, the so-called polyglot persistence architecture. For example, Driver Management, which finds drivers close to a potential passenger, must use a database that supports efficient geo-queries. 每一個服務使用不一樣的數據庫,可使服務選擇適合其的數據庫產品
On the surface, the Microservice architecture pattern is similar to SOA. With both approaches, the architecture consists of a set of services. However, one way to think about the Microservice architecture pattern is that it’s SOA without the commercialization and perceived baggage of web service specifications (WS-) and an Enterprise Service Bus (ESB). Microservice-based applications favor simpler, lightweight protocols such as REST, rather than WS-. They also very much avoid using ESBs and instead implement ESB-like functionality in the microservices themselves. The Microservice architecture pattern also rejects other parts of SOA, such as the concept of a canonical schema. 表面上微服務架構模式相似 SOA。不一樣點在於 SOA 使用了 Web Service 規範組 (WS-*) 和 企業服務總線 (ESB)。微服務偏心簡單輕量的協議,而不是像 SOAP 這樣重量級的技術。(隨着技術的發展,程序員能夠用比過去少得多的代碼開發出同樣,甚至更好的功能來)
The Microservice architecture pattern has a number of important benefits. First, it tackles the problem of complexity. It decomposes what would otherwise be a monstrous monolithic application into a set of services. While the total amount of functionality is unchanged, the application has been broken up into manageable chunks or services. Each service has a well-defined boundary in the form of an RPC- or message-driven API. The Microservice architecture pattern enforces a level of modularity that in practice is extremely difficult to achieve with a monolithic code base. Consequently, individual services are much faster to develop, and much easier to understand and maintain. 微服務將複雜的單體應用分解爲一組小的服務。微服務促進了模塊化,這在單體應用中難以實現(並不是指單體應用技術上難以實現模塊化,而是之單體應用的模塊化設計容易墮落爲混亂的狀態)。每一個服務更容易開發、理解和維護。
Second, this architecture enables each service to be developed independently by a team that is focused on that service. The developers are free to choose whatever technologies make sense, provided that the service honors the API contract. Of course, most organizations would want to avoid complete anarchy and limit technology options. However, this freedom means that developers are no longer obligated to use the possibly obsolete technologies that existed at the start of a new project. When writing a new service, they have the option of using current technology. Moreover, since services are relatively small it becomes feasible to rewrite an old service using current technology. 這個架構使得每一個服務容易被一個團隊專一地開發。開發者能夠自由選擇適合的技術。小的服務也使得用新的技術重寫變得更爲可行。
Third, the Microservice architecture pattern enables each microservice to be deployed independently. Developers never need to coordinate the deployment of changes that are local to their service. These kinds of changes can be deployed as soon as they have been tested. The UI team can, for example, perform A|B testing and rapidly iterate on UI changes. The Microservice architecture pattern makes continuous deployment possible. 微服務架構使得每一個服務能夠被獨立地部署。一個服務一旦完成測試就能被部署。例如,UI 團隊可使用 AB 測試,快速地迭代 UI 變化。微服務架構使得持續部署變爲可能。
Finally, the Microservice architecture pattern enables each service to be scaled independently. You can deploy just the number of instances of each service that satisfy its capacity and availability constraints. Moreover, you can use the hardware that best matches a service’s resource requirements. For example, you can deploy a CPU-intensive image processing service on EC2 Compute Optimized instances and deploy an in-memory database service on EC2 Memory-optimizedinstances. 微服務使得每一個服務能夠被單獨地伸縮擴展。能夠按照每一個服務不一樣的容量和可用性要去部署。每一個服務不一樣的資源要求也能被知足。
As Fred Brooks wrote almost 30 years ago, there are no silver bullets. Like every other technology, the Microservice architecture has drawbacks. One drawback is the name itself. The term microservice places excessive emphasis on service size. In fact, there are some developers who advocate for building extremely fine-grained 10-100 LOC services. While small services are preferable, it’s important to remember that they are a means to an end and not the primary goal. The goal of microservices is to sufficiently decompose the application in order to facilitate agile application development and deployment. 微服務不是銀彈。微服務的微只是結果,而非主要的目的
Another major drawback of microservices is the complexity that arises from the fact that a microservices application is a distributed system. Developers need to choose and implement an inter-process communication mechanism based on either messaging or RPC. Moreover, they must also write code to handle partial failure since the destination of a request might be slow or unavailable. While none of this is rocket science, it’s much more complex than in a monolithic application where modules invoke one another via language-level method/procedure calls. 由於微服務本質上是一個分佈式系統,這會增長系統技術上的複雜性。開發人員要考慮如何實現跨進程通訊。進一步,還要處理處理更復雜的失敗場景。雖然這不是高深的技術,可是顯然要難於單體應用。
Another challenge with microservices is the partitioned database architecture. Business transactions that update multiple business entities are fairly common. These kinds of transactions are trivial to implement in a monolithic application because there is a single database. In a microservices-based application, however, you need to update multiple databases owned by different services. Using distributed transactions is usually not an option, and not only because of the CAP theorem. They simply are not supported by many of today’s highly scalable NoSQL databases and messaging brokers. You end up having to use an eventual consistency based approach, which is more challenging for developers. 另外一個挑戰來源於事務性,由於服務使用的數據庫彼此分離。ACID 再也不像單體應用那樣容易實現。這不只是由於分佈式的 CAP 理論,也來源於不少 NoSQL 和消息隊列並不支持強一致性。你最終能選擇的只是實現最終一致性。
Testing a microservices application is also much more complex. For example, with a modern framework such as Spring Boot it is trivial to write a test class that starts up a monolithic web application and tests its REST API. In contrast, a similar test class for a service would need to launch that service and any services that it depends upon (or at least configure stubs for those services). Once again, this is not rocket science but it’s important to not underestimate the complexity of doing this. 測試也會更爲複雜呢。例如,使用像 Spring Boot 這樣的現代框架測試開發一個單體的 Web 應用的 REST API 很是簡單。可是若是是微服務架構,你將要運行一系列你所依賴的服務進行測試(這裏做者沒有區分單元測試和集成測試,一個複雜的單體應用的集成測試並不比微服務架構的應用簡單多少)
Another major challenge with the Microservice architecture pattern is implementing changes that span multiple services. For example, let’s imagine that you are implementing a story that requires changes to services A, B, and C, where A depends upon B and B depends upon C. In a monolithic application you could simply change the corresponding modules, integrate the changes, and deploy them in one go. In contrast, in a Microservice architecture pattern you need to carefully plan and coordinate the rollout of changes to each of the services. For example, you would need to update service C, followed by service B, and then finally service A. Fortunately, most changes typically impact only one service and multi-service changes that require coordination are relatively rare. 在微服務中,改變功能以後的部署要更加當心
Deploying a microservices-based application is also much more complex. A monolithic application is simply deployed on a set of identical servers behind a traditional load balancer. Each application instance is configured with the locations (host and ports) of infrastructure services such as the database and a message broker. In contrast, a microservice application typically consists of a large number of services. For example, Hailo has 160 different services and Netflix has over 600 according to Adrian Cockcroft. Each service will have multiple runtime instances. That’s many more moving parts that need to be configured, deployed, scaled, and monitored. In addition, you will also need to implement a service discovery mechanism (discussed in a later post) that enables a service to discover the locations (hosts and ports) of any other services it needs to communicate with. Traditional trouble ticket-based and manual approaches to operations cannot scale to this level of complexity. Consequently, successfully deploying a microservices application requires greater control of deployment methods by developers, and a high level of automation. 微服務在部署方面存在它本身的難點。單體服務的部署難點在於慢,微服務的部署難點在於亂。可是微服務部署難點是能夠經過例如 Chef 這樣的 IT 自動化工具來解決的,在解決以後,微服務就能實現更快的部署頻率。這一點是單體應用難以實現的。這一段除了部署自己之外,還提到了要實現微服務架構的應用,還必須實現一套服務發現機制。單體應用雖然不存在這樣的技術難度,但須要認識到的是微服務架構的應用每每是比單體應用能實現更大的部署規模。換句話說單體應用不須要服務發現的機制是由於其難以實現比微服務架構更大更復雜的分佈式集羣。
One approach to automation is to use an off-the-shelf PaaS such as Cloud Foundry. A PaaS provides developers with an easy way to deploy and manage their microservices. It insulates them from concerns such as procuring and configuring IT resources. At the same time, the systems and network professionals who configure the PaaS can ensure compliance with best practices and with company policies. Another way to automate the deployment of microservices is to develop what is essentially your own PaaS. One typical starting point is to use a clustering solution, such as Mesos or Kubernetes in conjunction with a technology such as Docker. Later in this series we will look at how software-based application delivery approaches such as NGINX, which easily handles caching, access control, API metering, and monitoring at the microservice level, can help solve this problem. 其實 CloudFoundry 這樣 PaaS 平臺不是一個好選擇。實現微服務平臺的更好選擇是 Docker,以及在 Docker 生態圈中的 Apache Mesos 或者 Kubernetes 容器管理平臺技術。
Building complex applications is inherently difficult. A Monolithic architecture only makes sense for simple, lightweight applications. You will end up in a world of pain if you use it for complex applications. The Microservice architecture pattern is the better choice for complex, evolving applications despite the drawbacks and implementation challenges. 單體架構只適合簡單輕量的應用。若是用其實現複雜應用每每會使你深陷痛苦。
In later blog posts, I’ll dive into the details of various aspects of the Microservice architecture pattern and discuss topics such as service discovery, service deployment options, and strategies for refactoring a monolithic application into services. 接下來,「我」將深刻介紹和討論例如服務發現、服務部署、單體應用如何重構成微服務應用等話題。
Stay tuned…