Microservices vs SOA – Chap5. Summary

This post is part of a series of posts with my personal notes about the chapters in the book “Microservices vs. Service-Oriented Architecture” by Mark Richards.

Although the microservices pattern has certainly addressed the many issues commonly found in large monolithic applications and complex SOA architectures, it does lack some of the core capabilities provided by a SOA—including contract decoupling and protocol-agnostic heterogeneous interoperability.

One of the fundamental concepts to remember is that microservices architecture is a share-as-little-as-possible architecture pattern that places a heavy emphasis on the concept of a bounded context, whereas SOA is a share-as-much-as-possible architecture pattern that places heavy emphasis on abstraction and business functionality reuse.

For more information about microservices, SOA, and distributed architecture in general, you can view Service-Based Architectures: Structure, Engineering Practices, and Migration (O’Reilly video) by Neal Ford and Mark Richards.

For an excellent in-depth look at microservices, I highly recommend Sam Newman’s book Building Microservices (O’Reilly).

Finally, for more information about messaging as it relates to service-based architectures for both microservices and SOA, you can view Enterprise Messaging: JMS 1.1 and JMS 2.0 Fundamentals (O’Reilly video) and Enterprise Messaging: Advanced Topics and Spring JMS (O’Reilly video).

– The end

edwardthienhoang

 

Microservices vs SOA – Chap4. Comparing Architecture Capabilities

This post is part of a series of posts with my personal notes about the chapters in the book “Microservices vs. Service-Oriented Architecture” by Mark Richards.

In this chapter I compare microservices and SOA by focusing on three major architectural capabilities—the size of the application each architecture pattern supports, the type of systems and components that can be integrated using each architecture pattern, and finally the ability of the architecture pattern to support contract decoupling

Application Scope

SOA is well-suited for large, complex, enterprise-wide systems that require integration with many heterogeneous applications and services. It is also well-suited for applications that have many shared components, particularly components that are shared across the enterprise. As such, SOA tends to be a good fit for large insurance companies due to the heterogeneous systems environment and the sharing of common services—customer, claim, policy, etc.—across multiple applications and systems.

The microservices pattern is better suited for smaller, well-partitioned web-based systems rather than large-scale enterprise-wide systems. The lack of a mediator (messaging middle-ware) is one of the factors that makes it ill-suited for large-scale complex business application environments.

In some cases you might find that the microservices pattern is a good initial architecture choice in the early stages of your business, but as the business grows and matures, you begin to need capabilities such as complex request transformation, complex orchestration, and heterogeneous systems integration. In these situations you will likely turn to the SOA pattern to replace your initial microservices architecture. Of course, the opposite is true as well—you may have started out with a large, complex SOA architecture, only to find that you didn’t need all of those powerful capabilities that it supports after all. In this case you will likely find yourself in the common position of moving from an SOA architecture to microservices to simplify the architecture.

Heterogeneous Interoperability

The ability to integrate with multiple heterogeneous systems and services is one of the few areas where microservices architecture takes a back seat to SOA

The microservices architecture style supports protocol-aware heterogeneous interoperability. communication between a particular service consumer and the corresponding service that it’s invoking must be the same (e.g., REST).

SOA also supports protocol-aware heterogeneous interoperability, but it takes this concept one step further by supporting protocol agnostic heterogeneous interoperability. A particular service consumer written in C# on the .NET platform may invoke a corresponding service using REST, but the service (in this case an EJB3 bean) is only able to communicate using RMI. Being able to translate the consumer protocol to the service protocol known as protocol transformation is supported through the use of a messaging middleware component.

If you find yourself in a heterogeneous environment where you need to integrate several different types of systems or services using different protocols, chances are that you will need to look toward SOA rather than microservices. However, if all of your services can be exposed and accessed through the same remote-access protocol (e.g., REST), then microservices can be the right choice.

Contract Decoupling

There are two primary forms of contract decoupling: message transformation and message enhancement. Microservices architecture does not support contract decoupling, whereas contract decoupling is one of the primary capabilities offered within a SOA. If you require this level of abstraction in your architecture, you will need to look toward a SOA solution rather than a microservices one for your application or system.

In the last chapter 5, we will do summary and recommend some useful resource for you to continue explore more deep dive into Microservices and SOA

edwardthienhoang

Microservices vs SOA – Chap3. Comparing Architecture Characteristics

This post is part of a series of posts with my personal notes about the chapters in the book “Microservices vs. Service-Oriented Architecture” by Mark Richards.

In this chapter I explore the differences between microservices and SOA in terms of the overall architecture topology and the defining characteristics of the architecture pattern

Component Sharing

SOA is built on the concept of a share-as-much-as-possible architecture style, whereas microservices architecture is built on the concept of a share-as-little-as-possible architecture style.

Microservices architecture, being built on the concept of share-as-little-as-possible, leverages a concept from domain-driven design called a bounded context. microservices architecture is a share-nothing architecture with the exception of two things—how services integrate with one another, and the infrastructure plumbing to ensure engineering consistency.

Service Orchestration and Choreography

The term service orchestration refers to the coordination of multiple services through a centralized mediator such as a service consumer or an integration hub (Mule, Camel, Spring Integration, etc.).

3.3 - Service orchestration

Service choreography refers to the coordination of multiple service calls without a central mediator. The term inter-service communication is sometimes used in conjunction with service choreography.

3.4 - Service choreography

If you find that you need a lot of service choreography between your functional services, chances are your services are too fine-grained.

Too much service choreography in a microservices architecture can lead to high efferent coupling, which is the degree to which one component is dependent on other components to complete a single business request.

One solution to the issue of service choreography among functional services within a microservices architecture is to combine fine-grained services into a more coarse-grained service.

SOA, being a share-as-much-as-possible architecture, relies on both service orchestration and service choreography to process business requests.

Middle-ware vs. API Layer

The microservices architecture pattern typically has what is known as an API layer, whereas SOA has a messaging middle-ware component.

The microservices pattern does not support the concept of messaging middle-ware (e.g., integration hub or enterprise service bus). Rather, it supports the notion of an API layer in front of the services that acts as a service-access facade.

SOA relies on its messaging middle-ware to coordinate service calls. Using messaging middle-ware (what I like to refer to as an integration hub) provides a host of additional architectural capabilities not found in the microservices architecture style, including mediation and routing, message enhancement, message transformation, and protocol transformation.

Mediation and routing

describes the capability of the architecture to locate and invoke a service (or services) based on a specific business or user request

Both microservices and SOA share this capability, particularly with regard to a service registry or service-discovery component. However, with microservices service orchestration is typically minimized or not used at all, whereas with SOA it is frequently used

Message enhancement

describes the capability of the architecture to modify, remove, or augment the data portion of a request before it reaches the service

The microservices pattern does not support this capability, primarily because it doesn’t include a middle-ware component to implement this functionality. SOA fully supports this capability through its messaging middle-ware

Message transformation

describes the capability of the architecture to modify the format of the data from one type to other

Again, microservices architecture does not support this capability, but SOA does through the use of the messaging middle-ware.

Protocol transformation

describes the capability of the architecture to have a service consumer call a service with a protocol that differs from what the service is expecting

Microservices can support multiple protocol types, but the service consumer and service must use the same protocol. In SOA, you can mix and match them as much as you want.

Accessing Remote Services

Microservices architectures usually rely on only two different remote-access protocols to access services — REST and simple messaging (JMS, MSMQ, AMQP, etc.).

SOA architectures typically rely on messaging (e.g., JMS, AMQP, MSMQ) and SOAP as the primary service remote-access protocols

In chapter 4, we will compare Architecture Capabilities of Microservices and SOA

edwardthienhoang

Microservices vs SOA – Chap2. Comparing Service Characteristics

This post is part of a series of posts with my personal notes about the chapters in the book “Microservices vs. Service-Oriented Architecture” by Mark Richards.

In this chapter I compare microservices and SOA by focusing on how the services are classified within each pattern (i.e., service taxonomy), how services are coordinated based on the service owner, and finally the difference in service granularity between microservices and SOA

Service Taxonomy

The term service taxonomy refers to how services are classified within an architecture.

Microservices architectures have a limited service taxonomy when it comes to service type classification, mostly consisting of only two service types as illustrated in below Figure. Functional services are services that support specific business operations or functions, whereas infrastructure services support nonfunctional tasks such as authentication, authorization, auditing, logging, and monitoring.

2.1 - Microservice service taxonomy

The service taxonomy within SOA varies significantly from microservices taxonomy. The architecture pattern defines four basic types, as illustrated in below Figure

2.2 - SOA taxonomy

Business services are abstract, high-level, coarse-grained services that define the core business operations that are performed at the enterprise level, typically represented through either XML, Web Services Definition Language(WSDL), or Business Process Execution Language (BPEL). ProcessTrade is a good business service candidate

Enterprise services are concrete, enterprise-level, coarse-grained services that implement the functionality defined by business services. CheckTradeCompliance, CreateCustomer, ValidateOrder, and GetInventory are all good examples of enterprise services. Enterprise services typically rely on application services and infrastructure services to fulfill a particular business request, but in some cases all of the business functionality needed for a particular request may be self-contained within that enterprise service.

Application services are fine-grained, application-specific services that are bound to a specific application context. Some examples of an application service might be AddDriver, AddVehicle, and CalculateAutoQuote.

The final basic type of service found in SOA is infrastructure services. As in microservices architecture, these are services that implement nonfunctional tasks such as auditing, security, and logging.

Service Ownership and Coordination

A service owner is the type of group within the organization that is responsible for creating and maintaining a service.

Because microservices architecture has a limited service taxonomy (functional services and infrastructure services), it is typical for application development teams to own both the infrastructure and functional services

2.3 - Microservices service ownership model

With SOA, there are usually different service owners for each type of service. Business services are typically owned by business users, whereas enterprise services are typically owned by shared services teams or architects. Application services are usually owned by application development teams, and infrastructure services are owned by either application development teams or infrastructure services teams. Although not formally a service, the middle-ware components usually found in SOA are typically owned by integration architects or middle-ware teams.

2.4 - SOA service ownership model

The significance of the service owner is that of overall service coordination. In SOA, you must coordinate with multiple groups to create or maintain a single business request; business users must be consulted about the abstract business services, shared services teams must be consulted about the enterprise services created to implement the business services, application development teams must be coordinated so that enterprise services can invoke lower-level functionality, and infrastructure teams must be coordinated to ensure nonfunctional requirements are met through the infrastructure services. Finally, all of that needs to be coordinated through the middle-ware teams or integration architects managing the messaging middle-ware.

With microservices, there is little or no coordination among services to fulfill a single business request. If coordination is needed among service owners, it is done quickly and efficiently through small application development teams

Service Granularity

One of the bigger differences from a services perspective between microservices and SOA is service granularity. Whether you are using a microservices architecture or SOA, designing services with the right level of granularity is not an easy task.

As the name suggests, microservices are small, fine-grained services. With SOA, service components can range in size anywhere from small application services to very large enterprise services. In fact, it is common to have a service component within SOA represented by a large product or even a subsystem.

Service granularity affects both performance and transaction management. Services that are too fine-grained will require inter service communication to fulfill a single business request, resulting in numerous remote service calls that take up valuable time.

Transaction management is also impacted by service granularity. I am referring here to traditional ACID transactions, not the BASE transactions I discussed in the previous chapter. If your remote services are too fine-grained, you will not be able to coordinate the services using a single transactional unit of work

When dealing with service granularity I usually find it easier to start out with services that are more coarse-grained than that you might otherwise create, and then break them apart as you learn how they are used. As Sam Newman states in his excellent book Building Microservices (O’Reilly), “Start with a small number of larger services frst.” Just watch out for transaction issues and too much inter-service communication, particularly with microservices—these are good indicators that your services might be too fine-grained.

Granularity and Pattern Selection

Microservices allows this architecture pattern to improve all aspects of the software development life-cycle, including development, testing, deployment, and maintenance. Although moving to services that are more coarse-grained certainly resolves performance and transactional issues

If you find that your services range in size from small to large, you will likely need to look toward more of a SOA pattern than the more simple microservices architecture pattern. However,if you are able to break down the business functionality of your application into very small, independent parts, then the microservices pattern is a likely candidate for your architecture.

In chapter 3, we will compare Architecture Characteristics of Microservices and SOA

edwardthienhoang

Microservices vs SOA – Chap1. The World of Service-Based Architectures

This post is part of a series of posts with my personal notes about the chapters in the book “Microservices vs. Service-Oriented Architecture” by Mark Richards.

Both microservices architecture and SOA are considered service-based architectures, meaning that they are architecture patterns that place a heavy emphasis on services as the primary architecture component used to implement and perform business and nonbusiness functionality.

All service-based architectures have in common is that they are generally distributed architectures, meaning that service components are accessed remotely through some sort of remote access protocol —for example, Representational State Transfer (REST), Simple Object Access Protocol (SOAP), Advanced Message Queuing Protocol (AMQP), Java Message Service (JMS), Microsoft Message Queuing (MSMQ), Remote Method Invocation (RMI), or .NET Remoting.

Distributed architectures also lend themselves to more loosely coupled and modular applications.

Service Contracts

A service contract is an agreement between a (usually remote) service and a service consumer (client) that specifies the inbound and outbound data along with the contract format (XML, JavaScript Object Notation [JSON], Java object, etc.)

In service-based architecture you can use two basic types of service contract models: service-based contracts and consumer-driven contracts

Contract versioning allows you to roll out new service features that involve contract changes and at the same time provide backward compatibility for service consumers that are still using prior contracts

There are two basic techniques to implement your own custom contract-versioning strategy: homogeneous versioning and heterogeneous versioning

In many circumstances this may not be feasible because the number of internal and/or external service consumers is large. In this situation an integration hub (i.e., messaging middleware) can help by providing an abstraction layer to transform service contracts between services and service consumers.

Service Availability

Service availability and service responsiveness are two other considerations common to all service-based architectures

Service availability refers to the ability of a remote service to accept requests in a timely manner (e.g., establishing a connection to the remote service).

Service responsiveness refers to the ability of the service consumer to receive a timely response from the service.

Service responsiveness is much more difficult to address. A popular technique to address this issue is to use the circuit breaker pattern.

Security

Depending on your situation, service consumers may need to be both authenticated and authorized.

Authentication refers to whether the service consumer can connect to the service, usually through sign-on credentials using a username and password.

Authorization refers to whether or not a service consumer is allowed to access specific business functionality within a service.

With microservices, security becomes a challenge primarily because no middleware component handles security-based functionality.
Instead, each service must handle security on its own, or in some cases the API layer can be made more intelligent to handle the security aspects of the application.

Transactions

Transaction management is a big challenge in service-based architectures. Most of the time when we talk about transactions we are referring to the ACID (atomicity, consistency, isolation, and durability). Given that service-based architectures are generally distributed architectures, it is extremely difficult to propagate and maintain a transaction context across multiple remote services

Transaction issues are much more prevalent in SOA because, unlike in microservices architecture, multiple services are typically used to perform a single business request.

Rather than use ACID transactions, service-based architectures rely on BASE transactions. BASE is a family of styles that include basic availability, soft state, and eventual consistency.

In situations in which you simply cannot rely on eventual consistency and soft state and require transactional consistency, you can make your services more coarse-grained to encapsulate the business logic into a single service, allowing the use of ACID transactions to achieve consistency at the transaction level.

Too Much Complexity?

Service-based architectures are a significant improvement over monolithic applications, but as you can see they involve many considerations—including service contracts, availability, security, and transactions, …

In chapter 2, we will compare Service Characteristics of Microservices and SOA

edwardthienhoang

Building Microservices Application – Phần 3: Xác thực API bằng OAuth 2.0

Trong các bài viết trước chúng ta đã làm quen với Netflix Eureka, Ribbon, ZuulHystrix. Trong bài này hãy cùng làm quen với việc xác thực API sử dụng OAuth 2.0

Các bạn có thể tham khảo bài viết tiếng Anh tại: http://callistaenterprise.se/blogg/teknik/2015/04/27/building-microservices-part-3-secure-APIs-with-OAuth/

1. Giới thiệu về OAuth và Single Sign On

Các hệ thống phân tán (decentralized system) ngày càng trở lên phổ biến và xác thực là một khía cạnh quan trọng của tất cả chúng. Xác thực Single Sign On (SSO) ngày càng trở nên cần thiết hơn bao giờ hết. Ngày nay, hầu hết các trang web đều yêu cầu xác thực để truy cập tới các tính năng và nội dung của nó. Với số lượng các trang web và dịch vụ đang tăng lên, một hệ thống đăng nhập tập trung (centralized login system) trở nên cần thiết.

SSO giải quyết một vấn đề lớn: làm thế nào để quản được số lượng người dùng đang tăng lên trên toàn bộ hệ thống gồm nhiều ứng dụng và dịch vụ. Các framework chẳng hạn như OpenID Connect và các dịch vụ chẳng hạn như Auth0 làm cho việc tích hợp Single Sign On vào các ứng dụng mới hoặc đã có của bạn trở nên dễ dàng hơn nhiều. Nếu bạn đang triển khai xác thực trên một ứng dụng hay dịch vụ mới hãy xem xét tích hợp SSO.

Đọc thêm tại: https://techmaster.vn/posts/34688/xac-thuc-single-sign-on-la-gi-va-no-hoat-dong-nhu-the-nao

OAuth2 là một chuẩn mở để ủy quyền/phân quyền (authorization), OAuth2 cũng là nền tảng của OpenID Connect, nó cung cấp OpenID (xác thực – authentication) ở phía trên của OAuth2 (ủy quyền – authorization) để có một giải pháp bảo mật hoàn chỉnh.

Đọc thêm tại: https://techmaster.vn/posts/34473/authentication-va-authorization-openid-vs-oauth2-vs-saml

Tiếp theo hãy vào phần áp dụng

2. Kiến trúc

Chúng ta sẽ thêm một microservice mới có tên product-api hoạt động như một external API (hay còn gọi là Resource Server trong thuật ngữ của OAuth) và được expose thông qua edge server đóng vai trò token relay, tức là chuyển tiếp OAuth access tokens từ client đến resource server. Chúng ta cũng sẽ thêm OAuth Authorization Server và OAuth client ở phía Service consumer.

Phần được thêm mới được đóng khung màu đỏ trong diagram dưới đây:

1

Ghi chú:

  • Trong phần này chúng ta sẽ xây dựng một máy chủ OAuth authorization đơn giản để minh họa toàn bộ quá trình. Trong thực tế, bạn nên sử dụng các cơ chế SSO có sẵn từ Google, Facebook, Twitter.
  • Bài viết cũng chỉ sử dụng HTTP thay vì TSL như HTTPS

3. Checkout source code

Yêu cầu Java SE 8, Git và Gradle.

git clone https://github.com/callistaenterprise/blog-microservices.git
cd blog-microservices
git checkout -b B3 M3.1
./build-all.sh

Nếu đang sử dụng Windows, bạn có thể thực thi tập tin bat tương ứng build-all.bat!

Hai phần mới được thêm vào là OAuth Authorization Server (auth-server)OAuth Resource Server (product-api-service):

2

4. Diễn giải source code

4.1 Gradle dependencies

Để có thể sử dụng OAuth 2.0, chúng ta sẽ cần spring-cloud-securityspring-security-oauth2:

Đối với auth-server:

compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.security.oauth:spring-security-oauth2:2.0.6.RELEASE")

Đối với product-api-service:

compile("org.springframework.cloud:spring-cloud-starter-security:1.0.0.RELEASE")
compile("org.springframework.security.oauth:spring-security-oauth2:2.0.6.RELEASE")

4.2 Auth-server

Trước tiên là thêm @EnableAuthorizationServer annotation. Sau đó, sử dụng một configuration class để đăng ký các ứng dụng khách được approved (lưu trên memory thôi), chỉ định client-id, client-secret, allowed grant flows và scopes:

  @EnableAuthorizationServer
  protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
      clients.inMemory()
        .withClient("acme")
        .secret("acmesecret")
        .authorizedGrantTypes("authorization_code", "refresh_token", "implicit", "password", "client_credentials")
        .scopes("webshop");
    }
  }

Lưu ý: đây chỉ là cách chúng ta phát triển một OAuth server đơn giản để mô phỏng các máy chủ ủy quyền OAuth trong thế giới thực như Google, LinkedIn hoặc GitHub.

Để xem mã nguồn đầy đủ, hãy xem AuthserverApplication.java.

Đăng ký người dùng (Resource Owner trong thuật ngữ của OAuth) và mô phỏng Identity Provider (IdP) được thực hiện bằng cách thêm một dòng config cho mỗi user trong tệp application.properties, ví dụ:

security.user.password=password

Để xem mã nguồn đầy đủ, hãy xem application.properties.

Ngoài ra còn có hai giao diện người dùng web đơn giản dùng để user đăng nhập và cấp quyền, xem mã nguồn để biết chi tiết.

4.3 Produc-API-Service

Để Produc-API-Service hoạt động như một máy chủ OAuth, chúng ta cần thêm @EnableOAuth2Resource annotation:

@EnableOAuth2Resource
public class ProductApiServiceApplication {

Để xem mã nguồn đầy đủ, hãy xem ProductApiServiceApplication.java.

Produc-API-Service rất giống với Composite service trong phần 2. Để có thể xác minh rằng OAuth hoạt động, chúng ta sẽ xuất ra log: id người dùng và access token, lưu ý việc output access token ra log chỉ nên được dùng trong môi trường test thôi nhé:

@RequestMapping("/{productId}")
    @HystrixCommand(fallbackMethod = "defaultProductComposite")
    public ResponseEntity getProductComposite(
        @PathVariable int productId,
        @RequestHeader(value="Authorization") String authorizationHeader,
        Principal currentUser) {

        LOG.info("ProductApi: User={}, Auth={}, called with productId={}",
          currentUser.getName(), authorizationHeader, productId);
        ...

4.4 Sửa lại Edge Server

Cuối cùng, chúng ta cần làm cho Edge Server chuyển tiếp OAuth access tokens đến API-service.

zuul:
  ignoredServices: "*"
  prefix: /api
  routes:
    productapi: /product/**

URL sample:
http://localhost:8765/api/product/123

Chúng ta cũng thay thế các route đến composite-service sang api-service.

5. Khởi động system

Việc khởi động cũng giống như trong phần 2.

Đầu tiên start RabbitMQ:

$ ~/Applications/rabbitmq_server-3.4.3/sbin/rabbitmq-server

Sau đó start các infrastructure services:

$ cd support/auth-server;       ./gradlew bootRun
$ cd support/discovery-server;  ./gradlew bootRun
$ cd support/edge-server;       ./gradlew bootRun
$ cd support/monitor-dashboard; ./gradlew bootRun
$ cd support/turbine;           ./gradlew bootRun

Và các business services:

$ cd core/product-service;                ./gradlew bootRun
$ cd core/recommendation-service;         ./gradlew bootRun
$ cd core/review-service;                 ./gradlew bootRun
$ cd composite/product-composite-service; ./gradlew bootRun
$ cd api/product-api-service;             ./gradlew bootRun

Nếu đang sử dụng Windows, bạn có thể thực thi tập tin bat tương ứng start-all.bat!

Khi các microservices được khởi động và được đăng ký với máy chủ khám phá dịch vụ, chúng sẽ ghi các thông tin sau vào log:

DiscoveryClient … – registration status: 204

6. Oauth Authorization Grant Flows

Đặc tả OAuth 2.0 giới thiệu bốn luồng cấp quyền để nhận access token:

3

LƯU Ý : Trong đó có CodeImplicit flow là được sử dụng rộng rãi nhất và trong bài viết này chỉ xét 2 trường hợp đó.

6.1 Authorization Code Grant

Trước tiên, chúng ta cần lấy code grant (giống như one time password) bằng trình duyệt web:

http://localhost:9999/uaa/oauth/authorize? response_type=code& client_id=acme& redirect_uri=http://example.com& scope=webshop& state=97536

Đăng nhập ( user/ password) và đưa ra sự đồng ý của bạn trong các trang web được hiển thị. Trình duyệt web sẽ chuyển hướng đến URL dưới đây:

http://example.com/?
code=IyJh4Y&
state=97536

Lấy tham số code từ URL và lưu trữ nó trong một biến môi trường:

CODE=IyJh4Y

Bây giờ sẽ dùng code grant để lấy về access token:

curl acme:acmesecret@localhost:9999/uaa/oauth/token \
 -d grant_type=authorization_code \
 -d client_id=acme \
 -d redirect_uri=http://example.com \
 -d code=$CODE -s | jq .
{
  "access_token": "eba6a974-3c33-48fb-9c2e-5978217ae727",
  "token_type": "bearer",
  "refresh_token": "0eebc878-145d-4df5-a1bc-69a7ef5a0bc3",
  "expires_in": 43105,
  "scope": "webshop"
}

Lưu access token trong biến môi trường để sử dụng sau này khi chúng ta truy cập tới API:

TOKEN=eba6a974-3c33-48fb-9c2e-5978217ae727

Nếu bạn thực hiện lấy thêm mã token lần nữa bằng code grant trước đó, sẽ có thông báo lỗi vì code grant đó chỉ có giá trị one time.

curl acme:acmesecret@localhost:9999/uaa/oauth/token \
 -d grant_type=authorization_code \
 -d client_id=acme \
 -d redirect_uri=http://example.com \
 -d code=$CODE -s | jq .
{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: IyJh4Y"
}

6.2 Implicit Grant

Với implicit grant, chúng ta bỏ qua code grant, thay vào đó sẽ yêu cầu access token trực tiếp từ trình duyệt web (bảo mật thấp hơn). Sử dụng URL sau trong trình duyệt web:

http://localhost:9999/uaa/oauth/authorize? response_type=token& client_id=acme& redirect_uri=http://example.com& scope=webshop& state=48532

Đăng nhập ( user/ password) và đưa ra sự đồng ý cấp quyền. Trình duyệt web sẽ chuyển hướng đến URL dưới đây:

http://example.com/#
access_token=00d182dc-9f41-41cd-b37e-59de8f882703&
token_type=bearer&
state=48532&
expires_in=42704

Lưu access token trong biến môi trường để sử dụng sau này khi truy cập API:

TOKEN=00d182dc-9f41-41cd-b37e-59de8f882703

7. Access đến API

Bây giờ, khi đã có access token, chúng ta có thể bắt đầu truy cập API.

Trước tiên, hãy thử truy cập vào API mà không có access token, nó sẽ không thành công:

curl 'http://localhost:8765/api/product/123' -s | jq .
{
  "error": "unauthorized",
  "error_description": "Full authentication is required to access this resource"
}

Tiếp theo, hãy thử với một access token không hợp lệ, nó cũng sẽ thất bại:

curl 'http://localhost:8765/api/product/123' \
 -H  "Authorization: Bearer invalid-access-token" -s | jq .
{
  "error": "access_denied",
  "error_description": "Unable to obtain a new access token for resource 'null'. The provider manager is not configured to support it."
}

Bây giờ, chúng ta thực hiện một request đúng cung cấp một trong các access token có được ở bước phía trên:

curl 'http://localhost:8765/api/product/123' \
 -H  "Authorization: Bearer $TOKEN" -s | jq .
{
  "productId": 123,
  "name": "name",
  "weight": 123,
  "recommendations": [...],
  "reviews": [... ]
}

Ngon!

Check log events trong product-api-service:

2015-04-23 18:39:59.014  INFO 79321 --- [ XNIO-2 task-20] o.s.c.s.o.r.UserInfoTokenServices        : Getting user info from: http://localhost:9999/uaa/user
2015-04-23 18:39:59.030  INFO 79321 --- [ctApiService-10] s.c.m.a.p.service.ProductApiService      : ProductApi: User=user, Auth=Bearer a0f91d9e-00a6-4b61-a59f-9a084936e474, called with productId=123
2015-04-23 18:39:59.381  INFO 79321 --- [ctApiService-10] s.c.m.a.p.service.ProductApiService      : GetProductComposite http-status: 200

Chúng ta có thể thấy rằng API liên hệ với máy chủ ủy quyền để nhận thông tin về người dùng và sau đó in ra tên người dùng và access token trong log!

Cuối cùng, hãy thử làm mất hiệu lực của access token, bằng cách ví dụ như làm cho nó hết hạn. Một cách để làm điều đó là khởi động lại auth-server (nó chỉ lưu trữ thông tin trong bộ nhớ…) và sau đó thử lại:

curl 'http://localhost:8765/api/product/123' \
 -H  "Authorization: Bearer $TOKEN" -s | jq .
{
  "error": "access_denied",
  "error_description": "Unable to obtain a new access token for resource 'null'. The provider manager is not configured to support it."
}

Access token được chấp nhận trước đây hiện bị từ chối.

8. Tóm tắt

Các hệ thống phân tán (decentralized system) ngày càng trở lên phổ biến và xác thực là một khía cạnh quan trọng của tất cả chúng. SSO giải quyết một vấn đề lớn: làm thế nào để quản được số lượng người dùng đang tăng lên trên toàn bộ hệ thống gồm nhiều ứng dụng và dịch vụ. Các framework chẳng hạn như OpenID Connect và các dịch vụ chẳng hạn như Auth0 làm cho việc tích hợp Single Sign On vào các ứng dụng mới hoặc đã có của bạn trở nên dễ dàng hơn nhiều. Nếu bạn đang triển khai xác thực trên một ứng dụng hay dịch vụ mới hãy xem xét tích hợp SSO.

Bài viết đã trình bày, mô phỏng cách xác thực với OAuth 2.0. Lưu ý khi triển khai thực tế, các bạn nên dùng luôn các cơ chế xác thực của Google, Facebook.

9. Tiếp theo

Trong bài viết tiếp theo, chúng ta sẽ đến với việc quản lý log tập trung sử dụng ELK stack bao gồm: Elasticsearch, LogStash and Kibana.

Series này là phần tiếp theo series Microservices: Từ Thiết Kế Đến Triển Khai, tập trung vào việc hiện thực hóa các khái niệm đã mô tả ở phần lý thuyết. Hi vọng sẽ giúp ích được cho các bạn khi làm quen với microservies. Các bạn có thể tham khảo thêm về phần Architecture căn bản ở đây nhé.

Tổng hợp và dịch by edwardthienhoang

Building Microservices Application – Phần 2: Xử lý “chain of failures” dùng Circuit Breaker pattern với Netflix Hystrix

Trong bài trước, chúng ta đã làm quen với các nền tảng và công cụ để làm việc với Microservice bao gồm Spring Boot, Spring Cloud, Netflix OSS với 3 ứng viên CẦN THIẾT nhất là Netflix Eureka, Ribbon và Zuul để một hệ thống gồm nhiều Microservice có thể hoạt động trơn tru trong điều kiện “thời tiết tốt”, không có lỗi phát sinh nào.

Tuy nhiên, trong thực tế thì đâu có chuyện đơn giản như vậy. Như một tính chất quan trọng nhất mà một hệ thống microservice cần phải đáp ứng đó là khả năng chịu lỗi và phản hồi với lỗi. Đặc biệt là với các lỗi ở dạng “chain of failures”. Một hệ thống microservice, bạn hãy tưởng tượng đó là các quân cờ domino được xếp cạnh nhau, giả sử có một quân tự dưng đổ sầm ra, thì các quân còn lại, liên đới với quân bị đổ sẽ bị đổ theo.

Circuit Breaker Pattern

Để giải quyết vấn đề này, chúng ta có thể áp dụng Circuit Breaker Pattern. Đây là một pattern dùng để ngắt một quá trình xử lý khi hệ thống gặp sự cố, để đảm bảo số lượng message bị lỗi không tăng cao, làm cho việc khắc phục trở nên khó khăn, cũng như có thể làm cho hệ thống bị xụp đổ hàng loạt do ảnh hưởng lẫn nhau. Tư tưởng nó giống cái automat trong mạng điện, khi xảy ra chập điện, thì ngay lập tức automat sẽ ngắt mạch điện, khi nào khắc phúc xong đóng lại thì mạch điện mới thông trở lại. Các bạn có thể search thêm pattern này trên mạng để tìm hiểu chi tiết hơn. Áp dụng nó cho trường hợp microservice bị lỗi, thì ngay khi phát hiện ra sự cố thì ngay lập tức ngắt quá trình gửi/nhận message tới microservice bị lỗi và thay thế bằng các phương pháp dự phòng để tránh tình trạng nghẽn mạch.

Các bạn có thể tham khảo bài viết tiếng Anh tại: http://callistaenterprise.se/blogg/teknik/2015/04/15/building-microservices-with-spring-cloud-and-netflix-oss-part-2/

Tuy nhiên, đó chỉ là phần một của vấn đề. Để tìm hiểu rõ hơn thứ tự messge trong việc xử lý bất đồng bộ, các bạn có thể đọc thêm bài viết dưới đây của anh NGHIA MINH LE:
https://techblog.vn/van-thu-tu-messge-trong-viec-xu-ly-bat-dong-bo-dua-tren-message-queue

Trong bài viết này, hãy cùng tìm hiểu về Circuit Breaker pattern và Netflix Hystrix trước đã. Mô hình của circuit breaker như sau:

1

Nhìn lại bảng nguyên liệu cần thiết để làm món Microservices

1

Netflix Hystrix – cung cấp khả năng ngắt mạch cho service consumer. Nếu một dịch vụ không đáp ứng (do timeout hoặc lỗi giao tiếp), Hystrix có thể chuyển hướng cuộc gọi đến phương thức dự phòng trong service consumer. Nếu một dịch vụ liên tục không hoạt động, Hystrix sẽ mở mạch và thực hiện fail fast (tức là gọi phương thức dự phòng mà không gọi đến service đó luôn) trên tất cả request tiếp theo cho đến khi dịch vụ “sống” trở lại. Để xác định khi nào một dịch vụ sống lại, lâu lâu nó sẽ thử bằng cách cho phép các request tới dịch vụ đó để xem nó sống lại hay chưa. Hystrix được cài đặt ở phía service consumber.

Netflix Hystrix dashboard và Netflix Turbine – được sử dụng để cung cấp tình hình tổng quan của bộ ngắt mạch và Turbine, dựa trên thông tin trong Eureka.

2

2. Kiến trúc

Phần 2 này sẽ bổ Hystrix dashboardTurbine vào Infrastructure Server. Product-composite service cũng có thêm một bộ ngắt mạch Hystrix.

3

3. Source code

Cũng giống như Phần 1, chúng ta cần có Java SE 8, Git và Gradle.

$ git clone https://github.com/callistaenterprise/blog-microservices.git
$ cd blog-microservices
$ git checkout -b B2 M2.1
$ ./build-all.sh

Nếu đang sử dụng Windows, bạn có thể thực thi tập tin bat tương ứng build-all.bat!

Hai thành phần mã nguồn mới đã được thêm vào kể từ Phần 1 là: monitor-dashboardturbine:

4

4. Diễn giải source code

4.1 Gradle dependencies

Do Hystrix sử dụng RabbitMQ để giao tiếp giữa các bộ phận ngắt mạch và dashboards, chúng ta cần phải thiết lập các dependencies cho nó.

Đối với một service consumer, muốn sử dụng Hystrix như một bộ ngắt mạch cần thêm:

compile("org.springframework.cloud:spring-cloud-starter-hystrix:1.0.0.RELEASE")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RELEASE")
compile("org.springframework.cloud:spring-cloud-netflix-hystrix-amqp:1.0.0.RELEASE")

Để có thể thiết lập Turbine server, hãy thêm dependency sau:

compile('org.springframework.cloud:spring-cloud-starter-turbine-amqp:1.0.0.RELEASE')

4.2. Infrastructure Servers

Thiết lập Turbine server bằng cách thêm @EnableTurbineAmqp annotation vào Spring Boot application:

@SpringBootApplication
@EnableTurbineAmqp
@EnableDiscoveryClient
public class TurbineApplication {

    public static void main(String[] args) {
        SpringApplication.run(TurbineApplication.class, args);
    }

}

Để thiết lập Hystrix Dashboard, hãy thêm @EnableHystrixDashboard annotation. Có thể xem mã nguồn hoàn chỉnh trong file HystrixDashboardApplication.java.

Với các annotations đơn giản này, bạn đã có thể tạo ra các server đỉnh, làm được việc và không lo bị cháy cầu chì 😀

4.3 Business Service

Để kích hoạt Hystrix, hãy thêm @EnableCircuitBreaker annotation vào ứng dụng Spring Boot của bạn.

@SpringBootApplication
@EnableCircuitBreaker
@EnableDiscoveryClient
public class ProductCompositeServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductCompositeServiceApplication.class, args);
    }
}

Thêm @HystrixCommand annotation vào các service method và thiết lập fallback method trong trường hợp có lỗi:

@Component
public class ProductCompositeIntegration {
    @HystrixCommand(fallbackMethod = "defaultReviews")
    public ResponseEntity<List> getReviews(int productId) {
        ...
    }

    public ResponseEntity<List> defaultReviews(int productId) {
        ...
    }
}

Method dự phòng được sử dụng bởi Hystrix trong trường hợp có lỗi (gọi tới dịch vụ không thành công hoặc timeout) hoặc fail fast nếu mạch đang mở. Để xem ví dụ hoàn chỉnh, hãy xem ProductCompositeIntegration.java.

5. Khởi chạy các microservices

Để có thể chạy một số lệnh được sử dụng bên dưới, cần phải cài đặt các cURL và jq .

Như đã đề cập, Hystrix sử dụng RabbitMQ cho giao tiếp nội bộ nên cần phải cài đặt và chạy nó trước khi khởi động các microservices. Làm theo hướng dẫn tại Downloading and Installing. Sau đó, start RabbitMQ bằng rabbitmq-server trong folder sbin của thư mục cài đặt.

$ ~/Applications/rabbitmq_server-3.4.3/sbin/rabbitmq-server

              RabbitMQ 3.4.3. Copyright (C) 2007-2014 GoPivotal, Inc.
  ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/
  ##  ##
  ##########  Logs: /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro.log
  ######  ##        /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro-sasl.log
  ##########
              Starting broker... completed with 6 plugins.

Sau đó sử dụng lệnh ./gradlew bootRun để start các services

Đầu tiên hãy start các infrastructure services

$ cd support/discovery-server;  ./gradlew bootRun
$ cd support/edge-server;       ./gradlew bootRun
$ cd support/monitor-dashboard; ./gradlew bootRun
$ cd support/turbine;           ./gradlew bootRun

Sau đó start các business services

$ cd core/product-service;                ./gradlew bootRun
$ cd core/recommendation-service;         ./gradlew bootRun
$ cd core/review-service;                 ./gradlew bootRun
$ cd composite/product-composite-service; ./gradlew bootRun

Nếu đang sử dụng Windows, bạn có thể thực thi tập tin bat tương ứng start-all.bat!

Khi các microservices được khởi động và được đăng ký với máy chủ khám phá dịch vụ, chúng sẽ ghi các thông tin sau vào log:

DiscoveryClient … – registration status: 204

Trong ứng dụng web khám phá dịch vụ, bây giờ chúng ta có thể thấy bốn business services và một edge server (http://localhost:8761):

3

Cuối cùng đảm bảo rằng các bộ phận ngắt mạch đang hoạt động, tức là đang ở trạng thái đóng mạch (closed). Hãy thử gọi đến composite service thông qua the edge-server:

$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
    "name": "name",
    "productId": 1,
    "recommendations": [
        {
            "author": "Author 1",
            "rate": 1,
            "recommendationId": 0
        },
        ...
    ],
    "reviews": [
        {
            "author": "Author 1",
            "reviewId": 1,
            "subject": "Subject 1"
        },
        ...
    ],
    "weight": 123
}

Vào địa chỉ http://localhost:7979 trong trình duyệt web, nhập địa chỉ http://localhost:8989/turbine.stream và click vào “Monitor Stream“:

5

Chúng ta có thể thấy rằng composite service có ba bộ phận ngắt mạch hoạt động, mỗi cái tương ứng với một core service mà nó cần gọi đến. Hiện tại không có vấn đề gì, tức là bộ ngắt mạch đang đóng. Tiếp theo hãy thử nghiệm trong trường hợp có lỗi xảy ra.

6. Test

Stop review service và thử lại lệnh trên:

$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
    "name": "name",
    "productId": 1,
    "recommendations": [
        {
            "author": "Author 1",
            "rate": 1,
            "recommendationId": 0
        },
        ...
    ],
    "reviews": null,
    "weight": 123
}

Phần reviews trong response bị trống, nhưng những phần khác vẫn được trả về! Nhìn vào log của product-composite service sẽ thấy các warning:

2015-04-02 15:13:36.344  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:13:36.497  INFO 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...
2015-04-02 15:13:36.498  WARN 29901 --- [teIntegration-2] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:13:36.500  WARN 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

Tức là bộ ngắt mạch đã phát hiện ra sự cố với Review service và định tuyến đến phương thức dự phòng. Trong trường hợp này, chúng ta đơn giản là trả về null nhưng cung có thể, ví dụ, trả về dữ liệu từ bộ đệm local để cung cấp kết quả tốt nhất khi service review không có sẵn.

Mạch vẫn đóng vì lỗi không phải là thường xuyên:

6

Hãy tăng tần số lỗi vượt quá giới hạn mà Hystrix sẽ mở mạch và bắt đầu fail fast (sử dụng giá trị mặc định của Hystrix). Chúng ta sử dụng Apache HTTP server benchmarking tool cho việc này:

ab -n 30 -c 5 localhost:8765/productcomposite/product/1

Bây giờ mạch sẽ được mở ra:

xxx

… và các cuộc gọi tiếp theo sẽ nhanh chóng thất bại, tức là bộ ngắt mạch sẽ chuyển hướng cuộc gọi trực tiếp đến phương thức dự phòng của nó mà không cần cố gắng gọi đến service review nữa. Log lúc này sẽ không còn chứa thông báo GetReviews…:

2015-04-02 15:14:03.930  INFO 29901 --- [teIntegration-5] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:14:03.984  WARN 29901 --- [ XNIO-2 task-62] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

Tuy nhiên, theo thời gian nó sẽ cho phép một số cuộc gọi đi qua để xem nếu chúng thành công tức là service review đã sống lại như log dưới đây:

2015-04-02 15:17:33.587  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:33.769  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...
2015-04-02 15:17:33.769  WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:17:33.770  WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service
2015-04-02 15:17:34.431  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:34.569  WARN 29901 --- [ XNIO-2 task-18] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service
2015-04-02 15:17:35.209  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:35.402  WARN 29901 --- [ XNIO-2 task-20] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service
2015-04-02 15:17:36.043  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:36.192  WARN 29901 --- [ XNIO-2 task-21] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service
2015-04-02 15:17:36.874  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:37.031  WARN 29901 --- [ XNIO-2 task-22] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service
2015-04-02 15:17:41.148  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...
2015-04-02 15:17:41.340  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...
2015-04-02 15:17:41.340  WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:17:41.341  WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

Như chúng ta có thể thấy từ log, cứ mỗi 5 lần thì request được phép chuyển tới service review để kiểm tra một lần (tuy vẫn không thành công…).

Bây giờ hãy start service review lên và thử lại:
Bây giờ chúng ta có thể thấy phản hồi là ok, tức là review service đã trở lại và mạch được đóng lại:

7

7. Tóm tắt

Bài này chúng ta đã tìm hiểu về Netflix Hystrix để sử dụng như một bộ ngắt mạch gải quyết vấn đề chain of failures như thế nào chỉ với các annotation đơn giản. Hystrix dashboard và Turbine cũng có thể giúp bạn giám sát các bộ ngắt mạch trong toàn hệ thống.

8. Tiếp theo

Trong bài tiếp theo, chúng ta sẽ xem xét cách sử dụng OAuth 2.0 để kiểm soát quyền truy cập vào các microservice được phơi ra bên ngoài.

Series này là phần tiếp theo series Microservices: Từ Thiết Kế Đến Triển Khai, tập trung vào việc hiện thực hóa các khái niệm đã mô tả ở phần lý thuyết. Hi vọng sẽ giúp ích được cho các bạn khi làm quen với microservies. Các bạn có thể tham khảo thêm về phần Architecture căn bản ở đây nhé.

Tổng hợp và dịch by edwardthienhoang

 

Microservices Cheat Sheet

Microservices Cheat Sheet

  1. Do only one thing and do it well. The “one thing” is defined by a “Bounded Context” in Domain-Driven Design (DDD).
  2. Own your own data. No shared data stores.
  3. Embrace eventual consistency.
    • Don’t read your writes.
    • Publish your own state-changes (minimally) to an event log.
  4. Leverage event logging and/or streaming to replicate and denormalize data from other services.
    • The event log must be subscribable to publish events to subscribers.
    • The event log must be durable and must not lose messages for publishing and replay.
    • Examples: KafkaConfluent.ioAmazon Kinesis.
  5. When aggregating microservice calls, use asynchronous, non-blocking I/O. Perform as much as possible asynchronously.
  6. Support a registry/discovery mechanism.
  7. Support Location Transparency.
    • Support statelessness–no sticky sessions.
  8. Support the use of back-pressure (see, Reactive Streams specification) to avoid cascading failures.
  9. Support the Circuit Breaker pattern to manage faulty service dependencies.
  10. Consider CQRS to scale reads separately from writes.

Platform-Building Cheat Sheet

First off, we need to understand what is meant by the term ‘platform’ for the organization. In todays world, the term ‘platform’ is such an overused buzzword that it is largely meaningless. Platforms exist at many levels in the technology stack: hardware, datacenter, database, messaging, etc. and can also be used to describe ecosystems of user experiences.

The view presented here is decidedly business focused: the ‘platform’ is really the method of exposing and growing the digital business model and its offerings. So, the following ground rules define the platform as the digital server-side, back-end data and functionality, leaving the user experiences to be crafted (whether mobile, web or other) on top of that business functionality.

This API-centric definition of ‘platform’ enables:

  • Rapid user experience revision
  • Consistent user experience across devices
  • Better channel adaptation
  • Faster and cheaper third-party integrations
  • Increased innovation capabilities.

Platform Ground Rules

  1. Mobile applications are a first-class citizen and consumer of the platform.
    • Making mobile a priority increases ease of use and adoption for everyone.
  2. The platform exposes its data and functionality via a complete set of RESTful APIs.
    • An API-based strategy maximizes reuse and flexibility.
  3. All service interfaces and events are designed from the ground up to be public facing.
    • Causes design for ease of use, flexibility and reuse.
  4. Each team of developers access all APIs using their team’s own registered developer key.
    • Improves security, auditability.
  5. There is a single token source and format for all APIs.
    • Assists in ease of use and ensures all functionality is available to consumers.
  6. The platform will notify interested observers of all resource state changes via fully-composed events.
    • Enables synchronization asynchronously (for all create, update, delete state changes).
  7. All APIs use a single identity to represent the consumer / user.
    • Enables analytics and reasoning about consumers.
  8. All APIs have a consistent look and feel, and are documented at a single, publicly-available location.
    • Maximizes reuse and ease of use.
  9. No private interfaces. No backdoors. No shared databases across teams (Observe ‘Bounded Contexts’).
    • Ensures the public interfaces are sound.
  10. APIs are deployed in a distributed, always-on architecture (multi-node, multi-zone, and multi-region) with a discipline towards resilience.
    • Horizontal scale on commodity hardware, global reach. Account for the inevitable failures.

API Design Cheat Sheet

  1. Build the API with consumers in mind–as a product in its own right.
    • Not for a specific UI.
    • Embrace flexibility / tunability of each endpoint (see #5, 6 & 7).
    • Eat your own dogfood, even if you have to mockup an example UI.
  2. Use the Collection Metaphor.
    • Two URLs (endpoints) per resource:
      • The resource collection (e.g. /orders)
      • Individual resource within the collection (e.g. /orders/{orderId}).
    • Use plural forms (‘orders’ instead of ‘order’).
    • Alternate resource names with IDs as URL nodes (e.g. /orders/{orderId}/items/{itemId})
    • Keep URLs as short as possible. Preferably, no more-than three nodes per URL.
  3. Use nouns as resource names (e.g. don’t use verbs in URLs).
  4. Make resource representations meaningful.
    • “No Naked IDs!” No plain IDs embedded in responses. Use links and reference objects.
    • Design resource representations. Don’t simply represent database tables.
    • Merge representations. Don’t expose relationship tables as two IDs.
  5. Support filtering, sorting, and pagination on collections.
  6. Support link expansion of relationships. Allow clients to expand the data contained in the response by including additional representations instead of, or in addition to, links.
  7. Support field projections on resources. Allow clients to reduce the number of fields that come back in the response.
  8. Use the HTTP method names to mean something:
    • POST – create and other non-idempotent operations.
    • PUT – update.
    • GET – read a resource or collection.
    • DELETE – remove a resource or collection.
  9. Use HTTP status codes to be meaningful.
    • 200 – Success.
    • 201 – Created. Returned on successful creation of a new resource. Include a ‘Location’ header with a link to the newly-created resource.
    • 400 – Bad request. Data issues such as invalid JSON, etc.
    • 404 – Not found. Resource not found on GET.
    • 409 – Conflict. Duplicate data or invalid data state would occur.
  10. Use ISO 8601 timepoint formats for dates in representations.
  11. Consider connectedness by utilizing a linking strategy. Some popular examples are:
  12. Use OAuth2 to secure your API.
    • Use a Bearer token for authentication.
    • Require HTTPS / TLS / SSL to access your APIs. OAuth2 Bearer tokens demand it. Unencrypted communication over HTTP allows for simple eavesdroppping and impersonation.
  13. Use Content-Type negotiation to describe incoming request payloads.For example, let’s say you’re doing ratings, including a thumbs-up/thumbs-down and five-star rating. You have one route to create a rating: POST /ratings

    How do you distinguish the incoming data to the service so it can determine which rating type it is: thumbs-up or five star?

    The temptation is to create one route for each rating type: POST /ratings/five_star and POST /ratings/thumbs_up

    However, by using Content-Type negotiation we can use our same POST /ratings route for both types. By setting the Content-Type header on the request to something like Content-Type: application/vnd.company.rating.thumbsup or Content-Type: application/vnd.company.rating.fivestar the server can determine how to process the incoming rating data.

  14. Evolution over versioning. However, if versioning, use the Accept header instead of versioning in the URL.
    • Versioning via the URL signifies a ‘platform’ version and the entire platform must be versioned at the same time to enable the linking strategy.
    • Versioning via the Accept header is versioning the resource.
    • Additions to a JSON response do not require versioning. However, additions to a JSON request body that are ‘required’ are troublesome–and may require versioning.
    • Hypermedia linking and versioning is troublesome no matter what–minimize it.
    • Note that a version in the URL, while discouraged, can be used as a ‘platform’ version. It should appear as the first node in the path and not version individual endpoints differently (e.g. api.example.com/v1/…).
  15. Consider Cache-ability. At a minimum, use the following response headers:
    • ETag – An arbitrary string for the version of a representation. Make sure to include the media type in the hash value, because that makes a different representation. (ex: ETag: “686897696a7c876b7e”)
    • Date – Date and time the response was returned (in RFC1123 format). (ex: Date: Sun, 06 Nov 1994 08:49:37 GMT)
    • Cache-Control – The maximum number of seconds (max age) a response can be cached. However, if caching is not supported for the response, then no-cache is the value. (ex: Cache-Control: 360 or Cache-Control: no-cache)
    • Expires – If max age is given, contains the timestamp (in RFC1123 format) for when the response expires, which is the value of Date (e.g. now) plus max age. If caching is not supported for the response, this header is not present. (ex: Expires: Sun, 06 Nov 1994 08:49:37 GMT)
    • Pragma – When Cache-Control is ‘no-cache’ this header is also set to ‘no-cache’. Otherwise, it is not present. (ex: Pragma: no-cache)
    • Last-Modified – The timestamp that the resource itself was modified last (in RFC1123 format). (ex: Last-Modified: Sun, 06 Nov 1994 08:49:37 GMT)
  16. Ensure that your GET, PUT, and DELETE operations are all idempotent. There should be no adverse side affects from operations.

Building Microservices Application – Phần 1: Sử dụng Netflix Eureka, Ribbon và Zuul

Đây là bài viết thứ nhất (index start từ 0 😀 ) trong series Building Microservices Application với Spring Boot. Trong bài viết mở đầu series đã giới thiệu một cách tổng quan các “viên gạch” cần có khi xây dựng ứng dụng Microservices. Trong bài viết này, hãy bắt tay vào những viên gạch đầu tiên CẦN thiết nhất bao gồm: API Gateway, Load balancer và Service Discovery.

Các bạn có thể tham khảo bài viết tiếng Anh tại: http://callistaenterprise.se/blogg/teknik/2015/04/10/building-microservices-with-spring-cloud-and-netflix-oss-part-1/

SPring Boot, Spring Cloud và Netflix OSS

Spring Boot là một dự án nổi bật trong hệ sinh thái Spring Framework. Nếu như trước đây, công đoạn khởi tạo một dự án Spring khá vất vả từ việc khai báo các dependency trong file pom.xml cho đến cấu hình bằng XML hoặc annotation phức tạp, thì giờ đây với Spring Boot, chúng ta có thể tạo các ứng dụng Spring một cách nhanh chóng và cấu hình cũng đơn giản hơn.

Như các bạn biết, để cấu hình, setup một project web đơn giản cũng tốn kha khá thời gian, vậy để setup, quản lý cấu hình, dependency cho một Microservices application sẽ còn phức tạp hơn nhiều. Tuy nhiên với Spring Boot, bạn sẽ thấy nó giúp ích khá nhiều cho chúng ta. Có thể coi Spring Boot như một project configuration manager của bạn, hãy cho Spring Boot biết bạn muốn tạo ứng dụng gồm những tính năng gì, ví dụ như: Web service, Web MVC, Microservices với API Gateway, Load balancer và Service Discovery, Circuit breaker,… Spring Boot sẽ tự biết làm gì để tạo ra project skeleton với đầy đủ những thứ bạn cần, và thậm chí, bạn có thể bấm Run luôn cái project mới tạo ra luôn đấy.

Spring Cloud là nền tảng khá mới mẻ trong gia đình Spring.io dùng để xây dựng microservice một cách nhanh chóng. Spring Cloud cung cấp các công cụ cho các developer để nhanh chóng xây dựng một số common patterns trong các hệ thống phân tán (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). Chúng sẽ hoạt động tốt trong bất kỳ môi trường phân tán nào, bao gồm máy tính xách tay của chính developer, các data center hoặc trên cloud.

Bản thân hệ sinh thái Spring không tự build hết tất cả các viên gạch cần để xây dựng ứng dụng Microservices. Thay vào đó, có một kho gạch dành cho Microservices được Netflix ban đầu phát triển trong nội bộ của họ để xây dựng dịch vụ xem phim trực tuyến nổi tiếng của họ và sau đó public ra dưới dạng open source với cái tên Netflix OSS (Open Source Software). Và Spring đơn giản chỉ làm nhiệm vụ wrap chúng lại và dùng trong hệ sinh thái của Spring (tất nhiên Spring nó còn wrap nhiều thằng khác nữa). Bằng cách kết hợp Spring Boot, Spring Cloud và Netflix OSS sẽ đủ cung cấp các công cụ và nguyên liệu cần thiết nhất để giúp bạn có thể nhanh chóng và dễ dàng xây dựng các Microservices của mình.

Bảng nguyên liệu

Nhìn vào bảng dưới đây sẽ cho thấy cách mapping giữa các viên gạch chúng ta đã nói trong phần mở đầu và các công nghệ để giải quyết

1

Trong bài viết này, hãy cùng làm việc với 3 chú: Eureka, Ribbon và Zuul

Netflix Eureka – Là một Service Discovery Server cho phép các dịch vụ microservices tự đăng ký mình vào danh sách các services hoạt động lúc khởi chạy.

Netflix Ribbon – với chức năng Dynamic Routing và Load Balancing có thể được sử dụng bởi Service client để tra cứu dịch vụ lúc runtime. Ribbon sử dụng thông tin có sẵn trong Eureka để định vị các instance thích hợp. Nếu tìm thấy nhiều hơn một instance, Ribbon sẽ áp dụng cân bằng tải để phân phối các reuqest đến các instance rảnh việc nhất. Ribbon không chạy dưới dạng một dịch vụ riêng biệt mà thay vào đó no là một thành phần được nhúng trong mỗi Service client.

Netflix Zuul – Đóng vai trò như một Edge Server hoặc gatekeeper với thế giới bên ngoài, không cho phép bất kỳ yêu cầu bên ngoài trái phép nào đi qua. Các request đi tới services đều phải qua anh chàng Zuul này để check hàng trước. Zuul sử dụng Ribbon để tra cứu các dịch vụ sẵn có và định tuyến yêu cầu bên ngoài đến instance dịch vụ thích hợp. Trong bài đăng trên blog này, tôi sẽ chỉ sử dụng Zuul như một điểm vào (entry point), các khía cạnh về bảo mật sẽ có trong các bài đăng trên blog sắp tới. Các bạn có thể tìm hiểu thêm về GateKeeper hay nói cách khác là API Gateway ở đây nhé

2. Kiến trúc

2

Có 4 business services ( màu xanh lá cây ):

Ba core services chịu trách nhiệm xử lý thông tin liên quan đến sản phẩm, đề xuất và đánh giá.
Một composite service có thể tổng hợp thông tin từ ba core services và tạo ra chế độ xem thông tin sản phẩm cùng với các đánh giá và đề xuất của một sản phẩm.

Để hỗ trợ các business services, chúng ta sử dụng các infrastructure servives sau đây ( màu xanh dương ):

  • Service Discovery Server (Netflix Eureka)
  • Dynamic Routing and Load Balancer (Netflix Ribbon)
  • Edge Server (Netflix Zuul)

3. Source code

Bạn có thể checkout source code dưới này về. Lưu ý, cần cài đặt Java SE 8Git.

$ git clone https://github.com/callistaenterprise/blog-microservices.git
$ cd blog-microservices
$ git checkout -b B1 M1.1

Structure của source code

2.1

Mỗi thành phần được xây dựng một cách riêng biệt (hãy nhớ rằng chúng ta không phải xây dựng các ứng dụng nguyên khối 🙂 vì vậy mỗi thành phần có build file riêng của chúng. Sử dụng Gradle làm build system, nếu bạn chưa cài đặt Gradle, build file sẽ download xuống cho bạn. Run shell script dưới đây để build.

$ ./build-all.sh

Hoặc nếu đang sử dụng Windows thì có thể run:

build-all.bat!

4. Diễn giải source code

Chúng ta hãy xem nhanh một số cấu trúc mã nguồn chính. Mỗi microservice được phát triển dưới dạng ứng dụng Spring Boot độc lập và sử dụng Undertow, một container Servlet 3.1 nhẹ làm máy chủ web của nó. Spring MVC được sử dụng để thực hiện các dịch vụ dựa trên REST. Spring RestTemplate được sử dụng để thực hiện các cuộc gọi đi. Nếu muốn biết thêm về các công nghệ cốt lõi này, bạn có thể xem bài đăng trên blog sau đây .

Bây giờ hãy tập trung vào cách sử dụng các chức năng trong Spring CloudNetflix OSS!

4.1 Gradle dependencies

Theo tinh thần của Spring Boot, Spring Cloud đã định nghĩa một tập hợp các dependencies mặc định. Để sử dụng Eureka và Ribbon trong microservice, cần thêm config dưới đây vào build file:

    compile("org.springframework.cloud:spring-cloud-starter-eureka:1.0.0.RELEASE")

Để xem ví dụ hoàn chỉnh, hãy xem product-service/build.gradle.

Để có thể thiết lập máy chủ Eureka, hãy thêm phụ thuộc sau:

    compile('org.springframework.cloud:spring-cloud-starter-eureka-server:1.0.0.RELEASE')

Để xem ví dụ hoàn chỉnh, hãy xem discovery-server/build.gradle.

Tip: các bạn có thể vào trang https://start.spring.io/ và lựa chọn thực đơn (các tính năng) cho ứng dụng microservices của mình, Spring Boot sẽ giúp bạn tìm cách dependencies cần thiết

4.2. Infrastructure Servers

Thiết lập một máy chủ cơ sở hạ tầng (Infrastructure Server) dựa trên Spring Cloud và OSS Netflix thực sự dễ dàng. Ví dụ: đối với máy chủ Eureka, hãy thêm @EnableEurekaServer annotation vào ứng dụng Spring Boot chuẩn:

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

Để xem ví dụ hoàn chỉnh, hãy xem EurekaApplication.java .

Để dựng một máy chủ Zuul, bạn có thể thêm @EnableZuulProxy. Để xem ví dụ hoàn chỉnh, hãy xem ZuulApplication.java.

Với các annotations đơn giản này, bạn đã có thể tạo ra các server đỉnh, làm được việc rồi đấy. Theo mặc định, Zuul thiết lập một route cho mọi dịch vụ mà nó có thể tìm thấy ở Eureka. Với cấu hình sau trong application.yml – chúng ta hãy giới hạn các routes để chỉ cho phép các cuộc gọi đến composite product service:

zuul:
  ignoredServices: "*"
  routes:
    productcomposite:
      path: /productcomposite/**

Để xem ví dụ hoàn chỉnh, hãy xem edge-server/application.yml.

4.3 Business Service

Để tự động đăng ký microservices với Eureka, thêm một @EnableDiscoveryClient annotation vào ứng dụng Spring Boot.

@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.class, args);
    }
}

Để xem ví dụ hoàn chỉnh, hãy xem ProductServiceApplication.java.

Để tìm và gọi một instance của một microservice, sử dụng Ribbon và một Spring RestTemplate như sau:

    @Autowired
    private LoadBalancerClient loadBalancer;
    ...
    public ResponseEntity getReviews(int productId) {

            ServiceInstance instance = loadBalancer.choose("review");
            URI uri = instance.getUri();
		...
            response = restTemplate.getForEntity(url, String.class);

Service client chỉ cần biết tên của dịch vụ (ví dụ như review), Ribbon (tức là LoadBalancerClient ) sẽ tìm thấy một instance dịch vụ và trả về URI của nó cho Service client.

Để có một ví dụ hoàn chỉnh, hãy xem Util.java và ProductCompositeIntegration.java .

5. Khởi chạy các microservices

Trong bài đăng trên blog này, chúng ta sẽ start/run các microservices như các process java độc lập trên môi trường ở máy local. Về sau, chúng ta sẽ tìm hiểu cách triển khai các microservices trên cloudDocker containers!

Để có thể chạy một số lệnh được sử dụng bên dưới, cần phải cài đặt các cURL jq .

Mỗi microservice được start bằng cách sử dụng lệnh ./gradlew bootRun.

Đầu tiên hãy start các infrastructure services (Eureka và Zuul)

$ cd .../blog-microservices/microservices

$ cd support/discovery-server;  ./gradlew bootRun
$ cd support/edge-server;       ./gradlew bootRun

Sau đó start các business services

$ cd core/product-service;                ./gradlew bootRun
$ cd core/recommendation-service;         ./gradlew bootRun
$ cd core/review-service;                 ./gradlew bootRun
$ cd composite/product-composite-service; ./gradlew bootRun

Nếu đang sử dụng Windows, bạn có thể thực thi tập tin bat tương ứng start-all.bat!

Khi các microservices được khởi động và được đăng ký với máy chủ khám phá dịch vụ, chúng sẽ ghi các thông tin sau vào log:

DiscoveryClient … – registration status: 204

Trong ứng dụng web khám phá dịch vụ, bây giờ chúng ta có thể thấy bốn business services và edge server ( http: // localhost: 8761 ):

3

5.1 Test

Bắt đầu gọi composite service thông qua edge server ở port 8765 (xem application.yml) và như chúng ta đã thấy ở trên, chúng ta có thể sử dụng đường dẫn /productcomposite/** để tiếp cận product-composite service thông qua edge server. Kết quả trả về:

$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
    "name": "name",
    "productId": 1,
    "recommendations": [
        {
            "author": "Author 1",
            "rate": 1,
            "recommendationId": 1
        },
        ...
    ],
    "reviews": [
        {
            "author": "Author 1",
            "reviewId": 1,
            "subject": "Subject 1"
        },
        ...
    ],
    "weight": 123
}

5.2 Dynamic Load Balancing

Để tránh lỗi hoặc sự cố mạng tạm thời, sẽ có nhiều instance dịch vụ cùng loại chạy một lúc và sử dụng bộ cân bằng tải để phân bổ các request đến các instance. Vì chúng ta đang sử dụng các port được cấp phát động và một máy chủ khám phá dịch vụ nên rất dễ dàng để thêm một instance mới. Ví dụ, chỉ cần bắt start một review service mới và nó sẽ cấp phát một port mới một cách tự động và chính nó sẽ đăng ký với máy chủ khám phá dịch vụ.

$ cd .../blog-microservices/microservices/core/review-service
$ ./gradlew bootRun

Sau một lúc, bạn có thể check lại trong Eureka server ( http: // localhost: 8761 ):

4

Nếu chạy lệnh curl trước đó ( curl -s localhost:8765/productcomposite/product/1 | jq .) một vài lần và nhìn vào log của hai service instance, bạn sẽ thấy cách bộ cân bằng tải tự động phân bổ các request tới hai instance mà không cần bất kỳ cấu hình thủ công nào:

5.png

6. Tóm tắt

Chúng ta đã biết được sự lợi hại của bộ ba Spring Boot, Spring Cloud và Netflix OSS để đơn giản hóa việc phát triển và triển khai các microservices một cách tự động và mượt mà. Khi các service instance mới được start, chúng sẽ tự động được phát hiện bởi bộ cân bằng tải thông qua máy chủ khám phá dịch vụ và có thể bắt đầu nhận “công việc”. Sử dụng Edge server để kiểm soát các microservices nào được giao tiếp với bên ngoài.

7. Tiếp theo là gì

Có một số câu hỏi vẫn chưa được trả lời, ví dụ như:

  • Làm gì khi có lỗi xảy ra hoặc một hoặc thậm chí nhiều service bị down
  • Làm thế nào để ngăn chặn truy cập trái phép vào API thông qua Edger server?
  • Làm cách nào để có được bức tranh tổng hợp tốt về tình hình đang diễn ra trong toàn hệ thống microservice, ví dụ: tại sao đơn đặt hàng số 123456 chưa được giao?

Trong các bài viết sắp tới trong loạt bài về Building Microservices Application, chúng ta sẽ xem xét cách tăng khả năng phục hồi và chịu lỗi (resilience) bằng bộ ngắt mạch (circuit breaker), sử dụng OAuth 2 để hạn chế quyền truy cập bên ngoài. Chúng ta cũng sẽ xem xét cách sử dụng ELK stack để thu thập log từ tất cả các microservices theo cách tập trung và hợp nhất và more and more. 🙂

Series này là phần tiếp theo series Microservices: Từ Thiết Kế Đến Triển Khai, tập trung vào việc hiện thực hóa các khái niệm đã mô tả ở phần lý thuyết. Hi vọng sẽ giúp ích được cho các bạn khi làm quen với microservies. Các bạn có thể tham khảo thêm về phần Architecture căn bản ở đây nhé.

Tổng hợp và dịch by edwardthienhoang

Building Microservices Application – Phần mở đầu: Bức tranh tổng thể

Đây là bài viết đầu tiên trong phần Xây dựng ứng dụng với Microservices. Trong những loạt bài trước, chúng ta đã tìm hiểu qua phần lý thuyết về những “viên gạch” (building block) chủ đạo trong Microservies. Loạt bài tiếp theo sẽ hướng đến việc implement những pattern như API Gateway, Service Discovery, Circuit Breaker trong kiến trúc Microservices như thế nào.

Mục lục các bài viết sẽ bao gồm:

Đáng lẽ mình sẽ tự tay implement và giải thích về ý nghĩa của từng phần, tuy nhiên, trong thời gian research đã tìm ra được một nguồn tài liệu viết rất chuyên nghiệp và đầy đủ. Vì vậy mình sẽ dựa trên đó để viết, nhằm mang đến cái nhìn professional và đúng đắn nhất 🙂 Các bạn có thể đọc các bài viết nguyên bản tiếng Anh tại ĐÂY.

Trong bài viết đầu tiên này, hãy cùng xem xét về bức tranh tổng thể khi xây dựng một ứng dụng Microservices, sẽ gồm những thành phần (chính) nào, và cách chúng coordinate với nhau như thế nào.

(Bản tiếng Anh: http://callistaenterprise.se/blogg/teknik/2015/05/20/blog-series-building-microservices/)

1. Điều kiện cần

Điều gì là cần thiết để triển khai một số lượng lớn các microservices trong hệ thống?

Hình vẽ dưới đây, theo Martin Fowler, sẽ cho ta biết chính xác điều chúng ta cần đạt được

1

(Nguồn: http://martinfowler.com/articles/microservices.html)

Tuy nhiên, trước khi chúng ta có thể bắt đầu tung ra số lượng lớn các microservices trong hệ thống để thay thế các ứng dụng nguyên khối, có một số điều kiện tiên quyết cần được đáp ứng (hoặc ít nhất là ở mức độ nào đó). Chúng ta cần:

  • một kiến ​​trúc mục tiêu
  • một chuỗi công cụ phân phối liên tục (continues delivery)
  • một tổ chức phù hợp

Hãy xem xét một cách ngắn gọn từng điều kiện tiên quyết.

1.1. Kiến ​​trúc mục tiêu

Đầu tiên chúng ta cần một ý tưởng kiến ​​trúc về cách phân vùng tất cả các microservices. Ví dụ, có thể phân vùng chúng theo chiều dọc trong một số layer như:

  • Core services Xử lý logic nghiệp vụ cốt lõi
  • Composite services có thể phối hợp một số Core services để thực hiện nhiệm vụ chung hoặc tổng hợp thông tin từ một số Core services.
  • API services cung cấp chức năng cho bên ngoài

… và theo chiều ngang, chúng ta có thể áp dụng một số phân vùng theo domain. Điều này có thể dẫn đến một kiến ​​trúc như dưới đây:

2

Lưu ý: Đây chỉ là một kiến ​​trúc mẫu, kiến ​​trúc của bạn có thể hoàn toàn khác nhau. Điều quan trọng ở đây là cần phải có một kiến ​​trúc mẫu được thiết lập trước khi bắt đầu mở rộng quy mô triển khai các microservices. Nếu không, bạn có thể kết thúc trong một cảnh quan hệ thống mà chỉ trông giống như một dĩa mì spaghetti (cực kỳ rối rắm, vô tổ chức) với đặc điểm thậm chí còn tồi tệ hơn so với các ứng dụng nguyên khối hiện có.

1.2. Continous Delivery

Chúng ta cũng giả định rằng có một hệ thống continuous delivery tool chain để có thể triển khai các microservices của mình theo cách có hiệu quả và có thể lặp lại được, ví dụ:

3

(Nguồn: http://www.infoq.com/minibooks/emag-devops-toolchain)

1.3. Tổ chức

Cuối cùng, giả định rằng chúng ta đã thông qua tổ chức của mình để tránh các vấn đề với định luật Conway:

“Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”

“Một công ty thiết kế hệ thống thế nào cũng sẽ làm ra những thiết kế giống y hệt với thiết kế hệ thống của chính công ty họ.”

4

(Nguồn: http://martinfowler.com/articles/microservices.html)

2. Một hệ thống phức tạp hơn

Điều gì sẽ xảy ra trong một hệ thống khi chúng ta bắt đầu phân chia ứng dụng nguyên khối và thay thế chúng bằng một số lượng lớn các microservices?

Số lượng đơn vị triển khai (tức là microservice) lớn hơn. Nhiều microservices thay vì một ứng dụng nguyên khối lớn, do đó cần phải quản lý và theo dõi nhiều thành phần hơn.

Các services sử dụng và được sử dụng bởi các services khác sẽ dẫn đến một hệ thống mà nhiều services sẽ kết nối với nhau. (Xem thêm IPC)

Một số services cung cấp các API ra bên ngoài nhằm đóng gói và bảo vệ các services khác khỏi sự truy cập từ bên ngoài. (Xem thêm API Gateway)

Hệ thống sẽ động (dynamic) hơn. Các services mới được triển khai, các services cũ được thay thế hoặc loại bỏ, các instance mới của một service hiện có được khởi chạy thêm để đáp ứng tải gia tăng. Điều này có nghĩa là các services sẽ đến và đi với tần suất cao hơn nhiều so với trước đây. (Xem thêm Service Discovery)

MTBF (Mean time between failures – thời gian để có lỗi xảy ra) sẽ giảm (tức là lỗi nhiều hơn). Với rất nhiều service được triển khai và hoạt động thì xác suất xảy ra lỗi sẽ tăng lên là điều hiển nhiên.

3. Những vấn đề đặt ra

Làm thế nào tất cả các microservices được cấu hình và nó có đúng không? Xử lý cấu hình không phải là vấn đề lớn với một vài ứng dụng, ví dụ: mỗi ứng dụng lưu trữ cấu hình của riêng nó trong các tệp thuộc tính trên đĩa hoặc các bảng cấu hình trong cơ sở dữ liệu riêng của nó. Với một số lượng lớn các microservices được triển khai với nhiều instances trên nhiều máy chủ, cách tiếp cận này sẽ tạo nên vấn đề về cách quản lý cấu hình. Nó sẽ dẫn đến rất nhiều tập tin cấu hình nhỏ trên tất cả hệ thống làm cho việc duy trì và kiểm soát rất khó khăn.

Những microservices nào được triển khai và ở đâu? Bởi vì việc các microservies được triển khai với các địa chỉ máy chủ / cổng khác nhau. Với một số lượng lớn các microservices được triển khai độc lập với nhau sẽ có nhiều thay đổi liên tục trong hệ thống và điều này có thể dễ dẫn đến cơn ác mộng bảo trì nếu phải xử lý thủ công.

Cách cập nhật thông tin định tuyến (routing)? Client sử dụng các services cũng gặp các khó khăn. Cụ thể, nếu các bảng định tuyến, ví dụ như các reverse proxies hoặc các tệp cấu hình của Client, cần được cập nhật theo cách thủ công. Về cơ bản sẽ không có thời gian để chỉnh sửa thủ công các bảng định tuyến trong một hệ thống đang được phát triển liên tục với các microservices mới xuất hiện trên các địa chỉ máy chủ / cổng mới. Thời gian delivery sẽ kéo dài và rủi ro đối với các lỗi thủ công sẽ gây rủi ro về khía cạnh chất lượng và / hoặc làm cho chi phí hoạt động không cần thiết tăng lên.

Làm thế nào để ngăn chặn chuỗi sự cố xảy ra (chain of failures)? Vì các microservices sẽ được kết nối với nhau, cần phải chú ý đặc biệt để tránh các chuỗi sự cố. Nếu không được xử lý đúng thì một lỗi ở một microservies nào đó cũng có thể dẫn đến việc ngừng trệ toàn bộ cả hệ thống.

Làm cách nào để xác minh rằng tất cả các services đều đang hoạt động? Việc theo dõi trạng thái của một vài ứng dụng khá đơn giản nhưng làm cách nào để chúng ta xác minh rằng tất cả các microservices đều khỏe mạnh và sẵn sàng nhận request?

Làm cách nào để theo dõi các thông điệp giữa các services? Điều gì xảy ra nếu team bắt đầu nhận được khiếu nại về một số quá trình xử lý không thành công? Microservice nào là nguyên nhân gốc rễ của vấn đề? Làm thế nào ta có thể phát hiện ra rằng việc xử lý, ví dụ, đơn hàng 12345 bị kẹt vì không thể truy cập vào microservice A hoặc cần phê duyệt thủ công trước khi microservice B có thể gửi thông báo xác nhận liên quan đến đơn hàng đó?

Làm thế nào để đảm bảo rằng chỉ các API-services được đưa ra bên ngoài? Ví dụ: làm cách nào để tránh truy cập trái phép từ bên ngoài vào các microservices nội bộ?

Làm cách nào để bảo mật các API-services? Không phải là câu hỏi mới hoặc cụ thể liên quan đến microservices nhưng vẫn rất quan trọng để bảo đảm cho các microservices an toàn khi đưa ra ngoài.

4. Các thành phần chính trong microservices

Để giải quyết các câu hỏi này, chúng ta sẽ cần các thành phần sau trong một hệ thống microservies:

Central Configuration server. Thay vì cấu hình cục bộ cho mỗi đơn vị triển khai (tức là microservice), chúng ta cần quản lý cấu hình tập trung. Chúng ta cũng cần một configuration API để các microservices có thể sử dụng để lấy thông tin cấu hình.

Service Discovery server. Thay vì theo dõi thủ công những microservices nào được triển khai hiện tại và trên máy chủ và cổng nào, chúng ta cần chức năng Service Discovery cho phép microservices tự đăng ký khi khởi động thông qua API.

Dynamic Routing and Load Balancer. Với chức năng service discovery, các thành phần định tuyến có thể sử dụng discovery API để tra cứu nơi mà microservice được yêu cầu được triển khai và các thành phần cân bằng tải có thể quyết định định tuyến yêu cầu tới instance nào nếu nhiều instance được triển khai cho một service được yêu cầu.

Circuit Breaker. Để tránh chuỗi sự cố, cần phải áp dụng Circuit Breaker pattern, bạn có thể đọc thêm trong cuốn sách Release It! hoặc bài đăng trên blog của Fowler – Circuit Breaker.

Monitoring. Vì đã có circuit breakers, chúng ta có thể bắt đầu theo dõi trạng thái của chúng và thu thập số liệu thống kê thời gian chạy từ chúng để có được một bức tranh về tình trạng sức khỏe của hệ thống.

Centralized log analysis. Để có thể theo dõi messages và phát hiện khi chúng bị kẹt (stuck), chúng ta cần một chức năng phân tích log tập trung có khả năng tiếp cận với máy chủ và thu thập các tệp log mà mỗi services microservice tạo ra. Chức năng phân tích log lưu trữ thông tin log này trong cơ sở dữ liệu trung tâm và cung cấp khả năng tìm kiếm và dashboard. Lưu ý : Để có thể tìm thấy các messages liên quan, điều quan trọng là tất cả các microservices phải sử dụng id đồng nhất trong các log message.

Edge Server. Để đưa các API services ra bên ngoài và để ngăn chặn truy cập trái phép vào các microservices nội bộ, chúng ta cần một edge server nơi tất cả request bên ngoài đi qua. Một edge server có thể tái sử dụng khả năng định tuyến động và cân bằng tải dựa trên service discovery được mô tả ở trên. Edge server sẽ hoạt động như một proxy ngược chủ động mà không cần cập nhật thủ công khi hệ thống nội bộ thay đổi.

OAuth 2.0 protected API’s Để bảo vệ các API services được expose ra bên ngoài, quy trình của OAuth 2.0 có thể như sau:

  • Một component mới có thể đóng vai trò như một Máy chủ ủy quyền (OAuth Authorization Server)
  • Các API services sẽ đóng vai trò như các Máy chủ tài nguyên (OAuth Resource Server)
  • Các Client bên ngoài gọi đến API services với tư cách là OAuth Clients
  • Edge server sẽ làm việc như một OAuth Token Relay, có nghĩa là:
    • Nó sẽ hoạt động như một OAuth Resource Server
    • Nó sẽ chuyển các OAuth Access Tokens có trong request bên ngoài đến các API services

5. Mô hình tham chiếu

5

Lưu ý: Để giảm độ phức tạp, các tương tác giữa microservices và các services hỗ trợ không được vẽ.

6. Bước tiếp theo

Trong các bài viết sắp tới, chúng ta sẽ lần lượt tìm hiểu về từng thành phần trong mô hình tham chiếu.

Series này là phần tiếp theo series Microservices: Từ Thiết Kế Đến Triển Khai, tập trung vào việc hiện thực hóa các khái niệm đã mô tả ở phần lý thuyết. Hi vọng sẽ giúp ích được cho các bạn khi làm quen với microservies. Các bạn có thể tham khảo thêm về phần Architecture căn bản ở đây nhé.

Tổng hợp và dịch by edwardthienhoang