読者です 読者をやめる 読者になる 読者になる

宇宙スープ

Once upon a time, the Universe expanded from an extremely dense and hot soup

システムがおもしろいという話

大学生のころ自宅にインターネット開通したときが楽しくて、しばらくWikipediaをネットサーフィンしてた時期があった。
特に印象深く覚えているのは「バタフライ効果」を筆頭とする複雑系の説明だった。

バタフライ効果とは、「ブラジルの1匹の蝶の羽ばたきがテキサスで竜巻を引き起こす」といった、ごく微小な大気の撹乱が巡り巡って増幅し、大きな変化となって予想もしない場所に現れる現象を言う。大気などの複雑極まるシステムでは、ミクロに見るとごく単純な法則で動いているのに膨大な要素が絡みあうため、はじめの状態から時間が経過すると予測もつかない大事件が起こりうる。この事実は、この世界が決定論的に動いていたとしても、観測誤差がわずかでも生じる限り長期予測が不可能なことを示唆している。この説明に当時なにかグッと来るものがあり、以来お気に入りになった。

奇妙なシステム障害との遭遇

ただのお気に入り話だったバタフライ効果を再び思い出したのは、社会人になって1年ほど経ったときだった。ソフトウェアエンジニアとして就職して、アクセス量の多いウェブサイトの運用を担当してた。右も左もわけがわからず、謎の専門用語が飛び交う前線でひたすらシステムトラブル対応をやっていた。

ある日、ロードバランサとよばれる機器の異常を知らせるアラートが上がった。
ロードバランサは自分の所属部署管理ではなく、ネットワーク部の管轄だったので、その担当者をつかまえて対応してもらおうと考えた。しかししばらくするとそのネットワーク部担当の方から「あなたの部署管理のウェブサイトがロード許容量をオーバーしています」みたいな連絡が来た。
流れに身を任せて調査を進めていると、なんとトラブルの原因はそのサービスのデータベースにあったことがわかったのだ。

Webエンジニアでなければわけがわからないと思うので、一般的なウェブサイトのシステム構成を説明する。

f:id:metheglin:20160902205127p:plain

データベース(以下DB)は、データを保存する担当である。たとえばあなたが会員登録をすると、その情報をなくさないようにどこかのハードディスクに保存しておく必要がある。アプリケーションサーバがDBに「これ保存しといて」「この情報教えて」などと指示を出す。

ウェブアプリケーションサーバ(以下APPサーバ)は、サービスそのものである。たとえばユーザが会員登録ボタンを押したら、画面Aを表示させて、個人情報入力したらDBに保存の命令を出して...などなどアプリケーションを構成する機能がすべてプログラミングされたものが動いている。必然的にこの機器は忙しくなりがち。パソコンでいろいろやってると動作が重くなることがあるが、それと同じ状況に陥りやすい。

ロードバランサ(load balancer)(以下LB)とはload(積み荷、荷重)をbalance(分散)させるための機器である。荷物の中央集積所のような場所で、次から次とやってくる積み荷をどこに受け渡すかを指揮するのがLBの役割である。ゲームなどでお馴染みのNow loading...のloadも同様に必要な荷物をトラックなどに積み込む作業をイメージした言葉と思われる。
前述のようにAPPサーバは忙しくなりやすい。それゆえ、サーバが重くなったときは、機器自体の台数を増やすという戦略をとる。そのとき、ユーザから次々とやってくるアクセス(積み荷)をどうバランスよく複数のAPPサーバに振り分けるかということが問題になる。LBはその問題を解決する機器となる。

つまり、ユーザがウェブサイトのページを見ようとすると、そのアクセスはLBが受信し、APPサーバへと渡され、さらにDBへと命令が渡る。アクセスの流れ、それぞれの機器の役割をざっと把握したところで、はじめの問題を再考したい。

当時自分はLBがアラートを出したのでそこに問題があると思った。しかし実際の問題はシステム奥底のDBにあった。前述の説明をふまえればこのときの自分の戸惑いを少しは分かってくれたかもしれない。

「なぜ、システム奥底のデータベースに起こった問題がシステムの最前線であるロードバランサの障害となって出現するのか?」

このときはじめてシステム障害がバタフライ効果に似ていると思ったのだった。複雑に構成されたシステムはとある原因が思いもよらぬ別の場所で障害となって現れる。

どういうメカニズムでこんな奇妙なことが起こるのか、そろそろ理解しないとやばいと思った自分は情報をかき集めて真相を理解しようと頭を整理した。

どんなシステムも単位時間にこなせる仕事量、キャパシティ(許容量)を持っている

先ほどloadを積み荷と表現したが*1、この荷物の中にはなにが入っているのか?ユーザがサイトにアクセスすると、それが荷物となってシステム内を流れる。つまり荷物の中には「ユーザがなにをしたいか、何の情報を見たいか」という情報が入っている。
つまり、loadには「大きさ」があるということである。KB(キロバイト)、MB、GBなどおなじみの単位で表せるようなサイズを持っているということ。サイズがあるということは無限にloadを溜め込むことはできないということだ。その限界は、その機器が搭載するメモリのサイズに依存する。

そしてloadを受け取った機器はその荷物の中身を見て、おのおのがやるべきことを処理する。
「処理する」ということは計算をおこなったり、データ書き換えなどを実際におこなうことである。こういった作業は通常人間が観測できないほど超高速でおこなわれることがほとんどだが、0秒ではない。ほんのわずかでも処理時間が必要になる。

要するにシステムにはそのキャパシティ(仕事の許容量)を決定づける時間(処理時間)と空間(メモリサイズ)が存在するのである。

システムの許容量を超えた仕事を与え続けるとどうなるか?

キャパシティを持つシステムに対して、loadはユーザのページビュー数だけやってくる。
たとえば、1回の会員登録を完了するのに0.1秒を要し、同時に10アクセスを許容できるシステムがあったとすると、秒間100回の会員登録が許容の限界ということになる。秒間100以上の会員登録が来た場合、その積み荷の出し手に待ってもらわないといけない。これをloadが「滞留する」と表現したりする。
「滞留」は、現実世界にたとえるとレジ待ちの行列ができるようなものである。前述のようにloadにもサイズがあるので、現実の行列がスペースを占有するのと同じように、loadが滞留するとメモリを占有してしまう。
秒間100以上の会員登録がずっと来続けると、空きメモリはどんどん少なくなり、限界に達する。最終的にはloadを拒否するしかない。ウェブサイト上では、アクセスを拒否されたユーザは「503 Service Temporarily Unavailable」などの表示を見ることになる。

DBトラブルがLBの問題を引き起こす仕組み

まとめると、

  • DBに異常が起きて動作が遅くなるとどうなる?
  • => DB上にloadが滞留する
  • DB上にloadが滞留するとどうなる?
  • => APPサーバ上にloadが滞留する(APPがDBに命令を出してその応答を待っている。DBの仕事が終わるまではAPPサーバの仕事もやめられないので、滞留させておかないといけない)
  • APPサーバ上のloadが滞留するとどうなる?
  • => LB上のloadが滞留する
  • LB上のloadが滞留するとどうなる?
  • => 限界までloadを滞留させておくことはできるが、それを超えると新規のユーザアクセスを拒否する。同時にその異常事態を知らせるアラートがLBからとんだ。

これが事の真相であった。

極限の綱引きでバランスされる大規模システム

問題の根本的原因はDBにあったことがわかったが、停止したわけではなかった。停止していたらさすがにDBの異常を知らせるアラートが上がっていたはずだ。
実際にDBで起こっていたことは、「CPU使用率」の高騰である。

パソコンを使ってるとファンがシューシューとうめき、熱くなることがあるのはご存知と思うが、あれはCPUがフル稼働するときに起こる。このとき電力の消費量が大きくなり、大きな熱を発する。CPU使用率は、そのコンピュータの忙しさを表していると言える。CPU使用率が100%だと、新しい仕事がやってきてもなかなか対応する余裕がないといった具合だ。

ここでおもしろいのは、たとえば前述の例で1回の会員登録に0.1秒かかると思っていたものは正常時の数値なのである。CPUがせわしなくなってくると0.1秒で処理が完了しなくなる。処理時間が遅くなる。
処理時間が遅くなるとloadが滞留するので、CPUは休む暇なく次の荷物を処理する必要に駆られ、さらに忙しくなる。

これは大規模なウェブサイトでよく起こる、最も典型的なシステム悪循環の例である。
仕事をがんばらないといけないときに限って、CPU使用率が高騰し処理時間が遅くなるので、システムのキャパシティは見る見る減っていくのだ。

高校数学で極限という分野があって、「0 × ∞ = 0ではない。不定である。」と習う。0と∞の綱引きでより強い方が勝つのだ。
大規模システムのバランスもこれとよく似ている。
処理時間は通常限りなく0に近く、一方loadの数は膨大である。処理時間が0に近ければどんな大量のloadが来ても瞬時に処理されるので問題はない。しかしCPU高騰などで処理時間がわずかに悪化すると、0が弱くなり、途端に∞が勝つということが起こる。大規模システムの保守とは、極限のせめぎ合いだったのだ。

これに気付いたときの感激は未だに忘れられない。もう、トラブル対応が楽しくてしようがないというかんじ。それ以来、自然界、人体、社会など、システム的な動きを見せる現象にすごく興味を持つようになった。

 「世界はシステムで動く」を読んで、それを再認識できた。

世界はシステムで動く ― いま起きていることの本質をつかむ考え方

世界はシステムで動く ― いま起きていることの本質をつかむ考え方

 

 

*1:loadは、仕事上では「負荷」と訳されるのが一般的。また、loadが滞留するような場合には、loadではなくセッション、コネクションなどと表現することが多い。荷物が流れたり、滞留するという説明のほうが非Webエンジニアには分かりやすいと考えてこの表現にしている。