Chào các bạn, có bao giờ bạn thấy bực mình khi làm việc nhóm trên một ứng dụng nào đó mà:Đang gõ lia lịa, "ùm" cái mất sạch chữ?Con trỏ nhảy nhót loạn xạ như ma làm?Đứa này sửa, đứa kia gõ, thế là "giẫm chân" lên nhau, dữ liệu bay màu?Đúng là ác mộng của dân công sở luôn! Đa số các ứng dụng cộng tác "bình dân" rất dễ "tụt huyết áp" dưới áp lực, dẫn đến đủ thứ xung đột và mất mát dữ liệu.NHƯNG, tin vui là với bộ đôi "siêu sao" Phoenix LiveView và CRDTs, bạn hoàn toàn có thể tạo ra những giao diện đa người dùng không một vết "cãi vã," mượt mà y chang Google Docs vậy đó – mà "ghê gớm" hơn nữa là: tất cả đều được xử lý gọn gàng từ phía server! Nghe có vẻ "ảo diệu" đúng không? Cùng tìm hiểu nhé! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/gdocs_liveview_crdt.png' alt='Google Docs và Phoenix LiveView & CRDTs'> Bài Toán Khó Nhằn: Làm Sao Để Cộng Tác Thật Sự "Phê"?Hãy thử hình dung: Nếu hai người dùng cùng lúc gõ vào một chỗ thì sao?Với cách quản lý trạng thái "ngây thơ" thông thường, y như rằng một người sẽ "thắng" và người kia mất bài hoặc bị ghi đè. Để giải quyết bài toán hóc búa này, chúng ta cần những "nguyên liệu" đặc biệt sau:⚡ Cập nhật tức thì qua WebSockets: Nhanh như chớp, không độ trễ.🔀 Cấu trúc dữ liệu biết "hòa giải": Dù sửa ở đâu, gõ kiểu gì, cuối cùng cũng phải "cùng chung một nhà," không đứa nào bị bỏ rơi.🖥️ Hiển thị "sự hiện diện" và con trỏ: Bạn đang ở đâu, ai đang gõ? Cần biết chứ!🧠 Trạng thái "não cá vàng" vẫn nhớ: Dù mất mạng, dù tín hiệu chập chờn, dữ liệu vẫn phải nguyên vẹn khi kết nối lại.Ở đây, LiveView sẽ lo phần "giao thông" và "hiển thị" siêu tốc cho bạn. Còn CRDTs (Conflict-free Replicated Data Types) chính là "người hòa giải" tối thượng, đảm bảo dữ liệu của bạn luôn nhất quán và không xung đột, bất kể có bao nhiêu người cùng chỉnh sửa. Nghe đã thấy "xịn" rồi đúng không? <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/liveview_crdt_synergy.png' alt='Sự kết hợp giữa LiveView và CRDTs'> Bước 1: "Loa Phát Thanh" Mọi Hành Động Của Người DùngThay vì gửi cả một "cục" văn bản sau mỗi lần sửa, chúng ta sẽ coi mỗi chỉnh sửa là một "mẩu tin nhỏ" riêng biệt. Ví dụ, khi bạn gõ chữ "a" vào vị trí 24, hệ thống sẽ phát một "mẩu tin" như thế này:Phoenix.PubSub.broadcast(MyApp.PubSub, "doc:123", %{ op: :insert, pos: 24, char: "a", user_id: "u9"}) Trong LiveView của bạn, chúng ta sẽ làm thế này:* Khi "khởi động" LiveView: Chúng ta sẽ "đăng ký" để lắng nghe mọi "mẩu tin" từ tài liệu đó. Đây là lúc CRDT của chúng ta được khởi tạo, sẵn sàng "tiếp nhận" thông tin.def mount(%{"doc_id" => doc_id}, _session, socket) do Phoenix.PubSub.subscribe(MyApp.PubSub, "doc:#{doc_id}") {:ok, assign(socket, crdt: MyCRDT.new())}end* Khi có "mẩu tin" mới: Mỗi khi có một "mẩu tin" về thay đổi nào đó, LiveView sẽ nhận được và dùng nó để cập nhật trạng thái CRDT hiện tại của mình.def handle_info(%{op: _, pos: _, char: _, user_id: _} = change, socket) do updated_crdt = MyCRDT.apply(socket.assigns.crdt, change) {:noreply, assign(socket, crdt: updated_crdt)}endCứ như vậy, mọi hành động của người dùng đều được "báo cáo" và "ghi nhận" một cách chi tiết! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/pubsub_crdt_flow.png' alt='Luồng dữ liệu trong ứng dụng cộng tác LiveView CRDT'> Bước 2: Sử Dụng CRDT – "Người Hòa Giải" Siêu Đẳng!Đây chính là "linh hồn" của mọi chuyện! Thay vì phải đau đầu với khóa (locks) hay nguy cơ ghi đè, chúng ta sẽ dùng một loại CRDT đặc biệt để theo dõi từng thay đổi nhỏ (chèn, xóa ký tự). Hãy nghĩ CRDT như một "bộ não thông minh" giúp hợp nhất mọi thay đổi từ khắp nơi mà không bao giờ "cãi nhau" hay làm mất dữ liệu của ai.Bạn có thể dùng thư viện xịn xò như delta_crdt_ex để đồng bộ dữ liệu giữa các "đồng nghiệp" (peers). Hoặc đơn giản hơn, mỗi LiveView sẽ giữ một bản sao CRDT của riêng mình trong bộ nhớ để tăng hiệu suất. Dù cách nào đi nữa, mỗi "mẩu tin" thay đổi sẽ được áp dụng theo cùng một thứ tự ở mọi nơi – đảm bảo không khóa, không ghi đè, cứ thế mà "hòa nhập"! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/crdt_concept_merge.png' alt='CRDTs giúp hợp nhất thay đổi mà không xung đột'> Bước 3: Hiển Thị Trạng Thái "Chia Sẻ" Lên Màn HìnhGiờ thì, làm sao để những thay đổi trên CRDT "nhảy" lên màn hình người dùng đây? Đơn giản thôi! LiveView sẽ giúp bạn làm điều này với vài dòng code: <div class="prose whitespace-pre-wrap font-mono"> <%= for char <- MyCRDT.to_list(@crdt) do %> <%= char %> <% end %> </div> Điều kỳ diệu ở đây là: LiveView cực kỳ thông minh! Nó chỉ render lại phần văn bản đã thay đổi thôi, nhờ vào công nghệ "vá DOM" siêu đỉnh. Kết quả ư?Cập nhật nhanh như điện!Không hề bị nháy mắt một cái nào!Và dù tài liệu có dài đến đâu cũng chẳng hề hấn gì! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/liveview_dom_patching.png' alt='LiveView cập nhật DOM thông minh'> Bước 4: "Bật Radar" Để Thấy Con Trỏ Và Sự Hiện Diện Của Nhau!Muốn có cảm giác "cộng tác thật sự" thì phải thấy nhau chứ, đúng không? Chúng ta sẽ dùng Phoenix.Presence – một tính năng có sẵn trong Phoenix – để theo dõi xem ai đang online, đang ở đâu trong tài liệu.presence_list = Phoenix.Presence.list(MyApp.Presence, "doc:123")Kết quả sẽ trông như thế này (ví dụ):%{ "u9" => %{metas: [%{cursor: {2, 18}, name: "Alice"}]}, "u5" => %{metas: [%{cursor: {7, 43}, name: "Bob"}]}} Và trong template, bạn chỉ cần vài dòng để "vẽ" con trỏ lên màn hình: <%= for {user_id, %{metas: [meta
Khám phá cách xây dựng các ứng dụng hợp tác 'mượt mà như Google Docs' với Phoenix LiveView và CRDTs, giải quyết vấn đề xung đột dữ liệu và tạo trải nghiệm người dùng liền mạch chỉ từ phía server.
Tìm hiểu cách một chiến dịch influencer có thể làm sập hệ thống Kafka, khiến công ty mất hàng trăm ngàn euro, và tại sao việc chuyển sang Google Pub/Sub lại là giải pháp cứu cánh.