Category Archives: Hardware and OS

Linux Web服务器性能调优 – Apache的工作模式及配置

一般来说Apache有两种常用工作模式prefork和worker;

要查看当前服务器的工作模式,请用命令 apache2 -l

$ apache2 -l
Compiled in modules:
core.c
mod_log_config.c
mod_logio.c
prefork.c
http_core.c
mod_so.c

可以看到prefork.c 说明现在在用prefork模式。

关于两种模式的区别,根据官方文档:

  • The workerMPM uses multiple child processes with many threads each. Each thread handles one connection at a time. Worker generally is a good choice for high-traffic servers because it has a smaller memory footprint than the prefork MPM.
  • The prefork MPM uses multiple child processes with one thread each. Each process handles one connection at a time. On many systems, prefork is comparable in speed to worker, but it uses more memory. Prefork’s threadless design has advantages over worker in some situations: it can be used with non-thread-safe third-party modules, and it is easier to debug on platforms with poor thread debugging support.

可以看到,这些主要和进程和线程有关,对于内存有限逻辑简单,不太考虑线程安全的网站,worker模式显然更加适合。

复习下进程和线程的主要区别和联系:

进程与线程区别与联系

  1. 划分尺度:线程更小,所以多线程程序并发性更高;
  2. 资源分配:进程是资源分配的基本单位,同一进程内多个线程共享其资源;
  3. 地址空间:进程拥有独立的地址空间,同一进程内多个线程共享其资源;
  4. 处理器调度:线程是处理器调度的基本单位;
  5. 执行:每个线程都有一个程序运行的入口,顺序执行序列和程序的出口,但线程不能单独执行,必须组成进程,一个进程至少有一个主线程。简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

worker模式是介于纯进程的prefork和纯线程的event模式直接的方式,在稳定性和资源上有一个取舍。

prefork配置解释

一个典型的prefork配置和解释如下

<IfModule prefork.c>
StartServers 20 # 启动服务数,对应启动进程数
MinSpareServers 50 # 最小空闲服务(提高响应能力),当前进程数 > 最小空闲服务 + 工作进程
MaxSpareServers 100 # 最大空闲服务(合理释放资源),当前进程数 < 最大空闲服务 + 工作进程
MaxClients 200 # 最大客户端,对应最大进程数
MaxRequestsPerChild 20000 # 每个服务最多处理的请求数量,设定一个有限值可以避免内存泄漏,但会消耗进程创建和销毁的资源
</IfModule>

prefork是用起来最方便的设置,apache的默认设置也是如此。
但该模式最内存资源消耗巨大。举例来说:
一般情况下,一个PHP网站中,每个server需要30M左右内存。
按照前文的配置,最多将占用6G左右的内存。
如果资源不足,就会引发频繁的page fault,大量的SWAP,系统产生大量IO,导致宕机。

所以合理的调整参数,满足网站并发要求和资源限制,在小内存(1G),prefork模式几乎是不可能做到的。

worker配置解释

<IfModule worker.c>

StartServers 15 # 启动的服务,对应进程

ServerLimit 15 # 最大服务限制 应满足 ServerLimit > MaxClients / ThreadsPerChild

MaxClients 256 # 最大客户端数量
ThreadLimit 256 # 最大线程数量
MinSpareThreads 30 # 最小空闲线程(提高响应能力),当前线程数 > 最小空闲服务 + 工作线程
MaxSpareThreads 305 # 最大空闲线程(合理释放资源),当前线程数 < 最大空闲服务 + 工作线程
ThreadsPerChild 255 # 每个子进程对应对线程数
MaxRequestsPerChild 0 # 每个进程处理的最大请求数量,达到即销毁新建进程
</IfModule>

类似的,我们也主要关注其并发响应能力和资源占用情况。

上面的配置可以支持256的并发,内存占用约大于 15 * 30M = 450M 左右,算上线程的开销,大致小于500M。

其他建议

并发和性能与很多东西相关,不是简单计算能够解决的。

这里的配置主要是避免系统瓶颈,同时保护服务器不要超过应用能力。

实际情况中,和磁盘性能,网络,CPU等都有关系,建议在对硬件的充分理解上,结合性能测试工具不断调优。Linux WEB Perfomance Tunning Toolbox

Ubuntu 8.10 VPN 简单配置要点

简单明了,四步走:

  1. 使用apt 安装 VPN Server Deamon: pptpd
  2. 配置IP, 用户控制文件
  3. 配置NAT
  4. 配置加密方式

具体请参考

http://crimm.me/2009/05/howto-ubuntu-810-pptp-vpn-server-with.html

我偷懒我骄傲

继续说Apache的优化

经过了前面一段时间的探索,我们对ApacheMySql的性能调优有了个初步的认识,我本来以为问题到这里应该就解决了,但是运行了十几天后,还是出现了负载达到50+的情况。于是,网站又挂了。

分析access.log与之前并无不同,被盗链的请求还是很多,不过这些都被302重定向了啊,死活想不到办法,一度怀疑是不是因为302或者404的错误日志过多的引起的IO问题导致服务器资源紧张。

除此之外,还是有个现象引起了注意,每次挂掉的不是Apache,而是数据库。为什么盗链会引起数据库问题,这显然无法解释。

不绕圈子了,最后发现的问题,就是为了防盗链而特意写的Rewrite。原本的rewrite是这样的,对于盗链的资源,重定向到首页。

这看起来没有问题,可是瞬间请求数百次到首页,然后运行脚本,执行数据库查询……

还有一点,返回的是302,这就意味着搜索引擎和下载工具会认为资源是存在的,不会停止响应。

所以,最终的解决方案。重定向所有盗链的资源到一个静态LOGO,同时,设定返回Code为403.

整个世界清净了。

性能调优:MySql Server at Linux

我们继续性能调优系列。

从过前两天的努力,再加上Cache和其他优化,系统的负载由原来的动不动10+下降到了1左右。这应当是巨大的变化,但是一段时间后发现,系统还是有不稳定的情况,CPU有时会莫名的高涨,虽然之前对Apache和PHP的限制使得系统有一点的稳定性,在大多数情况下可以在一段时间后恢复。不过凡事都应有个结局,对吧,找出问题是怪黍蜀的天性……

轮到了MySql, 现代系统,数据库基本上是应用的核心。系统后期再去调优基本上已经是木已成舟司马当作活马医,不过验尸为以后积攒经验还是必要的。再次多余一句,请尽可能优雅的设计数据库

设计到达一定阶段,就是应用了。这个时候可以进行SQL的Debug, 善用执行计划,调整索引和存储策略,参看Wiki 查询计划

好了,如果这些都没问题了,或者你没办法做这些事情了,就剩下数据库系统的调优了。Database Tuning 这是个多少有点复杂的主题,不过今天介绍的东西只要理解相关概念就可以了。

用于MySql调优的诊断脚本

MySqlTuner 是一个Perl脚本,简单好用。

下载脚本

wget http://mysqltuner.com/releases/mysqltuner-1.0.0.pl

修改脚本,增加执行权限

chmod +x mysqltuner-1.0.0.pl

运行

./mysqltuner-1.0.0.pl

程序输出

>>  MySQLTuner 1.0.0 – Major Hayden <major@mhtx.net>
>>  Bug reports, feature requests, and downloads at http://mysqltuner.com/
>>  Run with ‘–help’ for additional options and output filtering
Please enter your MySQL administrative login: root
Please enter your MySQL administrative password:

——– General Statistics ————————————————–
[--] Skipped version check for MySQLTuner script
[OK] Currently running supported MySQL version 5.0.45-log
[OK] Operating on 32-bit architecture with less than 2GB RAM

——– Storage Engine Statistics ——————————————-
[--] Status: -Archive -BDB -Federated +InnoDB -ISAM -NDBCluster
[--] Data in MyISAM tables: 89M (Tables: 147)
[--] Data in InnoDB tables: 27M (Tables: 157)
[--] Data in MEMORY tables: 126K (Tables: 2)
[!!] Total fragmented tables: 12

——– Performance Metrics ————————————————-
[--] Up for: 16h 33m 50s (480K q [8.050 qps], 28K conn, TX: 94M, RX: 95M)
[--] Reads / Writes: 75% / 25%
[--] Total buffers: 88.0M global + 2.7M per thread (60 max threads)
[OK] Maximum possible memory usage: 249.2M (49% of installed RAM)
[OK] Slow queries: 0% (18/480K)
[OK] Highest usage of available connections: 33% (20/60)
[OK] Key buffer size / total MyISAM indexes: 32.0M/17.2M
[OK] Key buffer hit rate: 99.6% (3M cached / 15K reads)
[OK] Query cache efficiency: 72.3% (248K cached / 344K selects)
[!!] Query cache prunes per day: 36459
[OK] Sorts requiring temporary tables: 0% (3 temp sorts / 26K sorts)
[OK] Temporary tables created on disk: 21% (3K on disk / 14K total)
[OK] Thread cache hit rate: 97% (765 created / 28K connections)
[OK] Table cache hit rate: 28% (351 open / 1K opened)
[OK] Open file limit used: 31% (343/1K)
[OK] Table locks acquired immediately: 99% (193K immediate / 193K locks)
[OK] InnoDB data size / buffer pool: 27.1M/30.0M

——– Recommendations —————————————————–
General recommendations:
    Run OPTIMIZE TABLE to defragment tables for better performance
    MySQL started within last 24 hours – recommendations may be inaccurate
Variables to adjust:
    query_cache_size (> 8M)

 

注意标注!!!的提示,同时脚本给出了若干优化意见。根据经验分析和修改就可以了。

顺带定时检查和优化表的cron

mysqlcheck -Aao -auto-repair -u root –password=*password* >/dev/null

同时给出  /etc/my.cnf参考配置

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1
#skip-locking
skip-bdb
# MySQL 4.x has query caching available.
# Enable it for vast improvement and it may be all you need to tweak.
query_cache_type=1
query_cache_limit=1M
query_cache_size=8M
# max_connections=500
# Reduced to 200 as memory will not be enough for 500 connections.
# memory=key_buffer+(sort_buffer_size+read_buffer_size)*max_connections
# which is now: 64 + (1 + 1) * 200 = 464 MB
# max_connections = approx. MaxClients setting in httpd.conf file
# Default set to 100.
max_connections=60
#interactive_timeout=180
interactive_timeout=100
#wait_timeout=180
#wait_timeout=100
# Reduced wait_timeout to prevent idle clients holding connections.
#wait_timeout=30
wait_timeout=15
connect_timeout=10
# max_connect_errors is set to 10 by default
#max_connect_errors=10
#table_cache=512
# Checked opened tables and adjusted accordingly after running for a while.
table_cache=512
#tmp_table_size=32M
#max_heap_table_size=32M
#thread_cache=128
# Reduced it to 32 to prevent memory hogging. Also, see notes below.
thread_cache=4
thread_cache_size=4
# key_buffer=258M
# Reduced it by checking current size of *.MYI files, see notes below.
key_buffer=32M
# Commented out the buffer sizes and keeping the default.
# sort_buffer_size=2M by default.
#sort_buffer_size=1M
# read_buffer_size=128K by default.
#read_buffer_size=1M
# 1Mb of read_rnd_buffer_size for 1GB RAM -- see notes below.
# read_rnd_buffer_size=256K by default.
#read_rnd_buffer_size=1M
# myisam_sort_buffer_size used for ALTER, OPTIMIZE, REPAIR TABLE commands.
# myisam_sort_buffer_size=8M by default.
#myisam_sort_buffer_size=64M
# thread_concurrency = 2 * (no. of CPU)
thread_concurrency=2
innodb_buffer_pool_size=30M
# log slow queries is a must. Many queries that take more than 2 seconds.
# If so, then your tables need enhancement.
log_slow_queries=/var/log/mysqld.slow.log
long_query_time=2