我想减少 VPS 上打开的文件数量。使用 lsof 时,我注意到 Apache 始终为服务器上托管的每个域保持 access.log 和 error.log 处于打开状态。
有没有什么办法可以改变这种行为?
答案1
打开许多文件通常不是问题。有一个系统限制,您可以使用命令检查sysctl fs.file-max
- 在我的 CentOS 6 系统上,4GB RAM 是 382299,应该足够了,而在我启动的 256MB VM 上,它是 23539,这可能有点太少了。但您可以轻松增加此限制,例如通过添加/etc/sysctl.conf
:
fs.file-max = 500000
然后运行sysctl -p
或重新启动。
您可以编写一个程序,每次从 stdin 接收到数据时,打开、写入、关闭日志文件,并像这样使用它:
CustomLog "||open-write-close /var/log/httpd/access_log" common
但效率不高。而且也不容易,因为它需要使用异步 IO。
我用 C 语言编写了一个程序来实现这个功能:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
int outfd;
int main(int argn, char* argv[])
{
if (argn != 2) {
fprintf(stderr, "Usage %s [output_file]\n", argv[0]);
return 1;
}
{
long stdinflags = fcntl(0,F_GETFL);
if ( stdinflags == -1 ) {
perror("fcntl: Can't read stdin status");
return 2;
}
if ( fcntl(0,F_SETFL,stdinflags|O_NONBLOCK) == -1 ) {
perror("fcntl: Can't set stdin to non-blocking mode");
return 2;
}
}
do {
#define BUFSIZE PIPE_BUF
char buf[BUFSIZE];
ssize_t bytesread = read(0, buf, BUFSIZE);
{
fd_set select_fdset;
FD_ZERO(&select_fdset);
FD_SET(0, &select_fdset);
if ( select(1, &select_fdset, NULL, NULL, NULL) == -1 ) {
if ( errno != EINTR ) {
perror("select");
return 2;
}
};
}
if ( bytesread==-1 ) {
perror("Can't read from stdin");
return 2;
}
if ( bytesread == 0 ) break;
outfd = open(argv[1],O_WRONLY|O_APPEND|O_CREAT);
if ( outfd < 0 ) {
fprintf(stderr, "Can't open file \"%s\": %s\n", argv[1], strerror(errno));
return 2;
}
do {
if ( write(outfd, buf, bytesread) == -1 ) {
fprintf(stderr, "Can't write to file \"%s\": %s\n", argv[1], strerror(errno));
return 2;
};
bytesread = read(0, buf, BUFSIZE);
if ( bytesread==-1 ) {
if ( errno==EAGAIN ) break;
perror("Can't read from stdin");
}
} while ( bytesread>0 );
if ( close(outfd) != 0) {
fprintf(stderr, "Can't close file \"%s\": %s\n", argv[1], strerror(errno));
return 2;
}
} while ( 1 );
return 0;
}
答案2
如果你有大量的虚拟主机,并且有单独的访问日志文件,我建议将所有内容记录到一个文件中(是的,消除每个虚拟主机中的 CustomLog),然后使用分割日志文件将它们分开。您可以使用日志解析脚本,来解析 DNS 名称。
到分割日志文件工作,您需要将 CustomLog 中的第一列设置为 ServerName。