昨年、私はある取引プラットフォーム向けのリアルタイム監視ダッシュボード構築プロジェクトを主導しました。要件は次の通りです:毎秒100万イベントで更新される市場データを、ユーザー画面へのレイテンシー100ミリ秒未満で可視化すること。
これは、私たちがデータ可視化について知っていると思っていたすべてを覆しました。
リアルタイムの現実
誰も教えてくれないこと:通常、「リアルタイム」はリアルタイムではありません。そして、多くの場合、それで十分なのです。
「リアルタイム」とラベル付けされたほとんどのダッシュボードは、実際には5〜30秒ごとに更新されます。ほとんどのユースケースでは、これで完全に十分です。しかし、実際に1秒未満の更新が必要な場合、ルールは完全に変わります。
3段階の「リアルタイム」
第1層: ニアリアルタイム (5〜60秒更新)
ユースケース: ビジネスダッシュボード、マーケティングアナリティクス、セールスメトリクス
アーキテクチャ: APIエンドポイントのポーリング、バッチ集計
複雑さ: 中程度
これがほとんどの人が必要なものです。データチームが毎分データを集計し、ダッシュボードが更新をポーリングします。シンプルで効果的です。
第2層: リアルタイム (1〜5秒更新)
ユースケース: 運用監視、ライブイベント追跡、カスタマーサポートキュー
アーキテクチャ: WebSocket、サーバー送信イベント(SSE)、ストリーミングクエリ
複雑さ: 高
ポーリングからプッシュへの移行はすべてを変えます。今、あなたは永続的な接続を維持し、再接続ロジックを処理し、クライアント/サーバー間で状態を管理しています。
第3層: サブセカンド (1秒未満)
ユースケース: 取引プラットフォーム、ライブゲーム統計、産業監視
アーキテクチャ: ストリーミングパイプライン、専用データベース、最適化されたレンダリング
複雑さ: 非常に高い
これが私たちが8か月間過ごした世界です。すべての最適化が重要です。すべてのミリ秒が重要です。
リアルタイム可視化が難しい理由
問題1: データ量
毎秒100万イベントでは、各イベントをレンダリングできません。それは毎秒100万ポイントです。ブラウザは爆発します。
解決策: 事前集計。生のイベントをフロントエンドに送らないでください。ソースで集計します—時間バケットごとの平均、カウント、パーセンタイル。私たちは100万の生イベントではなく、毎秒10の集計済み更新を送信しました。
問題2: レンダリングパフォーマンス
たとえ毎秒10回の更新でも、チャート全体を再レンダリングするとパフォーマンスが低下します。Reactの調整、SVG操作、Canvasの再描画—それらが積み重なります。
解決策: インクリメンタルアップデート。チャートを再構築しないで、追加します。最高頻度のチャートにはWebGLベースのレンダリングを使用し、60fpsの更新をスムーズに処理できます。
問題3: 人間の知覚
直感に反する発見です:約200ミリ秒より速い更新は、かすんでしまいます。ユーザーは10+fpsでの情報を処理できません。彼らはただちらつきを見るだけです。
解決策: 視覚的スムーシング。データが10Hzで更新されても、200ミリ秒かけてトランジションをアニメーション化しました。チャートは混沌と感じることなく、「生きている」ように感じられました。
問題4: ネットワークの多様性
WebSocket接続は切れます。パケットは遅延します。モバイルユーザーはネットワークを切り替えます。
解決策: 堅牢な再接続、メッセージキューイング、グレースフルデグレデーション。接続が切れた場合、最後の既知の状態を「再接続中」のインジケーターとともに表示します—空白の画面は表示しません。
機能したアーキテクチャ
以下が私たちの毎秒100万イベント要件を処理したスタックです:
データ層
- イベントインジェスト用 Apache Kafka
- リアルタイム集計用 Apache Flink
- 最新状態キャッシュ用 Redis
- 履歴クエリ用 TimescaleDB
API層
- WebSocketサーバー用 Go (効率的に同時接続を処理)
- 内部サービス通信用 gRPC
- メッセージバッチング (各イベントではなく、100ミリ秒ごとに更新を送信)
フロントエンド
- UI構造用 React
- 高頻度チャート用 WebGL (regl経由)
- 中頻度チャート用 軽量Canvas
- 低頻度でインタラクション重視のチャート用 SVG (D3経由)
重要な決定事項
- できるだけ早く集計する: フロントエンドは、生イベントではなく、表示準備の整ったデータを受け取るべきです。
- 更新頻度を分離する: すべての要素が10fpsを必要とするわけではありません。静的なコンテキストは30秒ごとに更新できます。
- ユーザーが制御する詳細レベル: ユーザーに「概要」(更新遅め、データ多め)と「詳細」(更新速め、焦点絞り)の選択をさせます。
パフォーマンス最適化
サーバー側
- 時間バケットを事前計算: クライアントに「過去5分間」を計算させない
- 差分エンコーディング: 完全な状態ではなく、変化したものだけを送信
- 圧縮: WebSocketメッセージをgzip (驚くほど効果的)
- コネクションプーリング: サブスクリプション間で接続を再利用
クライアント側
- オブジェクトプーリング: ガベージコレクションするのではなく、チャート要素を再利用
- requestAnimationFrameバッチング: 更新をブラウザのレンダリングサイクルに同期
- Canvasレイヤリング: 静的な要素は1つのCanvasに、動的な要素は別のCanvasに
- Web Worker: メインスレッドから受信データを解析
機能しなかったもの
- 高頻度更新用の SVG (DOM操作が遅すぎる)
- リアルタイム状態管理用の Redux (頻繁な更新にはオーバーヘッドが大きすぎる)
- 5fps超用の既製チャートライブラリ (このユースケースに最適化されていない)
リアルタイムから得られたUXの教訓
教訓1: ユーザーに制御を与える
誰もがライブ更新を望むわけではありません。一部のユーザーは気が散ると感じます。私たちは以下を追加しました:
- 一時停止ボタン: 現在のビューを「固定」
- 更新頻度選択: 1秒、5秒、30秒
- 履歴モード: 「5分前に何が起こったかを見せて」
教訓2: 状態を明確にする
ユーザーは以下を知る必要があります:
- これはライブか履歴か?
- 最後の更新はいつか?
- 接続は正常か?
私たちは、各更新とともに脈打つ永続的な「心拍」インジケーターを追加しました。驚くほど安心感を与えました。
教訓3: 退屈な状態を処理する
ほとんどの時間、面白いことは何も起こりません。チャートはただ…似たような値で更新されるだけです。
ここで注記が役立ちます:「14:32にスパイクを検出」は意味のある変化に注意を引きます。これがないと、ユーザーはノイズを見つめ続けます。
教訓4: モバイルは異なる
画面は小さく、接続は悪く、バッテリー制約があります。モバイル向けには:
- 更新頻度を自動的に下げる
- 可視化を簡素化する
- 積極的な再接続ロジックを追加する
リアルタイムが価値がないとき
このシステムを構築した後、私はリアルタイム要件に対してより懐疑的になりました。次のことを問いかけてください:
- より速い更新がユーザーの行動を変えますか?
- ユーザーは実際にあれほど速く情報に基づいて行動できますか?
- エンジニアリングコストは正当化されますか?
ほとんどのダッシュボードでは、答えはノーです。15秒更新で十分です。リアルタイムは、実際に秒単位が重要なケースのために取っておきましょう。
ツールとリソース
第1〜2層 (ニアリアルタイムおよびリアルタイム) 向け:
ChartGenのような最新ツールは、APIを効果的にポーリングするチャートを生成できます。WebSocketエンドポイントと組み合わせれば、カスタムインフラストラクチャなしで堅牢なリアルタイムダッシュボードを構築できます。
第3層 (サブセカンド) 向け:
特別なツールが必要になります:Canvasを使用したD3、カスタムWebGLレンダリング、またはuPlotやインクリメンタル更新モードのApache EChartsのような特定目的のライブラリ。
ストリーミングインフラストラクチャ向け:
- Apache Kafka + Flink (複雑だが強力)
- AWS Kinesis + Lambda (マネージドだが制限あり)
- Redis Streams + カスタム集計 (よりシンプルだがスケーラビリティは低め)
リアルタイムシステムの監視
私たちが測定したもの:
- エンドツーエンド遅延 (イベントタイムスタンプから画面上のピクセルまで)
- 接続健全性 (1時間あたりの再接続数)
- レンダリングパフォーマンス (1秒あたりのフレーム数)
- ユーザーエンゲージメント (人々は実際にリアルタイムビューを見ますか?)
驚くべき発見:多くのユーザーがダッシュボードを開き、2分間見た後、バックグラウンドタブに置き去りにしました。「ライブ」データはほとんど見られていませんでした。
最後に
リアルタイム可視化はエンジニアリング上の課題ですが、同時にUX上の課題でもあります。最も難しい部分は、データを速く画面に表示することではありません—それは、人間が実際に理解し、それに基づいて行動できる方法で提示することです。
リアルタイムを構築する前に、自問してください:より速いデータで、ユーザーは実際に何を変えるでしょうか?
答えが明確でなければ、あなたはリアルタイムを全く必要としていないかもしれません。


