KEMBAR78
MOVで実践したサーバーAPI実装の超最適化について [MOBILITY:dev] | PPTX
MOVで実践したサーバーAPI実装
の超最適化
株式会社ディー・エヌ・エー
オートモーティブ事業本部
スマートタクシー事業部システム開発部 部長
惠良和隆
自己紹介
2002年新卒でコンシューマゲーム開発会社に入社し、家庭用ゲーム機向けゲームタイトルの
開発に携わりながら、開発環境やフレームワークの構築に従事する。
2013年10月、ゲーム以外のBtoCサービスに携わるべくDeNAに中途入社する。しかしながら、
スマホ向けゲームのネイティブアプリ化待ったなしの状況において、基盤技術の構築とゲーム
開発力向上のためにゲーム事業にフルコミットすることからスタートする。
2018年7月、オートモーティブ事業本部に異動。AWS IoTを使ったプローブデータ収集システ
ムの開発・保守、地図データ整備、移動体情報配信システムの開発などに携わる。
2019年4月MOVのシステム開発担当部門の部長に就任し、マネジメントしつつ自らも開発に
携わる(現在は、APIサーバーと乗務員アプリ)。
惠良 和隆(えら かずたか)
3
みなさん、
タクシーに乗ってますか?
MOVとは?
• DeNAが提供するタクシー配車アプリ
• ITのチカラでタクシー利用を進化させるサービス
• 神奈川、東京、大阪、京都にサービス展開
• 近くのタクシーがすぐに来る
• 車輌ステータスのモニタリングすることにより、
呼べるタクシー車輌を選んで配車している
4
※MOVのシステムの詳細は、DeNA TechCon2019 の
『次世代タクシー配車サービス「MOV」を支える車載ハードウェアとソフトウェアの話」
を参照ください
5
MOVでは、呼び出すタクシーを
どのように選択しているのか?
(1) ユーザーの指定した迎車地に近い車輌を見つける
6
X m
(2) 呼べる状態の車輌のみを選別
7
例:すでにお客様が乗
車中の車輌を除く
(3) 各車輌から迎車地までの到着予想時間を算出
8
10分
3分
12分
4分
8分
7分
(3) 各車輌から迎車地までの到着予想時間を算出
9
10分
3分
12分
4分
8分
7分
最も早く到着する車輌
に配車依頼を送信する
呼べる状態の車輌とは?
• 空車であること
• タクシーの所属する交通圏に迎車地が含まれていること
• 休憩中など、MOV配車受付停止中でないこと
• 駅などのタクシー乗り場で、お客様を待つ列に並んでいな
いこと(駅待ちしていないこと)
10
呼べる状態の車輌とは?
• 空車であること
• タクシーの所属する交通圏に迎車地が含まれていること
• 休憩中など、MOV配車受付停止中でないこと
• 駅などのタクシー乗り場で、お客様を待つ列に並んでいな
いこと(駅待ちしていないこと)
11
呼べる状態の車輌とは?
• 空車であること
• タクシーの所属する交通圏に迎車地が含まれていること
• 休憩中など、MOV配車受付停止中でないこと
• 駅などのタクシー乗り場で、お客様を待つ列に並んでいな
いこと(駅待ちしていないこと)
12
駅待ちしていないことをどうやって判断するか?
タクシー乗り場を含む特定エリア内にいるか?
13
このエリア内にいる場合は、
駅待ちしていると判断する
©OpenStreetMap contributors
14
タクシーを呼べない場所があるって
ご存知ですか?
タクシーを呼べない場所
• そもそも車が進入できない場所
• 車輌侵入禁止区域
• 歩行者天国となっている道路
• お祭りや花火などのイベントによる交通規制区域
• 駅や空港、病院などの施設のタクシー乗り場
• すべてのタクシーが乗り入れることが出来ない場所もある
• 交通渋滞緩和のための自主規制
• お客様を乗せる順番は、タクシーの並び順に従うのが通常であり、
呼ばれたからと言って列に並ばずにお客様を乗せるとトラブルの
原因になりかねない
15
MOVでの対応は?
• 迎車地点として設定できないようにしている
16
アプリ内で迎車地として
指定できないエリアを表
示して、その旨を利用者
にお知らせする
タクシー配車における必須処理
• ポリゴンで定義された配車禁止エリアに、タクシー車輌や
迎車地が含まれるかどうか?
• そもそも迎車地がサービス圏内かどうか?
17
Point-In-Polygon判定
ポリゴンの中に任意の点が含まれるかどうか
本日お話する内容
• タクシー配車における必須処理
• Point-In-Polygon判定のための方法
• 超最適化の手法
• まとめ
18
Point-In-Polygon判定の手法
• アルゴリズムには様々なものがあるが、いずれかを自前実
装する or 実装されたライブラリを利用する
• ElasticsearchのGeolocation機能を利用する
• PostGIS(PostgreSQLのExtension)の機能を利用する
• 様々なサービスが提供しているWeb APIを利用する
19
MOVでのPoint-In-Polygon実装(1)
• リリース最初期は、AWSのElasticsearch Serviceを利用
• Elasticsearchには、GIS向けの機能が提供されている
• データタイプ:geo-point、geo-shape
• geo-shapeとgeo-pointが交差しているかの判定や、両者の距離
などをクエリで利用できる
• タクシー車輌位置を示すgeo-pointと交差するgeo-shape
をもつドキュメントがインデックス内に存在するかどうか
• ユーザー位置を示すgeo-pointから半径Xm以内の距離にあ
るドキュメント(geo-shape)を取得する
20
21
その後・・・
22
Point-In-Polygon判定に
AWS Elasticsearch Service
を利用するのは止めた
MOVでのPoint-In-Polygon実装(1)
• MOVの構成(当時)
23
AWS IoT Core Amazon Elasticsearch
Service
Service API
App Engine
MySQL
Cloud SQL
AWS Cloud
Android AndroidiOS
乗務員アプリ ユーザーアプリ
MOVでのPoint-In-Polygon実装(1)
• MOVのサービスAPIは、GCP環境(GAE/go)で動作して
おり、AWSのマネージドサービスであるElasticsearch
Serviceにアクセスする際に、必ずAWS Sigv4の認証が入
り、GCP-AWS間のレイテンシも存在する
(インスタンス規模の割にスループットが出なかった)
• Elasticsearch Serviceはマネージドサービスではあるが、
オートスケールしてくれないので、急激な負荷の上昇など
に対応できない
24
25
代替手段として採用したのは・・・
26
MOVでのPoint-In-Polygon実装(2)
27
• PostgreSQLの拡張機能であるPostGISを利用する
• PostgreSQL@CloudSQLはPostGISをサポート
• Point-In-Polygon以外にも多種多様なGISオペレーション
をSQLで実現できる
• 単純なQPS性能はElasticsearchよりもかなり高い
• フロントエンドとしてGAE/pythonを採用し、APIとして
利用できるように実装
MOVでのPoint-In-Polygon実装(2)
• 性能評価結果
• クエリ実行元は、Google Compute Engine上のインスタンスとする
• クエリ内容はどちらも同様の結果が得られるものとする
• 試験対象インスタンスのCPU負荷が65%程度になるようにクエリを実行する
28
Product Instance Type vCPU Memory
[GB]
QPS Response
Time [ms]
Elasticsearch c4.2xlarge
.elasticsearch
8 15 1615.85 6.189
PostGIS N/A 16 15 46303.36 0.66
1インスタンスあたりの性能
MOVでのPoint-In-Polygon実装(2)
• 性能評価結果
• クエリ実行元は、Google Compute Engine上のインスタンスとする
• クエリ内容はどちらも同様の結果が得られるものとする
• 試験対象インスタンスのCPU負荷が65%程度になるようにクエリを実行する
29
1インスタンスあたりの性能
PostGISのvCPUを考慮しても、QPSとResponse Timeが圧倒的
Product Instance Type vCPU Memory
[GB]
QPS Response
Time [ms]
Elasticsearch c4.2xlarge
.elasticsearch
8 15 1615.85 6.189
PostGIS N/A 16 15 46303.36 0.66
30
その後・・・
31
(・・・まさか・・・ゴクリ)
32
Point-In-Polygon判定に
PostGIS
を利用するのは止めた
MOVでのPoint-In-Polygon実装(2)
• CloudSQLのPostgreSQLは、インスタンスのメモリ容量
が多いほど最大同時接続数が増加する
• CloudSQLインスタンスのメモリが少ないと、 GAE側でイ
ンスタンスがスケールしてもCloudSQLの最大同時接続数
に到達してしまい接続できなくなる
• 結果として、大量のメモリを積んだインスタンスを複数台
使用しなければならなくなり、コスト高に・・・
33
MOVでのPoint-In-Polygon実装(2)
• CloudSQLのPostgreSQLは、インスタンスのメモリ容量
が多いほど最大同時接続数が増加する
• CloudSQLインスタンスのメモリが少ないと、 GAE側でイ
ンスタンスがスケールしてもCloudSQLの最大同時接続数
に到達してしまい接続できなくなる
• 結果として、大量のメモリを積んだインスタンスを複数台
使用しなければならなくなり、コスト高に・・・
34
PostGISのせいじゃないじゃん・・・
MOVでのPoint-In-Polygon実装(2)
• PostGISを使った判定にも性能的な課題はあった
• 交通圏のポリゴンデータが多頂点ポリゴンとなっており、
PostGISでもPoint-In-Polygon判定だけで数msかかって
いた
35
特別区・武三交通圏(東京都)
36出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
京浜交通圏(神奈川県)
37出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
MOVでのPoint-In-Polygon実装(2)
• PostGISを使った判定にも性能的な課題はあった
• 交通圏のポリゴンデータが多頂点ポリゴンとなっており、
PostGISでもPoint-In-Polygon判定だけで数msかかって
いた
• PostGISが内部で利用しているGDALを直接利用して判定
しても1ms以上かかることが判明した
38
MOVでのPoint-In-Polygon実装(2)
• Point-In-Polygon判定は、ユーザーアクセス数が増加する
とそれに比例して増加するため、一定以上のキャパシティ
が必要だが、インフラ費用を無駄に消費するのは避けたい
• 数ms程度なら十分高速な部類ではあるが、様々なAPIで利
用されるものであり、より高速にするとサービスAPIのレ
イテンシを削減できる
• 何より・・・
元ゲーム開発者としては、1msでも十分遅い!!!!
39
40
そして、超最適化へ・・・
MOVでのPoint-In-Polygon超最適化
• GDALを利用して判定する
• ただし、最適化のための事前処理を行う
41
事前処理①:Polygonの細分化
42
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理①:Polygonの細分化
43
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理①:Polygonの細分化
44
絶対に交差する
交差する
かもしれない
絶対に交差しない
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理①:Polygonの細分化
45
切り出した小さなポリ
ゴンとの判定を行う
交差する
かもしれない
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理①:Polygonの細分化
46
圧倒的に頂点数が削減されるので、計算量も激減する
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理①:Polygonの細分化
• ポリゴンを一定サイズのメッシュで分割し、各メッシュに
以下の情報をもたせる
• 絶対に交差するかどうかのBOOL値
• 交差するかもしれないメッシュは、切り出したポリゴンデータ
• 絶対に交差しないメッシュに関してはデータを持たない
• メッシュのIDと上記の情報のマッピングデータを事前計算
• 分割に使うメッシュの大きさはポリゴンのサイズに合わせ
てアダプティブに設定
• MOVでは地域メッシュを使って分割
47
事前処理②:ポリゴンのクラスタリング
• 交通圏以外のポリゴンは小さいけど大量にある
48
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理②:ポリゴンのクラスタリング
• どのポリゴンがどのメッシュに含まれるかを事前計算
49
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
事前処理②:ポリゴンのクラスタリング
• どのポリゴンがどのメッシュに含まれるかを事前計算
• ポリゴンが含まれるメッシュIDの配列をポリゴン情報に
含める
50
MOVでのPoint-In-Polygon超最適化
• GDALを直接利用して判定する
• ただし、最適化のための事前処理を行う
• 事前処理を行ったデータをすべてメモリにロードすることで全
計算をオンメモリで処理する
(protocol buffers形式のバイナリファイルをGCSに配置)
• 実装言語はgolang
• GDALをgolangで使用するためには、cgoが必須
⇒GAE/goは諦める
• GKE上にgolang実装されたWebサーバーを構築
51
MOVでのPoint-In-Polygon超最適化
• インフラ構成
52
Kubernetes Cluster
Container Engine
Ingress
Cloud Load Balancing
Preprocessed Data
Cloud Storage
Polygon Meta Data
Cloud SQL
Service API
App Engine
MOVでのPoint-In-Polygon超最適化
• 性能比較(交通圏判定API)
53
MOVでのPoint-In-Polygon超最適化
• 性能比較(交通圏判定API)
54
MOVでのPoint-In-Polygon超最適化
• 性能比較(配車禁止エリア判定API)
55
MOVでのPoint-In-Polygon超最適化
• 性能比較(配車禁止エリア判定API)
56
まとめ
• データに適切な事前処理を施すことにより、超効率的な
Point-In-Polygon判定処理を実装した
• 全データをオンメモリとすることで、交通圏判定や配車禁
止エリア判定を超高速化できた
• 実行性能が数百倍になったことでインスタンスあたりの性
能キャパシティが大幅に拡大した
• 結果として、GAE/goほどのスピンアップ速度がなくても
負荷上昇に十分耐えられるシステムになった
57
58
ご清聴ありがとうございました。

MOVで実践したサーバーAPI実装の超最適化について [MOBILITY:dev]