Webサービスにおけるインフラアーキテクチャの体系化とインフラアーキテクチャの選択自動化の研究課題についての整理と考察

第1回WSA研究会 開催概要 - Web System Architecture 研究会 (WSA研)で発表したときの予稿になります。
今回はWSA研の第一回ということもあり、自分自身で何をしたいのかという点を整理するための発表という形になりました。
まだ、整理や調査が不十分である状態ではありますが、WSA研のような場所で現状できているところまでを報告し、色々議論できたことでよりより調査を行えるかなと思っています。
このように、明確な成果でなくても発表し議論できるところがWSA研のいいところかなと思っている*1ので、興味ある人はぜひ参加を検討してみてください。

発表資料

speakerdeck.com

研究テーマ

Webサービスにおけるインフラアーキテクチャの体系化とインフラアーキテクチャの選択自動化の研究

研究背景

Webサービスに求められるユーザ要求は,高度かつ激しく変化する. それに伴い,webサービスのサーバサイドアプリケーションが動作するサーバやストレージ,ネットワーク(本稿ではWebサービスにおけるインフラと呼称する)は,ますます複雑化している. 一方で,仮想化技術,コンテナ技術,クラウドサービスの登場により,使用頻度の高いインフラストラクチャの構築はアーキテクチャのパターン化が進んでいる. これにより,サーバサイド技術者は要求を満たすために必要となる複雑なインフラストラクチャをアーキテクチャの組み合わせにより比較的容易に構築することができる. しかしながら,これらのアーキテクチャパターンには一長一短があり,効果的なインフラストラクチャを構築するためには対応するWebサービスに応じた適切なアーキテクチャを選択する必要がある. こうしたWebサービスの要求に対して適切なアーキテクチャを選択する作業はインフラアーキテクト設計者(以後,設計者とする)の経験や,ノウハウ,若しくは業界の”流行り”に頼っているのが実情である.

本研究はますます大規模かつ複雑化しているインフラストラクチャ構築を効率化し,設計者の暗黙知によらない,適切なアーキテクチャの自動選択を行う手法の確立を目指している. 本稿では,その初期段階として,アーキテクチャの体系化とインフラストラクチャ構築におけるアーキテクチャの自動選択を行うために必要となる課題を考察し,整理する. 加えて,課題の一部の考察も始めたので記載する.

研究課題の整理と方針

Webサービスの特性に応じて,適切なインフラアーキテクチャの選択自動化を実現するためには,以下の課題を解決する必要がある.

  1. 選択自動化のためのスコアリング手法の確立
  2. Webサービスの要素洗い出しとモデル化
  3. 既存のWebサービスの調査と分類
  4. インフラアーキテクチャの要素の洗い出しとモデル化
  5. 既存のインフラアーキテクチャの調査と分類

Webサービスの特性を入力値として,適切なインフラアーキテクチャが得られるようなスコアリング手法を確立する(1).
そのためには,Webサービスとインフラアーキテクチャのモデル化が必要となる.
そこで,Webサービスとインフラアーキテクチャの要素を結びつけ,Webサービスのモデル化を行う必要がある(2). Webサービスとインフラアーキテクチャでは,Webサービスのほうが抽象度が高くなるため,インフラアーキテクチャの要素に対し,Webサービスの要素を紐付けるほうがモデル化がしやすいと考えられる. Webサービスにはインフラに要求するサービスの特性を持つ. ただし,それはパラメータとしては一意に決定されず、サービスの分類として類型であってもサービスの特性として違う重みが付く可能性がある. よって,パターン化されたアーキテクチャそれぞれの持つ強み,弱みを評価要素とし,Webサービスの特性を評価要素に紐付けた解析をする必要がある. 例えば,ブログサービスAとBは同じブログサービスであるが,ネットワークトラフィック量というある要素について重み付けをした結果,違うサービス特性になる可能性がある.
したがって,簡単化のためにWebサービスを考慮する前に,インフラアーキテクチャのみでモデル化を行う(4).
また,要素の洗い出しには既存のWebサービスとインフラアーキテクチャの調査と分類が必要となる(3,5).

よって,本研究は大きく分けて下記のような段階を踏んで,研究を進めていく

  • インフラアーキテクチャのみのモデル化までを研究の第一段階とする(4,5).
  • 第一段階の結果を踏まえて,Webサービスを考慮したモデル化までを研究の第二段階とする(2,3).
  • 第二段階までのモデルを利用して,スコアリング手法を検討する(1)

既存のインフラアーキテクチャの調査と分類

一例として,高度化したインフラのアーキテクチャパターンとして注目されている,MicroServiceアーキテクチャ(以後,MSAとする)とServerlessアーキテクチャを例に取り上げ考察する. MSAでは,モノリシックなソフトウェアでWebサービスを構築するのではなく,ビジネス機能に沿った小さいMicroServiceが複数連携し,一つのWebサービスを構築するアーキテクチャである. 機能ごとにMicroService内で局所化出来るため,高度かつ激しくユーザ要求が変化するWebサービスに対応しやすいアーキテクチャであると考えられている. MSAはサービスの数が増えるため,モノリシックな一つの巨大なサービスのためのアーキテクチャとは異なった問題も出てくる. そのうちの一つとして,サービス数が増えることによるサーバの運用保守のコスト増加である. それらを解決する手段の一つとして注目されているのが,Serverlessアーキテクチャである. ServerlessアーキテクチャAWS lambdaに代表されるFunction as a Service(FaaS)を利用し,運用するサーバの数を抑えつつ多くのサービスを構築することが可能となる. Serverlessアーキテクチャを採用するためには,基本的にFaaSを使うことになるため,AWSGCPなどFaaSを提供しているクラウドを利用することになり,ある程度実装上の制限が発生すると考えられる. よって,Webサービスの要求に答えるため,MicroServiceアーキテクチャとServerlessアーキテクチャを採用するという場合もあれば,MicroServiceアーキテクチャを採用しつつも,Serverlessアーキテクチャではなく,また別の多数のMicroServiceを運用可能なアーキテクチャ(例えばFastContainerアーキテクチャ)と組み合わせて採用することも考えられる. このように,解決するためのアーキテクチャが複数提案はされているものの,アーキテクチャの問題点を解決するためのさらなるアーキテクチャが存在し,設計者は多くのアーキテクチャを組み合わせ,Webサービスの要求を満たすインフラ設計を行わなければならならず,インフラ設計のアーキテクチャ選択はより複雑になっている.

MSAとServerlessアーキテクチャの2つだけをとっても,要素の洗い出しには以下のような検討すべきことがある.

などがあり,MicroServiceアーキテクチャとServerlessアーキテクチャが,同じ分類として容易に比較できるものでは無いと考えられる. その他のアーキテクチャも含めたより詳細な調査を行ない,分類を検討していきたい.

また,分類と要素検討を行うための参考として,ソフトウェア工学などを参考にすることも考えている. 例えば,システム/ソフトウェアの品質モデルの国際規格であるISO/ICE 25010などの移植性,保守性などはインフラアーキテクチャの要素として利用できそうである. 一方で,ISO/ICE 25000シリーズはWSQB17による提言ではアジャイル開発や,クラウド環境下への対応は不十分であると提言されているので,アジャイル開発やクラウド環境化への課題に取り組んでいる研究,規格を調査する必要がある.

今後の課題

関連研究の調査が不足しているので引き続き調査を行う.加えて,最初の課題である既存のインフラアーキテクチャの調査と分類に取り掛かる.本稿ではMicroServiceアーキテクチャとServerlessアーキテクチャの簡易な考察を載せたが不十分であるので,その他のアーキテクチャとあわせてより深い考察を行う予定である.

参考文献

質疑応答とか

  • これができたとしてその先には何があるのか。我々が仕事をしなくても良くなるのか
  • これできるといいなと思ってました(e.g. 構築したはいいけどコストが非常に掛かるシステム見たことがあったり)口頭でも出た限り既存システムへの適用もしたくなるとか、あとビジネス的な要件にどのくらい追従できるかも気になりました。後者は例えばサービスがビジネスとして軌道に乗るか分からんので良いアーキテクチャで無くてもいいからスピード重視で作りたいとかあるかなーと
    • 実際には新規構築だけではなく、むしろそこから先のサービスの成長に合わせてインフラを成長させていくのが難しいと感じている。なので、現状のサービスと、新たに機能などが追加されたサービスの差分をサービス特性として入力とし、新たなインフラアーキテクチャを出力できたりする必要がある。最初は簡単化のために新規構築を対象とするが、最終的には差分なども考慮した特性で判別出来るようにしたい。例えば、最初はMonolithicだったが、規模が大きくなってきたのでMicroserviceにするときの適正なタイミングはどこかなど、考慮するべき項目はたくさんある。
  • アーキテクチャを体系化してインフラ構築などを加速していく、というのはある意味ソフトウェアのライブラリ化といっしょで再利用性を高めるのと似た利点を持つと感じがしました(そこを狙っているのかもしれません)

*1:成果があるならもっと影響力のある場所(論文やソフトウェアの公開、カンファレンスや大きな勉強会)での発表が良いでしょう。

はてなサマーインターン2017の講義とメンターをした話

はてなエンジニア Advent Calendar 2017 - Qiitaの17日目の記事になります。前回はid:dekokunによる Alexa(echo) スキル用AWS Lambda functionをAWS SAMを使ってバババッと立ち上げる - でこてっくろぐ ねおでした。
GitHub - masayoshi634/libipvsgoを元にGeneric NetLinkとIPVSを解説しようと思いましたが、気がついたら当日になっていたので、本日ははてなサマーインターン2017でメンターをしたときの話をしようと思います。

developer.hatenastaff.com

はてなサマーインターン2017では前半の講義パートと後半の実践パートがありました。 私は前半の講義パートのインフラ講義と後半の実践パートの大規模システムコースのメンターを担当しました。
講義の資料作成や大規模システムコースのメンターとして気にかけたことなどを書いてみようと思います。

インフラ講義

技術系の最後の講義として2時間インフラ講義を行いました。 そもそもインフラ講義を2時間してくれっていわれても何話せばいいのかよくわからなかったので色々悩んだのですが、結局インフラ設計の考え方の基礎をお話しました。

最近の学生は本当に技術レベルが高く、例えばテストを書くなどのコードを書く上での常識は比較的よく知っており、実践している学生も多いです。今年のインターン生もレベルが高く、前半パートの課題も動くだけでなくよりキレイな設計になるにはどうするか、といった内容の議論をメンターの方としている場面も見かけました。

一方で、学生は基本的にインフラ技術には詳しくない場合が多いです。なかなか経験することができない、インフラの課題がわからない、勉強すべき箇所がよくわからない(実は私もよくわかっていません)。また、そういった理由から勉強するためにインターンに参加したいという学生さんも多いと思います(社会人も多いと思いますが)。
そこで、インフラ講義ではこれからインフラを勉強する、インフラ技術の話を理解しやすくするために基本的なインフラ設計の考え方を話そうと決めました。 個別のミドルウェアなどは例として名前を出したりすることはしましたが、説明は特にしませんでした。ミドルウェアの仕様とか使い方、利用例はネット上を検索すれば出てくる内容も多いので、考え方などを中心にしたほうがインターンの講義内容としては価値があるだろうと考え、個別のミドルウェア内容は削りました。

大体大きく分けて以下の3部構成で話を作りました。

  1. インフラとは
  2. web,app,dbの3層構成
  3. パフォーマンスの話

インフラとは

まず基本的な話としてインフラという単語は指すものが大きいので注意しましょうみたいな話をしました。 ISP事業者、クラウド事業者、コンテンツプロバイダーがいうインフラはそれぞれが指しているレイヤーが異なることが多いので、話を聞いたりするときはどのレイヤーをインフラと言っているのか意識したほうが話が聞きやすいという感じの話です。 今回の講義ではwebサービスにおけるインフラ(つまりサーバやそれらが通信するためのネットワークの話)を中心としています。 webサービス事業者はサーバを資産として持っていなくてもAWSなどでサービスを提供できたりするのでインフラとはつまりAWS,GCPであるというところもあるよーという話ですね。 あとは、サービスの可用性、継続性、コスト、パフォーマンスとかを気にして設計しましょうという話。 ここだけで3-4時間以上は喋れる気もするけど、いきなり経験ない学生にそんなこといってもという感じもあるのでさらっと流しましたが、インフラはここが最重要ポイント(だと私は考えている)なので、喋る時は強調はしておきました。

web,app,dbの3層構成

web,app,dbに分けた上でさらにbatchとかbackup用のdbとかキャッシュサーバとかくっつけていくと実際動いているサービス構成みたいになるやでーという話をしました。 まぁ伝統の3層構成って感じの話ではあるんですが、それだけだとあんまりおもしろくなかったので、考え方はソフトウェアと同じで全く違う世界が広がっているというわけではないのが伝わるように話しました。3層構成に分けておいたほうがスケールや管理が楽になるといきなり言われてもわからんと思うので、main関数にすべてのコードが書かれている状態を各役割と責任範囲を明確にした上で各クラスに分離したような感じなど例を出すように説明しました。サーバ自体が状態を持ったオブジェクトであるというイメージがつくと、変更時の影響の局所化のためにサーバを分離して管理しようとか、メンテナンスがしやすいように名前を付けたり不要なパッケージは入れないようにしようとか、相互に接続するためのインターフェースは統一されていたほうが良いとか、大きなシステムになれば理解するために相互の関係性をUMLのように可視化したいとか、状態を可能な限り持たせないことでより容易に並列化しようとか、そういったプログラミングと同じ課題がインフラを見た時にも見えてくるんじゃないかなーと思っています。例えば、分散トレーシング、コンテナ技術とかを見た時に解決したい課題が、イメージしやすくなるといいなーなんて考えてたりします。
とは言え、2時間で話すのには限度があるので↑のようなところまで伝わったかはわかりませんが、サーバもどこまで分離するかとか、どう分離しようかみたいな議論は、ディレクトリ構成の分け方、クラス設計などに通じるものがあるというのがなんとなくわかったんじゃないかなーと思います。

パフォーマンスの話

ここは少し具体的な技術の話をしています。今まではフワッとした話だったのでちょっとおもしろ要素として入れています。まぁ2時間もフワッとした話しても飽きてしまうかもなーとおもったのでマルチプロセス、マルチスレッド、イベントなどの話や、DBのシャーディングなどのお話をちょろっといれてフィニッシュという感じです。
今回はここはそこまで重視して話していない(面白いところではあるけど)ので気になる人はこの後一緒に話しましょうぐらいで締めました

大規模システムコース

はてなのサーバ・ネットワーク基盤技術を探究するインターンの紹介 - Hatena Developer Blog *1に書いてあるとおり、大規模システムコースの課題はいくつかテーマを用意しておき、実際に配属されるインターン生の特性を見ながらインターン生と相談して実際に行うテーマを決定しました。今回のテーマは"次世代監視技術への挑戦"という感じでした。具体的な内容はインターン生がまとめてくれたブログをご覧ください。 developer.hatenastaff.com

内容の決定はid:y_uukiと案を出しつついくつかの候補をインターン生に示し、一番興味がありそうなのをやってもらう感じにしました。
案ではいくつかあってredis4.0などのミドルウェア検証から今回採用した次世代技術への挑戦みたいな研究に近い内容までありました。
インターン生に最高の夏だった、成長したと思ってもらうことが我々メンターの目標なので大規模システムコースのテーマの決定はなかなか大変です。2週間(10営業日)で実サービスのインフラ環境を触ったことないインターン生が、インフラ技術で内外に反響がある成果を出すというのは難しいものです。
大規模システムコースは他のサービスに紐付いたコースとは異なり、実サービスの機能開発という感じでは無いため、比較的自由にテーマを決定することができる反面、実際のユーザからのフィードバックなどがもらいにくいため、成功体験が得られにくいというデメリットがあります。今までの大規模システムコースも成果としては出ているものの、フィードバックが社内からしか得られにくいという点がありました。
また、サービスに関係したインフラ改善(例えばMySQLのバージョンを上げましたとか、パフォーマンス改善とか)はタイミングが合えばインターン生にも可能な範囲でユーザからのフィードバックがもらえるものがあるのですが、10日で出来るのかというのと果たしてそれが"大規模"であるかという問題点があります。
今回採用した次世代監視技術への挑戦では、現在の課題とそれに対する私とid:y_uukiが考える解決案のイメージを伝え、それをインターン生が自分たちで理解した上で自ら実装を提案し、それらの成果をOSSや技術ブログとして外部に公開するという研究に近い課題の出し方にしました。このテーマになった理由はインターン生が選んだというのもありますが、インターン生の基礎力が十分であると判断できたという点と他のテーマより圧倒的に楽しそうだったからです。
今回来てくれたインターン生2人(id:makenowjust, id:t-k3ntaroo)は、自ら調べ考え考察する技術、研究に必要な基礎力が十分に備わっていました。また、彼らなら我々が考えた解決案以上のものを提案し、共に議論が出来る実力が十分にあるのでやっている我々も楽しいものになると思ったからです。

実際にテーマが決まってからは、私が主にメンターを努め2人の進捗を見守りつつ議論に参加するという感じでした。
メンターをやる上で気を付けた点は以下の2点です

  1. メンター側から意見を出しすぎず、インターン生との議論に一人のエンジニアとして参加する
  2. こまめに進捗確認と議論をする

1つ目の"メンター側から意見を出しすぎず、インターン生との議論に一人のエンジニアとして参加する"のは可能な限り自分たちの手法を提案してほしいからです。私はインターン生を学生ではなく一人のエンジニアとして扱っていますが、インターン生側は私が意見してしまうと「実際に働いているエンジニアが言うのだからそうなのだ」と思ってしまう可能性があるからです。あくまで1つの意見などを出しますが、インターン生で考えた実装を成果としてもらうことで、成功体験を掴んでほしいと思っていました。「これはメンターから言われたものを実装したものではなく、自分たちが考えた実装なのだ」そういうものにして欲しいのです。
2つ目の"こまめに進捗確認と議論をする"のは別にインターンに限ったことではないですが、特に「普段一緒に開発しないメンバーと共に10日間で新しい技術に挑戦し、ブログとOSSとして公開する」ということをやり遂げる必要があるので、方向性が間違ったまま1日立つとそれを修正するだけで2日程度無駄にする可能性があります。なので出勤後,昼食後,退勤前の3回進捗と方向性の確認、困っていることと課題と感じていること、それに対する解決案を確認していました。短い時間で目的を達成するのには、Bestな選択をし続けるのは難しくても最低限Betterな選択をしていかなければなりません。本質で無いことに躓いていたり、熱中するあまり本来とは違うものを実装していないか注意する必要があります。

私もメンターをしたことがないので実際のところはよくわかっていませんが、上記の2点のみを注意してやったところ10日間でインターン成果をブログとして公開し、OSSとしてgithubリポジトリを公開するところまで行けました。まぁインターン生が優秀すぎたので特に上の2点を重視しなくても成功していた可能性が高いのですが、1に関しては意識しておいてよかったなーと思うことが多かったです。
実は始める段階では可視化までは行けないだろうと思っていたので、特に何も考えずgraphvizあたりで可視化するんだろうなーみたいに考えていたのですが、「見にくいのでneo4jで試してみました」と持ってきたのでびっくりしました。
上記リンクの成果を読んでもらえるとわかるかと思いますが、実装段階でいくつもの課題が出てきてそれぞれに議論を行っています。dockerでテストしてたらARPテーブル溢れてきたみたいな話から、接続の関係性のデータ保持は誰が担当するのか、クラスタを形成する時のnetstat情報はLISTEN側(サーバ側)からjoinするのかクライアント側からするのか、Gossipプロトコルを使うのは妥当か、Gossipプロトコルの通信量は問題ないか、ヘルスチェック監視に利用するものはpingでいいのか、UDPで問題ないのか、agent自体のCPU負荷はどうなのか、などなど紹介しきれていない議論もたくさんしました。
議論ではネットワークなどインターン生にとって前提知識が薄いものに関しては積極的に意見を出しつつ、それ以外のものに関してはあがってくる提案手法などに対して意見を出したりしていました。最初はConsul聞いたことはあるという程度の知識だったインターン生が、1週間も立たずにGossipプロトコルの挙動やネットワーク帯域や通信頻度への言及などの議論が出来るようになったのは、単純に使うのではなく、特性を考え活用するという過程を踏んでいるからだと思います。彼らからあがってくる報告や課題は私自身も「なるほどなー確かに実用を考えると気になる点だなー」と気付かされることが多く、もしかしたら私のほうが楽しんでいたかもしれません。

講義とメンターをしてみた感想

インフラ講義の資料作成では、実際に自分がインフラを学んできた過程、思考、知識の整理ができたので良かったかなーと思います。インフラなどにかかわらず人にものを教えることの最大のメリットですね。 ただ結局整理した結果良くわかっていないことも多いし、インフラ知識は体系だったものはあんまりなく結局個人の経験から得たものが多いのかなという印象があります。また、個人の経験では体系だった教科書を作ることは難しく、多くの経験者たちと議論をする必要がありそうです。そういったこともありWebSystemArchitecture研究会を発足し、広く議論することでより体系だったインフラ講義などを提供できるようになるかなとも思っています。

websystemarchitecture.hatenablog.jp

メンターは課題の設計から議論を考えるとかなり労力を使うなーという感じです。インフラは特に適当にやるのは簡単だけど、実力がつくインターンをするのは、会社としては工数をしっかりかけないと提供は難しそうです。逆に言えば学生はメンターがしっかりインフラのインターン内容を考えてくれそうなところに参加すれば、(学べるレイヤーの違いはあれど)しっかり実力や考え方を身に着けてインターンを終える可能性が高い(時間を無駄にした感が少ない)インターンを選ぶことが出来るんではないでしょうか?
来年のインターン担当かどうかはまだわかりませんが、担当になるとしたらより体系的な講義と課題にできたら良いなと思っていますので、もし本記事を読んで興味が出てきた学生がいればぜひ応募していただけたらと思います。

*1:ちなみにここに書いてある"昨年入社した新卒のエンジニアに、はてなインターンに応募しようと思ったが選考に通らないと思って応募しなかった人"は私のことである

LinuxのARPとL2スイッチのお話

この記事は、はてなエンジニアアドベントカレンダー2016の12月19日の記事です。

developer.hatenastaff.com

昨日はid:taketo957くんの 10ms以下のレスポンスタイムを支える継続的負荷テスト - taketo957の日記 でした!

Webオペレーションエンジニアのid:masayoshiです。 2016年に入社後、基盤チームとして仮想化、ネットワーク周りを中心に見ています。

さて、この記事ではLinuxARPの挙動とその挙動から起こった問題を紹介しようと思います。

長々と記事を読みたくない人向けに結論をまとめるとLinuxARPTCP通信で使われ続ける限りキャッシュが飛ばないという挙動になるので、複数のL2スイッチにまたがったセグメントや非対称ルーティングをしている場合は気をつけましょうという話が書かれています。

今回紹介する事例自体は別に新規性もなく、私が入社前から社内でも知られていて対策がされている内容なのですが、ネットワークに詳しくないインフラエンジニアやアプリケーションエンジニアはあまりこういう事例や、動作が説明されている記事がなく、検索してたどり着くのが大変そうな気配がしたので、自分の勉強ついでに書いてみることにしました。

はじめに

はてなでは、ロードバランサーとしてLVS(Linux Virtual Server) + keepalivedを利用しています。 LVSではNAT,DR,TUN形式が利用できますが、リアルサーバ(振り分け先のサーバ)のセグメントを選ばないかつLVSに負荷がかかりにくいTUN形式を用いています。 TUN形式はIP in IPトンネリングでパケットをカプセル化して送ることで、送信元IPアドレスをリアルサーバに渡すことが出来ます。 そのため、リアルサーバからの戻りパケットがLVSを経由することなく、送信元ホストに直接パケットを送ることが出来ます。(直接返せるのはDR方式と同じですね) EC2などとは違い、リソースマネージメントがめんどくさいDC環境ではネットワークを意識しなくて良いのは非常にありがたいことです。 ここらへんのお話は先月OSCTokyoFallでの発表資料も参照していただければと思います。

speakerdeck.com

今回の記事はLVS/TUN形式で送信元ホストとLVS、リアルサーバが同じセグメントに存在し、複数のL2スイッチで構築されている環境というかなり限定された状況下で、戻りパケットがブロードキャストされるという問題です。 正確に言えばLVSは直接関係ないのですが、今回のような状況が起こるのはLVSのようなロードバランサなどを利用している場合で起きやすいと感じた(実際に発生した)のでその事例を例に説明したいと思います。

発生した問題

f:id:masayoshi:20161219103137j:plain 図1-1: 想定している正常な通信

上記の図1-1のように、送信元ホストであるホストAがVIP宛にパケットを送信し(①)、LVSがリアルサーバA,Bに振り分け(②)、リアルサーバA,BはホストAに直接返信する(③)と環境です。

ただ、実際には通信開始から5分程度経つと、下記の図1-2のように、リアルサーバBの戻りパケットがその他のホストBにも届いてしまうようになります。

f:id:masayoshi:20161219103359j:plain 図1-2: 5分後の想定しいない通信

ホストBでtcpdumpをした際に全く関係ない通信であるはずのホストAの通信が見えてしまったことで発覚しました。また、ホストB以外でも関係ないホストでホストAの通信が見えており、ブロードキャストされているようでした。

今回発生した問題はあるホスティングサービス上で構築した際に発覚したので、L2スイッチの詳細なつなぎ方などはわからないため、図は簡略表示をしています。 なぜブロードキャストになったのかを理解するにはL2スイッチの挙動を理解しなければいけないので、まず先にその話をします。

L2スイッチの挙動について

L2スイッチ(普通のLANハブでもよい)では、MACアドレステーブルというものを持っています。これはMACアドレスと物理ポート(L4のポートではない)の対応表であり、対象のMACアドレス宛てのパケットをどの物理ポートから出せばいいのか調べる際に利用します。 MACアドレステーブルに対象のMACアドレスがない場合は送出先ポートがわからないため、フラッディング(受信したポート以外にすべて送る)します。また、当然ですがブロードキャストアドレス(FF:FF:FF:FF:FF:FF)は常にフラッディングします。

このMACアドレステーブルは受信したポートとパケットの送信元MACアドレスからひも付けを行います。先ほどの図1の通信では図2-1,2-2,2-3のようにMACアドレスと、ポート番号を覚えていきます。はじめはフラッディングしていたL2スイッチも図2-3の時点でフラッディングせずに通信が可能になります。

f:id:masayoshi:20161219103611j:plain 図2-1: ホストA->LVSの通信時

f:id:masayoshi:20161219103631j:plain 図2-2: LVS->サーバAの通信時

f:id:masayoshi:20161219103652j:plain 図2-3: サーバA->ホストAの通信時

以降の通信はMACアドレステーブルを参照し、対象のポートのみに通信していきますが、MACアドレステーブルにはエージングタイム(IEEE802.1Dでは300秒とされている)が設けられており、エージングタイム以降は再学習することになっています。細かい仕様は機器毎に違ったりしますが、大体300秒程たった後に再学習出来ないとMACアドレステーブルが更新されないため、対象のMACアドレスへの通信はフラッディングになります。

MACアドレステーブルと非対称ルーティング

これまでの説明で、通信開始から5分程度でブロードキャストになるというのがMACアドレステーブルのエージングタイム(300秒)が切れたタイミングであることから、MACアドレステーブルが更新されなかったことが原因ということが予想できるのですが、なぜそうなるのか見ていきましょう。

f:id:masayoshi:20161219175714j:plain 図3-1: ARP Request時にMACアドレステーブルにエントリを追加

図2にL2スイッチβを追加したのが図3-1です。先程は省略しましたが、一番最初のホストAからの通信はLVS/TUNのMACアドレスを調べるためにARP Requestから通信が始まります。このとき宛先MACアドレスはFF:FF:FF:FF:FF:FFでブロードキャストを使います。

ブロードキャストなので当然L2スイッチβにもARPパケットが届きます。このとき送信元MACアドレス(ホストAのMACアドレス)と受信ポートからMACアドレステーブルが作成されます。これで最低でも5分程度はホストA宛のパケットはフラッディングではなく、対象のポートのみに送られます(図3-2)。

f:id:masayoshi:20161219104041j:plain 図3-2: MACアドレステーブルにエントリがある時の挙動

図3-2の状態ですが、重要なのはホストAからの送信パケット(①)です。ホストAはVIP宛のパケットを送ります。VIPのMACアドレスLVSMACアドレスなのでL2スイッチαはMACアドレステーブルに従ってLVSのつながっているポートにのみパケットを送ります。LVSはサーバBにパケットを送りますが、このパケットの送信元MACアドレスLVSMACアドレスであり、ホストAのMACアドレスでありません(当然ですが)。

つまり最初のARPによるブロードキャスト以外はL2スイッチβにホストAからのパケットは来ないことになります。サーバBからホストA宛のパケットはMACアドレステーブルに従い、L2スイッチαにのみ送られ、その後、ホストAに届きます。ただしそのACKパケットなどもLVSに行ってから送られるのでL2スイッチβはホストAのMACアドレスをブロードキャスト以外で知ることはできません。

なので、そのままエージングタイムが過ぎてしまうと、MACアドレステーブルからエントリが消えてフラッディングになってしまいます(図3-3)。 LVS/TUNのような行きと帰りのパケットが違うルートを通るような非対称ルーティングな通信を行うときには、こういうことが発生しやすいので特に注意する必要があります。

f:id:masayoshi:20161219112355j:plain 図3-3: MACアドレステーブルからエントリが消えた時の挙動

さて、原因っぽいのがわかったのはいいのですが、MACアドレステーブルが消えるまでにホストAがブロードキャストしてくれれば再学習ができるのでなんの問題もありません。サーバ側でそもそもARPテーブルのキャッシュがきれて更新するためにARP Requestが飛ぶので問題ないような気がします。

しかし、LinuxではARPテーブルがTCP通信で使用され続けていると、ARPテーブルのキャッシュは基本的に切れないという挙動になっているようなので、ある程度の頻度でTCP通信が定期的に発生しているとARP Requestが飛ばず、MACアドレステーブルが更新できないという状況になります。

LinuxARPの挙動

カーネルを読み込みが甘く、自分でも追いきれていない部分もありますので、下記内容には誤り、情報が古いなどあるかも知れません。

ARPテーブルのキャッシュに関する状態遷移の簡易図が図4です。

f:id:masayoshi:20161219112417j:plain 図4: ARPの状態遷移の簡易図

実際にはNUD_INCOMPLETE,NUD_FAILEDなど、他にも状態がありますが簡略化しています。ARP Requestが成功するとエントリが登録されNUD_REACHABLEになります。この状態では通信の際に普通にARPテーブルから対象のMACアドレスを得ることが出来ます。一定時間経つとNUD_STALEになります。NUD_STALEのエントリは参照されるとNUD_DELAYに遷移します。NUD_DELAYは一定時間内にTCP通信の場合は対象のMACアドレスからのACKが返ってきた場合ARP Requestは送らずNUD_REACHABLEに遷移します。つまり、ACKが返ってきたということはIPアドレスMACアドレスのひも付けは正しく、再解決する必要がないとカーネルが判断します。 なので、TCPで通信し続けている限りその対象のIPアドレスに対してARP Requestを投げることはしないという動作になります。

ちなみにUDPなどではsendmsgにMSG_CONFIRMフラグをつけることによって対象がまだ生きていることを通知してNUD_REACHABLEにすることが出来るらしいです。

NUD_PROBEに遷移するとNUD_DELAYと同じくTCP ACKを受け取るか、ARP Requestをユニキャストで送り、成功した場合はNUD_REACHABLEに遷移します。 tcpdumpで覗いているとユニキャストのARP Requestが来ることがありますが、そのパケットはNUD_PROBE状態から送られています。

そのユニキャストでの解決に失敗し、送信キューがある場合はARP Requestをブロードキャストで実行します。送信キューがない場合や応答が一定時間内に返ってこない場合はARPテーブルからエントリを削除します。 疑問点としてはNUD_PROBEが行うユニキャストARPは送信キューに入ってなくても行うかどうかですね。送信キューがなくても解決する場合は応答ある限りARPテーブルからエントリは消えないし、ARP Requestのブロードキャストが発生しないことになりそうです。 なお、NUD_REACHABLEなどの情報はip neighbor listなどで確認が可能です

▶ ip -s neighbor list
10.13.0.254 dev wlp4s0 lladdr 2c:6b:f5:3a:48:35 ref 1 used 78630/0/224 probes 4 REACHABLE

対策

対策としては送信元ホスト(ホストAなど)がブロードキャストをしてくれればよいということになります。

簡単なのは送信元ホストでarpingなどをcronでまわしたりするのが良いかなと思います。

はてなでは入れ替えの激しい送信元ホストやリアルサーバに仕込むのではなく、LVSから/proc/net/ip_vs_connをパースして送信元IPアドレスを偽装したICMP echo Requestパケットを送信元ホストに送信し、ICMP echo Replyを行う際にARP Requestを誘発させてブロードキャストを行う方法をとっています。この方法ではLVSにcronを仕込むだけで良いので、サーバの引っ越しや設定変更で書きなおし等があまり発生しません。(LVSを構築し直すときは別ですが頻繁には行わないです。)

まとめ

実際におきた事例の紹介とL2スイッチの基本的な挙動、LinuxARPの挙動について紹介しました。

今回の事例ではサーバからみるといきなりブロードキャストし始めたようにみえるので、L2スイッチの挙動を知らないとサーバ側の調査ばかりしてなかなか答えにたどり着かないみたいなことになりがちです。 ネットワークの問題かな?と思ったら丁寧にパケットの気持ちになってどうやって書き換えられていくのか、書き換える情報はどこから得ているのか、どこに送られていくのかを追ってみるのが大切だと改めて実感させられる事例でした。

また、Linuxではブロードキャストしないようにかなり気を使って実装されているなぁという印象を受けました。 なんかARPテーブルに登録しておいて時間がたったらもう1回解決するんでしょ?ぐらいにしか考えていなかったので勉強になりました。

このエントリで少しでもネットワークに興味を持ってくれる方が増えてくれると嬉しいです。

明日のアドベントカレンダーid:hakobe932さんです!

株式会社はてなに入社しました

ブログをはじめましたid:masayoshiです。 

2016年4月1日に株式会社はてなに新卒枠で入社しました。職種はWebオペレーションエンジニア職です。なんかサーバとかネットワークをいじる職種です。詳しく知りたい人は以下の本が全体的な雰囲気をつかめてオススメです。 

ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE)

ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE)

 

 

同期が優秀な人しか居なくて、インターン生だったり、既にアルバイトとして働いている方だったり、アメリカから半年前入社に成功している猫だったりで、「このままだと殺される」と感じたので、3月の下旬からアルバイトとして入って、ほとんど研修ですが、実質2週間ぐらい仕事をしていた感じです。

何か長くなったので、上の方に目標でも書いておきます。

  • 試用期間中にクビにならないこと
  • Webサービスを支えられる技術を身につけること
  • 会社を支えられるようになること

"会社を支えられるようになる"というのは、別に技術とかそういう話だけではなくて、社内で困っている人の相談に乗るとか、そういうのも含めてです。ココらへん目標とかは別のエントリにしっかり書きたいと思います。

 

以下は見たい人用

  • はてなの印象
  • 2週間でやったこと
  • 新卒力

はてなの印象

まぁ一日目で雰囲気ってなんだという気もしますが、↑に書いたようにアルバイト期間も含めての印象ってことで。

一言でいうと「技術を大切にしている会社だな」と思いました。

会話してて、アプリケーションエンジニアやWebオペレーションエンジニアは当然として、その他の方たちもエンジニアっぽく感じることが多いです。

「何か人には簡単に真似できないような技術ですごい事するすごい人」という雑な上に個人的な”エンジニア”の定義だと、一般的なエンジニアだけではなく、営業、人事、総務なども含んで"エンジニア"かなっと思った。

そういう意味で全員”エンジニア”な会社だなーというのが現在の印象です。

2週間でやったこと

  • 研修
  • 技術的なアウトプットの準備
  • 会社用PCのセットアップ
研修

バイト期間中に研修をやっていました(今は社員用の研修をやってます)。はてな研修用教科書に沿ってPerlとかJavaScriptとか頑張るやつです。(同期は既にインターンやアルバイト期間に終了している..)

github.com

私は研究室でアルティメット雑なC言語Pythonのクソコードを時々書いてただけなので、Webアプリケーションや他人に見られるコードの書き方を全く知らない状態からのスタートです。

とにかくすごいと感じたのがレビューで、アプリケーションエンジニアなのかWebオペレーションエンジニアなのかミニ四駆レーサーなのかわからない社員の方が、自分の仕事をこなしつつ、私のクソコードを丁寧にレビューし、初心者丸出しの質問に的確に答えつつ、定時か定時1時間以内に仕事を終わらせ、ミニ四駆やアニメ映画を見にいっていることです。

あんな感じに他人のコードをさっと見てレビューしたり、サンプルコードとかパッと提示できるあたりにプロを感じた。

Webオペレーションエンジニアはアプリケーションエンジニアに比べたらコーディング量は多くないものの、コーディングはするしミドルウェアソースコードを読むことも多いので、プログラミング修行の必要性を感じられてよい。

その社員の影響ということは全く無いですが、私もミニ四駆を買いました!

技術的なアウトプットの準備

はてなはエンジニアが技術的なアウトプットすることを非常に推していて、私もアウトプットしたいなと思ってたので、簡単な内容からちょくちょくアウトプットしていこうかと思います。

インフラ系エンジニアの人はご存知の方も多いかもしれませんが、はてなのWebオペレーションエンジニアにはアウトプット魔神のような社員がいて、毎週「いつ記事を書くのか。今でしょ」的なプッシュをされるので早めにやっていきたいです。

会社用PCのセットアップ

はてなでは、業務で使用するPCを個人で選択できます。大体MacBookが多いです。

私は、家のノートPCはMacBookとX220を使用していますが、先日大学の色々が終わったので、OSXを"El Capitan"にアップデートしたら色々疲弊したのと、有線LANが変換コネクタなど無しで使いたかったので、X260にしました。

最初は業務用なので「DebianとかUbuntuでいいかな?」と思っていました。

安定していたほうがいいし、情報量も多いほうがいいと考えたからです。

しかし、CPUが新しいので、Linuxカーネルがほぼ最新(4.4以降)でないと動かない関係で

  • DebianとかUbuntuにしても、結局unstableな感じになってしまう
  • 隣の社員はFreeBSDで、CTOはGentooを推してくる

といった感じなので、脳みそがユルユルになり、ArchLinuxをいれることにしました。

ArchLinuxを入れた理由は、普段使っているので慣れていることと、最新を追っている割には情報量が多いことです。

例えばUbuntuは情報量が多いですが、あくまでstableの情報が多く、testやunstableの情報量はさほど多くないです。

それに比べ、ArchLinuxはローリングリリースなので、ArchLinuxの情報は全て最新に近い情報が手に入ります。(X260の情報も既にあります。Lenovo Thinkpad X260 - ArchWiki)

業務用のPCなので、ディスクの暗号化とかをする必要があり、dm-cryptをCUIで操作しディスク暗号化をしたのは始めてだったので勉強になりました。(そのうち記事にしようかと思います)

新卒力について

ここからは意識が低いお話

上で書いたように、同期はアルバイトやインターン生だったので、私が一番フレッシュ感あふれて新卒力で殴っていけるのではないか?と考え、フレッシュ感を推してキャラ付けし、新しい会社に馴染んでいこうという計画を3月31日に思いついた。

結果としては、「全然フレッシュ感が無い」と言われてしまった。

研修でも振り返りは大事ということだったので、何がいけなかったのか振り返ってみる。

  • 始業3分前に出社
  • 「2016年には一般家庭でもvmstatを叩いている」
  • 「フレッシュ感という状態を持たない新卒は、スケールアウトが容易」
  • 自己紹介スライドを作らないうえに、発表内容もその場で考える

初めに3分前出社。4月1日の私は「学生気分が抜けきれてなくて新卒感ある」という主張をしていたが、どう考えても緊張しながら絶対に遅刻しないように始業30分前にはいる方が新卒力が高い。だが、私が出社した1分後に出社してきた1年前からアルバイトしている入社同期氏のほうが新卒っぽいと言われていたので、出社時刻が決定的新卒力の差ではないことがわかった。

2つ目の発言はランチのときの発言。今見直すと何いってんのこいつ?感しかない。確か風が吹けば桶屋が儲かる理論で「一般家庭にもNASがある時代」「NASがあるとvmstatを叩く」みたいな流れで誤った推論をしまくった結果出た発言で、MySQLに詳しい社員とFreeBSD使いの社員がなにいってんのこいつ?みたいな顔してた。でも詳細はよくわからないが、隣の席で「人間ドックではなく人間Docker」みたいなよくわからなそうな話も出てたし許容範囲な発言の気がする。少なくても新卒力を高める感じはしない。

3つ目は新入社員歓迎会のときの2分前出社同期氏との会話で出た発言。全くコンテキストを覚えてないから分からないが、私は素面で同期は酒が入っていたので、よった勢いという言い訳もできない。

4つ目は3分ぐらいの自己紹介があるので準備しといてね的なことを言われ、中途採用の方や他の同期がスライドを用意している中、全く用意していなかったので、その場で考えて発表してしまった。2分前出社同期氏もスライドを用意していなかったが、発表時にスマホを片手にあたかも原稿があるかのように見せて発表していた。

全体として、落ち着きがありすぎる(緊張感がない)ということが新卒力、フレッシュ感のなさに繋がっていそうというご意見を頂いた。

これは"はてなという会社の文化"に自然に入れたからということな気がしないでもないので、結果的に良かったということにしておこう。

 

長々と書きましたが、これから色々頑張ります!