2006年、Hadoop黎明期とその衝撃

ここからはちょっと歴史の話です。タイムラインとしてはおおむねこんな感じです。

2003年から2018年、つまり今日までの話をしていきます。

主に分散システムのオープンソフトウェアとしての開発初期、黎明期から普及期の話。タイムラインとしてはそのあと、コンテナ化されたインフラストラクチャーの話に流れていきます。

まずHadoopの黎明期、これは明確に2006年なんですけれど、走りとしては、2003年と2004年にGoogleから大きな2つの論文がで出てきます。

1つはThe Google File Systemという、Googleの中で使われているGFSと呼ばれる分散ファイルシステム、分散ストレージの論文。もうひとつはその翌年に出てきたMapReduceで、どうやってGoogleの中で巨大なデータを処理するかというのかという論文。

2つ目がたしか、Jeff Dean伝説で有名なJeff Dean先生がファーストオーサーのやつですね。この2つが出てきて、Googleがどうやって検索エンジンの裏で巨大なデータ処理をやっているか、あるいは巨大なデータを維持しているかということがわかったわけです。

ただし、ソフトウェアの実装はない。Googleは、MapReduceの論文の中でSawzall言語を使ってやってるよ、みたいなことを言うんですけど、その言語の実装はどこにもない、みたいな感じで使えないわけですね。

みんなで「ああ、Googleはすごいんだな。Googleは世界の最先端を行ってるんだな」と思って指をくわえていたら、すごく勇気のあるYahoo!の人が「じゃあ作ってやろう」って言って、作って出てきたのがHadoopです。

バージョン0.1.0。これが2006年の4月1日。今見るとすごいですよねエイプリルフールの日ですね。そして、GoogleのGFSに対応する、Hadoop Distributed File Systemと呼ばれるものと、MapReduceの処理系の2つがふくまれた、Hadoop0.1.0というファーストリリースが出てきました。

アメリカのYahoo!からです。同じ年に出た論文には、Yahoo!は、300ノードのクラスタをデプロイしていて、そのうち188ノードを使って、1.8TBのデータを47.9時間かけてソートしたと書いてあります。

今から考えると、188ノード使って、たった1.8TBのデータを48時間もかけたの? という。今から見るとショボい。言っちゃなんですけど。

ただ12年前ですからね。当時はめちゃくちゃ画期的な出来事でした。これでついに我々もHadoop、使いやすい分散ファイルシステムとMapReduceのシステムが誰でも使えるようになったという画期的な出来事でした。

Hadoop 初期機能の内容

このあと、いろんな会社が一気にワーッと採用していって、その上に使いやすいエコシステムのソフトウェアを作っていって、Hadoopの1.0がリリースされたのが2011年12月。

5年ちょっとですね。この5年のあいだで、Hadoopというのは基本的にはほとんどのWeb、ほとんどのインターネット上の大きいサービサーに広まりました。2011年には僕ももうHadoopを使っていました。

Hadoopは0.13か0.14までいったんですけど、さすがに「0.いくつのまま上げ続けるのはどうかと思う」みたいなまっとうな意見の人が現れて。じゃあ1.0にしようかという記念バージョンみたいなやつが1.0です。つまりこのときには、もうみんなが使っているからメジャーバージョンにしようぜという、コンセンサスが取れるくらい使われていました。

たった5年でです。こういう時代でした。ただし、Hadoopの0.1.0。一番初期は、分散システムとしてはけっこうおそまつな代物でした。

機能の内容としては、なんかアプリケーションがデプロイされるので、それをMapReduceの論文に書かれているMapとShuffleとReduce、Shuffleって本当は一番大事なやつなんですけれど、MapReduceってShuffle書いてないんですよね。Map Shuffle Reduceだと長すぎるからだと思うんですけど。

MapとShuffleとReduceという処理に分解をして、その分解されたタスクをクラスター上に全部ばらまいて処理をさせる。

1つのクラスター上では、複数のジョブからばらまかれた大量のタスクが混在するので、そのタスクのあいだで処理の空間を分割してやらないといけない。処理内容がまざったり一方の処理内容がもう一方に影響を与えたりしたら困りますからね。

ということで、分割しないといけなくて、この分割をどうやってきたのというと、JVMのプロセスをタスクごとに立ち上げるという方法でした。けっこう豪快な方法ですけれども、実際にこれは動く方法です。

よいソフトウェアは使われる

あと、コンフィグレーションですね。そもそも、どういうタスクを行わなければならないのかとか、そのタスクはパラメーターとしてどういうコンフィグレーションを与えられているのかみたいなやつは、全部ジョブのデプロイのときに行われました。

つまり、「このジョブやってね」って言ってコマンドをぽんと叩いた瞬間に、コンフィグレーションは全部確定するという状態でした。データはHadoopからマスター上で作られたHDFSという分散ファイルシステムにすべて保存するというお約束ですね。

一方で、そもそもクラスター上にはどういうノードがいるのかは、なんと恐るべきことに、1枚のテキストファイルに書かれていました。

なので、ノード、コンピューターを入れ替えるときは、コンピューターを入れ替える作業をしたあとで、このテキストファイルを書き換えてクラスターを全部再起動するというのが、恐るべきHadoop0.1.0の世界でした。

また、マスターノードですね。どういう処理をどこにばらまいて、誰に実行させるというMapReduceのマスターノード、これをJobTrackerというんですけど。あとはHDFSのマスターノード、つまりどこのノードにどういうファイルのどういう切れっ端が置かれていて、どういうチェックサムを持っているはずだ、みたいなメタデータを全部持っているNameNodeという、マスターノードが2種類あったんです。

その2種類は両方ともクラスター上に1プロセスしか立ち上がってはいけない、ということになっていました。超わかりやすいSingle Point of Failure (SPoF)ですよね。こいつが落ちるとクラスターは死ぬ、みたいな感じで。

要するに、300ノード、クラスターがあって、そのうち299ノードは死んでも良いんです。299ノードはうまいこと他のノードが入れ替わって作業継続してくれるんですけど、そのうちの1ノード。

マスターノードは落ちた瞬間にクラスターが全部死ぬという、すごくわかりやすい、良い野趣にあふれたソフトウェアになっていました。

ただしこれでも、さっきも言ったとおりいろんな企業が一気に飛びついたように、こういう欠点があったにしても、実現される機能と性能が圧倒的だったんですねやっぱり。

これは忘れてはいけなくて、別にSPoFがあろうがどうだろうが、できるソフトウェアは使われるんですよ、結局。この例からわかる良い話だなと思います。

Hadoop2は汎用の分散処理のためのプラットホームに

一方、タイムラインを順に辿っていきますと、これが2006年ですね。ばーっと行って、2010年にHadoopの1.0が出るんですけれど、一方で、Hadoopの2。メジャーバージョン2が並行して開発が行われていました。

2.2.0というGenerally Available (GA)なリリースが2013年に出ます。この2.2.0というのがなんなのかというと、分散システムとして、Hadoopをもっとまともにしたものがいろいろ機能として入っているものです。

一番上にあるDAGというのは、MapReduce以外の処理モデルをいろいろサポートしようというもので、これは主に性能面の改善を図ったものです。

あと、機能としてマシンラーニングの機能とか、ライブラリーが乗ってきたりとかという。あとはHadoopのHDFS上にデータ、分散データベース、つまりGoogleのBigTableに相当するものを乗っけるHBaseというものが入ってきたり、あとはリアルタイムプロセシングですね。Apache Storm。

この頃はTwitter Stormかな。いや、Apache Stormというものが、Hadoopの上に乗るようになってきました。

つまりHadoopというのはもはや、MapReduceのためのクラスター、あるいはミドルウェアではなくて、汎用の分散処理のためのプラットホームになったと言って良いと思います。Hadoop2で。

Hadoop、どう変わったか

いろんなものに使われるようになったので、当然ですが安定性とスケーラビリティが非常に重要になります。「1ノード落ちたから全部止まりましたと」言って、いつまでもみんな許してくれるほど世の中甘くないので。ちょっとがんばってどうにかしようと、すごく直すんですね。

1つはコンフィグレーションの話。コンフィグレーションがジョブのデプロイ時にしかまけないのをどうにかして直す必要がある。ノードが死んだり、あるいはなんらかの状況が変わって、各ノードが動作を変えないといけなくなったときに、そういった状況を動的に更新できるなんらかの基板が必要になるということです。

もう1つは、ノードのリストですね。ノードのリストがテキストファイルに書かれているち牧歌的な時代は最初の1年くらいで終わって、「こんなんで使えるわけねえだろ」みたいな文句が当然のように噴出しました。

これは実際にHadoopの1.0ではもう直ってるんですけれど、ノードリストをどうにかしないといけない。つまりどういう計算リソースが、どこでクラスター内のどこで動いているかの管理ということですね。

もう1つは、SPoFが当然いっぱいあるので、これをどうにかしないといけない。「さっさと直せや〜」という話があっちこっちであるわけですね。

Hadoop2が分散システムとしてどういうものになったかというと、JVMのプロセスで分割するという処理の分割自体は変わっていません。ただ、一番最近のHadoopになってからは、実はDockerコンテナを処理タスクとして使うということができるようになったらしいです。僕もちょっとまだ試したことないんですけれど。

聞く人に聞くと、「いや〜、とりあえず、できるようにしてみたよね」みたいな。できるようにしとくと、「プレスリリースが書けてうれしいよね」みたいな話なのではないか、と言われています。風のうわさです。

一方で、コンフィグレーションに関しては、ジョブのデプロイ時に、おおむね配るというのがそのままなんですが、プラスしてZooKeeperという基盤がHadoopで非常によく使われるようになってきています。

これが、分散キーバリューストアと呼ばれるものです。プラス、Leader electionの機能も持っています。

こういったZooKeeperと呼ばれるものが入ってきた。細かくはあとで説明しますが、コンフィグレーションの管理やステートも管理が行われるようになってきました。ファイルシステムはHDFSのままです。

ノードの管理、ハイアベイラビリティの対応

ノードの管理については、ノードが自分からクラスターに参加して離れて、ということができるようになりました。

SPoFがあちこちにあったのは改善されました。NameNodeですね。Hadoop、HDFSのメタデータを管理するサーバーはハイアベイラビリティな状態になりました。つまり、マスタースレーブモデルになったわけです。

ジョブの管理については、この頃にはリソースの管理という方向になるんですけれど、リソースの管理を行うリソースマネージャーもハイアベイラビリティの対応のものになりました、と。

ハイアベイラビリティの対応というのは、実際にはソフトウェアでがんばればできる、あるプロセスの中でコードをがんばって書けばできるというものではなくて、実際にはそのデータを調停する誰かが必要になります。つまり、2台、2プロセスが同時に「おれがリーダーだ!」って言いだしたときに、「おまえはリーダーじゃねえ」って言う誰かが必要になるわけです。

これを作るのが1つの大きなパラダイムになっていて、これはHadoopの中では、QJM、クオラム・ジャーナル・マネージャーと呼ばれるものになります。

ジャーナルというのは、みなさんご存じの、ファイルシステムのジャーナルです。これをQuorumベースで管理しようというものがQJMと呼ばれるクラスターですね。あとさっきも言ったZooKeeperというものになります。

これらのソフトウェアは両方とも、あえてぼかした言い方をしますがある情報に対して、なにが正しいのかを、複数のノードで調停をします。その結果、どうも過半数……過半数は実は正確じゃないんですけど、3台のうちどうも2台以上が、「こいつが正しい」と言ってるから、じゃあこの情報が正しい、ということを確定してます。

例えばNameNodeだとか、リソースマネージャーに教えてくれる、というような機能になります。これが非常に、ハイアベイラビリティな分散システムを作るためには重要です。

サブコンポーネントがまかなう機能の詳細

分散システムのパターンとしては、まずプロセッシングですね。計算処理自体は、分散はします。ノードごとに効率的に分散をします。データは、分散ファイルシステムあるいは分散データベースを作ってそこに保存する。

一方、データの中でもコンフィグレーションに相当するものに関しては、コンフィグレーション用のキーバリューストアを作って、そこに格納するというのが、非常に大きなパラダイムになっています。

なぜかというと、コンフィグレーションに関しては、情報の粒度が非常に小さいのと、なにが正しいのかというのを確定しないといけないという性質上、いわゆる大きい、ビッグデータ用の分散ファイルシステムと相性が悪いんですね。なので、それ用にキーバリューストアを作るというのが、パターンの1つになっています。

あとは、環境の分離ですね。つまり、大量のアプリケーションが混在したときに、それぞれの環境をどうやって分離するかというと、コンテナごとにプロセスを立てることで分離すると。プロセスの分離機能を使うということです。

ハイアベイラビリティに関しては、HA。つまり高可用化されたプロセスを複数立てて、そいつが、「この処理はこのノードで動いてるから、おまえあっちに行け」みたいなルーティングを行うことになっています。

このハイアベイラビリティの機能は、低レイヤーにあるZooKeeperだとかのリーダーエレクションの機能を使っているという状況になります。Hadoopにおいては、こういった5つの機能は、これらのサブコンポーネントによってまかなわれているということです。

Dockerリリースのインパクト

こういったHadoop2の改良が行われたのが、2010年前後でした。今でももちろん行われていますが、2010年前後から今に至るまで、こういったHadoopを中心とした分散システムのOSSの改良が行われてきたんです。

その一方で2013年にインパクトあるできごとがあって、これがDockerのリリースです。Dockerというのは、きわめて簡単に言うと、コンテナビルダーとランタイムの2つが一緒になったものです。

Dockerのランタイムのほうを先に話すと、最初はLinux Containerという仕組みの上に乗っていたんですけれども、あとから自前で実装するようになりました。

これは、Linux Containerはあまりユーザーが居なかったわりに機能が複雑で、バグが多かったからだと言われています。あとWindowsとか、他のOSをサポートするためには、そもそも自前で実装するのでLinux Containerに頼ることができなかったというのも、大きな理由だと思います。

Dockerのイメージというのがあります。これはすごく簡単なDockerファイルを書くと作れますと。いくつかのスパースファイル、Dockerのイメージをフェッチすると、ダウンロードグラフがいっぱいバーッって出てくると思うんですけど、あれはそれぞれ、小さいスパースファイルです。

Dockerのイメージは1個のファイルでできてるわけではなく、小さい差分ファイルの集合によって成り立っています。Dockerのイメージをフェッチすると、その差分ファイルのダウンロードがあのグラフになって出てくるわけです。

あとは、Docker Hubというセントラルリポジトリがわりと初期のころからありました。つまり、パブリックなDockerのイメージ、Dockerコンテナのイメージというものをいろんな人が公開するようになっていた。

おかげで、「MySQLの、このバージョンのコンテナほしいな」というと、ちょっとフェッチしてくるとすぐダウンロードされてくる。Docker Hubがあるからですね。

すごい勢いで有名になっていきました。ただし、見たところやっぱり最初は開発用途、あるいはテストの用途に使われることがほとんどだったと思います。

もちろん初期の頃からプロダクションで使っていたところもなくはなかったと思います。ただいろいろ問題があって、デプロイメントがいろいろやりにくいだとか、コンフィグレーションをどうするんだとか、あるいはリソースのマネージメントにもちょっといろいろ難があったりとか。

あと、ストレージ関連のサポートが非常に弱くて、どうするんだこれみたいな話になったり。リクエストルーティングですね。どこのマシンで、どういうDockerのイメージを立てたのかが誰も管理していない。

ロードバランスのDockerのイメージ立てる、起動するたびにロードバランス設定を書き換えるのかとか、あとローディングどうするのかとか、いろいろそういう話がありました。

オープンソースソフトウェアとしての検討が問題

この問題ひっくるめてオーケストレーションといいます。Dockerだけでできてるのって、さっきのパターンですね。ディストリビューテッドシステムズのパターンと同じ項目をバーッと出したんですけれど、さっきのパターンの中で、Dockerだけでできてるのって、プロセスの分離だけです。

他にもいくつか重要な利点があるのは認めますが、このパターンの中ではこれだけです。でも実際には、いろんなワークロードがあって。Dockerのコンテナ動かすと、さっき言ったベアメタルサーバーからフリーになって、とか。

いろいろな条件を考えると、いろんなことを考えないといけない。ただし、これというのは実際には、分散システムで考えられ解決されてきた問題とほぼ同じである、ということになります。

そもそも、このDockerコンテナどこで動かせばいいのかは、Hadoop YARNであったり、リソーススケジューラー、あるいはリソースマネージャーの機能です。あるいは設定ファイルをどうやって管理したらいいのか、設定を動的にアップデートできる基盤をどうやって提供すれば良いの、というのは、分散キーバリューストアの機能ですね。

バーッといろんなデータが降ってくるのを処理して保存したいときに、どこに保存すれば良いのかは分散ファイルシステムや分散データベースのお仕事です。

一方、いろんなところにDockerのコンテナ置いて、誰がどのプロセスをマスター扱いすればいいのかというのは、リーダーエレクションの機能になります。ということで、さっきも言ったとおり、ほとんどの問題というのは、過去に、しかもわりと近い過去にオープンソースソフトウェアとして検討が進んできたことだったんです。このあと大きいインパクトのある出来事がまた1つあります。

DockerがKubernetesをバンドルし、覇権争いは終結

2013年にGoogleがKubernetesというオープンソースソフトウェアを公開します。それを引き取るかたちで、2014年にCloud Native Computing Foundationというファウンデーションが、Linux Foundationの下部の組織として作られます。

Kubernetesは要するに、プロセッシングのリソース管理の問題などを解決するためのオーケストレーションソフトウェアです。

プロセッシングだとか、ハイアベイラビリティだとかを。Kubernetesと、あとKubernetesが動作の前提とするEtcdという分散キーバリューストアをペアにして解決していくというものになりますが。

ただし、Kubernetesがいまだに解決していない問題が1つだけあって、アプリケーションロジックがストアするストレージの話です。

Kubernetesや、あるいはKubernetesじゃなくてもコンテナオーケストレーションをすでに使っている人たちは居ると思います。そういった人たちもおそらく、データの保存に関してのみ、AWSのRDSだとかAuroraだとか、GoogleのSQLサーバーだとか、S3だとか、そういったものを使っているはずです。

それらはこういうコンテナオーケストレーションの文脈に載っていないものなんですね。もちろん重要性が増してきたことは事実だと思いますが、載っていないものです。こういった問題がいまだにある、ということです。

そうは言っても、経過としてはKubernetesとCloud Native Computing Foundationが出てきたあとも、オーケストレーションの覇権を巡ってやいのやいのとやってたんですけど、ついに2017年にDockerがKubernetesをバンドルするという事件があり、これで戦争が終了しました。「世の中はDockerとKubernetesの時代です。めでたしめでたし」というふうになりました。

ストレージの問題に向き合う

ただしさっきも言ったとおり、ストレージの問題が片づいていません。片づいていないというのは、クラウド事業者の上でアプリケーションを走らせていればRDSとかS3だとかが使えますが、そうでない人たちにとっての問題というのはいまだにあるわけです。

ではどうしないといけないのかというと考えるべきことは2つあります。

1つはデータのタイプ。データの種類がどういうものなのか。例えば、設定なのか、プロセスの状態なのか、といった小さいものなのか、あるいはもっと大きいアプリケーションロジックから出てくるデータなのかということですね。

もう1つは、実際に解決方法を考えることになると、3つ考えないといけないことがあります。例えば、すごく大きいテキストデータあるいはバイナリデータみたいなものなのかどうかを考え、そうであれば分散ファイルシステムみたいなものを選ぶ必要があるかもしれない。

そうではなく、顧客情報の管理や売上情報みたいなものを使わないといけない場合。あるいは、ログというのが最近のサービスでは非常に重要で。例えばアド、広告配信をやっている場合は、誰にどういう広告をビッドしたのかというログがすごい非常に重要ですし、あるいは顧客が、どの、我々のサービス上でなにをやったのか、どこまでいって諦めて帰っていったのかといったビヘイビアのログだとか、そういったものも必要になってくる。これらによって、適しているソフト、ストレージシステムというのは性質が変わります。

コンフィグレーションに関しては、さっきも言ったとおり、分散キーバリューストアみたいなものを使いましょうということで。これはOSSとして、ZooKeeperをちょっと個別に使うかどうかともかくとして、EtcdとかConsulみたいなものがあります。

大きいテキストファイル、あるいはバイナリファイルみたいなものに関しては、分散ファイルシステムを使いましょう。顧客のデータだとか、売上データはRDBMSを使いましょう。ログに関してはロギングサービスを使いましょう。僕がやってるFluentdみたいなものでも良いですし、そういうものを使いましょうということになるんですけれども……。

じゃあこれを誰が提供するのかというのはなかなか難しい問題になってきますね。ストレージを管理するというのはものすごく手間とコストがかかる行為です。

次の道のりを目指そう

ストレージのライフタイムというのは、処理、計算ノードのライフタイムよりはるかに長い。データは1回ストアしたら、そのストアしたデータベースサーバーというのはだいたい数年、あるいはもっと生き延びることが当たり前です。

あるいはサービスレベルですね。RDBMSを1回落とすと、そいつに繋げるサーバー、何十台何百台は一気に処理ができなくなるので、サービスレベルも非常に高くなければならない。だから非常にコストのかかることになっています。

しかも、さっきのようにデータの性質に合わせていろんなストレージを扱わなければならないという問題があります。クラウドプロバイダを使っていれば、使えるものがいろいろあるんですけれども、そうでない場合はどうしましょうか、という答えがまだ出ていません。

ただし、いままで見てきたとおり、トレンドというものはあるわけですね。分散システムとコンテナシステムにだけ注目していままで話してきましたけれども、もちろん他のいろんなトレンドがあります。

Function as a Serviceだとか、あるいはマイクロサービスだとかに、その答えがあるかもしれないし、ないかもしれない。それはまだわからない話ですし、みなさんが工夫のしがいのあるところだと思います。

そういったところを、ぜひみなさんいろいろ考えて、試行錯誤をし、その体験をシェアしていただきたい。

ということで、次の道。次のトレンド。道のりが我々の前に出てくるかもしれないし、それは知見をシェアされないとできないことです。Hadoop0.1.0が出たときに世界が変わったのと同じですね。

そういったことを、ぜひみなさんにしていただければと思います。これで私の話をおしまいさせていただきます。すみません、だいぶ長くなりました。ありがとうございました。

(会場拍手)