同セッションでは、ギットハブ・ジャパン合同会社のSongmuさんに、この四半世紀でデータストアの定番がどのように移り変わってきたかを、memcachedからKVS戦国時代、そしてOSSのRDBMS隆盛に至るまで、時代背景やハードウェア制約の変化と絡めてお話しいただきました。ぜひ本編のアーカイブ動画とあわせてご覧ください。
Songmu:今回は「Web系OLTPにおけるデータストア技術選定変遷の私感的史観」という長いタイトルでお話をさせていただきます。以前からお話ししたかった内容だったので、いい機会なのでまとめました。
まず前段として、OLTPとOLAPという2つの分類があります。OLTPはOnline Transaction Processingの略で、リアルタイム性が求められる処理に使うデータストアの特性です。Webサービスの裏側のメインのデータベース(DB)はこうした特性のデータストアで構成されていて、今回お話しするのは主にこちら側です。一方のOLAPはOnline Analytical Processingの略で、いわゆるデータウェアハウスですが、こちらは今回のスコープ外となります。
今の自分のスタンスとしては、やはりRDBMSをちゃんと使えば大抵のことはできますし、かなりのアクセスは捌けると考えています。いたずらに分散したり複数のミドルウェアを併用すると逆に複雑になってしまいます。RDBMSで足りない部分をRedisで補うのが好きで、たまに使ったりもします。分析系はBigQueryを使うことが多いです。最近だとChatGPTのPostgreSQLのスケーリングの話も話題になりましたが、あの規模でも書き込みのメインのPostgreSQLは1台という形でやれているそうです。RDBMSをちゃんと扱うことが基本的には大事だと考えています。

人類はSQLから逃れられない
もうひとつ、人類はSQLから逃れられないと思っています。SQLに好き嫌いはあると思いますが、もはやエンジニアだけでなく、データアナリストやリサーチャーにとっても重要な汎用スキルになっています。例えば英語は自然言語としてあまり出来のいい言語ではないと思いますが、エスペラント語のようにもっと人工的に考えられた言語があっても結局みんな英語を使ってしまいます。それに似た話だと感じています。NoSQLを含むいろいろなデータストアが、後付けでSQL的なインターフェースを提供してしまうのもそうした流れのひとつではないでしょうか。
残念ながら人類には、置き換えが望まれるのだけれども現実的には困難な技術がいくつかあると思っています。シェルスクリプト、C言語、正規表現、そしてSQLもその中に入るのではないかと感じています。最近ではYAMLもそうかもしれません。
このトークでは、これまで自分が経験してきた時代の変遷の中で、データストア選定がどのように変わってきたかをいくつかの切り口でお伝えします。
分散メモリキャッシュが必須だった時代
Web 2.0時代の到来とハードウェア制約
2005年頃、もう20年前の話になりますが、Web 2.0の時代がありました。CGM(Consumer Generated Media)の広がりによって、それまでサーバー1台でWebサービスやシステムを作っていたところに、突然何万人、何十万人、100万人とアクセスするようなサービスを運用する局面が増えてきました。それまでと桁の違うアクセスを捌く必要性に直面し、サーバーを複数台構成にしたり。可能なら安く済ませたい、OSSで済ませたいという話も出てきました。SIer方面ではクライアントサーバーやVBで作っていたアプリをWebアプリ化していく流れもありました。当時のキーワードとしてはC10K問題やLAMPなどがありました。
この頃からアーキテクチャも変化してきて、三層アーキテクチャと呼ばれる複数台構成が当たり前になりました。前段にプロキシサーバーとしてApacheなどを立て、その裏側にアプリケーションサーバー、一番後ろにDBがいる構成です。それまでデータベースと言えば商用の高価なものか、WebサービスであればファイルやいわゆるDBMを使うという選択肢しかなかったところに、MySQLやPostgreSQLといったOSSも使えるのではないかと言われ始めた時代です。
当時はハードウェアの制約がありました。今は64bit OSが主流ですが、当時は32bit OSが主流で、命令セットの関係上メモリ空間を4GBまでしか持てません。実際はもっと少ないです。メインのデータストレージもハードディスクが主流で、SSDではなかったので遅い。1台のサーバーのメモリにサービス全体の主要データを載せることも難しく、ハードディスクにデータを置いてそれを都度読み込ませたらアクセスを捌けない状態でした。
データベースとキャッシュサーバーの併用構成
そのため当時は、データベースとキャッシュサーバーの併用構成が大きめのサービスでは取られていました。データベースにコアデータを持ちつつ、キャッシュサーバーに分散させます。当時よく言われていた言葉として「DBにアクセスが行ったら負け」があります。キャッシュを適切に温めておいてうまく捌きましょう、ということです。「スワップ使ったら負け」とも言われていました。メモリから溢れてスワップに入ってしまうとハードディスクアクセスになり、リクエストに対してレスポンスが追いつかなくなってサービスが止まってしまうこともありました。
分散メモリキャッシュは、サービスの主要データを複数台のキャッシュサーバーに分散する手法です。1台で上限4GBしかデータを持たせられないので、複数台にデータを持たせてメモリに置いておき、なるべくそこからデータを取るようにしていました。キャッシュサーバーの制約として、永続化は行わず、ミスヒットも基本的には許容します。サーバーを入れ替えたり再起動したりすればデータは揮発してしまいますし、メモリサイズを超えてキャッシュを作ろうとすれば使用頻度の低いアイテムが自動的に削除される仕組みです。

参考リンク:第1回 memcachedの基本 | gihyo.jp
今であれば1台のデータベースに何百GBとメモリを積めるので、データベース内にデータを保存してMySQLであればバッファプール上に適切に乗るように設計したり、PostgreSQLであればOSのファイルキャッシュに乗せてメモリからデータを取るようにすれば大体賄えます。しかし当時はそうした対応ができませんでした。
memcachedの登場と設計の妙
ここでよく使われたのがmemcachedです。今でも使っている方はたくさんいますが、2003年頃から存在しています。高速なインメモリKVSで、expireによる時限削除機能がありました。プロトコルがシンプルで優れていて、テキストプロトコルとバイナリプロトコルが用意されています。HTTPはプロトコルとしては優れているものの、特にテキストプロトコルだった時代は、小さいメッセージを細かく捌くにはあまり向いていませんでした。memcachedプロトコルはソケット上でやり取りするパケットがかなり小さく済むので、非常に効率的でした。
複数台並べてキャッシュサーバー群を構成するのがメインのユースケースですが、サーバー側は単純で、クライアント側に分散アルゴリズムを持たせる作りになっています。そのためキャッシュサーバーを動的に増減でき、スケールアウトが簡単です。当時はmemcachedを使っていると大規模サービスという雰囲気がありました。
memcachedはシンプルでありながら、ソフトウェア設計の宝庫のようなところがあります。メモリ内に効率よくアイテムを格納するSlabアロケーター、分散アルゴリズムであるConsistent Hashing、シンプルなプロトコル設計、そしてLRU(Least Recently Used)のような仕組みがきちんと機能するように作られています。

参考リンク:第4回 memcachedの分散アルゴリズム | gihyo.jp
Consistent Hashingはクライアント側でどのキャッシュサーバーにキャッシュを載せに行くかを決めるアルゴリズムですが、サーバーを増やしたり減らしたりしてもキャッシュの再配置が最小限で済むように設計されています。
利用局面の変化
ただ結局、ハードウェアが進化していく中で、分散キャッシュとしてのmemcachedの利用局面は減ってきました。64bit OSが当たり前になったり、SSDが普及したり、RDBMSの機能が充実してきてコミュニティでも設計ノウハウが共有されるようになり、キャッシュで頑張らなくても何とかなるケースが増えたのです。Redisのような新しい選択肢の台頭もあります。つい最近、Google CloudのMemorystore for Memcachedの非推奨化が話題になりましたが、今の時代をよく表していると感じます。ただし、マルチコアが使えてシンプルで高速であるという利点は健在で、例えばNetflixはまだまだヘビーに使っていてスポンサーもしています。
技術の進歩により、複雑なアーキテクチャを取らなくてよくなったというのはよくある話です。DBのシャーディングもかつては頑張ってやる時代がありましたが、やらなくてよくなった。いい時代になりました。
余談ですが、memcachedの作者であるBrad Fitzpatrickさんは10代でLiveJournalを起業し、その後Six Apartに吸収され、GoogleでGoのHTTPパッケージ周りの開発をし、2019年にTailscaleを起業しています。ちゃんとソフトウェアで勝負し続けている姿がかっこいいですし、かくありたいと思います。『Coders at Work』に彼の20代の頃のインタビューが載っていて、おすすめの本です。
アドテクやソシャゲにおけるKVS戦国時代
2010年前後には、アドテクやソーシャルゲームにおけるKVS戦国時代がありました。この頃の時代背景として、アドテクではハイスループットが求められていました。いろいろなサイトに広告が載っているため容赦なくアクセスが来て、それを高速に捌く必要があります。アクセス自体は比較的シンプルなもので済みますが、RDBMSでは間に合わないため、KVSをメインのストレージとして運用することがよくありました。memcachedは優れていたものの、メモリキャッシュのみだったため、ディスクに永続化できるKVSも求められるようになりました。
そこでmemcached互換のKVSがたくさん作られました。memcachedプロトコルはシンプルでサーバー実装がしやすい上、クライアント側も既存のライブラリをそのまま流用できます。そのため差し替えの手間が少なく済みました。具体的にはKyoto Tycoon(2009-)、世界的に使われているCouchbase(2012-)、cybozu/yrmcds(2013-)、gree/flare(2008-)などがあります。
MySQLにKVS的なインターフェースを生やす試みも盛んに行われていました。奥 一穂(kazuho)さんのアイデアによるmycached、MySQL公式のInnoDB memcached plugin、DeNAで使われていたHandlerSocketなどです。
Kyoto Tycoonと日本のKVS文化
Kyoto Tycoonは日本でかなり使われていたKVSです。平林 幹夫さんが作られていたもので、元々Tokyo Cabinet、Tokyo Tyrantというものがあり、これもアドテクでよく使われていました。ディスク永続化とレプリケーション機能を備えたmemcached互換KVSです。DBMというファイルの実装とサーバー実装が分離された設計になっていて、Tokyo CabinetやKyoto CabinetがDBM実装、Tokyo TyrantやKyoto Tycoonがサーバー側の実装です。かなり良いものでしたが、メンテナンス体制の問題もあり、今では使っているところは減っていると思います。
最近では平林さんの最新作として、2020年頃からtkrzwが作られています。これはDBMやKVSへの愛の集大成のようなもので、ブログ記事に設計思想がいろいろ書かれていて読み応えがあります。
Redisの台頭
Redisは2009年頃に出てきて、2010年以降に大きく台頭しました。memcached互換ではなかったのですが、勝ち残ったKVSだと思います。単なるKVSではなかったところに強みがありました。その頃になると単なるKVSはそれほど必要とされなくなっていましたが、Redisはオフィシャルでは“in-memory data structure store”と呼ばれていたように、プログラミング言語内のデータ構造に近い形で格納できるメリットがあります。Sidekiqが有力な利用例としてあったことも、広く受け入れられた要因です。
日本のコミュニティでRedisが流行ったのはISUCONの影響もあると個人的に思っています。おそらくISUCON2の時です。自分もfujiwara組にいて優勝した時のことですが、チームメイトのtypesterさんがRedisを突然入れて、それがかなり決定打になって優勝しました[1]。当時はtypesterさんがRedisを「とても良い」と言っていて、周りが本当に?と言っていた時代でしたが、ISUCONで実際に勝ったのでその評価が一変しました。なお、その後のISUCON5でもfujiwara組で出ていますが、予選ではRedisを使い、決勝ではmemcachedを使うといった使い分けをしていて、場面に応じた選択が大事だったりします。
筋の良い技術が生き残るとは限らない
筋の良い設計やmemcachedプロトコルのようなものも、時代の変化とともにこだわる必要がなくなることがあります。優れた技術が必ずしも生き残るわけではないという面もあり、Tokyo TyrantやKyoto Tycoonはとてもいい技術だったにもかかわらず、使われ続けたわけではありません。
典型的な話として、kazuhoさんの昔の発表があります。kazuhoさんが元々MyCachedというMySQLにmemcachedプロトコルを生やすものを作っていたにもかかわらず、DeNAの樋口さんが開発した後発のHandlerSocketの方が使われるようになり、少し残念な思いをしたという話です。ソフトウェアは使われてこそだし、普及活動をしてこそだという内容で、共感できる部分です。

参考リンク:オープンソース開発者がDeNAを選ぶ理由
OSSのRDBMS隆盛
2010年から2015年頃にかけて、堅牢なRDBMS開発の必要性が高まってきました。時代背景としてソーシャルゲームバブルがあり、世の中のシステムに対する要求が上がったことや、OSSの機能面での下地が整ってきたことがあります。RDBMSをちゃんと使いましょうという意識が広がり、そうしないとアイテムを間違って配ってしまったり消えてしまったりして大変なことになります。プレゼント機能を悪用してアイテムを無限に複製できるような事例が話題になったこともありました。OSSのRDBMS機能がこの頃充実してきて、2010年頃にMySQLにやっとトランザクションが標準で入ったり、PostgreSQLにレプリケーション機能が入ったりしました。
WebシステムにおけるMySQLとPostgreSQLの立ち位置
当時の状況としては、WebシステムではやはりMySQLが人気でした。高速で分散しやすく、主にKVS的な用途として使われていました。特にMySQL 4.0とMyISAMの時代です。SIerの現場ではPostgreSQLも人気で、SQL機能が充実していたり、商用データベースからの乗り換えだとMySQLでは使い物にならないのでPostgreSQLを使うという状況がありました。
LAMPという言葉を覚えている方も多いと思います。2000年代にWebサービスを構築する際の定番OSS技術スタックで、Linux、Apache、MySQL、P言語を指す呼称です。LAPPという言葉もたまに使われていましたが、基本的にはLAMPと言われることが多く、それぐらいMySQLが世界的にも人気でした。ちなみに、LAMPという言葉は1998年頃にドイツで提唱されたのが起源だそうです[2]。
当時はシャーディングの需要もありました。それまでのWebサービスは基本的に読み込みメインだったのでキャッシュにうまく逃がせばよかったのですが、ソーシャルゲームなどではアクセスの度に書き込みが走りまくる作りなので、書き込みを分散させたいということでシャーディングが使われることもありました。
MySQLが好まれた技術的な理由
この頃MySQLが好まれた理由としては、スケールアウトの容易さ、高速なフェイルオーバーの実現、運用ノウハウやエコシステムの充実、メッセージパイプラインとしての活用、そしてMySQL 5.x以降でInnoDBを使えば比較的ちゃんとしたDB設計ができるようになったことなどがあります。
レプリケーションは、リアルタイムにほかのサーバーにデータを同期するシステムで、冗長構成やリアルタイムな切り替え処理を実現するために必須の機能です。MySQLには2000年頃から存在していて、かなりのキラー機能でした。PostgreSQLは2010年頃からしかサポートしていなかったので、10年ほど遅れていたことになります。MySQLはプライマリーのDBサーバーがダウンした時にリアルタイム切り替えができましたが、PostgreSQLはバックアップからリストアするしかなかった時代です。

MySQLのレプリケーションは割り切った作りになっています。ノード間のデータ整合性を頑張って保つというよりは、実は単なるデータリレーです。データの不整合を意図的に作り出すこともでき、例えばレプリカ側でインデックス定義を変えて書き込みと読み込みで使うインデックスを使い分けたり、別のストレージエンジンを使ったりできました。バージョンを変えることもできたので、レプリカのバージョンを高くしておいて切り替えることでバージョンアップに利用できましたし、レプリケーションを数珠つなぎにして複雑なパイプラインを構築することも可能でした。
高速なコネクション確立と都度接続のメリット
MySQLはデータベース接続が高速でした。MySQLはコネクションがスレッド管理されているのに対し、PostgreSQLはプロセスで管理しているため、接続時にプロセスをフォークして新しいプロセスを作る分のオーバーヘッドがあります。接続が早いので、Webアプリケーションとデータベース間はユーザーリクエストが来るたびに接続して処理し、終わったら切断する都度接続でも問題ないとされていました。特に同一データセンター内であればそれで十分です。
これには大きなメリットがあります。PostgreSQLやJavaなどから使う場合は、プロセス内にコネクションプールを持ち、事前にいくつかコネクションを作っておくのが一般的です。しかしそうすると状態管理が発生し、構成が複雑になってしまいます。PHPやPerlのCGIのようにプロセス内に状態を持たせづらいアーキテクチャでは避けたいところです。
さらに、データベースのフェイルオーバーが起きた時にも高速な切り替えが可能です。コネクションプールを持っていると、プール内の接続が腐ってしまい、本来もう死んでいるサーバーに繋ぎに行こうとしてしまうことがありますが、都度接続であればDNSやVIPがうまく切り替わっていればすぐに対応できます。
当時よく使われていたMHAは、MySQLで冗長構成を組む際のフェイルオーバーを自動化する定番のソフトウェアでした。

プライマリーがダウンした時に数秒、カリカリにチューニングすれば10秒以内でセカンダリーをプライマリーに昇格できました。DeNA社はダウンタイムを削減するためにこれをカリカリにチューニングしていたので、逆にクラウド移行が遅れたという話も聞いたことがあります。
ストレージエンジンの柔軟性とその功罪
2000年代の全盛期にMySQLが使われていた頃は「MySQLはKVSである」と言われることもありましたが、ちゃんと使えると自分は思っています。
MySQLはストレージエンジンが分離されていて、柔軟に差し替えられる設計になっています。テーブルごとに変更可能です。現在標準のストレージエンジンであるInnoDBはトランザクションがサポートされています。その前に使われていたMyISAMはテーブルロックだけで、複数テーブルにまたがったトランザクションや行ロックがない比較的貧弱なエンジンでしたが、読み書きは早いという特徴がありました。そのほかにBLACKHOLEやSpiderなどもあります。BLACKHOLEはディスクにデータを記録しないストレージエンジンですが、レプリケーション用のバイナリログは記録するので、複雑なレプリケーションを組む際の中継用途やウォームアップなどに使えるユニークなエンジンです。
この頃よく使われたサードパーティのストレージエンジンとしてQ4Mがあります。MySQLでメッセージキューを実現するストレージエンジンで、kazuhoさんが作られたものです。当時日本のWeb企業で広く使われていました。
このように柔軟なストレージエンジン機構はMySQLの大きな特徴であり強みでしたが、Q4Mも今であれば専用のメッセージブローカーを使えばいいという話になります。ストレージエンジンが分離されているからAWSがAuroraのようなものを作りやすかったという面もあるのかもしれません。しかし逆に今はそれが足枷になっている部分もあると感じていて、密結合になっていた方がデータ制約を実現しやすい面もあります。実際、今はInnoDBがほぼ一択であり、各パブリッククラウドのMySQL互換エンジンはストレージエンジンの差し替え機構を提供していないため、その利点も活かせません。
パーティションとPostgreSQL優位の流れ
パーティションはデータベーステーブルを内部的に複数に分割する機能で、MySQLの方がサポートが早く2008年頃から使えました。PostgreSQLは2017年頃からです。ただし現状ではPostgreSQLも十分使えるようになり、パーティションテーブルの外部キー制約も張れるようになったので、機能的にはPostgreSQLが上回っている状況です。
時代としてはPostgreSQLが優位になってきていると自分も感じています。理由はいくつかあります。まず、クラウド化が進んだことで、アーキテクチャ上のMySQLの優位性があまり活きなくなりました。冗長構成やフェイルオーバー機能はPostgreSQLのレプリケーションでも実現できますし、パブリッククラウド上でそうした機能やバージョンアップ機能がちゃんと提供されているので機能差がなくなりました。ステートレスな都度接続アーキテクチャについても、同一データセンターという前提が崩れたため、コネクションプール管理がいずれにせよ必要になりました。柔軟なストレージエンジンというMySQLの武器も、パブリッククラウドでは差し替えできないので能力が制限されています。
コミュニティやエコシステム、開発体制についても、おそらく2010年頃から世界的にはPostgreSQLの方が好まれるようになってきたと思います。RailsがPostgreSQLを優遇するようになったのが大きい印象で、例えばHeroku標準のデータベースもPostgreSQLでした。OracleによるMySQL買収やMariaDBの分岐の混乱が指摘されることもありますが、個人的にはその影響の大きさについてはどうだろうと思うところもあります。OSS開発がコミュニティ主導か企業主導かは一概には言えませんが、この件がきっかけでMySQLから離れていった動きは実際にあるでしょう。そもそもRDBMSの機能的にはPostgreSQLの方が優位な部分がかなり多く、押し負けてきています。自分としてもMySQLはとても好きで、お世話になったミドルウェアですが、今使うならPostgreSQLを選ぶだろうと思っています。
まとめ
駆け足でしたが、時代の流れによって「正解」は変わってきます。技術がちゃんと進化して淘汰されていく面もありますが、偶然の要素や不可抗力的にボタンの掛け違いで方向が変わってしまうことも多いと感じています。その場その場でちゃんと選択をしつつ変化させていくこと、昔の当たり前に固執しないことが大事だと考えています。
データ設計はやはり重要で、データの読み書きの速度はユーザー体験に直結します。いい感じに隠蔽してくれるデータストアも増えましたが、裏側がどういう仕組みでやってくれているかを理解しておくことも大事ではないでしょうか。AIでも何でもそうですが、物理法則はねじ曲げられません。光の速度やストレージの読み書き速度は変えられないのです。どのように配置するか、どこに置くかはとても重要です。Rob Pikeさんの言葉に「プログラミングの中心はアルゴリズムではなくデータ構造」がありますが、今ではアルゴリズムはAIが書いてくれることもあるので、データ構造と計算量の理解がますます大事になってきていると思います。
アーカイブ動画・発表資料
イベント本編は、アーカイブ動画を公開しています。また、当日の発表資料も掲載しています。あわせてご覧ください。
▼動画・資料はこちら
※動画の視聴にはFindyへのログインが必要です。
-
「Redis布教活動報告 ISUCON 編 - unknownplace.org」 https://unknownplace.org/memo/2012/11/07/1/ ↩
-
「LAMP (ソフトウェアバンドル) - Wikipedia」 https://ja.wikipedia.org/wiki/LAMP_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%90%E3%83%B3%E3%83%89%E3%83%AB) ↩

