Upgrade to Pro — share decks privately, control downloads, hide ads and more …

nginxの初期化について

karky7
November 28, 2015

 nginxの初期化について

karky7

November 28, 2015
Tweet

Other Decks in Technology

Transcript

  1. main関数その3 12. モジュール数のカウント 13. ngx_init_cycle() ・・・これでかい 14. ngx_os_status() 15. ngx_init_signals()

    16. ngx_daemon() ・・・ デーモン化 ※ページを稼いでいる分けではありませ
  2. pagesizeの取得 ngx_pagesize = getpagesize(); / * s y s c

    o n f ( _ S C _ P A G E S I Z E ) * /
  3. CPU Cache Line とりあえず暫定的に決め打ちしておいて、後でcpuinfoでしっかり設定 ngx_cacheline_size = NGX_CPU_CACHE_LINE; ... void ngx_cpuinfo(void)

    { ... ... case 6: ngx_cacheline_size = 32; model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0); if (model >= 0xd0) { / * I n t e l C o r e , C o r e 2 , A t o m * / ngx_cacheline_size = 64; } break; ...
  4. CPU Cache Line Pentium /Pro/II/III ... 32 Intel Core, Core

    2, Atom ... 64 AMD ... 64 その他 ... 128 となっております
  5. open可能fd数 プロセスがオープンできる最大のfd数 getrlimit(RLIMIT_NOFILE, &rlmt) ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur; karky7 ~

    # ulimit -a ... open files (-n) 1024 ここで設定されるのは初期値で、のちにnginx.confファイルの worker_rlimit_nofileで指定可能
  6. ngx_module_t *ngx_modules[]とは モジュールを管理するオブジェクトをまとめた構造体、モジュールを追 っかけるにはこの構造体からみるといいね! objs/ngx_modiles.c ngx_module_t *ngx_modules[] = { &ngx_core_module,

    &ngx_errlog_module, ... ... &ngx_http_copy_filter_module, &ngx_http_range_body_filter_module, &ngx_http_not_modified_filter_module, NULL }; objsディレクトリはconfigure時に生成されます
  7. module context ngx_module_t経由でngx_core_module_create_confが呼ばれます static ngx_core_module_t ngx_core_module_ctx = { ngx_string("core"), ngx_core_module_create_conf,

    / * v o i d * ( * c r e a t e _ c o n f ) ( n g x _ c y c l e _ t * c y c l e ) ; * / ngx_core_module_init_conf / * c h a r * ( * i n i t _ c o n f ) ( n g x _ c y c l e _ t * c y c l e , v o i d * c o n f ) ; * / }; ngx_module_t ngx_core_module = { NGX_MODULE_V1, &ngx_core_module_ctx, / * m o d u l e c o n t e x t * / ngx_core_commands, / * m o d u l e d i r e c t i v e s * / NGX_CORE_MODULE, / * m o d u l e t y p e * / NULL, / * i n i t m a s t e r * / NULL, / * i n i t m o d u l e * / NULL, / * i n i t p r o c e s s * / NULL, / * i n i t t h r e a d * / NULL, / * e x i t t h r e a d * / NULL, / * e x i t p r o c e s s * / NULL, / * e x i t m a s t e r * / NGX_MODULE_V1_PADDING };
  8. ngx_conf_parse() 実際のnginx.confのparseを実行 #define NGX_CONF_BUFFER 4096 .. for ( ;; )

    { rc = ngx_conf_read_token(cf); ... defaultでnginx.confファイルのサイズは4096バイトに制限される でかいファイルを読みたい場合は、NGX_CONF_BUFFERをでかくし てコンパイル confファイルにluaコードとか書きすぎると叱られる
  9. 引数を内部数値へ変換 static ngx_command_t ngx_core_commands[] = { { ngx_string("daemon"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot,

    / * パラメータ化する関数 * / 0, offsetof(ngx_core_conf_t, daemon), NULL }, ... { ngx_string("worker_processes"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_set_worker_processes, / * パラメータ化する関数 * / 0, 0, NULL }, ... ...
  10. ログファイルなどのopen accecc_log、error_logのopen if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) { ngx_log_error(NGX_LOG_EMERG,

    log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", file[i].name.data); goto failed; } FD_CLOEXECでexecve()された場合でも適切にfdをcloseするように 設定
  11. Listen socketをnonblocking化 int nb = 1; retrun ioctl(s, FIONBIO, &nb);

    ソケットをnonblockingへ設定 fcntl ・・・ F_SETFL,O_NONBLOCK ioctl ・・・ FIONBIO Posix.1g ・・・ fcntlで設定を推奨ということらしい
  12. NGX_CORE_MODULEの初期化 static ngx_core_module_t ngx_core_module_ctx = { ngx_string("core"), ngx_core_module_create_conf, / *

    v o i d * ( * c r e a t e _ c o n f ) ( n g x _ c y c l e _ t * c y c l e ) ; * / ngx_core_module_init_conf / * こちらです * / }; 最終初期化処理の実行
  13. module_init系の呼出 全てのモジュールのinit_module系を呼び出す(定義されていればです が) for (i = 0; ngx_modules[i]; i++) {

    if (ngx_modules[i]->init_module) { if (ngx_modules[i]->init_module(cycle) != NGX_OK) { / * f a t a l * / exit(1); } } } ngx_event_module_init ngx_regex_module_init ngx_http_spdy_module_init
  14. ngx_init_signals() ... 1 シグナル情報をまとめたテーブルを利用してシグナルハンドラを登録 ngx_signal_t signals[] = { { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),/

    * S I G H U P * / "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), / * " S I G H U P " * / "reload", ngx_signal_handler }, / * h a n d l e r * /
  15. ngx_init_signals() ... 2 シグナルハンドラをngx_signal_handler()へセット SIGHUP ... NGX_RECONFIGURE_SIGNAL SIGTERM ... NGX_TERMINATE_SIGNAL

    SIGQUIT ... NGX_SHUTDOWN_SIGNAL SIGWINCH ... NGX_NOACCEPT_SIGNAL SIGUSR1 ... NGX_REOPEN_SIGNAL SIGUSR2 ... NGX_CHANGEBIN_SIGNAL SIGALRM SIGINT SIGIO SIGCHLD SIGSYS SIGPIPE
  16. ngx_signal_handler() ... 1 ngx_processの値が以下の場合 NGX_PROCESS_MASTER NGX_PROCESS_SINGLE NGX_SHUTDOWN_SIGNAL ... ngx_quit =

    1(shutdown) NGX_TERMINATE_SIGNAL ... ngx_terminate = 1 (exiting) SIGINT ... ngx_terminate = 1 (exiting) NGX_NOACCEPT_SIGNAL ... ngx_noaccept = 1 (stop accepting connections) NGX_RECONFIGURE_SIGNAL ... ngx_reconfigure = 1 (reconfiguring) NGX_REOPEN_SIGNAL ... ngx_reopen = 1 (reopeninig log) NGX_CHANGEBIN_SIGNAL ... ignore = 1 (ignore) SIGALRM ... ngx_sigalrm = 1 SIGIO ... ngx_sigio = 1 SIGCHLD ... ngx_reap = 1
  17. ngx_signal_handler() ... 2 ngx_processの値が以下の場合 NGX_PROCESS_WORKER NGX_PROCESS_HELPER NGX_NOACCEPT_SIGNAL ... ngx_debug_quit =

    1(ngx_daemonized == 0) NGX_SHUTDOWN_SIGNAL ... ngx_quit = 1 (shutting down) NGX_TERMINATE_SIGNAL ... ngx_terminate = 1 (exiting) NGX_REOPEN_SIGNAL ... ngx_reopen = 1 (reopening logs) NGX_RECONFIGURE_SIGNAL ... (ignoring) NGX_CHANGEBIN_SIGNAL ... (ignoring) SIGIO ... (ignoring)
  18. ngx_process_get_status() ... 1 SIGCHLDは子プロセスの終了ステータスを取得してクリーンアップ for ( ;; ) { pid

    = waitpid(-1, &status, WNOHANG); ... / * p i d から終了プロセスをe x i t e d へ設定 * / for (i = 0; i < ngx_last_process; i++) { if (ngx_processes[i].pid == pid) { ngx_processes[i].status = status; ngx_processes[i].exited = 1; process = ngx_processes[i].name; break; } } ...
  19. ngx_process_get_status() ... 2 子プロセスの終了ステータスによってログを書込 WIFEXITED(status) 子プロセスが通常終了(exit())した場合にTrueを返す WEXITSTATUS(status) 子プロセスの終了ステータスを返す、WIFEXITEDがTrueの場合だ け呼ぶこと WTERMSIG(status)

    子プロセスの終了の原因となったシグナル番号を返す、 WIFSIGNALEDがTrueの場合だけ呼ぶこと if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "%s %P exited with fatal code %d " "and cannot be respawned", process, pid, WEXITSTATUS(status)); ngx_processes[i].respawn = 0; } ngx_unlock_mutexes(pid); ...
  20. ngx_master_process_cycle() ... 2 その後呼ぶforループ中でシグナルを受信したくないため、無視するシ グナルを設定する。 forループ中では子プロセスを調整するための処理 を実行中のためシグナルを受信してしまうと、まずい事になる。 sigemptyset(&set); sigaddset(&set, SIGCHLD);

    sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } ...
  21. ngx_master_process_cycle() ... 3 ngx_start_worker_processes()呼出 子プロセスとしてworker_processが生成 for ( ;; ) {

    ... sigsuspend(&set); ... worker_processを生成した親はループに突入しsigsuspend()でsleep
  22. ngx_start_worker_processes() 「worker_processes」数のworker_processをさらにfork()する type = NGX_PROCESS_RESPAWNでngx_spawn_process()の呼出 / * n = w

    o r k e r _ p r o c e s s e s * / for (i = 0; i < n; i++) { ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type); / * f o r k ( ) した子プロセスの情報を保存 * / ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; ngx_pass_open_channel(cycle, &ch); }
  23. ngx_spawn_process() 子プロセス通信するためのStream UNIX Domain Socketを作成 if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel)

    == -1) { ... ngx_processes[s].channel[0,1]をnonblockingへ設定 ngx_processes[s].channel[0]をシグナル駆動IOへ設定 ngx_processes[s].channel[0]をF_SETOWN SIGIOを受け取るソケットのプロセスを ngx_pid(NGX_MASTER_PROCESS)に設定 ngx_processes[s].channel[0,1]をFD_CLOEXEC execされても自動closeするようsocketを設定
  24. ngx_process_events() event loopのepoolでクライアントのアクセスがまるまでsleep events = epoll_wait(ep, event_list, (int) nevents, timer);

    backtraceスはこんな感じ #0 ngx_epoll_process_events (cycle=0x7457f0, timer=18446744073709551615, flags=1) at src/event/ #1 0x00000000004326b3 in ngx_process_events_and_timers (cycle=0x7457f0) at src/event/ngx_event. #2 0x000000000044007d in ngx_worker_process_cycle (cycle=0x7457f0, data=0x0) at src/os/unix/ngx #3 0x000000000043c6db in ngx_spawn_process (cycle=0x7457f0, proc=0x43fe5c <ngx_worker_process_c #4 0x000000000043ed3f in ngx_start_worker_processes (cycle=0x7457f0, n=1, type=-3) at src/os/un #5 0x000000000043e34d in ngx_master_process_cycle (cycle=0x7457f0) at src/os/unix/ngx_process_c #6 0x0000000000407e5d in main (argc=1, argv=0x7fffffffd868) at src/core/nginx.c:431
  25. epollのサーバーサイドのそれ 1 1. epollオブジェクトの作成 epfd = epoll_create(MAX_EVENTS) 2. Listenソケットをイベントへ登録 struct

    epoll_event ev; / * L i s t e n s o k e t 設定用* / struct epoll_event events[MAX_EVENTS]; / * e v e n t 発生取得用 * / sock = socket(PF_INET, SOCK_STREAM, 0) bind(sock, (struct sockaddr *) &sin, sizeof sin); listen(sock, BACKLOG); ev.events = EPOLLIN; ev.data.fd = sock; epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev); 3. wait int nfd = epoll_wait(epfd, events, MAX_EVENTS, -1);
  26. epollのサーバーサイドのそれ 2 4. イベントループ開始 for (i = 0; i <

    nfd; i++) { / * L i s t e n S o c k e t が起きた * / if (events[i].data.fd == sock) { / * s o c k はL i s t e n s o c k e t * / / * クライアントのs o k e t ファイルディスクリプタの取得 * / int client = accept(socket, (struct sockaddr *) &client_addr, &client_addr_len); / * クライアントのs o k e t をn o n b l o c k i n g へ * / int flag = fcntl(client, F_GETFL, 0); fcntl(client, F_SETFL, flag | O_NONBLOCK); / * k e r n e l へ読込可能、エッジトリガ形式で登録依頼 * / ev.events = EPOLLIN | EPOLLET; ev.data.fd = client; / * 登録 * / epoll_ctl(epfd, EPOLL_CTL_ADD, client, &ev); } else { / * 読込が可能なf d が既に入ってる * / int client = events[i].data.fd; int n = read(client, buffer, sizeof(buffer)); write(client, buffer, n); } } というような感じで動きます...コードはイメージです アハ
  27. nginxをデバックモードでトレースしてみる configure # ! / b i n / b

    a s h uname -r | grep gentoo GENTOO=$? if [ $GENTOO -eq 0 ] ; then echo '' echo 'Check system is `Gentoo`' echo '' ADDOPT="--with-cc-opt=-I/usr/include --with-ld-opt=-L/usr/lib64" else ADDOPT=" " fi CFLAGS="-g -O0" ./configure --prefix=$HOME/devbin/nginx \ --conf-path=$HOME/devbin/nginx/conf/nginx.conf \ --error-log-path=$HOME/devbin/nginx/var/log/error_log \ --pid-path=$HOME/devbin/nginx/var/run/nginx.pid \ --lock-path=$HOME/devbin/nginx/var/run/lock/nginx.lock \ --http-log-path=$HOME/devbin/nginx/var/log/nginx/access_log \ --http-client-body-temp-path=$HOME/devbin/nginx/var/lib/nginx/tmp/client \ --http-proxy-temp-path=$HOME/devbin/nginx/var/lib/nginx/tmp/proxy \ --http-fastcgi-temp-path=$HOME/devbin/nginx/var/lib/nginx/tmp/fastcgi \
  28. ビルド build # ! / b i n / b

    a s h TMP=$HOME/devbin/nginx/var/lib/nginx/tmp/ LOG=$HOME/devbin/nginx/logs/ make -j6 make install if [ -d $TMP ]; then echo "[ $TMP ] found" else echo "Create directory [ $TMP ]" mkdir -p $TMP fi if [ -d $LOG ]; then echo "[ $LOG ] found" else echo "Create directory [ $LOG ]" mkdir -p $LOG fi
  29. fork()に備えたgdbの設定 ~/.gdbinit set history save on set history size 10000

    set history filename ~/.gdb_history set print pretty on set print static-members off set charset UTF-8 set follow-fork-mode child set detach-on-fork off dir /home/cuomo/Code/nginx/ngx-1.8.0/src dir /home/cuomo/Code/nginx/ngx-1.8.0/src/event dir /home/cuomo/Code/nginx/ngx-1.8.0/src/event/modules ... set follow-fork-mode child fork()したら子プロセスに自動attach set detach-on-fork off fork()後親、子プロセスともに捕まえる
  30. ちょっとやってみる emacsから「M-x gdb」 emacs> gdb -i=mi ~/devbin/nginx/sbin/nginx Type "apropos word"

    to search for commands related to "word"... Reading symbols from /home/cuomo/devbin/nginx/sbin/nginx...done. (gdb) b main Breakpoint 1 at 0x40791f: file src/core/nginx.c, line 203. (gdb) r Starting program: /home/cuomo/devbin/nginx/sbin/nginx [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Breakpoint 1, main (argc=1, argv=0x7fffffffd818) at src/core/nginx.c:203 203 { (gdb) できたか?!