DataChannelってなに?
WebRTCと聞くと「ビデオ通話」のイメージが強いですが、実は映像や音声だけでなく軽いデータも送れる専用の通路があります。それが DataChannel です。チャットメッセージやAI推論の進捗、中間結果などを即時に返すのにピッタリ。HTTPよりもずっと遅延が少なく、リアルタイム性が高いのが魅力です。
使いどころ(ユースケース)
- AI推論の途中経過を返す:長い処理を待たせず「今こんな分析中です」と小出しに通知できる
- チャットやコマンド送信:軽いテキストデータを即座に届けたいときに便利
- センサー情報やログのストリーミング:IoT機器のデータをほぼリアルタイムで集めたい場合
- マルチプレイヤーゲーム:プレイヤーの位置や入力イベントを遅延なく共有
「映像や音声まではいらないけど、小さくて即時性が欲しいデータ」に最適です。
よくあるつまずき
- 信頼性モード(reliable)にしてしまう → 再送で遅延が大きくなる
- モバイルでアプリがバックグラウンドに回る → 接続が切れてしまう
- STUN/TURNを設定していない → 社内ネットワークや外部から繋がらない
リアルタイム性を守るコツ
- DataChannelを作るときに:
pc.createDataChannel("dc", {ordered: false, maxRetransmits: 0})
→ パケットロスは多少許容、でも遅延は最小化! - 定期的にping/pongを送って接続が生きているか確認
- TURNサーバを必ず用意して、TCP/443でも通せるようにする(モバイルや企業NW対策)
Djangoとのつなぎ込み
Djangoは「シグナリング役」。フロント同士が直接やり取りできるように、Offer/AnswerやICE Candidateを仲介するだけ。実際のデータ通信はブラウザ同士で行うので低遅延。
# Django Channelsでシグナリングの受信例
class SignalingConsumer(AsyncWebsocketConsumer):
async def receive(self, text_data):
data = json.loads(text_data)
# offer/answer/candidateをそのまま相手へ中継
await self.channel_layer.group_send(
"room1", {"type": "signal.message", "msg": data}
)
運用でチェックすべき指標
- RTT(往復遅延) → 数百ms以上なら遅すぎる
- パケットロス率 → 多いと会話やデータが途切れる
- TURN経由率 → 急に増えたらネットワーク障害の兆候
gRPCと比較した使い分け
- DataChannelが得意:小さくて即時性が欲しいデータ(チャット、推論進捗、IoTログ、ゲームイベントなど)
- gRPCが得意:明確なリクエスト→レスポンス形式、大きめのデータ転送、型安全なAPI設計や再利用が必要な場面
- 使い分けの目安:
- 「数ミリ秒でも速く返したい」→ DataChannel
- 「APIとして管理・拡張したい」→ gRPC
両者を組み合わせた構成例
例えば以下のように役割を分けるとバランスが良いです:
- 認証・制御 → DjangoがJWTなどで認証し、利用制御を行う
- リクエスト処理 → gRPCでML推論APIを呼び出し、型安全にレスポンスを取得
- リアルタイム配信 → WebRTC DataChannelで途中経過や最終結果をユーザーに逐次配信
この構成だと「管理や拡張性はgRPC」「ユーザー体験の速さはDataChannel」と、それぞれの強みを活かせます。
両方を組み合わせた構成例(実運用イメージ)
目的:認証はDjango、推論呼び出しはgRPC、途中経過や軽量通知はDataChannelで即時配信。
流れ(ざっくり)
- ブラウザが Django にログイン → 短命JWT を発行
- ブラウザは WebRTC接続(STUN/TURN経由)。DataChannelを開く
- 同時に gRPC‑Web→Envoy→MLサーバ に推論を開始(JWTをヘッダで添付)
- MLサーバはServer‑Streamingで結果を小分けに返却/進捗はDataChannelで即時通知
- 失敗時は冪等RPCのみ自動リトライ、DataChannelでユーザーに軽量エラー通知
[Browser]
├─ WebSocket(シグナリング) → [Django]
├─ DataChannel(進捗/軽量通知) ⇄ [Peer]
└─ gRPC‑Web(推論) → [Envoy] → [ML gRPC Server]
↑JWT検証
Django(JWT発行の最小例)
from datetime import datetime, timedelta, timezone
import jwt
def issue_token(request):
now = datetime.now(timezone.utc)
payload = {"sub": str(request.user.id),
"exp": int((now + timedelta(minutes=5)).timestamp())}
return JsonResponse({"token": jwt.encode(payload, SECRET, "HS256")})
gRPCサーバ(JWT検証インターセプタ例:Python)
import grpc, jwt
def auth_interceptor(SECRET):
def intercept(method):
def wrapper(request, context):
md = dict(context.invocation_metadata())
token = md.get("authorization", "").replace("Bearer ", "")
try:
jwt.decode(token, SECRET, algorithms=["HS256"])
except Exception:
context.abort(grpc.StatusCode.UNAUTHENTICATED, "bad token")
return method(request, context)
return wrapper
return auth_interceptor
Envoy(要点)
envoy.filters.http.grpc_web
を有効化- UpstreamはHTTP/2、
max_grpc_timeout
を短めに - CORSで
content-type, x-grpc-web, x-user-agent, authorization
を許可
運用チェック
- p95接続確立時間(WebRTC)/ p95応答時間(gRPC)
- TURN経由率とEnvoyのupstreamエラー率
- 再接続/リトライ回数(ユーザー体験に直結)
まとめ
DataChannelは「軽くて即時性が欲しいデータ」に最適。一方で、型安全なリクエスト/レスポンス処理や大きめのデータにはgRPCが向きます。両者を場面ごとに使い分けることで、安定した低遅延の仕組みを作れます。