苹果相关

浏览模式: 标准 | 列表 | 图文

apache 性能调优-2.2版中文手册(转)

文章很长。请慢慢看,有部分因为没有接触过,所以不懂。。。
当成学习资料吧。。

硬件和操作系统

影响web服务器性能的最大的因素是内存。一个web服务器应该从不使用交换机制,因为交换产生的滞后使用户总感觉"不够快",所以用户就可能去按"停止"和"刷新",从而带来更大的负载。你可以,也应该,控制MaxClients的设置,以避免服务器产生太多的子进程而发生交换。这个过程很简单:通过top命令计算出每个Apache进程平均消耗的内存,然后再为其它进程留出足够多的内存。

其他因素就很普通了,装一个足够快的CPU,一个足够快的网卡,几个足够快的硬盘,这里说的"足够快"是指能满足实际应用的需求。

操作系统是很值得关注的又一个因素,已经被证实的很有用的经验有:

  • 选择能够得到的最新最稳定的版本并打好补丁。近年来,许多操作系统厂商都提供了可以显著改善性能的TCP协议栈和线程库。

  • 如果你的操作系统支持sendfile()系统调用,则务必安装带有此功能的版本或补丁(译者注:Linux2.4内核支持sendfile()系统调用,但2.6内核已经不再支持;对Solaris8的早期版本,则需要安装补丁)。在支持sendfile的系统中,Apache2可以更快地发送静态内容而且占用较少的CPU时间。

top

运行时的配置

HostnameLookups 和其他DNS考虑

在Apache1.3以前的版本中,HostnameLookups默认被设为On。它会带来延迟,因为对每一个请求都需要作一次DNS查询。在Apache1.3中,它被默认地设置为Off。如果需要日志文件提供主机名信息以生成分析报告,则可以使用日志后处理程序logresolve,以完成DNS查询,而客户端无须等待。

推荐你最好是在其他机器上,而不是在web服务器上执行后处理和其他日志统计操作,以免影响服务器的性能。

如果你使用了任何"Allowfrom domain"或"Denyfrom domain"指令(也就是domain使用的是主机名而不是IP地址),则代价是要进行两次DNS查询(一次正向和一次反向,以确认没有作假)。所以,为了得到最高的性能,应该避免使用这些指令(不用域名而用IP地址也是可以的)。

注意,可以把这些指令包含在<Location /server-status>段中使之局部化。在这种情况下,只有对这个区域的请求才会发生DNS查询。下例禁止除了.html和.cgi以外的所有DNS查询:

HostnameLookups off
<Files ~ "\.(html|cgi)$">
HostnameLookups on
</Files>

如果在某些CGI中偶尔需要DNS名称,则可以调用gethostbyname来解决。

FollowSymLinks 和 SymLinksIfOwnerMatch

如果网站空间中没有使用Options FollowSymLinks,或使用了Options SymLinksIfOwnerMatch,Apache就必须执行额外的系统调用以验证符号连接。文件名的每一个组成部分都需要一个额外的调用。例如,如果设置了:

DocumentRoot /www/htdocs
<Directory />
Options SymLinksIfOwnerMatch
</Directory>

在请求"/index.html"时,Apache将对"/www"、"/www/htdocs"、"/www/htdocs/index.html"执行lstat()调用。而且lstat()的执行结果不被缓存,因此对每一个请求都要执行一次。如果确实需要验证符号连接的安全性,则可以这样:

DocumentRoot /www/htdocs
<Directory />
Options FollowSymLinks
</Directory>

<Directory /www/htdocs>
Options -FollowSymLinks +SymLinksIfOwnerMatch
</Directory>

这样,至少可以避免对DocumentRoot路径的多余的验证。注意,如果Alias或RewriteRule中含有DocumentRoot以外的路径,那么同样需要增加这样的段。为了得到最佳性能,应当放弃对符号连接的保护,在所有地方都设置FollowSymLinks,并放弃使用SymLinksIfOwnerMatch。

AllowOverride

如果网站空间允许覆盖(通常是用.htaccess文件),则Apache会试图对文件名的每一个组成部分都打开.htaccess,例如:

DocumentRoot /www/htdocs
<Directory />
AllowOverride all
</Directory>

如果请求"/index.html",则Apache会试图打开"/.htaccess"、"/www/.htaccess"、"/www/htdocs/.htaccess"。其解决方法和前面所述的Options FollowSymLinks类似。为了得到最佳性能,应当对文件系统中所有的地方都使用AllowOverride None。

内容协商

实践中,内容协商的好处大于性能的损失,如果你很在意那一点点的性能损失,则可以禁止使用内容协商。但是仍然有个方法可以提高服务器的速度,就是不要使用通配符,如:

DirectoryIndex index

而使用完整的列表,如:

DirectoryIndex index.cgi index.pl index.shtml index.html

其中最常用的应该放在前面。

还有,建立一个明确的type-map文件在性能上优于使用"Options MultiViews",因为所有需要的信息都在一个单独的文件中,而无须搜索目录。请参考内容协商文档以获得更详细的协商方法和创建type-map文件的指导。

内存映射

在Apache2.0需要搜索被发送文件的内容时,比如处理服务器端包含时,如果操作系统支持某种形式的mmap(),则会对此文件执行内存映射。

在某些平台上,内存映射可以提高性能,但是在某些情况下,内存映射会降低性能甚至影响到httpd的稳定性:

  • 在某些操作系统中,如果增加了CPU,mmap还不如read()迅速。比如,在多处理器的Solaris服务器上,关闭了mmap,Apache2.0传送服务端解析文件有时候反而更快。

  • 如果你对作为NFS装载的文件系统中的一个文件进行了内存映射,而另一个NFS客户端的进程删除或者截断了这个文件,那么你的进程在下一次访问已经被映射的文件内容时,会产生一个总线错误。

如果有上述情况发生,则应该使用EnableMMAP off关闭对发送文件的内存映射。注意:此指令可以被针对目录的设置覆盖。

Sendfile

在Apache2.0能够忽略将要被发送的文件的内容的时候(比如发送静态内容),如果操作系统支持sendfile(),则Apache将使用内核提供的sendfile()来发送文件。译者注:Linux2.4内核支持sendfile()系统调用,但2.6内核已经不再支持。

在大多数平台上,使用sendfile可以通过免除分离的读和写操作来提升性能。然而在某些情况下,使用sendfile会危害到httpd的稳定性

  • 一些平台可能会有Apache编译系统检测不到的有缺陷的sendfile支持,特别是将在其他平台上使用交叉编译得到的二进制文件运行于当前对sendfile支持有缺陷的平台时。

  • 对于一个挂载了NFS文件系统的内核,它可能无法可靠的通过自己的cache服务于网络文件。

如果出现以上情况,你应当使用"EnableSendfile off"来禁用sendfile 。注意,这个指令可以被针对目录的设置覆盖。

进程的建立

在Apache1.3以前,MinSpareServers,MaxSpareServers,StartServers的设置对性能都有很大的影响。尤其是为了应对负载而建立足够的子进程时,Apache需要有一个"渐进"的过程。在最初建立StartServers数量的子进程后,为了满足MinSpareServers设置的需要,每一秒钟只能建立一个子进程。所以,对一个需要同时处理100个客户端的服务器,如果StartServers使用默认的设置5,则为了应对负载而建立足够多的子进程需要95秒。在实际应用中,如果不频繁重新启动服务器,这样还可以,但是如果仅仅为了提供10分钟的服务,这样就很糟糕了。

" 一秒钟一个"的规定是为了避免在创建子进程过程中服务器对请求的响应停顿,但是它对服务器性能的影响太大了,必须予以改变。在Apache1.3中,这 个"一秒钟一个"的规定变得宽松了,创建一个进程,等待一秒钟,继续创建第二个,再等待一秒钟,继而创建四个,如此按指数级增加创建的进程数,最多达到每 秒32个,直到满足MinSpareServers设置的值为止。

从多数反映看来,似乎没有必要调整MinSpareServers,MaxSpareServers,StartServers。如果每秒钟创建的进程数超过4个,则会在ErrorLog中产生一条消息,如果产生大量此消息,则可以考虑修改这些设置。可以使用mod_status的输出作为参考。

与进程创建相关的是由MaxRequestsPerChild引发的进程的销毁。其默认值是"0",意味着每个进程所处理的请求数是不受限制的。如果此值设置得很小,比如30,则可能需要大幅增加。在SunOS或者Solaris的早期版本上,其最大值为10000以免内存泄漏。

如果启用了持久链接,子进程将保持忙碌状态以等待被打开连接上的新请求。为了最小化其负面影响,KeepAliveTimeout的默认值被设置为5秒,以谋求网络带宽和服务器资源之间的平衡。在任何情况下此值都不应当大于60秒,参见most of the benefits are lost。

top

编译时的配置

选择一个MPM

Apache 2.x 支持插入式并行处理模块,称为多路处理模块(MPM)。在编译Apache时你必须选择也只能选择一个MPM,这里有几个针对非UNIX系统的MPM:beos,mpm_netware,mpmt_os2,mpm_winnt。对类UNIX系统,有几个不同的MPM可供选择,他们都会影响到httpd的速度和可伸缩性:

  • workerMPM使用多个子进程,每个子进程中又有多个线程。每个线程处理一个请求。该MPM通常对高流量的服务器是一个不错的选择。因为它比preforkMPM需要更少的内存且更具有伸缩性。
  • preforkMPM使用多个子进程,但每个子进程并不包含多线程。每个进程只处理一个链接。在许多系统上它的速度和workerMPM一样快,但是需要更多的内存。这种无线程的设计在某些情况下优于workerMPM:它可以应用于不具备线程安全的第三方模块(比如php3/4/5),且在不支持线程调试的平台上易于调试,而且还具有比workerMPM更高的稳定性。

关于MPM的更多内容,请参考其文档。

模块

既然内存用量是影响性能的重要因素,你就应当尽量去除你不需要的模块。如果你将模块编译成DSO,取消不必要的模块就是一件非常简单的事情:注释掉LoadModule指令中不需要的模块。

如果你已经将模块静态链接进Apache二进制核心,你就必须重新编译Apache并去掉你不想要的模块。

增减模块牵涉到的一个问题是:究竟需要哪些模块、不需要哪些模块?这取决于服务器的具体情况。一般说来,至少要包含下列模块:mod_mime,mod_dir,mod_log_config。你也可以不要mod_log_config,但是一般不推荐这样做。

原子操作

一些模块,比如mod_cache和worker使用APR(Apache可移植运行时)的原子API。这些API提供了能够用于轻量级线程同步的原子操作。

默 认情况下,APR在每个目标OS/CPU上使用其最有效的特性执行这些操作。比如许多现代CPU的指令集中有一个原子的比较交换(compare- and-swap, CAS)操作指令。在一些老式平台上,APR默认使用一种缓慢的、基于互斥执行的原子API以保持对没有CAS指令的老式CPU的兼容。如果你只打算在新 式的CPU上运行Apache,你可以在编译时使用--enable-nonportable-atomics选项:

./buildconf
./configure --with-mpm=worker --enable-nonportable-atomics=yes

--enable-nonportable-atomics选项只和下列平台相关:

  • SPARC上的Solaris
    默认情况下,APR使用基于互斥执行的原子操作。如果你使用--enable-nonportable-atomics选项,APR将使用SPARC v8plus操作码来加快基于硬件的CAS操作。注意,这仅对UltraSPARC CPU有效。
  • x86上的Linux
    默认情况下,APR在Linux上使用基于互斥执行的原子操作。如果你使用--enable-nonportable-atomics选项,APR将使用486操作码来加快基于硬件的CAS操作。注意,这仅对486以上的CPU有效。

mod_status 和 "ExtendedStatus On"

如果Apache在编译时包含了mod_status,而且在运行时设置了"ExtendedStatus On",那么Apache会对每个请求调用两次gettimeofday()(或者根据操作系统的不同,调用times())以及(1.3版之前)几个额外的time()调用,使状态记录带有时间标志。为了得到最佳性能,可以设置"ExtendedStatus off"(这也是默认值)。

多socket情况下的串行accept

警告

这部分内容尚未完全根据Apache2.0中的变化进行更新 。一些信息依然有效,使用中请注意。

这里要说的是 Unix socket API 的一个缺点。假设web服务器使用了多个Listen语句监听多个端口或者多个地址,Apache会使用select()以检测每个socket是否就绪。select()会表明一个socket有零或至少一个连接正等候处理。由于Apache的模型是多子进程的,所有空闲进程会同时检测新的连接。一个很天真的实现方法是这样的(这些例子并不是源代码,只是为了说明问题而已):

for (;;) {
for (;;) {
fd_set accept_fds;

FD_ZERO (&accept_fds);
for (i = first_socket; i <= last_socket; ++i) {
FD_SET (i, &accept_fds);
}
rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
if (rc < 1) continue;
new_connection = -1;
for (i = first_socket; i <= last_socket; ++i) {
if (FD_ISSET (i, &accept_fds)) {
new_connection = accept (i, NULL, NULL);
if (new_connection != -1) break;
}
}
if (new_connection != -1) break;
}
process the new_connection;
}

这种天真的实现方法有一个严重的"饥饿"问题。如果多个子进程同时执行这个循环,则在多个请求之间,进程会被阻塞在select,随即进入循环并试图accept此连接,但是只有一个进程可以成功执行(假设还有一个连接就绪),而其余的则会被阻塞在accept。这样,只有那一个socket可以处理请求,而其他都被锁住了,直到有足够多的请求将它们唤醒。此"饥饿"问题在PR#467中有专门的讲述。目前至少有两种解决方案。

一种方案是使用非阻塞型socket ,不阻塞子进程并允许它们立即继续执行。但是这样会浪费CPU时间。设想一下,select有10个子进程,当一个请求到达的时候,其中9个被唤醒,并试图accept此连接,继而进入select循环,无所事事,并且其间没有一个子进程能够响应出现在其他socket上的请求,直到退出select循环。总之,这个方案效率并不怎么高,除非你有很多的CPU,而且开了很多子进程。

另一种也是Apache所使用的方案是,使内层循环的入口串行化,形如(不同之处以高亮显示):

for (;;) {
accept_mutex_on ();
for (;;) {
fd_set accept_fds;

FD_ZERO (&accept_fds);
for (i = first_socket; i <= last_socket; ++i) {
FD_SET (i, &accept_fds);
}
rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
if (rc < 1) continue;
new_connection = -1;
for (i = first_socket; i <= last_socket; ++i) {
if (FD_ISSET (i, &accept_fds)) {
new_connection = accept (i, NULL, NULL);
if (new_connection != -1) break;
}
}
if (new_connection != -1) break;
}
accept_mutex_off ();
process the new_connection;
}

函数accept_mutex_on和accept_mutex_off实现了一个互斥信号灯,在任何时刻只被为一个子进程所拥有。实现互斥的方法有多种,其定义位于src/conf.h(1.3以前的版本)或src/include/ap_config.h(1.3或以后的版本)中。在一些根本没有锁定机制的体系中,使用多个Listen指令就是不安全的。

AcceptMutex指令被用来改变在运行时使用的互斥方案。

AcceptMutex flock

这种方法调用系统函数flock()来锁定一个加锁文件(其位置取决于LockFile指令)。

AcceptMutex fcntl

这种方法调用系统函数fcntl()来锁定一个加锁文件(其位置取决于LockFile指令)。

AcceptMutex sysvsem

(1.3及更新版本)这种方案使用SysV风格的信号灯以实现互斥。不幸的是,SysV风格的信号灯有一些副作用,其一是,Apache有可能不能在结束以前释放这种信号灯(见ipcs()的man page),另外,这种信号灯API给与网络服务器有相同uid的CGI提供了拒绝服务攻击的机会(所有CGI,除非用了类似suexec或cgiwrapper)。鉴于此,在多数体系中都不用这种方法,除了IRIX(因为前两种方法在IRIX中代价太高)。

AcceptMutex pthread

(1.3 及更新版本)这种方法使用了POSIX互斥,按理应该可以用于所有完整实现了POSIX线程规范的体系中,但是似乎只能用在Solaris2.5及更新版 本中,甚至只能在某种配置下才正常运作。如果遇到这种情况,则应该提防服务器的挂起和失去响应。只提供静态内容的服务器可能不受影响。

AcceptMutex posixsem

(2.0及更新版本)这种方法使用了POSIX信号灯。如果一个运行中的线程占有了互斥segfault ,则信号灯的所有者将不会被恢复,从而导致服务器的挂起和失去响应。

如果你的系统提供了上述方法以外的串行机制,那就可能需要为APR增加代码(或者提交一个补丁给Apache)。

还 有一种曾经考虑过但从未予以实施的方案是使循环部分地串行化,即只允许一定数量的进程进入循环。这种方法仅在多个进程可以同时进行的多处理器的系统中才是 有价值的,而且这样的串行方法并没有占用整个带宽。它也许是将来研究的一个领域,但是由于高度并行的网络服务器并不符合规范,所以其被优先考虑的程度会比 较低。

当然,为了得到最佳性能,最后就根本不使用多个Listen语句。但是上述内容还是值得读一读。

单socket情况下的串行accept

上述对多socket的服务器进行了一流的讲述,那么对单socket的服务器又怎样呢?理论上似乎应该没有什么问题,因为所有进程在连接到来的时候可以由accept()阻塞,而不会产生进程"饥饿"的问题,但是在实际应用中,它掩盖了与上述非阻塞方案几乎相同的问题。按大多数TCP栈的实现方法,在单个连接到来时,内核实际上唤醒了所有阻塞在accept的进程,但只有一个能得到此连接并返回到用户空间,而其余的由于得不到连接而在内核中处于休眠状态。这种休眠状态为代码所掩盖,但的确存在,并产生与多socket中采用非阻塞方案相同的负载尖峰的浪费。

同时,我们发现在许多体系结构中,即使在单socket的情况下,实施串行化的效果也不错,因此在几乎所有的情况下,事实上就都这样处理了。在Linux(2.0.30,双Pentium pro 166/128M RAM)下的测试显示,对单socket,串行化比不串行化每秒钟可以处理的请求少了不到3%,但是,不串行化对每一个请求多了额外的100ms的延迟,此延迟可能是因为长距离的网络线路所致,并且仅发生在LAN中。如果需要改变对单socket的串行化,可以定义SINGLE_LISTEN_UNSERIALIZED_ACCEPT,使单socket的服务器彻底放弃串行化。

延迟的关闭

正如draft-ietf-http-connection-00.txtsection 8所述,HTTP服务器为了可靠地实现此协议,需要单独地在每个方向上关闭通讯(重申一下,一个TCP连接是双向的,两个方向之间是独立的)。在这一点上,其他服务器经常敷衍了事,但从1.2版本开始被Apache正确实现了。

但是增加了此功能以后,由于一些Unix版本的短见,随之也出现了许多问题。TCP规范并没有规定FIN_WAIT_2必须有一个超时,但也没有明确禁止。在没有超时的系统中,Apache1.2经常会陷于FIN_WAIT_2状态中。多数情况下,这个问题可以用供应商提供的TCP/IP补丁予以解决。而如果供应商不提供补丁(指SunOS4 -- 尽管用户们持有允许自己修补代码的许可证),那么只能关闭此功能。

实现的方法有两种,其一是socket选项SO_LINGER,但是似乎命中注定,大多数TCP/IP栈都从未予以正确实现。即使在正确实现的栈中(指Linux2.0.31),此方法也被证明其代价比下一种方法高昂。

Apache对此的实现代码大多位于函数lingering_close(位于http_main.c)中。此函数大致形如:

void lingering_close (int s)
{
char junk_buffer[2048];

/* shutdown the sending side */
shutdown (s, 1);

signal (SIGALRM, lingering_death);
alarm (30);

for (;;) {
select (s for reading, 2 second timeout);
if (error) break;
if (s is ready for reading) {
if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
break;
}
/* just toss away whatever is here */
}
}

close (s);
}

此代码在连接结束时多了一些开销,但这是可靠实现所必须的。由于HTTP/1.1越来越流行,而且所有连接都是稳定的,此开销将由更多的请求共同分担。如果你要玩火去关闭这个功能,可以定义NO_LINGCLOSE,但绝不推荐这样做。尤其是,随着HTTP/1.1中管道化稳定连接的启用,lingering_close已经成为绝对必须。而且,管道化连接速度更快,应该考虑予以支持。

Scoreboard 文件

Apache父进程和子进程通过scoreboard进行通讯。通过共享内存来实现当然是最理想的。在我们曾经实践过或者提供了完整移植的操作系统中,都使用共享内存,其余的则使用磁盘文件。磁盘文件不仅速度慢,而且不可靠(功能也少)。仔细阅读你的体系所对应的src/main/conf.h文件,并查找USE_MMAP_SCOREBOARD或USE_SHMGET_SCOREBOARD。定义其中之一(或者分别类似HAVE_MMAP和HAVE_SHMGET),可以使共享内容的相关代码生效。如果你的系统提供其他类型的共享内容,则需要修改src/main/http_main.c文件,并把必需的挂钩添加到服务器中。(也请发送一个补丁给我们)

注意:在对Linux的Apache1.2移植版本之前,没有使用内存共享,此失误使Apache的早期版本在Linux中表现很差。

DYNAMIC_MODULE_LIMIT

如果你不想使用动态加载模块(或者是因为看见了这段话,或者是为了获得最后一点点性能上的提高),可以在编译服务器时定义-DDYNAMIC_MODULE_LIMIT=0,这样可以节省为支持动态加载模块而分配的内存。

top

附录:踪迹的详细分析

在Solaris8的MPM中,Apache2.0.38使用一个系统调用以收集踪迹:

truss -l -phttpd_child_pid.

-l参数使truss记录每个执行系统调用的LWP(lightweight process--Solaris核心级线程)的ID。

其他系统可能使用不同的系统调用追踪工具,诸如strace,ktrace,par,其输出都是相似的。

下例中,一个客户端向httpd请求了一个10KB的静态文件。对非静态或内容协商请求的记录会有很大不同(有时也很难看明白)。

/67:    accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
/67: accept(3, 0x00200BEC, 0x00200C0C, 1) = 9

下例中,监听线程是 LWP #67 。

注意对accept()串行化支持的匮乏。与这个特殊平台对应的MPM在默认情况下使用非串行的accept ,除了在监听多个端口的时候。
/65:    lwp_park(0x00000000, 0)                         = 0
/67: lwp_unpark(65, 1) = 0

接受了一个连接后,监听线程唤醒一个工作线程以处理此请求。下例中,处理请求的那个工作线程是 LWP #65 。

/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0

为了实现虚拟主机,Apache需要知道接受连接的本地socket地址。在许多情况下,有可能无须执行此调用(比如没有虚拟主机,或者Listen指令中没有使用通配地址),但是目前并没有对此作优化处理。

/65:    brk(0x002170E8)                                 = 0
/65: brk(0x002190E8) = 0

此brk()调用是从堆中分配内存的,它在系统调用记录中并不多见,因为httpd在多数请求处理中使用了自己的内存分配器(apr_pool和apr_bucket_alloc)。下例中,httpd刚刚启动,所以它必须调用malloc()以分配原始内存块用于自己的内存分配器。

/65:    fcntl(9, F_GETFL, 0x00000000)                   = 2
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
/65: setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
/65: fcntl(9, F_SETFL, 0x00000082) = 0

接着,工作线程使客户端连接处于非阻塞模式。setsockopt()和getsockopt()调用是Solaris的libc对socket执行fcntl()所必须的。

/65:    read(9, " G E T   / 1 0 k . h t m".., 8000)     = 97

工作线程从客户端读取请求。

/65:    stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
/65: open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10

这里,httpd被配置为"Options FollowSymLinks"和"AllowOverride None"。所以,无须对每个被请求文件路径中的目录执行lstat(),也不需要检查.htaccess文件,它简单地调用stat()以检查此文件是否存在,以及是一个普通的文件还是一个目录。

/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269

此例中,httpd可以通过单个系统调用sendfilev()发送HTTP响应头和被请求的文件。Sendfile因操作系统会有所不同,有些系统中,在调用sendfile()以前,需要调用write()或writev()以发送响应头。

/65:    write(4, " 1 2 7 . 0 . 0 . 1   -  ".., 78)      = 78

此write()调用在访问日志中对请求作了记录。注意,其中没有对time()的调用的记录。与Apache1.3不同,Apache2.0使用gettimeofday()以查询时间。在有些操作系统中,比如Linux和Solaris,gettimeofday有一个优化的版本,其开销比一个普通的系统调用要小一点。

/65:    shutdown(9, 1, 1)                               = 0
/65: poll(0xFAF7B980, 1, 2000) = 1
/65: read(9, 0xFAF7BC20, 512) = 0
/65: close(9) = 0

工作线程对连接作延迟的关闭。

/65:    close(10)                                       = 0
/65: lwp_park(0x00000000, 0) (sleeping...)

最后,工作线程关闭发送完的文件和块,直到监听进程把它指派给另一个连接。

/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)

其间,监听进程可以在把一个连接指派给一个工作进程后立即接受另一个连接(但是如果所有工作进程都处于忙碌状态,则会受MPM中的一些溢出控制逻辑的制约)。虽然在此例中并不明显,在工作线程刚接受了一个连接之后,下一个accept()会(在高负荷的情况下更会)立即并行产生。

本文允许自由使用、分发、转载,但必须保留译者署名;详见:译者声明。

______________________________________

本手册是在原来尚未完成的“Apache 2.0手册中文版翻译项目”的基础上,根据新的 Apache 2.2 文档进行修订、更新、补充的结果,没有他们之前辛勤劳动积累的成果,单靠一人之力是很难完成的[目前尚有部分未翻译]。所以首先应当感谢那个项目的各位自 愿者:kajaa 、biAji 、fei 、suncjs 、Daniel 、flytosea 、forehead 。

感谢http://www.15913.com/热心的站长 bingzhou 兄提供网络空间[电信]。

感谢LinuxFans.Org上热心的 sejishikong 兄提供网络空间[网通]。

感谢http://www.haloso.com/热心的站长 harvey 兄提供网络空间[铁通,教育网]。

感谢热心的 乔章池 兄制作 chm 版本。

感谢热心的 刘智丹 兄制作 pdf 版本。

linux 查找目录或文件

linux 查找目录或文件

原文地址:http://hi.baidu.com/corylus/blog/item/911f1a0871817ad962d98686.html

查找目录:find /(查找范围) -name '查找关键字' -type d
查找文件:find /(查找范围) -name 查找关键字 -print

如果需要更进一步的了解,可以参看Linux的命令详解。

这里摘抄如下:

·find path -option [ -print ] [ -exec -ok command ] {} \;
#-print 将查找到的文件输出到标准输出
#-exec command {} \; -----将查到的文件执行command操作,{} 和 \;之间有空格
#-ok 和-exec相同,只不过在操作前要询用户

====================================================

-name filename #查找名为filename的文件
-perm #按执行权限来查找
-user username #按文件属主来查找
-group groupname #按组来查找
-mtime -n +n #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime -n +n #按文件访问时间来查
-perm #按执行权限来查找
-user username #按文件属主来查找
-group groupname #按组来查找
-mtime -n +n #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime -n +n #按文件访问时间来查找文件,-n指n天以内,+n指n天以前
-ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nogroup #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer f1 !f2 找文件,-n指n天以内,+n指n天以前
-ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nogroup #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer f1 !f2 #查更改时间比f1新但比f2旧的文件
-type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
-size n[c] #查长度为n块[或n字节]的文件
-depth #使查找在进入子目录前先行查找完本目录
-fstype #查更改时间比f1新但比f2旧的文件
-type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
-size n[c] #查长度为n块[或n字节]的文件
-depth #使查找在进入子目录前先行查找完本目录
-fstype #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
-mount #查文件时不跨越文件系统mount点
-follow #如果遇到符号链接文件,就跟踪链接所指的文件
-cpio #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
-mount #查文件时不跨越文件系统mount点
-follow #如果遇到符号链接文件,就跟踪链接所指的文件
-cpio #对匹配的文件使用cpio命令,将他们备份到磁带设备中
-prune #忽略某个目录

====================================================
$find ~ -name "*.txt" -print #在$HOME中查.txt文件并显示
$find . -name "*.txt" -print
$find . -name "[A-Z]*" -pri26nbsp; #对匹配的文件使用cpio命令,将他们备份到磁带设备中
-prune #忽略某个目录

=====================================================
$find ~ -name "*.txt" -print #在$HOME中查.txt文件并显示
$find . -name "*.txt" -print
$find . -name "[A-Z]*" -print #查以大写字母开头的文件
$find /etc -name "host*" -print #查以host开头的文件
$find . -name "[a-z][a-z][0--9][0--9].txt" -print #查以两个小写字母和两个数字开头的txt文件
$find . -perm 755 -print
$find . -perm -007 -exec ls -l {} \; #查所有用户都可读写执行的文件同-perm 777
$find . -type d -print
$find . ! -type d -print
$find . -type l -print

$find . -size +1000000c -print #查长度大于1Mb的文件
$find . -size 100c -print # 查长度为100c的文件
$find . -size +10 -print #查长度超过期作废10块的文件(1块=512字节)

$cd /
$find etc home apps -depth -print | cpio -ivcdC65536 -o /dev/rmt0
$find /etc -name "passwd*" -exec grep "cnscn" {} \; #看是否存在cnscn用户
$find . -name "yao*" | xargs file
$find . -name "yao*" | xargs echo "" > /tmp/core.log
$find . -name "yao*" | xargs chmod o-w

======================================================

find -name april* 在当前目录下查找以april开始的文件
find -name april* fprint file 在当前目录下查找以april开始的文件,并把结果输出到file中
find -name ap* -o -name may* 查找以ap或may开头的文件
find /mnt -name tom.txt -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型为vfat的文件
find /mnt -name t.txt ! -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型不为vfat的文件
find /tmp -name wa* -type l 在/tmp下查找名为wa开头且类型为符号链接的文件
find /home -mtime -2 在/home下查最近两天内改动过的文件
find /home -atime -1 查1天之内被存取过的文件
find /home -mmin +60 在/home下查60分钟前改动过的文件
find /home -amin +30 查最近30分钟前被存取过的文件
find /home -newer tmp.txt 在/home下查更新时间比tmp.txt近的文件或目录
find /home -anewer tmp.txt 在/home下查存取时间比tmp.txt近的文件或目录
find /home -used -2 列出文件或目录被改动过之后,在2日内被存取过的文件或目录
find /home -user cnscn 列出/home目录内属于用户cnscn的文件或目录
find /home -uid +501 列出/home目录内用户的识别码大于501的文件或目录
find /home -group cnscn 列出/home内组为cnscn的文件或目录
find /home -gid 501 列出/home内组id为501的文件或目录
find /home -nouser 列出/home内不属于本地用户的文件或目录
find /home -nogroup 列出/home内不属于本地组的文件或目录
find /home -name tmp.txt -maxdepth 4 列出/home内的tmp.txt 查时深度最多为3层
find /home -name tmp.txt -mindepth 3 从第2层开始查
find /home -empty 查找大小为0的文件或空目录
find /home -size +512k 查大于512k的文件
find /home -size -512k 查小于512k的文件
find /home -links +2 查硬连接数大于2的文件或目录
find /home -perm 0700 查权限为700的文件或目录
find /tmp -name tmp.txt -exec cat {} \;
find /tmp -name tmp.txt -ok rm {} \;

find / -amin -10 # 查找在系统中最后10分钟访问的文件
find / -atime -2 # 查找在系统中最后48小时访问的文件
find / -empty # 查找在系统中为空的文件或者文件夹
find / -group cat # 查找在系统中属于 groupcat的文件
find / -mmin -5 # 查找在系统中最后5分钟里修改过的文件
find / -mtime -1 #查找在系统中最后24小时里修改过的文件
find / -nouser #查找在系统中属于作废用户的文件
find / -user fred #查找在系统中属于FRED这个用户的文件

查当前目录下的所有普通文件
--------------------------------------------------------------------------------

# find . -type f -exec ls -l {} \;
-rw-r--r-- 1 root root 34928 2003-02-25 ./conf/httpd.conf
-rw-r--r-- 1 root root 12959 2003-02-25 ./conf/magic
-rw-r--r-- 1 root root 180 2003-02-25 ./conf.d/README
查当前目录下的所有普通文件,并在- e x e c选项中使用ls -l命令将它们列出


=================================================
在/ l o g s目录中查找更改时间在5日以前的文件并删除它们:
$ find logs -type f -mtime +5 -exec -ok rm {} \;


=================================================
查询当天修改过的文件
[root@book class]# find ./ -mtime -1 -type f -exec ls -l {} \;


=================================================
查询文件并询问是否要显示
[root@book class]# find ./ -mtime -1 -type f -ok ls -l {} \;
< ls ... ./classDB.inc.php > ? y
-rw-r--r-- 1 cnscn cnscn 13709 1月 12 12:22 ./classDB.inc.php
[root@book class]# find ./ -mtime -1 -type f -ok ls -l {} \;
< ls ... ./classDB.inc.php > ? n
[root@book class]#

=================================================
查询并交给awk去处理
[root@book class]# who | awk '{print $1"\t"$2}'
cnscn pts/0

=================================================
awk---grep---sed

[root@book class]# df -k | awk '{print $1}' | grep -v 'none' | sed s"/\/dev\///g"
文件系统
sda2
sda1
[root@book class]# df -k | awk '{print $1}' | grep -v 'none'
文件系统
/dev/sda2
/dev/sda1


1)在/tmp中查找所有的*.h,并在这些文件中查找“SYSCALL_VECTOR",最后打印出所有包含"SYSCALL_VECTOR"的文件名

A) find /tmp -name "*.h" | xargs -n50 grep SYSCALL_VECTOR
B) grep SYSCALL_VECTOR /tmp/*.h | cut -d':' -f1| uniq > filename
C) find /tmp -name "*.h" -exec grep "SYSCALL_VECTOR" {} \; -print


2)find / -name filename -exec rm -rf {} \;
find / -name filename -ok rm -rf {} \;


3)比如要查找磁盘中大于3M的文件:
find . -size +3000k -exec ls -ld {} ;


4)将find出来的东西拷到另一个地方
find *.c -exec cp '{}' /tmp ';'

如果有特殊文件,可以用cpio,也可以用这样的语法:
find dir -name filename -print | cpio -pdv newdir


6)查找2004-11-30 16:36:37时更改过的文件
# A=`find ./ -name "*php"` | ls -l --full-time $A 2>/dev/null | grep "2004-11-30 16:36:37"

linux命令vmstat介绍

还是来自于淘宝QATEAM,linux命令vmstat介绍

原文如下:
通过STATSPACK收集服务器信息,主要通过收集VMSTAT的信息来展现服务器状况。VMSTAT工具是最常见的UNIX监控工具,可以展现给定时间间隔的服务器的状态值。
一般VMSTAT工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数。如:
[oracle@localhost oracle]$vmstat 2
procs ———–memory———- —swap– —–io—- –system– —-cpu—-
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 195804 3812 40616 1598656 0 0 0 0 1024 66976 0 0 100 0
0 0 195804 3812 40616 1598656 0 0 0 12 1048 66961 0 0 100 0
0 0 195804 3812 40616 1598656 0 0 0 28 1054 67067 0 0 100 0
0 0 195804 3812 40616 1598656 0 0 0 0 1020 66988 0 0 100 0
(注:目前系统几乎空闲,并且不同操作系统VMSTAT输出内容有所不同)
目前说来,对于服务器监控有用处的度量主要有:
r(运行队列)

pi(页导入)

us(用户CPU)

sy(系统CPU)

id(空闲)
(如果r经常大于4 ,且id经常少于40,表示cpu的负荷很重。)

(如果bi,bo 长期不等于0,表示内存不足)

通过VMSTAT识别CPU瓶颈
r(运行队列)展示了正在执行和等待CPU资源的任务个数。当这个值超过了CPU数目,就会出现CPU瓶颈了

获得CPU个数的命令(LINUX环境):
cat /proc/cpuinfo|grep processor|wc -l
当r值超过了CPU个数,就会出现CPU瓶颈,解决办法大体几种:
1. 最简单的就是增加CPU个数
2. 通过调整任务执行时间,如大任务放到系统不繁忙的情况下进行执行,进尔平衡系统任务
3. 调整已有任务的优先级

通过VMSTAT识别CPU满负荷
首先需要声明一点的是,vmstat中CPU的度量是百分比的。当us+sy的值接近100的时候,表示CPU正在接近满负荷工作。但要注意的是,CPU 满负荷工作并不能说明什么,UNIX总是试图要CPU尽可能的繁忙,使得任务的吞吐量最大化。唯一能够确定CPU瓶颈的还是r(运行队列)的值。

通过VMSTAT识别RAM瓶颈
数据库服务器都只有有限的RAM,出现内存争用现象是Oracle的常见问题。
首先察看RAM的数量,命令如下(LINUX环境):
[oracle@oracle-db02 ~]$ free
total used free shared buffers cached
Mem: 2074924 2071112 3812 0 40616 1598656
-/+ buffers/cache: 431840 1643084
Swap: 3068404 195804 2872600

当然可以使用top等其他命令来显示RAM。
当内存的需求大于RAM的数量,服务器启动了虚拟内存机制,通过虚拟内存,可以将RAM段移到SWAP DISK的特殊磁盘段上,这样会 出现虚拟内存的页导出和页导入现象,页导出并不能说明RAM瓶颈,虚拟内存系统经常会对内存段进行页导出,但页导入操作就表明了服务器需要更多的内存了, 页导入需要从SWAP DISK上将内存段复制回RAM,导致服务器速度变慢。

解决的办法有几种:
1. 最简单的,加大RAM
2. 改小SGA,使得对RAM需求减少
3. 减少RAM的需求(如:减少PGA)

Linux查看系统配置常用命令

Linux查看系统配置常用命令

前两天刚刚转载完老王的Linux杂记 ,结果淘宝QA团队也来了一个Linux查看系统配置常用命令,当然,对于这些命令来说我是多多益善。
虽然不一定记得住,但,作为我的参考还是有用的。

系统 # uname -a # 查看内核/操作系统/CPU信息
# head -n 1 /etc/issue # 查看操作系统版本
# cat /proc/cpuinfo # 查看CPU信息
# hostname # 查看计算机名
# lspci -tv # 列出所有PCI设备
# lsusb -tv # 列出所有USB设备
# lsmod # 列出加载的内核模块
# env # 查看环境变量 资源
# free -m # 查看内存使用量和交换区使用量
# df -h # 查看各分区使用情况
# du -sh # 查看指定目录的大小
# grep MemTotal /proc/meminfo # 查看内存总量
# grep MemFree /proc/meminfo # 查看空闲内存量
# uptime # 查看系统运行时间、用户数、负载
# cat /proc/loadavg # 查看系统负载 磁盘和分区
# mount | column -t # 查看挂接的分区状态
# fdisk -l # 查看所有分区
# swapon -s # 查看所有交换分区
# hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备)
# dmesg | grep IDE # 查看启动时IDE设备检测状况 网络
# ifconfig # 查看所有网络接口的属性
# iptables -L # 查看防火墙设置
# route -n # 查看路由表
# netstat -lntp # 查看所有监听端口
# netstat -antp # 查看所有已经建立的连接
# netstat -s # 查看网络统计信息 进程
# ps -ef # 查看所有进程
# top # 实时显示进程状态 用户
# w # 查看活动用户
# id # 查看指定用户信息
# last # 查看用户登录日志
# cut -d: -f1 /etc/passwd # 查看系统所有用户 # cut -d: -f1 /etc/group # 查看系统所有组
# crontab -l # 查看当前用户的计划任务 服务
# chkconfig –list # 列出所有系统服务
# chkconfig –list | grep on # 列出所有启动的系统服务 程序
# rpm -qa # 查看所有安装的软件包

看到最后的rpm,估计淘宝QA们用的是redhat系列的产品线了,什么RH、fedora,centos吧?
估计是,哈哈

老王的Linux杂记

老王的Linux杂记

作者:老王

命令ps aux中的TIME是指什么时间。

经验主义会让我们惯性的认为这个时间是程序运行的时间,实际上如果你通过man ps查看一下手册,就会发现这个时间时间上时程序累计占用的CPU时间。

如何判断64位CPU装了32位的操作系统。

总有一些运维人员这么干,所以不得不防。判断操作系统的位数很简单,只要使用uname -i即可,如果是32位的话,则一般显示i386,如果是64位的话,则一般显示x86_64。问题的重点在于判断CPU的位数,查看CPU的信息很简 单,无非就是cat /proc/cpuinfo,但这里哪些信息能表明位数呢?高人可以通过model name来判断,不过对多数人来说,这样的方法缺少可操作性,更好的方法是查看flags里是否有lm选项,lm选项的意思是Long Mode. (64bit Extensions, AMD’s AMD64 or Intel’s EM64T).,有的话就说明是64位,没有就是32位。

CPU feature flags and their meanings

玩转TOP命令

top命令有很多方便的操作,比如执行top命令后按1键就可以展开CPU列表,按c键就可以查看命令完整路径。还可以通过shift+f或者shift+o把进程排序,更多参数通过按键h或者?查询。

管道符中变量范围的问题

先看一个例子,先用read命令给变量赋值,再分别打印:

echo "a b c" | read x y
echo $x
echo $y

结果你会发现$x, $y都没有设置。

echo "a b c" | (read x y; echo $x; echo $y)

这样就OK了,这是因为管道符后面产生的变量仅在子SHELL中有效,类似的还可以采用这样的方式:

echo "a b c" | while read x y; do
echo $x; echo $y
done

watch监控程序

例如用watch监控mysql:watch -n 1 mysqladmin processlist

更方便的history功能

需要历史操作记录的时候,大家基本上都是采用history | grep ...的操作方式,实际上还有更方便的history功能,在man bash里的reverse-search-history部分能查看到相关介绍,操作方式就是Ctrl+r,然后键入部分命令就会自动查找,找到后直接 回车即可。比如说每次重启动nginx都要不厌其烦的kill -HUP `cat /path/to/nginx.pid`,通过使用reverse-search-history技巧,操作会方便快捷很多。

原文地址为:http://hi.baidu.com/thinkinginlamp/blog/item/39734f4ae8346e2a09f7ef8f.html

但有人对于老王验证CPU是否为64位持不同意见,认为他自己的32位CPU中也有lm,我的是xeon,也有lm,我不知道是否同样为64位CPU。。
一切等某个更牛的人来解释一下吧

字符集研究(VIM版本)

字符集研究(VIM版本)

以前我曾经发贴说,VIM看汉字是乱码,当时我说的是ssh连接乱码,最后是通过更改服务器的language来解决的。
taobaoDBA的陶方则研究的比较深入,他认为:无论字符串采用了什么字符集,在内存和文件中的存储形式都是二进制的。出现乱码的原因是解释并显示二进制数据的字符集和产生二进制数据的字符集不能兼容引起的。
原文如下:

字符集转换是个很麻烦的事情,特别是数据库的字符集转换,涉及到了很多细节。
为了引出更多的讨论,我这先抛个砖头,是关于vim编码的问题,希望大家看完能有所收获。

1、无论字符串采用了什么字符集,在内存和文件中的存储形式都是二进制的。出现乱码的原因是解释并显示二进制数据的字符集和产生二进制数据的字符集不能兼容引起的。
2、从一个字符集转换到另外一个字符集是可以做到的,但是必须要有代码去实现这个转换。有些时候是显式转换,有些时候是隐式转换。vim属于显式转换。

vim有三个编码参数,分别是fileencoding(或fileencodings)、encoding、termencoding,根据字面理解,分别代表了文件的编码格式、缓存的编码格式、终端的编码格式。fileencoding和encoding不一致的时候,缓存中的数据会进行一次字符集转换,然后存入磁盘。当encoding和termencoding不一致的时候,缓存中的数据也会进行一次转换,然后以字节流的形式传给终端。终端(TTY)和伪终端(PTS)都有自己的编码格式。Linux的LANG即是TTY的编码格式,SecureCRT的字符集设置即是PTS的编码格式(无论是ssh和是telnet都一样)。如果不指定fileencoding、encoding、termencoding的编码格式,那么vim将会读取操作系统的字符集设置。实际上,只要正确设置这三个参数和SecureCRT,操作系统的字符集是不会影响远程查看和编辑文件(什么,你用emac?-。 -b)。

--EOF--

还贴了一张图:

Memcahed分布式缓存服务替换Session解决方案

Memcahed分布式缓存服务替换Session解决方案

个人觉得以下内容不是特别成熟,不过可以用来做个参考。关于memcached做此类事情,张宴那里好象有不少资料,权当是参考吧?

全文如下:
http://www.cnblogs.com/xuanfeng/archive/2009/06/04/1494735.html
需求:

有个ASP.NET网站系统,有一级域名,二级域名,三级域名,系统的各个功能模块分布在不同的域名,同一域名的也有可能分布在不同省份的服务器或者同一同一省份的不同的服务器中,同一省份的的服务器可以通过内部局域网访问。在系统中,现在需要所有功能模块共享用户会话信私有数据。

常用的方式是启用Session的数据库持久会模式可以达到上面的需求(没尝试过),现在需要使用Memcached分布式缓存服务来达到保存用户的会话数据,而达到各个功能模块都能够跨省份、跨服务器共享本次会话中的私有数据的目的。

解决方案:

每个省份使用一台服务器来做为Memcached服务器来存储用话的会话中的数据,当然也可以多台服务器,但必须确保每个省份的做Memcached服务器数量必须一致,这样才能够保证Memcached客户端操作的是同一份数据,保证数据的一致性。

会话数据的添加、删除、修改:

Memcached客 户端,添加、删除和、修改会话信息数据时,不仅要添加、删除、修改本省的Memcached服务器数据,而且同时要对其它省份的Memcahed服务器做 同样的操作,这样用户访问其它省份的服务器的功能模块进也能读取到相同的会话数据。Memcached客户端服务器的列表使用局域网的内网 IP(如:192.168.1.179)操作本省的Memcahed服务器,使用公网的IP((如:202.183.62.210))操作其它省份的 Memcahe服务器。

会话数据的读取

系统所有模块读取会话数据的Memcached客户端服务器列表都设为本省Memcached服务器地址的内网IP来向Memcahed服务器中读取会话数据。

b07a66c7941c1c5ffef3bc8ca4854ce7

如 上图所示,A省有四台服务器,B省也有四台服务器,两个三份都有三台Web服务器、一台Memcached服务器,且A省四台服务器同在一个局域网内的可 能通过内网IP相互访问,B省也一样。假如:A省的A1,B1,C1这三台Web服务器其中的一台要添加或修改、或删除会话数据,它首先调服 Memcached客户端使服D1服务器的内网IP向D1服务器中添加或修改、或删除会话数据,操作完成后,还用调用Memcache客户端使服D2服务 器的公网IP向D2服务器做同样的操作,这样才算完整的操作过程,也可以当做一个事务来处理。假如:A省的A1,B1,C1这三台Web服务器其中一台服 务器想要读取会话的数据,只需要调用Memcached客户端使服D1服务器的内网IP读取数据即可,如果发现该数据不存在,即做向Memcached服 务器添加数据的相关业务处理。B省处理逻辑同A省。

同一会话的确认:

使用Cookie来保持客户与服务端的联系。 每一次会话开始就生成一个GUID作为SessionID,保存在客户端的Cookie中,作用域是顶级域名,这样二级、三级域名就可以共享到这个Cookie,系统中就使用这个SessionID来确认它是否是同一个会话。

会话数据的唯一ID

会话数据存储在Memcached服务器上的唯一键Key也就是会话数据数据的唯一ID定义为:SessionID_Name, SessionID就是保存在客户端Cookie中的SessionID, Name就是会话数据的名称,同一次会话中各个会话数据的Name必须是唯一的,否则新的会话数据将覆盖旧的会话数据。

会话的失效时间:

会话的失效通过控制Cookie的有效时间来实现,会话的时间设为SessionID或Cookie中的有效时间,且每一次访问SessionID时都要重新设置一下Cookie的有效时间,这样就达到的会话的有效时间就是两次间访问Cookie中SessionID值的的最长时间,如果两次访问的间隔时间超过用效时间,那么保存在SessionID的Cookie将会失效,并生成新的SessionID存放在Cookie中, SessionID改变啦,会话就结束啦。

Memcached服务器中会话数据的失效

每 一次向Memcache服务器中添加会话数据时,都把有效时间设为一天也就是24小时,让Memcached服务使用它内部的机制去清除,不必在程序中特 别做会话数据的删除操作。数据在Memcache服务器中有有效时间只是逻辑上的,就算是过了24 小时,如果分配给Memcached服务的内存还够用的话,数据还是保存在内存当中的,只是Memcache客户端读取不到而已。只有到了分配给 Memcached服务的内存不够用时,它才会清理没用或者比较旧的数据,也就是懒性清除。


关于张宴博客上一些memcached的资料,建议查看:http://blog.s135.com/category/13/
虽然对于存储session之类的没有介绍,但他介绍的分布式存储,如果运用起来就是实现上面的效果哦。。


网站多服务器负载均衡引起的开发问题及解决方案

网站多服务器负载均衡引起的开发问题及解决方案

本文来自kakapo的博客,kakapo,如果没有记错,应该是pchome的人吧。。。负载均衡我暂时还没有用到,毕竟我就一台服务器也没必要在服务器上装上17、8个虚拟机来跑这些负载均衡吧。

原文地址:http://www.kakapo.cn/blog/read.php?153

内容:

先罗列一下问题:
1、session会话数据共享问题
2、缓存数据文件共享问题
3、用户数据共享问题
4、上传数据存储问题
5、Log日志文件共享同步问题
6、配置文件管理问题
7、web服务器时间获取不一致问题

这些问题都是从项目经验中总结出来的,接下来在一一讨论解决的办法。
1、session会话数据共享问题

推荐使用memcached分布式缓存系统来解决,可以参考我之前写一篇文章《Memcached的介绍和应用》。

2、缓存数据文件共享问题解决方案

所谓缓存数据,一般指网站前台程序本身产生的数据,比如,数据库查询类产生的数据对象缓存,缓存类产生的本地缓存数据,远程抓取类产生的本地临时缓存文件等等。
有 些数据看似不需要共享,就像那些在每台机器上都能自动产生的数据。但是如果刚好碰到某个时刻数据更新了,缓存时间又不同步,就会造成负载均衡上的每台机器 缓存数据不相同。这也会给用户的访问带来一定的困扰。当然针对的解决办法就是想办法让缓存同时过期,保证缓存的内容相同,这就不需要考虑共享的问 题。
远程抓取经常会涉及到模拟登陆,在本地一般会保存模拟登陆用户的cookie数据,这个就一定得想办法解决共享。否则用户在负载 A机器上执行了模拟登陆程序,在本地产生了cookie文件,但是下次请求被分配到负载B机器上执行抓取程序,却发现需要用上的cookie文件在本地不 存在,马上程序就会被远程服务器拒绝访问。这种cookie的临时文件很多而且改动频繁。目前我们采用了NFS的方案,mount指定的一个缓存目录,让 负载的每台机器都能像本地目录一样访问,暂且还行的通。也可以将这个单独的应用放到一台机器,来避免这个问题。

3、用户数据共享问题
所谓用户数据,范围比较广。这里一般指在用户的独立目录空间保存的用户独用的数据。比例用户自己的相片,头像等等。
之 前我们采用的方法是搞一台存储服务器,通过一定的规则为用户创建目录空间,然后存储服务器通过NFS共享到所有负载均衡的web服务器。这种做法在几百万 用户的网站还行得通。主要问题在于NFS在高并发访问下会出现一些不稳定,会丢失文件访问句柄。另外还有mount管理带来的麻烦,以及数据安全等风险。 顺便提起用户目录空间的创建规则,分散均匀是一个最大的原则,采用哈希值切分方式比较合适。 采用用户名或者时间因子虽然方便了一些记忆和查询,但是容易碰到局部目录达到系统最大限制的问题。
所以,推荐使用分布式文件系统解决方案。国人happy_fish100开发了一个高效的开源的分布式文件系统FastDFS,比较完善,使用简单,功能强大。特别适合解决我当前遇到的问题。自称比国外的Mogilefs还强大。让我更心动的是提供了PHP client API,采用socket访问。在应用中调用也非常方便。

4、上传数据存储问题

这 个问题再单独拿出来谈是有根据的。在前台用户上传的自己相关的数据可以归属前面一个问题的范畴。前台也有一些用户上传的数据跟用户无关,还有网站后台也会 有很多上传的数据。之前的做法可以是通过FTP服务将这些数据上传到存储静态文件的服务器上,也有通过NFS方式共享静态文件服务器的指定目录到web服 务器。现在除了FTP方案之外,我也推荐尝试使用FastDFS来管理静态文件服务器的数据,但是要修改一下设计,可以在FastDFS的storge服 务器上直接架设http服务器,让静态文件能直接通过URL访问。

5、Log日志文件共享同步问题

所谓的Log日志也是web服务器程序自动产生的,比如错误日志,访问日志等。在一般情况一下也可以考虑让其不共享,无非是分析日志的时候每台机器都要做一遍。

6、配置文件管理问题&web服务器时间获取不一致问题

配置文件管理问题严格来讲不属于开发遇到的问题,而是运维人员烦恼的事情。当然,通过合理的将配置文件进行归类和存储,还是可以减少运维人员的困难的。web服务器的配置文件的最好也不用共享,文件的同步可以让系统管理员通过系统命令去自动完成。
web服务器时间不一致虽然可以通过系统定时跟全球的时间服务器同步,但是在开发过程中程序还是要尽量避免使用本地时间函数,特别是跟数据库有关系的数据,可以通过采用数据库的时间函数来解决。

Ubuntu创始人:Linux的未来并不在于对Windows的兼容性

Ubuntu创始人:Linux的未来并不在于对Windows的兼容性

Ubuntu的创始人Mark Shuttleworth最近对桌面Linux以及其未来发表了一些比较重要的言论,他说Linux的未来不在对Windows的兼容性上面。在其发言中,他特意提到了Wine这个程序——这是一个可以在Linux上提供对Windows程序的支持的程序,如果要想从Windows迁移到Linux,而你有些程序无法割舍,使用它再好不过,而且很多时候你会发现你想要的程序在Windows下才有。

Mark Shuttleworth称,类似Wine的兼容Windows的程序或者工程其重要程序不言而喻,但Linux的未来不在于对Windows的兼容性。 Linux与Windows有着本质的区别。linux作为自由软件,这个平台是否成功要依靠自身的发展,如果使用linux只是一种运行Windows 程序的媒介,那么linux永远不会有成功的那一天。
虽然他仅仅针对Ubuntu发表以上言论,但是很显然这番言论对任何linux版本都是合适的。正如他所说,在linux模拟运行 Windows程序并不能很好的抢占这个市场。linux开发者应该把重点放在核心应用上,让linux也可实现所有Windows才可实现的功能。

原文:alect
来自:http://www.cnbeta.com/articles/83517.htm
[知道分子]Linux 省电十招

[知道分子]Linux 省电十招

我的笔记本装上ubuntu后,只能使用4小时不到,但使用xp可以将近7小时。所以看到这个标题的时候就激动的记录了下来。。

原文:http://hutuworm.blogspot.com/2009/04/linux.html


1. Linux Kernel 2.6.21 开始支持 Tickless(此前的内核默认设置为 1000Hz timer tick),于是系统空闲时不再无故骚扰 CPU,可以节省大量能耗。Fedora 7+ 以及目前的 Ubuntu Linux 发行版都含有 Tickless 特性,而 RHEL 则要到版本 6 才会随新版本内核正式支持该特性(预计 2010年上市)。检查你的 Linux 系统是否支持 Tickless: watch --interval=1 cat /proc/interrupts ,若 timer 中断值并非以 1000 为步进单位增加,则说明该内核支持 Tickless。

2. 编译内核(make menuconfig):

  • 启用 Tickless: Processor type and features -> [*] Tickless System (Dynamic Ticks)
  • 启 用 CONFIG_USB_SUSPEND: Device Drivers -> USB support -> [*] USB selective suspend/resume and wakeup (自动禁用 UHCI USB,可以节省约 1 watt)

3. PowerTOP 可以找出计算机闲置时哪些进程耗电最多。(Kernel Hacking -> [*] Collect kernel timers statistics) 详见: http://www.lesswatts.org/projects/powertop/

4. 启用 power aware CPU scheduler(Scheduler Power Saving Mode): echo 1 > /sys/devices/system/cpu/sched_mc_power_savings

5. RHEL 5.3 支持 Intel Core i7 (Nehalem) 的电源管理功能。

6. 启用 irqbalance 服务,既可以提升性能,又可以降低能耗。irqbalance 用于优化中断分配,它会自动收集系统数据以分析使用模式,并依据系统负载状况将工作状态置于 Performance mode 或 Power-save mode。处于 Performance mode 时,irqbalance 会将中断尽可能均匀地分发给各个 CPU core,以充分利用 CPU 多核,提升性能。处于 Power-save mode 时,irqbalance 会将中断集中分配给第一个 CPU,以保证其它空闲 CPU 的睡眠时间,降低能耗。(详见:http://www.irqbalance.org/documentation.php )

7. 禁用 pcscd,该进程会阻碍 USB 子系统进入 Power-save mode。

8. 将 VM dirty writeback time 延长至 15 秒: echo 1500 > /proc/sys/vm/dirty_writeback_centisecs

9. 启用 noatime 文件系统选项: mount -o remount,noatime / (noatime 禁止更新 atime,可以节省大量 I/O,但为了避免 atime 相关应用程序出现问题,建议启用 relatime 代之: mount -o remount,relatime / ,relatime 自 Kernel 2.6.29 起为默认设置。)

10. 禁止 hal 轮询你的 cdrom: hal-disable-polling --device /dev/cdrom

* 关于 Linux 节能的更多信息,请看: http://www.lesswatts.org