分散処理とコンテナ化インフラの面白い関係

田籠聡氏(以下、田籠):よろしくお願いします。本日は、ぼくが最近やっている分散システムと、コンテナ化されたシステムのことを含めて話します。

英語で言うとContainerized systemsといって、2単語なので楽なんですが、日本語だとあまり良い短縮形が今のところありません。コンテナ化されたインフラストラクチャー、あるいはコンテナ化されたシステムについて、事実だけ述べるというより、なんでそうなっているのか、どういった点が重要なのか話します。

分散システムやコンテナ化システムのそのものの話というより、そういったところにどんなエッセンスが入っているのかという話を中心に、過去の経緯を含めて話していこうかなと思います。よろしくお願いします。

田籠聡といいます。Fluentdとか、 MessagePack-Rubyのメンテナーをやっていたりとか、Norikra、Wootheeというソフトウェアの開発やっていたりしています。

トレジャーデータという会社で働いています。本社はアメリカで、データ処理を行うための仕組みをサービスとして提供する会社です。東京オフィスで働いています。開発チームとしてはワールドワイド1個だけ。あとはどこにいるかというと、USに居たり、東京にいたり、リモートであちこちにいたり、というチーム構成で仕事をしています。

今日は、最近モダンなシステムはどういうパターンのものがあるかをざっくりおさらいとして話します。

そのあとに分散システム、あるいはコンテナライゼーションの話。過去の経緯ですね。どういった事情で、どういうシステムになっていったのかという話をまとめて、最終的にこれからどうなるのかといった話。今の問題とこれからの話を、ちょっとだけ最後につけ加えておしまいにしたいと思います。

モダンシステムのパターン

モダンシステム。「モダンシステム」というとすごくかっこ良い感じですね。簡単に言うと、いろんな勉強会で「最近これがイケてる!」みたいな話がよくあると思います。それについてはみなさんがそうやってシステムを実際に作れているかというとそうではなくて、「目指すべき方向はこういう方向だ」ということが、「今イケてる」という単純な単語で言われているものだと、僕は理解しています。

こういったシステムに、過去の、既存のシステムを持っていくのはけっこう大変なんですけれども、目指すべき点として間違ってないというパターンがいくつかあって、その話ですね。そういうパターンに何があるかという話です。1つは、分散システム。分散システムというのは、みなさんあんまり直接作ることはないかもしれないですが、使われている例はけっこうあります。

例えばみなさんがAmazonのS3、あるいはGoogleのBigQueryとかを使ったりすると、それは裏で分散システムというものが動いているわけです。

あと、アプリケーションとしてはマイクロサービスですね。細かいアプリケーション、細かい機能単位で分割して、小さいサービスとして作っていくことで、主にデプロイメントの頻度を上げ、サービスの改善の速度を上げるのを狙ったパターンの1つですね。

もう1つはコンテナ化。コンテナ化はさっき雑なのをちょっと言ってましたけれども、いろんなものをシンプルにしてくれる側面があると。

あとはもう1つ、ちょっとここで扱いづらいものではあるんですけれど、サーバレスシステム。サーバーレスシステムって名前はぼくは嫌いなんですけど、Function as a Serviceって言葉がありますね。AWS Lambdaに代表されるものですが、小さいスクリプトを単位としてアップロードしておくと、なにかのイベントをトリガーにしてその機能が走り出すと。

その機能自体はクラウド事業者側がホストをするので、利用者、つまり我々アプリケーション開発者は、そのファンクションを動かすための基盤について、注意をはらう必要がなくなるという点で、サーバーレスと呼ばれているものです。Function as a Serviceという言葉のほうがぼくは好きですが。

モダンシステムのパターンに共通していること

まずこれらのパターンに共通してるものはなにかという話をしますと、すべてベアメタルサーバー、つまり昔ながらのいわゆるサーバーのハードから解放されているものです。我々がふだんいろんなこと……。すみません、マイクロサービスに関してはちょっと、離れる方向ではありますが。直接的にそれを意味するわけではないですけれども。

我々がふだんこれらのパターンに沿ってアプリケーションを作るときに、どのサーバーにこのロジックを置くか、ということはおそらく意識していないと思います。いくつかの計算資源があって、その中のどれかにこのファンクションがあれば良い。そのファンクションは、こういった冗長度、こういった性能を担保していれば良い、という考え方をおそらくすると思います。

もう1つは、プロセスライフタイムが短くなること。Short process lifetimeと書いていますが、これは何かといいますと、主にこれらのモダンなシステムのパターンは、根本的にはすべて、アプリケーションのデプロイメントを高速化するというよりは、アプリケーションのデプロイメントの頻度を高める、アプリケーションの更新の頻度を高める方向に向いています。

つまり、アプリケーションの更新をするということは、それまで動いていたプロセスが死んで、新しいもので置き換わるということですね。

1年前から動いているプロセスみたいなものは存在が難しくなって、根本的には何かの更新が走るたびに、プロセスが新しく作り直される、という方向に向かっているはずです。

デプロイメント、リソースの最適化にフォーカス

もう1つは、アプリケーションのデプロイメント、あるいはリソースの最適化というところにフォーカスしているということです。マイクロサービスに関して言うと、アプリケーションのデプロイメントに焦点を置いたパターンになっていますし、コンテナも私の意見としては、そっちの方向を向いています。

一方、分散システムや、Function as a Serviceというものに関しては、デプロイメントも関係はあるんですけれど、どちらかというとリソースの最適化ですね。計算リソースの最適化に焦点を置いている点がある。

とくにFunction as a Serviceのほうですね。これはおそらくみなさんはあまり意識していないところだと思いますが、Function as a Serviceというのは、クラウド事業者の側から見ると、リソース最適化をするための有効な手なんです。なぜかというと、Function as a ServiceってだいたいLambdaだと今30秒かな? 最長の走行時間しか認められてないと思いますけれど、1プロセスが30秒で死ぬということは、1プロセス30秒で死んだものをもう1回動かすときに、なんの断りもなく別のサーバーに移動させちゃってもかまわないんですね。なぜならそういう前提のサービスだから。

例えばあるレンタルサーバーだとか、ある仮想サーバーだとかで処理が集中した、あるいは重い処理をしたことで負荷が高まった場合に、簡単に他のリソース、他のファンクションを他のノードに移しちゃえば良いんですね。

そういうことがあって、Function as a Serviceというのは実際には利用者の側からすると、極めてコストパフォーマンスの悪い機能なんです。

クラウド事業者の側から見ると、リソース最適化をするための非常に有効な手の1つであると言えます。だから、そういう意味ではAWS Lambdaが安く見えるというのは、クラウド事業者なんかがリソースの最適化をやった結果、あの値段で使えているということなんですね。

同じくらいのリソースの最適化を自分たちでもできれば、あれよりもさらに安い値段で実行できる程度のロジックのはずなんですけれども、それは規模の経済がきくのでなかなか難しいという面があります。ちょっと脱線しましたが。

最後にもう1つ、これは一番大事な点なんですが、ローカルのファイルシステムの存在を基本的には前提としていないというのが、この4つ(スライド参照)とも大きな特徴です。

これはレンタルサーバーから離れていることとほぼイコールです。例えばサーバーを4台買って、「この4台で1年間サービスをやるぞ」とやっていた昔の頃は、その4台のディスクがずっとくっついていたので、例えばそこにデーターベースを立てて、あるいはそのファイルシステムにいろんなファイルをいっぱいバーッと書いて、データのストレージにするということをごく当たり前に行っていました。

今となっては、サーバー自体、クラウドサービス上で使う仮想サーバーということも非常に多いと思いますし、そのうえで例えば、オーケストレーションのツールを動かすだとか、あるいはDockerを動かすだとか、そういうことをすると、そもそもローカルストレージってなんだっけ? みたいな話になるわけですね。

だから、いわゆるアプリケーションのプロセスからローカルストレージにデータを書くという操作を今ではおそらくほとんど行ってないと思います。

代わりにネットワーク上のどこかにあるデータベースに書きにいくとか、あるいはデータの保存をやってくれるマイクロサービスにAPIリクエストを送るとか、そういうことになっていると思います。これは、この4つのパターン全部に共通する非常に大きなパラダイムの変化であると言えるとぼくは思っています。

この4つについて全部話していくと時間がいくらあっても足りないので、本日は分散システムとコンテナについての話を集中的にやっていこうと思っています。

分散システムの歴史とトレンド

まず分散システムについて。分散システムというのは実際にはものすごく長い歴史があります。1900年代の後半から……半ばくらいからと言っても良いですけれど、要するにコンピューティングというものがあった時代からずっと存在しています。

論文だとか、あるいはスーパーコンピューターだとか、あるいはもうちょっとおりてくると、汎用機だとかですね。あるいはその他いろいろなところで、分散システムの研究、あるいは実践が行われていました。

明確なトレンドとして、ごく最近我々がOSSで普通に使える分散システムのソフトウェアが手に入るようになりました。

代表例としては、分散ストレージとしてのCassandraだとか、HadoopのHDFSだとか、HBaseだとか、Riakだとか。分散処理のシステムとしてHadoop MapReduceだとか、Sparkだとか、Prestoとか。

あとプロセススケジューラーというと、分散システムを知らない人には馴染みがないかもしれませんが、リソースの最適化をやるためのソフトウェアのことです。これが、HadoopのYARNだとか、Mesosだとか、Kubernetesだとかが出てくるようになりました。Kubernetesというのも実際にはここに入るんですけれども。

あとは、サービスディスカバリーも実際には分散システムの文脈の1つで、ZooKeeperだとか、Etcdだとか、Consulだとか。Consulはおそらくみなさん聞いたことあるとが思いますが。そういうものが出てくるということになっています。

オープンソースソフトウェアの話で、特別な流れとしては、最初はストレージから始まったと。データストアですね。そこから始まって、その次に処理単位で分割して分散する。その次にリソースを分割して、任意の処理をその上に乗せる。というように、移ってきているというのが、いわゆる分散システムと呼ばれるもののトレンドです。

コンテナの歴史とトレンド

あと、コンテナですね。Dockerが登場してはじめてコンテナってなんだっけ? みたいな話を耳にされた方ももしかしたら居るかもしれません。

これも実際には古い歴史があって、よく手の届きやすかったところでいっても、FreeBSDのjailという機能があったりだとか。

FreeBSDのjailは2000年前後か90年代後半に、すごく使われていた時期があったんです。2000年代前半かな? さすがにそろそろ死滅したかなと思っていた2010年に、僕が某企業に転職したら、そこの掲示板サービスですごいjailが動いてて「うお〜っ」と思った覚えがありますね。

僕はその頃インフラ野郎で、オペレーション担当だったので、障害が起きたらオペレーションしに行く立場だったので、頼むからそのサービスだけ障害起きてくれないでほしいなって思ってた時期がちょっとあります。

あのとき障害なんかあったかな? ありましたっけ? あんまりなかった? なんか安定して動いてましたね。「jailスゲーな」と思っていた覚えがあります。

FreeBSDのjailだとかSolarisのコンテナだとか、わりと最近になってから出てきたLinuxコンテナーだとか。こういう仕組み自体はけっこうありました。

ただし、広く使われるという状況であったかというとまったくそうではなくて、やっぱりこれも知る人ぞ知る、に近いところがあったんです。これが2010年代に入って、DockerとKubernetesが登場したことで一気にガラッと切り替わります。

DockerとKubernetesはご存じの方も多いと思います。DockerはDockerfileという定義ファイルですね、この定義ファイルがすごく革命的で。ファイルにコンテナの作り方をばーっと書いていくと、コンテナイメージができあがる。

今までは、コンテナを1回作って、その中でいろいろセットアップ作業をやって、保存するみたいな、あたたかみのある手作業が必要だったのが、Dockerファイルという定義ファイルで、一気にコードとして……コードと言うにはちょっとあれですけれど、リポジトリでバージョン管理可能なかたちで再現できるようになったというのが非常に大きな革命でした。

あと、差分のスパースファイルをベースとしたDockerのコンテナイメージがあると。あとKubernetesは、そのコンテナをいっぱいまとめて管理するオーケストレーションのシステムです。

Kubernetesに関してはあとで出てきます。これも昔は主にデベロッパーが使うもので、あとはステージングとか、テスティング目的で使うのが多かったんですが、どんどんプロダクションに広がってきたのがここ最近のトレンドですね。

インフラストラクチャの移行と現代的な問題

これらの、とくに分散システムとコンテナライゼーションシステムのパターンを見ていくと、主にジェネラルパーパス、みなさんのWebアプリケーションとかを乗っけるような汎用のコンピューティング目的では、主にコンテナアプリケーション、コンテナ化されたアプリケーションがデプロイされるということが多くて。

その一方で、S3だとか、BigQueryとか、そういったデータ処理、あるいはストレージに代表されるところでは、分散システムを作って、その目的にあてるというのが非常に大きなトレンドで、ここ最近のパターンになっています。

さっきも言ったとおり、これらのサービスを作るんですけれど、レンタルのサーバーを前提とはできない。プロセスのライフタイムが短い。デプロイとかリソースの効率化をなんとかして狙わないといけない。一方で、パーマネントのストレージ、ローカルファイルシステムは使うことができない。

とういうことで、全体のトレンドとしては、物理的なインフラストラクチャから、ロジカルなインフラストラクチャに移行してきている。

実際には2000年代の半ばごろ、仮想化仮想化って言っていた時代からずっと続いているトレンドではありますけれども、それが今になっても続いているというのが現状です。

一方で、プロセスのライフタイムが短くなって、どのサーバーにでもアプリケーションをぽんぽんデプロイしたりするということになると、いろいろな問題が生まれきます。

これが現代的な問題で、「そもそも今デプロイしたアプリケーションってどこで動いてるの?」という話だとか、「このアプリケーションってそもそもCPUコアいくつ使って良いの?」「メモリいくつ使って良いの?」あるいは、「このアプリケーションのメモリいくつ必要なの?」みたいなことも考えなきゃいけない。

「このアプリケーションのデータどこに置いたの?」「あそこのサーバーにデプロイしたのはわかるけど、データはどこか別のところに保存してるらしい。それって実際にはどこなの?」という話だと。

あるいは例えば、アプリケーションプロセスを、あっちのデータセンターとこっちのデータセンターにぼんぼんっと置いたとします。集中的に管理をするためのバッチをどこかで動かさないといけないんだけど、それをどこで動かすべきなのか、どのプロセスが主導権を取ってあっちに居るプロセスとこっちに居るプロセスの調停をするのか、ということを考えなければいけなくなります。

モダンシステム5つの問題点

これらの問題を、ぱっと5つにまとめました。

モダンなシステムにおいては、けっこう本質的に解決が難しいこういった問題がでてくることになりました。

1つは、ストレージの管理ですね。もう1つは、コンフィグレーションをどうやって運ぶか。つまり、どこで起動しているかわからないアプリケーションに、どうやってコンフィグレーションを運んで更新すれば良いのか。

あとは、ステートのマネージメントですね。どこかでアプリケーションをデプロイしたところまではわかってるんだけど、そのプロセスがまだ動いてるのかどうかを監視しないといけない。あるいは、動かなくなったら別の場所で代わりに立てないといけない。こういうステートのマネジメントも必要になる。

そして、リソースのアサインメントです。サーバーはそもそも、どういうポートをListenしないといけなくて、どれくらいのCPUリソースやメモリリソースが必要なのか、どのくらいストレージを使いたいのか、ということを、誰かが管理してアサインしてあげないといけません。

もう1つはリーダーエレクションですね。さっきも言ったとおり、いろんなところにプロセスを分散して配置すると、例えばマスターデータの管理はどのプロセスが責任を持つべきなのか、みたいな問題が必ずあるわけです。

複数のプロセスから同時にマスターデータの更新をかけたら、もちろんそのマスターデータはぶっ壊れますので……。まあRDBに入ってれば良いですけどね。

JSONで管理されている商品一覧とかありますよね? みなさん。そういったものを、複数のプロセスが同時に更新しようとすると当然データがぶっ壊れるので、それについて誰がリーダーシップを取るのか、誰にリーダーシップを取らせて良いのか、というようなのが現代的な問題としてでてきます。

こういった問題を、実際に良く使われてるソフトウェアが解決しています。あるいは解決しようとしています。その話を順を追ってしていきたいと思います。