ミドルウェア実行環境の多様化を考慮したインフラアーキテクチャの一検討

このエントリは第2回Web System Architecture研究会の予稿です.

発表資料

speakerdeck.com

はじめに

Webサービスのインフラを設計する上で、RDBやWebサーバを始めとした多くのミドルウェアは欠かせないコンポーネントの一つであり、それらの構築、運用も重要な要素である。 LAMP環境が提唱された1998年頃とは異なり、同じことを実現できるミドルウェアが複数あり、Webサービス開発者はミドルウェアの選択肢の幅が広がった。 また、2005年以降、サーバ仮想化技術の普及を始めに、クラウドベンダーによるミドルウェアのフルマネージドサービスやコンテナ技術の登場により、ミドルウェアの実行環境は多様化してきた。 同一のミドルウェアでも、実行環境が変わることにより、構築、運用手法や利用可能なツールが異なることがあり、それらの違いを表現可能なアーキテクチャの議論は十分にされていない。 本稿では、ソフトウェア設計で提案されているオニオンアーキテクチャ*1やクリーンアーキテクチャ*2の考え方を参考に、Webサービスにおけるインフラアーキテクチャの捉え方を再考、整理を行なっている。 再考したアーキテクチャを洗練することで、多様化したミドルウェア実行環境を、Webアプリケーションの機能要件のみならず、運用も考慮した選択手法を議論する際に利用できると考えている。 しかしながら、アーキテクチャ検討は不十分であり、発表時に提案したアーキテクチャについての議論を行ないたいと考えている。

本稿の位置づけ

筆者はWebサービスにおけるインフラアーキテクチャの体系化し、Webサービス毎に適切なアーキテクチャを自動的に生成する研究を個人的に取り組んでいる。 本稿は、前回の発表*3で整理した課題における「既存のインフラアーキテクチャの調査と分類」の一部である。

既存のインフラアーキテクチャ

Webサービス構築の全体的なインフラ設計をするための、汎用的で明確な命名がされているインフラアーキテクチャはほとんど存在しない。そのうちの有名なアーキテクチャとして1990年代にできた3層アーキテクチャと呼ばれるものがある。 3層アーキテクチャを図1に示す。

f:id:masayoshi:20180505163015j:plain
図1: 3層アーキテクチャ

このアーキテクチャはWebサーバ、アプリケーションサーバ、DBサーバの3つからなるアーキテクチャである。 図1に示すように、それぞれがプレゼンテーション層、アプリケーション層、データ層のレイヤーで表現される。 この3層アーキテクチャを実装するためのOSSの種類としてLAMP構成と呼ばれる造語が1998年に誕生した。LAMPはサーバOSとしてLinux、WebサーバとしてApache、DBサーバのMySQL、そしてWebアプリケーション実装をPerlで行うものである。当時はミドルウェアの種類も多くなかったため、このような造語が誕生したと思われる。 Webサーバ、アプリケーションサーバ、DBサーバはそれぞれワークロードが異なり、冗長化手法なども異なるため、スケーラビリティやキャパシティプランニングが容易になる。 Webアプリケーションはアプリケーションサーバのみにデプロイすればよく、WebサーバやDBサーバへのアプリケーションのデプロイは不要である。 3層アーキテクチャの特に重要な点は、3層というレイヤードアーキテクチャではなく、役割毎に違うサーバを分離しておくということである。 3層というのは、当時のWebサービスがシンプルな動的ページを返すサービスがほとんどであり、クライアントサーバモデルの基本が3層であるという実装上の話に過ぎない。 また、現在のWebサービスCDNやオンメモリKVSのキャッシュサーバなどを利用されるため、3層以上のレイヤーになることや、リクエスト処理のアプリケーションとバッチ処理のアプリケーションを分離するなど、データの流れや依存は複雑化しており、単純な階層化で表現することは困難である。

そこで本稿では、3層アーキテクチャからデータの流れによる階層化を除き、役割毎に別サーバに分離するアーキテクチャをロール分割アーキテクチャと呼ぶことにする。 ロール分割アーキテクチャの図2に、ロール分割アーキテクチャの例を図3を示す。

f:id:masayoshi:20180505163234j:plain
図2: ロール分割アーキテクチャ f:id:masayoshi:20180505163333j:plain
図3: ロール分割アーキテクチャの構成例

図2、3の赤い線はリクエスト処理の依存を表す。 2007年頃からは現在Webサービスではよく利用されるRedis,Cassandra,MongoDBなどのKVSミドルウェアを始め、より高度なWebサービスを作るため、様々なミドルウェアOSSとして実装され、多くのWebサービス事業者が利用出来るようになった。 ロール分割アーキテクチャミドルウェアを多様化にも対応可能であり、複数のミドルウェアを組み合わせや、アプリケーションの処理内容によって、複数のアプリケーションに分離した場合でも表現ができる。 図3の例では、WebサーバのNginx、RDBMySQL、アプリケーションに加え、キャッシュサーバとしてRedisを追加し、バッチ処理用のアプリケーションを別サーバに分離している。 このように、ロール分割アーキテクチャミドルウェア毎にサーバを別にするため、多数のサーバを構築、管理する必要が出てくる。Webサービスの高度化と増加するサーバ、ミドルウェアの運用コストとのバランスが重要になり、効率の良い運用、管理手法の重要度が増した。 多くのサーバの構築に利用されるChefなどのプロビジョニングツールなどが登場したのもこの頃である。 ミドルウェアは多様化しているものの、ミドルウェアの実行環境であるOS部分は統一可能であることが多いため、ミドルウェアの構築やアプリケーションのデプロイなどは例えばSSHを利用して自動構築、デプロイするツールを利用することで自動構築することが可能であった。 また、監視ツールなどもミドルウェア固有のパラメータの取得はミドルウェア毎に対応が必要なものの、CPU利用率やネットワークの死活監視、プロセスの生存確認などはOSの機能やSNMPなどのプロトコルを利用して取得が可能であった。 これらを言い換えると、Webサービスの提供とは直接関係のない構築、管理のためのアプリケーションやミドルウェア(例えばSSHサーバ)がミドルウェア実行環境がOS上であることが前提だったため、Webサービスのインフラ設計と、サーバ(正確に言えばOS)の構築、管理の仕組みはある程度分離して考えることが可能であったということである。

既存のインフラアーキテクチャの問題点

上述した既存のインフラアーキテクチャの問題点は、ミドルウェアの実行環境が多様化した際にWebサービスのリクエスト処理などは考慮できるものの、ミドルウェアの構築や監視など、Webサービスを運用していく上で重要となるインフラ管理、運用を考慮しきれていないことである。 現在、以下の2つの要因でミドルウェア実行環境の多様化が発生している

1つめはコンテナ技術である。コンテナ技術には様々な実装形態があるが、本稿ではDockerを例に説明する。 Dockerでは対象のアプリケーションをコンテナ上で実行できるが、Dockerは基本的に1コンテナに1アプリケーションという設計で作られている。例えばWebサーバであるNginxとSSHサーバであるOpenSSHを同じコンテナ上で動かすことはDockerの設計とは合わない。コンテナ上にNginxを構築するにはDockerが提供しているDockerfileという仕組みを利用して構築する。ChefなどのSSHが前提のプロビジョニングツールを利用した構築には不向きである。 2つめはミドルウェアのマネージドサービスである。本稿ではAWSを例に説明をする。 RDBサーバとしてMySQLを利用する場合、AWSのマネージドサービスとしてRDSとAuroraが存在する。RDSやAuroraを構築する方法は通常のOS上にMySQLを構築する方法とは大きく異なり、AWSが提供しているAPIを利用して構築する必要がある。ツールとしてはAWSが提供するCloudformationといったサービスやAWS APIに対応したTerraformなどのOSSを利用できる。SSHを利用したプロビジョニングツールの利用は基本的にはできない。 これらはミドルウェアの監視にも同じことが言える。OSの機能を使った監視(例えばPSコマンドによる監視)はマネージドサービスには利用できない。コンテナ上でも一部制限があるものが多い。 特にFaaSであるAWS Lambdaなどによるサーバレス環境は特に運用、管理に注意が必要である。マイクロサービスが実行されるサーバレス環境の管理手法とコンテナ、仮想サーバの管理手法などと併せて考える必要がある。本稿ではマイクロサービスへの議論までは行わないが、サーバレスなアプリケーションはミドルウェアのマネージドサービス管理手法の応用で対応が可能であるのではないかと筆者は考えており、今後検討が必要である。

DockerでNginxを動かしても、仮想マシン上でNginxを動かしてもHTTPリクエスト処理は可能であるため、Webアプリケーションの要件は満たせるが、構築、運用の要件によって使い分ける必要がある。 一般的に単体で見ればコンテナ技術やマネージドサービスが効率よく構築、運用が可能であるが、一つのWebサービスでコンテナ技術やマネージドサービスと従来の仮想マシン上で実行するミドルウェアが混在する場合、バランスを取ったほうがよいケースも存在しうる。

ミドルウェア実行環境の多様化により、Webサービスの機能要件だけではなく、運用管理手法も併せて選択する必要があるが、既存のインフラアーキテクチャでは表現が不十分である。 現在はロール分割アーキテクチャから下層のServerを除き、ミドルウェアクラウドサービスの依存や、リクエスト処理フロー、データフローを記載したインフラアーキテクチャ図によって表現されることが多いが、これらだけではアプリケーションの要件を満たすか議論することはできるが運用、管理を同じアーキテクチャで議論できない。別のアーキテクチャで運用、管理を表現し議論すると、アプリケーションの要件やデータフローなどの確認が難しい。 そのため、アーキテクチャを見ただけでその選択により何のトレードオフが発生するかをイメージすることが難しく、識者でなければ把握することが難しい(コンテナを選択するとChefが選択できないなど)。

提案手法

ミドルウェア実行環境の多様化を考慮し、かつ運用、管理手法を表現できるアーキテクチャをオニオンアーキテクチャなどのソフトウェア設計手法を参考に検討する。 ソフトウェア設計手法を参考にする理由を下記に示す。

ソフトウェア設計手法と同じくまずは実装ベースのレイヤードアーキテクチャを考え、そこから見方を変えることで、よりアプリケーションの要件と運用、管理を考慮しやすいアーキテクチャを再考していく。 ソフトウェア開発は、実装を自らが行ないその際のクラスの依存関係がシンプルになるようにするためのアーキテクチャであるのに対し、インフラ設計はミドルウェアなど既に存在する実装から選択し、その選択によるツールの依存関係を知りたい、もしくはシンプルにしたいと言うように実際には異なる点も多々ある。 そのため、そのまま適用できるわけではないので、参考にしつつ取り入れられるところを取り込んでいく形となる。 具体例として以下を環境を想定して話をすすめる。

  • WebアプリケーションがRDBを利用したいので、MySQLを選択する例をとる
  • MySQLを仮想サーバ上に構築する場合、コンテナ上に構築する場合、マネージドサービス上に構築する場合における構築ツールとの関係と監視手法との関係、Webアプリケーションとの関係を考える
  • コンテナを使う場合にはDockerを使うことにする
  • AWSMySQL互換のマネージドサービスとしてRDS、Auroraを検討する
  • 構築ツールとしてサーバにはChef、コンテナにはDockerfile、RDS,AuroraにはCloudformationを使う

実装ベースの単純なレイヤードアーキテクチャ

実装ベースのレイヤードアーキテクチャを図4に示す。

f:id:masayoshi:20180505163732j:plain
図4: 実装ベースのレイヤードアーキテクチャ

このアーキテクチャでは図4のように、上からUI、Middleware、Infrastractureとする。これはソフトウェア設計のレイヤードアーキテクチャと似た命名をしている。 UIはミドルウェアが提供するAPIプロトコルである。ソフトウェア設計と異なる点としてはUIは自分たちで設計し実装するため自由に設計できるが、ミドルウェアの場合は追加が困難なことも多い。 Middleware層はミドルウェアの実装を指す。ここも自分たちで実装することも出来るが、多くの場合は既に存在するミドルウェアを選択すると考えられる。 Infrastractureはミドルウェアの実行環境を指す。OSやコンテナ、マネージドサービスであったりする。

ここで具体例を当てはめたのが図5である。

f:id:masayoshi:20180505163858j:plain
図5: レイヤードアーキテクチャの例

UIにはMySQLプロトコル、MiddleWareにはMySQLかRDSかAuroraが、InfrastractureにはOS、コンテナ、AWS(マネージドサービス)が入る。 Webアプリケーションはどの場合にもMySQLプロトコルを使って通信をする。 構築ツールはChefはOSにSSH経由で、Dockerfileはコンテナへ、CloudformationはAWSAPI経由で実行される。 外部から一番下層のレイヤーに接続しており、レイヤードアーキテクチャとしては少々おかしい。 構築ツールはMySQLを構築するためのものなので、実装ベースのレイヤードアーキテクチャでは再下層に接続するのは自然である。

実装ベースのレイヤードアーキテクチャの問題点を以下に示す。

  • 外部からの接続で最下層レイヤーを参照している
  • UIやMiddleWareはミドルウェア実装を選択した時点で記載内容が決まっている
  • ミドルウェア選択の際に利用できる情報がない

2つめと3つめはインフラ設計においてミドルウェアの選択が重要であるが、その選択の際に必要となる依存関係などがわからない、表現できないため既存のインフラアーキテクチャと大きく変わりはない。

オニオンアーキテクチャを参考にしたインフラアーキテクチャ

オニオンアーキテクチャを図6に示す。

f:id:masayoshi:20180505164806j:plain
図6: オニオンアーキテクチャ

オニオンアーキテクチャは名前の通り、玉ねぎのように同心円状で表されるアーキテクチャである。似たようなアーキテクチャとしてヘキサゴナルアーキテクチャ*4、クリーンアーキテクチャがあげられる。名前の違いなどあるものの、抽象度の高いDomain Modelを中心に置き、Interface、Infrastracture、TestsをDomainから分離している。
この特徴を参考にインフラアーキテクチャへ置き換えたものを図7に示す。

f:id:masayoshi:20180505164931j:plain
図7: オニオンインフラアーキテクチャ

図7に示したアーキテクチャを本稿ではオニオンインフラアーキテクチャと呼ぶことにする。 domainはミドルウェア実装の本来のdomainを示す。例えば今回の例であればRDBMSということになる。 実際の設計者はWebアプリケーションにおいてRDBを利用したいという要望があり、それからミドルウェアの選択に移ることが多いだろう。 その次のMiddlewareでは実際のミドルウェア実装を示す。今回はMySQLなどが該当する。 一番外枠はUI、Infrastracture、ManagedServiceである。UIとInfrastracutureは基本的にレイヤードアーキテクチャと同じものが該当する。 Middleware Serviceは下層のMiddlewareに対して互換をもつ実装やマネージドサービスが該当する。 実際に今回の具体例を上記のアーキテクチャに当てはめた例が図8である。
f:id:masayoshi:20180505165151j:plain
図8: オニオンインフラアーキテクチャの具体例

Webアプリケーションはレイヤードアーキテクチャと同じく、MySQLプロトコルで接続する。 ここでは省略しているがWebアプリケーションはそのままオニオンアーキテクチャを利用し、WebアプリケーションのInfrastractureとRDBのUIが接続している。 簡易的にプロビジョニングツールは、Domainとしてprovisioningとなり、それぞれのツールがInfrastructureにつながり構築を表現する。 実際にはこの他にWebサーバやKVSなど他のDomainのオニオンインフラアーキテクチャも記載し、それぞれをWebアプリケーションからの接続、Provisioningからの接続を書き記すことで、依存関係を把握することが出来る。可能な限り依存関係の接続は少ないほうが、シンプルなより良いアーキテクチャの選択となる。例えばProvisionigのツールとしてCloudformationでWebサーバ、KVS、RDBMSのすべての接続が可能であるならば、図のChefやDockerfileは使う必要はなく、そういった選択を出来るかUIとWebアプリケーションとの接続も併せて同じアーキテクチャ内で検討することが出来る。

レイヤードアーキテクチャに比べて以下の改善点が見られる

  • Domainを導入したことにより、ミドルウェア実装の表現が可能になった。
  • レイヤードアーキテクチャが並べてあるよりも、Interfrastructureの選択とProvisioningツールとの関わりがわかりやすくなった。
  • また、外部との接続は外郭のみとなり、レイヤードアーキテクチャよりは違和感がすくなくなった。

しかし、以下の問題点が存在する。

  • ProvisioningがMiddleware ServiceとInfrastractureにの両方と繋がっている
    • Provisioningの規模を小さく抑えるために考慮する際に、接続箇所が2つあるのは検討がしにくいのではないか
  • Domainの記述ではRDBMSとして同じでも実際の機能が大きく異なる点も多いがそれらを表現しきれていない
    • 依存関係の明確化と機能の明確化は異なるのでそれぞれ違うアプローチを試みるのが良いかもしれない

まとめ

既存のインフラアーキテクチャミドルウェアの観点からみて問題点を考察した。 ミドルウェアの実行環境の多様化による運用管理の考慮事項の増加は、昨今のインフラ設計において無視できないものであり、それらを考慮したインフラアーキテクチャをソフトウェア設計の考え方の一部を適用し、改善できないか再考した。 まだ、整理や考察が足りない箇所があるが、新規性や有用性がより明確に出てくる可能性があると考えている。

議論したいこと

  • アーキテクチャというよりはどちらかというとUMLのようなものに近いかも?
    • 依存の可視化を行ない、選択を容易にするという観点でもUMLのほうが近い気もする。
    • 実際に実装するわけではないのでこの辺はそのままアーキテクチャとして持ってくると違和感があるかも
  • RDB, Webサーバ, KVSという感じにDomainを作っていきそれぞれをつなげてみるともっと見えてくるかもしれない
  • プロビジョニングツールのような運用管理ツールはミドルウェアとは少し違う同心円状かも?
  • プロビジョニングだけではなくモニタリングも入れたい
    • 現状上手い形が見つからずもう少し整理が必要そう
    • なにかいい案が無いだろうか
  • もう少し整理されると面白そうで新規性や有用性も見えてくる気がしている

議論で出た内容

  • OSのレイヤー(ハードウェア、カーネルシステムコール、システムライブラリ)や、リングプロテクションに似ている
    • OSなど権限がはっきりし、レイヤーを明確に分離する場合にはこういった表現が使える
      • レイヤーをオーバして成功した例も存在する(SDNなど)
  • 現在は過渡期なので実行環境が混在しているが、最終的には全部はマネージドサービスになるのではないか
    • 今回はミドルウェアの実行環境を想定したが、下のレイヤーが変化、多様化することはいつでも発生しうるため、それらを考慮したアーキテクチャを考えることは重要
  • UMLというのは時代と逆行してそうで筋が悪そう
  • ミドルウェアというのも既に死語になりつつあるのではないか
  • プロビジョニングツールなどが複雑になってしまうのは、筋の悪い間違った(レイヤーをオーバーしたような)使い方をしているだけなのではないか
    • そういった使い方が、図示したときに可視化されることによって、ユーザーがレイヤーをオーバーした使い方をしていることが分かることは重要

あとがき

今回は既存のWebサービスにおけるインフラアーキテクチャを調査を開始し、それらからミドルウェアの実行環境の多様化に焦点を当てて、ソフトウェア開発手法を参考に適用したものを検討した。 現在は既存のものを調査、整理している段階であることもあり、予稿や資料の作成、発表をするにあたって、まだまだしっかりとした言葉の定義や検討内容が不十分であると感じた。 しかし、多様化と複雑化を解決するためによりソフトウェア的な解決方法(という言い方で良いのかわからないが)をとるようになったインフラの設計手法は、複雑かつ巨大なソフトウェアを開発するために進化したソフトウェア開発手法を参考にできることがあるのではないかという考えは今回の整理でより強くなった。 今後はソフトウェア開発手法の変化と、インフラの多様化を更に調査、整理することで、体系化への一歩を進めたいと思う

*1:Jeffrey Palermo (.com). The Onion Architecture : part 1. Retrieved May 5, 2018 from http://jeffreypalermo.com/blog/the-onion-architecture-part-1/

*2:8th Light. The Clean Architecture. Retrieved May 5, 2018 from https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

*3:Webサービスにおけるインフラアーキテクチャの体系化とインフラアーキテクチャの選択自動化の研究課題についての整理と考察. Retrieved May 5, 2018 from http://masayoshi.hatenablog.jp/entry/2017/12/27/235456

*4:Alistair.Cockburn.us. Hexagonal architecture. Retrieved May 5, 2018 from http://alistair.cockburn.us/Hexagonal+architecture

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分前出社同期氏もスライドを用意していなかったが、発表時にスマホを片手にあたかも原稿があるかのように見せて発表していた。

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

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

 

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