SWIM: Giao thức của những người bạn
1. Giới thiệu
Trong các hệ thống phân tán (distributed system), các node giao tiếp với nhau theo mô hình peer-to-peer, chúng cần hợp tác và trao đổi message lẫn nhau. Vì vậy giữa chúng cần có một membership protocol. Ngoài ra trong mỗi node cần duy trì một danh sách các nodes còn hoạt động (alive), và thông báo lẫn nhau khi có một node được thêm mới hoặc xoá khỏi hệ thống. SWIM — Scalable Weakly-consistent Infection-style Process Group Membership Protocol là một trong những giao thức như vậy.
Bài viết này mình sẽ trình các khái niệm cơ bản về SWIM để giúp chúng ta hiểu hơn về SWIM.
2. Một số khái niệm cơ bản
Khả năng mở rộng (Scalable)
Các memberships protocol hay dùng kĩ thuật heart-beating để kiểm tra các node còn sống hay không. Sau mỗi khoảng thời gian t mỗi node sẽ gửi heartbeat tới tất cả các node trong hệ thống. Nếu sau khoảng thời gian timeout mà node N1 không nhận được heartbeat từ node N2 thì node N2 xem như là đã chết. Sử dụng kỹ thuật này khá tốt đối với các hệ thống nhỏ chỉ có 2 đến 5 node. Vì số heartbeat gửi đi trong cluster sẽ bằng N² (N là số lượng node trong hệ thống). Vì vậy áp dụng kĩ thuật này khó mà có thể scale được.
Nhất quán yếu (Weakly-consistent)
Nghĩa là trong một thời điểm, data giữa các node có sự sai lệch, nhưng về sau data sẽ được đồng bộ hay được gọi là eventual consistency.
Kỹ thuật lây lan (Infection-style)
Một node trong hệ thống chỉ cần chia sẻ dữ liệu xung quanh các nodes peer cạnh mình, các node peer sẽ tiếp tục chia sẻ cho các nodes peer của nó, chúng được gọi là kĩ thuật lây nhiễm (gossip or epidemic). Vì vậy một node không cần gửi broadcast đến tất cả các node trong cluster.
3. Các components trong SWIM
Kĩ thuật heartbeat giải quyết hai vấn đề sau:
- Detect được node bị fail (vì không gửi heartbeat).
- Giữ danh sách tất cả các node trong cluster (danh sách các node cần gửi heartbeat).
Trong SWIM sẽ chia 2 vấn đề đó thành hai components:
- Failure detection
- Dissemination module
3.1. Failure detection
Mỗi node trong cluster sẽ chọn random node (ví dụ N1 chọn N2) trong hệ thống và gửi ping message, sau đó đợi ack message trả về từ N2. Nếu N1 nhận được ack thì N2 còn hoạt động. Nếu N1 không nhận được ack sau timeout thì chưa khẳng định vội N2 đã ngưng hoạt động, N1 sẽ thử gọi qua node khác để node khác gửi ping-request tới N2 kiểm tra thử. N1 sẽ random chọn k node khác từ membership.
Sử dụng cách này có thể giúp ngăn chặn các trường hợp mà vì lý do nào đó N1 không nhận được ack của N2 như mất gói tin,.., nhưng thật chất N2 vẫn còn hoạt động.
Nếu k node membership không thể giao tiếp với N2 thì lúc này mới xác nhận N2 đã ngưng hoạt động.
3.2 Dissemination
Khi phát hiện một node đã ngưng hoạt động thì node phát hiện ra có thể gửi multicast thông tin của node ngưng hoạt động đó cho các node trong hệ thống, mỗi node sẽ xoá node đó khỏi danh sách member. Tương tự cho việc thêm mới một node.
4. Cải tiến SWIM
4.1 Infection-style dissemination
Chúng ta dễ nhận thấy vấn đề khi sử dụng cách multicast:
- IP multicast: ảnh hưởng bởi môi trường.
- Đa phần sử dụng giao thức UDP nên có thể bị mất gói tin.
Cách cải tiến:
- Thay thế multicast bằng cách sử dụng kĩ thuật như ping, ping-req, ack message mà chúng ta dùng để phát hiện lỗi để thực hiện việc truyền thông tin luôn. Không cần tạo thêm các loại message mới. Điểm hay là chúng ta tận dụng lại các message ping để truyền tải thông tin giữa các node.
4.2 Cơ chế đánh dấu node bị lỗi
Chúng ta chỉ cần đánh dấu là nghi ngờ (suspect) node đó đã ngưng hoạt động thay vì khẳng định node đó đã ngưng hoạt động. Mục đích kĩ thuật này là giảm thiểu thời gian xử lý node đó đã ngưng hoạt động như xoá bỏ node đó ra khỏi list member. Nhưng việc đánh dấu node đã ngưng hoạt động dù có sai thì vẫn tốn ít thời gian hơn.
Ta có ví dụ sau: N1 không nhận được ack từ node N2 (kể cách dùng trực tiếp ping hay gián tiếp qua k node), thay vì N1 thông báo các node là N2 đã ngưng hoạt động và cần remove nó ra khỏi list member. N1 chỉ cần thông báo với các node là N2 có thể bị ngưng hoạt động rồi. Lúc này N2 vẫn hoạt động như một node sống, vẫn nhận được các gói tin ping từ các node khác gửi tới. Nếu bất kì node nào nhận được ack từ N2 thì N2 lại được đánh dấu là còn hoạt động. N2 cũng có thể nhận được message báo nó đang bị nghi ngờ là đã ngưng hoạt động và nó có thể thông báo với các node là nó vẫn còn hoạt động.
Sau một khoảng thời gian timeout, vẫn không nhận được tín hiệu gì từ N2 thì lúc này xác định N2 đã ngưng hoạt động.
5.3 Sử dụng kĩ thuật round-robin
Theo như phần trên trình bày thì chúng ta phải chọn random một node để kiểm tra, điều này có thể xảy ra nhiều exception như: random ra kết quả giống nhau làm cho việc phát hiện một node bị failure sẽ tốn thời gian dài để tìm kiếm.
Giải pháp là mỗi node duy trì một danh sách các node để kiểm tra, và dùng kỹ thuật round robin duyệt qua dạnh sách đó. Và khi có node mới thêm vào cluster thì sẽ random vị trí node đó trong danh sách duyệt. Với cách này chúng ta có thể giới hạn được thời gian phát hiện ra một node bị failure. Thời gian tối đa có thể phát hiện là t = interval x number of nodes được chọn kiểm tra.
6. Kết luận
Hiện nay SWIM protocol được sử dụng rất nhiều ở các hệ thống phân tán. Một trong số đó là open-source Serf một giải pháp phát triển bởi Hashicorp. Bài viết trên chỉ là những giới thiệu tổng quát về SWIM, các bạn có thể đọc thêm về SWIM ở những bài viết sau: