Thứ Năm, 16 tháng 1, 2020

Phân biệt Stateful và Stateless, khái niệm StatefulSet trong Kubernetes



Stateless

Trong lập trình web, chúng ta có sự tương tác giữa client với server. Phần mềm gồm 2 thành phần chính: phần mềm và data. Như vậy, một phần mềm được thiết kế theo tương tác client – server thì phần nhiều tập lệnh sẽ nằm phía server. Client có nhiệm vụ gửi dữ liệu lên để xử lý sau đó nhận kết quả trả về. Vậy stateful vs stateless là gì?
Stateless là thiết kế không lưu dữ liệu của client trên server. Có nghĩa là sau khi client gửi dữ liệu lên server, server thực thi xong, trả kết quả thì “quan hệ” giữa client và server bị “cắt đứt” – server không lưu bất cứ dữ liệu gì của client. Như vậy, khái niệm “trạng thái” ở đây được hiểu là dữ liệu.

Stateful

Stateful là một thiết kế ngược lại, chúng ta cần server lưu dữ liệu của client, điều đó đồng nghĩa với việc ràng buộc giữa client và server vẫn được giữ sau mỗi request (yêu cầu) của client. Data được lưu lại phía server có thể làm input parameters cho lần kế tiếp.

Tổng kết và ví dụ

HTTP là một Application Protocol dạng stateless, tương tác client-server theo HTTP thì phần server sẽ không lưu lại dữ liệu của client. HTTP ban đầu chỉ được dùng đơn thuần cho website, client gửi request, server nhận request xử lý rồi trả về lại cho client hiển thị. Sau đó thì kết thúc 1 quy trình. Sau này người ta mới bắt đầu nâng cấp cho phép website giống như một ứng dụng stateful bao gồm html, database (mysql, mongodb…), transaction…
Có 4 cách lưu data của client khi xây dựng Web Application bao gồm: URL Rewriter, Form, Cookie, HTTP Session.
Nhân dịp gần đây tôi có tham dự một meetup về Kubernetes và có tham gia thảo luận về Stateful và Stateless, nay tôi đưa phần thảo luận lên blog. Thảo luận ban đầu xoay quanh StatefulSet và được mở rộng ra Stateful và Stateless nói chung trong cả Software Development và Devops.
Cái tên StatefulSet là một cái tên dễ gây nhầm lẫn, nhất là với những bạn làm DevOps không tham gia nhiều vào Software Development.

StatefulSet ở đây nên được hiểu là nơi chứa các ứng dụng stateful (stateful application). Chữ stateful trong StatefulSet không phải để miêu tả cách hoạt động của bản thân nó, mà để miêu tả tính chất của container application mà nó chứa. Như vậy ở đây cần hiểu rõ stateful application là gì và tại sao phải cần 1 cái như StatefulSet để chứa nó.
Định nghĩa cơ bản state là trạng thái (dữ liệu, thông tin, thuộc tính,…) của đối tượng đang đề cập. Ví dụ state của một remote máy lạnh là nhiệt độ, mode, tốc độ quạt,… và khi ta điều chỉnh state trên remote thì nó sẽ sync state này qua máy lạnh. State của máy lạnh độc lập với state trên remote (bạn che đầu hồng ngoại rồi bấm remote thì state 2 bên sẽ không được đồng bộ nữa). Như vậy state của một ứng dụng có thể là những dữ liệu ta xem và lưu trữ trên ứng dụng đó, tuy nhiên không phải dữ liệu nào cũng là state, do đó mới có khái niệm stateful và stateless, phần kế tiếp sẽ nói về việc này.
Như định nghĩa ở trên thì hầu hết các ứng dụng đều có state, trừ những ứng dụng kiểu utility như converter, cat, sed, mkdir,… là hoàn toàn không có state (thuần tuý stateless). Tiếp theo ta chỉ xét những ứng dụng mà ta thấy có state. Stateful và stateless là tính chất ám chỉ state nằm trong lòng (lifecycle) của ứng dụng hay nằm bên ngoài ứng dụng.
Ví dụ điện thoại tháo pin ra gắn lại phải set lại ngày giờ, như vậy điện thoại có state là ngày giờ được ghi nhớ trong một vùng nhớ tạm nào đó, mất nguồn điện là mất hết (khi tắt máy pin vẫn duy trì 1 lượng để duy trì state của điện thoại). Vậy ta thấy điện thoại là stateful. Hầu hết các thiết bị ta dùng mỗi ngày đều stateful ít hay nhiều.
Màn hình máy tính, nếu bỏ qua những phần như chỉnh độ sáng, độ bão hoà màu…, có thể được xem là stateless, bởi vì màn hình chỉ chuyển tải state từ máy tính ra cho người xem. Bạn tắt mở bao nhiêu lần thì nội dung cũng không đổi. Ngay cả rút nguồn mở lại thì vẫn vậy. Đây cũng là một tính chất của functional programing: stateless function (hay pure function) có gọi n lần thì cũng ra cùng 1 kết quả, không có sự khác biệt giữa gọi 1 lần và n lần.
HTTP request thuần bản chất là stateless vì mỗi request lifecycle sinh ra một thread mới và hoàn toàn độc lập với các request khác, state được lưu trên session memory hoặc database hoặc file system (như php session) là nằm ngoài lifecycle của request, đó n-request khác nhau nếu không update state thì đều cho cùng một kết quả.
Tuy nhiên xét đến lifecycle của ứng dụng web thì sẽ khác. Stateful application nghĩa là state nằm trong lifecycle của application đó. Cụ thể là ASP.NET in-memory session sẽ mất nếu ta reset lại server; PHP session lưu trên file system nên không ảnh hưởng nếu reset lại server nhưng nếu load balancing về 2 application server khác nhau thì sẽ dẫn đến việc request thứ nhất dẫn về server1, user đã authenticated, đến request thứ 2 dẫn về server 2, user bị mất authenticated, hoặc bị mất giỏ hàng,… cho nên PHP session bản chất vẫn là stateful.
Như vậy stateless application nghĩa là ta phải đưa được state ra khỏi lifecycle của application. Các ứng dụng sau này viết ra để ready to load-balancing đều phải đẩy server state ra shared persistent location như database, Redis cache,… hoặc đẩy về client-side như ASP.NET Identity sử dụng cookie ticket để authenticate. Bù lại, đẩy ra database hay Redis cache sẽ bị thêm overhead về performance, còn đẩy về client-side sẽ tăng overhead về traffic load.
Hiểu stateful và stateless application rồi thì ta sẽ hiểu tại sao cần StatefulSet. StatefulSet điều chỉnh load-balance routing để request tiếp theo của user về đúng server ban đầu được chọn, mục tiêu là để đảm bảo user không bị mất session state. Các ứng dụng như WordPress, ASP.NET WebForms sử dụng nhiều session state sẽ cần StatefulSet. Các ứng dụng được viết ra không lưu trữ state trong nội tại server/container của mình thì có thể dùng deployment thông thường.

FAQ:

  1. Có bạn hỏi tại sao TCP là stateful trong khi đó HTTP dựa trên nền tảng TCP lại là stateless. Câu trả lời nằm ở định nghĩa: mối liên hệ giữa state và đối tượng đang xét. Đối với TCP, lifecycle của mỗi TCP request gắn liền với state của nó, 2 TCP request khác nhau là hoàn toàn khác nhau, không thể thay thế cho nhau. Nhưng xét ở HTTP level, state của TCP không liên quan gì đến HTTP request cả, mặc dù HTTP sử dụng TCP làm công cụ truyền tải thông tin. 2 HTTP GET request đến cùng một endpoint (URL) và nhận về cùng 1 kết quả thì có thể xem là như nhau.
  2. Docker container là stateful hay stateless? Có bạn trả lời tùy vào ứng dụng mà docker chứa. Câu trả lời nghe cũng hợp lý nhưng chỉ đúng khi nói chuyện với nhau bằng tiếng Việt. Các bạn search một vòng sẽ thấy người ta phân biệt rất rõ docker container và application. Container có thể chứa stateful application hoặc stateless application. Còn docker container nó sẽ stateful hay stateless tùy theo cách ta define. Thông thường một docker container đúng nghĩa nên là stateless, nghĩa là ta đẩy hết state ra volume, cho dù ta có rebuild và recreate lại container đó thì nó vẫn tiếp tục chạy như nó đã từng chạy.

0 nhận xét:

Đăng nhận xét