共计 22802 个字符,预计需要花费 58 分钟才能阅读完成。
Nginx 是一个高性能的 http 服务器和反向代理服务器,是一个高度模块化的 web 服务器,和 Apache 的模块化不同,Nginx 的模块不支持动态编译,Nginx 要加入新的第三方模块的时候,必须先下载模块,然后重新编译 Nginx,而 Apache 只需要将新加入的模块编译成 so 文件,然后配置文件指定是否加载即可,无需重新编译 Apache。并且 Nginx 的 rewrite 模块会使用正则表示式进行匹配,因此需要 pcre 软件库的支持,另外 ssl 加密需要 openssl-devel 软件库的支持,gzip 压缩传输需要 zlib-devel 软件库的支持。编译安装 Nginx 之前确定这三个软件库已经安装。
目录
Nginx 的配置文件结构
Nginx 的配置文件参数
虚拟主机
LNMP 架构
状态监控页面
URL 重写
Nginx 的负载均衡功能
Nginx 的缓存服务器应用
Nginx 的性能优化
Nginx 的 I / O 模型
1.Nginx 的配置文件结构
通过 epel 源安装的 Nginx 的配置文件在 /etc/nginx/ 目录下,对于编译安装的 Nginx,其配置文件在安装目录下的 conf 目录下,Nginx 配置文件以 block 块的形式组织,每个 block 以 {…} 为界限,block 块中包含各种指令。整体结构分为 main 层、events 块、http 块,main 是最高层,从上到下继承,位于 main 层的指令会向下继承至 events 和 http,events 块指令会继承至 http。http 往下分为多个 server 块,server 块再往下分为 location 块,继承关系是从外到内。
一个完整的 Nginx 的配置结构如下,
events {#events 块,包含 events 指令
…
}
http #http 块,包含 http 指令和多个 server 块
{
… #http 全局指令块
server #server 块
{
… #server 全局指令块
location [PATTERN] #location 块
{
…
}
location [PATTERN]
{
…
}
}
server
{
…
}
… #http 全局块
}
2.Nginx 的配置文件参数
通过 yum 安装的 Nginx,其配置文件类型如下图所示,当然了,Nginx 都会默认为 每种类型的配置文件提供一个.default 结尾的文件用以参考。
主配置文件 nginx.conf
对于 rpm 安装的 Nginx 而言,它的主配置文件是由 /etc/sysconfig/nginx 文件决定的,其中的 NGINX_CONF_FILE 参数定义主配置文件。
主配置文件的主要参数如下,关于 main 全局配置
user nginx nginx; 定义 Nginx 的 worker 进程的用户和用户组,默认是 nobody
worker_processes auto; 定义开启 worker 进程的数量
error_log(日志错误级别 debug|info|notice|warn|error|crit)定义全局错误日志文件
pid 定义 nginx 的 master 进程 ID 的存储文件,防止程序启动多个实例
进程运行后会给 pid 文件加一个文件锁,只有获得该锁的进程才具有写权限,将自身的 pid 写入 pid 文件中,其他试图获得该锁的进程会退出。
关于 events 事件驱动配置
use epoll; 定义 Nginx 工作时的 I / O 模型,支持的 I / O 模型有 select、poll、epoll 等,其中 select 和 poll 是标准的方式,epoll 是高效的工作方式,也是 Nginx 优先考虑的 I / O 模型。
work_connections 定义每个 worker 进程允许的最大的同时连接数,总之,Nginx 能够同时打开的最大文件数 =worker_processes*work_connections。
注意:Linux 系统默认规定进程打开的最大文件数为 1024,因此,如果work_connections 的值大于 1024 的话,则无法生效。例如,设置 worker_connnects 65535,Nginx 在启动之前需要运行命令 ulimit -n 65535 将进程支持的最大文件数改为 65535。
关于 http 块的配置
log_format 定义 Nginx 的日志输出格式,main 为该日志的输出格式名称,下面的指令如果想要调用该日志格式的话,直接引用 main 关键词即可。
access_log /var/log/nginx/access.log main; 定义 Nginx 被访问的日志,同时引用 log_format 定义的以 main 为命名的日志格式。
日志格式中各变量的含义如下,
$remote_addr 客户端 IP 地址
$remote_user 客户端用户名称
$time_local 访问的时间与时区
$request 请求的 URL
$status 请求状态(http 的请求状态码)
$body_bytes_sent 发送给客户端的文件主体大小
$http_referer 记录从哪个页面链接过来的
$http_user_agent 客户端浏览器的信息
$http_x_forwarded_for 客户端的 IP 地址
注意:$remote_addr 和 $http_x_forwarded_for 同样都是访问服务器的客户端 IP,但是这两者还是有区别的,对于前端设置了反向代理的服务器,$remote_addr 是指反向代理服务器的 IP 地址,$http_x_forwarded_for 是指真实的客户端 IP 地址
charset utf-8 设置网页的编码格式,默认编码为 utf-8,还有 gb2312 等
server_names_hash_bucket_size
服务器名字的 hash 表大小,nginx 的多个 server_name 是存放在哈希表中的。这样可以提高 nginx 速度
client_max_body_size 客户端请求单个文件的最大字节数
当请求的文件数大于该值的时候,服务器会报出 413(Request Entity Too Large)的错误
client_header_buffer_size 指定客户端请求头的 buffer 大小, 一般情况下 1K 大小足以
large_client_header_buffers <number> <size>
请求头大小超过 client_header_buffer_size 的值时,会将请求头的大小重新设置为 large_client_header_buffers 的值。例如large_client_header_buffers 4 128K,最大缓存量为 4 个 128K。
上诉两个请求头的 buffer 的关系,受到 http 请求时,先根据 client_header_buffer_size 分配一个 buffer,如果 buffer 无法容纳请求头,那么会根据 large_client_header_buffers 重新分配 buffer。
keepalived_timeout 客户端保持连接的超时时间
client_header_timeout 客户端请求头读取超时时间
client_body_timeout 客户端请求主体读取超时时间
上述请求头和请求主体的超时时间,如果超过时间客户端还没有发送数据,则 Nginx 返回 408(Request time out)的错误。
send_timeout 服务端响应的超时时间,对于已经建立的连接,如果客户端在超时时间内没有任何动作,Nginx 断开连接。
conf.d/ 和 default.d/ 扩展配置文件目录
Nginx 中引入扩展配置文件的目录是为了降低主配置文件 nginx.conf 的复杂度,Nginx 的 http 块是由多个 server 块组成,每个 server 也是有多个 location 块组成的,这么多的 server 和 location 当然都可以放在一个主配置文件中,但还是 server 过多的情况下,会使得主配置文件变得十分庞大,而且也不便于管理与修改。因此引入了扩展配置文件目录。
conf.d/ 目录下存放 server 块的配置文件,default.d/ 目录下存放 location 块的配置文件,引用的时候使用 include 指令将相对应的 server 块配置文件和 location 配置文件加入各自的 block 块中即可。
http {
…<http 全局指令 >…
include /etc/nginx/conf.d/*.conf;
}
或者
server {
…<server 全局指令 >…
include /etc/nginx/default.d/*.conf;
}
fastcgi_params/fastcgi.conf
Nginx 在 fastcgi 解析的时候,需要调用这两个文件中的服务器变量,内置的服务器变量如下,
这个文件的区别就是.conf 比 params 多了一行 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
uwsgi_params
和 fastcgi_params 一样,这里是调用关于 uwsgi 协议的一些服务器变量。
scgi_params
这里是调用关于 scgi 协议的一些服务器变量。
mime.types
web 资源类型配置文件,定义 web 资源的类型,即文件扩展名和资源类型的映射表,nginx 就是根据这个映射表设置 http 请求响应头的 Content-Type 值。
mime.types 在 http 块的全局配置中被引用,下面的指令的意思是根据 mime.types 定义 web 资源类型,如果在映射表中找不到对应关系,则使用 default_type 定义的默认资源类型。
koi-win/koi-utf/win-utf
这三个文件都是与编码转换映射相关的文件,用于在输出内容到客户端时,将一种编码转换到另一种编码。
koi-win:charset_map koi8-r < — > windows-1251
koi-utf:charset_map koi8-r < — > utf-8
win-utf:charset_map windows-1251 < — > utf-8
3. 虚拟主机
对 Nginx 而言,一个 server 块就是一个虚拟主机,我这里将每个 server 块的配置单独作为一个文件放入 conf.d/ 目录下。然后在主配置文件中 include 命令包含进来即可。
关于虚拟主机的指令如下,
server {…} 虚拟主机开始的关键字
listen address[:port] [default_server]
虚拟主机监听的 IP 和端口
default_server 定义该 server 为默认,如果所有 server 段都没有使用该参数,则第一个 server 为默认
该参数通常在地址列没有输入 server_name,而是输入 IP 地址的时候,Nginx 会定位在 default_server 的虚拟主机。
例: listen 192.168.124.100:80 default_server
server_name 指定虚拟主机的域名,可以定义多个域名,之间用空格隔开,可以使用通配符和正则表达式
server_name 的作用:Nginx 收到一个 http 请求的时候,会取出首部的 server 字段,然后和所有 server_name 字段进行比较,匹配则定位到对应的 server 块;
server 可以是多个,相对应的 server_name 也会有多个,多个 server_name 之间的优先顺序是:
精确匹配 www.linux.com
左侧通配符匹配 *.linux.com
这个左侧通配符匹配实际应用场景很广,www.linux.com、bbs.linux.com、blog.linux.com 等都可以通过一个左侧通配符来完成
右侧通配符匹配 www.*
正则表达式匹配 ^.*\.linux\.com$
root 定义虚拟主机的网页根目录,可以是绝对路径,也可是相对路径
index 定义虚拟主机默认的首页文件
charset 定义网页的默认编码格式,既可以用于 http 全局,也可以用于 server 全局
access_log 同样既可以用于 http 全局,也可以用于 server 全局
location {…} 地址匹配开始的关键字,location 块对 URL 地址匹配进行设置,支持正则表达式匹配
location 和 URL 进行匹配,匹配成功则进行其中的处理。控制服务端的访问路径
= 精确匹配
~ 正则表达式匹配,区分大小写
~* 正则表达式匹配,不区分大小写
^~ URL 前半部分匹配,忽略大小写
/ 通用匹配,因为所有的匹配都是以 / 为开始的
他们的优先级:
= -> ^~ -> ~ 或者~* -> /
例如:
location ^~ /bbs.txt {| location ^~ /bbs{
alias /var/www/html/1.txt; | alias /var/www/html/1.txt;
} | }
location = /bbs.txt {| location = /bbs{
alias /var/www/html/2.txt; | alias /var/www/html/2.txt;
} | }
结果会优先返回优先级高的匹配 URL | 结果会优先返回优先级高的匹配 URL
即 2.txt 的页面内容 | 即 2.txt 的页面内容
alias 定义 Nginx 中别名功能,只能用在 location 中
tips:
root 既可以写在 server 中,也可以写在 location,当同时存在时,内层会替换外层。例如
root path1;
location / {
root path2;
}
location ~ \.php$ {
}
第一个 location 生效的是 path2,第二个 location 生效的是 path1.
root 和 alias 的区别:
root 指定的是根目录,alias 指定的是当前目录,
location /html {
root /data/web/;
}
# 如果 URL 请求的是 /html/index.html,则 nginx 会在 /data/web/html/ 目录查找 index.html 文件
location /html {
alias /data/web/;
}
# 如果 URL 请求的是 /html/index.html,则 nginx 会在 /data/web/ 目录下查找 index.html 文件
location ~ ^/download/(.*)$ {
alias /data/web/$1;
}
# 如果 URL 请求的是 /download/nginx.tar.gz,则 nginx 会在 /data/web/ 目录下查找 nginx.tar.gz 文件
nginx 中配置文件中的正则表达式依赖于 pcre 库,这也是安装 nginx 之前为什么必须先安装 pcre 的原因。
http_geoip_module 模块可以处理来自不同地区的访问
include /usr/share/nginx/modules/mod-http-geoip.conf
Nginx -V # 查看 Nginx 编译过程中的参数
–sbin-path 定义开启 Nginx 的主进程的命令路径
–modules-path 定义 Nginx 的模块的存储路径
–conf-path 定义 Nginx 配置文件的路径
–error-log-path 定义错误日志的路径
–http-client-body-temp-path 客户端主体请求的临时文件的路径
–http-proxy-temp-pathNginx 代理(负载均衡)的临时文件的路径
–http-fastcgi-temp-path fastcgi 的临时文件的路径
–with-file-aio 文件的异步 IO
4.LNMP 架构
现在大多数的电子商务网站都是基于 LNMP(Linux+Nginx+MySQL+PHP)架构设计的。LNMP 的架构的简单的工作原理如下,
其中,Nginx 作为 web 服务器,响应客户端发来的 http 请求,和 Apache 一样,本身只能处理静态请求,而对于动态请求,则需要 Nginx 与专门的语言解释器进行交互,例如 PHP 解释器,然后 PHP 解释器执行 php 脚本,其中会涉及到一些数据的操作,因此就需要到后端的数据库服务器中存取数据。最后 php 的执行结果交给 nginx,nginx 继而将结果返回给客户端。
fastcgi:
nginx 收到的请求不能直接转发给 php,因为 php 不认识,反过来,php 处理后的结果也不能直接返回给 nginx,因此需要在他们两者中间加入公共接口,即 fastcgi,使得 nginx 和 php 都能够支持 fastcgi,当 nginx 和 php 交互的时候,都需要通过 fastcgi 协议的处理。
PHP 和 php-fpm 的关系:
php-fpm 是 php 和 fastcgi 的管理器,它其实 php 的一个补丁,是为了将 fastcgi 的管理器整合到 php 中,这样一来,仅可以通过 php-fpm 服务,既可以管理 fastcgi 进程,也可以 reload 重新加载 php(在修改 php 的配置文件 php.ini 后无需重新启动 php)。
因此 LNMP 详细的工作流程是,Nginx 收到浏览器的 web 请求后,Nginx 自身处理其中的静态请求,例如图片、视频等,对于动态请求,Nginx 将其通过 fastcgi 处理后转发给 php-fpm 进程,php-fpm 调用 php 解析器执行 fastcgi 处理后的 php 脚本,期间 php 再连接数据库进行数据的操作,php 解析器处理完毕后,将结果转发给 php-fpm 进程,php-fpm 将结果通过 fastcgi 交付给 Nginx,最后 Nginx 将最终的结果返回给浏览器。
LNMP 搭建过程:
① 安装 Nginx,为了方便我这里使用 yum 安装,当然也可以使用源码编译安装,我使用的阿里云的 epel 源,直接在 Linux 中输入如下命令,就可以成功配置 yum 仓库。
[root@CentOS6 ~]# yum makecache
[root@CentOS6 ~]# yum -y install nginx
我这里安装的 nginx 版本是 1.10.2
② 安装数据库 mysql,直接使用本地 base 源即可。
安装成功之后会发现也会为我们安装 mysql 客户端工具,用于连接 mysql 服务端。
然后创建用于存放数据的数据库 wordpress,赋予用户 wordpress 使用该数据库的所有权限,并设置连接数据库的秘密 centos,
[root@CentOS6 ~]# mysql
mysql> create database wordpress;
mysql> grant all on wordpress.* to wordpress@’%’ identified by ‘centos’;
mysql> flush privileges;
③ 接下来就是 php 和及其扩展包的安装,同样使用 base 源即可
[root@CentOS6 ~]# yum -y install php php-mysql
④ 安装 统一管理php 解释器和 fastcgi 进程的工具 php-fpm。
[root@CentOS6 ~]# yum -y install php-fpm
修改 php-fpm 的工作进程的用户和用户组为 nobody.nobody(需要同 Nginx 工作进程的用户 / 用户组一致,我这里设置的是 nobody.nobody),这样做的目的是限制 php-fpm 和 Nginx 的权限。php-fpm 的配置文件是/etc/nginx/php-fpm.d/www.conf
修改后的内容如下,其他的指令保持默认。
⑤ 修改 Nginx 的配置,使其能将动态请求转发给 php-fpm。
Nginx 主配置文件的内容如下:
user nobody nobody;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 1024;
}
http {
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /var/log/nginx/access.log main;
keepalive_timeout 65;
charset utf-8;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf; # 引用 server 块的扩展配置文件
}
Nginx 的 server 块的扩展配置文件内容如下,
[root@CentOS6 conf.d]# cat /etc/nginx/conf.d/default.conf
#
# The default server
#
server {
listen 80;
server_name wordpress.linux.com;
root /data/web;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # 运行 php-fpm 进程的 ip 和端口
fastcgi_index index.php; # 定义网页的入口文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
}
⑥ 测试 LNMP 架构是否成功
在 nginx 服务器的 /data/web/(由 root 指令决定)目录下,创建 index.php 文件,写入连接数据库和 php 的测试代码
[root@CentOS6 ~]# cd /data/web
[root@CentOS6 web]# cat index.php
<?php
$link=mysql_connect(“192.168.239.129″,”wordpress”,”centos”);
# 三个参数分别为运行数据库服务的 IP 地址,用户,密码
if ($link)
echo “success”;
else
echo “failed”;
phpinfo();
?>
在 windows 的 hosts 文件中添加记录,
然后在浏览器中出现如下如所示的界面,表示 LNMP 架构已经搭建完成。
利用 LNMP 架构搭建博客,下载 wordpress,将解压后的所有文件放在 /data/web/ 目录下,需要保持这些文件的用户和用户组和 nginx 进程的保持一致,因此设置这些文件的用户和组为 nobody。
[root@CentOS6 web]# chown -R nobody.nobody /data/web/*
然后修改其中的 wp-config.php 文件,该文件主要用于连接数据库配置,主要修改的内容如下,
define(‘DB_NAME’, ‘wordpress’);
/** MySQL database username */
define(‘DB_USER’, ‘wordpress’);
/** MySQL database password */
define(‘DB_PASSWORD’, ‘centos’);
/** MySQL hostname */
define(‘DB_HOST’, ‘192.168.239.129’);
最后在浏览器中输入 wordpress.linux.com,首次访问需要完成安装的步骤,按照指示一步步完成即可。最后再次访问该域名,出现如下界面表示博客搭建成功。这样 LNMP 的一个实际应用就已经实现了。
tips:
LNMP 搭建网站的时候,首次都需要连接数据库的步骤,该步骤的完成通常都是修改源码中的 config.php 文件来完成的(例如该例中的 wp-config.php),该文件中一般定义了要连接的数据库的名称,用户和用户口令等信息。
LNMP 和 LAMP 的区别:
LAMP 中的 php 是作为 Apache 的一个模块存在的,所以 php 和 Apache 共存亡;LNMP 中的 php 是作为一个单独的服务存在的,通过 php-fpm 进行管理。
5. 状态监控页面
Nginx 内置了 StubStatus 的工作模块,该模块可以监控 Nginx 的工作状态。监控页面完成通过一个 location 就可以完成,location 的配置如下,
location /status {
stub_status on; # 开启状态监控的功能
access_log /var/log/nginx/status.log; # 定义状态页面的访问日志
# 采用 auth_basic 认证机制
auth_basic “NginxStatus”; # 定义状态页面的名称
auth_basic_user_file /etc/nignx/conf.d/htpasswd; # 指定密码文件
}
其实只需要 stub_status on 就可以开启 Nginx 的状态监控功能,和上边的区别就是没有日志记录文件,没有密码认证的功能。
另外 auth_basic 认证机制的密码文件需要 Apache 的 htpasswd 命令生成。
# 允许登录的用户为 admin,然后根据指示设置密码
# 因为 nginx 的工作进程为 nobody,因此需要将密码文件对 nobody 用户有 r – 权限
[root@CentOS6 default.d]# chown nobody.nobody /etc/nignx/conf.d/htpasswd
[root@CentOS6 conf.d]# chmod 400 htpasswd
[root@CentOS6 conf.d]# ll htpasswd
-r——–. 1 nobody nobody 20 Jul 19 03:03 htpasswd
然后在浏览器中输入 wordpress.linux.com/status,输入正确的用户名和密码后,就可以看到状态页面。
Nginx 的状态页面的参数含义:
Active connections 当前活动的客户端连接数
accepts 已经累计收到的客户端连接数量
handled 已经处理的客户端连接数量
requests 客户端的总的请求数量
accepts/handled/requests 这三个参数的区别是:
客户端发起的总的请求数是 requests,服务端可以不接受请求,也即实际接受的请求数是 accepts,而服务器在接受的请求数中实际处理的请求数是 handled
reading 正在读取的客户端请求数量
writing 正在发送响应报文的连接数量
waiting 等待发送请求的空闲连接数量
对于长连接,还需要等待用户发送数据等等的情况,因此会出现空闲连接。
6.URL 重写
Nginx 的配置文件支持类似 shell 编程的逻辑判断,对于不同的请求定义不同的规则。
URI/URN/URL 的区别
URI 统一资源标识符,URI 由 URN 和 URL 组成,mailto:John.Doe@example.com
URN 统一资源名称,代表资源的名称,John.Doe
URL 统一资源定位符,代表资源的路径,mailto:example.com
if 判断指令
if (condition) {…}, 仅仅在 server 和 location 块中使用
condition 是一个变量的时候,为空或者以 0 开头的字符串都将被判定为 false
逻辑判断表达式:
= 或!= 等于或不等于
正则表达式匹配:
~ 区分大小写的匹配
~* 不区分大小写的匹配
!~ 区分大小写的不匹配
!~* 不区分大小写的不匹配
文件 / 目录匹配:
-f/!-f 文件是否存在
-d/!-d 目录是否存在
-e/!-e 文件或者目录是否存在
-x/!-x 文件是否可以执行
Nginx 内置的全局变量
$host 请求主机头字段,即 server_name
$http_user_agent 客户端 agent 信息,即客户端使用的何种浏览器, 这个值一定要根据日志 access.log 中显示的浏览器信息为依据,尤其是 IE 浏览器,之前我就以 MSIE 为 IE 的 http_user_agent,结果实验老是失败。
$http_cookie 会话标识
$limit_rate 限制连接速率,例如网盘的限速
$request_meathod 客户端请求的动作
$remote_addr 客户端的 IP 地址
$request_filename 当前请求的文件路径
$scheme http 方法(http 或者 https)
$server_protocol http 协议版本
$server_addr 服务器 IP 地址
$server_name 服务器名称
$server_port 服务器的端口号
$request_uri 包含参数的 URI,例如 www.xxx.com/xxx.php?xxx
rewrite 指令
只能用在 server、location、if 中,并且只能对 URL 中的非传递参数的字符串起作用。
rewrite 和 location 都能实现地址跳转,但是两者还是有区别的,rewrite 是在同一域名内改变资源路径,而 location 是对一类路径做访问控制,他们的执行顺序是server 中 rewrite->location-> location 中 rewrite。
rewrite 重复执行超过 10 次还找不到资源就会返回 500 错误代码。
rewrite 指令的格式:rewrite <regex> < 替换后的 URL> [flag]
重定向的标志位 flag
last 表示完成 rewrite,一般用在 server 和 if 中,浏览器地址栏的 URL 不变
break 通常使用在 locating 中,表示后续的 rewrite 不再执行,浏览器地址栏的 URL 不变
redirect 返回 302 临时重定向,浏览器地址栏显示跳转后的地址
permanent 返回 301 永久重定向,浏览器 地址栏显示跳转后的地址
例子:
以上边 LNMP 搭建的博客为例,在浏览器中的域名后边随便输入一个字符串表示一个不存在的目录或者文件,然后浏览器默认会返回 404 的错误页面。
现在使用 yum 安装 nginx 时其默认提供的 404 错误页面,而不是使用浏览器提供的 404 错误页面。
cp /usr/share/nginx/html/404.html /data/web/
server {
listen 80;
server_name wordpress.linux.com;
…
if (!-e $request_filename) {
rewrite ^(.*)$ /404.html break;
}
…
}
如果访问的文件或者目录不存在,则重定向到 404.html 页面
listen 80;
server_name wordpress.linux.com;
…
if ($http_user_agent ~ “Firefox”) {
rewrite ^(.*)$ http://www.baidu.com/ redirect;
…
}
域名跳转
现在使用火狐浏览器访问,结果成功的跳转到百度的首页。
然后使用 360 浏览器,结果域名没有跳转。
7.Nginx 的负载均衡功能
Nginx 拥有基于 7 层交换的负载均衡功能,对于后端 10 台左右的 web 服务器的情况,Nginx 的负载均衡性能最佳。因此 Nginx 适用于小型网站的负载均衡。Nginx 通过 upstream 命令实现负载均衡功能。Nginx 的负载均衡模块支持的常用负载均衡算法如下,
轮询 Nginx 默认调度算法,按请求时间将请求逐一分配到后端服务器
加权轮询 指定后端服务器的权值,权值越大,请求被分配的概率越大,轮询是权值都为 1 的加权轮询
ip_hash 根据客户端 IP 的哈希结果分配请求,这样同一客户端的请求就可以分配到固定的后端服务器,可以解决 session 共享的问题
fair 根据后端服务器的响应时间分配请求,响应时间短的优先分配。
url_hash 根据访问的 URL 的哈希结果分配请求,这样同一 URL 的请求就可以分配到固定的后端服务器。
Nginx 的负载均衡调度算法中,轮询、加权轮询、ip_hash 是 Nginx 自身提供的,而 fair、url_hash 分别由第三方模块 upstream_fair 模块和 hash 软件包提供。
Nginx 负载均衡功能的配置格式:
upstream xxx {
server ip1:port1 status;
server ip2:port2 status;
…
}
server {
…
location …{
proxy_set_header Host $host;
proxy_set_header X-Forward-For $remote_addr;
proxy_pass http://xxx;
…
}
}
# xxx 为定义的后端服务器群的名称
# ip:port 为后端提供 web 服务的 ip 和端口号
# status 是后端服务器群各个节点的状态
proxy_set_header 的作用:
该指令的意义在于修改 http 请求头的信息。这里修改的主要是请求头中的 host 字段和 remote_addr 字段。在设置了负载均衡之后,客户端的请求先到达负载均衡层,再到真实的 web 服务器,由此请求经过了一个中间层。Host 的含义是表明请求的主机名,因为 nginx 作为反向代理使用,而如果后端真实的服务器设置根据 http 请求头中的 host 字段来进行路由或判断功能的话(即根据 host 字段判断请求发往哪个虚拟主机),如果反向代理层的 nginx 不重写请求头中的 host 字段,将会导致请求失败(默认反向代理服务器会向后端真实服务器发送请求,并且请求头中的 host 字段应为 proxy_pass 指令设置的服务器,也就是上边的 xxx)。x-forward-for 表示 http 请求由谁发起的,如果负载均衡层不重写该字段的 ip,则后端真实服务器收到的 http 请求头中都是负载均衡服务器的 ip 地址,如果后端有防×××策略的话,那么负载均衡服务器就被真实服务器封掉了。
status 的常用状态有
down 表示该 web 节点不参与负载均衡的调度
weight 定义该 web 节点的权值
backup 表示预留 web 节点,只有当所有的非 backup 的 web 节点出现故障的时候,backup 节点才会接受请求
max_fails 表示请求该 web 节点的最大的失败次数
fail_timeout 表示该节点在经历 max_fails 次的失败请求之后,暂停服务的时间
实验环境:
192.168.239.130:80 前端负载均衡节点
192.168.239.129:80 后端提供 web 服务的节点 1
192.168.239.132:80 后端提供 web 服务的节点 2
负载均衡节点的 nginx.conf 内容如下:
worker_processes 2;
error_log /usr/local/nginx/logs/error.log notice;
pid /usr/local/nginx/logs/nginx.pid;
events {
use epoll;
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /usr/local/nginx/logs/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;
gzip on;
upstream webserver {
# web1
server 192.168.239.129:80 weight=4 max_fails=3 fail_timeout=20s;
# web2
server 192.168.239.132:80 weight=3 max_fails=3 fail_timeout=20s;
}
server {
listen 80;
server_name blog.linux.com;
root /data/html;
index index.php index.html index.htm;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forward-For $remote_addr;
proxy_pass http://webserver;
}
节点 1 就是 4.LNMP 架构搭建的 web 服务,这里不再重写其 nginx.conf 文件的内容
节点 2 的 nginx.conf 的配置内容如下:
user nobody nobody;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
use epoll;
worker_connections 1024;
}
http {
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name web2.linux.com;
root /data/web;
location / {
index index.html;
}
}
然后在节点 2 的 web 根目录下创建 index.html 文件。
这样负载均衡服务器和后端服务器已经搭建完成,现在在浏览器中输入负载均衡服务器的 ip,不停地刷新,结果会交替返回节点 1 和节点 2 的 web 页面。
8.Nginx 的缓存服务器应用
这里使用的是 Nginx 自带的缓存模块,通过 proxy_cache 指令来实现。用于反向代理时对后端 web 服务器进行缓存。这里的实验以前一小节搭建负载均衡服务器为前提。在负载均衡服务器上设置缓存。nginx.conf 文件中增加的内容如下:
http {
…
proxy_cache_path /data/cache levels=1:2 keys_zone=cache_one:1m inactive=1h max_size=1g;
proxy_temp_path /data/temp_cache;
server {
…
location / {
proxy_cache cache_one;
proxy_cache_valid 200 304 302 12h;
proxy_cache_key $host$uri$is_args$args;
proxy_set_header Host $host;
proxy_set_header X-Forward-For $remote_addr;
proxy_pass http://webserver;
expires 1d;
}
}
}
proxy_cache_path
/data/cache 定义缓存文件的目录
levels=1:2 定义目录深度,并且第一层目录为 1 个字符,第二层目录为 2 个字符。
缓存文件是以 proxy_cache_key 指令定义的 key 值进行 hash 得到的结果,例如生成的缓存文件为 f9e228c5ead32aa97fe65df97a5b8196,从文件名的最右边开始,第一层目录的目录名为 6,第二层目录的目录名为 19。
keys_zone cache_one 为自定义的缓存区的名称,1m 表示内存缓存空间大小为 1M
inactive 定义自动清除没有第二次访问的缓存文件的时间
max_size 当内存缓冲空间不足时,需要将缓存文件放到硬盘中,这里的 max_size 为存放缓存文件的硬盘空间最大值
proxy_temp_path 定义临时缓存文件路径
proxy_cache 反向代理设置缓存的指令,格式为 proxy_cache zone|off,关闭为 off,开启直接写keys_zone 指令定义缓存区名称
proxy_cache_valid 对不同 http 状态码的页面设置不同的缓存时间
proxy_cache_key 定义以什么样的 key 值得到文件名
这样反向代理缓存已经配置完成,重启 nginx,然后在查看进程状态,当出现 cache manager process 进程时表明缓存已经建立成功。
并且生成了缓存文件目录。
最后在浏览器中输入负载均衡服务器的 ip 地址,当返回页面内容的时候,查看 /data/cache/ 目录,结果生成了缓存文件。
查看该缓存文件正是刚才返回的页面的请求头信息和页面内容信息。
9.Nginx 的性能优化
提高 Nginx 进程和 CPU 的亲缘性,减少进程上下文的切换
worker_process 开启 worker 进程数
worker_cpu_affinity 开启利用多核 cpu,将 worker 进程绑定至 CPU,提高 CPU 的性能
例如: 两核 CPU,两个进程
worker_process 2;
worker_cpu_affinity 01 10;
目的:
提高 CPU 的缓存命中率,设置 worker 进程数和 CPU 核心数一致,并且将一个 worker 进程绑定至一个 CPU 核心,这样就可以避免 CPU 缓存从一个核心切换到另一个核心,减少进程上下文的切换的时间。当然上诉情况仅用于 CPU 密集型,对于网络密集型和 I / O 密集型的情况,可以设置 CPU 核心数是 worker 进程数的 1.5- 2 倍。
taskset 命令
查看某个进程运行在哪个 CPU 核心上。可以将某个进程运行在指定的 CPU 核心上
taskset -pc PID 查看 PID 的进程运行在哪个 CPU 核心
taskset -c <CPU 核心 > < 指定命令 > 定义指定命令开启的进程运行在指定 CPU 核心
[root@CentOS6 ~]# ps -ef |grep ping
root 13707 8104 0 11:14 pts/0 00:00:00 /bin/ping www.baidu.com
root 13709 9069 0 11:14 pts/1 00:00:00 grep ping
[root@CentOS6 ~]# taskset -pc 13707
pid 13707’s current affinity list: 0,1
[root@CentOS6 ~]# ps -ef |grep ping
root 13729 8104 0 11:18 pts/0 00:00:00 /bin/ping www.baidu.com
root 13731 9069 0 11:18 pts/1 00:00:00 grep ping
[root@CentOS6 ~]# taskset -pc 13729
pid 13729’s current affinity list: 0
提高处理性能
开启 epoll 事件处理模型,提高处理效率 –use epoll
multi_accept 开启多请求处理机制,worker 按串行方式处理连接,一个连接只有一个 worker,其他的 worker 处于休眠状态 –multi_accept on
sendfile on 避免内核缓冲区数据和用户缓冲区数据之间的拷贝
提高并发
worker_connections 决定允许客户端每个进程的最大连接数,一般 65535 足够了 –worker_connection 65535
worker_rlimit_nofile 能够打开的最大文件数 –worker_rlimit_nofile 65535
提高连接复用率
keepalive_timeout 60 连接超时时间
tcp_nodelay on 提高高频发送小数据报文的实时性
tcp_nopush on 允许将 http 首部和内容在同一个报文中发送
开启 Nginx 压缩功能,节省带宽
gzip on
gzip_comp_level 3 压缩比,1-9,默认是 1
gzip_min_length 设置页面开始压缩的最小字节数,默认为 0,建议设置为 1K,小于 1K 的页面压缩效果不好。
页面的字节数就是 http 头的 Content_Length
gzip_buffers 设置内存大小作为压缩缓存
例如 gzip_buffers 4 16K 设置 4 个 16KB 的内存作为压缩缓存
gzip_http_version 设置 http 协议版本,默认 1.1 即可
gzip_types 指定被压缩文件的类型
gzip_vary on 让前端的缓存服务器缓存经过压缩的页面
fastcgi 性能优化
fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=TEST:10m inactive=5m
fastcgi 缓存文件路径,目录等级结构、关键字区域存储时间和非活动删除时间
fastcgi_connect_timeout 指定连接到后端 fastcgi 的超时时间
fastcgi_send_timeout 指定向 fastcgi 传送请求的超时时间
fastcgi_read_timeout 指定接受 fastcgi 应答的超时时间
fastcgi_buffer_size 指定读取 fastcgi 应答第一部分需要大多的缓冲区
fastcgi_buffers 指定本地需要多少和多大的缓冲区来缓冲 fastcgi 的应答请求
php-fpm 参数优化(php-fpm 的配置文件)
request_terminate_timeout 脚本运行超时时间
pm = dynamic | static 调整 php-fpm 进程的工作模式
pm.max_children 静态模式下的 php-fpm 进程数量
pm.start_servers 动态模式下的 php-fpm 的起始进程数量
pm.min_spare_servers 动态模式下的 php-fpm 的最小进程数量
pm.max_spare_servers 动态模式下的 php-fpm 的最大进程数量
pm.max_requests php-fpm 进程处理多少个请求后销毁
request_slowlog_timeout 慢查询日志时间
slowlog 慢查询日志路径
rlimit_files 打开的最大文件数
针对 Nginx 的 Linux 内核参数优化
net.ipv4.tcp_syncookies = 1 开启 SYN cookies
net.ipv4.tcp_max_tw_buckets = 6000 设置 timewait 的数量
net.ipv4.ip_local_port_range = 1024 65000 设置允许系统打开的端口范围
net.ipv4.tcp_tw_recycle = 1 启用 timewait 的快速回收
net.ipv4.tcp_tw_reuse = 1 启用 timewait 的重用,就是将 TIME-WAIT sockets 重新用于新的 tcp 连接
net.core.somaxconn = 262144 设置系统同时发起的 tcp 连接数
net.core.netdev_max_backlog = 262144 当网络接口接受数据包的速率大于内核处理速率的时候,设置发送到队列的数据包的最大数量
net.ipv4.tcp_max_orphans = 262144 设置系统最多多少个 TCP 套接字不被关联到用户文件句柄
net.ipv4.tcp_max_syn_backlog = 262144 设置尚未收到客户端确认信息的最大连接请求最大值
net.ipv4.tcp_synack_retries = 1 设置内核放弃连接之前发送 syn + ack 数据包的数量
net.ipv4.tcp_syn_retries = 1 设置内核放弃建立连接之前发送 syn 数据包的数量
net.ipv4.tcp_fin_timeout = 1 设置套接字保持在 FIN-WAIT- 2 状态的时间
net.ipv4.tcp_keepalive_time = 30 TCP 发送 keepalive 消息的频度,单位是小时
10.Nginx 的 I / O 模型
Web 服务器的网络 I / O 流程:
(1)客户发起请求到服务器网卡;
(2)服务器网卡接受到请求后转交给内核处理;
(3)内核根据请求对应的套接字,将请求交给工作在用户空间的 Web 服务器进程
(4)Web 服务器进程根据用户请求,向内核进行系统调用,申请获取相应资源(如 index.html)
(5)内核发现 web 服务器进程请求的是一个存放在硬盘上的资源,因此通过驱动程序连接磁盘
(6)内核调度磁盘,获取需要的资源
(7)内核将资源存放在自己的缓冲区中,并通知 Web 服务器进程
(8)Web 服务器进程通过系统调用取得资源,并将其复制到进程自己的缓冲区中
(9)Web 服务器进程形成响应,通过系统调用再次发给内核以响应用户请求
(10)内核将响应发送至网卡
(11)网卡发送响应给用户
用户请求 –> 送达到用户空间 –> 系统调用 –> 内核空间 –> 内核到磁盘上读取网页资源 -> 返回到用户空间 -> 响应给用户。
客户端向 Web 服务器请求的过程中,有两个 I / O 过程,一个就是客户端请求的 I /O,另一个就是 Web 服务器请求页面的磁盘 I /O
I/ O 模型
同步 / 异步(以被调用者是否有消息通知机制为依据)
同步 – 调用者主动等待被调用者返回结果
异步 – 调用者只需被调用者的消息通知,期间无需特地等待结果
阻塞 / 非阻塞(以调用者等待结果之前的状态为依据)
阻塞 – 结果返回之前,调用者被挂起
非阻塞 – 结果返回之前,调用者不会被挂起
通常就是同步阻塞和异步非阻塞,Nginx 采用的就是异步非堵塞 I / O 模型。
例子:
①老王以传统的水壶烧水,老王相当于调用者,水壶相当于被调用者,老王必须一直盯着水壶,等待水烧开,这就是 同步,后来老王换了一个响水壶,可以在水烧开的时候发出响声(加入消息通知机制),老王再也不用死盯着水壶(无需等待),水烧开的时候,发出响声通知老王即可,这就是异步。
②水壶在烧水的期间,老王不干别的事情,这就是 堵塞,水壶在烧水的期间,老王去看个电视啥的,这就是非堵塞。
I/ O 复用
进程可以监听多个文件描述符
select–I/ O 复用模型,监听端口数量受限于 /proc/sys/fs/file-max,采用轮询方式扫描端口
poll–I/ O 复用模型,本质和 select 没有区别,poll 将数据放置在内核空间,select 将数据放置在用户空间,放置在内核空间之后,效率提高,并且最大连接数没有限制
epoll–I/ O 复用模型,select 和 poll 的增强版
: