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

Bài viết được sự cho phép của tác giả Edward Thien Hoang

Đâ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.

  Building Microservices Application - Phần mở đầu: Bức tranh tổng thể
  Các thao tác cơ bản với Database SQL Server (tạo mới database, table,...)

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.

1. 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 8 và Git.

$ 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 Cloud và Netflix 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 cloud và Docker 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 và 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é.

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Jobs for Developer hấp dẫn trên TopDev