(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

GimmeS 2020-01-01

nginx简介

nginx(engine x)是一个高性能的http和反向代理服务器,具有占有内存少、并发能力强等特点,其性能在同类型的网页服务器中表现较好。在中国有大量的网站用户都在使用nginx,比如:京东、新浪、网易等等。当然淘宝也是,不过淘宝基于nginx进行了修改,现在用的是Tengine。

nginx可以作为静态页面的web服务器,同时还支持许多主流编程语言。nginx专门为性能优化而开发,经过测试证明nginx最大能并发支持50000个连接

nginx相关概念

反向代理

nginx百科介绍就是可以作为反向代理服务器,那么什么是反向代理呢?不过在介绍反向代理之前,我们先了解一下正向代理

正向代理

举个通俗的例子,当我们想访问某个资源的时候没办法访问,而是需要通过代理服务器来访问,那么这种代理服务就称之为正向代理

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

事实上,我们挂威批N去访问谷歌(任意网站)的时候,都是先向代理服务器发送请求,然后代理服务器将我们的请求转发给谷歌,然后谷歌将响应的结果返回给代理服务器,然后代理服务器再返回给我们。所以我们的资源实际上是从代理服务器那里获取的,而谷歌接收到的也是代理服务器的请求,我们和谷歌之间没有任何的交互。

反向代理

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

此时的nginx所在的服务器就是反向代理服务器,假设我们部署了多个服务,用户并不会直接访问部署服务的机器、或者说目标服务器,而是会访问反向代理服务器,反向代理服务器会将请求转发到目标服务器上(怎么转化就涉及到了负载均衡),目标服务器返回数据给反向代理服务器,然后反向代理服务器再将内容返回给用户。因此此时反向代理服务器和目标服务器对外就相当于是一个整体,那么暴露给用户的就是反向代理服务器的地址,隐藏了真实服务器的ip地址。

负载均衡

早期访问量不大的时候,都是用户直接访问服务器,服务器处理请求,比如从数据库里面拿数据等等,处理完毕之后,服务器再将结果返回给客户端。但是这种方式只是适用于并发量比较小的情况,如果并发量一多,就会陷入瓶颈。即便是增加机器的硬件配置,对于现如今这个信息量庞大的社会来说,单台机器也是杯水车薪。

因此我们需要采用多台机器的方式,增加服务器的数量。将请求分发到不同的机器上,不会让某台机器承受的负载过重,这就是所谓的覆盖均衡

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

n个请求,理想的情况就是每台服务器都负责n/3个请求,当然事实情况不一定完全相等,但也会尽量使得每台机器上的负载一样。

动静分离

有些请求是访问服务器的某个静态资源,比如我就想查看某一张图片等等,那么直接把图片返回即可,该资源不涉及和其它组件的交互;而那些需要访问缓存、数据库等等则称之为动态资源。因此为了加快网站的解析速度,会把动态资源和静态资源交给不同的服务器来解析,从而降低单个服务器的压力,并且分工更明确。而返回静态资源的任务正好可以交给nginx

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

nginx除了能将请求转发到目标服务器之外,还指向了一台存放静态资源(html、css、图片等等)的服务器,如果用户访问的是静态资源,那么nginx直接从静态资源的服务器将静态资源拿出来返回给用户即可,如果访问动态资源,然后再通过负载均衡转发到目标服务器。

安装nginx

安装nginx我们只介绍如何在linux上安装,因为nginx底层用到了epoll,而这个Windows是不支持的。

docker安装nginx

直接通过docker?pull?nginx拉取nginx镜像即可。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们来看看服务是否可用。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

docker安装是成功了的。

普通安装

如果机器上有一个docker的话,安装nginx很方便。但是我们为了学习nginx,还是要知道nginx直接在linux机器上怎么安装,我们后面讲解的时候也会按照普通安装的方式来讲解。因为学习的是nginx,如果涉及到docker也不太好,毕竟用到了另外一项技术。熟悉nginx的时候,可以推荐docker直接一键部署。

nginx安装的话,直接去http://nginx.org/去下载即可

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们注意到上面有三个版本,mainline?version是增在主力开发的版本,stable?version是最新稳定版本,而legacy?version则是以前的稳定的老版本。我们这里下载最新稳定版,nginx-1.16.1

但是注意的是,nginx需要依赖,否则编译nginx的时候会报错。安装nginx的依赖直接通过yum install gcc gcc-c++ make automake autoconf libtool pcre* zlib openssl openssl-devel安装即可。

安装完依赖之后,解压tar包,进入到nginx目录。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

执行./configure,然后执行make?&&?make install

然后进入到/usr/local目录,会发现一个名为nginx的目录。因为编译完之后,会默认安装到/usr/local目录下面。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们进入到这个目录

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

然后在sbin目录里面会有一个nginx可执行程序。

我们把之前的docker服务停掉,启动现在的nginx,看看能不能访问。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

依旧可以访问,证明安装并且启动成功。

另外,可能会因为防火墙的原因,使得端口未对外开方,导致无法访问,这时候我们需要开放需要让外界访问的端口号。我这里使用的是阿里云,因此可以通过阿里提供的web页面的方式开放端口,如果通过命令的话该怎么做呢?

firewall-cmd --list-all:查看所有开放的端口号

firewall-cmd --add-service=http --permanent

firewall-cmd --add-port=80/tcp --permanent:设置要开放的端口号

firewall-cmd --reload:重启防火墙

nginx的常用命令

  • nginx -v:查看nginx当前的版本号

    (写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

  • nginx:启动nginx

  • nginx -s stop:关闭nginx

  • nginx -s reload:重新加载nginx,如果配置文件修改了,那么无需重启nginx,可以通过重新加载的方式。

nginx配置文件

我们来看看nginx的配置文件长什么样子,nginx的配置文件在nginx目录下的conf目录下,名字为nginx.conf

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

根据配置文件的内容,我们可以将nginx的配置文件分为三部分

第一部分:全局块

从配置文件开始到events块之间的内容,主要会设置一些影响nginx服务器整体运行的配置指令,主要包括配置运行nginx服务器的用户(组)、允许生成work process数,进程pid的存放路径,日志存放路径和类型,以及配置文件的引入等等。

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

比如这里的worker_processes,这是nginx并发处理服务的关键配置,该值越大,可以支持的并发处理处理也越多,但是会受到硬件、软件等设备的制约。

第二部分:events块

events {
    worker_connections  1024;
}

events块主要设置nginx服务器与用户的网络连接,常用的设置包括是否开启对多worker process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个work process可以同时支持的最大连接数。

worker_connections 1024;就表示每个work process支持的最大连接数是1024。这部分的配置对nginx的性能影响较大,在实际中应该灵活配置。

第三部分:http块

这算是nginx中最频繁配置的部分,代理、缓存、日志定义依旧我们说的负载均衡、动静分离等绝大部分功能都是在这里面进行配置的。另外,http块也可以分为http全局块和server块

http全局块

http全局块配置的指令包括文件的引入,MIME-TYPE定义,日志自定义,连接超时时间,单链接请求数上限等等。

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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

这一部分就是http全局块

server块

而server块就是我们改动最频繁的部分了

server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

listen 80表示nginx监听80端口,server_name表示监听的主机为本机。实际上这一部分也可以叫做server全局块,而下面是location块

location /则表示当你访问的路径是/的时候,进行相应的处理,怎么处理我们后面会详细介绍。我们很多时候都只是使用nginx做一层转发,而转发所进行的配置就是配置location。

nginx配置实例--实现反向代理(一)

需求:

当我打开浏览器,输入阿里云的ip的时候,会自动跳转到百度页面。

修改配置文件:

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们只需要加上一行proxy_pass?http://www.baidu.com,由于该机器监听的是80端口,而浏览器默认访问80端口,那么当我们直接输入ip地址访问该机器的时候,会自动转发到百度。然后不要忘记nginx -s?reload,为了方便,可以办nginx的sbin目录配置到环境变量,我这里就不配了。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

当我输入阿里云的ip地址的时候,自动跳转到了百度,就是nginx帮我们做了转发。而原来是没有proxy_pass这一行的,当没有这一行的时候,会来到nginx的指定页面。对,那个root?html就是指nginx的主目录下的html目录,index?index.html?index.htm就是html目录下的文件,当没有指定proxy_pass的时候,就会到html目录下面找index选项指定的文件。

这里我们把proxy_pass这一项给去掉,然后让nginx访问我们自己指定的页面,假设访问satori.html,那么显然此时的location就应该这么配。

location / {
    root   /root;
    index  satori.html index.html index.htm;
        }

配置中有有三个html文件,会依次从左向右查找。我把配置文件给改掉了,但是/root目录下还没有satori.html这个文件,所以出现了403。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

下面我们就来写一个这样的文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 style="text-align: center">古明地さとりの避難小屋へようこそ</h1>
</body>
</html>

丢进去再次访问,会发现依旧报出了403,这是因为我们看到全局块中是#user nobody;,这个user表示nginx的启动用户,但是这行被注释掉了,表示nginx没有权限。一种解决办法就是把#user这个注释打开,然后把用户换成/root这个目录的所属用户,或者说是有权限读的用户。另一种办法就是chmod?-R?755?/root,让这个目录所有用户都有权限执行。我们使用chmod命令修改权限,之后再来访问,会发现访问成功。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

nginx配置实例--实现反向代理(二)

需求:

访问不同的路径,跳转到不同的url。比如当我输入ip/satori的时候跳转到bilibili页面,输入ip/koishi的时候跳转到知乎页面。显然此时就需要两个location了,因为这是两个不同的url

修改配置文件:

# 这个原来的location,就还让它保持原样
location / {
    root   html;
    index index.html index.htm;
        }

location /satori {
    proxy_pass http://www.bilibili.com;
    }
location /koishi{
    proxy_pass http://www.zhihu.com;
    }

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

首先访问成功了,但是我们看到指定的location的路径参数(ip:port或者http://www.xxx.com后面的那部分内容,我习惯称之为路径参数。)会自动跟在要映射的url后面。就像我们要将/satori映射到http://www.bilibili.com,但是当我们输入/satori的时候,这个/satori会跟在http://www.bilibili.com的后面,也就是http://www.bilibili.com/satori,同理知乎也是。但是如果我们访问的路径参数很多呢?

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

显然从图中我们可以看到,不管访问的url有多长,只要location和访问的url从头开始对比是相同的,比如这里的/koishi匹配上了,那么不管后面还跟着多少参数,都会加在http://www.zhihu.com的屁股后面。

新需求:

我们目前算是完成了url的转发,但是我们发现这里貌似访问的都是80端口。这个时候,如果我希望访问阿里云主机的90端口,让其跳转到百度呢?

修改配置文件:

如果仔细看一下配置文件,我们发现之前配置的多个location实际上都是在一个server下面的。而一个server只能监听一个端口,一个server可以配置多个location,不管什么url,只要你访问的是server指定的端口,那么就会匹配对应server端口下面的location,如果匹配上了进行转发。但是现在问题是,我们不访问80端口了,而是要访问90端口,那么显然就再需要一个server了,让这个server监听90端口,然后在监听90端口的server下,配置location。我们来试一下

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们看到nginx已经给我提供了多个server,但是这些server是被注释掉的,所以我们可以把注释打开,然后修改,但是我们也可以自己写一个server,粘贴过去

server {
    # 监听90端口
    listen 90; 
    # 主机依旧是本地
    server_name localhost;
    
    # 配置location
    location / {
        proxy_pass http://www.baidu.com;
    }
}

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们看到nginx已经给我提供了多个server,但是这些server是被注释掉的,所以我们可以把注释打开,然后修改,但是我们也可以自己写一个server,粘贴过去
(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

我们看到此时我们访问的都只是ip,所以匹配/,都没有任何路径参数,但是却得到了不同的结果,就是因为端口不一样。我们访问80端口,只会匹配监听80端口的server下的location,同理90端口也是,因此不同端口下的location是互不影响的。

nginx配置实例--实现反向代理(三)

需求:

现在我要求,只要访问的url中包含了satori,就跳转到bilibili。就是说url可以是ip/satori,ip/aaa/satori,ip/aaa/bbb/c/satori/aa,只要路径参数中包含了satori,那么就跳转到bilibili,怎么做呢?

修改配置文件:

这种做法显然要使用正则来实现,对于我们上面的需求,location使用正则简直不要太好配,直接~?/satori/即可,此时同样匹配上之后,所有的路径参数都会跟在跳转的url的后面。

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

此时就配好啦,访问/a/b/c/satori/abc

(写了一点写不下去了,虽然垃圾但又不想扔)nginx--最流行的web服务器

只要路径有/satori,那么就能匹配成功,另外这里面跳转的url是不能够有路径参数的

nginx中的正则

关于nginx中的正则,我们见到了,那么location还支持一下几种方式。

=:表示url不包含正则表达式,要求请求的url和location指定的url完全一致。

~:url包含正则表达式,并且区分大小写

**~*:url包含正则表达式,并且不区分大小写**

^~:url不包含正则表达式,要求nginx找到请求的url和location指定的url相似度最后的location,然后用该location进行请求处理。

nginx配置实例--负载均衡

需求:

假设我们有两台服务器,我们需要实现当访问ip:90/satori的时候,能够把请求转发到不同的服务器当中去,也就是实现负载均衡的效果

修改配置文件:

这里就要修改http全局块,不记得这是哪一部分的可以回头看看。

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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    
    # 我们需要加上一个upstream,然后给upstream起一个名字
    # 假设就叫my_server
    upstream my_server {
        # 写上你要转发的机器
        server 1.1.1.1:5555;
        server 2.2.2.2:6666;
    }

然后修改location

server {
    # 监听90端口
    listen 90; 
    # 主机依旧是本地
    server_name localhost;
    
    # 配置location
    location /satori {
        # 这里将proxy_pass改成http://my_server即可,这个my_server就是给upstream起的名字
        proxy_pass http://my_server;
    }
}

随着互联网信息的爆炸式增长,负载均衡(load balance)已经不再是一个陌生的话题,就是把负载分摊到不同的存储单元,既保证服务的可用性,又保证服务足够快。但是负载均衡只是平摊负载吗?如果有的机器性能好,那么它的负载是不是应该要多一些呢?所以nginx在负载均衡方面有如下策略:

轮询(默认):

每个请求按照时间顺序逐一分配到不同的后端服务器,如果后端服务器宕机了,会自动剔除。

weight(权重):

权重越高,被分配的请求越多,权重与请求数成正比。默认是1,比如 server 1.1.1.1:80 weight=10,此时1.1.1.1这台服务器的权重就是10

ip_hash:

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题

upstream my_server {
    ip_hash;
    server 1.1.1.1:80;
    server 2.2.2.2:88;
}

fair:

按照服务器的响应时间来分配,响应时间短的优先分配

upstream my_server {
    server 1.1.1.1:80;
    server 2.2.2.2:88;
    fair;
}

nginx配置实例--动静分离

nginx动静分离简单来说,就是把动态和静态请求分开,不能简单理解成只是把动态页面和静态页面物理分离。严格来讲,是动态请求和静态请求分开,可以理解成使用nginx处理静态页面,uwsgi处理动态页面,动静分离从实现角度上大致分为两种:

  • 纯粹把静态文件独立出来,放在一个单独服务器上,也是目前主流方案
  • 把动态和静态文件放在一起,通过nginx来分开。

现在在我/root/bg目录下有很多图片,下面我们就进行配置,通过nginx直接访问静态资源。我们希望当输入/pic/1.png的时候,就会访问/root/bg下面的1.png。可能有人觉得这个是不是做过类似的,之前弄那个satori.html的时候好像弄过,确实如此。

server {
    listen 80; 
    server_name localhost;
    
    # 配置location
    location /pic {
        root /root/bg;
        # 当我们访问/pic/1.png,那么会返回/root/bg/1.png
        # 而这个autoindex指的是当输入/pic的时候,会把/root/bg里面的内容全部列出来,像索引一样
        # 可以通过点击的方式访问指定的静态资源
        autoindex on;
    }
}

。。。。。。。。。。。。

相关推荐