Skip to content
Home » Spring Cloud La Gi | Eureka Service Registry

Spring Cloud La Gi | Eureka Service Registry

Kiến trúc Micro Service - Spring Cloud Framework

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 ):

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 ):

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:

Spring Cloud Gateway

3.1 Giới thiệu

Dự án này cung cấp API Gateway dựa trên hệ sinh thái Spring bao gồm: Spring 5, Spring boot 2, Project Reactor. Mục đích đưa ra giải pháp hiệu quả trong việc routing api, security, monitoring/metrics và khả năng phục hồi lỗi. Được xem la một trong số API Gateway nổi tiếng, cung cấp đơn giản và hiệu quả để định tuyến các request đến điểm đích bằng việc sử dụng cơ chế Gateway Handler Mapping. Bên cạnh đó, sử dụng Netty Server để cung cấp async request

Spring Cloud Gateway gồm có ba phần chính:

  • Route: Gồm những yếu cơ bản của gateway. Được xác định bởi ID, URI, tập các Filter, tập các điều kiện
  • Predicate: Như khái niệm Predicate trong Java 8 Function Predicate. Cho phép chúng ta sử dụng các params hoặc header từ HTTP để xác định. Là một object để xác định điều kiện. Với mỗi route chúng ta có thể có nhiều predicate
  • Filter: là instance của Spring Framework Webfilter. Mục đích sử dụng là chúng ta có thể chỉnh sửa được request và response trong quá trình routing

public abstract class AbstractRoutePredicateFactory

extends AbstractConfigurable

implements RoutePredicateFactory

{ public AbstractRoutePredicateFactory(Class

configClass) { super(configClass); } }



Spring Cloud Gateway sử dụng [Factory Method Pattern] như một cơ chế để hỗ trợ việc tạo các phiên bản Predicate theo cách có thể mở rộng. Khi chúng ta tạo một custom predicate chúng ta cần khai báo cho Spring Cloud Gateway biết được việc này bằng cách khai báo bean. Nhưng do implemnt RoutePredicateFactor, Spring sẽ tự động hiểu và khởi tạo context phù hợp sau đó cung cấp cho Spring Cloud Gateway

Chúng ta có hai cách để routing request:

  • Code client sử dụng Spring RouteLocator. Nhưng vấn đề cứ lần add hoặc update route chúng ta phải redeploy application
  • Sử dụng file config

Lưu ý: Khi chúng ta tạo một custom predicate. PostFix của class name đó phải là RoutePredicateFactory. VD: SampleRoutePredicateFactory. Khi đó muốn sử dụng ở file config, chúng ta chỉ cần ghi Sample

Dưới đây là cách config một route theo file yaml

routes: – id: test uri: predicates: – Path=/test/** – Before=2021-01-20T17:42:47.789-07:00[America/Denver] filters: – name: PreFilter

  • id: mỗi route phải có một id riêng biệt
  • uri: là hostname của service ta muốn route đến. không cần full context, chỉ cần hostname
  • predicates: là tập những điều kiện Gateway check có thõa điều kiện hay không trước khi routing đến uri

Spring Clould Gateway có hỗ trợ nhiều class Filter như Path, After, Before,… Hoặc chúng ta có thể chủ động tạo class custom Filters theo nhu cầu của mình bằng việc implements GatewayFilterFactory

public class TelcoGatewayFilterFactory implements GatewayFilterFactory

{ }

3.2 Cách hoạt động

Clients sẽ gửi request Spring Cloud Gateway nếu Gateway Handler Mapping xác định một request phù hợp với route, nó sẽ gửi đến Gateway Web Handler. Handler này sẽ gửi request này qua chuỗi Filter đúng với config dành riêng có request này.Lưu ý nếu URI define không có port cụ thể thì service gateway sẽ mặc định 80 đối với HTTP và 443 đối với HTTPS URIs. Ngoài ra, chuỗi Filter sẽ thực hiện các Filter theo thứ tự chúng ta config

3.3 Route Predicate Factories

Spring Cloud Gateway hỗ trợ nhiều cơ chế built-in route predicate. Tất cả các predicate sẽ match với từng attribute của http request. Chúng ta có thể combine route bằng việc dùng logic and để kết hợp nhiều predicate. Tham khảo các thuộc tính tại đây

Map

uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange); String segment = uriVariables.get(“segment”);

3.4 Route Filter (Gateway Filter)

Cho phép chúng ta chỉnh sửa incoming HTTP request hoặc outgoing HTTP response. Sau đây là những config được Spring Cloud Gateway giới thiệu. Tham khảo các thuộc tính tại đây

3.5 Global Filter

Global Filter có cùng những đặc điểm với GatewayFilter những khác biệt ở chỗ nó apply cho all route. Khi kết hợp Global Filter và GateFilter Ordering, request matches với route, filtering web handler sẽ add tất cả instance của GlobalFilter và instance của GatewayFilter vào trong 1 chuỗi lọc. Thứ tự filter phụ thuộc vào hàm getOrder(). Những thuộc tính được liệt kê rõ tại đây

Kiến trúc Micro Service - Spring Cloud Framework
Kiến trúc Micro Service – Spring Cloud Framework

Kết luận

Eureka – Spring Cloud Service Discovery cũng có chút lạc hậu tại thời điểm hiện nay. Nó chỉ phù hợp với những dự án Spring Boot, Quarkus hay các ngôn ngữ lập trình có thư viện kết nối đến Eureka server. Thực ra cấu trúc API của Eureka server đơn giản, tuân thủ REST/JSON. Do đó bạn có thể biến mọi service dùng bất kỳ ngôn ngữ lập trình nào cũng có thể nối đến Eureka và được quản lý. Nếu dự án thuần Java Spring Boot, bạn dùng Eureka Server tốt vì nó đơn giản, có sẵn. Còn nếu dự án microservice có đủ loại ngôn ngữ lập trình, công nghệ khác nhau, hãy cân nhắc Kubernetes service discovery hay Istio service mesh. Một ngày rảnh rỗi, tôi sẽ dựng Kubernetes, Istio Service Mesh để quản lý các dịch vụ viết bằng Spring Boot, Golang, Node.js. Giờ tôi phải dừng ở đây. Hãy thường xuyên vào Blog Techmaster để đọc những bài viết mới nhé.

API Gateway, Spring Cloud Gateway & Zuul 2

Trong bài blog trước chúng ta đã thảo luận về các vấn đề giao tiếp giữa các service với nhau có thể xảy ra khi phát triển theo kiến trúc Microservice Architecture. Microserivce tuy phức tạp nhưng thường là lựa chọn lý tưởng cho các ứng dụng lớn và đòi hỏi sự đáp ứng nhanh. Ngoài những vấn đề đã nêu ở bài trước, chúng ta còn gặp khó khăn gì khi xây dựng service theo kiến trúc này?

Eureka service registry

Chúng ta tạo dự án Spring Boot sử dụng https://start.spring.io/ sử dụng thư viện Eureka Server

. ├── main │ ├── java │ │ └── vn │ │ └── techmaster │ │ └── service_registry │ │ └── ServiceRegistryApplication.java │ └── resources │ ├── application.properties │ └── application.yml <–Khai báo cấu hình Eureka Server

Trong file ServiceRegistryApplication.java hãy bổ xung annotation

@EnableEurekaServer

package vn.techmaster.service_registry; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; public class ServiceRegistryApplication { public static void main(String[] args) { SpringApplication.run(ServiceRegistryApplication.class, args); } }

Trong thư mục resource, tạo file cấu hình application.yml

server port8761 eureka client registerWithEurekafalse fetchRegistryfalse

Eureka server lắng nghe ở cổng 8761. Vì đây là server nên phần Eureka client chúng ta không cần đăng ký

registerWithEureka: false

và cũng không cần lấy danh sách các service đăng ký về

fetchRegistry: false

Hãy chạy dự án này, rồi dùng trình duyệt vào địa chỉ http://localhost:8761/

Microservices: Spring Cloud Eureka Naming Server - Discovery Server
Microservices: Spring Cloud Eureka Naming Server – Discovery Server

Mấy điểm cần lưu ý trong ví dụ demo này

  1. Tôi chưa có áp dụng các phương pháp bảo mật gì cả. Code chỉ dùng để minh hoạ Service Discovery

  2. Ở cả REST API và Web đều phải định nghĩa model Product. Nếu có nhiều dịch vụ cùng dùng chung một số model, bạn nên tạo ra một package riêng chứa tất cả các model này.

    public class Product { private String name; private int price; }

  3. Trong thực tế triển khai lên production, mỗi dịch vụ sẽ được đóng gói thành docker container. Sau đó chúng ta dùng Docker Swarm hay Kubernetes để vận hành các docker container, việc khai báo đường dẫn đến Eureka Server cần phải chỉnh lại cho phù hợp. Tôi sẽ viết ở bài sau.

KIẾN TRÚC

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)
Service Discovery and Microservices Tutorial
Service Discovery and Microservices Tutorial

Những lựa chọn khác thay thế Eureka Service Discovery

Netflix Eureka được tạo ra vào thời kỳ 2008-2010, khi Netflix chuyển từ mô hình Monolithic sang Microservice. Khi đó Docker, Kubernetes chưa có hay phổ biến như hiện nay. Thậm chí khái niệm Mesh service chưa có nốt. Giờ đây Kubernetes cũng đã có tính năng Service Discovery. Điểm khác biệt là Kubernetes Service Discovery áp dụng cho mọi ngôn ngữ lập trình, framework, và không cần phải tác động vào code của từng dịch vụ (thêm Eureka Client, rồi bổ xung annotation, @EnableEurekaClient, cấu hình application.yml..). Rồi service mesh ra đời, với khái niệm Side Car (thùng xe ghép vào xe motor), giúp lập trình không phải cấu hình, sửa đổi code ứng dụng mà vẫn có được tính năng service discovery thậm chí còn thu thập thông tin sức khoẻ từng service để báo cáo tập trung.

Tham khảo:

  • Microservice 4.0 Journey – From Spring NetFlix OSS to Istio Service Mesh and Serverless at Open Source Summit Japan
  • Istio & Service Mesh – simply explained in 15 mins

Zuul là gì?

Nó là một proxy, gateway và một lớp trung gian giữa user và các service của bạn. Eureka server đã giải quyết vấn đề đặt tên cho từng service thay vì dùng địa chỉ IP của chúng. Tuy nhiên một service vẫn có thể có nhiều instance và chúng sẽ chạy trên các cổng khác nhau nên nhiệm vụ của Zuul sẽ là:

  • Map giữa một prefix path (/gallery/**) và một service (gallery-service). Nó sử dụng Euraka server để định tuyến các service được request.
  • Nó giúp cân bằng tải giữa các instance của một service.
  • Còn gì nữa? Chúng ta có thể dùng nó để filter request, thêm xác thực,…

Trong file

pom.xml

của project Zuul, chúng ta sẽ có các dependencies: Web, Eureka Client và Zuul:





org.springframework.boot


spring-boot-starter-web




org.springframework.cloud


spring-cloud-starter-netflix-zuul




org.springframework.cloud


spring-cloud-starter-netflix-eureka-client




org.springframework.boot


spring-boot-devtools


runtime




org.springframework.boot


spring-boot-starter-test


test



Điều đáng nói là Zuul hoạt động như một Eureka client. Vì vậy chúng ta có thể đặt tên cho nó, chỉ định port và đường dẫn đến Eureka server như các client trước đó.


server.port=8762 spring.application.name=zuul-server eureka.client.service-url.default-zone=http://localhost:8761/eureka/ # A prefix that can added to beginning of all requests. #zuul.prefix=/api # Disable accessing services using service name (i.e. gallery-service). # They should be only accessed through the path defined below. zuul.ignored-services=* # Map paths to services zuul.routes.gallery-service.path=/gallery/** zuul.routes.gallery-service.service-id=gallery-service

Cuối cùng là thêm các annotation để thông báo đây là Zuul và Eureka client:


package io.github.tubean.eureka.zuulserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableEurekaClient // It acts as a eureka client @EnableZuulProxy // Enable Zuul public class ZuulServerApplication { public static void main(String[] args) { SpringApplication.run(ZuulServerApplication.class, args); } }

Testing

Ok, như vậy là chúng ta đã dựng xong bộ khung cho hệ thống microservice. Chúng ta đã có một service discovery (Eureka server), hai service (Image và Gallery), một cổng gateway (Zuul) và giờ chỉ cần start chúng lên.

Để chạy nhiều instance thì trong Eclipse, bạn vào Run -> Configurations/Arguments -> VM options và thêm


-Dsever.port=8300

Để kiểm tra ứng dụng của chúng ta, hãy truy cập vào

localhost:8761

, đây là cổng của Eureka Server. Và bạn sẽ thấy các server đang chạy như sau:

Sau đó hãy gọi tiếp đến gallery service bằng đường dẫn

localhost:8762/gallery

. Chúng ta sẽ nhận được message như sau:
>Hello from Gallery Service running at port: 8100

Nếu dùng multiple instance, bạn sẽ nhận được 2 dòng như trên với 2 cổng khác nhau.

Tiếp theo chúng ta gọi đến service Image thông qua Gallery bằng đường dẫn

localhost:8762/gallery/1

. Kết quả nhận được sẽ là:


// 20181218230927 // http://localhost:8762/gallery/1 { "id": 1, "images": [ { "id": 1, "title": "Treehouse of Horror V", "url": "https://www.imdb.com/title/tt0096697/mediaviewer/rm3842005760" }, { "id": 2, "title": "The Town", "url": "https://www.imdb.com/title/tt0096697/mediaviewer/rm3698134272" }, { "id": 3, "title": "The Last Traction Hero", "url": "https://www.imdb.com/title/tt0096697/mediaviewer/rm1445594112" } ] }

Kết thúc phần đầu tiên ở đây, ở phần tiếp theo chúng ta sẽ tìm hiểu cách để xác thực user bằng JWT.

https://tubean.github.io/2018/12/microservice-springboot-eureka-part2/

Nguồn bài viết

https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-intro-to-microservices-part-1-c0d24cd422c3

https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-creating-our-microserivces-gateway-part-2-31f8aa6b215b

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.

Microservices là gì? Kiến trúc \
Microservices là gì? Kiến trúc \”nhỏ\” cho các dự án siêu to – Code Dạo Dễ Òm

Mô hình hệ thống demo

Để tối giản, tôi lập trình 3 dự án:

  • “Eureka Server” trong thư mục service_registry.

  • “Shop” REST API trả về danh sách sản phẩm.

  • “Web” Ứng dụng web cần gọi vào “Shop” để lấy dữ liệu.

    Cả “Shop” và “Web” sẽ là Eureka Client, cần kết nối vào Eureka Server.

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

Xây dựng Api Gateway service | Khóa học xây dựng hệ thống microservice với Spring Boot #8
Xây dựng Api Gateway service | Khóa học xây dựng hệ thống microservice với Spring Boot #8

Service Discovery là gì?

Tôi phát triển một web site thương mại điện tử trên kiến trúc microservice. Phía ngoài cùng sẽ là API Gateway cùng module Authentication/Authorization, phía sau là rất nhiều các service chuyên biệt gọi lẫn nhau chứ không dùng chung một database:

  • Catalog: danh mục mặt hàng

  • Sales: quản lý order, thanh toán, khuyến mại, giảm giá…

  • Merchant: quản lý các nhà cung cấp

  • Inventory: quản lý kho – nhập / xuất, hàng tồn kho

  • Guarantee: dịch vụ bảo hành sửa chữa

  • User: quản lý tất cả các user tham gia hệ thống

Mỗi service không chỉ phục vụ các request từ API Gateway điều hướng tới, mà còn phục vụ dữ liệu cho các service khác. Có rất nhiều vấn đề mà chúng ta phải đối mặt để đảm bảo hệ thống hoạt động thông suốt. Có những pattern mà bạn chắc đã nghe như:

  • Service Discovery: khám phá dịch vụ –> Đây là pattern bài viết này tập trung vào
  • Centralize Configuration: cấu hình tập trung
  • Load Balancing: căn bằng tải
  • Circuit Breaker: cầu trì ngắt lỗi
  • Tracing – Monitoring: theo dõi
  • Routing: định tuyến
  • Message Queue: trao đổi bằng thông điệp
  • Event Sourcing – CQRS

Service Discovery giúp các service có thể nói chuyện trực tiếp với nhau dễ dàng hơn. Giả sử hệ thống có 20 service hoặc nhiều hơn. Chúng ta không để gán từ tên miền cho mỗi service được. Một số service có thể chung địa chỉ IP nhưng khác cổng. Một số service lại phân tải ra nhiều node ở các địa chỉ IP khác nhau. Service cũng có thể bị lỗi, khởi động lại, lại được cấp một địa chỉ IP mới tinh.

Service Discovery hoạt động giống như một Domain Name Server: mỗi service bật lên, cần nối đến để đăng ký địa chỉ IP, cổng, tên servide, đồng thời lấy danh sách của service khác về. Như thế mọi service sẽ biết lẫn nhau kịp thời.

Netflix là một dịch vụ cho thuê phim số 1 thế giới. Để đáp ứng số lượng thuê bao khồng lồ, trên toàn thế giới, Netflix kiến trúc hệ thống mô hình microservice từ 2008. Eureka là một thư viện được Netflix phát triển phục vụ cho hệ thống microservice của mình. Sau một thời gian, Netflix mở mã nguồn, phiên bản Eureka 1.0. Trong lúc chuẩn bị nâng cấp lên phiên bản 2.0, thì Spring Cloud một dự án mã nguồn mở của Pivotal, đã tích hợp Netflix thành https://github.com/spring-cloud/spring-cloud-netflix. Do đó phiên bản Eureka 2.0 sẽ không phát triển tiếp.

Nói thêm về Pivotal một chút, đây là công ty bảo trợ cho rất nhiều phần mềm mã nguồn mở nổi tiếng như:

Pivotal bị VMWare mua lại. Sau đó VMWare lại bị Dell Technologies mua lại. Dell Technologies thuộc tập đoàn Dell, có người anh em Dell Computer chuyên sản xuất laptop, workstation mà các người anh em lập trình Việt nam hay dùng rồi cài Hackintosh đó.

Những gì tôi trình bày dưới đây sẽ về thư viện Service Discovery của Spring Cloud, đã học hỏi, vay mượn từ Netflix Eureka để phát triển lên.

REST server ‘shop’

Để tạo REST API, tôi cần một số thư viện:

  • spring-boot-starter-web: để tạo REST Controller

  • spring-cloud-starter-netflix-eureka-client: đăng ký Eureka server và lấy danh sách service về

  • spring-boot-starter-actuator: tạo dashboard để cung cấp thông tin tình trạng của server

  • lombok: giúp định nghĩa class model ngắn gọn, đơn giản hơn



org.springframework.boot


spring-boot-starter-web




org.springframework.cloud


spring-cloud-starter-netflix-eureka-client




org.springframework.boot


spring-boot-starter-actuator




org.projectlombok


lombok

true

Cấu trúc thư mục dự án như sau:

. ├── main │ ├── java │ │ └── vn │ │ └── techmaster │ │ └── shop │ │ ├── controller │ │ │ └── ProductController.java <– REST Controller │ │ ├── model │ │ │ └── Product.java <– định nghĩa model │ │ └── ShopApplication.java │ └── resources │ ├── application.properties <– cấu hình Actuator │ └── application.yml <– cấu hình Eureka Client

File application.yml cấu hình kết nối vào Eureka server.

spring application nameshop server port0 eureka client serviceUrl defaultZone$ EUREKA_URI http //localhost 8761/eureka instance preferIpAddresstrue

Giải thích:


  • server.port = 0

    cho phép chọn ngẫu nhiên port mà REST server phục vụ.

  • eureka.client.serviceUrl.defaultZone

    khai báo đường dẫn đến Eureka Server.

    http://localhost:8761/eureka

    .

  • instance.preferIpAddress: true

    : yêu cầu Eureka server trả về danh sách service với địa chỉ IP của mỗi service thay vì tên miền nếu có. Việc này giúp kết nối sẽ nhanh hơn, bỏ qua giai đoạn dịch từ tên miền sang IP nhờ DNS.

File application.properties cấu hình cho Actuator

management.endpoints.enabled-by-default=true management.endpoint.info.enabled=true management.endpoints.web.exposure.include=health,info,metrics management.endpoint.health.show-details=always [email protected]@ [email protected]@ [email protected]@ [email protected]@ [email protected]@

File ShopApplication.java bổ xung annotation

@EnableEurekaClient

public class ShopApplication { … }

File ProductController.java chỉ có một phương thức trả về danh sách sản phẩm

“/”) public class ProductController { (“products”) public List getProducts() { return new ArrayList<>(List.of(new Product(“Nike 360”, 100), new Product(“Sony WXMH4”, 200))); } }(

Hãy biên dịch và chạy, rồi quay lại đường dẫn http://localhost:8761 refresh sẽ thấy dịch vụ “shop” đã đăng ký với Eureka

Ấn vào link sẽ mở ra Actuator info của dịch vụ “shop”

Gõ đường dẫn đến /products thì có dữ liệu trả về

Vậy chúng ta sẽ dựng được Eureka server. Tiếp đến dựng REST server có tên là shop, biến nó thành Eureka client, kết nối vào Eureka server.

Spring Cloud | What is Spring Cloud Really All About?
Spring Cloud | What is Spring Cloud Really All About?

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.

Đặt vấn đề

Khi xây dựng ứng dụng bằng một tập hợp các microservices, chúng ta cần quyết định các application clients sẽ tương tác với microservices như thế nào. Với một ứng dụng theo hướng Monolithic Architecture chỉ có một tập hợp các endpoints. Tuy nhiên, trong kiến trúc Microservices thì mỗi service sẽ có tập các endpoints nhỏ riêng theo từng service. Những URL public sẽ ánh xạ tới load balancer của microservice, phân phối các request trên tới các instance đang có sẵn và để lấy thông tin từ phía service, application client chỉ cần gửi request đúng với endpoint đó, đúng với các tham số quy định, từ đó có thể lấy thông tin. Mọi thử ở đây khá đơn giản 🙂

Tuy nhiên sẽ có vấn đề tìm ẩn ở đây và nó chỉ xảy ra khi hệ thống chúng ta mở rộng không kiểm soát. Khi đó mỗi service sẽ có một tập danh sách api dài để phục vụ cho business. Nên nhớ business liên tục thay đổi và phức tạp hơn theo thời gian và cách tiếp cận bên trên có thể mang đến những thách thức và hạn chế nhất định.

  • Sự không phù hợp giữa nhu cầu client và các api chi tiết được cung cấp bởi từng service. Do mỗi service sẽ có các business logic khác nhau nên khi client muốn lấy hết thông tin thì phải thực hiện nhiều request đến từng service khác nhau và nó sẽ càng nhiều hơn trong tương lai. Cách tiếp cận này làm cho mã nguồn các client sẽ phức tạp hơn rất nhiều.
  • Đối với một số service sử dụng các giao thức không thân thiện với web như (RPC, AMQP) các protocol này chỉ phù hợp cho cách giao tiếp nội bộ.
  • Gây khó khăn trong việc tái cấu trúc microservices. Theo thời gian chúng ta có nhu cầu muốn thay đổi cách hệ thống để phân vùng các services (hợp nhất 2 service hoặc chia service chung thành 2 service riêng biệt). Nếu như client giao tiếp trực tiếp với dịch vụ thì việc thực hiện tái cấu trúc này sẽ khó hơn.
  • Hiệu suất mạng sẽ khác nhau đối với mỗi client. Với mạng di động thường sẽ chậm hơn và latency cao hơn đối non-mobile network. Điều đó phản ánh mobile client sẽ có hiệu suất chậm hơn việc server-side web sử dụng mạng LAN. Ở phía server-side web có thể thực hiện nhiều request đến backend service mà không ảnh hưởng đến trải nghiệm user.

Câu hỏi được đặt ra “Làm thể nào để có thể giải quyết được vấn đề này ?”. Bài viết này chúng ta sẽ tìm hiểu việc xây dựng microservices bằng cách sử dụng API Gateway.

Spring microservices phần 7 - Hướng dẫn tổng quan và cách tạo gateway service
Spring microservices phần 7 – Hướng dẫn tổng quan và cách tạo gateway service

Các khái niệm

Spring Boot là gì ?

Spring Boot là một framework được xây dựng trên nền tảng của Spring Framework và được thiết kế để giúp cho việc phát triển ứng dụng Spring nhanh hơn và đơn giản hóa việc cấu hình. Nó cung cấp cho các nhà phát triển một cách tiếp cận mới để phát triển các ứng dụng web Spring một cách nhanh chóng, mà không cần phải tốn nhiều thời gian để cấu hình hoặc sắp xếp các dependency phức tạp. Spring Boot cung cấp nhiều tính năng tiện lợi như auto-configuration, embedded web server, starter dependencies và actuator để giúp việc phát triển và triển khai ứng dụng Spring trở nên đơn giản hơn.

Spring Cloud là gì?

Spring Cloud là một framework phát triển trên nền tảng Spring để giúp cho việc xây dựng các ứng dụng phân tán trở nên dễ dàng hơn. Nó cung cấp các tính năng và công cụ để giải quyết các vấn đề phức tạp như phân tán, khả năng mở rộng, cân bằng tải, khả năng phục hồi, giám sát và quản lý cấu hình. Spring Cloud cũng hỗ trợ các công nghệ mở như Netflix OSS (Open Source Software) và các giải pháp đám mây như Eureka, Ribbon, Hystrix, Zuul, Config Server, và nhiều hơn nữa. Sử dụng Spring Cloud giúp cho việc triển khai các ứng dụng phân tán trở nên đơn giản và dễ quản lý hơn.

Microservices là gì?

Có nhiều định nghĩa khác nhau về Microservices và có thể bạn sẽ bị bối rối không biết cái nào đúng, cái nào tối ưu. Định nghĩa sau đấ sẽ kết hợp các khái niệm phổ biến nhất của Microservices.

Một microservice là một phương pháp kỹ thuật tập trung vào việc phân tách (decomposing) ứng dụng thành các module chức năng đơn (single-function ) với các giao diện được xác định rõ ràng (well-defined interfaces), được triển khai và vận hành độc lập (Independent) bởi các nhóm nhỏ (Small Teams) có quản lý toàn bộ vòng đời (Entire Lifecycle) của dịch vụ.

Microservices giúp gia tăng tốc độ phát triển bằng cách giảm thiểu sự giao tiếp (Minimizing Communication) và phối hợp giữa các thành viên trong nhóm, đồng thời giảm phạm vi và rủi ro của các thay đổi (The scope and risk of change) .

Phân tách (Decomposing) là gì?

Decomposing trong ngữ cảnh của microservices nghĩa là phân tách ứng dụng thành các module chức năng đơn. Tức là, thay vì có một ứng dụng lớn thì chúng ta sẽ tách thành nhiều ứng dụng nhỏ hơn, mỗi ứng dụng nhỏ này có chức năng rõ ràng và phục vụ cho một nhu cầu cụ thể của ứng dụng lớn. Việc phân tách này giúp cho việc phát triển và bảo trì ứng dụng trở nên dễ dàng hơn và tăng tính linh hoạt của hệ thống.

Ví dụ:


class BookApp { User getBook() { // 1. lấy thông danh sách book // 2. lấy thông tin chi tiết book // 3. ghi lịch sử book đã xem } } class BookApp { void getBooks() { ... } User getDetailBook() { ... } void logHistoryReadBook() { ... } }

Single-function (Chức năng đơn) là gì?

Single-function là thuật ngữ trong kiến trúc Microservices, chỉ định rằng mỗi microservice chỉ nên chứa một chức năng cố định, thực hiện một nhiệm vụ cụ thể của hệ thống. Điều này giúp tách biệt các chức năng khác nhau của ứng dụng và giúp cho việc phát triển và bảo trì các microservice trở nên đơn giản hơn.

Giao diện được xác định rõ ràng (well-defined interfaces) là gì?

Well-defined interfaces là các giao diện được định nghĩa rõ ràng và cung cấp các quy tắc về cách các thành phần khác của hệ thống có thể tương tác với chúng. Các giao diện này giúp đảm bảo tính tương thích và khả năng mở rộng trong hệ thống phân tán, bởi vì các thành phần khác nhau có thể giao tiếp với nhau thông qua các giao diện được định nghĩa trước đó mà không cần biết chi tiết bên trong của nhau.

Độc lập (Independent) là gì?

Trong ngữ cảnh của microservices, độc lập (independent) thường được hiểu là các service có thể hoạt động hoàn toàn độc lập với nhau, mà không bị phụ thuộc vào các service khác. Nói cách khác, các service có thể triển khai và vận hành độc lập, và không cần phải liên tục phối hợp với nhau để thực hiện một chức năng nào đó. Điều này giúp giảm thiểu sự phụ thuộc giữa các service và làm cho hệ thống dễ dàng mở rộng và bảo trì hơn.

Ví dụ:

Giả sử rằng chúng ta cần triển khai một microservice độc lập để tính toán giá trị VAT cho các sản phẩm bán hàng. Ta sẽ tạo một ứng dụng Spring Boot mới với một REST endpoint để tính toán VAT cho một sản phẩm.

Trước tiên, ta sẽ tạo một interface để định nghĩa các phương thức cần thiết để tính toán giá trị VAT:


public interface VatCalculator { double calculateVat(double price, double vatRate); }

Sau đó, ta sẽ tạo một implementation của interface này:


@Service public class VatCalculatorImpl implements VatCalculator { @Override public double calculateVat(double price, double vatRate) { return price * vatRate / 100; } }

Cuối cùng, ta sẽ tạo một REST controller để xử lý yêu cầu và trả về kết quả tính toán VAT:


@RestController public class VatController { @Autowired private VatCalculator vatCalculator; @GetMapping("/calculate-vat") public double calculateVat(@RequestParam double price, @RequestParam double vatRate) { return vatCalculator.calculateVat(price, vatRate); } }

Như vậy, ta đã tạo ra một microservice độc lập trong Java sử dụng Spring Boot để tính toán giá trị VAT cho các sản phẩm bán hàng.

Các nhóm nhỏ (Small Teams) là gì?

  • Chúng ta chia công việc và phân nhóm cho các dịch vụ. Mỗi nhóm tập trung vào một dịch vụ cụ thể, họ không cần biết về các hoạt động nội bộ của các nhóm khác.
  • Những nhóm này có thể làm việc hiệu quả, giao tiếp dễ dàng và mỗi dịch vụ có thể triển khai nhanh chóng ngay khi sẵn sàng.

Toàn bộ vòng đời (Entire Lifecycle) là gì?

  • Đội ngũ chịu trách nhiệm cho toàn bộ vòng đời của dịch vụ; từ việc viết mã, kiểm thử, phát triển, triển khai, gỡ lỗi và bảo trì.
  • Trong một ứng dụng truyền thống, chúng ta có thể có một nhóm chịu trách nhiệm cho việc viết mã, và một nhóm khác chịu trách nhiệm cho việc triển khai. Tuy nhiên, trong kiến trúc microservices, điều này không đúng.

Giảm thiểu sự giao tiếp (Minimizing Communication) là gì?

  • Giảm thiểu sự giao tiếp không có nghĩa là các thành viên trong nhóm không cần quan tâm đến nhau. Điều này có nghĩa là chỉ giao tiếp cần thiết giữa các nhóm nên thông qua giao diện mà mỗi dịch vụ cung cấp.
  • Các nhóm cần đồng ý về giao diện bên ngoài để việc giao tiếp giữa các dịch vụ được xác định rõ ràng.

Giảm phạm vi và rủi ro của các thay đổi (The scope and risk of change) là gì?

  • Các dịch vụ nên được thay đổi mà không làm hỏng các dịch vụ khác. Và miễn là chúng ta không thay đổi giao diện bên ngoài thì sẽ không có vấn đề cho các dịch vụ khác.
  • Kết quả của các thay đổi là phiên bản của các dịch vụ được cập nhật một cách độc lập và không có mối quan hệ giữa chúng.

Monolithic Vs Microservices

  • Sự lựa chọn giữa hai phương pháp phụ thuộc vào ngữ cảnh và độ phức tạp của ứng dụng.
  • Thực sự, microservices giải quyết các vấn đề xuất hiện trong ứng dụng lớn khi nói đến khả năng mở rộng, quản lý, nhưng nó không phải lúc nào cũng là giải pháp tối ưu.
  • Quan trọng là phải nhớ rằng microservices có thể được sử dụng trong ngữ cảnh không phù hợp, dẫn đến tăng thêm công sức và chi phí, thậm chí là thất bại của dự án.
  • Hầu hết các vấn đề trong Microservices được thừa kế do việc có các thành phần riêng lẻ.
  • Ví dụ, việc giao tiếp giữa các phương thức trong monolithic nhanh hơn rất nhiều so với giao tiếp bất đồng bộ trong các dịch vụ, điều này khiến nó chậm hơn, khó gỡ lỗi và phải được bảo mật.
  • Và chắc chắn, sẽ có thêm công sức cho các hoạt động liên quan đến vận hành, triển khai, mở rộng, cấu hình, giám sát và kiểm thử vì mỗi dịch vụ đều là độc lập.
  • Do đó, chúng ta cần có một nhóm DevOps có kỹ năng để xử lý độ phức tạp liên quan đến triển khai và tự động giám sát.

Bài viết tham khảo: https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-intro-to-microservices-part-1-c0d24cd422c3

Vậy là chúng ta đã hoàn thành phần giới thiệu về Microservices

Cảm ơn bạn đã đọc! Nếu bạn thấy bài viết hữu ích, vui lòng nhấn 👍️ (upvote), dể mình có động lực làm nhiều bài viết hay hơn

All rights reserved

Microservices với Spring Boot và Spring Cloud (Phần 2) – Cấu hình dự án ban đầu bằng Eureka Server, Spring Cloud Gateway, Spring Cloud Config

Phiên bản của các ứng dụng Spring Boot mà chúng ta sẽ tạo là: 3.0.6 , Java 17

Các bài viết tham khảo:

  • https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-creating-our-microserivces-gateway-part-2-31f8aa6b215b
  • https://medium.com/@ihorkosandiak/spring-cloud-gateway-security-with-jwt-93341b342020

Link github để các bạn tham khảo code : https://github.com/akitectio/microservices-spring-boot-3

Ta có kiến trúc hệ thống triển khai như sau:

Eureka Server

Eureka Server là một máy chủ đăng ký dịch vụ trong hệ thống Microservices. Nó đảm nhiệm việc đặt tên cho mỗi microservice. Tại sao cần đặt tên? Bởi vì khi có nhiều microservices được triển khai và hoạt động trên nhiều instance khác nhau, không cần phải mã hóa địa chỉ IP cứng của mỗi service, thay vào đó, chúng ta có thể sử dụng tên service đã đăng ký trên Eureka Server để tìm kiếm và truy cập các dịch vụ này. Điều này giúp cho việc quản lý và mở rộng các dịch vụ một cách dễ dàng và hiệu quả hơn.

Vì vậy, mỗi dịch vụ đăng ký với Eureka và gửi yêu cầu ping tới Eureka server để thông báo rằng nó đang hoạt động.

Nếu Eureka server không nhận được bất kỳ thông báo nào từ một dịch vụ, dịch vụ đó sẽ bị hủy đăng ký tự động từ Eureka server.

Bạn sử dụng Spring Initializr dể tạo một Project Eureka Server và thêm dependencies: Web, Eureka Server, DevTools

Ta chọn và điền phần Project Metadata theo như cầu dự án của mình

Sau đó nhập vào để tạo project

Tiếp tục tạo thư mục mới tên là microservices-project và coppy thư mục vừa vào tạo và tạo thêm file pom.xml với nội dung



4.0.0

org.springframework.boot


spring-boot-starter-parent


3.0.6


com.duytran


microservices-system


0.0.1-SNAPSHOT
pom
microservices System


Microservices System
UTF-8 UTF-8
17


eureka-server



org.springframework.boot


spring-boot-maven-plugin

Tiếp theo, trong tệp

application.properties

, chúng ta cần thiết lập một số cấu hình.


# Give a name to the eureka server spring.application.name=eureka-server # default port for eureka server server.port=8761 # eureka by default will register itself as a client. So, we need to set it to false. # What's a client server? See other microservices (image, gallery, auth, etc). eureka.client.register-with-eureka=false eureka.client.fetch-registry=false

Cuối cùng, trong lớp ứng dụng chính của Spring Boot, chúng ta cần kích hoạt Eureka server bằng cách sử dụng chú thích

@EnableEurekaServer

.


package com.duytran.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer // Enable eureka server public class SpringEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(SpringEurekaServerApplication.class, args); } }

Tới đây thì bạn đã khởi tạo thành công Eureka Server

Service 01 – EnableDiscoveryClient

Service Eureka client là một dịch vụ độc lập trong kiến trúc microservice. Nó có thể được sử dụng cho thanh toán, tài khoản, thông báo, xác thực, cấu hình, v.v.

Chúng ta tiếp tục sử dụng Spring Initializr dể tạo một Project Eureka Client mang tên là Service01 và thêm dependencies: **Eureka Discovery Client,Rest Repositories **

Ta chọn và điền phần Project Metadata theo như cầu dự án của mình

Sau đó nhập vào để tạo project

Tiếp tục tạo thư mục mới tên là microservices-project và coppy thư mục vừa vào tạo và thêm config vào file pom.xml với nội dung




eureka-server


service01

#<- Thêm vào đây

Trong tệp

application.properties

, chúng ta xác định các cấu hình


# serivce name spring.application.name=service01 # port server.port=8801 # eureka server url eureka.client.service-url.default-zone=http://localhost:8761/eureka

Sau đó, kích hoạt eureka client bằng cách sử dụng chú thích

@EnableDiscoveryClient

.


package com.duytran.service01.controllers; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableDiscoveryClient // Enable eureka client. It inherits from @EnableDiscoveryClient. public class SpringEurekaImageApp { public static void main(String[] args) { SpringApplication.run(SpringEurekaImageApp.class, args); } }

Tiếp tục thêm HomeController và entities Image

HomeController


package com.duytran.service01.controllers; import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.duytran.service01.entities.Image; @RestController @RequestMapping("/") public class HomeController { @Autowired private Environment env; @RequestMapping("/service01") public List getImages() { List images = Arrays.asList( new Image(1, "Treehouse of Horror V", "https://www.imdb.com/title/tt0096697/mediaviewer/rm3842005760"), new Image(2, "The Town", "https://www.imdb.com/title/tt0096697/mediaviewer/rm3698134272"), new Image(3, "The Last Traction Hero", "https://www.imdb.com/title/tt0096697/mediaviewer/rm1445594112")); return images; } }

entities Image


package com.duytran.service01.entities; public class Image { private int id; private String name; private String url; public Image(int id, String name, String url) { this.id = id; this.name = name; this.url = url; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }

Service 02 – EnableDiscoveryClient

Để gọi tới một REST client hoặc nhiều services khác bạn có thể dùng:

  1. RestTemplate là một đối tượng trong Spring Framework cung cấp khả năng gửi các yêu cầu HTTP đến các dịch vụ REST API khác. Nó hỗ trợ nhiều phương thức HTTP như GET, POST, PUT, DELETE, PATCH, … để gửi các yêu cầu đến các địa chỉ URL khác nhau và xử lý các phản hồi trả về từ các dịch vụ đó.
  2. FeignClient là một annotation trong Spring Cloud, được sử dụng để tạo ra một client đại diện cho một RESTful service. Thay vì sử dụng RestTemplate, FeignClient sử dụng cấu hình interface và annotation để định nghĩa các method và URL endpoint cho các request. FeignClient cũng cung cấp khả năng load balancing và fault tolerance cho các service.

Cả hai cách điều cân bằng tải trên tất cả dịch vụ.

Thế nào là cân bằng tải (load balancing)?

  • Khi một dịch vụ có nhiều hơn một phiên bản đang chạy trên các cổng khác nhau, ta cần phải cân bằng tải các yêu cầu giữa các phiên bản của dịch vụ đó.
  • Khi sử dụng phương pháp “Ribbon” (mặc định), các yêu cầu sẽ được phân phối đều giữa các phiên bản của dịch vụ đó.

Chúng ta tiếp tục sử dụng Spring Initializr dể tạo một Project Eureka Client mang tên là Service02 và thêm dependencies: **Eureka Discovery Client,Rest Repositories **

Ta chọn và điền phần Project Metadata theo như cầu dự án của mình

Sau đó nhập vào để tạo project

Tiếp tục tạo thư mục mới tên là microservices-project và coppy thư mục vừa vào tạo và thêm config vào file pom.xml với nội dung




eureka-server


service01


service02

#<- Thêm vào đây

Tiếp theo là tập tin

application.properties

.


spring.application.name=service02 server.port=8802 eureka.client.service-url.default-zone=http://localhost:8761/eureka

Trong class chính của ứng dụng Spring Boot, bên cạnh việc kích hoạt Eureka client, chúng ta cần tạo một bean cho RestTemplate để gọi đến service01.

Tệp Service02Application.java:


package com.duytran.service02; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class Service02Application { public static void main(String[] args) { SpringApplication.run(Service02Application.class, args); } } @Configuration class RestTemplateConfig { // Create a bean for restTemplate to call services @Bean @LoadBalanced // Load balance between service instances running at different ports. public RestTemplate restTemplate() { return new RestTemplate(); } }

Trong controller tạo HomeController, gọi serivce01 bằng RestTemplate và trả kết quả.


package com.duytran.service02.controllers; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.duytran.service02.entities.Gallery; @RestController @RequestMapping("/") public class HomeController { @Autowired private RestTemplate restTemplate; @Autowired private Environment env; @RequestMapping("/") public String home() { // This is useful for debugging // When having multiple instance of gallery service running at different ports. // We load balance among them, and display which instance received the request. return "Hello from Gallery Service running at port: " + env.getProperty("local.server.port"); } @RequestMapping("/{id}") public Gallery getGallery(@PathVariable final int id) { // create gallery object Gallery gallery = new Gallery(); gallery.setId(id); // get list of available images List
images = restTemplate.getForObject("http://service01/images/", List.class); gallery.setImages(images); return gallery; } // -------- Admin Area -------- // This method should only be accessed by users with role of 'admin' // We'll add the logic of role based auth later @RequestMapping("/admin") public String homeAdmin() { return "This is the admin area of Gallery service running at port: " + env.getProperty("local.server.port"); } }

Trong thư mục entities tạo Gallery.


package com.duytran.service02.entities; import java.util.List; public class Gallery { private int id; private List
images; public Gallery() { } public Gallery(int galleryId) { this.id = galleryId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public List
getImages() { return images; } public void setImages(List
images) { this.images = images; } }

Một điều cần lưu ý. Vì chúng ta đang sử dụng restTemplate – sử dụng Eureka Server để đặt tên cho các dịch vụ và Ribbon để cân bằng tải. Vì vậy, chúng ta có thể sử dụng tên dịch vụ (như service01) thay vì localhost:port.

Gateway — Spring Cloud Gateway

Khi gọi bất kỳ dịch vụ nào từ trình duyệt, chúng ta không thể gọi bằng tên như chúng ta đã làm từ dịch vụ Service02 – Điều này được sử dụng nội bộ giữa các dịch vụ.

Và khi chúng ta tạo nhiều phiên bản của dịch vụ, mỗi phiên bản có một số cổng khác nhau. Vậy, câu hỏi là: Làm thế nào để gọi các dịch vụ từ trình duyệt và phân phối yêu cầu đến các phiên bản khác nhau đang chạy trên các cổng khác nhau?

Vâng, một giải pháp thông thường là sử dụng một Gateway.

Một Gateway là một điểm nhập cửa đơn giản vào hệ thống, được sử dụng để xử lý các yêu cầu bằng cách định tuyến chúng đến dịch vụ tương ứng. Nó cũng có thể được sử dụng cho xác thực, giám sát và nhiều hơn nữa.

Spring Cloud Gateway là gì?

Spring Cloud Gateway là một thư viện được sử dụng để xây dựng cổng API trên nền tảng Spring WebFlux. Dự án này nhằm mục đích cung cấp một cách đơn giản và hiệu quả để định tuyến đến các API và cung cấp các vấn đề liên quan đến bảo mật, giám sát/thống kê và tính chịu lỗi.

Nó là một proxy, cổng thông tin, một lớp trung gian giữa người dùng và dịch vụ của bạn.

Eureka server giải quyết vấn đề đặt tên cho các dịch vụ thay vì hardcode địa chỉ IP của chúng.

Tuy nhiên, chúng ta vẫn có thể có nhiều hơn một dịch vụ (instances) đang chạy trên các cổng khác nhau

  1. Spring Cloud Gateway sẽ ánh xạ giữa một tiền tố đường dẫn, ví dụ như /service02/ và một dịch vụ Service02. Nó sử dụng Eureka server để định tuyến dịch vụ được yêu cầu.
  2. Nó cân bằng tải (sử dụng Ribbon) giữa các phiên bản của dịch vụ đang chạy trên các cổng khác nhau.
  3. Chúng ta có thể lọc các yêu cầu( filter requests), thêm xác thực(authentication) và nhiều hơn nữa.

Tính năng của Spring Cloud Gateway:

  1. Xây dựng trên Spring Framework 5, Project Reactor và Spring Boot 2.0
  2. Có thể khớp các tuyến đường với bất kỳ thuộc tính yêu cầu nào.
  3. Các Predicates và Filters được chỉ định cho từng tuyến đường cụ thể.
  4. Tích hợp Circuit Breaker.
  5. Tích hợp DiscoveryClient của Spring Cloud.
  6. Dễ dàng viết Predicates và Filters.
  7. Giới hạn tốc độ yêu cầu (Request Rate Limiting).
  8. Chuyển đổi lại đường dẫn (Path Rewriting).

Chúng ta tiếp tục sử dụng Spring Initializr dể tạo một Project Spring Cloud Gateway mang tên là Service Gatewayl và thêm dependencies: Spring Cloud Gateway,Spring Security,Spring Boot DevTools,Eureka Discovery Client

Ta chọn và điền phần Project Metadata theo như cầu dự án của mình

Sau đó nhập vào để tạo project

Tiếp tục tạo thư mục mới tên là microservices-project và coppy thư mục vừa vào tạo và thêm config vào file pom.xml với nội dung




eureka-server


service01


service02


gateway-service

#<- Thêm vào đây

Tiếp tục trong file pom.xml trong project gateway-service thêm 1 dòng dependency




org.springframework.cloud


spring-cloud-starter-netflix-zuul




org.springframework.boot


spring-boot-starter-actuator


3.0.6




org.springframework.cloud


spring-cloud-starter-netflix-hystrix


2.2.10.RELEASE




io.jsonwebtoken


jjwt-api


0.11.1




io.jsonwebtoken


jjwt-impl


0.11.1


runtime




javax.annotation


javax.annotation-api


1.3.2


Spring Cloud Gateway cũng hoạt động như một Eureka client. Vì vậy, chúng ta đặt tên cho nó, cổng và liên kết đến Eureka Server (giống như chúng ta đã làm với Service01).


server: port: 8762 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true jwt: secret: BvPHGM8C0ia4uOuxxqPD5DTbWC9F9TWvPStp3pb7ARo0oK2mJ3pd3YG4lxA9i8bj6OTbadwezxgeEByY

Tiếp tục ta thêm

@EnableDiscoveryClient

trong Application


package com.duytran.gatewayservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class GatewayServiceApplication { public static void main(String[] args) { SpringApplication.run(GatewayServiceApplication.class, args); } }

Trong thư mục controller tạo FallbackController.


package com.duytran.gatewayservice.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FallbackController { @GetMapping("/fallback1") public String userFallback() { return "User service is not available"; } @GetMapping("/auth-fallback") public String authFallback() { return "Auth service is not available"; } }

Trong thư mục config tạo AuthenticationFilter , GatewayConfig, JwtUtil, RouterValidator,

AuthenticationFilter


@RefreshScope @Component public class AuthenticationFilter implements GatewayFilter { @Autowired private RouterValidator routerValidator; @Autowired private JwtUtil jwtUtil; @Override public Mono

filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); if (routerValidator.isSecured.test(request)) { if (this.isAuthMissing(request)) return this.onError(exchange, "Authorization header is missing in request", HttpStatus.UNAUTHORIZED); final String token = this.getAuthHeader(request); if (jwtUtil.isInvalid(token)) return this.onError(exchange, "Authorization header is invalid", HttpStatus.UNAUTHORIZED); this.populateRequestWithHeaders(exchange, token); } return chain.filter(exchange); } /*PRIVATE*/ private Mono

onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(httpStatus); return response.setComplete(); } private String getAuthHeader(ServerHttpRequest request) { return request.getHeaders().getOrEmpty("Authorization").get(0); } private boolean isAuthMissing(ServerHttpRequest request) { return !request.getHeaders().containsKey("Authorization"); } private void populateRequestWithHeaders(ServerWebExchange exchange, String token) { Claims claims = jwtUtil.getAllClaimsFromToken(token); exchange.getRequest().mutate() .header("id", String.valueOf(claims.get("id"))) .header("role", String.valueOf(claims.get("role"))) .build(); } }


Đây là một đoạn code để thực hiện xác thực JWT (JSON Web Token) trong Spring Cloud Gateway. Nó kiểm tra xem có yêu cầu được bảo mật hay không và xác minh tính hợp lệ của token JWT trong tiêu đề yêu cầu. Nếu token không hợp lệ hoặc thiếu, nó sẽ trả về lỗi UNAUTHORIZED (401) cho khách hàng. Nếu token hợp lệ, nó sẽ lấy thông tin được giải mã từ token và thêm chúng vào tiêu đề của yêu cầu để sử dụng cho các mục đích khác.

GatewayConfig


package com.duytran.gatewayservice.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableHystrix public class GatewayConfig { @Autowired AuthenticationFilter filter; @Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("user-service", r -> r.path("/users/**") .filters(f -> f.filter(filter)) .uri("lb://user-service")) .route("auth-service", r -> r.path("/auth/**") .filters(f -> f.filter(filter)) .uri("lb://auth-service")) .build(); } }

Đoạn code trên là cấu hình cho Gateway Service của Spring Cloud, nó khai báo một bean là routes là một RouteLocator, được tạo bằng cách sử dụng đối tượng RouteLocatorBuilder để xác định các routes cho Gateway. Ở đây, routes được cấu hình để định tuyến các yêu cầu gửi đến đường dẫn “/users/” đến service “user-service” và định tuyến các yêu cầu gửi đến đường dẫn “/auth/” đến service “auth-service”, và áp dụng AuthenticationFilter cho tất cả các routes này.

JwtUtil


package com.duytran.gatewayservice.config; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.security.Key; import java.util.Date; @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; private Key key; @PostConstruct public void init(){ this.key = Keys.hmacShaKeyFor(secret.getBytes()); } public Claims getAllClaimsFromToken(String token) { return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); } private boolean isTokenExpired(String token) { return this.getAllClaimsFromToken(token).getExpiration().before(new Date()); } public boolean isInvalid(String token) { return this.isTokenExpired(token); } }

Đoạn code trên là một lớp tiện ích (utility class) để xử lý mã thông báo JWT (JSON Web Token). Lớp này cung cấp các phương thức để trích xuất thông tin từ mã thông báo và kiểm tra tính hợp lệ của nó. Nó sử dụng thư viện JJWT để xử lý mã thông báo. Phương thức init() được gọi sau khi đối tượng được tạo ra để khởi tạo khóa sử dụng trong việc tạo và xác minh mã thông báo.

RouterValidator


package com.duytran.gatewayservice.config; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import java.util.List; import java.util.function.Predicate; @Component public class RouterValidator { public static final List

openApiEndpoints = List.of( "/auth/register", "/auth/login" ); public Predicate

isSecured = request -> openApiEndpoints .stream() .noneMatch(uri -> request.getURI().getPath().contains(uri)); }


Đoạn code trên có chức năng kiểm tra đường dẫn yêu cầu của một request, nếu đường dẫn đó không nằm trong danh sách các endpoint công khai (openApiEndpoints) thì request sẽ được coi là yêu cầu bảo mật và phải đi kèm với token xác thực. Chức năng này được sử dụng trong AuthenticationFilter của Spring Cloud Gateway để kiểm tra xem request có yêu cầu bảo mật hay không.

Config Service – Spring Cloud Config

Spring Cloud Config là một dịch vụ của Spring Cloud, cung cấp khả năng quản lý cấu hình trung tâm cho các ứng dụng phân tán. Nó cho phép các ứng dụng lấy cấu hình của chúng từ một vị trí tập trung thay vì phải lưu trữ cấu hình trực tiếp trong mã nguồn hoặc tệp tin. Các ứng dụng có thể truy cập cấu hình của chúng thông qua giao diện REST API, hoặc thông qua các thư viện khách được cung cấp bởi Spring Cloud Config. Sử dụng Spring Cloud Config, ta có thể dễ dàng quản lý và triển khai các ứng dụng phân tán một cách hiệu quả và an toàn hơn.

Các tính năng của Spring Cloud Config Server:

  • API dựa trên HTTP và tài nguyên cho cấu hình bên ngoài (các cặp tên-giá trị hoặc tương đương nội dung YAML).
  • Mã hóa và giải mã các giá trị thuộc tính (symmetric or asymmetric).
  • Có thể dễ dàng nhúng vào một ứng dụng Spring Boot bằng cách sử dụng

    @EnableConfigServer

    .

Các tính năng của Config Client (cho các ứng dụng Spring):

  • Kết nối đến Config Server và khởi tạo Spring Environment với các nguồn thuộc tính từ xa.
  • Mã hóa (Encrypt) và giải mã (decrypt) các giá trị thuộc tính (symmetric or asymmetric).

Chúng ta tiếp tục sử dụng Spring Initializr dể tạo một Project **Spring Cloud Config ** mang tên là Service Config và thêm dependencies: Config Server,Spring Boot DevTools,Eureka Discovery Client

Ta chọn và điền phần Project Metadata theo như cầu dự án của mình

Sau đó nhập vào để tạo project

Tiếp tục tạo thư mục mới tên là microservices-project và coppy thư mục vừa vào tạo và thêm config vào file pom.xml với nội dung




eureka-server


service01


service02


gateway-service


config-service

# <- Thêm ở đây

Tiếp tục thêm config vào tiệp application.yml


server: port: 9297 spring: application: name: config-server cloud: config: server: git: uri: https://github.com/tdduydev/demo-config-server.git clone-on-start: true

Tiếp tục tạo thêm một tiệp bootstrap.yml


server: port: 9297 spring: application: name: config-server cloud: config: server: git: uri: https://github.com/tdduydev/demo-config-server.git clone-on-start: true

Tiếp tục ta thêm

@EnableDiscoveryClient



@EnableConfigServer

trong Application


import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableDiscoveryClient @EnableConfigServer public class ConfigServiceApplication { public static void main(String[] args) { SpringApplication.run(ConfigServiceApplication.class, args); } }

Trong bài viết này, chúng ta đã tìm hiểu về các khái niệm và công nghệ liên quan đến thiết kế và triển khai hệ thống microservices. Chúng ta đã bắt đầu với một số khái niệm cơ bản như Eureka Server, một giải pháp để quản lý và phân phối các microservice. Sau đó, chúng ta đã tìm hiểu về Spring Cloud Gateway và Zuul, hai công nghệ được sử dụng để định tuyến và phân phối các yêu cầu đến các microservice.

Cuối cùng, chúng ta đã xem xét Spring Cloud Config, một công nghệ quản lý cấu hình tập trung cho các ứng dụng microservices. Với Spring Cloud Config, chúng ta có thể quản lý các cấu hình tập trung cho các ứng dụng và triển khai chúng đến các môi trường khác nhau với độ tin cậy cao.

Tóm lại, các công nghệ và giải pháp này đóng một vai trò quan trọng trong việc thiết kế và triển khai các hệ thống microservices hiệu quả và đáng tin cậy. Với kiến thức được tìm hiểu ở đây, chúng ta hy vọng bạn sẽ có thể bắt đầu xây dựng các hệ thống microservices của riêng mình một cách dễ dàng hơn.

All rights reserved

Spring Cloud là gì?

Spring Cloud cung cấp các công cụ dành cho các developers có thể nhanh chóng xây dựng những mẫu thiết kế phổ biến trong các hệ thống phân tán, ví dụ như quản lý cấu hình, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed session, cluster state). Điều phối các hệ thống phân tán dẫn đến các boiler plate patterns, và sử fungj Spring Cloud, các nhà phát triển có thể nhanh chóng dựng nên các services và ứng ựng mà hiện thực những patterns này. Chúng sẽ hoạt động tốt trong mọi môi trường phân tán, bao gồm cả máy tính của nhà phát triển đó, các trung tâm dữ liệ và các nền tảng như Cloud Foundry.

Spring Cloud xây dựng trên Spring Boot bằng việc cung cấp một tập các thư viện mà cải thiện hành vi của một ứng dụng khi thêm vào classpath. Bạn có thể tận dụng ưu điểm của hành vi mặc định để tạo một dự án quick start, và sau đó khi bạn cần, bạn có thể cấu hình hoặc mở rộng để tạo một custom solution.

Tính năng

Spring Cloud tập trung vào việc cung cấp trải nghiệm tốt cho các trường hợp điển hình và có cơ chế mở rộng cho các trường hợp khác.

  • Distributed/versioned configuration
  • Service registration and discovery
  • Routing
  • Service-to-service calls
  • Load balancing
  • Circuit Breakers
  • Global locks
  • Leadership election and cluster state
  • Distributed messaging

Spring Cloud có hướng tiếp cận kiểu Declarative, và bạn thường có nhiều tính năng với chỉ cần một classpath change hoặc một annotaion.

Main Projects

Spring Cloud Config

Centralized external configuration management backed by a git repository. The configuration resources map directly to Spring `Environment` but could be used by non-Spring applications if desired.

Spring Cloud Netflix

Integration with various Netflix OSS components (Eureka, Hystrix, Zuul, Archaius, etc.).

Spring Cloud Bus

An event bus for linking services and service instances together with distributed messaging. Useful for propagating state changes across a cluster (e.g. config change events).

Spring Cloud for Cloud Foundry

Integrates your application with Pivotal Cloud Foundry. Provides a service discovery implementation and also makes it easy to implement SSO and OAuth2 protected resources.

Spring Cloud Open Service Broker

Provides a starting point for building a service broker that implements the Open Service Broker API.

Spring Cloud Cluster

Leadership election and common stateful patterns with an abstraction and implementation for Zookeeper, Redis, Hazelcast, Consul.

Spring Cloud Consul

Service discovery and configuration management with Hashicorp Consul.

Spring Cloud Security

Provides support for load-balanced OAuth2 rest client and authentication header relays in a Zuul proxy.

Spring Cloud Sleuth

Distributed tracing for Spring Cloud applications, compatible with Zipkin, HTrace and log-based (e.g. ELK) tracing.

Spring Cloud Data Flow

A cloud-native orchestration service for composable microservice applications on modern runtimes. Easy-to-use DSL, drag-and-drop GUI, and REST-APIs together simplifies the overall orchestration of microservice based data pipelines.

Spring Cloud Stream

A lightweight event-driven microservices framework to quickly build applications that can connect to external systems. Simple declarative model to send and receive messages using Apache Kafka or RabbitMQ between Spring Boot apps.

Spring Cloud Stream App Starters

Spring Cloud Stream App Starters are Spring Boot based Spring Integration applications that provide integration with external systems.

Spring Cloud Task

A short-lived microservices framework to quickly build applications that perform finite amounts of data processing. Simple declarative for adding both functional and non-functional features to Spring Boot apps.

Spring Cloud Task App Starters

Spring Cloud Task App Starters are Spring Boot applications that may be any process including Spring Batch jobs that do not run forever, and they end/stop after a finite period of data processing.

Spring Cloud Zookeeper

Service discovery and configuration management with Apache Zookeeper.

Spring Cloud for Amazon Web Services

Easy integration with hosted Amazon Web Services. It offers a convenient way to interact with AWS provided services using well-known Spring idioms and APIs, such as the messaging or caching API. Developers can build their application around the hosted services without having to care about infrastructure or maintenance.

Spring Cloud Connectors

Makes it easy for PaaS applications in a variety of platforms to connect to backend services like databases and message brokers (the project formerly known as “Spring Cloud”).

Spring Cloud Starters

Spring Boot-style starter projects to ease dependency management for consumers of Spring Cloud. (Discontinued as a project and merged with the other projects after Angel.SR2.)

Spring Cloud CLI

Spring Boot CLI plugin for creating Spring Cloud component applications quickly in Groovy

Spring Cloud Contract

Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach.

Spring Cloud Gateway

Spring Cloud Gateway is an intelligent and programmable router based on Project Reactor.

Spring Cloud OpenFeign

Spring Cloud OpenFeign provides integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms.

Spring Cloud Pipelines

Spring Cloud Pipelines provides an opinionated deployment pipeline with steps to ensure that your application can be deployed in zero downtime fashion and easilly rolled back of something goes wrong.

Spring Cloud Function

Spring Cloud Function promotes the implementation of business logic via functions. It supports a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).

Release Trains

Spring Cloud is an umbrella project consisting of independent projects with, in principle, different release cadences. To manage the portfolio a BOM (Bill of Materials) is published with a curated set of dependencies on the individual project (see below). The release trains have names, not versions, to avoid confusion with the sub-projects. The names are an alphabetic sequence (so you can sort them chronologically) with names of London Tube stations (“Angel” is the first release, “Brixton” is the second). When point releases of the individual projects accumulate to a critical mass, or if there is a critical bug in one of them that needs to be available to everyone, the release train will push out “service releases” with names ending “.SRX”, where “X” is a number.


Microservices

là một giải pháp cho phép chia một hệ thống lớn thành một vài các component độc lập về phát triển, test và deploy.


Spring Cloud

là một dự án con trong họ nhà Spring, được sử dụng để phát triển các ứng dụng phân tán. Một ứng dụng được gọi là phần tán (Distributed application) khi các phần của nó có thể được phát triển trên các ngôn ngữ khác nhau và được triển khai trên các máy chủ khác nhau. Như vậy, Spring Cloud sinh ra là để làm các hệ thống microservice. Tất cả các dự sán Spring Cloud nên được tạo từ Spring Boot để giảm thiểu các cấu hình phức tạp và dễ cài đặt hơn.

Trong series này, chúng ta sẽ cùng tìm hiểu cách xây dựng một hệ thống microservice bằng Spring Boot và Eureka (một dự án trong Spring Cloud). Phần đầu tiên là tạo các microservice và gateway.

Tổng quan

Nhìn vào sơ đồ các thành phần của hệ thống ở trên, chúng ta cần tạo các service registry, image, gallery và một gateway. Gallery service sẽ sử dụng những bức ảnh lấy từ Image service và sắp xếp chúng thành một album ảnh.

Phiên bản Spring Boot mà chúng ta sẽ sử dụng trong serries này là

2.0.0.RELEASE

.


org.springframework.boot


spring-boot-starter-parent


2.0.0.RELEASE

Eureka Server

Đây là một máy chủ dùng để quản lý, đặt tên cho các service, hay còn gọi là

service registry

. Nhưng tại sao chúng ta lại cần một server để đặt tên cho mỗi service. Lý do:

  • Chúng ta không muốn hardcode địa chỉ IP của mỗi microservice. Bạn chẳng bao giờ dùng địa chỉ

    64.233.181.99

    để truy cập vào trang

    google.com

    , đúng chứ?
  • Khi mà các service của chúng ta sử dụng IP động, nó sẽ tự động cập nhật, chúng ta không cần thay đổi code.

Vậy là mỗi service sẽ được đăng ký với Eureka và sẽ ping cho Eureka để đảm bảo chúng vẫn hoạt động. Nếu Eureka server không nhận được bất kỳ thông báo nào từ service thì service đó sẽ bị gỡ khỏi Eureka một cách tự động.

Ok, để tạo Eureka server, chúng ta sẽ dùng Maven để quản lý các dependencies. Lưu ý khác với kiến trúc monolithic, mỗi component trong microservice được dựng một cách độc lập. Do đó chúng ta sẽ tạo mới một project Spring Boot và khai báo file

pom.xml

có các dependencies Web, Eureka Server và DevTools (tùy chọn):





org.springframework.boot


spring-boot-starter-web




org.springframework.cloud


spring-cloud-starter-netflix-eureka-server




org.springframework.boot


spring-boot-devtools


runtime




org.springframework.boot


spring-boot-starter-test


test



Tiếp theo, trong file

application.properties

, chúng ta cần cấu hình một số thứ như sau:


# Give a name to the eureka server spring.application.name=eureka-server # default port for eureka server server.port=8761 # eureka by default will register itself as a client. So, we need to set it to false. # What's a client server? See other microservices (image, gallery, auth, etc). eureka.client.register-with-eureka=false eureka.client.fetch-registry=false

Cuối cùng, trong class main của project, chúng ta sẽ khai báo đây là một Eureka server bằng annotation

@EnableEurekaServer

:


package io.github.tubean.eureka.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } }

Đơn giản thế thôi, đi tiếp đến những service về nghiệp vụ nào 😄

Image Service

Các Eureka client service là một service độc lập trong kiến trúc microservice. Mỗi client service chỉ thực hiện duy nhất một nghiệp vụ nào đó trong hệ thống như thanh toán, tài khoản, thông báo, xác thực, cấu hình,… Chúng ta sẽ xây dựng image service như một nguồn để chứa và cung cấp các bức ảnh, mỗi bức ảnh sẽ có id, title và địa chỉ url. Chỉ đơn giản như vậy thôi.

Ok, cũng như Eureka Server, chúng ta sẽ tạo một project Spring Boot mới nhưng sử dụng Eureka Client trong file

pom.xml

:





org.springframework.boot


spring-boot-starter-web




org.springframework.cloud


spring-cloud-starter-netflix-eureka-client




org.springframework.boot


spring-boot-starter-data-rest




org.springframework.boot


spring-boot-devtools


runtime




org.springframework.boot


spring-boot-starter-test


test



Trong file

appication.properties

chúng ta sẽ ghi lại địa chỉ của Eureka server:


# serivce name spring.application.name=image-service # port server.port=8200 # eureka server url eureka.client.service-url.default-zone=http://localhost:8761/eureka

Sau đó để chỉ cho Spring Boot biết đây là một Eureka client, chúng ta dùng annotation

@EnableEurekaClient

trong class main:


package io.github.tubean.eureka.image; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ImageApplication { public static void main(String[] args) { SpringApplication.run(ImageApplication.class, args); } }

Bây giờ để image service có thể expose data ra ngoài, chúng ta cần có các endpoint đúng không? Tương tự một RESTful web service, chúng ta sẽ tạo một entity định nghĩa cấu trúc chuỗi JSON và một controller điều hướng:

  • Image.java


package io.github.tubean.eureka.image.entity; public class Image { private Integer id; private String title; private String url; public Image(Integer id, String title, String url) { this.id = id; this.title = title; this.url = url; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }

  • HomeController.java


package io.github.tubean.eureka.image.controller; import io.github.tubean.eureka.image.entity.Image; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; import java.util.List; @RestController @RequestMapping("/") public class HomeController { @Autowired private Environment env; @RequestMapping("/") public String home() { // This is useful for debugging // When having multiple instance of image service running at different ports. // We load balance among them, and display which instance received the request. return "Hello from Image Service running at port: " + env.getProperty("local.server.port"); } @RequestMapping("/images") public List getImages() { List images = Arrays.asList( new Image(1, "Treehouse of Horror V", "https://www.imdb.com/title/tt0096697/mediaviewer/rm3842005760"), new Image(2, "The Town", "https://www.imdb.com/title/tt0096697/mediaviewer/rm3698134272"), new Image(3, "The Last Traction Hero", "https://www.imdb.com/title/tt0096697/mediaviewer/rm1445594112")); return images; } }

Gallery Service

Các Eureka client service có thể là một REST client dùng để cung cấp data cho một service khác (REST API service). Do đó, trong hệ thống của chúng ta, gallery service sẽ gọi đến image service thông qua các endpoint mà chúng ta đã tạo ra ở trên, và từ đó sẽ get ra một list ảnh để tạo ra một album. Để gọi đến một service từ một REST client, chúng ta có thể sử dụng:


  1. RestTemplate

    : Đây là một object cho phép gửi request đến một REST API service.

  2. FeignClient

    : hoạt động như một proxy, cung cấp các giải pháp khác cho RestTemplate.

Và cả 2 cách thì cân bằng tải đều có thể áp dụng.

Cân bằng tải (Load balancing) là gì? Nếu như có nhiều hơn một instance của một service chạy trên các port khác nhau thì chúng ta cần cân bằng những request giữa tất cả các instance đó. Trong điều kiện lý tưởng thì cân bằng tải sẽ giúp các port nhận số lượng request tương đương nhau.

Tương tự Image service, chúng ta khai báo file

pom.xml

cho Gallery service. Và trong

application.properties

, port sử dụng sẽ khác với Image service:


spring.application.name=gallery-service server.port=8100 eureka.client.service-url.default-zone=http://localhost:8761/eureka

Trong class main, bên cạnh annotation

@EnableEurekaClient

, chúng ta sẽ cần tạo thêm một bean cho

RestTemplate

dùng để gọi đến image service.


package io.github.tubean.eureka.gallery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient public class GalleryServiceApplication { public static void main(String[] args) { SpringApplication.run(GalleryServiceApplication.class, args); } } @Configuration class RestTemplateConfig { // Create a bean for restTemplate to call services @Bean @LoadBalanced // Load balance between service instances running at different ports. public RestTemplate restTemplate() { return new RestTemplate(); } }

Đừng quên entity và controller:

  • Gallery.java


package io.github.tubean.eureka.gallery.entity; import java.util.List; public class Gallery { private Integer id; private List
images; public Gallery(Integer id, List
images) { this.id = id; this.images = images; } public Gallery() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public List
getImages() { return images; } public void setImages(List
images) { this.images = images; } }

  • HomeController.java


package io.github.tubean.eureka.gallery.controller; import io.github.tubean.eureka.gallery.entity.Gallery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController @RequestMapping("/") public class HomeController { @Autowired private RestTemplate restTemplate; @Autowired private Environment env; @RequestMapping("/") public String home() { // This is useful for debugging // When having multiple instance of gallery service running at different ports. // We load balance among them, and display which instance received the request. return "Hello from Gallery Service running at port: " + env.getProperty("local.server.port"); } @RequestMapping("/{id}") public Gallery getGallery(@PathVariable final int id) { // create gallery object Gallery gallery = new Gallery(); gallery.setId(id); // get list of available images List
images = restTemplate.getForObject("http://image-service/images/", List.class); gallery.setImages(images); return gallery; } // -------- Admin Area -------- // This method should only be accessed by users with role of 'admin' // We'll add the logic of role based auth later @RequestMapping("/admin") public String homeAdmin() { return "This is the admin area of Gallery service running at port: " + env.getProperty("local.server.port"); } }

Ok, đến đây chúng ta cần chú ý khi sử dụng

restTemplate

thì trong Eureka Server đã đặt tên cho các service nên chúng ta sẽ sử dụng tên của chúng (

image-service

thay vì

localhost:port

) nhằm mục đích sử dụng cân bằng tải.

Gateway – Zuul

Khi chúng ta gọi đến bất kỳ service nào từ browser, chúng ta không thể gọi trực tiếp bằng tên của chúng như ở trên Gallery server đã làm bởi vì những tên service như vậy phải được bí mật và chỉ sử dụng trong nội bộ các service với nhau.

Nếu chúng ta có nhiều instance của một service, mỗi instance lại sử dụng một port khác nhau. Vậy làm thế nào chúng ta có thể gọi tất cả các service từ browser và phân tán những request đến các instance đó thông qua các cổng khác nhau? Câu trả lời là sử dụng một

Gateway

.

Một gateway là một entry point đơn trong hệ thống, được dùng để handle các request bằng cách định tuyến chúng đến các service tương ứng. Nó cũng có thể được dùng để xác thực, giám sát và làm nhiều việc khác.

So sánh Zuul vs Spring Cloud Gateway

Trước khi đi vào so sánh, chúng ta hãy xem qua hai thế hệ của Gateway (hình trái và phải)

Thế hệ đầu Blocking IO: Zuul1

Về lịch sử Zuul1 được build trên Servlet framework, sử dụng blocking và multi-threading. Nghĩa là một luồng xử lý một yêu cầu kết nối. Điều này làm tăng số lượng connection còn tồn tại khi có độ trễ và fail dẫn đến tăng luồng xử lý và đó cũng là điểm khác nhau giữa Zuul1 và Zuul2 khi Zuul 2 đã sử dụng mô hình asynchronous và non-blocking framworks. Mỗi thread trên CPU core xử lý tất cả request và response. Vòng đời của request, response được xử lý thông qua events và callback, điều này cho thấy giảm đi số luồng xử lý. Những thay đổi này đã cải thiện được đáng kể về performance

Thế hệ sau Non Blocking IO: Zuul2, Spring Cloud Gateway

Netflix dù đã cho ra mắt bản Zuul 2.x nhưng Spring Cloud dường như không có kế hoạch tích hợp. Bản mới nhất của Spring vẫn tích hợp Zuul 1.x. Spring Cloud đã tự xây dựng cổng API Gateway riêng là Spring Cloud Gateway được cho là đơn giản hơn Zuul, cấu hình thuận tiện hơn

Java Interview Prep -  Spring boot and Microservices interview questions for experienced | Live Mock
Java Interview Prep – Spring boot and Microservices interview questions for experienced | Live Mock

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

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é

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

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!

Microservices là gì? Hiểu Microservices trong 12 phút !!!
Microservices là gì? Hiểu Microservices trong 12 phút !!!

Kết luận

Qua bài viết trên chúng ta đã biết sức mạnh của API Gateway khi áp dụng vào kiến trúc mircoservices. Mọi người có thể tham khảo code tại đây. Vậy khi áp dụng API Gateway, hệ thống sẽ có ưu nhược điểm thế nào ?

Ưu điểm:

  • Vì không phải tracking nhiều endpoints, tất cả chỉ việc gọi đến api gateway nên phần code frontend sẽ gọn gàng hơn so với việc tracking hàng trăm endpoints trên từng service một, nhất là khi tương lai sẽ càng phình to
  • Thay thế authentication services trên từng service, việc đó chuyển sang API Gateway đảm nhiệm
  • Che dấu được cấu trúc bên trong của hệ thống microservice so với bên ngoài. Clients sẽ tương tác với hệ thống thông qua api gateway chứ không gọi trực tiếp tới một service cụ thể, Các endpoints của các service sẽ chỉ được gọi nội bộ (các serivce gọi với nhau hoặc từ api gateway). Điều này khiến client không cần biết được các service backend được phân chia như thế nào

Nhược điểm:

  • Tăng latency vì phải đi qua trung gian
  • Tăng khả năng lỗi cao hơn do để sử dung api gateway thì chúng ta cần phải config riêng, chỉnh sửa code, quản lý server gateway,… là điểm bottleneck của hệ thống, chẳng may gateway có lỗi thì request sẽ không thể tới được phía server

Kiến trúc Micro Service được sử dụng rộng rãi trong các Project Java Web hiện nay. Bản chất của Kiến trúc Micro Service là “Chia để trị”. Tức là Project Java Web lớn có thể chia thành nhiều Project Java Web nhỏ để có thể dễ dàng quản lý thời gian cũng như lỗi hay việc quản lý Member tài nguyên trong dự án. Mỗi Project Java web nhỏ được gọi là Micro Service và thường sử dụng Spring Boot.

Kiến trúc Micro Service – Spring Cloud Framework

Spring Boot là một bản nâng cấp hơn của Spring MVC. Kết hợp với mô hình Micro service, chúng ta sử dụng Spring Cloud Framwork. Đó là Framework đầu tiên về Java hỗ trợ hoàn chỉnh kiến trúc Micro service này. Mọi thứ trong việc cấu hình sẽ trở nên đơn giản và dễ dàng sử dụng. Chúng ta không cần cài thêm phần mềm nào. Tất cả mọi thứ đều được Spring Cloud Frame work hỗ trợ chúng ta kết nối mọi thứ với nhau. Chúng ta chỉ cần tập trung vào code và phân chia Project cho các đơn vị Outsourches khác nhau. Như vậy, Spring hỗ trợ chúng ta rất nhiều trong Java Web làm hệ thống. Theo kiến trúc Micro Service, thường Java được sử dụng viết Core Service, còn Angular được sử dụng để viết Finance tức là website kết hợp Android và IOS để tạo nên 1 hệ thống hoàn chỉnh.

Chi tiết bài học đã được Giảng viên hướng dẫn chi tiết qua video trên Youtube Trung tâm Java

Link full >> Tại đây

Hãy liên hệ với chúng tôi để có thể biết thêm thông tin chi tiết.

Số điện thoại liên lạc: 0986 983 766.

Xem thêm chi tiết các khóa học >> trung tâm Java Master

Trung tâm Java Master sẽ luôn đồng hành cùng thành công của bạn.

Neflix Zuul

4.1 Giới thiệu

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 còn wrap nhiều thứ 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.

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 đang available. 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 Zuul để kiểm tra 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

Spring Cloud Netflix cung cấp nần tảng tích hợp Netflix OSS (Open Source Software). Với một vài annotation chúng ta có thể nhanh chóng kích hoạt và cấu hình các mẫu phổ biến bên trong ứng dụng của mình và xây dựng các hệ thống phân tán lớn với các thành phần Netflix đã được thử nghiệm. Sẽ dễ dàng tích hợp được với những tính năng của thư viện: Service Discovery (Eureka), Circuit Breaker(Hystrix), Client Side Load Balancer (Ribbon), External Configuration

Zuul là một định tuyến dựa trên JVM và bộ cân bằng tải phía máy của từ Neflix,là một proxy, gateway và là một lớp trung gian giữa user và các service. Eureka server đã giải quyết vấn đề đặt tên cho từng service thay vì dùng địa chỉ IP của chúng. Tuy nhiên một service vẫn có thể có nhiều instance và sẽ chạy trên các cổng khác nhau nên nhiệm vụ của Zuul sẽ map giữa một prefix path (/gallery/**) và một service (gallery-service). Nó sử dụng Euraka server để định tuyến các service được request. Nó giúp cân bằng tải giữa các instance của một service

Zuul có thể sử dụng các loại filter khác nhau để chúng ta có thể apply vào hệ thống 1 cách nhanh chóng, đây là những tính năng được liệt kê

  • Authentication and Security: xác định các yêu cầu xác thực cho từng tài nguyên và từ chối các yêu cầu không đáp ứng chúng.
  • Monitoring: tracking đượcc data và thống kê được có bao nhiêu request pass qua đến service backend
  • Dynamic Routing: routing requests đến các service backend khác nhau
  • Static Response handling: Xử lý phản hồi tĩnh – xây dựng một số phản hồi trực tiếp ở gateway thay vì chuyển tiếp chúng đến một cụm backend nội bộ

4.2 Cách hoạt động

Zuul 2.0 là Netty server sẽ chạy từ pre-filters(inbound filters), sau đó proxies request đến những Netty client và cuối cùng là trả response sau khi run post filters(outbound filter)

Filter chính là core business logic của Zuul. Vì chúng có thể thực hiện mọi hoạt động và chạy từng phần khác nhau trong vòng đời của request và response

  • Inboud Filters excute trước khi route đến origin, đc sử dụng như authen, routing, decorating request
  • Endpoint Filters được sử dụng để trả static response hoặc không thì sẽ kết hợp với ProxyEndpoint để route request đến origin. Sẽ xử lý request dựa theo excute của incoming filter. Zuul đi kèm với một bộ lọc tích hợp ProxyEndpoint để proxy request đến backend server.
  • Outbound Filters excute sau khi nhận response từ origin và để collect metric và decorate reponse hoặc add custom header. Thường ở đây sẽ làm những thứ như: định hình reponse lại hoặc add metric chứ không làm gì nhiều: storing statistics, adding/stripping standard headers, sending events to real-time streams.

Filter của Zuul có 5 yếu tố:

  • Type: Được xác định là tên của việc routing flow khi filter này apply vào (any custom string)
  • Async: sync hoặc async. xác định là cuộc gọi ngoài hay nội bộ
  • Execution Order: đi theo type xác định thứ tự excute khi multiple filter
  • Criteria: điều kiện cụ thể để filter đượcc excute
  • Action: là hành động excute khi critera thõa

Zuul cung cấp framework để đọc dynamically, compile, run filter. Các filter sẽ không tự trực tiếp giao tiếp với nhau mà sẽ chia sẻ state trạng thái thông qua request context là duy nhất với mỗi request

public class ResponseLogFilter extends ZuulFilter { private Logger logger = LoggerFactory.getLogger(ResponseLogFilter.class); @Override public String filterType() { return POST_TYPE; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } }

Lưu ý: Giá trị trong method filterType() rất quan trọng. Nó sẽ có ý nghĩa hoàn toàn khác với chính filter đó nhưng khác filterType().

shoudFilter() => return true khi chúng ta muốn filter này này chạy trong chuỗi filter nên để ở config bên ngoài để flexible hơn. Khi chúng ta xác định được instance RequestContext từ đó mới có thể lấy được response data input stream. Ở đây có thể bị NULL do service bị timeout

Microservices Là Gì
Microservices Là Gì

Giới thiệu API Gateway

Với mô hình kinh điển của mircoservice:

Với mô hình trên chúng ta có thể hình dung mỗi một service sẽ đi kèm với một Security, lẫn Logging được quản lý theo version và để quản lý các flow như trên chắc hẳn chúng ta sẽ cần ít nhất một người am hiểu về hệ thống và phát triển sau này. Điều này làm cho việc quản trị sẽ bị phụ thuộc. Chắc hẳn mọi người ở đây đều biết đến khái niệm Facade Pattern, là một design pattern của thuộc Structural Pattern và API Gateway có khái niệm gần giống khái niệm Facade Pattern. Nó đóng vai trò là một nơi trung gian, là một cổng vào duy nhất đến hệ thống microservice. API Gateway sẽ đóng gói hệ thống nội bộ và cung cấp các API được thiết kế riêng cho từng client

Ý tưởng API Gateway rất hay nhưng lại đơn giản, nó sẽ lo việc điều hướng các request đến service mong muốn. Nhiệm vụ chính là xác thực (authentication), điều hướng yêu cầu (routing request), giám sát (monitoring), cân bằng tải (load balancing) và xử lý phản hỗi tĩnh (static response handling).

Trong thực tế với Netflix cổng API Gateway của họ một ngày phải xử lý đến hàng tỷ request, với mô hình trên chỉ là khái quát cách hoạt động của API Gateway, nhưng với Netflix họ phải định nghĩa lại API Gateway vì khác hàng của Netflix sử dụng rất nhiều các thiệt bị truy cập khác nhau vì thế API one-size-fill-alls (đa nền tảng) không đáp ứng được nhu cầu. Ngoài Netflix sử dụng chính API Gateway họ xây dựng là Netflix Zuul, chúng ta còn có một số công nghệ/framework để sử dụng mô hình API Gateway là: NginxPlus, AWS API Gateway, Kong, Spring Cloud Gateway, …

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.

CII tăng mạnh ngày khai xuân. Chờ đợi điều gì từ CII ?
CII tăng mạnh ngày khai xuân. Chờ đợi điều gì từ CII ?

Web App

Bước cuối cùng, tôi sẽ tạo một Spring Boot Web app sử dụng Thymeleaf để render HTML sau khi lấy dữ liệu từ REST server “shop”. Nếu không có Eureka server, tôi cần gán cứng cho REST server “shop” một địa chỉ IP tĩnh, rồi từ dịch vụ khác dùng địa chỉ IP này gọi vào.

Cách này không hay ở chỗ: dải IP tĩnh không còn nhiều, nếu số lượng dịch vụ tăng nhanh thì sẽ rất tốn địa chỉ IP tĩnh cấp phát. Việc ghi nhớ dịch vụ nào nằm ở IP nào cũng không phù hợp với hệ thống lớn, phức tạp. Do đó, tôi tiếp tục biến Web App thành Eureka client. Khi nó khởi động sẽ đăng ký địa chỉ IP, các thông tin cần thiết với Eureka và nhận về danh sách các dịch vụ khác.

. ├── main │ ├── java │ │ └── vn │ │ └── techmaster │ │ └── web │ │ ├── controller │ │ │ ├── APIController.java │ │ │ └── WebController.java <– Controller render web │ │ ├── feign │ │ │ └── ShopClient.java <– OpenFeign interface định nghĩa kết nối đến REST │ │ ├── model │ │ │ └── Product.java │ │ └── WebApplication.java <– Thêm annotation @EnableFeignClients │ └── resources │ ├── static │ │ └── diagram.jpg │ ├── templates │ │ └── products.html <– File view template │ ├── application.properties <– cấu hình Actuator │ └── application.yml <– cấu hình Eureka client

Ứng dụng này cũng là Eureka client, nên file cấu hình application.yml cũng tương tự như dịch vụ REST. Điểm khác biệt là nó sẽ gọi sang REST server “shop” để lấy dự liệu. Do đó tôi tạo và dùng Open Feign client bằng 3 bước:

Bước 1: trong file pom.xml nhớ bổ xung dependency



org.springframework.cloud


spring-cloud-starter-openfeign

Bước 2: định nghĩa

public interface ShopClient

rồi đánh dấu nó bằng

@FeignClient("shop")

package vn.techmaster.web.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import vn.techmaster.web.model.Product; import java.util.List; (“shop”) public interface ShopClient { (“/products”) public List getProducts(); }

Bước 3: Sử dụng Open Feign client trong WebController.java

public class WebController { private ShopClient shopClient; (“/”) public String showProducts(Model model) { List products = shopClient.getProducts(); model.addAttribute(“products”, products); return “products.html”; } }

Khi chạy dịch vụ web này xong, rồi quay lại http://localhost:8761 sẽ thấy application “WEB” được bổ xung vào danh sách đăng ký.

Vào địa chỉ http://localhost:8080 sẽ thấy dữ liệu đã được xuất ra HTML

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:

  • Building Microservices Application – Phần mở đầu: Bức tranh tổng thể
  • Phát triển phần mềm theo kiến trúc microservice
  • Các kĩ sư Eureka đã tối ưu ứng dụng chat sử dụng gRPC như thế nào

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

Trong microservice, bên cạnh API Gateway pattern rất phổ biến, còn có Service Discovery (khám phá dịch vụ). Service Discovery cũng tương tự như DNS (Domain Name Service). Thay vì phải sử dụng địa chỉ IP khó nhớ hoặc có thể biến động, các client, thiết bị, dịch vụ sẽ tìm thấy nhau bằng tên dễ nhớ và có một dịch vụ chung để chuyển tên dễ nhớ thành địa chỉ IP. Spring Cloud có thư viện Eureka Service Discovery để giúp các dịch vụ REST, Web đăng ký với nó sau đó giúp các dịch vụ này tìm kiếm nhau, kết nối với nhau đơn giản hơn. Eureka là thư viện do Netflix viết từ đầu, sau đó được team Spring thuộc Pivotal và cộng đồng tham gia phát triển tiếp. Mã nguồn minh hoạ cho bài viết này ở đây

Kubernetes vs Docker: Hiểu trước sau đó là cách triển khai hoạt động giữa thực tế và microservices
Kubernetes vs Docker: Hiểu trước sau đó là cách triển khai hoạt động giữa thực tế và microservices

Keywords searched by users: spring cloud la gi

Giới Thiệu Về Spring Boot. Spring Boot Là Gì? | Topdev
Giới Thiệu Về Spring Boot. Spring Boot Là Gì? | Topdev
Spring Cloud Service Discovery Với Eureka
Spring Cloud Service Discovery Với Eureka
Tìm Hiểu Về Spring Cloud Config Server Với Ví Dụ | Openplanning.Net
Tìm Hiểu Về Spring Cloud Config Server Với Ví Dụ | Openplanning.Net
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Build Api Gateway With Spring Cloud Gateway And Consul
Build Api Gateway With Spring Cloud Gateway And Consul
Để Học Spring Boot Cần Bắt Đầu Từ Đâu?
Để Học Spring Boot Cần Bắt Đầu Từ Đâu?
Spring Security Là Gì? Cơ Chế Hoạt Động Của Spring Security
Spring Security Là Gì? Cơ Chế Hoạt Động Của Spring Security
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Spring Boot Và Những Điều Cần Biết
Spring Boot Và Những Điều Cần Biết
Spring Là Gì? Lợi Ích Mà Spring Mang Lại Cho Người Dùng
Spring Là Gì? Lợi Ích Mà Spring Mang Lại Cho Người Dùng
Khám Phá Spring Là Gì? Nền Tảng Quan Trọng Của Ứng Dụng Java -  Fptshop.Com.Vn
Khám Phá Spring Là Gì? Nền Tảng Quan Trọng Của Ứng Dụng Java – Fptshop.Com.Vn
Bean Và Applicationcontext Là Gì Trong Spring Boot?
Bean Và Applicationcontext Là Gì Trong Spring Boot?
Jdk 21 Có Gì Những Cập Nhật Gì Mới ? Lịch Ra Mắt - Idc Online
Jdk 21 Có Gì Những Cập Nhật Gì Mới ? Lịch Ra Mắt – Idc Online
Khóa Học Microservice Với Spring Webflux & Apache Kafka | Udemy
Khóa Học Microservice Với Spring Webflux & Apache Kafka | Udemy
Spring Cloud Service Discovery Với Eureka
Spring Cloud Service Discovery Với Eureka
Spring Boot Starters Là Gì? - Cơ Chế Của Spring Boot - Stackjava
Spring Boot Starters Là Gì? – Cơ Chế Của Spring Boot – Stackjava
Api Gateway, Spring Cloud Gateway & Zuul 2
Api Gateway, Spring Cloud Gateway & Zuul 2
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Spring Boot Là Gì? Kiến Thức Cần Biết Khi Học Spring Boot
Kafka 00 - Giới Thiệu Khóa Học Spring Boot Và Kafka | Jmaster.Io - Youtube
Kafka 00 – Giới Thiệu Khóa Học Spring Boot Và Kafka | Jmaster.Io – Youtube
Luồng Đi Trong Spring Boot
Luồng Đi Trong Spring Boot
Học Spring Boot Spring Framework Cơ Bản Miễn Phí
Học Spring Boot Spring Framework Cơ Bản Miễn Phí
Thực Chiến Microservice Với Spring Boot Và Event Sourcing | Udemy
Thực Chiến Microservice Với Spring Boot Và Event Sourcing | Udemy
Kiến Trúc Micro Service - Spring Cloud Framework - Youtube
Kiến Trúc Micro Service – Spring Cloud Framework – Youtube
Infrastructure As Code Là Gì? Một Số Lợi Ích Infrastructure As Code Mang Lại
Infrastructure As Code Là Gì? Một Số Lợi Ích Infrastructure As Code Mang Lại
Spring Framework Là Gì ? Học Lập Trình Java Spring Framework
Spring Framework Là Gì ? Học Lập Trình Java Spring Framework
Building Microservices Application – Phần Mở Đầu: Bức Tranh Tổng Thể –  Craftsmanship
Building Microservices Application – Phần Mở Đầu: Bức Tranh Tổng Thể – Craftsmanship
Spring Security Là Gì? Cơ Chế Hoạt Động Của Spring Security
Spring Security Là Gì? Cơ Chế Hoạt Động Của Spring Security
Spring Boot Là Gì? Bạn Cần Biết Những Gì Khi Học Spring Boot
Spring Boot Là Gì? Bạn Cần Biết Những Gì Khi Học Spring Boot
Khám Phá Spring Là Gì? Nền Tảng Quan Trọng Của Ứng Dụng Java -  Fptshop.Com.Vn
Khám Phá Spring Là Gì? Nền Tảng Quan Trọng Của Ứng Dụng Java – Fptshop.Com.Vn
Microservices With Spring Cloud | Jmaster.Io
Microservices With Spring Cloud | Jmaster.Io
Yaml File Là Gì? Đọc File Yaml/Yml Với Spring Boot - Stackjava
Yaml File Là Gì? Đọc File Yaml/Yml Với Spring Boot – Stackjava
Building Microservices Application - Phần 1: Sử Dụng Netflix Eureka, Ribbon  Và Zuul | Topdev
Building Microservices Application – Phần 1: Sử Dụng Netflix Eureka, Ribbon Và Zuul | Topdev
Truy Tìm Dịch Vụ Trong Một Kiến Trúc Microservices
Truy Tìm Dịch Vụ Trong Một Kiến Trúc Microservices
Java Spring Boot Là Gì ? Java Spring Mvc Là Gì ? Spring Framework Là Gì ?
Java Spring Boot Là Gì ? Java Spring Mvc Là Gì ? Spring Framework Là Gì ?

See more here: kientrucannam.vn

Leave a Reply

Your email address will not be published. Required fields are marked *