デジタルディスラプションを象徴する企業として、いまこの瞬間も破竹の勢いで成長を続け、交通サービスの世界を大胆に塗り替えているUber。未上場ながらすでに企業価値は6兆円を超えているとも言われており、世界最大のユニコーン企業として、その動向はつねに注目されつづけています。
クラウドやビッグデータ分析、オープンソースなど、最先端のITをフル活用し、ごく短期間で劇的にビジネスを拡大させたUberに対しては、やはり技術者からの強い関心があつまります。現在、1200名を超えると言われるUberのエンジニアたちは何をどんな環境で使い、どう動かしているのか ―Uberのエンジニアリングチームが公開している技術ブログ「Uber Engineering Blog 」は、Uberのエンジニアたちが現場でどんな課題に向き合い、どう解決しているのかを知るにはうってつけの情報ソースです。
7月27日、そのUber Engineering Blogにある"問題作"とも言えるエントリが投稿されました。「 Why Uber Engineering Switched From Postgres To MySQL(なぜUberエンジニアリングはPostgreSQLからMySQLに移行したのか) 」というタイトルにある通り、UberがデータベースをPostgreSQLからMySQLに移行した理由について詳細に書かれているのですが、全体的に「PostgreSQLではアーキテクチャに制限がありすぎてUberのシステムを支えきれない、MySQL+InnoDBに変えたら全部解決した」 というトーンで貫かれています。
これに対し世界中の開発者、とくに(当然ながら)PostgreSQL開発者から強い疑問と反論の声が聞こえてくるようになりました。同時に少なくないPostgreSQL開発者が「PostgreSQLはそんなに大規模システムには向かないのか…」「 あのUberがPostgreSQLはダメだと言っている」と不安な思いを抱いたのではないでしょうか。
そこで本稿ではPostgreSQLコミッタのひとりであり、 SRA OSS, Inc. 日本支社 取締役支社長 石井達夫氏にいただいたコメントを紹介しながら、件のブログエントリの問題点を探ってみたいと思います。
Uberの決断 ―PostgreSQLからMySQL+InnoDBへ
Uberは2014年から「Project Mezzanine」という名のプロジェクトの下で、モノリシックなPostgreSQLからMySQL+InnoDBへの移行を実施しています。この移行の最大の理由は「リアルタイムのシステムを支えるにはバックエンドとは別のスキーマレスなデータベースが必要」というものでした。2014年といえばUberの利用者が急激に増えていた時期でもあります。ドライバーがいつ、どこで、誰をピックアップし、どこまで乗せているのか、それらのトリップデータは頻繁な更新が要求され、しかもそのトラフィックは日に日に増えていきます。まさしくビジネスの拡大とともにデータが増大していく、という状況を地で行っていた真っ最中だったのでしょう。
当時、UberではシングルインスタンスのPostgreSQLがこれらのリアルタイムデータ処理に加え、バックエンド(ドライバーへの支払い、利用者への請求、詐欺対策、ユーザデータ分析など)のデータストアも兼ねていましたが、リアルタイムに処理すべきトリップデータがデータベース内に占める割合がその他のデータをはるかに上回るようになり、スケーラビリティやパフォーマンスで大きな支障が出るようになりました。
ここでUberはスケーラビリティ(シャーディング)をとくに重視した結果、MySQL+InnoDBをトリップデータを扱うためのデータストアとして選択し、約6週間の構築期間を経て2014年10月末に本番環境として稼働を開始、現在に至っています。Project MezzanineについてはすでにUber Engineering Blogで記事が公開 されているので、詳細はそちらをご参照ください。
Project Mezzanineの内容だけなら「膨大なトラフィック増加にともなうアーキテクチャの見直し」であり、「 シャーディング重視のNoSQLライクな実装が可能なMySQLのほうがピュアなRDBMSのPostgreSQLよりも、Uberの拡大路線にはあっていたのかも」であって、とくにとくにPostgreSQL関係者が目くじらを立てるようなこともありません。では7/27のエントリは何がPostgreSQL関係者の怒りを買ったのでしょうか。
Uberの言い分は妥当なのか?
このエントリでは冒頭で、「 PostgreSQLのアーキテクチャ」と題しつつ、PostgreSQLの技術的制限として以下の項目を挙げています。
非効率な書き込みアーキテクチャ
非効率なデータレプリケーション
テーブルコラプションの問題
レプリカにおける貧弱なMVCCサポート
新しいリリースへのアップグレードが面倒
冒頭からすでに全PostgreSQL開発者をわざと怒らせるように煽っている雰囲気を強く感じるのですが、つづけて「今回の記事はPostgreSQL 9.2での経験をベースに書いているが、以降のバージョンでもPostgreSQLのアーキテクチャはそれほど変わっていない。そしてPostgreSQL 9.2のアーキテクチャは基本的に(10年以上前にリリースされた)8.3から大きく変わっていない」と書かれています。さすがに10年前のアーキテクチャと変わっていない、と言われて心穏やかなPostgreSQL開発者はいないのではないでしょうか。
以降、PostgreSQLのアーキテクチャ、とくに書き込みの非効率性についての批判と、それと比較してMySQL+InnoDBがいかに効率的でUberのニーズにあっているかが延々と続くのですが、PostgreSQL開発者にとっては明らかに看過できないポイントが散見されます。そのいくつかについて、石井氏からいただいたコメントを紹介します。
石井達夫氏
[その1]Write Amplification ―実際に書き込んだデータ量よりも、ディスクやフラッシュに書き込まれるデータ量が増える問題
このブログエントリでは、PostgreSQLのインデックス更新の効率が悪いことが書かれています。その理由について「行の一部の列を更新した場合でも、すべての列に関するインデックスを更新しなければならないから」とあります。
たしかに、エントリ冒頭の例(人物データベースで、ファーストネームとラストネームが同一だが、生年が違う場合のレコード更新)に挙げられているテーブルを更新する限りはそうなってしまいますが、これはそのテーブルにおいてはすべての列にインデックスが貼られているからなのです。エントリではまったく触れられていませんが、PostgreSQLでは、インデックスが貼られていない列を更新する際に、該当列以外のインデックスを更新しなくて済む「HOT ( Heap Only Tuple) 」という機能がPostgreSQL 8.3から実装されており、すべての列にインデックスが貼られているわけではない現実的なケースでは、更新オーバヘッドを大幅に少なくすることができます。
このブログエントリの著者がHOTを知らなかったのか、それともUberではテーブルのすべての列にインデックスを貼る必要があるのかはわかりませんが、エントリ中でHOTにまったく触れなかったのは、正直片手落ちという印象があります。
なお、エントリで説明されているMySQLのインデックスの実装では、たしかにインデックス付きの列の更新は効率が良くなりますが、逆に検索時には、主キー付き以外の列でPostgreSQLの実装よりもオーバヘッドが増えます。主キー付き以外の列でも、必ず主キーを経由してアクセスしなければならないからです。
ちなみに、現在PostgreSQL開発者の間ではインデックスが付いている列を更新しても、それ以外の列のインデックスを更新しなくて済む改良が議論されています。これが実現すれば、( MySQLと違って)主キー経由のアクセスが必要ない検索高速性と、キー付き列でも高速更新ができるという、いいとこ取りのシステムができると期待されています。
[その2]レプリカにおける貧弱なMVCCサポート
このブログエントリで問題とされているケースの全部ではありませんが、多くのケースではPostgreSQL 9.1以降で実装された「hot_standby_feedback」という機能で解決できます。記事中でなぜ hot_standby_feedbackに触れていないのかは謎ですね。;p>
[その3]アップグレードが面倒
"Run a command called pg_upgrade on the master, which updates the master data in place. This can easily take many hours for a large database, and no traffic can be served from the master while this process takes place."
バージョンアップの際にpg_upgradeを使うと何時間もかかるということのようですが、pg_upgradeには--linkというオプションがあり、これを使うとデータのコピーが回避できるので、pg_upgradeの実行は短時間(数十秒から1分程度)で完了します。なぜこのオプションを使わなかったのかは、これまた謎です。
石井達夫氏による考察
このブログエントリ全体を読んでどういった感想をお持ちになったのか、あらためて石井氏に伺ってみました。
ブログエントリを通して感じた第一印象は「UberではPostgreSQLの使いこなしの技術が不足していたのではないか」ということです。これはHOTやhot_standby_feedbackに触れられていないことからも推測できます。
PostgreSQLに対する勉強不足でうまくいかなかったので、あまり深く考えずにまたMySQLに戻してみたら、たまたま彼らのユースケース(NoSQLっぽい使い方)にはMySQLが合っていた、ということなのではないかと想像しています。
それをそのとおりに素直に書けばよいものを、PostgreSQL vs. MySQLの構図にしてブログにしてみた、というのがよく理解できないところです。
石井氏のコメントからもわかるように、このブログエントリの著者はHOTやpg_upgrade --linkなど、PostgreSQL開発者なら知っていて当然の内容をあえて避けているように思えます。冒頭でわざわざ「PostgreSQLは8.3から基本的なアーキテクチャが変わっていない」と明言しているところからも、8.3でHOTが実装されたことを知っていながら本文ではわざとHOTに触れていないようです。「 ( ブログエントリ内で)例として挙げられているテーブルでは、全部の列にインデックスを貼ってあり、あえてHOTが効かないようにしているところに意図的なものを感じます」( 石井氏)
そのほかにもこのエントリにはPostgreSQLへの誤解を招きかねない表現が数多くあり、さすがに我慢できなくなったのか、何人かのPostgreSQL開発者がこれについての反論記事を書いています。彼らも石井氏と同様、HOTについての記述がないことを強く批判しています。
星の数ほどあるスタートアップの中でも、Uberほど劇的なスピードで成長した企業はほとんどありません。そしてあまりの成長の速さに、既存の環境が追いつかなくなりリプレースを余儀なくされるという事情も十分に理解できます。また、プロジェクトを率いるリーダーやCTOの好みで、採用される技術が左右されることも多分にあるでしょう。今回のように、スキーマレスなNoSQLでスケーラビリティを担保し、膨大なトラフィックをリアルタイムにさばきたい、というニーズならたしかにPostgreSQLよりもMySQLが向いているのかもしれません。
しかし、そうした事情があるにせよ、PostgreSQLに対するミスリーディングを"意図的"に誘発していると受け取られても仕方ない筆致の技術エントリ、もっとはっきりいえば「アンフェア」なスタイルの記事をUberが公式サイトで世界に向けてアップしたことには、やはり強い失望を覚えます。最先端テクノロジをもって急成長したUberだからこそ、テクノロジに対してだけは誠実であってほしいと、米国出張のたびにUberにお世話になっている筆者はひそかに願っています。