大規模分散システムの現在 -- twitter

244
大大大大大大大大大大大大 @maruyama097 大大大大大

Upload: maruyama097

Post on 06-Aug-2015

19.374 views

Category:

Internet


0 download

TRANSCRIPT

Page 1: 大規模分散システムの現在 -- Twitter

大規模分散システムの現在

@maruyama097丸山不二夫

Page 2: 大規模分散システムの現在 -- Twitter

Most of our systems are big “Future transformers”

- Marius Eriksen

Page 3: 大規模分散システムの現在 -- Twitter

predictable performance is difficult to achieve. In a predictable system, worst-case performance is crucial; average performance not so much.

... predictable performance is difficult to achieve. In a predictable system, worst-case performance is crucial; average performance not so much.

- Peter Schuller

Page 4: 大規模分散システムの現在 -- Twitter

predictable performance is difficult to achieve. In a predictable system, worst-case performance is crucial; average performance not so much.

It’s with the intent of modeling a world where the Twitters, Googles, and Facebooks are no longer superpowers… just power

- Aurora

Page 5: 大規模分散システムの現在 -- Twitter

はじめに Twitter の大規模分散システムが、世界有数のもので

あることは論を待たない。 2 億人以上のユーザーが、このプラットフォームを利用し、彼らのシステムは、毎秒 100 万以上の tweet に耐えられることを目指している。

Twitter のアプローチの大きな特徴の一つは、こうした大規模分散システムの記述には、関数型のプログラム言語が、適合的だという積極的な主張にある。

小論では、まず、彼らのシステム記述の中核ライブラリーである Finagle を取り上げる。ここでは、非同期性を表現する Future が本質的な役割を果たす。 Twitter の大規模分散システムは、「 Future の巨大な変換装置」とされる。こうした認識は、 Twitter のシステム理解の要になる。

Page 6: 大規模分散システムの現在 -- Twitter

はじめに Twitter のアプローチのもう一つの特徴は、彼らが彼

らの大規模分散システムの心臓部分の実装を、オープンソースで公開していることである。 Google もAmazon も Microsoft も、そういうことはしていない。

Mesos は、「分散アプリケーション、すなわち、フレームワークをまたいで、効果的なリソースの分離と共有を提供するクラスター・マネージャー」である。それは、データセンターあるいはクラウドのOS と呼ぶべきものである。

Mesos だけでなく、その周辺の Aurora, Mesosphere といった「 Mesos 文化圏」ともいうべきものは、大規模分散の世界で、もっともダイナミックでアクティブな領域に成長しようとしている。

Page 7: 大規模分散システムの現在 -- Twitter

Agenda

Twitter のシステムの変化 Finagle 関数型言語による分散処理の記述 Manhattan 多機能分散データベース Mesos  データセンター OS とその影響

の拡大

Page 8: 大規模分散システムの現在 -- Twitter

OverviewTwitter のシステムの変化

ここでは、 Twitter のシステムの変化を概観しよう。

Page 9: 大規模分散システムの現在 -- Twitter

2009 年 MySQL を使った純粋な Ruby-on-Rails アプリ。 たくさんの memcache を使い、投稿されたタイム

ラインを memcache に積む。 ソーシャル・グラフはサービスで扱う。 遅延は、 queue で吸収。

Page 10: 大規模分散システムの現在 -- Twitter

monolithic なアプリケーション

サービス・インフラの欠如

新しいサービス・新しい特徴追加が困難

スピード、効率性、信頼性で勝る大規模インフラへ

関心の分離 チームの独立性

“Real-time systems at Twitter”http://goo.gl/EaYyZA

2009

2010

Page 11: 大規模分散システムの現在 -- Twitter

2010 年 - 2011 年 - 2012 年 2010 年:タイムラインを、独自のサービス・シス

テムに移行開始する。 ruby on rails から離れるためのプロジェクト godwit 開始。サービス・インフラの共有化に取り組む。

2011 年:インフラの整備進む。無数のアプリのポーティング。 TFE(HTTP Proxy) オンライン稼働。

2012 年: TFE が通年で全てのトラフィックを扱うようになる。ますます多くの API のトラフィックが新しいシステムで動くようになる。

Page 12: 大規模分散システムの現在 -- Twitter

2011

2012

“Real-time systems at Twitter”http://goo.gl/EaYyZA

Page 13: 大規模分散システムの現在 -- Twitter

2012 年末のアーキテクチャー

多くのオープンソース・コンポーネントの導入 Memcache, redis, MySQL, etc. 必然的にヘテロなシステムに

サービス中心に組織化 異なった責任を持つ 相互に分離されている 分散化された処理とデータ システム間の RPC

前面に HTTP のマルチプレキシング モデュラー性とロードバランシングにとって、本

質的に重要

Page 14: 大規模分散システムの現在 -- Twitter

2013 年  Twitter stack Finagle Ostrich Zipkin Mesos Iago ZooKeeper Scalding jvmgcprof

http://goo.gl/Ax9LVw

Page 15: 大規模分散システムの現在 -- Twitter

2013 年  Finagle Twitter のサービスの中心部分には、 Finagle ライ

ブラリーがある。 RPC システムの基本的な土台の部分を抽象化することによって、 Finagle は、サービス開発者が扱わなければいけなかった複雑さを大幅に軽減した。

それは、分散システムの低レベルの詳細にこだわらねばいけなかったかわりに、アプリケーションに固有のビジネス・ロジックを書くことに集中することを可能にした。

最終的には、 Web サイト自身も、運用を効率化でも、 HTML を書き出すのに必要なデータの取り出しにも、このサービスを使っている。 Twitter では内部のサービスは Thrift を使っているのだが、 Finagle では、 Protocol bufferや HTTP のような他のプロトコルもサポートしている。

http://goo.gl/Ax9LVw

Page 16: 大規模分散システムの現在 -- Twitter

2013 年  Mesos Mesos は、自分を次のように規定している。

「分散アプリケーション、すなわち、フレームワークをまたいで、効果的なリソースの分離と共有を提供するクラスター・マネージャー」

Mesos の中心プロジェクトは、オープンソースのApache インキュベーター・プロジェクトである。Mesos の上に、例えば、 Stormや Hadoop といった特別の技術を扱うスケジューラーを走らせることができる。そのアイデアは、同じハードウェアは、複数の目的のために利用でき、リソースの浪費を低減できるというものである。

http://goo.gl/Ax9LVw

Page 17: 大規模分散システムの現在 -- Twitter

2014 年  Manhattan Twitter が、パブリックな自己表現と会話のグローバ

ルなプラットフォームに成長するにつれ、我々のストレージに対する要請も増大した。この数年間にわたって、我々は、リアルタイムの環境の中で、非常に低い遅延で、毎秒数百万のクエリーに応えられるストレージ・システムが必要であることに気づいていた。可用性とシステムのスピードが、最も重要な要素になっていた。単に、早いことが必要なだけでなく、世界中のいくつかの地域をまたいで、スケーラブルである必要があった。

https://goo.gl/GN960E

Page 18: 大規模分散システムの現在 -- Twitter

2014 年  Manhattan 何年にもわたって、我々は、多くのオープンソース

のデータベースを利用してきたし、それらに重要な貢献もしてきた。しかし、 Twitter のリアルタイムの本性は、既存のオープンソース製品が提供しているものより、低い遅延を要求していることに、我々は気づいていた。我々の様々な製品のパフォーマンスの期待にそうために、火を噴きそうな製品システムと、我々は、非常に長い時間を過ごしてきた。そして、あまりに多くの手作業やプロセスを含んだユースケースに代わる、新しいストレージの能力を立ち上げようとしている。

https://goo.gl/GN960E

Page 19: 大規模分散システムの現在 -- Twitter

Finagle

Page 20: 大規模分散システムの現在 -- Twitter

Finagle関数型言語による分散処理の記述

シーケンシャルな処理を考える改めて、シーケンシャルな処理を考え Future の利用パラレルな処理を考える サービスのモジュールへの分割 Finagle: RPC システム

Page 21: 大規模分散システムの現在 -- Twitter

シーケンシャルな処理を考える

Page 22: 大規模分散システムの現在 -- Twitter

計算処理を関数と考える

処理

関数 f

入力 出力

関数の引数 x 関数の返り値 y

y = f( x)

引数の型が A で、その返り値の型が B なら、この処理は次のような型を持つ関数 f で定義される。

def f(x:A):B

Page 23: 大規模分散システムの現在 -- Twitter

シーケンシャルな処理

処理 1入力 出力

二つの処理 f と g が、シーケンシャルに連続して行われる時、その処理 h は、関数 f と関数 g の合成になる。これを、

h = g ・ f と表す。

処理 2入力 出力

関数 f引数 x

返り値f(x) 関数

g引数 返り値 y

y = h(x) = g(f( x) )

関数 h

Page 24: 大規模分散システムの現在 -- Twitter

シーケンシャルな処理

処理 1入力 出力

シーケンシャルな処理が、 f1, f2, ... , fn と連続して行われる時、その処理 h は、 h = fn ・ ... ・ f2 ・ f1 と表わすことができる。。

処理 2入力 出力

y = h(x) = fn( ・・・ (f2( f1( x) ) ・・・ )

関数 h

処理 n出力

・・・

f1 f2 fn・・・引数 x 返り値 y

Page 25: 大規模分散システムの現在 -- Twitter

シーケンシャルな処理の特徴h = fn ・ ... ・ f2 ・ f1

関数の合成で、シーケンシャルな処理が記述できたのだが、それだけではシーケンシャルな処理の特徴を捉えたことにはならない。そこには、次のような問題がある。

f1 の処理が終わるまで、 f2の処理は待たされる。f2 の処理が終わるまで、 f3 の処理は待たされる。  ・・・fn の処理は、それ以前のすべての処理が終わるまで待たされる。

h = fn ・ ... ・ fi ・ ... ・ f2 ・ f1待たされるだけではない。途中の処理 fi の一つでも失敗すれば、その時点で、全体の処理 h は、失敗する。

待つことや、エラーの処理に、うまい方法はないのだろうか?

Page 26: 大規模分散システムの現在 -- Twitter

出力に時間がかかる場合

f

f

入力 出力

入力 出力がない! 待機!

出力がすぐ返ればいいのだが、処理に時間がかかる場合には、出力がない状態が生まれる。

Page 27: 大規模分散システムの現在 -- Twitter

非同期処理

f

g

入力 出力がない状態

入力 出力

こうした場合には、出力がない状態で待機せずに、別の処理に制御を写すのが好ましい。 f は、呼び出されると、出力の有無にかかわらず、すぐに制御を返すのがいい。非同期処理である。ただ、それには、仕掛けが必要である。

別の処理 g待機せずに、別の処理に制御を移す。

Page 28: 大規模分散システムの現在 -- Twitter

Future Future は、関数が返すものを入れる「箱」である。 この「箱」は、空の場合もあれば、中身を一つ持っ

ている場合もある。 Future は、ゼロ個か 1個の中身を持つ。

中身は、関数が返した値が入っているか、あるいは、関数の実行に失敗したという情報が入っているかの、いずれかである。

T 値 エラー

空の Future

中身を持つ Future

結果待ち状態           実行成功            実行失敗

Page 29: 大規模分散システムの現在 -- Twitter

Futures が必要とされる場合

出力を得るのに、待機する必要がある場合 長い時間を要する計算 ネットワークの呼び出し ディスクからの読み出し

計算は失敗することがある。 接続の失敗 時間切れ ゼロでの除算

Page 30: 大規模分散システムの現在 -- Twitter

Future と関数の非同期化

f

g

入力

入力別の処理 g

Future が返ったら、別の処理にただちに、制御を移す。

Future が返る

Future が返る

h入力

別の処理 h

Future が返る

Future が返ったら、別の処理にただちに、制御を移す。

もし、関数がFuture を返すなら、関数は、非同期にできる。

非同期型def f(x:A):Future[B]

同期型def f(x:A):B

Page 31: 大規模分散システムの現在 -- Twitter

Futures の値の取得 get

Future は、ある種のコンテナーである。 trait Future[A]それは、 empty, full, failed の三つの状態を取る。我々は、それを待つことができる。その値は get で取得できる。   val f: Future[A]   val result = f()   f.get() match {   case Return(res) => ...    case Throw(exc) => ...   }ただ、いつ get するのか? せっかく非同期にしたのに、 get の利用は、あまり意味がない

Page 32: 大規模分散システムの現在 -- Twitter

scala> import com.twitter.util.{Future,Promise} import com.twitter.util.{Future, Promise}

// すでに解決済みの Future を作る。scala> val f6 = Future.value(6)f6: com.twitter.util.Future[Int] = com.twitter.util.ConstFuture@c63a8af

scala> f6.get() res0: Int = 6

// 失敗となる Future を作るscala> val fex = Future.exception(new Exception) fex: com.twitter.util.Future[Nothing] = com.twitter.util.ConstFuture@38ddab20

scala> fex.get() java.lang.Exception

... stack trace ...

Future の get を実験する

Page 33: 大規模分散システムの現在 -- Twitter

// 解決されていない Promise を作るscala> val pr7 = new Promise[Int] pr7: com.twitter.util.Promise[Int] = Promise@1994943491(...)

scala> pr7.get() ...console hangs, waiting for future to resolve... Ctrl-C Execution interrupted by signal.

scala> pr7.setValue(7)

scala> pr7.get() res1: Int = 7

scala>

Future の get を実験する

Page 34: 大規模分散システムの現在 -- Twitter

Future のコールバック「私に電話するな。私がかける。」 と Mr. Future はいう。( Hollywood principle )

   val f: Future[String]    f onSuccess {     s => log.info(s)    } onFailure {      exc => log.error(exc)    }

Page 35: 大規模分散システムの現在 -- Twitter

Promises

Futures は read-only だが (初期化の時に、一回だけ、書かれる)、 Promise は、何回でも書き込み可能である

val p: Promise[Int]val f: Future[Int] = pSuccess:   p.setValue(1)Failure:   p.setException(new MyExc)

Page 36: 大規模分散システムの現在 -- Twitter

改めて、シーケンシャルな処理を考える  Future の利用

Future の準備はできた。ここでは、 Future を返すことで非同期化された関数の、シーケンシャルな合成を考えてみよう。

Page 37: 大規模分散システムの現在 -- Twitter

サンプルのシナリオgetThumbnail ここでは、与えられた URL から Webページを取得

し、つづいて、その Webページの最初の画像リンクから画像を取得する処理 getThumbnail を考えてみよう。

基本的なデータ型として、 Webpage を次のように定義しよう。要は、 Webページは、画像リンク( imagelinks)とリンク (links) からなり、それぞれは、文字列( URL)の Sequence( リストと思っていい ) だということ。

   trait Webpage {    def imageLinks: Seq[String]    def links: Seq[String] ...   }

Page 38: 大規模分散システムの現在 -- Twitter

同期型のシナリオgetThumbnailSync Future を使わない同期型では、こんな感じになる。  def fetchSync(url: String): Webpage = { ... }   def firstImageURLSync(page:Webpage):String = {       page.imageLinks(0) } def getThumbnailSync(url:String):Webpage = { fetchSync( firstImageURLSync( fetchSync( url ))) }

fetchSync firstImageURLSync fetchSync

url page image-url pageI

getThumbnailSync

Page 39: 大規模分散システムの現在 -- Twitter

非同期型のシナリオgetThumbnail Future を使った同期型では、こんな感じになる。中

間の部分の処理は、大して時間かからなそうなので、内部に組み込んだ。

  def fetch(url: String):Future[Webpage]    def getThumbnailSync(url:String):Future[Webpage]

page.imageLinks(0)

fetch fetch

url

getThumbnail

page

onSuccess                      onSuccess

onFailure                      onFailure

Page 40: 大規模分散システムの現在 -- Twitter

非同期型のシナリオgetThumbnail のコードdef getThumbnail(url: String): Future[Webpage] = { val promise = new Promise[Webpage] fetch(url) onSuccess { page => fetch(page.imageLinks(0)) onSuccess { p => promise.setValue(p) } onFailure { exc => promise.setException(exc) } } onFailure { exc => promise.setException(exc) } promise}

   これは、よくある Callback Hell のパターンだ。

Page 41: 大規模分散システムの現在 -- Twitter

getThumbnail を flatMap で実装

def getThumbnail(url: String): Future[Webpage] = fetch(url) flatMap { page => fetch(page.imageLinks(0)) }

Page 42: 大規模分散システムの現在 -- Twitter

回り道Collection の map

こうしたコンビネーターを、おそらく、毎日使っているかもしれない。例えば、 collection に働く “map” は、コンビネーターである。

val l = Seq(1,2,3,4)val mult2 = { x => x*2 }val l2 = l map mult2 // 次の様にも書ける : l map { x => x*2 }l2 == Seq(2,4,6,8)

Page 43: 大規模分散システムの現在 -- Twitter

回り道Collection の flatMap

flatMap コンビネーターは、非常に汎用的なツールである。

trait Seq[A] { def flatMap[B](f: A => Seq[B]): Seq[B] ...

その名前が示唆する様に、それは、 map と flatten の組み合わせである。

def flatMap[B](f: A => Seq[B]) = map(f).flatten

Page 44: 大規模分散システムの現在 -- Twitter

flatMap で、何ができるか?拡張 : Seq(1,2,3,4) flatMap { x => Seq(x, -x)} == Seq(Seq(1,-1)),Seq(2,-2),Seq(3,-3),Seq(4,-4).flatten == Seq(1,-1,2,-2,3,-3,4,-4)

条件 : Seq(1,2,3,4) flatMap { x => if (x%2 == 0) Seq(x) else Seq()} == Seq(Seq(2),Seq(4)).flatten == Seq(2,4)

Seq[Seq[int]] を、 Seq[int] に変える

Page 45: 大規模分散システムの現在 -- Twitter

Future の flatMap

trait Future[A] { def flatMap[B](f: A => Future[B]): Future[B] ...

Future[Future[T]] を、 Future[T] に変える

Page 46: 大規模分散システムの現在 -- Twitter

flatMap が助けになる?我々は、次のような関数を定義しようとしている。   def getThumbnail(url: String): Future[Webpage]最初にページを取り込んで、最初のイメージのリンクを見つけ、そのリンクからイメージを取り込む。この操作のいずれかが失敗すれば、この getThumbnailも失敗する。

trait Future[A] { ... def flatMap[B](f: A => Future[B]): Future[B]

Page 47: 大規模分散システムの現在 -- Twitter

page.imageLinks(0)

fetch fetch

url

getThumbnail

page

onSuccess                      onSuccess

onFailure                      onFailure

url

fetch

page.imageLinks(0)

fetch

Future 非同期関数

Page 48: 大規模分散システムの現在 -- Twitter

flatMapurl

fetch

page.imageLinks(0)

fetch

flatMap ... エラー

flatMappagepage.imageLinks(0)

fetch

エラー

page

Page 49: 大規模分散システムの現在 -- Twitter

flatMappagepage.imageLinks(0)

fetch

page

map . flattenpagepage.imageLinks(0)

fetch

page

page.imageLinks(0)

fetch

. flatten

Page 50: 大規模分散システムの現在 -- Twitter

page.imageLinks(0)

fetch

. flatten

. flatten

. flatten

エラー

エラー

Image page

Page 51: 大規模分散システムの現在 -- Twitter

. flattenImage page

Image page

Future flatmap 非同期関数で、新しい Future が返る

flatMap で、 Future[Future[T]]が、 Future[T] に変わる

Page 52: 大規模分散システムの現在 -- Twitter

getThumbnail を flatMap で実装

def getThumbnail(url: String): Future[Webpage] = fetch(url) flatMap { page => fetch(page.imageLinks(0)) }

Page 53: 大規模分散システムの現在 -- Twitter

失敗はどうなるのか?これらは、合成も上手く行く。また、それは、回復可能でなければならない。 flatMap には、その双対が必要である。 flatMap は、成功した値の上に働き、 rescue は、例外を処理する。trait Future[A] { ... def rescue[B](f: Exception => Future[B]): Future[B]

エラーの回復は、次のようになるval f = fetch(url) rescue { case ConnectionFailed => ....}

Page 54: 大規模分散システムの現在 -- Twitter

flatMap の利用 flatMap シーケンスは二つの Future を持つ。それ

は、 Future と非同期関数を引数にとって別のFuture を返す。

このメソッドのシグニチャーは、次のようなストーリーを語っている。

与えられた成功した Future の値に対して、関数 fは、次の Future を提供する。 flatMap は、入力のFuture が成功裏に終了した時に、自動的に f を呼び出す。この操作の結果は、別の Future で、二つのFuture の双方が終了した場合にのみ終了する。もし、どちらかの Future が失敗すれば、この Futureは失敗する。

Page 55: 大規模分散システムの現在 -- Twitter

flatMap の利用 この暗黙のエラーの織り込みは、エラーが意味的に重要な場所で起きた場合にのみそれらを処理することを可能にする。 flatMap は、こうしたセマンティックを持つ combinator の標準的な名前である。

もし、 Future があって、非同期 API をその値に適用しようと思ったら、 flatMap を使うこと。

Page 56: 大規模分散システムの現在 -- Twitter

flatMap の利用 もう一つの例 例えば、 Future[User] があったとしよう。そして、

特定のユーザーが失格になっていることを示すFuture[Boolean] が必要だとしよう。あるユーザーが失格になっているかどうかを決める isBanned API がある。ただ、これは非同期 API なので、 flatMap を利用することができる。

Page 57: 大規模分散システムの現在 -- Twitter

scala> import com.twitter.util.{Future,Promise} import com.twitter.util.{Future, Promise}

scala> class User(n: String) { val name = n } defined class User scala> def isBanned(u: User) = { Future.value(false) } isBanned: (u: User)com.twitter.util.Future[Boolean] scala> val pru = new Promise[User] pru: com.twitter.util.Promise[User] = Promise@897588993(...)

// apply isBanned to future scala> val futBan = pru flatMap isBanned futBan: com.twitter.util.Future[Boolean] = Promise@1733189548(...) scala> futBan.get() ...REPL hangs, futBan not resolved yet... Ctrl-C Execution interrupted by signal.

scala> pru.setValue(new User("prudence")) scala> futBan.get() res45: Boolean = false scala>

Page 58: 大規模分散システムの現在 -- Twitter

シーケンシャルな処理の非同期化h = fn ・ ... ・ f2 ・ f1

シーケンシャルな処理は、時間やエラーの問題を無視すれば、 h = fn ・ ... ・ f2 ・ f1 のように、「関数の合成」でモデル化できた。

Future で非同期化された関数の合成は、 flatMap を使うと次のように簡単に表現でき、かつ、より現実的なシーケンシャルな処理のモデルを与える。

  f1 flatMap f2 flatMap ... flatMap fn

Page 59: 大規模分散システムの現在 -- Twitter

パラレルな処理を考える

Page 60: 大規模分散システムの現在 -- Twitter

パラレルな処理を考える パラレルな処理が、計算上で意味を持つのは、独立

に計算されたそれらの結果が、別の一つの処理で利用される場合だけである。

処理

出力処理 1

処理 2

処理 n

入力

パラレルな処理

Page 61: 大規模分散システムの現在 -- Twitter

パラレルな処理の合成を関数で考える この複数の処理を一つに束ねる処理の、もっとも簡単な関数での解釈の一つは、複数の引数を持つ関数を考えることである。

         f(x1, x2, ... , xn)

f

返り値p1

p2

pn

引数

パラレルな処理

Page 62: 大規模分散システムの現在 -- Twitter

「複数の引数」の問題 パラレルに走っている、引数を与える方の関数がエ

ラーを起こして、引数が、一つでも揃わないことが確定すると、その時点で、複数の引数を受け取る関数は、失敗する。

複数の引数が、同時に与えられる保証はない。複数の引数を受け取る関数は、引数が全部揃うまで「待機」する必要がある。

例えば、コンテンツと広告を表示する Web サービスを書いているとしよう。この時、あるサービスからコンテンツを取り出し、他のサービスから広告を取り出すことになるだろう。しかし、両方の返答を待てということをどうしたらコードに伝えれることができるだろう。

ここでも、 Future が使える。

Page 63: 大規模分散システムの現在 -- Twitter

パラレルな処理の合成を非同期関数と Future で考える 複数の引数を持つ関数を考える代わりに、複数の

Future の List を、複数の List の一つの Future に変換する combinator を考えよう。

collect

p1

p2

pn

パラレルな処理の結果としての Future の List

p1

p2

pn

List

パラレルな処理の結果の List の Future

ListFuture

Page 64: 大規模分散システムの現在 -- Twitter

パラレルな処理の合成を非同期関数と Future で考える この combinator が成功するのは、左の List の要素

のすべての Future が成功する場会のみである。逆に、この時、すべての要素は揃っている。

collect

p1

p2

pn

パラレルな処理の結果としての Future の List

p1

p2

pn

List

パラレルな処理の結果の List の Future

ListFuture

Page 65: 大規模分散システムの現在 -- Twitter

Future は、ある種の並列処理の combinator を提供している。一般的には、これらは、 Future のリストを、少し違ったやり方で、リストの Future に変換する。これは、本質的には、複数の Future を一つのFuture にパッケージするので、都合がいい。

object Future { …    def collect[A](fs: Seq[Future[A]]):       Future[Seq[A]]    def join(fs: Seq[Future[_]]):       Future[Unit]    def select(fs: Seq[Future[A]]) :       Future[(Try[A], Seq[Future[A]])] }

パラレルな処理の合成

Page 66: 大規模分散システムの現在 -- Twitter

先の、ページから最初の画像ページを取り出すプログラムを、少し修正して、あるページの全ての画像ページを取り出すプログラムを作ることができる。

    def getThumbnails(url: String):        Future[Seq[Webpage]] =     fetch(url) flatMap { page =>     Future.collect(     page.imageLinks map { u => fetch(u) }     )     }

ページから、すべての画像ページを取り出すプログラム

a1a2 ・ ・an

a1a2 ・ ・an

collectfan-out

Page 67: 大規模分散システムの現在 -- Twitter

単純な Web Crawler

def crawl(url: String): Future[Seq[Webpage]] = fetch(url) flatMap { page => Future.collect( page.links map { u => crawl(u) } ) map { pps => pps.flatten } }

(* Apocryphal  ほんとかな? )

Page 68: 大規模分散システムの現在 -- Twitter

サービスのモジュールへの分割

Page 69: 大規模分散システムの現在 -- Twitter

Services

future が、いかに並行プラグラミングに利用できるかを見てきた。ここでは、ネットワーク・プログラミングが、いかに、この図式に当てはまるかを見ることにしよう。

RPC は、どうだろうか? リクエストを送る しばらく待つ 成功か、失敗か

これは、関数である。

type Service[Req, Rep] = Req => Future[Rep]

Page 70: 大規模分散システムの現在 -- Twitter

単純なサービスA server: val multiplier = { i => Future.value(i*2)}

A client: multiplier(123) onSuccess { res => println(“result”, r)}

Page 71: 大規模分散システムの現在 -- Twitter

Server 同様に Finagle server は Service をネットワーク

に “ exports” する。 server は、二つの部分を持つ。

1. Service を実装した関数: Req を受け取り、 Future[Rep] を返す。

2. 入ってくる Req をどう“ listen” するかの設定。例えば、 HTTP のリクエストを、 80番ポートで待つ等。

こうして、 Service のロジックと、ネットワーク上どのようにデータが流れるかの設定は、分離される。

Page 72: 大規模分散システムの現在 -- Twitter

Client

Finagl の client は、ネットワークから Service を “ imports” する。概念的には、 Finagle client は、二つの部分からなる。1. Service を利用する関数 : リクエスト Req を送

り、帰って来た Future[Rep] を処理する。2. リクエストをどう送るかの設定。例えば、次のよう

な設定 api.twitter.com のポート 80 に、 HTTP で送る。

Page 73: 大規模分散システムの現在 -- Twitter

Filters

サービスに共通の振る舞いの多くは、サービスに固有の特徴とは無関係である。つぎのようなものがある。 繰り返し 時間切れ 例外処理 統計情報

Filter は、サービスの上で合成される。概念的に言えば、我々は、サービスが「何」なのかとは無関係に、サービスの「振る舞い」 を変えたいのである。

Page 74: 大規模分散システムの現在 -- Twitter

Filter Finagle filter は、次のようなものである。 filter

は、サービスの間に入って、その中を通るデータを変換する。 filter は、サービスとうまく合成できる。 例えば、 rate-limiter フィルターと tweet-serving サービスがあったとすれば、これらを一緒にして、 rate-limited tweet-serving サービスを作ることができる。

Page 75: 大規模分散システムの現在 -- Twitter

Filter は、 service を変形する。 それらは、 service generic な機能を提供できる。例えば、 rate-limiting をサポートすべき複数のサービスがあったとする。一つの rate-limiting フィルターを書けば、それをすべてのサービスに適用できる。 Filter は、また、サービスを異なったフェーズに分解するのにいい働きをする。単純な proxy は、次のような形をしているだろう。ここで、 rewriteReq と rewriteRes は、プロトコルの変換を提供する。

   class MyService(client: Service[..]) extends    Service[HttpRequest, HttpResponse] {   def apply(request: HttpRequest) = {   client(rewriteReq(request)) map { res =>    rewriteRes(res)   }   }   }

Page 76: 大規模分散システムの現在 -- Twitter

filter の例与えられた request と service に対して、それを実行するが、1秒後にタイムアウトする。val timeout = {  (req, service) => service(req).within(1.second)}

request を認証し、それが成功した時にのみ、サービスを実行する。val auth = { (req, service) => if (isAuth(req)) service(req) else Future.exception(AuthErr)}

Page 77: 大規模分散システムの現在 -- Twitter

Filter は、積み重ねられる。val timeout: Filter[…]val auth: Filter[…]val service: Service[…]timeout andThen auth andThen service

def andThen[A](g: (R) ⇒ A): (T1) ⇒ A Composes two instances of Function1 in a new Function1, with this function applied first. def compose[A](g: (A) ⇒ T1): (A) ⇒ R Composes two instances of Function1 in a new Function1, with this function applied last.

Page 78: 大規模分散システムの現在 -- Twitter

Finagle: RPC システム

Page 79: 大規模分散システムの現在 -- Twitter

Finagle

Finagle は、次のことを可能にする クライアントがサービスを提供して、サーバーがそれ

を消費する コンフィグ可能な振る舞いを追加する:

ロードバランシング、コネクション・プーリング、再実行、タイムアウト、割合の制限、モニタリング、統計情報の収集

プロトコル独立性: codec で、ワイア・プロトコルを実装

リソースの管理

Page 80: 大規模分散システムの現在 -- Twitter

Clients

val client = ClientBuilder() .name("loadtest") .codec(Http) .hosts("google.com:80,..") .build()

client は、 Service[HttpReq, HttpRep] である。client(HttpRequest(GET, "/"))

Page 81: 大規模分散システムの現在 -- Twitter

Servers

val service = { req => Future.value(HttpRes(Code.OK, "blah"))}

ServerBuilder() .name("httpd") .codec(Http) .bindTo(":8080") .build(service)

Page 82: 大規模分散システムの現在 -- Twitter

それらをまとめると新しい処理を追加したくなったとしよう。それは簡単である。val backupReq: Filter[…] = { (req, service) => val reqs = Seq( service(req), timer.doLater(delay) { service(req)).flatten } ) Future.select(reqs) flatMap { case (Return(res), Seq(other)) => other.cancel() Future.value(res) case (Throw(_), Seq(other)) => other }}

Page 83: 大規模分散システムの現在 -- Twitter

[昔話 ]SOA と RPC を振り返る

SOA 「サービス指向アーキテクチャー」や RPCやモジュラーなコンポーネントの歴史は古い。ここでは、 2002 年に筆者が行った講演の一部を紹介する。「サービス」概念の抽象化と実装の変化を振り返るのは、興味深い。

Page 84: 大規模分散システムの現在 -- Twitter

2002 年 6月マルレク 「 Web コンポーネンと Web サービス」から

https://goo.gl/wLGyYe

Page 85: 大規模分散システムの現在 -- Twitter
Page 86: 大規模分散システムの現在 -- Twitter
Page 87: 大規模分散システムの現在 -- Twitter
Page 88: 大規模分散システムの現在 -- Twitter
Page 89: 大規模分散システムの現在 -- Twitter
Page 90: 大規模分散システムの現在 -- Twitter
Page 91: 大規模分散システムの現在 -- Twitter
Page 92: 大規模分散システムの現在 -- Twitter
Page 93: 大規模分散システムの現在 -- Twitter

https://goo.gl/4f4Hos

Manhattan, our real-time, multi-tenant

distributed database for Twitter scale

https://goo.gl/MROsMq

Page 94: 大規模分散システムの現在 -- Twitter

Manhattan

開発の背景と要請 大規模システムでの信頼性 Storage System Storage Service Storage as a Service

Page 95: 大規模分散システムの現在 -- Twitter

Data Platform Landscape Map 次の電車の路線図みたいのは、必見。拡大して、よ

く見て欲しい。世の中のデータストアの地図だ!! 真ん中右の白いエリアがリレーショナル・データ

ベース、右下のグリーンのエリアが、 Grid/Cacheのエリア。残りのグレーの部分が、 NonSQL のエリア。「エリア」内の「各駅」が、 General Purposeとか、 Key Value とか、 Graph といった「路線」でつながっている。 571 もある。

https://goo.gl/rQ6XHc

Page 96: 大規模分散システムの現在 -- Twitter
Page 98: 大規模分散システムの現在 -- Twitter

Manhattan 開発の背景 Twitter が、パブリックな自己表現と会話のグローバ

ルなプラットフォームに成長するにつれ、我々のストレージに対する要請も増大した。この数年間にわたって、我々は、リアルタイムの環境の中で、非常に低い遅延で、毎秒数百万のクエリーに応えられるストレージ・システムが必要であることに気づいていた。

可用性とシステムのスピードが、最も重要な要素になっていた。単に、早いことが必要なだけでなく、世界中のいくつかの地域をまたいで、スケーラブルである必要があった。

Twitter のリアルタイムの本性は、既存のオープンソース製品が提供しているものより、低い遅延を要求していることに、我々は気づいていた。

Page 99: 大規模分散システムの現在 -- Twitter

データベースに対する要請 Reliability: Twitter のサービスは、予測可能なパ

フォーマンスを持った耐久性のあるデータストアを必要としている。それは、失敗やスピード低下や急拡大や負荷集中その他、想定できるあらゆる事態を通じて、信頼できるものである。

Availability: 我々のユースケースの大部分は、整合性以上に可用性を強く望んでいる。それゆえ、常に稼働している、 eventually consistent なデータベースは、必須であった。

Page 100: 大規模分散システムの現在 -- Twitter

Extensibility: 我々の構築するテクノロジーは、我々の要請の変化に応じて、発展することが可能でなければならない。それゆえ、新しいストレージ・エンジンから強い整合性にいたる、あらゆるものがその上に構築される、強固でモジューラー型の基礎を持たなければならない。さらに追加すれば、スキーマのない key-value データ・モデルが、大部分の顧客のニーズにフィットし、構造をあとで追加する余地を持つことを可能にする。

Operability: クラスターが、数百から数千のノードに成長するにつれ、もっとも単純なオペレーションは苦痛になり、オペレーターの時間を奪う。マンパワーを効率的にスケールさせるために、最初の日から運用を容易なものにする必要がある。すべての新しい特徴について、運用の複雑さと診断の容易さについて、我々は考えた。

Page 101: 大規模分散システムの現在 -- Twitter

Low latency: リアルタイムのサービスとして、 Titter の製品は、整合性をもった低遅延を要求する。低遅延のパフォーマンスを保証するために、 Twitter固有のトレードオフを行わなければならない。

Real-world scalability: スケールの変化は、分散システムでは、普遍的なものである。 Twitterは、ある点でだけスケールできるデータベースではなく、コストの効率性や運用の容易さを犠牲にすることなく、すべてのメトリック -- クラスターのサイズ、一秒あたりのリクエスト、データのサイズ、地理的な拡大、顧客数 --等において、新しい高みに成長を続けられるデータベースを必要とする。

Developer productivity: 会社の開発者は、サービスを構築するために必要とされるものすべてを、セルフ・サービス型のプラットフォームとして、ストレージの技術者の干渉を必要としないで、蓄積できる必要がある。システムは、彼らから見れば、「いつも動いている」ものである。

Page 102: 大規模分散システムの現在 -- Twitter

大規模システムでの信頼性

Manhattan の構築を始めた時、 Twitter には、すでに沢山の大規模なストレージ・クラスターがあった。それで、我々は、大規模なシステムを走らせることからくる挑戦を理解していた。それは、新しいシステムでは、どのような性質を望み、どれを避けなければいけないかを教えていた。

Page 103: 大規模分散システムの現在 -- Twitter

最悪ケースのパフォーマンス 信頼できるストレージシステムというのは、運用の

あらゆる場面でうまく稼働することを信用できるシステムである。そして、予測可能なパフォーマンスは、達成するのは難しいのだ。予測可能なシステムでは、最悪ケースのパフォーマンスが、本質的に重要になる。平均的なパフォーマンスは、大きな問題にならない。よく実装され、正しく配備されたシステムでは、平均的なパフォーマンスが、関心を引くことはほとんどない。

我々は、最悪ケースのスループットのために設計・配備を行う必要がある。

Page 104: 大規模分散システムの現在 -- Twitter

予測可能であることの、この優先順によって、いかなる潜在的な問題、失敗のモードのあいだでも、いいパフォーマンスのためにプランが必要となる。顧客は、我々の実装の詳細にも、言い訳にも興味がない。我々のサービスが、彼らと Twitter にとって、動いているか動いていないかが問題なのである。たとえ、全くありそうもない問題に直面して、好ましくないトレードオフを行わなければいけないことになったとしても、我々が記憶せねばならないのは、稀な出来事というのは、大規模システムでは、もはや稀ではないのだということである。

スケールとともに、マシンやリクエストやデータの量が巨大になるばかりではなく、そのシステムを利用しサポートする両方の人間の数が増大するという人間のスケールの要因が生まれてくる。幾つかの関心にフォーカスして、我々は、この問題を管理している。

Page 105: 大規模分散システムの現在 -- Twitter

ストレージ・システムの構築

次世代のストレージシステムを構築する際、我々は、システムを幾つかの階層に分割することを決めた。そうすることで、システムは、十分なモジュラー性を持ち我々がその上で構築できるものに、強固な基礎を提供する。また、大きな変更を行うことなしに、少しずつ特徴をロールアウトすることが可能になる。

Page 106: 大規模分散システムの現在 -- Twitter

Manhattan の階層 我々は、 Manhattan を、以下の四つの階層に分離し

た。 interfaces, storage services, storage engines 、 core である。

Page 107: 大規模分散システムの現在 -- Twitter

Core core は、ストレージシステムの最もクリティカルな側面である。それは、高度に安定していて頑健である。 core は、失敗、結果整合性、ルーティング、トポロジーの管理、データセンター内・データセンター間の複製の作成、衝突の解決を処理する。システムの core の内部では、アークテクチャー上重要な部分は、完全に差し替え可能になっていて、速いスピードでデザインや改良を繰り返すことができる。同様に、ユニット・テストも効果的に行われる。

Page 108: 大規模分散システムの現在 -- Twitter

整合性のモデル Twitter のアプリケーションの多くは、 eventually

consistent モデルに、非常によくフィットする。我々は、ほとんどすべてのユースケースで、整合性より高可用性を好む。それで、 Manhattan を、 core の部分では、 eventually consistent なシステムとして構築したのは、自然なことであった。

しかし、データについて、強い整合性を要求するアプリケーションは、常にあり得る。そうしたシステムを構築することは、多くの顧客を得るために、高いプライオリティがあった。

強い整合性は、 opt-inモデルである。開発者は、そのトレードオフをよく知っていなければならない。

Page 109: 大規模分散システムの現在 -- Twitter

整合性の追求 eventually consistent なシステムで整合性を達成

するためには、我々がレプリカの調停と呼んでいる、要求されたメカニズムが必要になる。このメカニズムは、 incremental でなければならず、また、常にレプリカ間のデータを調整するプロセスが走っている必要がある。それは、ビット落ちやソフトウェアのバグや書き込みの失敗(ノードが長い期間ダウンした)、データセンター間の分離などに直面した時に役に立つ。

read-repair hinted-handoff

Page 110: 大規模分散システムの現在 -- Twitter

Storage engines 我々は、現在、三つのストレージ・エンジンを持っ

ている。

seadb : Hadoop からのバッチ処理のデータのための読み取り専用のファイル・フォーマット。

sstable : 重い書き込み処理のための、ログ構造のmerge tree ベースのフォーマット。

btree : 重い読み出し、軽い書き出しのためのbtree ベースのフォーマット。

すべてのストレージエンジンは、ブロック単位の圧縮をサポートしている。

Page 111: 大規模分散システムの現在 -- Twitter

二つの整合性モデル

三つの Storage Engine

二つの整合性モデル、三つの Storage Engine

Page 112: 大規模分散システムの現在 -- Twitter

ストレージ・サービス

我々は、 Manhattan の core の上に、開発者が伝統的なデータベースから期待するようになるかもしれない特徴を、もっと頑健なものにすることを可能にする、追加のサービスを作り出した。

Page 113: 大規模分散システムの現在 -- Twitter

Batch Hadoop importing もともとの、 Manhattan のユースケースの一つ

は、 Hadoop で生み出されるデータ上で、効率的にサービスを提供する層というものだった。

我々は、顧客が HDFS 上に単純なフォーマットのデータセットを作り出すことを可能にする、インポート用のパイプラインを構築し、その場所をセルフサービスのインターフェースに指定した。我々のWatcher が、自動的に新しいデータセットをピックアップし、それを HDFS の中の seadb に変換する、だから、それらは、 SSD からでもメモリーからでも、高速にクラスターにインポートされる。

Page 114: 大規模分散システムの現在 -- Twitter

binary diffs このインポート用のパイプラインは、ストリーム・

ライン化されて扱いが容易なので、我々は、成長を続けるデータセット上で、開発者が、直ちに開発を繰り返し行えるようにすることにフォーカスした。顧客から我々が学んだ一つの教訓は、彼らは、巨大な数テラバイトもあるデータセットを作る傾向があるということだった。その後のデータセットの更新では、典型的には、 10-20% 以下のデータしか変更されないにもかかわらずだ。我々は、このデータをレプリカにダウンロードするときに適用することができる binary diffs を作ることで、ネットワークの帯域を低減するための最適化を組み込んだ。これによってデータセンター間のすべてのデータのインポート時間を、実質的に低減した。

Page 115: 大規模分散システムの現在 -- Twitter

強い整合性のサービス 強い整合性のサービスは、顧客がある一群の操作を

行うときに、強い整合性を持つことを可能にする。我々は、コンセンサス・アルゴリズムと複製されたログをペアで利用して、すべてのレプリカにイベントが順番どうりに到達することを保証した。これで、 Check-And-Set (CAS)や、強い読み込み、強い書き出しのような操作を行うことを可能にした。今日では、 LOCAL_CAS と GLOBAL_CAS と呼ばれている二つのモードをサポートしている。 GLOBAL_CAS は、複数のデータセンターの quorumをまたいで、強い整合性の操作を開発者に可能にする。一方、 LOCAL_CAS は、それが発行されたデータセンターの内部でだけ、調整される。両方の操作とも、遅延とアプリケーションのモデリングで、異なったトレードオフを持つ。

Page 116: 大規模分散システムの現在 -- Twitter

Timeseries Counters service 我々は、 Manhattan で、大きな容量を持つ時系列のカウンターを扱う、極めて特殊なサービスを開発した。このサービスを要請した顧客は、一秒あたり数百万のカウンター・インクリメントを扱うことを必要としていた、我々の Observability インフラであった。

このスケールのレベルでは、耐久性の課題、インクリメントの前にそれが警報システムに見えるために必要とされる遅延の問題、また顧客からのどのような種類の秒以下のトタフィックのパターンなら耐えられるのかといった問題等々、様々な事柄でのトレードオフのデザインについて合意する必要があるのだが、合意に至るまで、我々の技術者は、演習に駆り出された。

Page 117: 大規模分散システムの現在 -- Twitter

ツール 我々は、 host group と weight の入ったファイルを編集するだけで、システム全体のトポロジーを変更させ、再起動のような共通の操作を、ノード全体で一つのコマンドで実行できることを可能にするようなツールから始めた。こうした初期のツールでさえも、あまりにも煩わしいものになり始めたころ、クラスターの状態を目標とする単純なコマンドを受け入れる自動化されたエージェントを構築した。それは、オペレーターからの注意を引くこともなく、安全に効率的に、命令をスタックし結合し実行することができる。

Page 118: 大規模分散システムの現在 -- Twitter

Storage as a service 既存のデータベースで我々が見てきた共通の問題

は、それが、ユースケースのある特別な集まりに対して、設定され管理されるようにデザインされていることだった。 Twitter の新しい内部サービスが成長するにつれ、我々が認識したのは、そうしたことは、我々のビジネスには効率的ではないということだった。

我々のソリューシンは、 storage as a service というものだ。我々は、エンジニアと運用者のチームに、エンジニアをコントロールする、完全なセルフサービスのストレージ・システムを構築することによって、大きな生産性の改善を提供してきた。

Page 119: 大規模分散システムの現在 -- Twitter
Page 120: 大規模分散システムの現在 -- Twitter

Storage as a service エンジニアは、彼らのアプリケーションが必要とす

るもの(ストレージのサイズ、一秒あたりのクエリー等)を与え、ハードウェアがインストールされスキーマが設定されるのを待つことなしに、瞬時にストレージの利用を開始することができる。

会社内の顧客は、我々の運用チームが管理するマルチ・テナントな環境で実行する。セルフサービスとマルチ・テナントのクラスターを管理することは、ある種のチャレンジだった。それで、我々は、このサービス層を、第一級の特徴として扱った。

Page 121: 大規模分散システムの現在 -- Twitter

Storage as a service 我々は顧客に、データと処理を、見える形で提供し

た。 quota の機能強化と rate制限を組み込んで、エンジニアが、彼らの定義された制限を超えた時には警告を受け取るようにした。我々のすべての情報は、分析と報告のため Capacity and Fleet Managementチームに、直接送られる。

エンジニアが新しい特徴をローンチすることを容易にすることで、我々が見たのは、実験が活発に立ち上がり、新しいユースケースが急速に増えたということだった。これらをうまくハンドルするために、これらのデータを、コスト分析に結びつける内部の API を開発した。これによって、どのユースケースが最もビジネスにコストをかけ、また、どのユースケースがおきそうもないかを決定することができた。

Page 122: 大規模分散システムの現在 -- Twitter

マルチ・テナンシーと QoS マルチ・テナンシーをサポートすることは、多くの

異なったアプリケーションが、同じリソースを共有することを意味するのだが、それは、当初からキーとなる重要な要請だった。それ以前のシステムを我々は Twitter で管理していたのだが、我々は、すべての特徴ごとにクラスターを構築していた。それは、オペレーターの負荷を高め、リソースを浪費し、顧客が新しい特徴を生み出すのを遅れさせていた。

先にも述べたように、複数の顧客が同じクラスターを使うことを認めることは、我々のシステム実行のチャレンジを増大させる。我々は、今では、隔離、リソースの管理、複数の顧客の容量のモデリング、 rate の制限、 QoS 、 quota 、その他たくさんのことを考えなければならない。

Page 123: 大規模分散システムの現在 -- Twitter

マルチ・テナンシーと QoS 顧客に可視性を与えることに加えて、顧客は良き市民であることが求められる。我々は、我々自身のrate制限サービスを、顧客のリソースや quota の利用を強制するためにデザインした。我々は、モニターし、必要であれば、リソース利用を絞る。それは、多くのメトリックを通じて、システム上では、誰のアプリケーションも他人のアプリに影響を与えないことを保証するためである。 rate制限は、荒い粒度ではなく、秒以下のレベルで起きる。実世界の利用で起きるある種のスパイクの間、耐えるために。

Page 124: 大規模分散システムの現在 -- Twitter

マルチ・テナンシーと QoS 我々は、すべての顧客からデータを抽出して、それ

を Capacity チームに送るという必要から API を構築した。 Capacity チームは、 ( Twitter の標準によれば)小規模ないしは中規模の要求をもった顧客に対して、我々はいつも準備ができた利用可能なリソースがあることを保証するために働いている。だから、これらのエンジニアには、我々からの追加のヘルプは必要でない。こうしたこと全てを直接セルフ・サービスに統合することで、顧客は我々の大規模マルチテナントクラスター上に、新しい特徴をより早くローンチすることが可能になり、我々は、もっと簡単にトラフィックのスパイクを吸収することが可能になる。というのも、大部分の顧客は、リソースの全てを、全ての時間で使うことはないからだ。

Page 125: 大規模分散システムの現在 -- Twitter

将来展望 我々は、将来に、まだ多くの仕事を残している。挑戦は、増え続いており、 Manhattan 上で内部的にローンチされる特徴の数も、速いペースで増え続けている。我々自身を、より良いよりスマートなものへと強く押しているのは、 Core Storage チームで我々を駆り立てているものだ。我々は我々の価値に誇りを持っている。 twitter を良くするために何ができるか、我々の顧客を成功させるにはいかにすればいいか? 我々は、 Manhattan についてもっと技術的な詳細と、我々が、製品として 2 年以上の稼働の間に学んだものは何かを概括したホワイト・ペーパーのリリースを計画している。期待してほしい。

Page 126: 大規模分散システムの現在 -- Twitter
Page 127: 大規模分散システムの現在 -- Twitter

Mesos データセンター OS とその影響の拡大

Mesos Aurora Docker Containerizer Mesosphere Mesos の影響の拡大

Page 128: 大規模分散システムの現在 -- Twitter

Mesos Datacenter Operation System

“Program against your datacenter like it’s a single pool of resources”http://mesos.apache.org/ 

Page 129: 大規模分散システムの現在 -- Twitter

Mesos とは何か? Mesos は、自分を次のように規定している。

「分散アプリケーション、すなわち、フレームワークをまたいで、効果的なリソースの分離と共有を提供するクラスター・マネージャー」

Mesos の中心プロジェクトは、オープンソースのApache インキュベーター・プロジェクトである。Mesos の上に、例えば、 Stormや Hadoop といった特別の技術を扱うスケジューラーを走らせることができる。そのアイデアは、同じハードウェアは、複数の目的のために利用でき、リソースの浪費を低減できるというものである。

http://goo.gl/Ax9LVw

Page 130: 大規模分散システムの現在 -- Twitter

Mesos とは何か? 数万のノードへの Scalability ZooKeeper を使った、 Fault-tolerant なマスター

とスレーブのレプリカ管理 Docker コンテナーのサポート Linux コンテナーでの、タスク間のネーティブな隔

離 マルチ・リソース (memory, CPU, disk, ports) の

スケジューリング 新しいパラレル・アプリケーションを開発するため

の Java, Python, C++ APIs クラスターの状態を見る Web UI

Page 132: 大規模分散システムの現在 -- Twitter

Mesos の主要なコンポーネント 次の図は、 Mesos の主要なコンポーネントを表して

いる。

Mesos は、それぞれのクラスター上のノードで走るスレーブ・デーモンと、それを管理するマスター・デーモン、これらのスレーブ上でタスクを走らせるアプリケーション(これは、フレームワークとも呼ばれる)から構成される。

Page 133: 大規模分散システムの現在 -- Twitter

Framework

Page 134: 大規模分散システムの現在 -- Twitter

マスターとリソース・オファー マスターは、アプリケーションがリソースのオ

ファーを行うことで、アプリケーション間の細かな粒度でのリソース( CPU, RAM等)の共有を可能にする。

それぞれのリソース・オファーは、それらのリストを含んでいる。マスターは、与えられた( fair sharing, strict priority といった)組織的なポリシーに応じて、どれだけのリソースをそれぞれのフレームワークに提供するかを決定する。

多様なポリシーの集合をサポートするために、マスターは、プラグインのメカニズムを通じて、容易に新しいモジュールを割り当てられるように、モジュラー・アーキテクチャーを用いている。

Page 135: 大規模分散システムの現在 -- Twitter

scheduler と executor Mesos の上で走っているフレームワークは、二つの

コンポーネントからなる。一つは、フレームワークの scheduler(スケジューラー)で、マスターに提供されるべきリソースを登録する。もう一つは、 executor プロセスで、スレーブノード上で起動されてフレームワークのタスクを実行する。

マスターは、どれだけの量のリソースが、それぞれのフレームワークに提供されるかを決定し、その一方で、フレームワークのスケジューラーは、どの提供されたリソースを使うかを決定する。フレームワークが、提供されたリソースを受け取る時には、Mesos に、実行しようと思っているタスクの記述をMesos に渡す。その代わりに、 Mesos は、対応するスレーブ上で、タスクを起動する。

Page 136: 大規模分散システムの現在 -- Twitter

リソース・オファーの例

フレームワーク

Mesosマスター

Mesosスレーブ

Page 137: 大規模分散システムの現在 -- Twitter

リソース・オファーのプロセス① Slave 1 は Master に、自分には 4 CPU あって 4

GB のメモリーが空いていると報告する。報告を受けると Master は、 Allocation Policy Module を呼び出す。 Allocation Module は、 Framework 1 が、利用できるリソースを求めていると伝える。

② Master は、 Slave 1 にこれだけの利用可能なリソースがあると Framework 1 にリソース提供を申し出る。

③ Framework 1 のスケジューラは、 Master に二つのタスクを Slave 1 で走らせて欲しいと応答する。一つ目のタスクは <2 CPUs, 1 GB RAM> で、二つ目のタスクは <1 CPUs, 2 GB RAM> でという情報と一緒に。

Page 138: 大規模分散システムの現在 -- Twitter

リソース・オファーのプロセス④ 最後に、 Master は、 Slave 1 にタスクを送る。そ

れは、 Slave1 の Framework1 の実行エンジンに適切なリソースを割り当てる。こうして、二つのタスクが起動される(図での、 Slave 1 の点線で囲まれた部分)。 Slave 1 の、 1 CPU と 1 GB のメモリーは、アロケートされていないので、 Framework 2 のタスクに使われるかもしれない。

このリソース提供のプロセスは、タスクが終了して、新しいリソースがフリーになった時には、繰り返される。

Page 139: 大規模分散システムの現在 -- Twitter

フレームワークの制約条件とdelay scheduling

Mesos によって提供される薄いインターフェースは、フレームワークが独立に、スケールし発展することを許すのだが、一つの疑問が残る。すなわち、フレームワークの制約条件は、 Mesos がこれらの制約条件を知らなくとも、満たされることはできるのかということである。

例えば、 Mesos がフレームワークが必要とするデータが、どのノードにあるのかを知らないままで、フレームワークは、どのようにしたら、データの局所性を実現することはできるのだろうかという問題である。

Mesos の、こうした問題に対する答えは、フレームワークにオファーを断る能力を与えるという単純なものである。あるフレームワークは、自身の制約条件を満たさないオファーは断り、満たすもののみを受け入れるのだ。

Page 140: 大規模分散システムの現在 -- Twitter

フレームワークの制約条件とdelay scheduling 特に、入力データを格納するノードを見つけるま

で、制限時間のあいだは、フレームワークは待機するという、 delay scheduling と呼ばれている単純なポリシーが、ほとんど最適なデータの局所性を与えることを、我々は、見つけ出した。

Page 141: 大規模分散システムの現在 -- Twitter

http://aurora.apache.org/

Apache Aurora長時間走るサービスと

cron ジョブのためのフレームワーク

Page 142: 大規模分散システムの現在 -- Twitter

Apache Aurora

Apache Aurora は、 Mesos 上で走るサービス・スケジューラーである。それは、 Mesos のスケーラビリティ、耐障害性、リソース隔離の利点を生かして、長時間走るサービスを走らせることを可能にする。 Apache Aurora は、現在は、 Apache Incubator の一部である。https://github.com/apache/aurora/blob/master/docs/tutorial.md

Page 143: 大規模分散システムの現在 -- Twitter

Aurora: Job Aurora は、 Mesos 上で job をスケジュールするた

めに利用される Mesos のフレームワークである。 Mesos は、個々の task を面倒見るのだが、典型的な job は、数百にも昇る task のレプリカを持つ。 Aurora は、 Mesos の上に、 job という抽象の層を提供する。

Aurora の job は、 task のテンプレートと、そのtask とほとんど等しい task のレプリカ(” instance id” が違うとか、マシンごとにポート番号が違うとか。それ以外は、ほぼ同じ。)を生成する命令からなる。

いくつの task が job を構成するかは、複雑である。基本的には、一つの job は、一つの task テンプレートとその task とほとんど等しい task のレプリカ(”インスタンス”とか“ shard” と呼ばれることもある)を生成する命令からなる。

Page 144: 大規模分散システムの現在 -- Twitter

Aurora: task と process task は、一つのコマンドラインの命令(例えば、

my_script.py のような)に対応した、一つのprocess にすぎないこともある。ただし、 taskは、その全てが一つの sandbox 上で走る沢山の別々の process から構成されることもある。例えば、 logrotate, installer, master, slave というような複数のエージェントが協調して走ることがある。

こうした時、 Thermos が登場する。 Aurora がMesos の Task 上で Job の抽象を与えるように、 Thermos は、 Mesos の Task の下で、 Aurora フレームワークの executor の一部としてサービスし、 Process の抽象を与える。

Page 145: 大規模分散システムの現在 -- Twitter
Page 146: 大規模分散システムの現在 -- Twitter

Aurora の階層 Aurora は、 task からなる job を管理する。 Mesos は、 process からなる task を管理する。 Thermos は、 process を管理する。 全ては、 .aurora 設定ファイルで定義される。

Page 147: 大規模分散システムの現在 -- Twitter

Sandbox それぞれの Task は、 Task が起動した時に生成さ

れ、それが終了した時に、ガーベージコレクトされる Sandbox を持つ。

全ての Task の Process は、この sandbox の中で走る。だから、 process は、共有された current working directory を使って、状態の共有が可能である。

Sandbox のガーベージ・コレクションのポリシーは、多くのファクターを考慮して決める必要がある。もっとも重要なのは、経過時間とサイズである。

Page 148: 大規模分散システムの現在 -- Twitter

Aurora で Hello World!

Aurora で、 Hallo World! を実行してみよう

Aurora で

Page 149: 大規模分散システムの現在 -- Twitter

import sys import time

def main(argv): SLEEP_DELAY = 10 # Python ninjas - ignore this blatant bug. for i in xrange(100): print("Hello world! The time is now: %s. Sleeping for %d secs" % ( time.asctime(), SLEEP_DELAY)) sys.stdout.flush() time.sleep(SLEEP_DELAY)

if __name__ == "__main__": main(sys.argv)

hello_world.py

Page 150: 大規模分散システムの現在 -- Twitter

pkg_path = '/vagrant/hello_world.py'

# ファイルの中身に応じて設定を変える。ここでは、バージョン番号に、# ファイルの chekusum を使う。import hashlib with open(pkg_path, 'rb') as f: pkg_checksum = hashlib.md5(f.read()).hexdigest()

# hello_world.py をローカルの sandbox にコピー install = Process( name = 'fetch_package', cmdline = ‘cp %s . && echo %s && chmod +x hello_world.py’ % (pkg_path, pkg_checksum))

# スクリプトの実行hello_world = Process( name = 'hello_world', cmdline = 'python hello_world.py')

Aurora の設定ファイルhello_world.aurora

Page 151: 大規模分散システムの現在 -- Twitter

# task の記述 # install と hello_world をシーケンシャルに実行する。hello_world_task = SequentialTask( processes = [install, hello_world], resources = Resources (cpu = 1, ram = 1*MB, disk=8*MB))

# job の記述jobs = [ Service ( cluster = 'devcluster', environment = 'devel', role = 'www-data', name = 'hello_world', task = hello_world_task ) ]

Aurora の設定ファイルhello_world.aurora  (続き)

Page 152: 大規模分散システムの現在 -- Twitter

Aurora の設定ファイルがしていること まず、二つの process 、 install と hello_world を定義。   install = Process( ... )   hello_world = Process( ... )

ついで、この二つの process をシーケンシャルに実行する Task を定義する。   hello_world_task = SequentialTask( ... )

この Task定義の際に、 Mesos が利用できるように、この task が利用可能な計算リソースも定義しておく。   resources = Resources(                      cpu = 1,                       ram = 1*MB,                      disk=8*MB)             )

Page 153: 大規模分散システムの現在 -- Twitter

Aurora の設定ファイルがしていること 最後に、 Job の定義。 Job は、利用可能なマシン上

に Task をスケジュールする。この例では、 Job はJob リストの唯一のメンバーだが、 config ファイルでは、一つ以上の Job を指定できる。   jobs = [      Service(       cluster = ‘devcluster’,        environment = ‘devel’,        role = ‘www-data’,        name = ‘hello_world’,        task = hello_world_task     )    ]

Page 154: 大規模分散システムの現在 -- Twitter

Aurora の設定ファイルがしていること Process レベルでは、この設定ファイルは、コード

が走るローカルの sandbox に、どのようにコードをインストールするのかを指定している。   install = Process( ... )  

ついで、第二のプロセスが起動した時、実際に、どのようにコードが実行されるかを指定している。   hello_world = Process( ... )

Page 155: 大規模分散システムの現在 -- Twitter

Job の生成と実行aurora job create ... 実際に、我々の job を走らせる Aurora クライアン

ト・コマンドは、 aurora job create である。それは、 job key と、 config ファイルを引数に取り、それらで指定された job を生成しそれを実行する。

aurora job create devcluster/www-data/devel/hello_world /vagrant/hello_world.aurora

job key

Aurora Configuration File

Page 156: 大規模分散システムの現在 -- Twitter

job key の構成 job key は、“ /” で区切られた四つの部分からなる。四つ

の部分は、次のような部分から構成される。

<cluster>/<role>/<environment>/<jobname>

先のコマンドの例で言うと、次のようになる。

   devcluster/www-data/devel/hello_world

     cluster role environment jobname

Page 157: 大規模分散システムの現在 -- Twitter

job key と job の一意な指定 Cluster : cluster の名前。 Role :その slave マシン上に存在する、ユーザーの

アカウント名。 Environment :名前空間。” prod” (製品版)、 “ devel”(開発版)、” test” (テスト用) の三つが用意されている。

Jobname:job名

二つの job key を比較して、四つの構成要素が対応する要素と、一つでも違っていれば、二つの job key は、二つの別々の job を指定していることになる。四つの値が全て同じであれば、この job keyは、同一の job を指定する

Page 158: 大規模分散システムの現在 -- Twitter

cluster の定義 この job key の指定は、よく見ると、この例では、

*.aurora の Aurora設定ファイルが、   jobs = [      Service( ... ) ... ]の中で、 Service のパラメータに設定されたものと重複している。( job を Task に結びつける、 task = ... というパラメータを除いては)

それぞれのパラメーターの説明は、これから、おいおいすることにして、まず、先頭の cluster は、どのように定義されているのだろうか?

Page 159: 大規模分散システムの現在 -- Twitter

cluster の設定 /etc/aurora/clusters.json cluster の設定は、 /etc/aurora/clusters.json という

ファイルの中で行われている。こんな中身だ。

   [{ “name”: “devcluster”,     “ zk”: “192.168.33.7”,    “ scheduler_zk_path”: “/aurora/scheduler”,    “ auth_mechanism”: “UNAUTHENTICATED”    }]

Page 160: 大規模分散システムの現在 -- Twitter

Marathon とChronos

Page 161: 大規模分散システムの現在 -- Twitter

Marathon と Chronos Marathon:

長時間走るアプリのための Apache Mesos のフレームワーク。 Mesos がデータセンターの kernel だとすれば、 Marathon は、 init デーモンにあたる。https://github.com/mesosphere/marathonhttp://mesosphere.github.io/marathon/   

Chronos:同じく、 Apache Mesos のフレームワークで、 cron に相当する。https://github.com/mesos/chronoshttp://mesos.github.io/chronos/

  

Page 162: 大規模分散システムの現在 -- Twitter

Marathon によって起動された Task と、Chronos によって起動された Task 。

Chronos は、Marathon によって起動されている。

Chronos によって定期的に、 dump-dbや、 rake emailsend が呼び出されている。

http://mesosphere.github.io/marathon/

Page 163: 大規模分散システムの現在 -- Twitter

Scale out

Server Error再配置

Marathon の仕事

Page 164: 大規模分散システムの現在 -- Twitter

Apache Mesos 0.20/Apache Aurora 0.7 で、 Docker サポート

Page 166: 大規模分散システムの現在 -- Twitter

Docker Containerizer Mesos 0.20.0 は、 Docker イメージを含んだ task

の実行のサポートを追加した。また、 Docker でサポートされているオプションのいくつかを、将来的には追加していく。

ユーザーは、 Docker のイメージを、 Task あるいは Excutor として実行できる。

slave が、 Docker Containerizer を実行可能にするためには、 containerizer のオプションの一つとして、” docker” を指定する必要がある。次のように。

  mesos-slave –containerizers=docker,mesos Docker containerizer を持つ、それぞれの slave

には、 Docker CLI client (version >= 1.0.0) がインストールされる必要がある。

Page 167: 大規模分散システムの現在 -- Twitter

Docker Containerizer をどのように利用するか? 0.20.0 以前の TaskInfo は、 bash コマンドを走らせ

る CommandInfo を設定するか、 task を起動する特別の Executor を起動する ExecutorInfo を設定するか、どちらかのサポートのためにのみ利用されていた。

0.20.0 では、 TaskInfo と ExecutorInfo に、 我々は、 ContainerInfo フィールドを追加して、 Docker のような Containerizer が、 task あるいは executor の実行を設定されることを可能にした。

Page 168: 大規模分散システムの現在 -- Twitter

Docker イメージを task として実行するためには、TaskInfo の中で、コマンドとともに、 Docker Containerizer が Docker イメージを起動するために、それに伴って利用するコマンドのコンテナー・フィールドの、両方を設定しなければならない。 この ContainerInfo は、 Docker という type と、 希望する docker イメージを持つ DockerInfo を持たなければならない。

Docker イメージを、 executor として実行するためには、 TaskInfo の中で、 type docker を持つContainerInfo と、 executor を起動するために利用される CommandInfo を含む、 ExecutorInfo を設定しなければならない。

Docker イメージは、 Mesos executor として立ち上がることが期待されていることに留意すること。それは、一回起動された際に、 slave とともに、登録するだろう。

Page 169: 大規模分散システムの現在 -- Twitter

Docker Containerizer は、何をしているのか? Docker Containerizer は、 Task/Executor の

Launch と Destroy 呼び出しを、 Docker CLI コマンドへ変換している。

現時点で、 Docker Containerizer は task として起動された時、次のことをしている。

1. CommandInfo で指定されたファイルをすべて、 sandbox に取り込む。

2. リモート・リポジトリーから docker イメージを取得。

Page 170: 大規模分散システムの現在 -- Twitter

Docker Containerizer は、何をしているのか?3. Docker executor は、

docker イメージを実行し、 sandbox のディレクトリーを Docker コンテ

ナーにマップし、 ディレクトリー・マッピングを

MESOS_SANDBOX環境変数にセット executor は、コンテナのログを sandbox の

stdout/stderr ファイルに流し込む。4. container exit あるいは、 containerizer destroy

で docker コンテナーを stop 、 remove する。

Page 171: 大規模分散システムの現在 -- Twitter

Docker Containerizer は、先頭に”mesos-” がつき、その後ろに slave の id が続く(例えば、 mesos-slave1-abcdefghji のような)名前を持つ、すべてのコンテナーを起動する。そして、”mesos-” の名前を持つすべてのコンテナーは、 slave によって管理され、自由にコンテナーをstop あるいは kill できると想定する。

Executor として docker イメージを起動する時には、ただ一つの違いは、 executor コマンドをスキップして、 docker コンテナーの executor の pidを取得することだけである。

Page 172: 大規模分散システムの現在 -- Twitter

docker イメージを実行する時、現時点では、デフォールトでは、ホストのネットワークに繋がっていることに留意すること。それは、 Executor として docker イメージの実行をサポートするのを容易にするためである。

containerizer は、イメージを強制的に取得する機能も、オプションとしてサポートしている。 これがオフにされていると、 docker イメージは、ホストで利用できない場合にしか再更新されない。

Page 173: 大規模分散システムの現在 -- Twitter

プライベート Docker レポジトリー イメージをプライベート・レポジトリーから実行す

るために、 ログイン情報を含んでいる .dockercfgをポイントしている uri を含めることができる。 この .dockercfg ファイルは sandbox に引き出されて、 Docker Containerizer は、 HOME環境変数を、この sandbox をポイントするように設定する。それで、 docker の cli は、自動的に config ファイルをピックアップできる。

Page 174: 大規模分散システムの現在 -- Twitter

Docker イメージを実行するCommandInfo docker イメージは、現時点では、 entrypoint とデ

フォールト・コマンドをサポートしている。 docker run image のように、デフォールト・コマ

ンドで docker イメージを実行するためには、 CommandInfo の値が設定されていなければならない。もし、値が設定されていれば、それはデフォールト・コマンドを上書きする。

定義された entrypoint で docker イメージを走らせるためには、 CommandInfo の shell オプションは、 false に設定されていなくてはならない。それが true の時、 Docker Containerizer は、 /bin/sh -c でラップされたユーザーコマンドを実行する。それはまた、イメージの entrypoint へのパラメーターにもなる。

Page 175: 大規模分散システムの現在 -- Twitter

slave の recovery で、 Docker コンテナーを回復する Docker containerizer は、 slave が再起動した時、

Docker コンテナーの recovery をサポートしている。それは、 slave が docker コンテナーの中で走っていても、そうでなくとも、両方でサポートされる。

With the docker_mesos_image フラグが立っていれば、 Docker containerizer は、このconternerizer がコンテナー自身の内部で走っていると想定する。そして、 docker コンテナーが、それに従って recoverや launch を行うメカニズムを修正する。

Page 176: 大規模分散システムの現在 -- Twitter

Mesosphere

Page 177: 大規模分散システムの現在 -- Twitter

Mesosphere DCOS と Apache Mesos の違い Mesosphere DCOS は、オープンソースの Mesos

上に構築された、商用サポートのあるソフトウェア製品。コマンドライン、 Web インターフェース、パッケージングやインストールが強化されている。また、技術的なパートナーとのエコシステムも拡大している。

Mesosphere DCOS は、オープンソースではない。ただそれは、オープンソースの Apache Mesos, Marathon, Chronos に基づいている。

Page 178: 大規模分散システムの現在 -- Twitter

The Mesosphere Datacenter Operating System

「自分のデータセンターやクラウドを、 Mesosphere データセンター・オペレーティング・システムで、自動運転させる。時間とお金を節約して、ソフトウェアはより早く配布する。」

https://mesosphere.com/

Page 179: 大規模分散システムの現在 -- Twitter

A New Kind of Operating System Mesosphere データセンター・オペレーティング・

システム (DCOS) は、新しい種類のオペレーティング・システムである。それは、物理サーバー、クラウド・ベースのデータセンターのサーバーをまたいで、その上で、あらゆるバージョンの Linux が走る。

Killer Apps            User Interface         Programmable Datacenter

Page 180: 大規模分散システムの現在 -- Twitter

特徴 キラー・アプリ: どんな Linux のアプリケーショ

ンも、簡単にデプロイする。一つのコマンドで、データセンターのサービスをインストールできる。その中には、 Hadoopや Sparkや CassandraやKubernates が含まれる。

ユーザー・インターフェース: オペレーターや開発者は、データセンターを一つの大きなマシンのようにコントロールできる、我々の Command Line Interface (CLI) を、気に入っている。

プログラム可能なデータセンター: 我々のSoftware Developers Kit (SDK) と API で、新しい分散アプリを開発しよう。データセンターに対して、それが一つの大きなコンピュータであるかのようにプログラムしよう。

Page 181: 大規模分散システムの現在 -- Twitter

Mesosphere DCOS Mesosphere DCOS は、すべてのマシン、 VM 、ク

ラウド上のインスタンスを、インテリジェントで動的な共有リソースの単一のプールに組織する、新しいタイプのオペレーティング・システムである。それは、あらゆるバージョンのモダンな Linux の上で走り、それを強化する。

Mesosphere DCOS は、高可用性と耐障害性を持ち、プライベートなデータセンターでも、パブリックなクラウドの上でも動く。それは、劇的に、利用率を高め、オペレーションの複雑さを減少させ、開発者をもっと生産的にする。

Mesosphere DCOS は、 Apache Mesos を中心に構成されている。その分散システム・カーネルは、 UC Berkeley の AMP Lab で発明され、 TwitterやNetflixや Airbnb のような会社で、大規模に利用されている。

Page 182: 大規模分散システムの現在 -- Twitter

データセンターでしたいと思うことは、なんでも、我々がカバーする .

新しいアプリケーションを、書いてデプロイすることが、個々のマシンと静的なパーティションを管理することを意味していた時代は、過ぎ去った。データセンターとクラウドのリソースをプールして、すべてのアプリが同じマシン上で動くこと。これは、複雑さと浪費を削減する。

Scale Infinitely数万のノードに、ほとんど手間をかけなくても拡大でき、そうして、動的にリソースを割り当てることが簡単にできる。

Run Anywhere Mesosphere は、オープンソース・テクノロジーの上に構築されているので、 どんなクラウドやデータセンターでも、柔軟さを保ったまま、走ることができる。

Page 183: 大規模分散システムの現在 -- Twitter

Never Fail Mesosphere は、リソースを再バランスしながら、 走り続け、失敗したタスクは自動的に再スタートされる。

Optimize Resources Mesosphere は、それぞれのサーバーに、複数のアプリをパックして、リソースの利用を高める。

Operate Automatically Mesosphere は、クラスターを管理する高度な自動化をもたらし、オペレーションの時間とお金を節約する。

Develop Quickly Mesosphere で、開発者は、サーバーのことを考えずに、コードだけを考えればいいので、ビルドとデプロイを高速に行うことができる。

Page 184: 大規模分散システムの現在 -- Twitter

Mesosphere データセンター OSは、全ての主要なプラットフォームで走る

Page 185: 大規模分散システムの現在 -- Twitter

Mesos データセンター OS とその影響の拡大

Apache Mesos だけでなく、そのデータセンター OS への機能強化版の Apache Aurora, Aurora 相当の商業製品Mesosphere といった「 Mesos 文化圏」ともいうべきものは、 Docker, Kubernetes といった Container技術と結びつき、大規模分散の世界で、もっともダイナミックでアクティブな領域に成長しようとしている。

Page 186: 大規模分散システムの現在 -- Twitter

PaaS andLong Running Big data processing Batch scheduling Data storage

“Framework on Mesos” https://goo.gl/1oDvTc

Page 187: 大規模分散システムの現在 -- Twitter

Mesos 利用の拡大-- Mesosphere Blog タイトルから --

The Mesosphere Datacenter Operating System is now generally available

Get Mesos-DNS up and running in under 5 minutes using Docker

Building real-time data flows with Kafka on Mesos

Cassandra on Mesos: Performance + Reliability

Deploying Kubernetes on Mesos  It’s easier than ever to scale like Google withou

t being Googlehttps://mesosphere.com/blog/

Page 189: 大規模分散システムの現在 -- Twitter

“Mesosphere は、 Google スケールの計算能力を万人にもたらす。” Abdur Chowdhury, Former Chief Scientist, Twitter

“Mesosphere は、クラウド・コンピューティングの避けられない運命だ。” Brad Silverberg, Fuel Capital

“Mesosphere は、開発者にとってのブレークスルーだ。数千の Droplet でさえ、一つのコンピュータのように管理するその能力は、とてもエキサイティングなものだ。” Ben Uretsky, CEO and Co-founder of DigitalOcean

Page 190: 大規模分散システムの現在 -- Twitter

[余談 ]  大規模分散システムのパワーを、誰が、どのように利用するのか?

21 世紀初頭の Google の登場は、大規模分散システムが、そのパワーを現した画期だった。あれから、もう 15 年がたつ。ただ、その当時には、 Google だけしかそれができなかった。大規模分散システムのパワーを、誰が、どのように利用するのかについて、次の変化が起きつつあるように見える。

Page 191: 大規模分散システムの現在 -- Twitter

Mesos と Borg Mesos は、 Google の Borg にインスパイアされて生まれた、オープンソース・プロジェクトである。

Borg は、以前から、その存在は知られていたが、 GFS, MapReduce, BigTable とは異なって、その技術的詳細を Google が明かすことはなかった。 Borg は、 Google の大規模分散の中核技術であり、ある人は、それを「 Google の秘密兵器」「 Google の急速な進化の、もっともよく保たれた秘密」と呼んでいた。 “Return of the Borg: How Twitter Rebuilt Google‘s

Secret Weapon”http://goo.gl/QyhGjx "Twitter’s Aurora and How it Relates to Google’s Borg

(Part 1)"http://goo.gl/BRhL7x

Page 192: 大規模分散システムの現在 -- Twitter

Google, Borg の情報公開 今年の 4月、 Google は、 Borg の情報を初めて公開

した。“ Large-scale cluster management at Google with Borg” https://goo.gl/aN03bI

この発表に対して、 Aurora のアーキテクトのコメントを含む記事が、出ている。“ Google Lifts the Veil on Borg, Revealing Apache Aurora’s Heritage”http://goo.gl/Nv8ZIQ 

僕には謎だった Borg の名前の由来だが、それは、 Star Trek に登場する「宇宙種族のひとつ。蜂や蟻をモチーフにした社会的集合意識を持っているとされ、中央制御装置としての Queen がいる」とのこと。 Facebook で友人から教えてもらった。納得。

Page 193: 大規模分散システムの現在 -- Twitter

Google Borg

Google’s Borg system is a cluster manager that runs hundreds of thousands of jobs, from many thousandsof different applications, across a number of clusters each with up to tens of thousands of machines

数十万のジョブ数千のアプリケーション数万のマシン

Page 194: 大規模分散システムの現在 -- Twitter

大規模分散システムとクラウド -- いくつかの視点 概念的には、大規模分散システムの方が、クラウド

より広い。ただ、 2006 年の AWS のサービス開始に始まるクラウドの成立は、大規模分散の第二の画期である。

「作る人」と「使う人」: 大規模分散システムを作るのは難しく、使うのは易しい。 FacebookやTwitter を使うのに、そのサービスを支える技術を理解する必要はない。

クラウドを作るのは簡単ではない。クラウドを「作る人」は、まだ、少数である。

クラウドを「使う人」は、二つのタイプに分かれる。一つは、クラウド上にサービスを構築する人達である。彼らは、「作る人」でもある。もう一つは、こうしてクラウドを「使う人」によって構築されたサービスを、消費する人たちだ。

Page 195: 大規模分散システムの現在 -- Twitter

大規模分散システムとクラウド -- いくつかの視点 クラウドを「使う人」であると同時に、クラウド上

のサービスを「作る人」が、現在のクラウドの活況の中心にいる。それはそれで結構なことである。

それでは、彼らのエネルギーは、これからどこに向かうのだろうか? ここで、あらためて最初に述べた、大規模分散とクラウドの違いを考えるのは、意味があると思う。

これから重要なことは、基本的には、大規模分散のパワーを、新しいサービスに結びつけること、そうした新しいビジネスを作り出すことだと思う。

かつては、非常に困難だった、大規模分散システムを「作る人」に、誰もが簡単になれる時代が始まろうとしている。

Page 196: 大規模分散システムの現在 -- Twitter

資料編 Aurora 実行例

https://github.com/apache/aurora/blob/master/docs/tutorial.md

Aurora + Thermos Configuration Referencehttps://github.com/apache/aurora/blob/master/docs/configuration-reference.md 

データセンター OS APIhttp://goo.gl/Iwkn9u 

Hosting Environment ( これまでの Container技術 )  マルレク 2003 からhttps://goo.gl/MnjtqO 

Page 197: 大規模分散システムの現在 -- Twitter

Aurora 実行例

Page 198: 大規模分散システムの現在 -- Twitter

$ vagrant ssh Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

Documentation: https://help.ubuntu.com/ Welcome to your Vagrant-built virtual machine. Last login: Fri Jan 3 02:18:55 2014 from 10.0.2.2 vagrant@precise64:~$ aurora job create devcluster/www-data/devel/hello_world /vagrant/hello_world.aurora

INFO] Creating job hello_world INFO] Response from scheduler: OK (message: 1 new tasks pending for job www-data/devel/hello_world) INFO] Job url: http://precise64:8081/scheduler/www-data/devel/hello_world ......

実行結果

Page 199: 大規模分散システムの現在 -- Twitter

scheduler の状態を見る http://$scheduler_hostname:$scheduler_port/

scheduler  にアクセスすると scheduler の状態を見ることができる。この例では、 http://192.168.33.7:8081/scheduler である。

Role www-data の job が一つ走っていることがわかる。

Page 200: 大規模分散システムの現在 -- Twitter

role( ユーザー )ごとの job を見る 先の状態で、ユーザー名(この場合、 www-data)

をクリックする。 Environment devlで、 hello_world Job が走っていることがわかる。

Page 201: 大規模分散システムの現在 -- Twitter

Job の実行を見る hello_world をクリックすると、 job の実行状態が見える。

あれ、 Task が失敗して、終了している。

Page 202: 大規模分散システムの現在 -- Twitter

Task の状態をチェックする host をクリックして、 Task の状態を見る

Page 203: 大規模分散システムの現在 -- Twitter

バグを修正して、再実行 実行プログラムにバグがあったようだ。バグを修正

して、再実行すると、今度は、上手くいく。

Page 204: 大規模分散システムの現在 -- Twitter

process の出力を見る process の stdout をクリックすると、その出力が確

認できる。

Page 205: 大規模分散システムの現在 -- Twitter

job を殺すaurora job killall ... 次のようにして、投入した job を殺せる。

vagrant@precise64:~$ aurora job killall devcluster/www-data/devel/hello_world INFO] Killing tasks for job: devcluster/www-data/devel/hello_world INFO] Response from scheduler: OK (message: Tasks killed.) INFO] Job url: http://precise64:8081/scheduler/www-data/devel/hello_world vagrant@precise64:~$

Page 206: 大規模分散システムの現在 -- Twitter

jobページで、結果を確認する Hello_world プロセスは、 kill されている。

Page 208: 大規模分散システムの現在 -- Twitter

Process Schema

Page 209: 大規模分散システムの現在 -- Twitter

Attribute Name Type Description

name String プロセス名(必須)

cmdline String コマンドライン(必須)

max_failures Integer プロセス失敗最大数 (Default: 1)

daemon Boolean真の時、 daemon プロセスである (Default: False)

ephemeral Boolean真の時、 ephemeral プロセスである (Default: False)

min_duration Integerプロセスが再起動する間の最小継続秒 (Default: 15)

final Boolean真の時、このプロセスは、最後に走る finalizing プロセスである (Default: False)

Page 210: 大規模分散システムの現在 -- Twitter

Task Schema

Page 211: 大規模分散システムの現在 -- Twitter

param_ type description

name Stringプロセス名(必須) (Default: processes0.name)

processes List of Process objects

この task に結びつけられているプロセスのリスト ( 必須 )

constraintsList of

Constraint objects

プロセスを制約している constrainオブジェクトのリスト

resourcesResource

objectリソースの詳細情報 ( 必須 )

max_failures Integer失敗したとみなされるプロセスの失敗の最大回数 (Default: 1)

max_concurrency Integer並列プロセスの最大数 (Default: 0, 並列プロセス数に制限なしの意 )

finalization_wait Integerfinalizing プロセスに割り当てられた時間の総量。秒で。 (Default: 30)

Page 212: 大規模分散システムの現在 -- Twitter

Job Schema

Page 213: 大規模分散システムの現在 -- Twitter

name type description

task Taskこの job にバインドする Task オブジェクト。必須。

name StringJob名。 (Default: task の属性名から継承 )

role String Job role のアカウント。 必須。

cluster Stringこの job が、その中でスケジュールされている Cluster 。必須。

environment StringJob環境。 default は devel 。 prod, devel, test, staging<number> のうちのひとつでなければならない。

contact Stringjob のオーナーにリーチするのに最適のメールアドレス。製品版の job では、通常は、開発チームのメーリングリスト。

instances Integer生成された task(場合によっては、レプリカあるいは shard) のインスタンスの数。(Default: 1)

Page 214: 大規模分散システムの現在 -- Twitter

cron_schedule String

cron フォーマットでの Cron スケジュール。サービスではない job にのみ利用されるだろう。詳細な情報は、 Cron Jobs を参照されたい。 Default: None (cron job ではないということ )

cron_collision_policy

String

以前の実行が生きている間に、 cron job が起動された場合のポリシー。KILL_EXISTING : 以前の実行を殺して、新しい実行をスケジュールする。CANCEL_NEW : 以前の実行を継続して、新しい実行をキャンセルする。 (Default: KILL_EXISTING)

update_config update_config object

rolling アップデートの率とポリシーをコントロールするパラメータ。

Page 215: 大規模分散システムの現在 -- Twitter

constraints dicttask のスケジューリングの制約条件。constraint specification languageを参照。

service Booleanもし真ならば、成功・失敗に関わりなくtask を再起動する。 (Default: False)

max_task_failures Integer

task が失敗したとみなされるまでの失敗の数の最大数。 (Default: 1) 無限回の失敗を許す場合には、 -1 をセットする。

priority Integer

task に与えられる Preemption プライオリティ (Default 0). 高いプライオリティのtask は、低いプライオリティの task より、優先的に実行される。

Page 216: 大規模分散システムの現在 -- Twitter

production Boolean

これが production task であろうとなかろうと、 quota で back される。 (Default: False). Production jobs は、どんな non-production job よりも優先され、同じ role のより高いプライオリティの production jobs によってのみ優先される。このレベルで job を実行するためには、 job role は、適当な quota を持たなければならない。 production の特定の role に quota を認めるためには、オペレーターは、 aurora_admin set_quota コマンドを利用する。

health_check_config

heath_check_config object

HTTP経由での task のヘルス・チェックをコントロールするパラメータ。ヘルス・ポートが、コマンドラインのワイルドカードで指定された時にのみ利用される。

containerContainer

object全てのプロセスが、その中で走るオプショナルなコンテナ。

Page 217: 大規模分散システムの現在 -- Twitter

データセンター OS API

“Building & Deploying Applications to Apache Mesos” http://goo.gl/Iwkn9u の一部抜粋

Page 218: 大規模分散システムの現在 -- Twitter

FrameworkInfo

https://github.com/apache/mesos/blob/master/include/mesos/mesos.proto

message FrameworkInfo { required string user = 1; required string name = 2; optional FrameworkID id = 3; optional double failover_timeout = 4 [default = 0.0]; optional bool checkpoint = 5 [default = false]; optional string role = 6 [default = "*"]; optional string hostname = 7; optional string principal = 8; optional string webui_url = 9;}

Page 219: 大規模分散システムの現在 -- Twitter

TaskInfo

message TaskInfo { required string name = 1; required TaskID task_id = 2; required SlaveID slave_id = 3; repeated Resource resources = 4; optional ExecutorInfo executor = 5; optional CommandInfo command = 7; optional ContainerInfo container = 9; optional bytes data = 6; optional HealthCheck health_check = 8;

optional Labels labels = 10;

optional DiscoveryInfo discovery = 11;}

Page 220: 大規模分散システムの現在 -- Twitter

TaskState可能なタスクの状態を記述する。 Mesosは、終了状態に入ったタスクは、もはや実行されていないとみなす。そして、このタスクに関連したすべてのものを片付ける。(最終的には、このタスクで消費されていたリソースは、他のタスクに回される)

enum TaskState { TASK_STAGING = 6; // Initial state. Framework status updates should not use. TASK_STARTING = 0; TASK_RUNNING = 1; TASK_FINISHED = 2; // TERMINAL. The task finished successfully. TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully. TASK_KILLED = 4; // TERMINAL. The task was killed by the executor. TASK_LOST = 5; // TERMINAL. The task failed but can be rescheduled. TASK_ERROR = 7; // TERMINAL. The task description contains an error.}

Page 221: 大規模分散システムの現在 -- Twitter

Scheduler registered

スケジューラーが Mesos マスターへの登録が成功した時に起動される。ユニークな ID(マスターによって生成される)は、このフレームワークを他のフレームワークと区別するために利用される。現在のマスターの IP アドレスとポート番号をもつ MasterInfo が、引数として提供される。def registered(

driver: SchedulerDriver,

frameworkId: FrameworkID,

masterInfo: MasterInfo): Unit = {

log.info("Scheduler.registered")

log.info("FrameworkID:\n%s" format frameworkId)

log.info("MasterInfo:\n%s" format masterInfo)

}

Page 222: 大規模分散システムの現在 -- Twitter

Scheduler reregistered

新しい Mesos マスターが選出された、スケジューラーが登録された時起動される。これは、スケジューラーが以前に登録されていた場合にのみ呼び出される。 MasterInfo は、新しく選出されたマスターの更新された情報を含んでいて、引数を提供する。

def reregistered(

driver: SchedulerDriver,

masterInfo: MasterInfo): Unit = {

log.info("Scheduler.reregistered")

log.info("MasterInfo:\n%s" format masterInfo)

}

Page 223: 大規模分散システムの現在 -- Twitter

SchedulerresourceOffers

スクジューラは、リソースがこのフレームワークにオファーされた時に起動される。単一のオファーは、単一のスレーブからのリソースだけを含んでいるだろう。オファーに関連したリソースは、次の条件を満たさなければ、このフレームワークには、再オファーされることはないだろう。(a) このフレームワークが、これらのリソースを断っていた。(b) これらのリソースが撤回されていた。リソースは、同時に(利用されている Allocator に従って)、一つ以上のフレームワークにオファーされることがあることに注意せよ。この場合には、これらのリソースを使ってタスクを起動した最初のフレームワークが、それを使うことができる。

Page 224: 大規模分散システムの現在 -- Twitter

SchedulerresourceOffers

( あるいは、フレームワークが、すでにこれらのリソースを使ってタスクを起動していたとすれば、これらのタスクは、 TASK_LOST の状態で失敗するだろう。メッセージを見て欲しい )

def resourceOffers(

driver: SchedulerDriver, offers: JList[Offer]): Unit = {

log.info("Scheduler.resourceOffers")

// print and decline all received offers

offers foreach { offer =>

log.info(offer.toString)

driver declineOffer offer.getId

}

}

Page 225: 大規模分散システムの現在 -- Twitter

SchedulerofferRescinded

/**

* オファーが、もはや有効でない場合に呼び出される。

* (例えば、スレーブが失われたり、他のフレームワークがリソースを

* オファーにつかった場合とか) どんな理由であれ、オファーが撤回され

* ないなら l(メッセージが落ちる、あるいは、フレームワークが失敗する等で )

* フレームワークは ost or another framework used resources in the offer). If for

* 妥当ではないオファーを使ってタスクを起動しようとしたフレームワークは、

* このタスクについて、 TASK_LOST ステータス更新を受け取る。

*/

def offerRescinded(

driver: SchedulerDriver,

offerId: OfferID): Unit = {

log.info("Scheduler.offerRescinded [%s]" format offerId.getValue)

}

Page 226: 大規模分散システムの現在 -- Twitter

SchedulerstatusUpdate

/**

* タスクのステータスが変わった時に呼び出される。 * 例えば、スレーブが失われ、タスクも消えた時。 executor は * ステータスが更新されたというメッセージを送る。このステータスの• * callback _acknowledges_ receipt の返り値は更新される。 * なんらかの理由で、この callback の間に scheduler が落ちたならば、 * (あるいは、プロセスが exit すれば)他のステータスの更新が配布され

る * しかし、現在の実装ではそうなっていない。*/

def statusUpdate(

driver: SchedulerDriver, status: TaskStatus): Unit = {

log.info("Scheduler.statusUpdate:\n%s" format status)

}

Page 227: 大規模分散システムの現在 -- Twitter

SchedulerframeworkMessage

/**

* executor が、メッセージを送った時に呼び出される。これらの * メッセージは、 best effort である。フレームワークが、なんらかの * 信頼できるやり方で、メッセージを再送信するのを期待しないこと */

def frameworkMessage(

driver: SchedulerDriver,

executorId: ExecutorID,

slaveId: SlaveID,

data: Array[Byte]): Unit = {

log.info("Scheduler.frameworkMessage")

}

Page 228: 大規模分散システムの現在 -- Twitter

Schedulerdisconnected

/**

* scheduler が“ disconnected” になった時にマスターから呼び出される。

* (例えば、マスターが落ちた時) */

def disconnected(driver: SchedulerDriver): Unit = {

log.info("Scheduler.disconnected")

}

Page 229: 大規模分散システムの現在 -- Twitter

SchedulerslaveLost

/**

* スレーブが unreachable になった時呼び出される。 * (マシンの失敗、ネットワークの分断等)ほとんどのフレームワー

ク * は、このスレーブで起動されたタスクは、他のスレーブに * リスケジュールされる必要がある。 */

def slaveLost(

driver: SchedulerDriver,

slaveId: SlaveID): Unit = {

log.info("Scheduler.slaveLost: [%s]" format slaveId.getValue)

}

Page 230: 大規模分散システムの現在 -- Twitter

SchedulerexecutorLost

/**

* executor が、 exited/terminated になった時に呼び出される。 * 実行中のすべてのタスクは、 TASK_LOST のステータスになり、 * 自動的に(魔法のように)更新される。 */

def executorLost(

driver: SchedulerDriver,executorId: ExecutorID, slaveId: SlaveID,

status: Int): Unit = {

log.info("Scheduler.executorLost: [%s]" format executorId.getValue)

}

Page 231: 大規模分散システムの現在 -- Twitter

Schedulererror

/**

* scheduler あるいはそのドライバーに、修復不可能なエラーが * 起きた時に呼び出される。ドライバーは、これが呼び出される以前

に * 中止する。 */

def error(driver: SchedulerDriver, message: String): Unit = {

log.info("Scheduler.error: [%s]" format message)

}

Page 232: 大規模分散システムの現在 -- Twitter

Executorregistered

/**

* executor のドライバーが、成功裏に Mesos に接続できた時に * 呼び出される。特に、 scheduler は executor に ExecutorInfo の * データ・フィールドを使って、データを渡すことができる。*/

def registered(

driver: ExecutorDriver,

executorInfo: ExecutorInfo,

frameworkInfo: FrameworkInfo,

slaveInfo: SlaveInfo): Unit = {

log.info("Executor.registered")

}

Page 233: 大規模分散システムの現在 -- Twitter

Executorreregistered

/**

* executor が再起動されたスレーブで再登録された時、呼び出される。 */

def reregistered(

driver: ExecutorDriver,

slaveInfo: SlaveInfo): Unit = {

log.info("Executor.reregistered")

}

/** executor が , “スレーブから disconnected” になった時、呼び出される。

* (更新のためにスレーブが再起動された時など) */

def disconnected(driver: ExecutorDriver): Unit = {

log.info("Executor.disconnected")

}

Page 234: 大規模分散システムの現在 -- Twitter

ExecutorlaunchTask

/**

* Scheduler.launchTasks で始められたタスクが、この executor で * 起動された時、呼び出される。このタスクは、 thread, process,

* あるいは、単純な計算で実現されうるのだが、この callback が * 返らなければ、この executor 上では、他の callback は呼び出されな

い * ないことに注意。 */

def launchTask(driver: ExecutorDriver, task: TaskInfo): Unit = {

log.info("Executor.launchTask")

}

Page 235: 大規模分散システムの現在 -- Twitter

ExecutorkillTask

/**

* この executor の中で、タスクが殺された時に呼び出される。 * ( SchedulerDriver.killTask を通じて ) この executor のためには、 * ステータスの更新は往診されないことに注意。 * executor は、新しい TaskStatus を作ることに責任がある。 * (TASK_KILLED で ) そして ExecutorDriver.sendStatusUpdate

* を呼び出す。 */

def killTask(driver: ExecutorDriver, taskId: TaskID): Unit = {

log.info("Executor.killTask")

}

Page 236: 大規模分散システムの現在 -- Twitter

ExecutorframeworkMessage

/**

* この executor に、フレームワークのメッセージが届いた時に * 呼び出される。これらのメッセージは best effort である。これら

が、 * なんらかの信頼できるスタイルで再送信されることを期待しないこ

と */

def frameworkMessage(driver: ExecutorDriver, data: Array[Byte]): Unit = {

log.info("Executor.frameworkMessage")

}

Page 237: 大規模分散システムの現在 -- Twitter

Executorshutdown

/**

* この executor が、現在実行中のすべてのタスクを終了すべき時に * 呼び出される。 Mesos が executor が最終ステータス (例えば、

* TASK_KILLED, TASK_FINISHED, TASK_FAILED 等々 ) の更新 * を送らないすべてのタスクを終了させることを決めた後では、 * TASK_LOST ステータス更新が生成される。 */

def shutdown(driver: ExecutorDriver): Unit = {

log.info("Executor.shutdown")

}

Page 238: 大規模分散システムの現在 -- Twitter

Executorerror

/**

* executor あるいはそのドライバーに、致命的ななエラーが * 起きた時に呼び出される。ドライバーは、これが呼び出される以前

に * 中止する */

def error(driver: ExecutorDriver, message: String): Unit = {

log.info("Executor.error")

}

Page 239: 大規模分散システムの現在 -- Twitter

Hosting Environment

これまでの Container技術。マルレク 2003 から。https://goo.gl/MnjtqO CORBA J2EEWeb ServiceGrid

Page 240: 大規模分散システムの現在 -- Twitter
Page 241: 大規模分散システムの現在 -- Twitter
Page 242: 大規模分散システムの現在 -- Twitter
Page 243: 大規模分散システムの現在 -- Twitter
Page 244: 大規模分散システムの現在 -- Twitter