NginxとかNode.jsで使われてるあれ
イベント駆動アーキテクチャとは
イベント駆動とは「イベント」と呼ばれるアプリや端末上で起きた出来事に対して処理を行うプログラムの実行形式のことです。 イベントがトリガーとなって、関数やメソッドが実行される、というイメージです。 javascriptでのプログラミングもobjective-Cでのプログラミングも、このイベント駆動の仕組みを理解するとプログラミングがしやすくなります。
NginxやらNode.jsで採用されているイベント駆動モデル
httpリクエストを1プロセス1スレッドで処理することでc10k問題などを回避している。
基本的には1プロセスでは同時に複数の処理を行うことができないが非同期IO/ノンブロッキングIO/IOの多重化といった技術を組み合わせて 1プロセスで複数のリクエストを捌いている。
今回はIOの多重化の話。 IOの多重化とは1つのプロセス内で複数のファイルディスクリプタを継続的に監視して読み込み可能なディスクリプタがあれば処理を行うもの 具体的にpoll(2)やselect(2)を使って行われる。
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); #define _GNU_SOURCE /* feature_test_macros(7) 参照 */ #include <signal.h> #include <poll.h> int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);
pollの定義は上記の通り。 ファイルディスクリプタの配列を受けとって読み込み可能なディスクリプタがあれば処理をするというような実装を実現できる。 (nginxやnodeではソケットの生成時にノンブロッキングオプションを付加して生成。)
nginx実装
せっかくなのでnginxの実装をみてみる pollを読んでるのは具体的には下記
static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { int ready, revents; ngx_err_t err; ngx_uint_t i, found, level; ngx_event_t *ev; ngx_queue_t *queue; ngx_connection_t *c; // 省略 ready = poll(event_list, (u_int) nevents, (int) timer); /* event_list : ngx_poll_add_event()などでイベントを追加 nevents : イベントの数 timer : ngx_process_events_and_timers()関数にて定義 */
イベントごとにリストを生成してpollを呼び出している。 呼び出したあとはreadyの値をみて「POLLOUT」「POLLIN」のビットをみて処理を分けている。
// ngx_connection_tはコネクションの状態を保持する構造体 if ((revents & POLLIN) && c->read->active) { found = 1; ev = c->read; ev->ready = 1; ev->available = -1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; ngx_post_event(ev, queue); } if ((revents & POLLOUT) && c->write->active) { found = 1; ev = c->write; ev->ready = 1; ngx_post_event(ev, &ngx_posted_events); }
その他
ネットワークIOでの非同期/ノンブロッキングは理解はしやすいが実装するのはとても難しそう。。 nodejsも読みたかったけどjsで書かれていたので断念しますw