配置您的LEMP系统(Linux,nginx,MySQL,PHP-FPM)以获得最佳性能

配置您的LEMP系统(Linux,nginx,MySQL,PHP-FPM)以获得最佳性能 如果您使用nginx作为您的网络服务器,您正在寻找...

配置您的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设置为一个明显的值,如两秒钟。 启用sendfiletcp_nopushtcp_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;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_read_timeout 240; [...]

完整的位置〜\ .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
pm.max_children = 100
pm.process_idle_timeout = 5s [...]

3.5使用Unix套接字代替TCP套接字

为了减少网络开销,您应该将池配置为使用Unix套接字而不是TCP:

[...]
;listen = 127.0.0.1:9000
listen = /var/lib/php5-fpm/www.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660 [...]

如果你改变这个,你必须调整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.pltune-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。 这提供了巨大的性能提升。

你可以在这里找到关于这方面的教程:

您可以通过使用tmpfs文件系统将其直接放置在服务器的内存中来加快静态文件缓存的速度:

使用tmpfs将文件/目录存储在内存中

当然,您也可以从第2.6章的nginx FastCGI缓存中使用tmpfs。

关于作者

Falko Timme是所有者 nginx Webhosting Timme Hosting (超快nginx网页托管)。 他是Howtoing(自2005年以来)的主要维护者, 也是ISPConfig的核心开发人员之一 (自2000年起)。 他还为O'Reilly的“Linux系统管理”一书作出了贡献。