Я подозреваю, что одно из наших серверных приложений исчерпало максимальное количество открытых файлов.
Приложение работает в пользовательском пространстве под собственной учетной записью. Сценарий инициализации запускает большое количество процессов, которые, в свою очередь, запускают ряд подпроцессов и большое количество потоков.
Согласно книге, которую я установил /etc/security/limits.conf:
USERNAME - nofile 2048
Я подозреваю, что приложение исчерпало лимит - просмотрев каталог временных файлов, я обнаружил там более 2000 файлов.
После увеличения лимита до 4096 и перезапуска приложения я обнаружил там более 2100 файлов.
Теперь вопрос: если приложение достигло лимита 2048 - почему это не было зарегистрировано в / var / log / messages?
syslog-ng - это текущий используемый демон syslog.
/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
.
Обратите внимание, что у каждого процесса есть свои ограничения (например, дочерние элементы родительского процесса). Однако потоки явно разделяют таблицу дескрипторов файлов вызывающего процесса и, как таковые, делать разделяйте ограничение файла между потоками и вызывающим процессом.
Хотя вы не можете создавать потоки в bash, эту программу можно использовать для демонстрации эффекта.
/* 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)
Каждый дочерний процесс и поток непрерывно создают новый дескриптор файла каждые полсекунды плюс некоторое случайное ожидание.
Вы можете видеть, что из дочерних процессов каждый дочерний процесс имеет независимую таблицу дескрипторов файлов.
$ 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
Также обратите внимание, что дочерние идентификаторы могут иметь независимые ограничения. Эта программа также устанавливает случайный лимит на вызов каждого дочернего элемента.
$ 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
А для дополнительного удовольствия он также устанавливает лимит случайных открытых файлов на поток. Но это не прилипает и используется всеми потоками процесса и дочерним процессом.
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: "));
Тогда все в порядке!