はじめに:なぜナレッジグラフなのか
実務において「繋がり」という概念は想像以上に複雑です。ユーザー間の関係、デバイス間の接続、アカウント間の関連性 — これらすべてをリレーショナルデータベースで表現しようとすると、無数のJOINが必要になり、1回のクエリに数十秒かかることは珍しくありません。
Airbnbはこの問題を解決するために**ナレッジグラフ(Knowledge Graph)**を導入しました。特にTrust & Safety(信頼と安全)領域において、ユーザー間の関係を追跡し、不正行為を検出し、リンクされたアカウントを特定するためにグラフが中核的な役割を果たしています。
本記事では、Airbnbが70億のノードと110億のエッジを持つアイデンティティグラフ(Identity Graph)をどう運用しているか、そしてどのようなインフラ判断を下したのかを詳しく見ていきます。特に自社管理型インフラを検討されている方に実践的なインサイトを提供します。
参考資料: Airbnbエンジニアリングブログ原文

第1世代→第3世代:アイデンティティグラフの進化
Airbnbのアイデンティティグラフは大きく3回の進化を経ています。
第1世代:RDBMS + KVストア
- 構成: リレーショナルDBにユーザー情報、RedisのようなKVストアにJSON形式のエッジリスト
- 問題点: グラフ密度(Graph Density)が増加するにつれてスケールが困難になり、コストが指数関数的に増加
第2世代:サードパーティSaaSグラフDB(2021年導入)
- メリット: 水平スケーラビリティを確保
- デメリット:
- ロングテールレイテンシ問題 — P95とP99がP50と比較して急激に増加
- 運用の不安定性 — 定期的な手動インスタンス再起動が必要
- 詳細なアクセス制御やパフォーマンスチューニングが不可能
- ベンダーロックイン
第3世代:自社管理型 JanusGraph + DynamoDB(現在)
- 特徴: 完全な内部管理型プラットフォームへ移行
- 主要な判断: JanusGraph(オープンソース分散グラフDB) + DynamoDB(ストレージバックエンド) + OpenSearch(インデックス)
# JanusGraph + DynamoDB設定例(核心概念)
# gremlin-server.yaml 設定ファイル
host: 0.0.0.0
port: 8182
scriptEvaluationTimeout: 30000
channelizer: org.apache.tinkerpop.gremlin.server.channel.WsAndHttpChannelizer
graphs: {
graph: conf/gremlin-server/janusgraph-dynamodb.properties
}
# janusgraph-dynamodb.properties
# ストレージバックエンドにDynamoDBを使用
storage.backend=dynamodb
storage.dynamodb.client.credentials.class=com.amazonaws.auth.DefaultAWSCredentialsProviderChain
storage.dynamodb.region=us-west-2
storage.dynamodb.prefix=airbnb_identity_graph
# インデックスバックエンドにOpenSearchを使用
index.search.backend=elasticsearch
index.search.hostname=search-cluster.airbnb.internal
index.search.elasticsearch.client-only=true
# キャッシュ設定
cache.db-cache=true
cache.db-cache-clean-wait=20
cache.db-cache-time=180000
実務のポイント: JanusGraphの最大の利点はストレージとコンピューティングレイヤーの分離です。DynamoDBのスケーラビリティと信頼性をグラフロジックレイヤーと分離することで、各レイヤーを独立してチューニングできます。日本国内でもDynamoDBの代わりにScyllaDBやCockroachDBをバックエンドとして採用する事例が増えています。

主要な最適化戦略:ロングテールレイテンシとの戦い
AirbnbがJanusGraphをカスタマイズした核心ポイントは以下の3つです。
1. トランザクション最適化
JanusGraphのデフォルトのロック機構はオーバーヘッドが大きいです。AirbnbはDynamoDBの条件付き書き込み(Conditional Write)とトランザクションAPIを活用し、データの整合性を保ちながらオーバーヘッドを大幅に削減しました。
2. 並列クエリ実行
特に**ハイファンアウト(High Fanout)**ノード(1つのノードに接続されたエッジが多い場合)で発生するパフォーマンス低下を解決するため、getMultiSlicesインターフェースを改善しました。
# Gremlinクエリ最適化例
# 非効率なPath step使用(低速)
g.V().has('user_id', 'U1234')
.repeat(out('HAS_DEVICE').simplePath())
.times(3)
.path()
# 最適化:Path stepを削除し、条件付きフィルターに置き換え
# Path stepはJanusGraphでバッチ処理されないためパフォーマンス低下の原因に
g.V().has('user_id', 'U1234')
.repeat(out('HAS_DEVICE').dedup())
.emit()
.times(3)
.dedup()
.fold()
3. 可観測性の確保
オープンソース版で不足していた分散トレーシング(Distributed Tracing)を内部フォークに統合しました。これにより各クエリのボトルネックを正確に特定できるようになりました。
移行結果:数値で見る改善効果
| 指標 | 移行前(サードパーティSaaS) | 移行後(自社管理型) | 改善率 |
|---|---|---|---|
| P99読み取りレイテンシ | 2,500ms | 450ms | 82%削減 |
| 書き込みQPS(最大) | 1x(基準) | 10x | 1,000%増加 |
| 運用介入の必要性 | 定期的な手動再起動 | 自動スケーリング | 運用負荷ゼロ |
| 障害対応時間 | ベンダー依存(平均4時間) | 内部対応(平均30分) | 87%短縮 |
日本市場における適用文脈
- 日本の大規模ECプラットフォームでも、類似のグラフベース不正検知システムの導入が増えています。特にメルカリ、楽天などでNeo4jではなくJanusGraphを検討する理由はコスト効率にあります。
- 注意点: JanusGraphはコミュニティ版のアップデート周期が不定期です。Airbnbのように内部フォークを管理するエンジニアリングリソースがない場合は、Managed Neo4j(AuraDB)やAmazon Neptuneを先に検討するのが現実的です。

まとめ:学べる7つの教訓
Airbnbの事例から得られる実践的な教訓をまとめます。
- ベンダーロックインはリスク: 初期は便利でも、規模が大きくなるにつれて制御不能になります。
- ストレージとコンピューティングの分離は最善手: JanusGraph + DynamoDBの組み合わせは各レイヤーを独立して最適化できる柔軟性を提供します。
- ロングテールレイテンシは「死の曲線」: P50だけを見ず、P95、P99も同時に監視しましょう。
- Gremlinクエリは想像以上に難しい: 同じクエリでもエンジンによってパフォーマンスが大きく異なります。必ずShadow Trafficテストを実施してください。
- オープンソースは「そのまま」使ってはいけない: 必ず内部要件に合わせてカスタマイズする覚悟が必要です。
- 可観測性は選択ではなく必須: 分散トレーシングなしでグラフDBを運用するのは盲目的運転と同じです。
- マイグレーションは「クエリ互換性」だけが全てではない: 同じGremlinクエリでも内部最適化戦略が異なればパフォーマンスが完全に変わります。
次のステップとしての学習方向
- 実務にすぐ適用したい方: JanusGraph公式ドキュメントで「Storage Backend」設定を優先的に学習してください。
- グラフモデリングを深く学びたい方: 「Labeled Property Graph Model」と「RDF」の違いを理解することが重要です。
- 日本コミュニティ: 国内ではJanusGraphに関する日本語資料が不足しています。Airbnbのアーキテクチャ判断プロセスを参考に、Airbnbマルチプロダクトデータアーキテクチャフレームワークと併せてご覧いただくとより深い理解が得られます。
最後に: グラフDBは銀の弾丸ではありません。「関係性」が核心となるドメイン(不正検知、レコメンデーション、ナレッジグラフ)に限定して導入し、単純なCRUDにはRDBMSをそのまま使用するのが賢明な選択です。