現在運用中のシステムでは rsync で数十台のサーバのログを、
ログ集計サーバに転送するようにしていますが、
送信側でエラーになっていて、転送に失敗することが多いため、
rsync のソース(rsync-3.1.3)を調べてみました。
結果的には、/etc/rsyncd.conf に "listen backlog = 転送元サーバ台数" を
設定すればよさそう。
ちなみに、listen backlog はデフォルトでは 5 になっています。
以下、クライアントからの要求をどのように処理しているかを、ソースを追って見てみます。
start_accept_loop() で accept しているので、次に start_accept_loop() を見てみます。
★1 で listen() していて、キューの最大長は第2引数の lp_listen_backlog() が指定されます。。
これがデフォルトでは 5 になっています(loadparm.c)。
★2 accept 後に fork しています。
select() で全クライアントとの読み書き処理を行っていたら...と思っていましたが、
fork() していたので、ひと安心。
★3 fn は start_accept_daemon() の第2引数の start_daemon()。
転送処理は start_daemon() で行っているはず。(ここで調査終了)
ログ集計サーバに転送するようにしていますが、
送信側でエラーになっていて、転送に失敗することが多いため、
rsync のソース(rsync-3.1.3)を調べてみました。
結果的には、/etc/rsyncd.conf に "listen backlog = 転送元サーバ台数" を
設定すればよさそう。
ちなみに、listen backlog はデフォルトでは 5 になっています。
■loadparm.c /* ==== global_vars ==== */ { ... /* listen_backlog; */ 5, ... },
以下、クライアントからの要求をどのように処理しているかを、ソースを追って見てみます。
■clientserver.c int daemon_main(void) { ... start_accept_loop(rsync_port, start_daemon); return -1; }
start_accept_loop() で accept しているので、次に start_accept_loop() を見てみます。
■socket.c void start_accept_loop(int port, int (*fn)(int, int)) { ... /* open an incoming socket */ sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); if (sp == NULL) exit_cleanup(RERR_SOCKETIO); /* ready to listen */ FD_ZERO(&deffds); for (i = 0, maxfd = -1; sp[i] >= 0; i++) { ★1 if (listen(sp[i], lp_listen_backlog()) < 0) { ... while (1) { ... if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) continue; for (i = 0, fd = -1; sp[i] >= 0; i++) { if (FD_ISSET(sp[i], &fds)) { fd = accept(sp[i], (struct sockaddr *)&addr, &addrlen); break; } } ... ★2 if ((pid = fork()) == 0) { int ret; for (i = 0; sp[i] >= 0; i++) close(sp[i]); /* Re-open log file in child before possibly giving * up privileges (see logfile_close() above). */ logfile_reopen(); ★3 ret = fn(fd, fd); close_all(); _exit(ret); } else if (pid < 0) { rsyserr(FERROR, errno, "could not create child server process"); close(fd); /* This might have happened because we're * overloaded. Sleep briefly before trying to * accept again. */ sleep(2); } else { /* Parent doesn't need this fd anymore. */ close(fd); } ... }
★1 で listen() していて、キューの最大長は第2引数の lp_listen_backlog() が指定されます。。
これがデフォルトでは 5 になっています(loadparm.c)。
★2 accept 後に fork しています。
select() で全クライアントとの読み書き処理を行っていたら...と思っていましたが、
fork() していたので、ひと安心。
★3 fn は start_accept_daemon() の第2引数の start_daemon()。
転送処理は start_daemon() で行っているはず。(ここで調査終了)