配置您的LEMP系统(Linux,nginx,MySQL,PHP-FPM)以获得最大性能
如果您使用nginx作为您的网络服务器,您正在寻找一个性能提升和更好的速度。 默认情况下,nginx很快,但您可以优化其与nginx一起工作的所有部件(如PHP和MySQL)的性能和性能。 这是一个小小的,不完整的提示和技巧列表,用于配置您的LEMP系统(Linux,nginx,MySQL,PHP-FPM)以获得最佳性能。 这些技巧为我工作,但是你的里程可能会有所不同。 不要一次实现它们,而是一个接一个地执行它们,并检查修改对系统性能的影响。
我不会保证这将为您工作!
1通过使用noatime和nodiratime安装PArtitions来减少磁盘I / O
将noatime和nodiratime添加到/ etc / fstab中的mount选项中:
vi /etc/fstab
# /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults 0 0 # / was on /dev/sda2 during installation UUID=9cc886cd-98f3-435a-9830-46b316e2a20e / ext3 errors=remount-ro,noatime,nodiratime,usrjquota=quota.user,grpjquota=quota.group,jqfmt=vfsv0 0 1 # swap was on /dev/sda1 during installation UUID=bba13162-121d-40a4-90a7-10f78a0097ae none swap sw 0 0 /dev/scd0 /media/cdrom0 udf,iso9660 user,noauto 0 0 #Parallels Shared Folder mount none /media/psf prl_fs sync,nosuid,nodev,noatime,share,nofail 0 0 |
按如下所示重新安装修改的分区(请确保为每个分区使用正确的安装点):
mount -o remount /
您可以在此了解更多信息: 通过在noatime中安装分区来减少磁盘IO
2调整nginx
2.1 worker_processes
确保在/etc/nginx/nginx.conf
中使用正确数量的worker_processes
。 这应该等于输出中CPU内核的数量
cat /proc/cpuinfo | grep processor
root@server1:~# cat /proc/cpuinfo | grep processor
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
root@server1:~#
在这个例子中,我们有八个CPU内核,所以我们设置
vi /etc/nginx/nginx.conf
[...] worker_processes 8; [...] |
2.2 keepalive_timeout,sendfile,tcp_nopush,tcp_nodelay
将keepalive_timeout
设置为一个明显的值,如两秒钟。 启用sendfile
, tcp_nopush
和tcp_nodelay
:
vi /etc/nginx/nginx.conf
[...] http { [...] sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 2; types_hash_max_size 2048; server_tokens off; [...] } [...] |
2.3文件缓存
启用nginx文件缓存:
vi /etc/nginx/nginx.conf
[...] http { [...] ## # File Cache Settings ## open_file_cache max=5000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; [...] } [...] |
2.4启用Gzip压缩
您可以在这里阅读有关Gzip压缩的更多信息: 如何使用nginx的HttpGzipModule保存流量(Debian Squeeze)
vi /etc/nginx/nginx.conf
[...] http { [...] ## # Gzip Settings ## gzip on; gzip_static on; gzip_disable "msie6"; gzip_http_version 1.1; gzip_vary on; gzip_comp_level 6; gzip_proxied any; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js; gzip_buffers 16 8k; [...] } [...] |
2.5启用SSL会话缓存
如果您提供https网站,则应启用SSL会话缓存:
vi /etc/nginx/nginx.conf
[...] http { [...] ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; [...] } [...] |
2.6使用FastCGI缓存
如果您有可缓存的PHP内容,可以使用nginx FastCGI缓存来缓存该内容。 在你的nginx.conf中
,添加一个类似于这个的行:
vi /etc/nginx/nginx.conf
[...] http { [...] fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=microcache:10m max_size=1000m inactive=60m; [...] } [...] |
缓存目录/ var / cache / nginx
必须存在并可写为nginx:
mkdir /var/cache/nginx
chown www-data:www-data /var/cache/nginx
(通过使用tmpfs,您甚至可以将目录直接放置在服务器的内存中,这提供了另一个小的速度优势 - 请参阅本教程了解更多信息: 使用tmpfs存储文件/目录 )。
在您的虚拟机配置中,将以下块添加到您的位置〜\ .php $ {}
部分(您可以根据何时缓存内容进行修改)
[...] # Setup var defaults set $no_cache ""; # If non GET/HEAD, don't cache & mark user as uncacheable for 1 second via cookie if ($request_method !~ ^(GET|HEAD)$) { set $no_cache "1"; } # Drop no cache cookie if need be # (for some reason, add_header fails if included in prior if-block) if ($no_cache = "1") { add_header Set-Cookie "_mcnc=1; Max-Age=2; Path=/"; add_header X-Microcachable "0"; } # Bypass cache if no-cache cookie is set if ($http_cookie ~* "_mcnc") { set $no_cache "1"; } # Bypass cache if flag is set fastcgi_no_cache $no_cache; fastcgi_cache_bypass $no_cache; fastcgi_cache microcache; fastcgi_cache_key $scheme$host$request_uri$request_method; fastcgi_cache_valid 200 301 302 10m; fastcgi_cache_use_stale updating error timeout invalid_header http_500; fastcgi_pass_header Set-Cookie; fastcgi_pass_header Cookie; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; [...] |
所以完整的位置〜\ .php $ {}
部分可能如下所示:
[...] location ~ \.php$ { # Setup var defaults set $no_cache ""; # If non GET/HEAD, don't cache & mark user as uncacheable for 1 second via cookie if ($request_method !~ ^(GET|HEAD)$) { set $no_cache "1"; } # Drop no cache cookie if need be # (for some reason, add_header fails if included in prior if-block) if ($no_cache = "1") { add_header Set-Cookie "_mcnc=1; Max-Age=2; Path=/"; add_header X-Microcachable "0"; } # Bypass cache if no-cache cookie is set if ($http_cookie ~* "_mcnc") { set $no_cache "1"; } # Bypass cache if flag is set fastcgi_no_cache $no_cache; fastcgi_cache_bypass $no_cache; fastcgi_cache microcache; fastcgi_cache_key $scheme$host$request_uri$request_method; fastcgi_cache_valid 200 301 302 10m; fastcgi_cache_use_stale updating error timeout invalid_header http_500; fastcgi_pass_header Set-Cookie; fastcgi_pass_header Cookie; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; try_files $uri =404; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/lib/php5-fpm/web1.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_intercept_errors on; } [...] |
这将使具有返回代码200,301和302的页面缓存十分钟。
您可以在这里阅读有关此主题的更多信息: 为什么您应该始终使用带有Microcaching的Nginx
2.7使用FastCGI缓冲区
在您的vhost配置中,您可以将以下行添加到您的位置〜\ .php $ {}
部分:
[...] fastcgi_buffer_size 128k; |
完整的位置〜\ .php $ {}
部分可能如下所示:
[...] location ~ \.php$ { try_files $uri =404; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/lib/php5-fpm/web1.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_intercept_errors on; fastcgi_buffer_size 128k; fastcgi_buffers 256 16k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_read_timeout 240; } [...] |
2.8使用memcached
nginx可以直接从memcached读取完整的页面。 因此,如果您的Web应用程序能够将完整的页面存储在memcached中,那么nginx可以从memcached中获取该页面。 一个示例配置(在您的vhost中)将如下所示:
[...] location ~ \.php$ { set $no_cache ""; if ($query_string ~ ".+") { set $no_cache "1"; } if ($request_method !~ ^(GET|HEAD)$ ) { set $no_cache "1"; } if ($request_uri ~ "nocache") { set $no_cache "1"; } if ($no_cache = "1") { return 405; } set $memcached_key $host$request_uri; memcached_pass 127.0.0.1:11211; default_type text/html; error_page 404 405 502 = @php; expires epoch; } location @php { try_files $uri =404; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/lib/php5-fpm/web1.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_intercept_errors on; } [...] |
重要的是,您的Web应用程序使用相同的密钥来存储memcached中的页面,nginx用于从memcached中获取这些页面(在本例中为$ host $ request_uri
),否则这将无法正常工作。
如果在memcached中存储大量数据,请确保已经为memcached分配了足够的RAM,例如:
vi /etc/memcached.conf
[...] # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default # Note that the daemon will grow to this size, but does not start out holding this much # memory -m 512 [...] |
2.9使浏览器使用expires指令缓存静态文件
不经常更改的文件(如图像,CSS,JS等)可以通过访问者的浏览器使用expires
指令进行缓存(请参见http://wiki.nginx.org/HttpHeadersModule#expires ):
[...] location ~* \.(jpg|jpeg|png|gif|ico)$ { expires 365d; } [...] |
2.10禁用日志记录静态文件
通常在访问日志中记录图像或CSS文件并不重要。 为了减少磁盘I / O,我们可以禁用这样的文件的日志记录,例如:
[...] location ~* \.(jpg|jpeg|png|gif|ico)$ { log_not_found off; access_log off; } [...] |
3调整PHP-FPM
3.1使用PHP操作码缓存,像Xcache或APC
确保您有安装了Xcache或APC的PHP操作码缓存。 在Debian / Ubuntu上,Xcache可以安装如下:
apt-get install php5-xcache
APC可以安装如下:
apt-get install php-apc
确保您只安装一个(Xcache或APC),而不是两个安装。 安装后重新装载PHP-FPM:
/etc/init.d/php5-fpm reload
3.2将足够的内存分配给Xcache / APC
如果你有很多PHP脚本,你应该提高分配给Xcache或APC的内存。 对于Xcache,可以在/etc/php5/conf.d/xcache.ini
中执行此操作
:
vi /etc/php5/conf.d/xcache.ini
[...] xcache.size = 512M [...] |
对于APC也是如此:
vi /etc/php5/conf.d/apc.ini
[...] apc.shm_size="512" [...] |
修改后重新加载PHP-FPM:
/etc/init.d/php5-fpm reload
3.3 PHP-FPM紧急设置
这比性能设置更可靠:PHP-FPM可以在停止工作时重新启动:
vi /etc/php5/fpm/php-fpm.conf
[...] ; If this number of child processes exit with SIGSEGV or SIGBUS within the time ; interval set by emergency_restart_interval then FPM will restart. A value ; of '0' means 'Off'. ; Default Value: 0 emergency_restart_threshold = 10 ; Interval of time used by emergency_restart_interval to determine when ; a graceful restart will be initiated. This can be useful to work around ; accidental corruptions in an accelerator's shared memory. ; Available Units: s(econds), m(inutes), h(ours), or d(ays) ; Default Unit: seconds ; Default Value: 0 emergency_restart_interval = 1m ; Time limit for child processes to wait for a reaction on signals from master. ; Available units: s(econds), m(inutes), h(ours), or d(ays) ; Default Unit: seconds ; Default Value: 0 process_control_timeout = 10s [...] |
3.4对于PHP> = 5.3.9:使用ondemand流程管理器
如果您使用PHP> = 5.3.9,您可以在PHP-FPM池中使用ondemand
进程管理器,而不是静态
或动态
,这将为您节省一些RAM:
[...] pm = ondemand |
3.5使用Unix套接字代替TCP套接字
为了减少网络开销,您应该将池配置为使用Unix套接字而不是TCP:
[...] ;listen = 127.0.0.1:9000 |
如果你改变这个,你必须调整nginx vhost中的位置〜\ .php $ {}
部分来使用套接字( fastcgi_pass unix:/var/lib/php5-fpm/www.sock;
而不是fastcgi_pass 127.0。 0.1:9000;
):
[...] location ~ \.php$ { try_files $uri =404; include /etc/nginx/fastcgi_params; ##fastcgi_pass 127.0.0.1:9000; fastcgi_pass unix:/var/lib/php5-fpm/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_intercept_errors on; } [...] |
3.6避免在忙碌站点上使用套接字的502错误网关错误
如果您使用带有PHP-FPM的Unix套接字,则可能会遇到随机网站错误的502错误网关错误。 为了避免这种情况,我们提高最大值。 允许连接到套接字的数量。 打开/etc/sysctl.conf
...
vi /etc/sysctl.conf
...并设置:
[...] net.core.somaxconn = 4096 [...] |
跑
sysctl -p
之后变更生效。
4调优MySQL
4.1优化my.cnf
您应该使用诸如mysqltuner.pl或tune-primer.sh (或两者)之类的脚本来找出您应该在my.cnf
文件中调整哪些设置。 最重要的变量之一是query_cache_size
,如果使用InnoDB表, innodb_buffer_pool_size
。
这是一个来自具有16GB RAM的测试服务器的示例配置,约30个数据库,具有50%的MyISAM表和50%的InnoDB表,这对于使用基准测试工具( ab
)强调的数据库驱动的测试站点来说相当不错:
[...] key_buffer = 256M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 100 table_open_cache = 16384 table_definition_cache = 8192 sort_buffer_size = 256K read_buffer_size = 128K read_rnd_buffer_size = 256K myisam_sort_buffer_size = 64M myisam_use_mmap = 1 thread_concurrency = 10 wait_timeout = 30 myisam-recover = BACKUP,FORCE query_cache_limit = 10M query_cache_size = 1024M query_cache_type = 1 join_buffer_size = 4M log_slow_queries = /var/log/mysql/mysql-slow.log long_query_time = 1 expire_logs_days = 10 max_binlog_size = 100M innodb_buffer_pool_size = 2048M innodb_log_file_size = 256M innodb_log_buffer_size = 16M innodb_flush_log_at_trx_commit = 0 innodb_thread_concurrency = 8 innodb_read_io_threads = 64 innodb_write_io_threads = 64 innodb_io_capacity = 50000 innodb_flush_method = O_DIRECT innodb_file_per_table innodb_additional_mem_pool_size = 256M transaction-isolation = READ-COMMITTED innodb_support_xa = 0 innodb_commit_concurrency = 8 innodb_old_blocks_time = 1000 [...] |
请注意:如果需要符合ACID,您必须将innodb_flush_log_at_trx_commit
设置为1
。 您可以在http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit上找到更多信息。
只有在SSD上使用MySQL时, innodb_io_capacity才
应设置为高值。 如果您在普通硬盘上使用它,最好离开这条线。
4.2使用SSD
通过使用具有固态硬盘(SSD)的MySQL可以大大提升性能,因为这样可以减少磁盘I / O。 最简单的方法是将/ var / lib / mysql
目录安装到SSD。
5 Web应用缓存
许多Web应用程序(例如具有WP Super Cache或W3 Total Cache插件的WordPress,具有Boost模块的Drupal,带有nc_staticfilecache扩展名的TYPO3)可以创建存储在硬盘驱动器上的全页缓存,并且可以可以直接由nginx访问,以便它可以绕过整个PHP-MySQL。 这提供了巨大的性能提升。
你可以在这里找到关于这方面的教程:
- 运行WordPress在Nginx(LEMP)在Debian Squeeze / Ubuntu 11.04
- 运行Drupal 7.7在Nginx(LEMP)上Debian Squeeze / Ubuntu 11.04
- 运行TYPO3 4.6在Nginx(LEMP)上Debian Squeeze / Ubuntu 11.10
您可以通过使用tmpfs文件系统将其直接放置在服务器的内存中来加快静态文件缓存的速度:
当然,您也可以从第2.6章的nginx FastCGI缓存中使用tmpfs。
6链接
- nginx维基: http : //wiki.nginx.org/Main
- PHP: http : //www.php.net/
- PHP-FPM: http : //php-fpm.org/
- MySQL: http : //www.mysql.com/
关于作者
Falko Timme是所有者 Timme Hosting (超快nginx网页托管)。 他是youcl(自2005年以来)的主要维护者, 也是ISPConfig的核心开发人员之一 (自2000年起)。 他还为O'Reilly的“Linux系统管理”一书作出了贡献。