网站建设

玩转Nginx

Jaydon · 12月15日 · 2018年

第一章 基础篇

1.1 Nginx介绍

Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。

最早由俄罗斯的程序设计师IgorSysoev所开发,并在一个BSD-like协议下发行。

其特点是轻量级,占有内存少,并发能力强,目前发展势头强劲。

web领域最经典的lamp组合已变成lnmp组合。

1.2 Nginx编译与启动

1.2.1 编译安装

到官方网站 http://nginx.org 寻找最新stable版,下载

例当前最新: http://nginx.org/download/nginx-1.12.0.tar.gz

安装准备: nginx依赖于pcre库,要先安装pcre

#yum install pcre pcre-devel​

#cd /usr/local/src/

​#wget http://nginx.org/download/nginx-1.12.0.tar.gz​

# tar zxvf nginx-1.12.0.tar.gz​

#cd nginx-1.12.0

​./configure --prefix=/var/local/nginx4

​#make && make install

为什么要先安装pcre? 因为:nginx要在rewrite时要解析正则表达式,PCRE是正则解析库

1.2.2 nginx目录介绍:

cd /var/local/nginx3, 看到如下4个目录

conf    配置文件

html   项目文件

logs    日志文件

sbin   主要二进制程序

1.2.3 启动nginx

/var/local/nginx3/sbin/nginx

没有出现错误提示,则启动成功了.

如果有错误,则根据错误提示再做处理.

常见的错误是”80端口被占用”

1.2.4 80端口被占用的解决

如果出现不能绑定80端口,80端口已经被占用

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] still could not bind()

(有时是自己装了apache,nginx等,还有更多情况是操作系统自带了apache并作为服务启动)

解决: 把占用80端口的软件或服务关闭即可.

如果是linux系统自带apache且自动启动. service httpd stop

如果是自行编译安装的,可以#/path/to/apacht/bin/apachctl stop

1.3 Nginx控制命令

nginx -t                   测试配置是否正确

nginx -s reload     作用:加载最新配置

nginx -s stop          作用: 立即停止

nginx -s quit           作用: 优雅停止

nginx -s reopen     作用: 重新打开日志

Kill     -信号      nginx的主进程号

TERM, INT      快速关闭

QUIT                优雅关闭

HUP                  重载配置用新的配置开始新的工作进程 从容关闭旧的工作进程

USR1                 重新打开日志文件

USR2                 平滑升级可执行程序。

第二章 应用篇

2.1 Nginx配置段详解

// 全局区
// 有1个工作的子进程,可以自行修改,但太大无益,因为要争夺CPU,
// 一般设置为 CPU数*核数
worker_processes 1;
Events {
// 一般是配置nginx连接的特性
// 如1个worker能同时允许多少连接 worker_connections 1024;
// 这是指 一个子进程最大允许连1024个连接
}
http {  //这是配置http服务器的主要段
      Server1{ // 这是虚拟主机段
         Location { //定位,把特殊的路径或文件再次定位 ,如image目录单独处理
         }    // 如.php单独处理 
     } 
      Server2{ 
         }
}

2.2 Nginx置虚拟主机

例1: 基于域名的虚拟主机

    server {
       listen 80;  #监听端口
       server_name a.com; #监听域名,如有多个,空格隔开
       location / {
               root /www/a.com;   #根目录定位
               index index.html;  #默认索引页
        }
    }

例2: 基于端口的虚拟主机配置

 server {
       listen 8080;
       server_name a.com;
       location / {
               root /www/b.com;
               index index.html;
        }
    }

2.3 日志管理

我们观察nginx的server段,可以看到如下类似信息

access_log logs/access.log main;

这说明 该server, 它的访问日志的文件是 logs/host.access.log ,

日志格式”main”格式.

main格式是什么?

   #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

除了main格式,你可以自定义其他格式.

log_format  mylog  'remote_addr [time_local]"$request" '

                      'status body_bytes_sent"$http_referer" '

                      '"$http_user_agent"';
server {

listen 80;
        #下面声明a.com使用mylog格式日志,并保存在logs/a.com.log文件中
       access_log logs/a.com.log mylog;
       server_name a.com www.a.com;
       ....

}

main格式是我们定义好一种日志的格式,并起个名字,便于引用.

以上面的例子, main类型的日志,记录的 remote_addr.... http_x_forwarded_for等选项.

1: 日志格式 是指记录哪些选项

如默认的main日志格式,记录这么几项

远程IP- 远程用户/用户时间 请求方法(如GET/POST) 请求体body长度 referer来源信息

http-user-agent用户代理/蜘蛛 ,被转发的请求的原始IP

http_x_forwarded_for:在经过代理时,代理把你的本来IP加在此头信息中,传输你的原始IP

实际应用: shell+定时任务+nginx信号管理,完成日志按日期存储

分析思路:

凌晨00:00:01,把昨天的日志重命名,放在相应的目录下

再USR1信息号控制nginx重新生成新的日志文件

具体脚本:

#!/bin/bash

base_path='/usr/local/nginx/logs'

log_path=$(date -d yesterday +"%Y%m")

day=$(date -d yesterday +"%d")

mkdir -p base_path/log_path

mv base_path/access.logbase_path/log_path/access_day.log

#echo base_path/log_path/access_$day.log

/usr/local/nginx/sbin/nginx -s reopen

定时任务

Crontab 编辑定时任务

01 00 * * * /xxx/path/b.sh

每天0时1分(建议在02-04点之间,系统负载小)

2.4 location

location 有”定位”的意思, 根据Uri来进行不同的定位.

在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上.比如, 碰到.php, 如何调用PHP解释器? --这时就需要location

location 的语法

location [=|~|~*|^~] patt {}

中括号可以不写任何参数,此时称为一般匹配

也可以写参数

因此,大类型可以分为3种

  • location = patt {} [精准匹配]
  • location patt{} [一般匹配]
  • location ~ patt{} [正则匹配]

如何发挥作用?:首先看有没有精准匹配,如果有,则停止匹配过程

location = patt{config A}

如果 $uri == patt,匹配成功,使用configA

location = / {

root    /var/www/html/;

index    index.htm index.html;

}

location / {

root    /usr/local/nginx/html;

index    index.html index.htm;

}

如果访问http://xxx.com/定位流程是:

  1. 精准匹配中”/” ,得到index页为index.htm
  2. 再次访问 /index.htm , 此次内部转跳uri已经是”/index.htm” , 根目录为/usr/local/nginx/html
  3. 最终结果,访问了 /usr/local/nginx/html/index.htm

再来看,正则也来参与

location / {

root       /usr/local/nginx/html;

index    index.html index.htm;

}

location ~ image {

root     /var/www/image;

index    index.html;

}

如果我们访问 http://xx.com/image/logo.png

此时, “/” 与”/image/logo.png” 匹配

同时,”image”正则 与”image/logo.png”也能匹配,

谁发挥作用?正则表达式的成果将会使用.

图片真正会访问 /var/www/image/logo.png

location / {

root      /usr/local/nginx/html;

index    index.html index.htm;

}

location /foo {

root    /var/www/html;

index    index.html;

}

我们访问 http://xxx.com/foo

对于uri “/foo”, 两个location的patt,都能匹配他们

即 ‘/’能从左前缀匹配 ‘/foo’,

‘/foo’也能左前缀匹配’/foo’

此时, 真正访问 /var/www/html/index.html

原因:’/foo’匹配的更长,因此使用之.;

第三章 实战篇:

3.1 Nginx 与PHP整合

nginx+php的编译

apache一般是把php当做自己的一个模块来启动的.

而nginx则是把http请求变量(如get,user_agent等)转发给 php进程,即php独立进程,与nginx进行通信. 称为 fastcgi运行方式.

因此,为apache所编译的php,是不能用于nginx的.

编译的PHP 要有如下功能:

连接mysql, gd,ttf, 以fpm(fascgi)方式运行

./configure --prefix=/var/local/php5 \

--with-mysql=mysqlnd \

--enable-mysqlnd \

--with-gd \

--enable-gd-native-ttf \

--enable-gd-jis-conv \

--enable-fpm

编译完毕后, copy配置文件

cp/path/to/php-fpm.conf.default /path/to/php-fpm.conf

nginx+php的配置比较简单,核心就一句话----

把请求的信息转发给9000端口的PHP进程,

让PHP进程处理 指定目录下的PHP文件.

如下例子:

location ~ .php$ {

           root html;

           fastcgi_pass   127.0.0.1:9000;

           fastcgi_index  index.php;

           fastcgi_param SCRIPT_FILENAME document_rootfastcgi_script_name;

           include        fastcgi_params;
       }

1:碰到php文件,

2: 把根目录定位到 html,

3: 把请求上下文转交给9000端口PHP进程,

4: 并告诉PHP进程,当前的脚本是document_rootfastcgi_scriptname

(注:PHP会去找这个脚本并处理,所以脚本的位置要指对)

3.2 pathinfo支持

# 典型配置

location ~ .php$ {

    root           html;

   fastcgi_pass   127.0.0.1:9000;

   fastcgi_index  index.php;

   fastcgi_param SCRIPT_FILENAME  DOCUMENT_ROOTfastcgi_script_name;

   include        fastcgi_params;

}

# 修改,支持pathinfo

location ~ \.php(.*)$ { # 正则匹配.php前后的script_name和pathinfo部分

    root html;

   fastcgi_pass   127.0.0.1:9000;

   fastcgi_index  index.php;

   fastcgi_param  SCRIPT_FILENAME  DOCUMENT_ROOTfastcgi_script_name;

   fastcgi_param PATH_INFO $1; # 把pathinfo部分赋给PATH_INFO变量

   include        fastcgi_params;

}

3.2 Nginx与Rewrite规则

Rewrite语法

Rewrite 正则表达式 定向后的位置 模式

重写中用到的指令

if  (条件) {}  设定条件,再进行重写 

set #设置变量

return #返回状态码 

break #跳出rewrite

rewrite #重写

If  语法格式

If 空格 (条件) {

    重写模式

}

条件又怎么写?

答:3种写法

  1.  “=”来判断相等, 用于字符串比较
  2.  “~” 用正则来匹配(此处的正则区分大小写) ~* 不区分大小写的正则
  3. -f -d -e来判断是否为文件,为目录,是否存在.

例子:

      if  ($remote_addr = 192.168.1.100) {
            return 403;
        }
        if ($http_user_agent ~ MSIE) {
            rewrite ^.*$ /ie.htm;
            break; #(不break会循环重定向)
         }
        if (!-e $document_root$fastcgi_script_name) {
            rewrite ^.*$ /404.html break;
        } 
        注, 此处还要加break,

以 xx.com/dsafsd.html这个不存在页面为例

我们观察访问日志, 日志中显示的访问路径,依然是GET /dsafsd.html HTTP/1.1

提示: 服务器内部的rewrite和302跳转不一样

跳转的话URL都变了,变成重新http请求404.html, 而内部rewrite, 上下文没变

就是说 fastcgi_script_name 仍然是 dsafsd.html,因此 会循环重定向

set 是设置变量用的, 可以用来达到多条件判断时作标志用

达到apache下的 rewrite_condition的效果

如下: 判断IE并重写,且不用break; 我们用set变量来达到目的


if ($http_user_agent ~* msie) {

set $isie 1;

}

if ($fastcgi_script_name = ie.html) {

set $isie 0;

}

if ($isie 1) {

rewrite ^.*$ ie.html;

}

location / {

index index.php;
if ( !-e $request_filename){
      rewrite (.*)$  /index.php/$1;
}

}

注意:用url重写时, 正则里如果有”{}”,正则要用双引号包起来

3.4 try_files

try_files $uri /index.php?$uri

第四章优化篇:

4.1 Nginx反向代理与动静分离

用nginx做反向代理用proxy_pass

以反向代理为例, nginx不自己处理图片的相关请求,而是把图片的请求转发给apache来处理.

----这就是传说的”动静分离”,动静分离不是一个严谨的说法,叫反向代理比较规范.

配置如下:

location ~ .(jpg|jpeg|png|gif)$ {

proxy_pass HTTP://IP:port;

}

思考:

1: 反向代理导致了后端服务器接到的客户端IP,为前端服务器的IP,而不是客户真正的IP,怎么办?

答: 代理服务器通过设置头信息字段,把用户IP传到后台服务器去.

如:

location ~ .(jpg|jpeg|png|gif)$ {

   proxy_set_header X-Forwarded-For  $remote_addr;
   proxy_pass  IP:port;
}

2: 如果后端的服务器非常多,该如何写? 又如何均匀的分发任务?(负载均衡)

Nginx反向代理与负载均衡

正向代理

反向代理

4.2 Nginx集群与负载均衡

注意:负载均衡是一种方案,实现办法有DNS轮询,DNS服务器允许一个域名有多个A记录,那么在用户访问时,一般按地域返回一个较近的解析记录.这样,全国不同的地区的用户,看到的baidu,来自不同的服务器.

这台主机后面还有N台,也要做负载均衡.

1: 硬件上做负载均衡, F5BIG-IP ,硬件负载均衡(很贵).

直接从TCP/IP的底层协议上,直接做数据包的中转.

2: 软件负载均衡, LVS 3: 反向代理+负载均衡

在nginx中做集群与负载均衡,步骤都是一样的

Upstream {}模块把多台服务器加入到一个组

然后memcached_pass, fastcgi_pass, proxy_pass ==> upstream组

具体配置步骤:

1:配置upstream

upstream imageserver {​

server192.168.1.204:8080 weight=1 max_fails=2 fail_timeout=30s;​ server192.168.1.204:8081 weight=1 max_fails=2 fail_timeout=30s;

}

2: 下游调用

location ~ .(jpg|jpeg|png|gif)$ {

proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://imageserver;

}

默认的负载均衡的算法:

是设置计数器,轮流请求N台服务器.

可以安装第3方模式,来利用不同参数把请求均衡到不同服务器去

如基于cookie值区别用户做负载均衡(nginx sticky 模块)

或基于URI利用一致性哈希算法做均衡(NginxHttpUpstreamConsistentHash模块)

或基于IP做负载均衡等.

0 条回应