Nginx

一、简介

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好。

二、windows环境的下载与安装

nginx官网下载地址如下:

http://nginx.org/en/download.html

第一步:下载该文件,下载后的文件如下图所示:

第二步:对该文件进行解压

       

第三步:控制台中切换到Nginx的解压目录下面,使用start nginx.exe命令启动Nginx

start nginx.exe

第四步: Nginx启动成功后,可以在任务管理器中看到Nginx的进程

第五步:在浏览器中输入127.0.0.1,可以看到nginx欢迎界面

         

提示:Nginx解压目录\logs目录下面存放着Nginx的日志文件,除了日志文件以外,这个目录下面还会有一个名为“ nginx.pid ”的文件(使用下面的 服务停止命令 以后,该文件会被自动删除)。

打开 nginx.pid 这个文件,可以看到里面是一个进程号: 

如果我们想停止nginx服务,则可以使用下述命令:

nginx.exe -s stop

三、Nginx的配置文件说明

#是用来显示是谁运行的NGINX
user  nobody;

#指明了nginx要开启的进程数,一般情况下开一个就行了,不到万不得一不要更改这个配置,更改以后需要根据实际情况做一下测试,选出最合适的进程数(取值范围为1-CPU核心数)
worker_processes 1

#设置操作记录日志文件的位置,此处使用的是相对路径
error_log  logs/error.log;
#设置日志的级别为notice
error_log  logs/error.log  notice;
#设置日志的级别为info
error_log  logs/error.log  info;

#进程号文件保存设置:nginx.pid文件就是一个纯文本文件,里面记录的是进程的pid号,此处默认使用相对路径,一般不建议更改
pid        logs/nginx.pid;


#events模块来用指定nginx的工作模式和工作模式下每个进程的连接数上限
#use用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,对于Linux系统,epoll工作模式是首选。
#worker_connections用于定义Nginx每个进程的最大连接数,即接收前端的最大请求数,默认是1024。最大客户端连接数由worker_processes和worker_connections决定,即Max_clients=worker_processes*worker_connections。在作为反向代理时,Max_clients变为:Max_clients = worker_processes * worker_connections/4
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表示设置局部访问记录日志
    access_log    logs/access.log  main;
    sendfile      on;
    keepalive_timeout  65;
    server {
        listen       8080;
        server_name  localhost;
        access_log   logs/access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        };
        error_page   500 502 503 504  /50x.html;
    }
}

http模块
include:表示纳入mine.types文件的配置

default_type:如果Web程序没设置,Nginx也没找到对应文件的扩展名的话,就使用默认的Type:default_type application/octet-stream,这是应用程序文件类型的默认值。application/octet-stream是HTTP规范中Content-Type的一种,意思是未知的应用程序文件

3.1 log_format

该配置行的作用为定义日志格式,其有下述9个参数可以配置:

$remote_addr:记录访问网站的客户端地址,例如打印为127.0.0.1

$remote_user:远程客户端用户名,一般没有值,没有值的时候打印为"-"

$time_local:记录访问时间与时区,例如打印为29/Apr/2020:18:51:29 +0800

$request:用户的http请求起始行信息,例如打印为GET / HTTP/1.1

$status:记录请求返回的http状态码,例如:200、301、404等

$body_bytes_sent:服务器发送给客户端的响应body字节数,例如取值为612

$http_referer:记录此次请求是从哪个连接访问过来的,可以根据该参数进行防盗链设置,例如打印为127.0.0.1,如果是直接访问url,则其打印值为"-"

$http_user_agent:浏览页面的访问者在用什么操作系统,例如:浏览器、手机客户端等,例如打印为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36

$http_x_forwarded_for:当前端有代理服务器时,设置web节点记录客户端地址的配置,此参数生效的前提是代理服务器也要进行相关的x_forwarded_for设置(注意:这个参数一般用不上,了解即可)

如下图所示,在nginx.conf配置文件中使用 log_format 定义一个名为main的日志格式并且设置访问日志的打印格式:

3.2 access_log

用来指定访问日志文件的路径及使用何种日志格式记录日志,此处示例中配置的main,其实就是一个日志格式标签名,引用该格式进行日志打印。 

access_log默认的配置如上所示,可以看到有两个地方引用了这个。如果没有修改默认的配置,我们直接启动Nginx,可以看到在logs目录下会自动新增一个名为access.log的日志文件,

浏览器中访问下述地址,这时可以看到在access.log日志文件中会新增一些访问日志:

http://127.0.0.1/

虽然第一处的access.log配置没有打开,但其实它是默认生效的!!!

如果同时开启第一处和第二处的access.log配置,可以看到在logs目录下会自动新增access.log的和“host.access.log两个日志文件。

特别提示:开启access_log配置时,log_format配置也要一起开启!!!

再次访问上述测试地址,可以看到这时只有host.access.log文件中有访问日志,而access.log日志文件中是没有访问日志。

这时如果我们再新增一个端口8081进行监听,关闭了server模块中的access.log配置,然后再在浏览器中访问下述测试地址:

http://127.0.0.1:8081/

可以看到这时8081服务的访问日志只会在access.log日志文件中输出,而host.access.log文件中是没有其相关的访问日志。

总结 

  1. 即使没有开启任何日志输出,默认情况下http模块中的access_log配置会生效。
  2. http模块中的access_log配置是属于全局的配置,如果server模块中没有开启access_log配置,则生效的是全局配置。
  3. server模块中开启了access_log配置,则http模块中的access_log全局配置相对于所监听端口服务而言会失效,访问日志只会输出在指定文件中。
  4. 多个端口监听时,可以通过各自server模块中的access_log配置使其访问日志输出在各自的日志文件。

3.3 sendfile

nginx的http模块中有一个sendfile指令,默认是开启状态。

简单来说就是启用sendfile()系统调用来替换read()和write()函数调用,减少系统上下文切换从而提高性能,当nginx是静态文件服务器时,能极大提高nginx的性能表现,而当nginx是反向代理服务器时,则没什么用了。

下面我们来分析一下这个sendfile的工作原理

首先我们需要知道sendfile()和read()、write()之间最大的区别就是前者是属于系统调用,而后者是属于函数调用,我们来看下面这幅图。

我们不难看出,nginx是属于Applicaiton的,而read()、write()属于函数调用,也就是在Lib Func这一层,sendfile()属于系统调用,位于System Call这一层,而想要对硬盘进行操作,是Kernel才有的权限,上面的那些层都需要往下调用。 

作为对比我们先来看一下正常情况下如果nginx调用read()和write()函数的操作过程:我们都知道数据是存储在硬盘上面的,当数据被调用的时候会被加载进内存再被层层递进最后被CPU使用,这里这个过程我们进行简化,共包含下述4个步骤。

  • 步骤一:首先nginx调用read函数,这时data从Hard Disk被加载进Kernel Buffer(Hard Disk)中,此时是从一开始的用户态(user mode)陷入内核态(kernel mode)才能完成操作。
  • 步骤二:接着由于data需要被write()函数进行操作,所以data还需从Kernel Buffer(Hard Disk)传输到User Buffer中,此时从内核态(kernel mode)切换回用户态(user mode)
  • 步骤三:再接着data被write()函数从user buffer写入到Kernel Buffer(Socket Engine),此时从用户态(user mode)陷入内核态(kernel mode)
  • 步骤四:data从Kernel Buffer(Socket Engine)传输到Socket Engine,此时从内核态(kernel mode)切换回用户态(user mode)

这里需要说明两点,一是用户态和内核态之间的切换是需要执行上下文切换操作的,这是十分耗费系统资源和时间的操作,二是因为read()、write()属于函数调用,它们是没有权限在kernel中操作,无法将data直接从Kernel Buffer(Hard Disk)传输到Kernel Buffer(Socket Engine)。

那么使用sendfile()呢?由于是系统调用,所以在步骤二和步骤三的时候就可以不需要再将数据传输到User Buffer,直接在kernel中进行操作,省去了两次状态切换,也就是省去了两次的上下文切换,从而大幅度提升了性能。

我们来看一下下面的这幅图:

最后我们再来解释一下,为什么当 nginx 是反向代理服务器时,sendfile()就没什么用了呢。

顾名思义,sendfile()的作用是发送文件,也就是接收数据的一段是文件句柄,发送数据的那一端是socket。而在做反向代理服务器的时候,两端都是socket,此时无法使用sendfile(),也就不存在性能提升这一说了。 

sendfile设置为on表示启动高效传输文件的模式。sendfile可以让Nginx在传输文件时直接在磁盘和tcp socket之间传输数据。如果这个参数不开启,会先在用户空间(Nginx进程空间)申请一个buffer,用read函数把数据从磁盘读到cache,再从cache读取到用户空间的buffer,再用write函数把数据从用户空间的buffer写入到内核的buffer,最后到tcp socket。开启这个参数后可以让数据不用经过用户buffer。

参考资料: 

官网的文档: http://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile
aio:http://nginx.org/en/docs/http/ngx_http_core_module.html#aio
read_ahead:http://nginx.org/en/docs/http/ngx_http_core_module.html#read_ahead

3.4 keepalive_timeout

该参数表示是一个请求完成之后还要保持连接多久,不是请求时间多久,目的是保持长连接,减少创建连接过程给系统带来的性能损耗,类似于线程池,数据库连接池。

keepalive_timeout的值为0时,则表示不启用长连接。

3.5 listen

server模块中有一个listen指令,表示所监听的端口

如上所示,该server模块监听的端口为80,当所部署的机器收到80端口的相关请求时就会被Nginx监听到,然后再按照其配置规则进行处理。

3.6 server_name

用于设置虚拟主机服务名称,这个还没有测试出具体的效果,真正使用时再深入一下。

3.7 root

server模块中的root设置的是根文件夹的目录路径,该路径可以是一个相对路径(相对于nginx的安装目录来说的)

例如在E:\nginx-1.23.1\html目录下创建了一个newpage目录

然后将原本位于E:\nginx-1.23.1\html目录下的index.html文件迁移到E:\nginx-1.23.1\html\newPage目录中

index.html文件中的内容如下,这是一个非常好看的前端访问页面的HTML代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        html {
            height: 100%;
        }
        body {
            height: 100%;
        }
        .container {
            height: 100%;
            background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);
        }
        .login-wrapper {
            background-color: #fff;
            width: 358px;
            height: 588px;
            border-radius: 15px;
            padding: 0 50px;
            position: relative;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
        }
        .header {
            font-size: 38px;
            font-weight: bold;
            text-align: center;
            line-height: 200px;
        }
        .input-item {
            display: block;
            width: 100%;
            margin-bottom: 20px;
            border: 0;
            padding: 10px;
            border-bottom: 1px solid rgb(128, 125, 125);
            font-size: 15px;
            outline: none;
        }
        .input-item:placeholder {
            text-transform: uppercase;
        }
        .btn {
            text-align: center;
            padding: 10px;
            width: 100%;
            margin-top: 40px;
            background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);
            color: #fff;
        }
        .msg {
            text-align: center;
            line-height: 88px;
        }
        a {
            text-decoration-line: none;
            color: #abc1ee;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="login-wrapper">
            <div class="header">Login</div>
            <div class="form-wrapper">
                <input type="text" name="username" placeholder="username" class="input-item">
                <input type="password" name="password" placeholder="password" class="input-item">
                <div class="btn">Login</div>
            </div>
            <div class="msg">
                Don't have account?
                <a href="#">Sign up</a>
            </div>
        </div>
    </div>
</body>
</html>

这时如果我们想在访问下述地址时,可以访问到该登录页面,有两种配置方式。

http://127.0.0.1/

第一种配置方式:使用相对路径

特别提示:如果html目录下创建的是index这么一个目录,那么此处的配置可以为 html\index。这个地方要留意下斜杠和反斜杠的方向,上述示例中不能写成 html\newpage,因为root 路径中的 \n 会被识别成了换行符号,这样会导致root路径错误,Nginx服务启动不会报错,但是在访问相关页面时就会报错。

针对上述问题,其解决方案如下:

第一种:把 \n 换成 /n

第二种:把 \n 换成 \\n

第二种配置方式:使用绝对路径

或者

  

3.8 index

设置启动Nginx后默认的访问根文件夹下面的哪一个页面,如下图所示,当找不到index.html时,就会去找下一个index.htm文件,依次类推

3.9 error_page

error_page的作用是当发生错误的时候能够显示一个预定义的uri,如下图所示,Nginx的配置文件nginx.conf中默认有两处error_page的使用: 

第一处虽然是使用 注释起来了,但是这个是默认生效的,如果我们访问一个不存在的资源时就会跳转到默认的404页面。

第二处的error_page配置是开启的,当访问出现502、503的时候就能返回50x.html中的内容,这里需要注意是否可以找到50x.html页面,所以加了个location保证找到你自定义的50x页面。

同时我们自己也可以定义上述这种情况下的返回状态码,比如:

error_page 500 502 503 504 =200 /50x.html;
location = /50x.html {
    root html;
}   

这样用户访问产生500、502 、503的时候给用户的返回状态是200,内容是50x.html。

自定义404错误页面配置中有无等号的区别:

  • error_page 404 /404.html 可显示自定义404页面内容,正常返回404状态码。
  • error_page 404 = /404.html 可显示自定义404页面内容,但返回200状态码。 
server  {
    listen 80;
    server_name  test.com;
    index       index.html index.htm;

    location / { 
        proxy_pass http://online;
        error_page 404 = @fallback;
        proxy_intercept_errors on;
    }
    location @fallback {
        proxy_pass http://backend;
    }

}

upstream online {
         server 192.168.1.108:80;
         server 192.168.1.109:80;
}

upstream backend {
         server 192.168.1.110:80;
}

由于在nginx配置中,设置了limit_req的流量限制,导致许多请求返回503错误代码,在限流的条件下,为提高用户体验,希望返回正常 Code 200,且返回操作频繁的信息:

location  /test {
  ...
  limit_req zone=zone_ip_rm burst=1 nodelay; 
  error_page 503 =200 /dealwith_503?callback=$arg_callback;
}
location /dealwith_503{ 
  set $ret_body '{"code": "V00006","msg": "操作太频繁了,请坐下来喝杯茶。"}';
   if ( $arg_callback != "" ) 
   { 
       return 200 'try{$arg_callback($ret_body)}catch(e){}'; 
   } 
   return 200 $ret_body; 
}

PS:上述这一段限流配置我测试过,但是没有按照我的预期生效。

如果在服务Down掉或者频繁访问导致超时时,仍然返回http status为200的json格式数据,最简单的格式如下:

server{
    # 错误页面返回JSON配置
    error_page 403 = /respon_403.json;
    location = /respon_403.json {
        default_type application/json;
        return 200 '{"code":"403","data":null,"message":"请登录"}';
    }

    error_page 404 = /respon_404.json;
    location = /respon_404.json {
        default_type application/json;
        return 200 '{"code":"404","data":null,"message":"没找到请求,请稍后再试~"}';
    }
}

进行接口调用测试,这时就会把上述定义好的信息返回: 

四、反向代理

反向代理和负载均衡配置:

官方配置:http://nginx.org/en/docs
Nginx反向代理proxy与负载均衡upstream
1.配置反向代理proxy
location ~ \.jsp${           //区分大小写,以jsp结尾的请求,适合动静分离 
	//设置客户端真实的ip地址
	proxy_set_header X-real-ip $remote_addr;
//负载均衡反向代理
proxy_pass http://192.168.1.171:8080
}

2.配置负载均衡upstream
upstream myapp{
	server 192.168.1.171:8080 weight=1 max_fails=2 fail_timeout=30s;
	server 192.168.1.172:8080 weight=1 max_fails=2 fail_timeout=30s;
}
注意:此处的upstream是配置在server模块外面的,不在server模块里面
weight:表示权重
max_fails:表示如果有两次请求过来都连接失败的话,表示该节点挂了
fail_timeout:表示连接失败的超时时间为30s

location{
	//设置客户端真实的ip地址
	proxy_set_header X-real-ip $remote_addr;
	//负载均衡反向代理
	proxy_pass http://myapp;
}

五、负载均衡

详解 nginx location ~ .*\.(js|css)?$ 什么意思? - 费元星的博客 - 博客园

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值