Nginx 无痛入门指南

在这个新的专题当中,笔者整理了Nginx的基本内容,以及在虚拟机环境下模拟部署高可用集群HA。咱们主要从如下内容入手:php

  1. Nginx是什么?它是用来作什么的?
  2. Nginx在Linux系统下的安装,包括反向代理,负载均衡,动静分离,配置高可用集群。

Nginx简介

Nginx (engine x)是一个高性能的HTTP和反向代理web服务器,同时也提供IMAP/POP3/SMTP服务。它的特色是:占用内存小,并发能力强css

Nginx能够做为静态的web服务器,同时支持CGI协议的动态语言,好比perl,php。而JavaWeb项目则须要与tomcat配合完成。Nginx专门为了优化而开发,性能是最重要的考量。html

Nginx支持热部署。能够在不间断服务的状况下,对软件版本进行升级。linux

反向代理

在介绍反向代理以前,首先介绍,什么是正向代理?nginx

咱们平常所使用的虚拟专用网络就属于正向代理。好比国内的客户想要直接访问Google官网是没法链接的,但若是该用户能够访问某服务器A,而A能够访问Google官网,那么客户能够将此服务器A设置为代理服务器,借助A服务器请求得到Google的响应报文,再转发给用户。此时这个服务器A称之为正向代理服务器。git

也就是说正向代理,须要用户主动配置代理服务器。 web

而反向代理,客户是对代理无感知的。客户只须要向公开的URL向代理服务器发送请求,代理服务器再选择目标服务器处理请求并返回数据,以下图所示。用户并不关心是哪一个具体的目标服务器替他完成了服务,虚线右侧的目标服务器对客户来讲是透明的。

负载均衡

若是一辆货车很难拉动一大批货物,那就再叫上几辆车。算法

客服端发送多个请求到服务器,服务器处理请求,有些请求须要与数据库交互,直到服务器处理完毕以后,再将结果返回给客户端。docker

这种架构模式对于早期并发请求较少的状况下仍是比较适合的,且维护成本也比较低。可是咱们已经都知道:摩尔定律逐渐失效,硬件的性能提高已经跟不上咱们实际的性能要求了。好比天猫双十一,其瞬时访问量都是很是庞大的,咱们即便将单节点升级到如今的顶级配置也很难应对(这还没考虑到升级设备的成本)。所以如今的服务都逐渐采用集群方式。

所谓负载均衡,就是反向代理服务器将大批量的请求分散到集群的节点当中,以减小单点服务器的压力,避免服务器崩溃的现象。 数据库

动静分离

为了加快网站的解析速度,咱们能够把动态页面和静态页面分散到不一样的服务器进行解析,加快解析速度,下降单个服务器的压力。

Nginx安装

咱们的主场仍旧是Linux系统。咱们能够进入到nginx官网,下载对应的版本,而后发送到咱们的云服务器/虚拟机当中安装,可是安装Nginx须要解决大量的依赖问题,在此不推荐用此方式。

笔者的虚拟机是CentOS 7.8 x86_64版本,在这里经过简单配置yum源的方式来安装(和笔者安装Docker的过程比较相似):

若是以前没有安装yum-utils,则须要先安装它:

$ yum install yum-utils
复制代码

进入到/etc/yum.reops.d/目录下,建立一个nginx的下载源配置文件:

$ vim nginx.repo
复制代码

在该文件中添加如下配置:

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
复制代码

配置完毕后,就可使用yum命令安装nginx服务器了。

#centOS7默认是没有nginx安装包的。
$ yum search nginx
$ yum install nginx
复制代码

咱们可使用find命令查看nginx的安装路径:

$ find / | grep nginx.conf
复制代码

此外,Nginx官网提供了RHEL/CentOS, Debian, Ubuntu等快捷安装方式。

📦Nginx提供的官方安装教程(适用于Linux内核)

尝试启动Nginx

咱们找到Nginx的启动脚本,而后启动Nginx服务(Nginx启动脚本在/usr/sbin目录下):

$ /usr/sbin/nginx
# 或者直接nginx也能够。
# 或者systemctl start nginx
# 查看进程中是否有nginx
$ ps -ef | grep nginx
复制代码

配置文件为/etc/nginx/nginx.conf,若是找不到nginx的配置路径,能够经过刚才的find命令搜索到。

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/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  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush on;

    keepalive_timeout  65;

    #gzip on;

    include /etc/nginx/conf.d/*.conf;
}
复制代码

经过观察该配置文件的最后一行,笔者注意到此下载版本中,nginx的配置被分散到了两个路径下:/etc/nginx/conf.d/*.conf

咱们再去浏览此/cet.nginx/conf.d/目录下,初始只有一个文件(/etc/nginx/conf.d/default.conf),经过listen可以观察到Nginx的默认启动端口是80。

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log /var/log/nginx/host.access.log main;

    location / {
        root   /usr/share/nginx/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   /usr/share/nginx/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;
    #}
}
复制代码

咱们在浏览器中输入对应的url(若是监听端口默认为80,咱们能够不主动地输入端口号)来访问nginx服务器,其中hadoop102是笔者已经配置好的主机名。

hadoop102
复制代码

当看到这个页面时,就说明咱们在虚拟机中启动的Nginx服务器成功了。

配置Linux防火墙规则

在Linux的firewalld防火墙启动状态下,若是不进行任何配置,咱们是没法访问到80端口的。咱们首先使用firewall命令查看目前开放的端口:

$ firewall-cmd --list-all
复制代码

咱们设置80端口号是开放的:

$ firewall-cmd --add-service=http --permanent
$ firewall-cmd --add-port=80/tcp --permanent
#重启firewall-cmd --reload
$ firewall-cmd --reload
复制代码

Nginx经常使用命令

查看Nginx的版本号:

$ nginx -v
#笔者的安装版本是:
#nginx version: nginx/1.18.0
复制代码

启动Nginx服务:

$ nginx
复制代码

中止Nginx服务:

$ nginx -s stop
复制代码

重加载Nginx(咱们在开篇就提到过,Nginx支持热部署,所以只须要从新刷新Nginx服务就能够):

$ nginx -s reload
复制代码

Nginx配置文件

咱们首先要对下面三个路径比较清晰:

启动脚本 -> /usr/sbin/nginx
主配置文件 -> /etc/nginx/nginx.conf
副配置文件-> /etc/nginx/conf.d/default.conf
复制代码

Nginx配置文件主要由三大块构成:全局块,events块,http块。其中,http块为核心,具体又可细分。:

全局块
events块
http块
  ┗ http全局块
  ┗ server块
      ┗ 全局server块
      ┗ location块
复制代码

全局块

做用域为文件开始到events块以前的部分。这里的配置会影响到nginx服务器总体的运行

其中,work_process表示可并发处理的请求数量。这个配置取决于机器实际的硬件/软件配置。

work_process 1
复制代码

events块

这里的配置会影响到Nginx服务器和用户的网络链接

其中,worker_connections表示最大的链接数,它会影响到Nginx的整体性能,因此应当灵活配置。

http块

这一块是配置的主要内容,http块还包含了两部分:http全局块,server块。其中nginx默认将server块单独迁移到了另一个配置文件中。

http全局块包括引入文件(如引入server块所在的配置文件),MIME-TYPE定义,日志自定义,链接超时时间,单连接请求数上限等内容。

server块

server块和虚拟主机由密切的联系,而从客户的角度而言,虚拟主机和独立的主机是没有区别的。它主要是为了节省互联网服务器硬件的成本。

一个http块,能够包含多个server块。每一个server块都至关因而一个虚拟主机。而每一个server块又分为全局server块,和一个(或者多个)location块

下面表明其中一个虚拟主机:启动在本地,并开启80端口。

listen			80;
server_name		localhost;
复制代码

location块配置了请求url和资源的映射(咱们在后续的实例中会进行更详细的配置),原配置文件中其实有大量有关location的注释内容,可是咱们基本均可以推测出其大体功能。

location / {
	root html;
	index index.html index.htm
}
复制代码

配置反向代理

咱们在Nginx简介中介绍过了反向代理的做用。咱们主要依赖http block -> servr block ->location block来配置具体的反向代理。对于动态请求,咱们常使用proxy_pass映射到指定主机号的对应端口,对于静态请求,咱们也可使用root将本机设为静态资源服务器,用于返回静态页面(详见配置动静分离的章节)。咱们还须要对location的uri匹配部分作一个基本的了解,才能避免意外的404问题。

关于Location的配置指令

实际上location能够包含如下形式:

location [ = | ~ | ~* | ^~ ] uri{
	....
}
复制代码
  • =表示最严格的精确匹配。好比配置location以下:

    # www.nginxText.com/hi/a.html => 127.0.0.1:9998/hello/a.html
    location = /hi/a.html {
    	proxy_pass http://127.0.0.1:9998;
    }
    复制代码
  • ^~表示在正则匹配以前进行前缀匹配。

    # www.nginxText.com/hi/a.html => 127.0.0.1:9998/helloworld/a.html
    location ^~ /hi {
    	proxy_pass http:127.0.0.1:9998/helloworld
    }
    复制代码
  • ~表示请求的uri包含了区分大小写的正则匹配

    # www.nginxText.com/hello/a.html => 127.0.0.1:9998/hello/a.html
    location ~ /hello/ {
    	#不容许在proxy_pass配置uri
    	proxy_pass http:127.0.0.1:9998
    }
    复制代码
  • ~*表示请求的uri包含了不区分大小写的正则匹配。

    # www.nginxText.com/hello/cafe.jpg => 127.0.0.1:9998/hello/cafe.jpg
    # www.nginxText.com/hello/cafe.JPG => 127.0.0.1:9998/hello/cafe.jpg
    location ~* \.(jpg|png)$ {
    	#不容许在proxy_pass配置uri
    	proxy_pass http:127.0.0.1:9998
    }
    复制代码
  • 若不带任何符号,则表示在正则匹配以后进行前缀匹配。

匹配顺序

匹配顺序以下(图源):

(location `=` ) 
(location `完整路径` )  
(location `^~` 路径)  
(location `~`,`~*` 正则顺序) 
(location 部分起始路径) 
(location `/`)
复制代码

注意如下点:

  1. 前缀匹配遵循最长匹配原则。

  2. 在进行正则匹配(~~*)时,配置的proxy_pass不容许包含uri。不然会报错:

    "proxy_pass" cannot have URI part in location given by regular expression
    复制代码

有关更多的location匹配细则参考这里

反向代理一个Tomcat服务器

根据配置反向代理,咱们主要想达到如下的效果:

打开浏览器,输入www.nginxtest.com访问咱们的Nginx服务器,Nginx服务器将请求转发到虚拟机系统下的Tomcat服务器。

首先,进入到物理机(笔者的物理机是Window10系统)的C:\Windows\System32\drivers\etc目录下,修改hosts文件,在文件末尾追加如下行:

{虚拟机ip地址} www.nginxtest.com
复制代码

随后在浏览器中直接输入www.nginxtest.com,默认访问80端口,便可访问到虚拟机中启动的Nginx服务。

笔者在这里使用Docker启动一个tomcat容器,端口映射为0.0.0.0:10000->8080。如今要访问Tomcat服务,咱们须要输入:

www.nginxtest.com:10000/
复制代码

咱们但愿仅输入www.nginxtest.com便可访问到Tomcat服务器,所以须要配置Nginx的反向代理服务。

咱们打开Nginx配置文件,在server域中添加下面的location配置,表示咱们将:

www.nginxtest.com/helloworld映射到127.0.0.1:10000/helloworld。(tomcat会默认返回/helloworld/index.jsp

location /helloworld {
	proxy_pass http://127.0.0.1:10000;
}
复制代码

随后刷新Nginx服务器:

$ nginx -s reload
复制代码

咱们在浏览器输入www.nginxtest.com时,就可让Nginx经过反向代理映射到虚拟机实际运行的Tomcat服务器了。

根据URI匹配不一样的Tomcat服务器

经过配置反向代理,咱们但愿实现如下效果:

www.nginxtest.com/hi/* -> 127.0.0.1:10000/hi/*

www.nginxtest.com/hello/* ->127.0.0.1:9998/hello/*
复制代码

当路径为/hi/..时,将此请求转发到127.0.0.1:10000的对应的/hi/..下的资源;当路径为/hello/..时,将此请求转发到127.0.0.1:10000的对应的/hello/..下的资源;

笔者在这里利用Docker的Tomcat镜像生成了一个新的实例,端口映射为0.0.0.0:9998->8080

咱们打开default.conf,进行以下配置:

location ~ /hi/ {
	proxy_pass http://127.0.0.1:10000;
}

location ~ /hello/ {
	proxy_pass http://127.0.0.1:9998;
}
复制代码

注意,此次的配置中多了一个~符号,表示正则匹配。这个配置告诉Nginx:全部包含/hi/的请求uri都会转发到10000端口的Tomcat服务器;全部包含/hello/的uri都会转发到9998端口的Tomcat服务器。注意每一个配置项后面都要带上;符号。

配置负载均衡

咱们想要实现一个这样的效果:Tomcat1(10000端口)和Tomcat2(9998端口)都具有/helloworld/b.html资源(为了观察到效果,能够在b.html中作下区分标记)。当客户端不断请求此资源的uri时,但愿Nginx可以根据相应策略做负载均衡。

最基本的配置

打开/etc/nginx/nginx.conf主配置文件的http块下,配置动态服务器组:

#upstream 后面加上本身配置的服务器组名字。
upstream dynamic {
    server localhost:10000; # docker->tomcat
    server localhost:9998; # docker->tomcat
}
复制代码

保存退出,进入到/etc/nginx/conf.d/default.confserver块下,在proxy_pass项中配置服务器组名。

location = /helloworld/b.html {
	proxy_pass http://dynamic;
}
复制代码

这个配置是一个精确匹配。表示当访问/helloworld/b.html这个资源时,将由Nginx根据负载均衡策略决定访问Tomcat1,或者是Tomcat2。

经过nginx -s reload保存配置,而后在浏览器中输入:www.nginxTest/helloworld/b.html,并反复刷新,能够观察到每次的内容是不同的,则证实Nginx的负载均衡策略生效了。

Nginx中的负载均衡策略

以上仅是最基本的复杂均衡配置,实际上要根据服务器的配置来采起不一样的策略。Nginx支持6种负载均衡策略,可是有2种须要依赖第三方。在这里详细介绍经常使用的四种方式。

参数 方式
不作任何配置,默认轮询方式。
weight 基于轮询方式,配置server配置项的后面表示权重。
ip_hash 依据ip分配方式,解决session跨域问题。
least_conn 最少链接方式
fair(第三方) 响应时间方式
url_hash(第三方) 依据URL分配方式

轮询(默认)方式

轮询是upstream默认的负载均衡策略,请求时按照时间顺序分配到各服务器。轮询策略可配置如下参数:

参数 做用
fail_timeout 设置超时时间,与max_fails结合使用。
max_fails 设置在fail_timeout参数设置的时间内最大失败次数,若是在这个时间内,全部针对该服务器的请求都失败了,那么认为该服务器会被认为是停机(down)了。
fail_time 服务器会被认为停机的时间长度,默认为10s。
backup 标记该服务器为备用服务器。当主服务器中止时,请求会被发送到它这里。
down 标记服务器永久停机了。

轮询策略适用于各个服务器之间配置至关,无状态(不须要coookie,session)的服务。

权重方式

在不作任何配置的状况下,每一个server的权重默认均为1。

权重越大的server,承担流量的几率也会越高。经常使用于服务器配置差距较大的状况。咱们会让性能更好的服务器来承受更大的流量。

#upstream 后面加上本身配置的服务器组名字。
upstream dynamic {

	# 假定此服务器性能更好,则上调它的访问权重。
    server localhost:10000 weight=2; 
    
    # 若是20秒内有10个请求都失败了,则该server会被停用。
    server localhost:9998 max_fails=10 fail_timeout=20; 
}
复制代码

ip_hash方式

session用于记录客户<->服务器的一个会话,所以有状态的服务不可以直接跨服务器。咱们使用ip_hash来基于客户端的ip进行分配,来保证同一个客户的请求只会发送到指定的服务器,来保证session会话状态。

#upstream 后面加上本身配置的服务器组名字。
upstream dynamic {
	#每一个访客分配到固定的服务器中。
	ip_hash; 
	
	# ip_hash方式能够基于轮询一块儿使用。
    server localhost:10000 weight=2; 
    server localhost:9998 max_fails=10 fail_timeout=20; 
}
复制代码

注意如下几点:

  • 若是使用ip_hash,则不能再分配备用服务器backup(合情合理,由于即便备用的服务器也没有记录其它服务器的session信息,没有意义)。

  • 在Nginx版本1.3.1以前,不能在ip_hash策略中配置权重(weight)。

  • 当有服务器须要剔除,必须手动down掉。

least_conn方式

把请求转发给链接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大体相同;可是,有些请求占用的时间很长,会致使其所在的后端负载较高。这种状况下,least_conn这种方式就能够达到更好的负载均衡效果。

#upstream 后面加上本身配置的服务器组名字。
upstream dynamic {
	#基于链接数分配。
	least_conn
	
    server localhost:10000 weight=2; 
    server localhost:9998 max_fails=10 fail_timeout=20; 
}
复制代码

适用于不一样请求的处理时间差别较明显的状况。

配置动静分离

动静分离,就是将静态资源(图片,视频,css,js等文件)和动态资源(jsp,php)区别开。动态分离并非为了单纯的将这两种资源区别开,而是使用Nginx处理静态资源,由Tomcat(或其它服务器)处理动态资源。

除此以外,经过配置反向代理和expires参数,咱们能够将一些不会常常变更的静态资源直接发送到对方浏览器中保存起来。

用户下次经过浏览器再访问此资源时,浏览器只须要作一件事:在必定时间内(取决于expires),浏览器向原资源服务器发送简单请求,仅对比最后修改时间来判断此静态资源是否发生变化。

服务器正常状况下会发送两种状态码:

  1. 304 => 文件没有变更,浏览器直接使用缓存的资源。
  2. 200 => 文件发生变更,浏览器成功下载到新的文件。

目前的主流作法是,将全部的静态文件单独分离出来保存到一个单独的域名中。也有部分开发者选择将动态文件和静态文件混合在一块儿发布。

动静分离的配置

在动静分离以前,笔者先在虚拟机的/usr/images/目录下存放一些.jpg,.png等格式的图像文件,并配置本地做为静态资源的仓库。

配置方式一:前缀匹配

location ^~ /images {
	root /usr;
	autoindex on;
}
复制代码

因为咱们直接使用本地文件夹,所以在这里配置的是root。所以全部前缀知足/images/...的资源都会映射到本机的/usr/iamges/...路径下。

当配置autoindex on;时,咱们能够在浏览器中输入www.nginxTest.com/images/直接查看此路径下全部的文件。为了不中文文件显示乱码,建议在server块中配置charset utf-8

配置方式二:正则匹配

另外一种思路是碰到全部后缀名为.jpg, .JPG, .png, .PNG等文件的uri时,使用本机的静态资源库。因为这里不肯定前缀名,这里将autoindex on;选项去掉。

location ~* \.(jpg|png|gif|jepg)$ {
	root /usr;
}
复制代码

若是静态资源存放在另外一个服务器,一样可使用proxy_pass进行反向代理。

设置expires缓存

设置expires比较简单,咱们在location内部直接配置便可。语法以下:

expires 30s;   #缓存30秒
expires 30m;   #缓存30分钟 
expires 2h;    #缓存2小时
expires 30d;   #缓存30天
复制代码

咱们直接在刚才的正则匹配中加入这段配置,刷新Nginx,在浏览器中输入uri,并查看response header

location ~* \.(jpg|png|gif|jepg)$ {
	#缓存1天
	expires 1d
	root /usr;
}
复制代码

笔者经过Postman工具查看,并标注了重点部分。

局域网*下搭建高可用集群

笔者出于学习目的,仅演示虚拟机环境下的局域网搭建一个简单的高可用集群(HA),而在实际部署环境中,咱们至少要准备两台云服务器搭建VPC,还须要另购一个公网IP用做VIP(Virtual IP)。

在学习了Nginx以后,咱们可以绘出这样的拓扑结构了:经过动静分离将静态资源单独保管到资源服务器中;经过负载均衡使不一样的服务器之间可以协同工做......尤为是笔者刚刚学会使用Docker快速部署服务,感受技能树一下点亮了很多。

如图展现了一个彻底是围绕着一个Nginx服务器构建的星型拓扑结构,这要咱们必须面临一个fatal的问题:若是Nginx自己宕机了,那么全部的请求就所有失效了。因此很明显,当前这种作法,是 存在风险的。

高可用模式的配置

为了不将全部的鸡蛋放到一个篮子里,最直观,最显著的方法就是:准备一个(或多个)Nginx的Backup(后备服务器),当Master因意外宕机的时候,Backup可以快速代替Master进行工做。

咱们须要使用一款keepalived来实现Nginx的主备模式。同时还对用户隐藏细节,使用户可以按统一的接口来访问

在配置高可用模式以前

咱们首先罗列一下配置高可用模式所须要的清单:

  1. 两台服务器(笔者使用两台虚拟机代替)
  2. 使用keepalived软件。
  3. 供keepalived进行检测目标Nginx是否运行的可执行脚本。
  4. 须要一个虚拟IP地址(用于对用户提供统一的访问)。
  5. 禁用SElinux,清除iptables规则,关闭防火墙

keepalived检测Nginx的流程

keepalived集群内部有多个Nginx服务器,在这个集群运做时,其中只有一个Nginx是处于工做状态,即Master(主机),其他的Nginx都处于Backup(候选)状态。每一个主机内的keepalived监视本机的Nginx运行的状态。

不过不管是Master仍是Backup在进行反向代理工做,对客户来讲是不可见的。这主要经过提供一个统一的VIP(Virtual IP)来实现。因此不管是谁在运做,客户都只经过这一个VIP来请求服务。

keepalived基于arp广播模式工做,所以全部的keepalived处于一个局域网当中。(若是是多个云服务器互备则要配置在同一个虚拟私有云VPC内)

每一个主机的keepalived和只本机的Nginx绑定。keepalived会经过一个脚原本检测本地的Nginx是否处于正常状态(或者称进行健康检查)。当keepalived检测到Nginx处于不可重启的状态中,则会将自己的keepalived进程一同中断(表示本机的"Nginx was died")。

集群中各个keepalived会进行心跳检测(经过组播形式实现)。其它的keepalived"感知"不到Master的keepalived(说明Master Nginx宕机了)时,便会从Backup中选出一个候补获取VIP的使用权,以后客户输入的路径将所有由此候选的Nginx负责。

对于实际工做的Nginx节点,咱们是能够经过ip addr检查到网口是绑定了VIP的。而处于候选状态的节点,ip addr是没有绑定VIP的。

keepalived的配置能够有两种形式:

  1. 抢占式(默认),主节点出现故障以后,由备机工做。当主节点从新启动时,备机将从新处于候选状态。
  2. 非抢占式,主节点出现故障以后,由备机工做。当主节点从新启动时,备机继续工做。

配置另外一个虚拟机的Nginx

咱们以前都是在主机"hadoop102"中配置的Nginx反向代理/负载均衡/动静分离,因此在hadoop102的Nginx中,有不少配置都指向"localhost","127.0.0.1"。

而对于新的主机"hadoop101"而言,这些配置就要相应地替换成主机hadoop102或者它的ip地址了。咱们直接拷贝以前hadoop102主机的配置文件,修正nginx.confdefault.conf的一些细节:

upstream dynamic{
    #因为此次咱们须要通信,因此要配置max_fails和fail_timeout。
	server hadoop102:10000 max_fails=10 fail_timeout=10s;
	server hadoop102:9998 max_fails=10 fail_timeout=10s;
}	
复制代码

default.conf中作如下修改,静态资源的目录再也不位于本机,因此须要proxy_pass进行代理。

location ~* \.(jpg|png|gif|jepg)$ {
	expires 1d;
	proxy_pass http://hadoop102;
}
复制代码

正常状况下,静态资源服务器是会单独在另外一个服务器中的,不过这里的hadoop102的Nginx既做为资源服务器,又做为keepalived集群的备用机。

在MASTER工做的状况下,处于BACKUP状态的Nginx也仍然正常工做。

安装keepalived

注意!!请谨慎阅读如下内容的每一处细节,由于稍有不慎就会致使keepalived没法正常运行。

其中keepalived有多种渠道安装,也能够直接使用yum源进行安装。两个服务器都须要安装此软件。

$ yum install keepalived -y
复制代码

咱们可使用find命令来查找到keepalived配置文件所在的目录(实际它在/etc/keepalived/目录下):

$ find / | grep keepalived.conf 
复制代码

除此以外,另一个虚拟机也须要安装一个Nginx服务器,过程参见上文。

编写检测脚本

笔者在健康检测脚本中的设定是:keepalived在Nginx处于关闭状态时仍然会尝试再次开启Nginx服务,直到2秒后发现Nginx仍没法启动时才会断定为dead.

keepalived使用脚原本实现检测目标Nginx是否正常运做。当脚本检测到Master Nginx宕机时,要切换到Backup Nginx上。

#!/bin/bash
A=`ps -C nginx --no-header |wc -l`
if [ $A -eq 0 ];then
    systemctl start nginx
    sleep 2
    if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
        killall keepalived
    fi
fi
复制代码

❗编写脚本注意的问题:

  1. 命令模式输入set ff检查文件的编码格式。若是显示文件的编码格式为doc,则须要更改成set off=unix

  2. 这个脚本须要被设置为具有x权限,可使用chmod a+x进行更改。

笔者将这个文件保存为/usr/local/src/nginx_check.sh。最好手动执行一遍这个脚原本排查问题,以避免稍后的keepalived不生效。

配置keepalived【谨慎配置】

keepalived的配置文件为/etc/keepalived/keepalive.conf默认状况下有很是多的默认配置。

从这个实例来讲,咱们只须要用到如下三个部分global_defs(全局定义),vrrp_script(用于检测脚本,须要手动添加),vrrp_instance(配置虚拟IP)。

对于用不上,或者不清楚其功能的配置项,强烈建议所有删去,不然很是容易致使keepalived不生效。

咱们首先对主节点Master为例进行配置:

在此,咱们不须要经过Mail的形式收发消息。所以在global_defs部分中,咱们只须要保留router_id项,来为为本身的主机命名。

# 配置此主机的主机名。至关于在配置/etc/hosts
global_defs {
   router_id r1
}
复制代码

原配置文件中没有vrrp_script选项,须要咱们手动添加上去。script的路径是刚才建立脚本的绝对路径。可能会有差别,请仔细甄别。

# vrrp_script后面的名称能够自定义(此处为check),可是要和稍后track_script块配置对应。
vrrp_script check {
   script  "/usr/local/src/nginx_check.sh"
   interval 4
}
复制代码

❗注意,这个interval的数值要比脚本中的睡眠时间sleep要大,不然脚本会执行失败。(笔者的脚本中,睡眠时间为2,所以在这里配置为了4)

其中,在vrrp_instance中咱们须要进行5处更改,笔者已经经过注释的方式给出。实际的更改值要取决于本身的网络环境,好比VIP的选择。在虚拟机环境下,咱们只须要选任意一个没有被占用的内网IP便可。而若是是云服务器构建的HA集群,要向服务提供商(腾讯云,华为云)另行购买一个HAVIP

笔者的物理机和宿主机集群经过NAT方式链接,并处在192.168.229.0/24网络。宿主机的系统均为CentOS 7系统,所以网卡口名称均为ens33。这些都取决于我的配置,不可直接粘贴。

vrrp_instance VI_1 {
    #1 可设置BACKUP和MASTER,取决于设置。
    state MASTER
    #2 配置成本身的网卡口!centOS7通常都叫ens33.
    # 可使用ip addr来查看。
    interface ens33
    
    # 注意,同一个集群下的virtual_router_id必须保持一致!
    virtual_router_id 51
    
    #3 保证BACKUP的优先级要比MASTER的优先级低。
    priority 100
    
    # 设置每1秒组播心跳消息,证实keepalived还存活。
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    #4 这一块须要本身手动添加。注意要写到virtual_ipaddress项的上面!
    # 内部的脚本名称实际上取决于你刚才在vrrp_script的配置名称
    track_script {
        check
    }
    
    #5 不管是BACKUP/MASTER,为了让用户经过统一域名访问,所以都要选择统一的VIP。
    # 这个IP根据你的局域网IP号而定。
    virtual_ipaddress {
        192.168.229.171
    }
}
复制代码

对于配置为BACKUP的主机,只须要把state一项修改便可。

启动keepalived集群

在确保以上的配置就绪以后,咱们经过systemctl命令启动nginxkeepalived

$ systemctl start nginx
$ systemctl start keepalived.service
复制代码

检查Nginx和keepalived服务是否正常启动:

$ systemctl status nginx
$ systemctl status keepalived.service
复制代码

在集群启动后,正在处于工做状态的服务器是能够经过ip addr检查到ens33网口绑定了VIP的。其它正在运行但处于候选状态的Nginx主机则没有绑定VIP。

若是不慎出了错误!

必定要去日志中寻找线索,获取在浏览器端开启调试模式检查错误码。

#nginx错误日志默认位置
cat /var/log/nginx/error.log
复制代码

笔者遇到并解决了如下错误:

(13: Permission denied) while connecting to upstream
复制代码

解决方案:多是因为selinux防火墙开启引起的问题,检查防火墙状态:

$ sestatus -v
复制代码

这里笔者姑且采用直接的方案:关闭selinux防火墙。

# SELINUX = disabled
$ vim /etc/selinux/config
# 重启生效
$ reboot
复制代码

另外,因为咱们对upstream的每一个节点都设置了超时时间,所以若是由于高并发(或其它缘由)致使全部节点所有处于down状态的话,日志文件会打印如下错误:

...no live upstreams while connecting to upstream...
复制代码

它表示没有一个存活的上游节点,但它并非根本问题。咱们须要继续跟踪日志,追查是什么缘由致使全部的节点所有down掉。此刻在浏览器端,咱们能够在调试模式下检测到502错误。

公网环境下的高可用方案

阿里云:阿里云服务器再也不支持单独购买IP,所以在公网环境下不能经过keepalived的方式进行热备。不过阿里云彷佛直接提供负载均衡服务?(要恰饭的嘛)

腾讯云和华为云的实现原理相似,须要为多个云服务器建立一个虚拟私有云VPC,而后再另行购买用于浮动的HAVIP,进行绑定。

不一样厂商间提供的解决方案稍有区别,所以要根据本身以后的实际状况查找具体方案。笔者目前没有在公网搭建HA的强烈需求(主要是穷),所以暂时不会再深刻研究公网环境下的HA搭建了(老实说,笔者认为这些应该是运维的工做......)。笔者在此罗列一些帖子供往后参考:

Nginx补充

Master与Worker

咱们使用ps命令查看进程时,能够留意到:Nginx服务实际上有两个进程:

$ ps -ef | grep nginx
#root 2016 1 0 10:49 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
#nginx 2017 2016 0 10:49 ? 00:00:00 nginx: worker process
复制代码

worker进程的数量实际上能够有多个的。正是由咱们当时在/etc/nginx/nginx.conf中配置的worker_process数量所决定的(默认为1,实际数量取决于机器性能)。当外部访问到Nginx服务器的时候,worker进程之间经过竞争的方式来获取此链接。

这种一个Master管理多个Worker的优点是什么呢?

  1. 基于这种模式,咱们可使用nginx -s reload对Nginx进行热部署:它是使得正在处理请求的worker不会被打断已有的工做,而空闲的worker则马上刷新了配置
  2. 每一个worker是独立的进程(非线程)。所以节省了各类同步锁形成的开销。此外,即使是个别worker因异常而关闭,其它worker仍然可以正常运行,提升了Nginx总体的稳定性,下降了风险。

Nginx 的高性能依赖于 Linux 2.6 内核的 epoll 或是 BSD 内核的 kqueue 提供高效的网络套接字状态轮询服务【时间复杂度为 O(1) 】。在没有这两个服务的内核上则退化成为性能低下的 select 【*nix ,Windows 都有,时间复杂度为 O(n) 】. Windows 没有 epoll 和 kqueue,Nginx 在 Windows 上用 select 表现天然不佳。

另外一个NoSQL数据库软件 Redis 也是一样的缘由,致使它在Windows运行的性能和*nix平台相比要低。

咱们应该设置多少个Worker数量最合适呢?通常状况下,咱们一般将这个数值设置为和物理机的CPU数量相等。

worker_connection

首先提一个问题:基于Http 1.1协议,一个用户发送一个请求到一个Worker中,会占用Worker的几个链接数呢?答案是2个或者4个。

当访问静态资源,Nginx直接从本地返回资源时,须要占用两个链接。

当Nginx进行反向代理的时候,则须要占用4个链接。

所以假设每一个worker的链接数值为worker_connection,则实际的并发访问量(指同时处理Client的请求数)是:

  1. (worker_connection * worker_process) / 2 => 做为静态服务器

  2. (worker_connection * worker_process) / 4 => 做为反向代理服务器

相关文章
相关标签/搜索