Nginx实现高可用集群

Posted by Lucky Xue on 2020-08-22

编译并安装Nginx

官网地址www.nginx.org,nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0

Nginx是单进程单线程模型,即启动的工作进程只有一个进程响应客户端请求,不像apache可以在一个进程内启动多个线程响应可请求,因此在内存占用上比apache小的很多。Nginx维持一万个非活动会话只要2.5M内存。Nginx和Mysql是CPU密集型的,就是对CPU的占用比较大,默认session在本地文件保存,支持将session保存在memcache,但是memcache默认支持最大1M的hash对象。

nginx的版本分为开发版、稳定版和过期版,nginx以功能丰富著称,它即可以作为http服务器,也可以作为反向代理服务器或者邮件服务器,能够快速的响应静态网页的请求,支持FastCGI/SSL/Virtual Host/URL Rwrite/Gzip/HTTP Basic Auth等功能,并且支持第三方的功能扩展。

nginx安装可以使用yum或源码安装,推荐使用源码,一是yum的版本比较旧,二是使用源码可以自定义功能,方便业务的上的使用,源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective-C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1. 去官网http://nginx.org/下载对应的nginx包括,推荐使用stable version
2. 上传nginx到linux系统
3. 安装依赖环境
1. 安装gcc环境 sudo yum install -y gcc-c++
2. 安装PCRE库,用于解析正则表达式 sudo yum install -y pcre pcre-devel
3. zlib压缩和解压缩依赖 sudo yum install -y zlib zlib-devel
4. SSL安全的加密套接字协议层,用于https安全传输 sudo yum install -y openssll openssl-devel
4. 解压,解压之后得到的是源码,源码编译之后才能安装
tar -xzvf nginx-1.18.1.tar.gz
5. 编译之后,先创建nginx临时目录,如果不创建,在启动nginx的过程中会报错
mkdir /var/tmp/nginx -p
6. 在nginx目录,输入如下命令进行配置,目的就是为了创建makefile文件
./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-tmp-path=/var/tmp/nginx/client \
--http-proxy-tmp-path=/var/tmp/nginx/proxy \
--http-fastcgi-tmp-path=/var/tmp/nginx/fastcgi \
--http-uwsgi-tmp-path=/var/tmp/nginx/uwsgi \
--http-scgi-tmp-path=/var/tmp/nginx/scgi

命令命令 解释解释
–prefix 指定nginx安装目录
–pid-path 指向nginx的pid
–lock-path 锁定安装文件,防止被恶意篡改或误操作
–error-log 错误日志
–http-log-path http日志
–with-http_gzip_static_module 启用gzip模块,在线实时压缩输出数据流
–http-client-body-tmp-path 设定客户端请求的临时目录
–http-proxy-tmp-path 设定http代理临时目录
–http-fastcgi-tmp-path 设定fastcgi临时目录
–http-uwsgi-tmp-path 设定uwsgi临时目录
–http-scgi-tmp-path 设定scgi临时目录

7. make编译
sudo make
8. 安装
sudo make install
9. 验证nginx
whereis nginx / which nginx

同步与异步,阻塞与非阻塞

很多同学可能会认为 同步 就是 阻塞 , 异步 就是 非阻塞 ,非也非也~~这一节咱们来聊一聊他们区别,如果学习过的可以当做复习,如果不太清楚的,可以好好的了解一番,因为这些概念往往在面试过程中有可能会被面试官问到。
这四个概念两两组合,会形成4个新的概念,如下:

  1. 同步阻塞: 客户端发送请求给服务端,此时服务端处理任务时间很久,则客户端则被服务端堵塞了,所以客户端会一直等待服务端的响应,此时客户端不能做事,服务端也不会接受其他客户端的请求。这种通信机制比较简单粗暴,但是效率不高。
  2. 同步非阻塞: 客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候虽然客户端会一直等待响应,但是服务端可以处理其他的请求,过一会回来的。这种方式很高效,一个服务端可以处理很多请求,不会在因为任务没有处理完而堵着,所以这是非阻塞的。
  3. 异步阻塞: 客户端发送请求给服务端,此时服务端处理任务时间很久,但是客户端不会等待服务器响应,它可以做其他的任务,等服务器处理完毕后再把结果端,客户端得到回调后再处理服务端的响应。这种方式可以避免客户端一直处于等待的状态,优化了用户体验,其实就是类似于网页里发起的ajax异步请求。
  4. 异步非阻塞: 客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候的任务虽然处理时间会很久,但是客户端可以做其他的任务,因为他是异步回调函数里处理响应;同时服务端是非阻塞的,所以服务端可以去处理其他的任务,如此,这个模式就显得非常的高效了。
    以上四点,除了第三点,其余的分别为BIO/NIO/AIO,面试官如果问你 “请简述一下BIO/NIO/AIO之间的概念与区别” ,那么你就可以组织一下语言来回答
    下生活实例来阐述也是可以的:
  5. BIO: 我去上厕所,这个时候坑位都满了,我必须等待坑位释放了,我才能上吧?!此时我啥都不干,站在厕所里盯着,过了一会有人出来了,我就赶紧蹲上
  6. NIO: 我去上厕所,这个时候坑位都满了,没关系,哥不急,我出去抽根烟,过会回来看看有没有空位,如果有我就蹲,如果没有我出去接着抽烟或者玩会手机
  7. 异步阻塞: 我去上厕所,这个时候坑位都满了,没事我等着,等有了新的空位,让他通知我就行,通知了我,我就蹲上去。
  8. AIO: 我去上厕所,这个时候坑位都满了,没事,我一点也不急,我去厕所外面抽根烟再玩玩手机,等有新的坑位释放了,会有人通知我的,通知我了,我就可以上了。
    从这个生活实例中能可以看得出来:
    同步 就是我需要自己每隔一段时间,以轮训的方式去看看有没有空的坑位;
    异步 则是有人拉完茅坑会通知你,通知你后你再回去蹲;
    阻塞 就是在等待的过程中,你不去做其他任何事情,干等着;
    非阻塞 就是你再等待的过程中可以去做其他的事,比如抽烟、喝酒、烫头、玩手机。
    小结: 异步 的优势显而易见,大大优化用户体验, 非阻塞 使得系统资源开销远远小于 阻塞 模式,因为系统不需要创建新的进程(或线程),大大地节省了系统多出来的系统资源可以给其他的中间件去服务了。

nginx.conf 核心配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1. 设置worker进行的用户,指的linux中的用户,会涉及到nginx操作目录或者文件的一些权限,默认为nobody
user root;
2. worker进程工作数设置,一般来说CPU有几个,就设置几个,或者设置N-1也行
worker_processes 1;
3. nginx日志级别debug | info | notice | warn | error | crit | alert | emerg,错误级别从左到到右越来越大
4. 设置nginx进程pid
pid logs/nginx.pid
5. 设置工作模式
events {
# 默认使用epoll
use epoll;
# 每个worker允许连接客户端最大连接数
worker_connections 10240;
}
6. http是指令块,针对http网络传输的一些指令配置
http {
}
7. include 引入外部配置,提高可读性,避免单个配置文件过大
include mime.types;
8. 设置日志格式,main为定义的格式名称,如此access_log就可以直接使用这个变量了
$remote_addr 客户端ip
$remote_user 远程客户端用户名,一般为:’-’
$time_local 时间和时区
$request 请求的url以及method
$status 响应状态码
$body_bytes_send 响应客户端内容字节数
$http_referer 记录用户从哪个链接跳转过来的
$http_user_agent 用户所使用的代理,一般来时都是浏览器
$http_x_forwarded_for 通过代理服务器来记录客户端的ip
9. sendfile 使用高效文件传输,提升传输性能。启用后才能使用 tcp_nopush ,是指当数据表累积一定大小后才发送,提高了效率。
sendfile on; tcp_nopush on;
10. keepalive_timeout 设置客户端与服务端请求的超时时间,保证客户端多次请求的时候不会重复建立新的连接,节约资源损耗。
#keepalive_timeout 0; keepalive_timeout 65;

Nginx日志切割

现有的日志都会存在 access.log 文件中,但是随着时间的推移,这个文件的内容会越来越多,体积会越来越大,不便于运维人员查看,所以我们可以通过把文件切割为多份不同的小文件作为日志,切割规则可以以 天 为单位,如果每天有几百G或者几个T的日志的话,则可以按需以 每半天 或者 每小时 对日志切割:

1
2
3
4
5
6
#!/bin/bash
LOG_PATH="/var/log/nginx/" RECORD_TIME=$(date -d "yesterday" +%Y-%m-%d+%H:%M)
PID=/var/run/nginx/nginx.pid
mv ${LOG_PATH}/access.log ${LOG_PATH}/access.${RECORD_TIME}.log
mv ${LOG_PATH}/error.log ${LOG_PATH}/error.${RECORD_TIME}.log #向Nginx主进程发送信号,用于重新打开日志文件
kill -USR1 `cat $PID`

Nginx配置文件

Nginx跨域配置支持

#允许跨域请求的域,*代表所有
add_header ‘Access-Control-Allow-Origin’ *;
#允许带上cookie请求 add_header ‘Access-Control-Allow-Credentials’ ‘true’;
#允许请求的方法,比如 GET/POST/PUT/DELETE add_header ‘Access-Control-Allow-Methods’ *;
#允许请求的header add_header ‘Access-Control-Allow-Headers’ *;

Nginx防盗链配置支持

1
2
3
4
5
6
#对源站点验证 valid_referers *.imooc.com;
#非法引入会进入下方判断
if ($invalid_referer)
{
return 404;
}

root与alias

1
2
3
4
5
6
7
8
9
10
11
假如服务器路径: /home/imooc/files/face.png,
root路径完全匹配访问,配置的时间为:
location /imooc {
root /home

}
用户访问的请求为:url:port/imooc/files/img/face.png,alias可以为你的路径做一个别名,对用户透明:
location /hello {
alias /home/imooc
}
用户访问的请求为:url:port/hello/files/img/face.png,如此相当于目录imooc做一个自定义的别名

location的匹配规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
location的匹配规则
空格:默认的匹配,普通匹配
location / {
root /home;
}
=: 精确匹配
location = /imooc/img/face.png {
root /home
}
~*: 匹配正则表达式,不区分大小写
#符合图片的显示
location ~* \. (GIF|JPG|PNG|JPEG) {
root /home;
}
~: 匹配正则表达式,区分大小写
#GIF必须大写能匹配
location ~ \.(GIF|jpg|png|jpeg) {
root /home;
}
^~:以某个字符路径开头
location ^~ /home/img {
root /home;
}

OSI 网络模型

在讲到Nginx负载均衡的时候,其实Nginx是七层负载均衡,后续我们还会涉及到LVS,是四层负载均衡,七层和四层是什么概念呢?这就必须提到网络模型。网络模型是计算机机网络基础的一部分内容,一般大学计算机系都会讲到此知识点,并且会作为考点;其实在面试过程中有时候也会被问到。

网络模型就是 OSI(Open System Interconnect) ,意思为 开放网络互联 ,是由国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)共同出版的,他是一种分层设计的互联模型,也是一种规范。网络模型分为七层,也就是当用户发起请求到服务器接收,会历经七道工序,或者说用户利用互联网发送消息给另一个用户,也会历经七道工序。这七层:

层级 名称 说明
第七层 应用层 与用户行为交互
第六层 表示层 定义数据格式以及数据加密
第五层 会话层 创建、管理以及销毁会话
第四层 传输层 创建、管理请求端到响应端(端到端)的连接
第三层 网络层 请求端的IP地址
第二层 数据链路层 提供介质访问与链路管理
第一层 物理层 传输介质,物理媒介

以上七层每层可以与上下相邻层进行通信。每一层都是非常复杂的,我们不在这里深究,我们以举例的形式来阐述每一层是干嘛的。

  • 应用层: 这是面向用户的,最靠近用户,为了让用户和计算机交互,在计算机里会有很多软件,比如eclipse,idea,qq,nginx等,这些都是应用层软件,用户可以通过这些应用软件和计算机交互,交互的过程其实就是接口的调用,应用层为用户提供了交互的接口,以此为用户提供功能。那么在这一层最常见的协议有:HTTP,HTTPS,FTP,SMTP,POP3等。Nginx在本层,为七层负载均衡。
    举例:我要寄一封信给远在天边的老外LiLei,我会打开快递软件下单,这个时候我是 用户 ,快递软件就是 应用服务 ,是建立在计算机之间供给用户交互的一种服务或称之为手段。
  • 表示层: 该层提供数据格式编码以及加密功能,确保 请求端 的数据能被 响应端 的应用层识别。
    举例:我写中文给LiLei,他看不懂,这个时候我就会使用翻译软件把中文翻译成英文,随后信中涉及到一些比较隐私的信息我会加密一这时候翻译软件和加密器就充当了 表示层 的作用,他用于显示用户能够识别的内容。
  • 会话层: 会话可以理解为session,请求发送到接受响应的这个过程之间存在会话,会话层就充当了这一过程的管理者,从创建会话到使用后销毁会话。举例:我每次写信给LiLei都会记录在一个小本本上,寄信时间日期,收信时间日期,这本小本本上存有每次通信记录,这个小本本就相当于会话的管理者。又或者说,我们平时在打电话,首先需要拨打电话,这是 建立会话 ,对方接听电话,此时正在通话( 维持并管理会话,结束后 会话销毁 ,那么这也是一次会话的生命周期。
  • 传输层: 该层建立端到端的连接,他提供了数据传输服务,在传输层通信会涉及到端口号,本层常见的协议为TCP、UDP,LVS就是在传输层,也就是四层负载均衡。举例:我和LiLei通信过程中会借助快递公司,快递公司会分配快递员取件和寄件,那么这个快递员则充当 传输层 的作用。
  • 网络层: 网络通信的时候必须要有本机IP和对方的IP,请求端和响应端都会有自己的IP的,IP就相当于你家地址门牌号,在网络上云服务器的公网IP,普通计算机也有,只不过是动态IP,运营商每天会分配不同的IP给你的计算机。所以网络层也能称之为IP层,IP是互联网能提供IP分配的设备则为路由器或交换机。举例:对于拥有固定IP的云服务来说,他们都是由腾讯云、阿里云等这样的供应商提供的,他们为云服务器提供固定ip;电信、移动、
    商为你的计算机动态分配ip,每天都不同;则这些供应商和运营商都是网络层。同理,快递员由物流公司分配和管理,那么物流公司就地址进行派送咯。
  • 数据链路层: 这一层会提供计算机MAC地址,通信的时候会携带,为了确保请求投递正确,所以他会验证检测MAC地址,以确保请求的准确性。举例:快递员在投递派送的时候,他(或客服)会预先提前打电话给你,确认你家地址对不对、有没有人、货到付款有没有准备好钱等,这时候快递员(或客服)就充当了 数据链路层 的职责。

upstream指令参数max_conns

限制每台server的连接数,用于包括避免过载,可起到限流作用,测试参考配置如下:

1
2
3
4
5
6
7
# worker进程设置1个,便于测试观察成功的连接数
worker_processes 1;
upstream tomcats {
server 192.168.1.173:8080 max_conns=2;
server 192.168.1.174:8080 max_conns=2;
server 192.168.1.175:8080 max_conns=2;
}

upstream指令参数slow_start

商业版nginx需要付费,该参数不能使用在 hash 和 random load balancing 中。如果在 upstream 中只有一台 server,则该参数失效。配置参考如下:

1
2
3
4
5
upstream tomcats {
server 192.168.1.173:8080 weight=6 slow_start=60s;
server 192.168.1.174:8080 weight=2;
server 192.168.1.175:8080 weight=2;
}

upstream 指令参数

max_fails、fail_timeout max_fails :表示失败几次,则标记server已宕机,剔出上游服务。
fail_timeout :表示失败的重试时间。
假设目前设置如下:
max_fails=2 fail_timeout=15s
则代表在15秒内请求某一server失败达到2次后,则认为该server已经挂了或者宕机了,随后再过15秒,这15秒内不会有新的请求到达刚刚挂掉的节点上,而是会
运作的server,15秒后会再有新请求尝试连接挂掉的server,如果还是失败,重复上一过程,直到恢复。

Keepalived提高吞吐量

keepalived:设置长连接处理的数量
proxy_http_version:设置长连接http版本为1.1
proxy_set_header :清除connection header 信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
upstream tomcats {
# server 192.168.1.173:8080 max_fails=2 fail_timeout=1s;
# server 192.168.1.174:8080 weight=1;
# server 192.168.1.175:8080 weight=1; keepalive 32;
server {
listen 80;
server_name www.tomcats.com;
location /
{
proxy_pass http://tomcats;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
}

负载均衡ip_hash

可以保证用户访问可以请求到上游服务中的固定的服务器,前提是用户ip没有发生更改。
使用ip_hash的注意点:
不能把后台服务器直接移除,只能标记 down .
If one of the servers needs to be tmporarily removed, it should be marked with the down parameter in order to preserve the current hashing of client IP add

1
2
3
4
5
6
upstream tomcats {
ip_hash;
server 192.168.1.173:8080;
server 192.168.1.174:8080 down;
server 192.168.1.175:8080;
}

负载均衡 url_hash 与 least_conn

根据每次请求的url地址,hash后访问到固定的服务器节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upstream tomcats { 
# url hash hash $request_uri;
# 最少连接数 # least_conn
server 192.168.1.173:8080;
server 192.168.1.174:8080;
server 192.168.1.175:8080;
server {
listen 80;
server_name www.tomcats.com;
location / {
proxy_pass http://tomcats;
}
}
}

Nginx的缓存

  1. 浏览器缓存:
    加速用户访问,提升单个用户(浏览器访问者)体验,缓存在本地
  2. Nginx缓存
    缓存在nginx端,提升所有访问到nginx这一端的用户
    提升访问上游(upstream)服务器的速度
    用户访问仍然会产生请求流量
    控制浏览器缓存:
1
2
3
4
5
6
7
8
9
location /files {
alias /home/imooc;
# expires 10s;
# expires @22h30m;
# expires -1h;
#expires epoch;
# expires off;
expires max;
}

Nginx的反向代理缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
# proxy_cache_path 设置缓存目录 
# keys_zone 设置共享内存以及占用空间大小
# max_size 设置缓存大小
# inactive 超过此时间则被清理
# use_tmp_path 临时目录,使用后会影响nginx性能
proxy_cache_path /usr/local/nginx/upstream_cache keys_zone=mycache:5m max_size=1g inactive=1m use_tmp_path=no
location / {
proxy_pass http://tomcats;
# 启用缓存,和keys_zone一致
proxy_cache mycache;
# 针对200和304状态码缓存时间为8小时
proxy_cache_valid 200 304 8h;
}

使用Nginx配置HTTPS域名证书

  1. 安装SSL模块
    要在nginx中配置https,就必须安装ssl模块,也就是: http_ssl_module 。
    进入到nginx的解压目录: /home/software/nginx-1.16.1
    新增ssl模块(原来的那些模块需要保留)
1
2
3
4
5
6
7
8
9
10
11
12
13
./configure \ 
--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-tmp-path=/var/tmp/nginx/client \
--http-proxy-tmp-path=/var/tmp/nginx/proxy \
--http-fastcgi-tmp-path=/var/tmp/nginx/fastcgi \
--http-uwsgi-tmp-path=/var/tmp/nginx/uwsgi \
--http-scgi-tmp-path=/var/tmp/nginx/scgi \
--with-http_ssl_module
  1. 配置HTTPS
    把ssl证书 *.crt 和 私钥 *.key 拷贝到 /usr/local/nginx/conf 目录中。
    新增 server 监听 443 端口:
1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 443;
server_name www.imoocdsp.com;
# 开启ssl ssl on;
# 配置ssl证书
ssl_certificate 1_www.imoocdsp.com_bundle.crt;
# 配置证书秘钥
ssl_certificate_key 2_www.imoocdsp.com.key;
# ssl会话cache ssl_session_cache shared:SSL:1m;
# ssl会话超时时间 ssl_session_timeout 5m;
# 配置加密套件,写法遵循 openssl 标准
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on;
}

关注【憨才好运】微信公众号,了解更多精彩内容⬇️⬇️⬇️

continuous_deployment