Swift が iPhone, iPad, Mac, Apple Watch そして Apple TV のアプリを開発する言語として選ばれていることはみなさんご存知でしょう。この数年、Swift は Linux で動作するサーバーサイドアプリケーションを開発するのにも優れた言語としても浮上してきました。現在、Apple, Facebook, Google, Netflix, Twitter などの企業が運用する大規模な環境では、Java、C ++などの言語による、パフォーマンスに最適化されたネットワークフレームワークが使われています。このトークでは、Apple のサーバーインフラストラクチャーチームが長年の経験を活かし、どのように高性能でスケーラビリティの高いネットワークアプリケーションを作成して、どのように開発時にSwiftを利用しているかについて説明します。
Event driven networking for Swift
Event driven networkingについて、バズワードでもあるので説明したいと思います。
非同期が何故大事なのか
答えは簡単、リソースを最大限使いたいと思うだろうからです
サーバーとモバイルの間での読み書きはおもったよりも低い頻度で起きていて、常にIO待ちとなってしまう。
非同期でないネットワーキングプログラムではスレッド、コネクションを一つ作成するか、コネクションごとにスレッドを用意するということになると思います。
IOオペレーションがスレッドの一つをブロックするとたちまち困ってしまいます。
こちらなら一つのスレッドが複数のコネクションを管理できます。
これまでIOに持っていた前提条件が壊れることになります。
データの中で怒ってからデータが返ってくるという前提は壊れます。
ネットワークサービス全体が大きく複雑化してしまいます。
この複雑さを許容しようとする理由を理解するには、常にトレードオフがあるが、ハイスケールサービス(システム)を口にする時、数百から数千を同時に処理しなければならなくなるということがあるのを理解する必要があります。
スレッドを使うとコストはある。
しかし、メモリオーバーヘッドしたとしても、他にもパローマンスコストになることがある。OSが一つのスレッドで進展する時にOSのスケジューラーに処理されるが、インパクトが一番大きいのは、必ずそのスイッチのコンタクトが必要だということです。
恐らく最悪、になるのは、CPUコアのキャッシュの廃棄です。
オペレーションは高速だったが、このトラッシングによりスローに鳴ってしまう。
キャッシュがないからデータが底にアクセス出来ないということになる。
こうした複雑性をどう解決していくか。Non Blocking IOを使っていきましょう
JVMや他の言語では、ネッティー(?)の開発に投資をしている
ここで、もしかしたら新しいものを作ったほうがいいかもという話になりました。
SwiftNIOと言うものです。
Swift用のNettyだと思って下さい
これまで成功してきたとおり、柔軟なのに、これまでは複雑でした。AppleはNettyで多くの経験を積み、複数の人間がNettyプロジェクトに関わっています。
Nettyは大きな人気の高いプロジェクトApacheやNoSQLデータベース、Sparkなどが使っています。GRPCも使っています。実証済みのAPIになりということです。
本当に最後に申し上げたいのはNettyは既に経験がある人にとって容易になるということです。Swiftの探索がとても簡単になります。JVMのユースケースと似ているわけですから。
低レベルネットワーキングフレームワークです
TCPプロキシなども使えますし、DNSサーバーなどもそうです。
高レベルフレームワークではありません。KituraやVaporではありません
そのひとつ下のレイヤーです。
殆どのユーザーは直接使わないでしょう。しかしその上に構築されたフレームワークを使うことになります。
簡単に説明していきます
イベントループグループがあります
スレッドプールと考えてもいいでしょう。
一つのイベントループは一つが専用のスレッドを持つ。これが大事な理由は後で話す。
チャネルそのものがエンドポイントを抽象化したものです。それが何を意味するかは実装に関わります。
ソケットのように考えて良いと思います。TCPやUDPなどです。
そしてチャネルパイプラインがあります。チャネルにアサインされます。チャネルパイプラインは複数のチャネルハンドラを持ちます。ハンドラそのものはロジックの処理をさせてくれます。インバウンド、アウトバウンドデータをインターセプトできます。
これも後で話します。
ブートストラップとかもあります。チャネルをセットアップします。
コンテナはデータストラクチャをコピーします。高度なオペレーションができます。
重要なのはSwiftがCopy on writeの機能があるので関数から関数に渡すのも簡単にできます。
イベントループの図式です
イベントループと読んでいますが無限ループの中で実行されています。シャットダウンもあるのですが。
様々なイベントタイプを収集処理していきますlイベントループは複数の処理を扱うことができます。一つのスレッドでコネクションを多重化する必要があるからです。
すべてのチャネルからコネクションをアクセプトします
これが終わるとタスクのキューに入ります。それを実行します。それを継続できるまでブロックします。これがここの基本的な考え方です。
興味深いとkロオへ行きましょう
これがチャネルパイプラインです。基本的に、複数扱うことができます
モバイルデバイスで十分読み込めない時はとめてメモリ稼働率を高める。BackPressureHandlerで。
この3つの構成要素があって、完全なechoサーバーができます。暗号化もされています。あんごうかが不要ならOpenSSLハンドラをれムーブすれば良いです。
チャネルハンドラは2つのコールバックがあります。パイプラインにAddされたのとRemoveされた時。
インバウンドハンドラ
メソッドが幾つかあります。チャネルがアクティブになった時、Inactiveは接続がKillされた時。ChanelReadは読み出される時、ReadCompleteは終わった時。ErrorgaおきたCaught
Outboundは逆
Promissというのはオペレーションが終わると呼び出されるもの
例です
flushというのはSysCall内のデータをすべて捨てる。 closeで閉じる、もうリカバーできません
どう組み合わせていくのか
echo サーバーをマウントしていく
パイプラインをOnTheFlyでできる
プロトコルのアップデートなどをハンドラーのリムーブをしながらできる
SwiftNIOがエコシステム全体にどのような影響があるのか
Nettyと同じようなものかと思います
すでにSwiftコンパイラチームに最適化するように言っています。
今日オープンソース化されました
Appleから7人ぐらい来ているので、恥ずかしがらずに話して下さい!