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

nginxの初期化について

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for karky7 karky7
November 28, 2015

 nginxの初期化について

Avatar for karky7

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) できたか?!