最大打开文件 – 为什么没有错误?

我怀疑我们的一个服务器应用程序已达到其最大打开文件限制。

该应用程序正在用户空间中运行自己的帐户。 init脚本启动大量的进程,进而启动一些subprocess和大量的线程。

根据我在/etc/security/limits.conf中设置的书:

USERNAME - nofile 2048 

我怀疑应用程序已经达到了极限 – 通过查看临时文件目录,我在那里find了超过2000个文件。

提高到4096的限制,并重新启动应用程序后,我发现超过2100个文件。

现在的问题是:如果应用程序达到了限制2048 – 为什么没有logging在/ var / log / messages?

syslog-ng是当前正在使用的syslog-daemon。

/etc/syslog-ng/syslog-ng.conf

 options { long_hostnames(off); sync(0); perm(0640); stats(3600); }; source src { internal(); unix-dgram("/dev/log"); unix-dgram("/var/lib/ntp/dev/log"); }; filter f_iptables { facility(kern) and match("IN=") and match("OUT="); }; filter f_console { level(warn) and facility(kern) and not filter(f_iptables) or level(err) and not facility(authpriv); }; filter f_newsnotice { level(notice) and facility(news); }; filter f_newscrit { level(crit) and facility(news); }; filter f_newserr { level(err) and facility(news); }; filter f_news { facility(news); }; filter f_mailinfo { level(info) and facility(mail); }; filter f_mailwarn { level(warn) and facility(mail); }; filter f_mailerr { level(err, crit) and facility(mail); }; filter f_mail { facility(mail); }; filter f_cron { facility(cron); }; filter f_local { facility(local0, local1, local2, local3, local4, local5, local6, local7); }; filter f_messages { not facility(news, mail, cron, authpriv, auth) and not filter(f_iptables); }; filter f_warn { level(warn, err, crit) and not filter(f_iptables); }; filter f_alert { level(alert); }; filter f_auth { facility(authpriv, auth); }; destination console { pipe("/dev/tty10" group(tty) perm(0620)); }; log { source(src); filter(f_console); destination(console); }; destination xconsole { pipe("/dev/xconsole" group(tty) perm(0400)); }; log { source(src); filter(f_console); destination(xconsole); }; destination auth { file("/var/log/auth"); }; log { source(src); filter(f_auth); destination(auth); }; destination newscrit { file("/var/log/news/news.crit"); }; log { source(src); filter(f_newscrit); destination(newscrit); }; destination newserr { file("/var/log/news/news.err"); }; log { source(src); filter(f_newserr); destination(newserr); }; destination newsnotice { file("/var/log/news/news.notice"); }; log { source(src); filter(f_newsnotice); destination(newserr); }; destination mailinfo { file("/var/log/mail.info"); }; log { source(src); filter(f_mailinfo); destination(mailinfo); }; destination mailwarn { file("/var/log/mail.warn"); }; log { source(src); filter(f_mailwarn); destination(mailwarn); }; destination mailerr { file("/var/log/mail.err" fsync(yes)); }; log { source(src); filter(f_mailerr); destination(mailerr); }; destination mail { file("/var/log/mail"); }; log { source(src); filter(f_mail); destination(mail); }; destination cron { file("/var/log/cron"); }; log { source(src); filter(f_cron); destination(cron); }; destination localmessages { file("/var/log/localmessages"); }; log { source(src); filter(f_local); destination(localmessages); }; destination messages { file("/var/log/messages"); }; log { source(src); filter(f_messages); destination(messages); }; destination firewall { file("/var/log/firewall"); }; log { source(src); filter(f_iptables); destination(firewall); }; destination warn { file("/var/log/warn" fsync(yes)); }; log { source(src); filter(f_warn); destination(warn); }; 

你需要真正知道你是否用完了文件。

运行你的过程。 然后检查猫/proc/<pid>/limits ,看看它的限制说什么。

然后,通过运行ls -1 /proc/<pid>/fd | wc -l来获得文件描述符的计数 ls -1 /proc/<pid>/fd | wc -l

请注意,每个进程都有其自己的限制(例如父级的子级)。 然而,线程清楚地共享调用进程的文件描述符表,因此在线程和调用进程之间共享文件限制。

虽然你不能在bash中创build线程,但是这个程序可以用来演示效果。

 /* Compiled with gcc -o upcount upcount.c -pthread */ #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include <unistd.h> #include <err.h> #include <sysexits.h> #include <errno.h> #include <pthread.h> #include <sys/types.h> #include <sys/time.h> #include <sys/resource.h> #define THREADS 3 #define NUMCHILD 3 #define DEF_OPEN_LIMIT 256 /* The gimmick in this program is to constantly dup an FD * until we run out of file handles */ void dup_fds( int basefd) { int i; int *fds = calloc(1048576, sizeof(int)); char etxt[256]; int me = pthread_self(); for (i=0; i < 1048576; i++) fds[i] = -1; for (i=0; i < 1048576; i++) { fds[i] = dup(basefd); if (fds[i] < 0) { strerror_r(errno, etxt, 256); fprintf(stderr, "Cannot dup file: %s\n", etxt); return; } usleep(100000 + (rand_r(&me) % 400000)); } } void * run_thread( void *data) { /* This procedure should not be independent */ struct rlimit ofiles; int i; i = pthread_self(); /* Obtain the open files limit */ if (getrlimit(RLIMIT_NOFILE, &ofiles) < 0) { perror("cannot get limits"); pthread_exit(NULL); } /* Assign a random value to current limit */ i = getpid(); ofiles.rlim_cur = 128 + (rand_r(&i) % 896); /* Set the limit */ if (setrlimit(RLIMIT_NOFILE, &ofiles) < 0) { perror("cannot set limits"); pthread_exit(NULL); } dup_fds(1); } void run_child( void) { int i; struct rlimit ofiles; pthread_t threads[THREADS]; /* Obtain the open files limit */ if (getrlimit(RLIMIT_NOFILE, &ofiles) < 0) err(EX_OSERR, "Cannot obtain limits"); /* Assign a random value to current limit */ i = getpid(); ofiles.rlim_cur = 128 + (rand_r(&i) % 896); /* Set the limit */ if (setrlimit(RLIMIT_NOFILE, &ofiles) < 0) err(EX_OSERR, "Canot set limits"); /* Create threads */ for (i=0; i < THREADS; i++) { if (pthread_create(&threads[i], NULL, run_thread, NULL)) err(EX_OSERR, "Cannot spawn thread"); } dup_fds(1); for (i=0; i < THREADS; i++) if (pthread_join(threads[i], NULL)) err(EX_OSERR, "Cannot join thread"); exit(0); } int main() { int i, s; /* Spawn children */ for (i=0; i < NUMCHILD; i++) { if (fork()) { continue; } run_child(); } for (i=0; i < NUMCHILD; i++) { if (wait(&s) < 0) warn("wait failed"); } return 0; } 

这个程序产生3个线程的3个孩子。

 $ ./upfilecnt & pstree -p $! upfilecnt(12662)─┬─upfilecnt(12663)─┬─{upfilecnt}(12666) │ ├─{upfilecnt}(12667) │ └─{upfilecnt}(12668) ├─upfilecnt(12664)─┬─{upfilecnt}(12669) │ ├─{upfilecnt}(12670) │ └─{upfilecnt}(12671) └─upfilecnt(12665)─┬─{upfilecnt}(12672) ├─{upfilecnt}(12673) └─{upfilecnt}(12674) 

每个孩子和线程每半秒钟不断创build一个新的文件描述符,加上一些随机的等待。

你可以从subprocess看到,每个subprocess都有一个独立的文件描述符表。

 $ for i in 1266{3,4,5}; do ls -1 /proc/$i/fd | wc -l; done 637 646 636 

然而,这些儿童的线程都与儿童进程共享相同的计数。

 # .. another invokation $ for i in 134{11,14,15,10,12,13,16,17,18}; do ls -1 /proc/$i/fd | wc -l; done 438 438 438 430 430 430 433 433 433 

还要注意,孩子的pid可以有独立的限制。 这个程序还设置了每个孩子的调用的随机限制。

 $ grep -h "Max open" /proc/1420{3,4,5}/limits Max open files 504 4096 files Max open files 502 4096 files Max open files 372 4096 files 

而且为了增加多余的乐趣,它还为每个线程设置了随机打开的文件限制。 但是这并不是一成不变的,在进程的所有线程和subprocess之间共享。

 grep -h "Max open" /proc/1420{3,4,5}/task/*/limits Max open files 1011 4096 files Max open files 1011 4096 files Max open files 1011 4096 files Max open files 1011 4096 files Max open files 1009 4096 files Max open files 1009 4096 files Max open files 1009 4096 files Max open files 1009 4096 files Max open files 750 4096 files Max open files 750 4096 files Max open files 750 4096 files Max open files 750 4096 files 

你缺乏这个源定义:

  # messages from the kernel file("/proc/kmsg" program_override("kernel: ")); 

那你就好了!