Introduction:
Trong tiến trình phát triển của IT nói riêng và khoa học nói chung thì hầu hết là các lớp phía trên như ứng dụng, sản phẩm tương tác trực tiếp với người dùng ra đời trước, sau đó mới đến hạ tầng phục vụ, hiếm khi có chiều hướng ngược lại. Ví dụ như bóng đèn có trước rồi mới xây dựng hệ thống điện, máy bay có trước rồi mới nghĩ đến xây dựng đường băng, cảng hàng không. Và tất nhiên với “cloud native” cũng vậy. Trong sự hình thành và phát triển của ý niệm “cloud native” thì rõ ràng những khái niệm về cloud native application sẽ được hình thành trước, sau đó mới phát sinh ra các yêu cầu về cloud native infrastructure. Trong series này, ta cũng sẽ tiếp cận theo hướng đó. Vậy, như thế nào là một cloud native application? Liệu cloud native application có giống với những kiến trúc phần mềm trước đó hay không?
Chúng ta có thể tham khảo định nghĩa của cloud native theo CNCF [1]. Cá nhân tôi cho rằng, một ứng dụng cloud native cần phải thoả mãn bốn yếu tố chính sau: Resiliency, Observability, Operability và Agilability.
Resiliency: Tức là khả năng phục hồi sau khi có lỗi và tiếp tục hoạt động.
Trong giai đoạn kiến trúc phân tán đang được áp dụng rộng rãi thì tần suất xuất hiện lỗi cũng như độ phức tạp của các lỗi xảy ra nhiều hơn. Hệ thống càng phân tán, càng phức tạp thì càng nhiều lỗi, càng khó khắc phục. Do đó ta không thể phụ thuộc vào tính resiliency của hạ tầng (mặc dù tính resiliency của app cũng một phần cho hạ tầng tốt mang lại) mà bản thân các ứng dụng cũng cần phải thiết kế để tự bản thân chúng đáp ứng được yêu cầu về tính resiliency.
Resiliency không có nghĩa là tránh lỗi (vì lỗi là điều không thể tránh khỏi) mà có nghĩa là các ứng dụng phải chấp nhận là lỗi xảy ra và cách các ứng dụng phản ứng như thế nào khi có lỗi. Tính resiliency không phải là khái niệm mới nhưng trong môi trường cloud và phân tán thì yếu tố này vô cùng quan trọng. Resiliency được chia thành 2 yếu tố chính: Graceful degradation và Design For Failure.
Một ví dụ điển hình cho Design For Failure là khi thiết kế cloud native app ta sử dụng kiến trúc microservice, các microservice sẽ trao đổi thông tin thông qua message queue để tránh việc phụ thuộc giữa các microservice, các lỗi xảy ra của 1 service cũng sẽ không ảnh hưởng đến sự hoạt động của service khác. Ngoài ra ta cũng có một số kỹ thuật khác khi thiết kế đó chính là circuit breaker, sử dụng “retries for back-off” – các request sẽ được “retries” gửi đến server trong số lần nhất định, etc. Design For Failure là kim chỉ nam cho các developer khi phát triển cloud native application mà muốn đạt được tính resilience. Đó là những app cần phải có kiến trúc được thiết kế để sẵn sàng phản ứng khi có lỗi, thiết kế để giảm thiểu sự phụ thuộc giữa các ứng dụng lẫn nhau,
Graceful degradation là khái niệm miêu tả việc một ứng dụng trả về một phản hồi (response) không đầy đủ nội dung như các phản hồi thông thường trong trường hợp nhận quá nhiều yêu cầu (request overload). Các ứng dụng cloud native cần phải có khả năng thích ứng trong điều kiện overload. Điều này có nghĩa là trong trường hợp overload thì ứng dụng cũng cần phải trả về các phản hồi chứa các thông tin cho dù ít ỏi, có thể là các thông tin cũ được lưu trong cache hay các thông tin chứa những nội dung báo lỗi.
Trong thực tế, rất khó để tách biệt hoàn toàn sự phụ thuộc lẫn nhau giữa các service, output của service này có thể là input của service khác. Do đó sự phản hồi thông tin trong bất kể tình huống nào sẽ giúp cho việc phát triển cũng như vận hành dễ dàng hơn, rõ ràng hơn. Bên cạnh đó còn là sự hỗ trợ của của logging và các thành phần ở lớp infra như load balancer, etc.
Observability
Là khả năng nắm bắt được trạng thái của một service. Trạng thái của một service được xác định bằng việc kiểm tra health report và thông qua các metrics report. Ý niệm về Observability ngày càng phổ biến khi chúng ta thay đổi cách tiếp cận ngày xưa là reverse engineering bằng việc monitoring ngay từ bên trong ứng dụng. Trước đây, khi quá trình DevOps còn là 2 thực thể tách biệt, để nắm bắt được sự hoạt động của một ứng dụng thì kỹ thuật reverse engineering được áp dụng rất nhiều. Tuy nhiên, càng về sau thì việc monitoring từ bên trong ứng dụng càng phổ biến, giúp cho sự vận hành ứng dụng linh hoạt, thuận tiện và dễ dàng hơn.
Health Report:
Bản thân 1 ứng dụng cần phải expose ra bên ngoài những phương thức để thể hiện trạng thái healthy của mình. Không có công cụ nào hiểu ứng dụng bằng chính bản thân nó. Việc đưa cách thức kiểm tra trạng thái vào trong nội hàm của ứng dụng thể hiện tính tự động hoá cao của ứng dụng, giúp cho ứng dụng chủ động trong việc quyết định trạng thái của mình. Có rất nhiều phương án để thực thi tác vụ này, một trong những cách phổ biến là expose một endpoint thông qua HTTP để kiểm tra trạng thái.
Health ko chỉ đơn thuần thể hiện việc ứng dụng có “up and running” hay không mà còn phải thể hiện ứng dụng có thực hiện đúng các tác vụ mà nó mang lại. Một ứng dụng có thể “up and running” nhưng khi nhận một request thì nó xảy ra lỗi và dừng hoạt động. Do đó, việc phát triển cách thức kiểm tra health trong một ứng dụng rất quan trọng đối với developer. Developer phải hiểu rõ được các yêu cầu quan trọng của business, các yêu cầu đó thể hiện như thế nào trong ứng dụng để từ đó thiết kế các health check phù hợp cho từng yêu cầu.
Metrics Report
Những dữ liệu metrics thu thập được phản ánh toàn bộ quá trình hoạt động của ứng dụng, thể hiện performance của ứng dụng đó, ví dụ như số lượng request/second, số lượng request được xử lý, lượng tiêu thụ tài nguyên, etc. Các dữ liệu loại này cần phải được đảm bảo nằm trong phạm vị của service-level objectives (SLO) và là những input vô cùng quan trọng để thiết kế alarm/alert, xa hơn là AIOps.
Các ứng dụng mới ngày nay, đặc biệt là microservice cần phải được implement các cách thức để lấy metrics ngay trong nội tại ứng dụng. Những metrics tối thiểu nhất chính là RED (Rate, Error, Duration). Rate là số lượng request được nhận, Error là số lượng lỗi xảy ra trong ứng dụng, Duration là khoảng thời gian mà một response được trả về.
Trong những hệ thống phân tán, được thiết kế self-healing ngày nay thì sự quan tâm được dành nhiều cho metrics. Điều này không có nghĩa là health report không quan trọng, nó vẫn cần thiết trong việc tự động hoá quá trình triển khai ứng dụng, e.g. Health report trong kubernetes.
[To be continued]
[1] https://github.com/cncf/toc/blob/main/DEFINITION.md