随着软件需求的发展,现在很多的系统都需要保证高可用、高并发,在此需求之下就需要部署的服务能够不间断的提供服务即避免单点故障问题因此系统需要做集群部署同时还能提升qps、tps等指标;集群部署后的服务就需要对用户的请求能够负载均衡,nginx是目前流行的高性能HTTP和反向代理web服务器,占有内存少,并发能力强,能够支持 50000 个并发连接数的响应;主要功能有反向代理、负载均衡、动静分离等。
PCRE(Perl Compatible Regular Expressions)是一个轻量级的Perl函数库,包括 perl 兼容的正则表达式库。它比Boost之类的正则表达式库小得多。PCRE十分易用,同时功能也很强大,性能超过了POSIX正则表达式库和一些经典的正则表达式库。
a、下载pcre安装包
wget方式下载:
wget http://downloads.sourceforge.net/project/pcre/pcre/8.45/pcre-8.45.tar.gz
官网下载 地址 下载后上传到Linux目录中:
b、解压pcre安装包
tar -zxvf pcre-8.45.tar.gz
cd pcre-8.45/ 切换到解压后的目录中
./configure
这一步如果出现如下错误:
configure: error: no acceptable C compiler found in $PATH
则需要安装gcc之后再次执行 ./configure
yum install gcc
如果在执行 ./configure 之后最后提示如下错误:
configure: error: Invalid C++ compiler or C++ compiler flags
则需要安装c++环境之后再次执行 ./configure
yum -y install gcc-c++
d、安装pcre
make && make install
e、检测pcre是否安装成功,能够输出对应版本则安装成功
pcre-config --version
openssl 、zlib 、 c++(如果刚才安装pcre有报错configure: error: Invalid C++ compiler or C++ compiler flags解决该错误时已安装了c++环境,重复安装不会有问题)
yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel
a、下载nginx安装包
wget方式下载:
wget http://nginx.org/download/nginx-1.23.4.tar.gz
官网下载 地址 下载后上传到Linux目录中:
b、解压nginx安装包
tar -zxvf nginx-1.23.4.tar.gz
cd nginx-1.23.4/ 切换到nginx安装包解压目录
./configure
make && make install
安装成功后会在 /usr/local/ 目录下生成一个 nginx 目录
e、启动nginx服务
cd /usr/local/nginx/sbin/
./nginx`
到此nginx安装完成。
访问启动 nginx 的Linux服务器地址,不需要端口,不写端口默认访问80端口。
如果不能成功访问,需要查看nginx是否成功启动,然后排查端口是否放开,比如阿里云服务器需要配置安全组打开对应端口;如果是直接操作防火墙,可以如下方式打开防火墙某个端口。
firewall-cmd --add-port=8080/tcp --permanent 添加8080端口让防火墙放行,将8080端口改为需要放行的端口
firewall-cmd --reload 重新加载防火墙
firewall-cmd --list-all 查看已放行端口中是否有刚刚添加的放行端口,如8080,需要执行重新加载防火墙放行的端口才能看到,才能让放行生效
systemctl status firewalld 查看防火墙状态
systemctl stop firewalld 关闭防火墙
systemctl start firewalld 开启防火墙
systemctl restart firewalld 重启防火墙
systemctl disable firewalld 开机禁用防火墙
systemctl enable firewalld 开机启用防火墙
firewall-cmd --version 查看防火墙版本
firewall-cmd --panic-on 拒绝所有包---不要轻易使用,开启后只能直接操作Linux服务器本身,所有远程方式都不能连接会被拦截掉,比如通过xshell等工具无法连接Linux服务器(已连接的会被中断),所有访问这台Linux服务器的请求也都会被拦截
firewall-cmd --panic-off 关闭拒绝所有包
firewall-cmd --query-panic 查看拒绝所有包是否开启
./nginx -v 查看nginx版本
./nginx -s stop 强制关闭nginx
./nginx -s quit 正常关闭nginx
./nginx 启动nginx
./nginx -s reload 重新加载配置文件
注意:因为这些命令都是基于 nginx 这个可执行文件进行执行的,而这个文件位于 /usr/local/nginx/sbin 目录下,所以上面的命令都需要在该目录下执行。
1、配置文件位置
/usr/local/nginx/conf/nginx.conf
2、配置文件主要内容,配置文件可以分为三部分
a、全局配置块:配置服务器整体运行的配置指令
从配置文件开始到 events 配置块之间的内容,主要设置一些影响 nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。
如:worker_processes 1; 配置,表示 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,会受到硬件、软件等设备的制约。
b、events配置块:影响 Nginx 服务器与用户的网络连接
events配置块即events括号部分,events配置块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等;这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。
如:worker_connections 1024; 配置,表示每个 work process 支持的最大连接数为 1024。
c、http配置块
http配置块是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。
http配置块包括 http 全局块、server 块两部分。
c1、http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。
c2、server 块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本,http 全局块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机,并且每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。
c21、全局 server 块:最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或 IP 配置。
c22、location 块:一个 server 块可以配置多个 location 块,主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称(也可以是 IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理;地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。
nginx配置文件具体配置说明可查看官网
主要配置说明(配置文件中被 # 标记的配置是被注释的,这些配置可能存在默认值,默认值就是被注释的值):
#user nobody; 指定由哪个用户管理nginx的worker进程,虽然是注释的,默认即nobody
worker_processes 1; #指定worker进程数量,nginx在启动时会开启master进程和worker进程,master进程负责校验配置文件以及reload时重新加载配置文件,维护worker进程数量等等,worker进程才是处理用户请求的进程,worker进程数量建议和nginx服务器cpu核数保持一致,如果不知道服务器配置可以写 auto 会自动和cpu核数保持一致,如果想要在修改配置文件后通过-s reload的形式热加载新的配置信息不中断nginx服务,那么需要worker进程有多个也可以防止单个worker挂掉导致服务中断
#error_log logs/error.log; 都是配置日志记录位置,notice和info是日志记录级别,第一个未写默认是error级别,全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid; nginx进程pid号保存位置,里面就一个pid号和master进程保持一致
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统ulimit -n的值)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
#worker_rlimit_nofile 65535;
events {
worker_connections 1024; #worker进程可以同时保持连接的数量,因为每次连接就会打开一个文件句柄(创建一个文件),所以该值受限于系统的文件句柄数约束限制,可以通过 ulimit -n 查看系统文件句柄数限制,临时修改可以通过 ulimit -n 数量 进行调整(只对当前会话生效),永久修改在 /etc/security/limits.conf 文件中添加配置
}
http {
include mime.types; #引用文件(如果是使用vim查看的配置文件,可以将光标移动到文件名(比如这里的mime.types)上,然后快捷键 gf 可以跳转至光标指定的文件中查看某个文件(这里是跳转至mime.types文件中) ,快捷键 ctrl+o 返回上一级(这里就是返回当前这个 nginx.conf 文件中)),一个server配置可以监听一个端口路由到一个服务端地址中,所以一个nginx可以作为多个服务端的入口,一般可以将每个server配置分开写在每个文件中,通过 include 导入这些server配置,为了区分每个server文件的名称可以是当前监听的服务端的域名.conf,引用配置文件的路径可以是绝对地址和相对地址(相对nginx.conf配置文件所在位置)
default_type application/octet-stream; #默认类型:二进制流,即nginx无法识别用户请求文件时,默认将用户的请求文件以二进制流返回给浏览器,然后浏览器会进行下载,也就是有些请求之后会出现下载界面而不是浏览器渲染html界面
#log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 定义日志格式,日志格式名称 main
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main; 定义访问日志,访问日志保存位置及记录访问日志的格式是名称为 main 的日志格式,上面定义的main访问格式和这里使用main格式记录访问日志,被注释了说明这是默认值
server_tokens off; #关闭nginx版本信息,因为nginx目前为止还是有些漏洞的,如果有人知道了版本可以通过这些漏洞攻击服务,所以可以通过该指令关闭nginx版本信息,关闭后nginx默认的html页面不会返回版本号且F12中Response Headers中的server也没有版本信息
sendfile on; #零拷贝开关,提升访问速度,减少一次数据在用户空间和内核空间的读取
#tcp_nopush on; 数据收集到一定大小再发送,减少网络开销
#tcp_nodelay on; 数据实时发送,提升响应速度
#keepalive_timeout 0;
keepalive_timeout 65; #保持TCP/IP连接的超时时间
keepalive_requests 100; #保持TCP/IP连接的请求次数 这两个一起配置的意思就是保持TCP/IP连接的时间是65s并且发送请求的次数不超过100次,超过65s或请求次数超过100次都将重新建立连接
#gzip on; 设置应答是否压缩,默认关闭,如果开启可以看到请求nginx的应答中response Headers中Content-Encoding: gzip,可以通过其他指令设置什么类型的文件需要压缩、多大
deny 192.168.238.132; #拒绝192.168.238.132这个ip地址访问nginx(如果是all则对所有,也可以指定网段比如192.168.238.0/24),如果该ip地址访问nginx则会应答403,deny 配置可以配置在http中、server中、location中、limit_except中,配置在哪里就是对哪个资源生效,如http中对所有server生效、server中对当前server生效,该配置相当于黑名单效果,拒绝某些ip地址访问nginx
allow 192.168.238.132; #允许某个ip地址访问nginx,默认值all,允许所有ip地址访问nginx,同样可以配置网段,允许某些ip地址访问nginx,相当于白名单效果,配置范围和deny一样;当然deny、allow可以一起使用,比如deny为all,allow为127.0.0.1那就是除本机外拒绝所有ip地址访问nginx,比如allow为all,deny为192.168.238.132那就是除192.168.238.132外允许所有ip地址访问nginx
auth_basic: "User auth"; #定义权限响应报文
auth_basic_user_file: "passwd"; #定义权限响应报文控制文件即auth_basic控制权限的文件,passwd是文件所在地址,这里表示和nginx.conf文件同一个目录的名称为passwd的文件(该文件可以通过htpasswd -c /usr/local/nginx/conf/passwd admin(admin是权限认证的用户名) 回车会提示输入密码和确认密码即可创建该文件),这两个配置是访问权限控制,效果是在访问时需要输入用户名和密码才能访问,这两个配置可以在http、server、location、limit_except中配置,分别对http、server、location、limit_except范围生效
server {
listen 80 default_server; #指定监听端口,还可以指定ip+端口,比如127.0.0.1:80,也就是指定监听的网卡+端口,那么要访问该server配置的信息就只能是127.0.0.1:80,即使该linux主机还有其他ip可以访问,如192.168.238.132:80则不能访问,不指定ip仅仅是端口则是对所有网卡进行监听,也可以仅指定ip,那么就是对该网卡的80端口进行监听,也就是可以使用不同的ip和端口实现同一个主机地址(下一行的server_name配置)转发到不同的服务端,default_server表示默认server即如果有多个server都是80端口监听,那么当前server作为80端口的处理server
server_name localhost; #指定服务名,也就是部署nginx服务的这台服务器配置的域名,可以配置多个域名,指定域名后可以通过server_name+listen访问当前server配置的信息,当然也可以配置为ip地址,可以通过配置不同的域名或ip实现转发到不同的服务端
#charset koi8-r; 设置当前server字符集编码,比如访问nginx的主页面,如果将这个html中写入中文,就需要这里改为utf-8否则浏览器访问主页面中文乱码
#access_log logs/host.access.log main; 设置访问日志,同上,该设置只对当前server生效,如果上面也有配置,那么访问当前server时,这里的访问日志配置会覆盖上面的
location / { #监听路径为根路径即请求访问当前server时所有请求都由该location处理相当于是请求该server时的默认location(前提是当前server中没有其他优先级更高的location被匹配到)
root html; #root指定当前location查找文件所在的目录(如下面index指定的文件即在该目录下查找),html目录表示当前配置文件所在目录同一级的html目录即 /usr/local/nginx/html
index index.html index.htm; #index指定访问当前location默认返回哪个文件,配置多个依次匹配
}
#error_page 404 /404.html; 指定发生404错误之后响应的文件,默认值也是该配置
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html; #指定发生500 502 503 504错误之后响应的文件,这里的/指的目录是上面location中root指定的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 8000;
# 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 / {
# proxy_pass http://127.0.0.1:8080/nginx/test/yyy8081;
# }
#location ~ /test/ {
# proxy_pass http://127.0.0.1:8081;
#}
#}
}
location / {
# / 匹配根路径,优先级最低即访问当前server时请求没有被其他location匹配上就由当前location处理,相当于server的默认location
rewrite /a.html /b.html; #rewrite重定向,其中a.html是匹配请求地址是a.html的请求(支持正则匹配,且一个location中可以有多个rewrite),b.html是目标地址,也就是说某个请求访问
#当前server并被当前location匹配时,如果请求地址是a.html那么重定向到b.html地址中,其中rewrite有四种flag:
#last:终止当前location重定向规则,也就是rewrite的flag是last的重定向规则之后的rewrite将不会执行 rewrite /a.html /b.html last;其中b.html是作为请求地址继续匹配其他的location,匹配到其他location之后由其他location定义的规则处理
#break:终止当前location重定向规则,也就是rewrite的flag是break的重定向规则之后的rewrite将不会执行 rewrite /a.html /b.html break;其中b.html不会作为请求地址继续匹配其他的location,而是直接访问b.html这个文件
#redirect:302重定向(临时性重定向,浏览器一直记录重定向之前的地址,每次访问地址时由服务端进行重定向到新地址中,如果服务端有问题浏览器则不能访问到重定向之后的地址中),此时b.html应该换成重定向之后的地址,比如http://192.168.238.132,redirect是默认值
#permanent:301重定向(永久性重定向,浏览器访问服务端之后由于服务端应答301永久性重定向此时浏览器会在缓存中记录重定向之后的新地址,即使服务端出现问题,访问该地址也会被重定向到新地址中),此时b.html应该换成重定向之后的地址,比如http://192.168.238.132
}
location ~* \.(jpg|png)$ {
# ~* 正则匹配,不区分大小写,优先级比 / 高,和~优先级同级如果都能匹配上,哪个location在前面由哪个location处理,这里表示location处理请求jpg或png资源且不区分大小写,如 server定义的ip:端口/images/aa.jpg 或 server定义的ip:端口/images/aa.JPG都由当前location处理
}
location ~ \.(jpg|png)$ {
# ~ 正则匹配,区分大小写,优先级比 / 高,和~*优先级同级如果都能匹配上,哪个location在前面由哪个location处理,这里表示location处理请求jpg或png资源且区分大小写,如 server定义的ip:端口/images/aa.jpg 由当前location处理
}
location ^~ /image/ {
# ^~ 包含匹配,即请求路径中包含定义的路径就由当前location处理,优先级比~*和~高,比如 server定义的ip:端口/image/aa.jpg或server定义的ip:端口/image/a/b.png都由当前location处理
}
location = /image/a.jpg {
# = 是全匹配,优先级最高,即请求路径和当前location定义的一样,这里就是请求路径是 server定义的ip:端口/image/a.jpg
}
nginx防盗链:
盗链:顾名思义盗用链接,比如服务器上的图片等静态资源,可以通过图片在服务器上的地址直接进行访问,那么三方网站就可以将这个图片的地址放在自己的前端页面中,这样访问这个三方网站时,不仅可以看到这个图片并且还没有消耗三方网站的资源。
nginx防盗链配置:因为http/https请求会在Request Headers中带上一个referer参数用来表示当前请求从哪个地址发起的(发起这个请求的网页地址),那么三方网站和我们自己的网站这个referer肯定是不一样的,因此就可以在nginx中配置referer验证,用来识别哪些地址发起的请求可以正常处理否则返回403或错误图片等信息;但是referer参数可以通过程序进行修改伪装,所以这种方式防盗链并非完全可靠,但可以杜绝大部分情况。
nginx配置:
location ~* \.(gif|jpg|png|swf|flv)$ { #配置location匹配的地址,也就是图片、视频等文件需要执行下面的防盗链处理
valid_referers none blocked xxx.com 172.11.xx.xx; #配置允许请求的referer地址来源,可以*等通配符
if ($invalid_referer) { #判断请求的referer地址是否在valid_referers配置的允许访问地址中
#rewrite /(.*) /403.jpg break; #如果不是valid_referers配置的允许访问的地址来源,重定向返回一张403.jpg图片,注意break,因为返回的403.jpg也是符合当前location的配置路径,那么又会进行防盗链判断,就会导致死循环,所以返回403.jpg需要break
return 403; #如果不是valid_referers配置的允许访问的地址来源直接返回403
}
}
说明:
none:允许没有referer参数的请求访问,比如通过浏览器地址栏直接访问img的url,这时的请求就没有referer参数,所以允许这类请求访问那么就可以配置valid_referers包含none参数。
blocked:允许请求有referer参数,但referer的内容被’防火墙或者代理服务器’删除了,允许这类请求访问就可以在valid_referers中包含blocked参数。
xxx.com/172.11.xx.xx:具体的域名或ip地址,也就是允许请求访问的referer参数的域名和ip地址即请求来源的网站的域名和ip。
$invalid_referer:获取valid_referers匹配的结果,如果请求的地址不在valid_referers配置的参数中返回1,否则返回0。即 $invalid_referer值为1时表示请求的地址没有在valid_referers配置的允许路径中,那么就应当拒绝请求,否则允许访问,可以通过if( $invalid_referer = 0)判断当前请求的referer地址在valid_referers参数中,返回403,实现黑名单效果即valid_referers参数配置的地址不允许访问。
防盗链的配置可以配置在任何的location块中,比如根路径的location / {}也是可以配置的,相当于对目录进行防盗链配置。
nginx限流:
有时候为了防止某个客户端下载资源占用大量网络资源,导致其他客户端使用变慢,可以通过限制客户端的下载占用网络资源,实现多个客户端使用体验均衡。
limit_rate限流配置可以在http中、server中、location中配置,这里以location为例:
limit_conn_zone $binary_remote_addr zone=test111:10m; #这块配置定义在http全局块中(即http块中但不在server块中),意思是以二进制的形式(binary_remote_addr)记录访问某个地址(这里是定义test111为访问地址,这个地址一般可以设置为server块中的server_name地址配合限制命令达到限制访问某个server的效果)的状态,记录状态的内存大小设置为10m
location / {
limit_rate: 1k; #客户端下载时每秒限速1k
limit_rate_after: 10k; #客户端下载时10k之后才进行限速即10k之前不限速,由于上面配置了limit_rate: 1k那么效果就是客户端请求下载时前10k不限速,超过10k的部分限速每秒1k,这里的两个配置存在一个问题,仅仅是针对单个请求的限制,也就是说每个请求都可以前10k不限速,那么客户端就可以通过多线程的请求方式利用前面10k不限速很快将资源下载完毕,比如linux命令 wget -c xxxxx/test.png 这种方式下载就可以实现继续下载,linux中执行该命令多次,那么后续执行的该命令就会在前一个命令下载的资源基础上进行下载而不是独立的重新下载,就可以实现同时执行多次该命令利用前10k不限速很快下载好资源
limit_conn test111 2; #限制和test111这个zone可以建立的连接数为2,test111是上面定义的 limit_conn_zone 中的记录状态的地址,这个限制加上后就可以防止客户端使用多线程或执行多次wget -c的形式快速下载资源,因为限制为2之后意味着同时只能存在两个连接,继续开线程请求或wget -c会提示503
root html;
index index.html index.htm;
}
反向代理是对服务端的代理,客户端请求服务端时不需要知道服务端的具体地址,直接把反向代理服务器(如nginx)当作服务端请求即可获取服务端返回的结果,客户端不需要做任何的配置。
正向代理是对客户端的代理,比如客户端不能访问某个服务端通过的方式去访问服务端,正向代理需要客户端做一定的配置。
1、绑定域名解析
如果是公网的域名需要在购买域名的平台绑定该域名解析的服务器ip地址信息,也就是绑定到启动nginx服务的服务器ip;
如果是本地测试,可以在windows的hosts文件中绑定域名和ip关系;
hosts文件路径:C:\Windows\System32\drivers\etc
前面ip是要绑定的服务器ip,也就是windows上安装的虚拟机的ip,后面的域名自定义。
这一步目的是可以通过域名访问nginx服务,如果不配置直接使用nginx服务器的ip及监听端口也可以访问。
2、启动需要转发的目标服务
在 192.168.238.132 这台服务器上启动一个Java服务其中有个接口如下(第一步在hosts文件中配置了域名解析,所以这里可以用域名访问 192.168.238.132 这台服务器)
3、配置nginx配置文件,配置反向代理转发的信息,将请求转发到Java服务上
配置server块中location的规则,匹配某个路径转发到对应服务上
proxy_pass http://192.168.238.132:8080; 这个配置作用是将访问路径中的ip及端口替换为http://192.168.238.132:8080进行访问
为了防止单节点故障,一般可以对一个服务做集群部署,那么就需要部署的多个服务节点都可以处理客户端的请求,就需要将客户端的请求分发给每个服务节点。
1、在http全局块中定义服务节点配置信息即定义需要负载的服务节点信息
upstream testlb{ #testlb是自定义名称,server定义每个服务端的ip端口信息
server 192.168.238.132:8080;
server 192.168.238.132:8081;
}
2、location定义需要负载的upstream
proxy_pass http://testlb; #testlb是http全局块中定义的upstream名称
3、重启nginx或重新加载nginx配置文件测试
负载均衡规则:
a、轮询:默认规则,依次循环将请求转发给每个服务端,如果服务端挂掉,会自动剔除。
b、weight:权重轮询,默认1(数值越大权重越大),将客户端请求按权重比例转发给服务端(按照轮询+权重转发)。
配置方式:
upstream testlb{
server 192.168.238.132:8080 weight=1; #http全局块中upstream配置服务节点的weight
server 192.168.238.132:8081 weight=2;
}
c、ip_hash:按照客户端请求ip地址进行hash计算,确定某个服务节点处理请求,只要是同一个客户端ip则都会由该服务节点处理(因为ip地址一样计算出来的处理请求服务节点一样),可以解决session共享问题(因为session保存在服务器中,如果下次请求给了其他服务器处理,就会有session问题)。
配置方式:
upstream testlb{
ip_hash; #http全局块中upstream配置加入ip_hash
server 192.168.238.132:8080;
server 192.168.238.132:8081;
}
d、fair:按照服务端处理请求时间进行分配客户端请求处理的服务节点,时间越短优先分配该服务节点处理请求(可能部署同一个服务的服务器配置不同这就会导致每个服务器在处理请求时时间有差距,服务器配置越好处理请求时间越短,那么fair这种负载均衡方式就可以比较均衡的利用服务器资源)。
upstream testlb{
fair; #http全局块中upstream配置加入fair
server 192.168.238.132:8080;
server 192.168.238.132:8081;
}
直接修改配置文件中负载均衡方式为fair会报错,这是第三方提供的功能,需要另外安装nginx-upstream-fair包。
将动态请求和静态请求分开处理,比如html、css、image这些信息就是静态信息,直接交给nginx处理,而需要后端服务处理的请求比如查询数据库数据则交由服务端处理,这样就避免了不需要服务端处理的请求也占用服务端资源的情况,提升处理效率。
通过配置location规则匹配请求是动态还是静态请求做相应转发处理,实现动静分离。
比如所有jpg或png的请求都在某个目录下查找对应资源,而不是请求服务端,配置如下:
location ~ \.(jpg|png)$ { #所有.jpg或.png的请求都在 /testjpg/ 目录下查找资源返回
root /testjpg/;
}
通过nginx实现反向代理、负载均衡、动静分离这些功能后,因为流量的入口在nginx服务,如果nginx服务出现单点故障的问题,那就会导致整个服务端功能都不可使用,因此就需要nginx服务做集群部署,以便保证nginx某些服务出现故障时,也有部分正常的nginx服务可以提供相关功能;新的组件能够感应到集群中的每个nginx服务节点并判断节点的状态是否正常,如果故障则不能将请求转发给对应nginx服务节点,如果正常则可以转发。
这里选用keepalived来构建nginx服务集群,做nginx的高可用设置,注意:keepalived的原理是通过将虚拟ip添加在某个节点的网卡上,那么就可以通过这个虚拟ip访问到对应的节点,从而访问到这个节点对应的nginx服务(那么这个节点的nginx服务就可以根据请求的url和nginx配置文件的server、location进行匹配做出相应的响应);所以keepalived的作用是通过监听每个节点上nginx服务的状态判断当前节点的nginx是否正常如果不正常则将对应节点的keepalived服务也进行关闭,如果关闭的keepalived节点是master节点,那么keepalived会自动根据剩余正常节点上的keepalived服务的优先级选定新的master节点,并将keepalived中定义的虚拟ip添加到新的master节点的网卡中,那么客户端通过这个虚拟ip访问时就会访问到新的可用nginx节点上,因此不需要运维人员做手动切换就可以持续对外提供服务。也就是说keepalived只是对真实服务(这里是nginx)做一个热备操作,并没有负载均衡的功能,即使有多个nginx备份服务也只会由keepalived为master节点的nginx服务对外提供服务,其他备份nginx服务只是在master节点的nginx不可用时通过keepalived自动选举新的master节点继续对外提供服务并且新的master能够成功选举的前提是旧的master已经关闭(这部分可以通过在keepalived配置文件中定义健康检查nginx服务的脚本,一旦当前节点的nginx服务异常,那么就关闭当前节点的keepalived服务),后端服务的反向代理、负载均衡、动静分离由nginx实现。
检测后端真实服务是否正常可以通过配置keepalived配置文件或配置健康检查脚本实现,而keepalived集群中只有MASTER节点会向BACKUP节点发送心跳包,如果BACKUP节点没有接收到MASTER节点发送的心跳包,那么就认为MASTER节点down了,需要根据优先级选出新的MASTER节点对外提供服务(所以健康检查脚本中需要有关闭当前节点keepalived服务的功能)。
1、安装keepalived服务
注意:安装keepalived服务需要在每个安装nginx服务的服务器上都安装
a、yum方式安装(需要连网)
安装命令:
yum install keepalived -y #-y是安装过程中需要确认yes/no的选择,都选择yes
查看安装版本:
rpm -q -a keepalived
b、安装包方式
keepalived安装包官方下载地址
b1、创建一个文件夹并将keepalived安装包上传至该文件夹中
b2、解压安装包并编译和安装
tar -zxvf keepalived-1.3.5.tar.gz
cd keepalived-1.3.5/
./configure --prefix=/usr/local/keepalived #编译时指定keepalived目录为 /usr/local/keepalived
make && make install #安装
/usr/local/keepalived/sbin/keepalived -v #查看keepalived版本
b3、安装后此时启动会有报错,无法启动,需要做如下配置
b31、keepalived启动默认读取 /etc/keepalived/keepalived.conf 配置文件,但是通过刚才的安装方式配置文件在 /usr/local/keepalived/etc/keepalived/keepalived.conf ,需要将此配置文件拷贝到 /etc/keepalived/ 目录中
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ #如果 /etc/keepalived/ 目录不存在先创建该目录
b32、设置PIDFile文件
vim /lib/systemd/system/keepalived.service #编辑该文件将其中的PIDFile配置改为 PIDFile=/var/run/keepalived.pid(该文件不存在需要先创建该文件)
systemctl daemon-reload #重新载入 systemd,扫描新的或有变动的单元
service keepalived start #启动 keepalived
systemctl status keepalived.service #查看 keepalived.状态
不做以上两步启动时会有类似报错:
keepalived相关操作指令:
#开机启动
chkconfig keepalived on
#启动服务
service keepalived start
#停止服务
service keepalived stop
#重启服务
service keepalived restart
#查看状态
service keepalived status
2、修改相关配置
yum安装方式配置文件是 /etc/keepalived/keepalived.conf ;安装包安装方式也将配置文件复制到了 /etc/keepalived/keepalived.conf ;所以修改配置文件时都是修改该配置文件。
配置文件说明:
虚拟路由器指由一组keepalived服务器实现的可供访问的vip并且可路由到对应真实服务上。
VRRP协议(Virtual Router Redundancy Protocol,虚拟路由冗余协议)。
! Configuration File for keepalived
global_defs { #全局配置
notification_email { #发生故障时需要发送告警邮件的地址
[email protected] #每行定义一个需要通知告警信息的邮件地址
[email protected]
[email protected]
}
notification_email_from [email protected] #发送邮件的发件人邮箱地址
smtp_server 192.168.200.1 #smtp服务器地址(也就是说发送的邮件遵循SMTP协议,这里定义发送邮件的服务器地址),可以是ip或域名.可选端口号 (默认25)
smtp_connect_timeout 30 #连接 smtp_server 的超时时间
router_id LVS_DEVEL #当前节点标识,一般为hosts文件中配置的hostname,故障发生时,邮件通知会用到该router_id
vrrp_skip_check_adv_addr #keepalived会对所有通告报文都进行检查,比较消耗性能,开启当前配置后,如果收到的通告报文和上一个报文是同一个路由器则跳过检查,默认值为全检查;
vrrp_strict #严格执行VRRP协议规范,此模式不支持节点单播
vrrp_garp_interval 0 #设置ARP接口之间发送免费报文的延迟时间,可以精确到毫秒,默认值0
vrrp_gna_interval 0 #设置非请求消息的发送延迟时间,默认为0
#vrrp_mcast_group4 #指定组播IP范围,可选择224.0.0.0到239.255.255.255之间的地址,默认为224.0.0.18
#vrrp_iptables #与vrrp_strict同时设置时可禁止iptables规则的生成,不设置vrrp_strict时可不加此项
}
vrrp_script check_nginx_service { #VRRP 脚本配置,check_nginx_service是自定义名称,即设置健康检查的脚本信息
script "/etc/keepalived/check_nginx.sh" #设置需要执行的脚本,主要两个作用第一是定义健康检查需要执行的内容即判断后端真实服务是否存活,第二则是当健康检查失败时杀掉当前节点的keepalived,因为只有keepalived的MASTER节点挂掉之后才能将BACKUP节点选举为新的MASTER
interval 3 #运行脚本的间隔时间,秒
weight -2 #权重,即每次健康检查失败当前节点的priority值就会减少2,对于主服务器来说就是主服务器发生故障时,priority减去此值之后需要小于备服务器的priority值
fall 3 #检测几次失败认为失败,整数
rise 2 #检测几次正常认为正常,整数
user keepalived_script #执行脚本的用户或组
}
vrrp_instance VI_1 { #vrrp_instance 用于配置虚拟路由器,VI_1 是自定义名称
state MASTER #设置当前节点在keepalived集群中的初始状态,MASTER/BACKUP
interface eth0 #设置虚拟路由器使用的物理网卡,如eth0、bond0、ens33、br0等(通过在节点上使用ifconfig查看当前节点有哪些物理网卡,对应节点上的keepalived配置文件interface设置为该物理网卡),可以和VIP地址不在同一张网卡上;lvs绑定在网卡上,realserver绑定在回环接口上。区别是lvs对访问为外,realserver为内不易暴露本机信息
virtual_router_id 51 #设置虚拟路由器的唯一标识,取值范围为0-255,每个虚拟路由器的该项值必须是唯一的,否则无法启动服务,并且同属一个虚拟路由器的多个keepalived节点必须相同,务必要确认在同一网络中此值必须唯一,也就是说如果当前虚拟路由器由部署在两台服务器上的keepalived集群组成,那么这两台服务器上的keepalived服务配置文件中该值要一样
priority 100 #设置当前节点在虚拟路由器中的优先级,优先级取值范围为1-254,值越大优先级越高,由优先级决定主备关系,每个keepalived节点取值不同,所以初始化时MASTER比BACKUP高
nopreempt #非抢占模式,比如MASTER挂掉之后某个BACKUP成为新的MASTER之后,此时已经挂掉的旧的MASTER重新启动之后是否进行抢占为MASTER,nopreempt 配置后,那么旧的MASTER不进行抢占,不配置则进行抢占;该参数只在 state 为BACKUP时生效,所以配置 nopreempt 参数时建议主备keepalived都配置为BACKUP,让keepalived通过 priority 的优先级选定MASTER
advert_int 1 #设置VRRP通告(即MASTER与BACKUP节点间同步检查)的时间间隔,单位秒,默认为1秒,同一组keepalived服务器(即同一个keepalived集群)每个节点设置值一样
authentication { #设置VRRP通告验证,同一虚拟路由器使用相同的密码才能正常通信
auth_type PASS #验证类型:PASS、AH ,AH为IPSC互联网安全协议认证,PASS为简单密码认证,推荐PASS认证
auth_pass 1111 #验证密码设置,仅前8位有效,同一虚拟路由器的多个keepalived节点auth_pass值必须保持一致
}
virtual_ipaddress { #设置虚拟路由器的VIP,并可设置VIP对应的子网掩码、网卡和标签等,可设置多个,不同的VIP分行隔开,不指定网卡时默认添加在eth0上,不设置子网掩码时默认为32位。在添加VIP地址时,需确保将要使用的VIP不存在,即还没被使用,也就是说当前keepalived集群可以使用以下ip进行访问,实际效果是会将以下的ip地址生成在MASTER节点的对应网卡中,因为是通过 ip addr的方式添加的ip,所以在节点上查看是否在网卡上生成vip时需要通过ip addr或hostname -I查看,通过ifconfig查看不到,并且keepalived集群启动后之后只在当前MASTER节点生成vip,如果多个节点都有生成vip则出现了脑裂问题,出现脑裂
192.168.200.16
192.168.200.17
192.168.200.18
}
virtual_ipaddress_excluded { #设置虚拟路由器排除的vip
192.168.200.19
}
track_script { #指定健康检查脚本
check_nginx_service #健康检查脚本名称即上面 vrrp_script 定义的脚本名称
}
notify_master "/etc/keepalived/master_haproxy.sh" #设置当前节点成为master时执行的脚本
notify_backup "/etc/keepalived/backup_haproxy.sh" #设置当前节点成为backup时执行的脚本
notify_fault "/etc/keepalived/fault_haproxy.sh" #设置当前节点出现故障时执行的脚本
notify_stop "/etc/keepalived/stop_haproxy.sh" #设置停止VRRP时执行的脚本
}
virtual_server 10.10.10.3 1358 { #设置虚拟服务器,将虚拟路由器中添加的VIP与后端real server对应起来,后面的ip是virtual_ipaddress中定义的其中一个vip,空格隔开,虚拟服务的端口号,即定义哪个vip和端口对应的真实服务器信息
delay_loop 3 #设置健康检查后端服务器的时间间隔,单位秒
lb_algo rr #设置负载均衡调度算法,互联网应用常用方式为wlc或rr,可选值有rr、wrr、lc、wlc、lblc、sh和dh
lb_kind NAT #设置负载均衡转发规则,DR|NAT|TUN 3种,一般使用路由(DR)
persistence_timeout 50 #设置持久连接超时时间,单位是秒
protocol TCP #设置服务协议,如TCP、UDP和SCTP,一般使用TCP
sorry_server 192.168.200.200 1358 #设置当所有后端服务器(即real_server)都不可用时的备用真实服务器ip和端口
real_server 192.168.200.4 1358 { #设置当前VIP及端口所对应的后端真实服务器IP和端口
weight 1 #设置当前 real_server 的权重,默认1,值越大越优先访问
HTTP_GET { #设置当前 real_server 的健康状况检查方法,可选值有SSL_GET、HTTP_GET、TCP_CHECK、SMTP_CHECK和MISC_CHECK
url { #定义健康检查url
path /testurl/test.jsp #健康检查url路径
digest 640205b7b0fc66c1ea91c463fac6334d #页面MD5摘要信息,可以通过命令查看:http类型:genhash -s [IP] -p [端口号] -u [url] https类型:genhash -S -s [IP] -p [端口号] -u [url],[IP]替换成真实ip地址,这里是当前 real_server 的ip地址,[端口号]替换成真实端口号,这里是当前 real_server 需要健康检查的端口号,[url]替换成真实url,这里是path的值即/testurl/test.jsp;比如这里是http类型那么查看健康检查的页面的digest值命令就是:genhash -s 192.168.200.4 -p 1358 -u /testurl/test.jsp;通过yum安装的keepalived也会安装genhash 指令
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3 #健康检查连接真实服务超时时长,单位:秒
#retry 3 #重连次数
nb_get_retry 3 #健康检查重试次数
delay_before_retry 3 #健康检查重试间隔时长
#connect_port 80 #健康检查真实服务器端口号
}
}
real_server 192.168.200.5 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
配置keepalived集群构建虚拟路由器:
总共需要配置以下部分:
2.1、全局配置中配置 router_id 为当前节点的hostname
2.2、vrrp_instance 中定义当前节点的state、interface、priority、virtual_router_id、advert_int、authentication、virtual_ipaddress 信息,其中主备节点除state分别设置为MASTER和BACKUP,以及priority的值MASTER比BACKUP大,interface根据节点的网卡设置之外其余配置主备都一样,到这里完成了keepalived本身高可用主备的配置,接下来对需要被keepalived监控的真实服务做健康检查配置
2.3、添加健康检查真实服务的脚本,目的是某个节点的真实服务down掉之后将当前节点的keepalived也主动关闭,以便让keepalived集群自动完成新的可用master节点的选举,并写入虚拟ip到新的节点中
具体配置如下:
MASTER:
! Configuration File for keepalived
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id master #MASTER节点的hostname
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script check_nginx_service { #健康检查脚本
script "/etc/keepalived/check_nginx.sh"
interval 3
weight -2
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER #主节点设置为MASTER
interface ens33 #主节点使用的网卡
virtual_router_id 51
priority 100 #主节点初始优先级,需要比BACKUP大
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.238.100 80 #vip
}
track_script { #指定健康检查脚本
check_nginx_service
}
}
BACKUP:
! Configuration File for keepalived
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id slave1 #BACKUP节点的hostname
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script check_nginx_service { #健康检查脚本
script "/etc/keepalived/check_nginx.sh"
interval 3
weight -2
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP #从节点设置为BACKUP
interface ens33 #从节点使用的网卡
virtual_router_id 51
priority 99 #从节点初始优先级
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.238.100 #vip
}
track_script { #指定健康检查脚本
check_nginx_service
}
}
检测nginx服务脚本:
#!/bin/bash
A='ps -C nginx -no-header |wc -l'
if [ $A -eq 0 ];then
/usr/local/nginx/sbin/nginx #如果nginx服务处于关闭状态,那么启动nginx服务
sleep 2
if [ 'ps -C nginx --no-header |wc -l' -eq 0 ];then #如果nginx服务无法启动,说明节点可能存在问题,那么关闭当前节点keepalived服务
service keepalived stop
fi
fi
3、测试
启动所有节点的nginx和keepalived服务。
所有节点都正常时,通过ip addr可以看到配置文件中设置为master节点的网卡中存在vip信息,那么此时通过vip访问时就是访问master节点的nginx服务,关闭master节点的nginx服务(脚本中会在监听到nginx服务down掉之后自动关闭当前节点的keepalived服务,如果未关闭则可能是脚本检测配置或脚本有问题),再次通过ip addr查看节点的ip,那么之前master节点vip已删除,新master节点的网卡中存在vip,此时通过虚拟ip访问时就是访问新master节点的nginx服务。