Skip to content

18.3.3 Làm việc với liveness và readiness của ứng dụng

Như chúng ta đã thấy trong chương 15, endpoint health của Actuator cung cấp trạng thái sức khỏe của một ứng dụng. Tuy nhiên, trạng thái này chỉ phản ánh sức khỏe của các phụ thuộc bên ngoài mà ứng dụng dựa vào, chẳng hạn như cơ sở dữ liệu hoặc hệ thống message broker. Ngay cả khi một ứng dụng hoàn toàn khỏe mạnh về kết nối cơ sở dữ liệu, điều đó không nhất thiết có nghĩa là nó đã sẵn sàng xử lý các yêu cầu hoặc đủ khỏe để tiếp tục chạy trong trạng thái hiện tại.

Kubernetes hỗ trợ khái niệm liveness và readiness probes: các chỉ số về sức khỏe của ứng dụng giúp Kubernetes xác định liệu có nên gửi lưu lượng đến ứng dụng hay khởi động lại ứng dụng để khắc phục sự cố nào đó. Spring Boot hỗ trợ liveness và readiness probes thông qua endpoint health của Actuator dưới dạng các nhóm health gọi là health groups.

Liveness là chỉ báo cho biết một ứng dụng có đủ khỏe để tiếp tục chạy mà không cần được khởi động lại. Nếu một ứng dụng báo rằng liveness của nó đang "down", Kubernetes có thể phản ứng bằng cách chấm dứt pod đang chạy ứng dụng đó và khởi động một pod mới thay thế.

Readiness, ngược lại, cho Kubernetes biết liệu ứng dụng đã sẵn sàng để xử lý lưu lượng chưa. Ví dụ, trong quá trình khởi động, một ứng dụng có thể cần thực hiện một số khởi tạo trước khi bắt đầu xử lý yêu cầu. Trong thời gian này, readiness của ứng dụng có thể hiển thị là "down". Khi đó, ứng dụng vẫn còn sống, vì vậy Kubernetes sẽ không khởi động lại nó. Tuy nhiên, Kubernetes sẽ tôn trọng chỉ báo readiness bằng cách không gửi yêu cầu đến ứng dụng. Khi ứng dụng hoàn tất khởi tạo, nó có thể thiết lập probe readiness thành "up", và Kubernetes sẽ bắt đầu định tuyến lưu lượng đến nó.

BẬT LIVENESS VÀ READINESS PROBES

Để bật liveness và readiness probes trong ứng dụng Spring Boot của bạn, bạn cần đặt management.health.probes.enabled thành true. Trong tệp application.yml, sẽ như sau:

yaml
management:
  health:
    probes:
      enabled: true

Khi probes được bật, một yêu cầu đến endpoint health của Actuator sẽ trông như sau (giả sử ứng dụng hoàn toàn khỏe mạnh):

json
{
  "status": "UP",
  "groups": [
    "liveness",
    "readiness"
  ]
}

Tuy nhiên, endpoint cơ bản này không cho biết nhiều về liveness hay readiness. Thay vào đó, yêu cầu đến /actuator/health/liveness hoặc /actuator/health/readiness sẽ cung cấp trạng thái tương ứng. Nếu mọi thứ đều "up", phản hồi sẽ như sau:

json
{
  "status": "UP"
}

Ngược lại, nếu một trong hai trạng thái là "down", kết quả sẽ trông như sau:

json
{
  "status": "DOWN"
}

Trong trường hợp trạng thái readiness là "down", Kubernetes sẽ không định tuyến lưu lượng đến ứng dụng. Nếu endpoint liveness báo "down", Kubernetes sẽ cố gắng khắc phục bằng cách xóa pod và khởi tạo phiên bản mới.

CẤU HÌNH LIVENESS VÀ READINESS TRONG DEPLOYMENT

Với Actuator cung cấp trạng thái liveness và readiness tại hai endpoint này, tất cả những gì bạn cần làm là thông báo cho Kubernetes biết cách kiểm tra chúng trong manifest triển khai. Đoạn cuối của manifest triển khai sau đây cho thấy cấu hình cần thiết để Kubernetes biết cách kiểm tra:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taco-cloud-deploy
  labels:
    app: taco-cloud
spec:
  replicas: 3
  selector:
    matchLabels:
      app: taco-cloud
  template:
    metadata:
      labels:
        app: taco-cloud
    spec:
      containers:
      - name: taco-cloud-container
        image: tacocloud/tacocloud:latest
        livenessProbe:
          initialDelaySeconds: 2
          periodSeconds: 5
          httpGet:
            path: /actuator/health/liveness
            port: 8080
        readinessProbe:
          initialDelaySeconds: 2
          periodSeconds: 5
          httpGet:
            path: /actuator/health/readiness
            port: 8080

Cấu hình này yêu cầu Kubernetes gửi yêu cầu GET đến đường dẫn tương ứng trên cổng 8080 sau 2 giây kể từ khi pod khởi chạy, và sau đó cứ mỗi 5 giây lặp lại.

QUẢN LÝ LIVENESS VÀ READINESS

Làm cách nào để thiết lập các trạng thái liveness và readiness? Nội bộ, Spring hoặc các thư viện của nó có thể thiết lập trạng thái bằng cách phát ra một availability change event. Tuy nhiên, bạn cũng có thể viết mã trong ứng dụng của mình để phát các sự kiện này.

Ví dụ, giả sử bạn muốn trì hoãn readiness của ứng dụng cho đến khi hoàn tất một số khởi tạo. Ngay trong vòng đời khởi động của ứng dụng, có thể trong một bean ApplicationRunner hoặc CommandLineRunner, bạn có thể xuất readiness state để từ chối lưu lượng như sau:

java
@Bean
public ApplicationRunner disableLiveness(ApplicationContext context) {
  return args -> {
    AvailabilityChangeEvent.publish(context, ReadinessState.REFUSING_TRAFFIC);
  };
}

Tại đây, ApplicationRunner nhận một instance của Spring application context làm tham số cho phương thức @Bean. Điều này cần thiết vì phương thức tĩnh publish() cần nó để phát hành sự kiện. Sau khi khởi tạo hoàn tất, trạng thái readiness của ứng dụng có thể được cập nhật để chấp nhận lưu lượng theo cách tương tự như sau:

java
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);

Trạng thái liveness cũng có thể được cập nhật theo cách tương tự. Sự khác biệt chính là thay vì phát hành ReadinessState.ACCEPTING_TRAFFIC hoặc ReadinessState.REFUSING_TRAFFIC, bạn sẽ phát hành LivenessState.CORRECT hoặc LivenessState.BROKEN. Ví dụ, nếu trong mã ứng dụng bạn phát hiện lỗi nghiêm trọng không thể phục hồi, ứng dụng có thể yêu cầu bị dừng và khởi động lại bằng cách phát hành LivenessState.BROKEN như sau:

java
AvailabilityChangeEvent.publish(context, LivenessState.BROKEN);

Ngay sau khi sự kiện này được phát hành, endpoint liveness sẽ báo rằng ứng dụng đang ở trạng thái DOWN, và Kubernetes sẽ hành động bằng cách khởi động lại ứng dụng. Bạn có rất ít thời gian để phát hành sự kiện LivenessState.CORRECT nhằm đảo ngược lại. Tuy nhiên, nếu bạn xác định rằng ứng dụng vẫn còn khỏe, bạn có thể hủy sự kiện lỗi bằng cách phát hành một sự kiện mới như sau:

java
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);

Miễn là Kubernetes chưa gọi đến endpoint liveness của bạn kể từ khi bạn đặt trạng thái thành BROKEN, ứng dụng có thể coi đây chỉ là một pha suýt lỗi và tiếp tục xử lý yêu cầu như bình thường.

Released under the MIT License.