現在運用中のシステムでは rsync で数十台のサーバのログを、
ログ集計サーバに転送するようにしていますが、
送信側でエラーになっていて、転送に失敗することが多いため、
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() で行っているはず。(ここで調査終了)