コンテンツにスキップ

バックエンド面接: Google Docs のリアルタイム更新

元ネタ

  • X: https://x.com/suni_code/status/2040859552531533992

問い

Google Docs を開いて、誰かがリアルタイムでタイピングしているのが見える。 その更新がリフレッシュせずに即座に表示されるのはなぜか。

まずの答え

ブラウザがページを毎回リロードしているのではなく、サーバーとの間に継続的な通信経路を持っているから。

代表的には WebSocket のような双方向通信を使い、誰かの編集内容をサーバーが受け取り、同じドキュメントを開いている他のクライアントへすぐ配信する。受け取ったクライアントは、ページ全体を読み直さず、ドキュメントの内部状態と画面の必要な部分だけを更新する。

何が起きているか

ユーザーAのブラウザ
  -> 編集操作を送る
  -> サーバー
  -> 同じドキュメントを見ているユーザーB/Cへ配信
  -> 各ブラウザが画面に反映

ここで送られるのは、HTML 全体ではなく「どこに、どんな文字を挿入したか」「どの範囲を削除したか」のような差分データであることが多い。

面接で見られそうな観点

  • WebSocket、Server-Sent Events、ロングポーリングなど、リロードなしに更新を届ける手段を知っているか
  • リアルタイム更新は通信だけでなく、編集差分の扱いが必要だと分かっているか
  • 複数人が同時に編集したときの競合をどう解決するかを考えられるか
  • ネットワーク遅延、切断、再接続、順序ずれを考慮できるか

深掘り

リアルタイム共同編集では、単に WebSocket で文字列を送るだけでは足りない。

同じ位置に複数人が同時に文字を入れた場合、どの順番で反映するかを決める必要がある。このため、Operational Transformation や CRDT のような同期アルゴリズムが使われる。Google Docs は代表例として Operational Transformation がよく知られている。

自分の理解

この質問の本質は「リロードなしで表示が変わる理由」だけではなく、リアルタイム共同編集を支える構成を説明できるかにある。

最小回答は「WebSocket などでサーバーから変更を push しているから」。

よりよい回答は、次の流れまで言えること。

  1. クライアントが編集操作を差分としてサーバーへ送る
  2. サーバーが権限やバージョンを確認する
  3. 同じ文書を開いている他のクライアントへ変更を配信する
  4. 各クライアントがローカルの文書モデルへ差分を適用する
  5. 同時編集の競合は OT や CRDT のような仕組みで整合性を保つ

バックエンドとの接続

似た仕組みを作るなら、まずは WebSocket サーバーと「ドキュメントルーム」を考える。

  • 1 ドキュメントごとに接続中クライアントを管理する
  • 受け取った編集イベントを同じルームの他クライアントへ broadcast する
  • 接続が切れたクライアントを掃除する
  • イベントの順序、重複、再送を扱う
  • 本格的な共同編集では OT / CRDT を別途設計する

次に調べる

  • WebSocket と Server-Sent Events の使い分け
  • Operational Transformation と CRDT の違い
  • Go で WebSocket の broadcast hub を作る基本設計
  • リアルタイム編集における backpressure と再接続処理