Thứ Hai, 14 tháng 8, 2023

Cấu hình để cài đặt cuốn chiếu zero downtime (ZDD) với Netflix Eureka, Zuul, Ribbon ở tình trạng sẵn dùng được (High Availability)

Về mặt lý thuyết


Ta cần chú ý đến 3 cache ở các thành phần sau : 1 ở gateway Zuul - đóng vai cổng vào để nhận các truy vấn đến; 1 ở load balancer Ribbon - đóng vai trò tác nhân cân bằng tải để điều hướng các truy vấn đến những dịch vụ web trong hệ thống; 1 của service discovery Eureka - dịch vụ chủ Eureka lưu dữ và cập nhật danh sách các dịch vụ web có trong hệ thống bao gồm các microservices. Mặc định mỗi cache của từng thành phần này sẽ tự cập nhật mỗi 30 giây. Vậy nên phải chờ khoảng 30+30+30 = 90 giây để tất cả các cache được cập nhật ở mọi lớp này.

Ta xét trường hợp một hệ thống HA (high availability) gồm hai replicas - mỗi một replica bao gồm một tập hợp hoàn chỉnh các dịch vụ web cho phép hệ thống hoạt động bình thường. Trong trường hợp này ta có thể tiến hành việc cài đặt như sau : 

- Hủy đăng ký của tất cả các dịch vụ web trong instance đầu tiên của Eureka server (dùng enpoint pause của actuator hoặc Eureka API PUT OUT_OF_SERVICE)
- Đợi 90 giây.
- Dừng tất cả các service, rồi cài đặt lại chúng cho instance thứ nhất này.
- Đợi 90 giây.
- Hủy đăng ký của tất cả các dịch vụ web trong instance thứ hai của Eureka server (dùng enpoint pause của actuator hoặc Eureka API PUT OUT_OF_SERVICE)
- Đợi 90 giây.
- Dừng tất cả các service, rồi cài đặt lại chúng cho instance thứ hai này.
- sau khoảng 90 giây, các dịch vụ web của instance thứ hai sẽ hoạt động trở lại.

Ngoài ra, cần phải cài đặt retry cho gateway để tránh trường hợp một dịch vụ web có vấn đề thì truy vấn vẫn sẽ được thực hiện trong một dịch web tương đương khác có sẵn. 


Cài đặt


1. Cấu hình để mở các endpoints actuator /pause và /shutdown

Trong tập tin application.yml

management:
endpoint:
pause:
enabled: true
restart:
enabled: true
resume:
enabled: true
shutdown:
enabled: true

Ví dụ dùng các endpoints này như sau :

$ curl -X POST http://localhost:1234/actuator/pause
$ curl -X POST http://localhost:1234/actuator/shutdown

2. Cài đặt retry

Trong tập tin pom.xml thêm Spring Retry vào dự án như sau :


        <!-- enable retry for non-reactive version (load-balanced RestTemplate) -->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

 Trong tập tin cấu hình application.xml của zuul, ta cần kích hoạt loadbalancer và retry như sau :

spring:
  cloud:
    # enable retry for reactive version (with WebClient)
    loadbalancer:
      retry:
        enabled: true
      ribbon:
        enabled: true

zuul:
  retryable: true

ribbon:
  OkToRetryOnAllOperations: true
  MaxAutoRetries: 3
  MaxAutoRetriesNextServer: 3
  # 500 (Internal Server Error), 503 (Service Unavailable), 408 (Request Timeout)
  retryableStatusCodes: 500, 503, 408

 

 Trong các tập tin cấu hình application.xml của các services, ta cần cấu hình cho retry như sau :

ribbon:
  OkToRetryOnAllOperations: true
  MaxAutoRetries: 3
  MaxAutoRetriesNextServer: 3
  # 500 (Internal Server Error), 503 (Service Unavailable), 408 (Request Timeout)
  retryableStatusCodes: 500, 503, 408

 

Xem thêm tại đây

https://openspacevn.blogspot.com/2023/07/cau-hinh-e-dung-auto-retry-cho-spring.html


3. Cài đặt cho các instance của HA

a. Cài đặt chung cho các instance trong tập tin application.xml

eureka:
instance:
prefer-ip-address: true
# Indicates the interval of heartbeats that the client sends to the server, in seconds (The default value is 30 seconds)
lease-renewal-interval-in-seconds: 1
# The time in seconds that the Eureka server waits since it received the last heartbeat from a client before it can remove that client from its registry (the default value is 90 seconds)
lease-expiration-duration-in-seconds: 1
client:
fetch-registry: true
register-with-eureka: true
healthcheck:
enabled: true
server:
# This property tells the Eureka server to run a job at this frequency to evict the expired clients. (the default value is 60 seconds)
eviction-interval-timer-in-ms: 1000
enableSelfPreservation: false



ribbon:
# in second
NFLoadBalancerPingInterval: 1
# in millisecond
ServerListRefreshInterval: 1000


server:
shutdown: graceful

spring:
lifecycle:
timeout-per-shutdown-phase: 2m


b. Cài đặt cho instance 1 trong tập tin application_ha_1.xml

eureka:
client:
service-url:
defaultZone: http://${app1.address.ip}:8761/eureka/,http://${app2.address.ip}:8761/eureka/
preferSameZoneEureka: true
transport:
applicationsResolverUseIp: true
instance:
metadata-map:
zone: zone1



c. Cài đặt cho instance 2 trong tập tin application_ha_2.xml


eureka:
client:
service-url:
defaultZone: http://${app2.address.ip}:8761/eureka/,http://${app1.address.ip}:8761/eureka/
preferSameZoneEureka: true
transport:
applicationsResolverUseIp: true
instance:
metadata-map:
zone: zone2


d. Cấu hình cho từng server Eureka ở HA


eureka:
client:
fetch-registry: true
register-with-eureka: true


e. Dùng Eureka API để đặt dịch vụ web ở chế độ OUT_OF_SERVICE

Cú pháp :

PUT /eureka/apps/appId/instanceId/status?value=OUT_OF_SERVICE



Ví dụ :

curl -X PUT 
http://localhost:8761/eureka/apps/DEMO-SERVICE/demo-service:f42adf31bb76e181988fc292a1344be9/status?value=OUT_OF_SERVICE


Tham khảo


Ngoài ra có thể tham khảo thêm các properties trong class org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean

(chẳng hạn như : peerEurekaNodesUpdateIntervalMs, peerEurekaStatusRefreshTimeIntervalMs ...)


Các đường dẫn tham khảo :


https://www.credera.com/insights/zero-downtime-rolling-deployments-netflixs-eureka-zuul

https://cloud.spring.io/spring-cloud-netflix/2.0.x/multi/multi__service_discovery_eureka_clients.html

https://github.com/spring-cloud/spring-cloud-netflix/issues/1571

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#graceful-shutdown

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.profile-specific