Geosharded Recommendations Part 3: Consistency

Bài tóm tắt Tinder 2019 3. Quy mô lớn Độ khó: Nâng cao

Tinder · 2019 · 3. Quy mô lớn · Độ khó: Nâng cao — bài gốc

Phần cuối của series. Phần 1: Tinder 2019; phần 2: Tinder 2019.

Bối cảnh

  • Sau khi shard theo địa lý, có hai kho dữ liệu phải khớp nhau:
    • kho ánh xạ document id → geoshard;
    • các index geoshard.
  • Document dời giữa các index, ví dụ khi user bật Passport để "đặt mình" ở nơi khác. Nhiều lệnh ghi cho cùng một document có thể đến cách nhau vài mili giây.
  • Thiết kế không tính tới consistency thì có ghi lỗi hoặc dữ liệu cũ, ví dụ user đã quay về chỗ cũ mà document vẫn nằm ở shard kia.

Thay đổi chính

  • Đảm bảo thứ tự ghi bằng Kafka:
    • partition theo key: mọi lệnh ghi của cùng document vào cùng partition;
    • consumer giữ lock trên partition mình đọc, tránh tranh chấp.
    • Theo Tinder, nhiều hệ queue khác chỉ có thứ tự "best-effort", hoặc FIFO nhưng throughput rất thấp.
  • Đọc nhất quán mạnh từ Elasticsearch:
    • Elasticsearch là near real-time: lệnh ghi nằm trong buffer bộ nhớ cho tới lần refresh mới tìm thấy được.
    • Reindex API dựa vào chính kỳ vọng đó nên có thể dời bản cũ.
    • Họ dùng GET + Index, vì GET mặc định refresh index nếu document còn lệnh ghi chưa refresh. Tốn thêm chút code ứng dụng nhưng hết bất nhất.
    • Kho ánh xạ nếu eventually consistent cũng phải đọc nhất quán mạnh, nếu không thì ánh xạ trỏ sai shard và các lệnh ghi sau đó hỏng.
  • Chuẩn bị cho lỗi:
    • retry với exponential backoff có jitter;
    • worker đọc Kafka bất đồng bộ thì ít lo latency và có checkpoint để chạy tiếp sau khi crash; ghi đồng bộ trong request thì client phải tự retry;
    • refeed index tìm kiếm từ kho nguồn sự thật: ngay khi phát hiện thiếu document, hoặc định kỳ bằng job nền. Refeed dày thì tốn tài nguyên, thưa thì bất nhất kéo dài.

Vì sao (theo Tinder)

Shard theo địa lý nghĩa là document phải di chuyển, và mỗi lần di chuyển là một thao tác không nguyên tử trải trên hai kho. Thứ tự ghi cộng với đọc nhất quán mạnh khử được phần lớn bất nhất; phần còn lại do retry và refeed lo.

Bài học cho SWE

  • Khoá shard có thể đổi giá trị (vị trí user) thì dời giữa shard là việc thường ngày, không phải ngoại lệ. Phải thiết kế thứ tự ghi cho nó.
  • Ghi tuần tự theo key bằng partition của log (Kafka) là cách phổ biến để có thứ tự mà không cần lock toàn cục.
  • Search index nên coi là dữ liệu dẫn xuất dựng lại được từ nguồn sự thật (refeed).
  • Retry phải có jitter, nếu không sẽ thành retry storm (xem Hot partition và thundering herd).

Liên quan