Java架构直通车:LVS+Nginx实现高可用集群
LVS+Nginx实现高可用集群
Nginx(engine x)是一个高性能的 HTTP 和反向代理web 服务器,同时也提供 IMAP/POP3/SMTP服务。
- 反向代理
- 通过配置文件实现集群和负载均衡
- 静态资源虚拟化
常见服务器
- MS IIS asp.net
- Weblogic、Jboss 传统行业 ERP/物流/金融/电信
- Tomcat、Jetty J2EE
- Apache、Nginx 静态服务、反向代理
- Netty 高性能服务器编程
安装 Nginx(CentOS)
命令 | 解释 |
---|---|
–prefix | 指定nginx安装目录 |
–pid-path | 指向nginx的pid |
–lock-path | 锁定安装文件,防止被恶意篡改或误操作 |
–error-log | 错误日志 |
–http-log-path | http日志 |
–with-http_gzip_static_module | 启用gzip模块,在线实时压缩输出数据流 |
–http-client-body-temp-path | 设定客户端请求的临时目录 |
–http-proxy-temp-path | 设定http代理临时目录 |
–http-fastcgi-temp-path | 设定fastcgi临时目录 |
–http-uwsgi-temp-path | 设定uwsgi临时目录 |
–http-scgi-temp-path | 设定scgi临时目录 |
Nginx 的进程模型
- master 进程:主进程
- worker 进程:工作进程
Nginx 事件处理
使用了多路径复用器,在出现了阻塞时一个 worker 可以处理多个客户端请求
nginx.conf 配置结构
BIO:同步阻塞
NIO:同步非阻塞
AIO:异步非阻塞
nginx.conf 核心配置文件
参数名 | 参数意义 |
---|---|
$remote_addr | 客户端ip |
$remote_user | 远程客户端用户名,一般为:’-’ |
$time_local | 通用日志格式的本地时间,例13/May/2019:08:30:23 +0800 |
$request | 请求方法,例 GET, POST |
$status | 响应状态码,例200 |
$body_bytes_send | 响应内容字节数 |
$http_referer | 进入页面的前一个链接 |
$http_user_agent | 用户代理,可判定访问所使用的浏览器、客户端 |
$http_x_forwarded_for | 通过代理服务器来记录客户端的ip |
静态文件两种配置方式(其中 xxx 为服务器中/home 下的静态文件目录名):
gzip 压缩配置示例
#开启 gzip 压缩功能以提高传输效率、节约带宽 gzip on; #限制最小压缩,小于1字节文件不进行压缩 gzip_min_length 1; #压缩比,级别为1-9,级别越高相应CPU 占用也越多 gzip_comp_level 3; #压缩文件类型 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
location的匹配规则
Hosts 文件管理工具(兼容多平台):SwitchHosts,通过它可避免手动去编辑系统 hosts 文件
Nginx 的跨域
CORS(Cross-Origin Resource Sharing)
解决跨域的方案Jsonp, SpingBoot Cors, Nginx
Nginx静态资源防盗链
负载均衡
四层负载均衡
- F5硬负载均衡(基于硬件)
- LVS四层负载均衡
- HAProxy 四层负载均衡
- Nginx 四层负载均衡
七层负载均衡
- Nginx 七层负载均衡
- HAProxy 七层负载均衡
- Apache 七层负载均衡
DNS地域负载均衡
层级 | 名称 | 说明 |
---|---|---|
第七层 | 应用层 | 与用户行为交互 |
第六层 | 表示层 | 定义数据格式以及数据加密 |
第五层 | 会话层 | 创建、管理以及销毁会话 |
第四层 | 传输层 | 创建、管理请求端到响应端(端到端)的连接 |
第三层 | 网络层 | 请求端的IP地址 |
第二层 | 数据链路层 | 提供介质访问与链路管理 |
第一层 | 物理层 | 传输介质,物理媒介 |
集群配置
本地集群可使用多台虚拟机,或直接在单台Linux机器上使用 Docker
我们连续启动了3个Docker
Jmeter
下载链接:https://jmeter.apache.org/download_jmeter.cgi
下载后 Windows 双击 jmeter.bat,macOS双击 jmeter 执行文件即可打开可视化窗口
1、测试计划>线程组:配置线程(用户)数和循环次数
2、线程组>采样器>HTTP 请求:配置请求的域名、端口等
3、测试计划>监听器:添加查看结果树、聚合报告、用表格查看结果等
着重对比单机和集群的异常率(聚合报告),以了解所能负载的用户数,一般超过20%即超出了异常极限
负载均衡 – 轮询、权重
负载均衡默认使用轮询,平均逐一分配给集群内的服务器;可通过配置来设置加权轮询
# 加权轮询配置(数值越小,分配的流量越少) upstream xxx { server 172.17.0.2:8080 weight=1; server 172.17.0.3:8080 weight=3; server 172.17.0.4:8080 weight=5; }
upstream指令参数
更多内容参见:官方文档,其中各参数的配置方法同上述的 weight,以下设置均位于 upstream 中
- max_conns
限制一台服务器的最大连接数,在有多个 worker 进程时因共享内存实际会超出
默认为0,不做任何限制
通过将 worker 设置为1,使用 Jmeter 可进行测试(线程组Ramp-Up 时间设置为0)
示例:server 172.17.0.2:8080 max_conns=2; - slow_start
让服务器缓慢加入集群,配合 weight 使用,当前仅适用于商业版
示例:server 172.17.0.4:8080 weight=5 slow_start=60s; - down
标识服务器为不可用
示例:server 172.17.0.2:8080 down; - backup
标识服务器为备用服务器,在主服务器都挂掉时启用
示例:server 172.17.0.2:8080 backup; - max_fails
fail_timeout所设置时间内失败尝试次数,默认值为1,若达到失败尝试上限次数,则判定为宕机 - fail_timeout
配合 max_fails 使用,默认为10秒,对判定为宕机的服务在达到 fail_timeout 的时长后会重新尝试连接
示例:server 172.17.0.2:8080 backup max_fails=2 fail_timout=10s;
keepalive吞吐量,用于设置长连接处理的数量
示例:keepalive 32;
对于 http,还应进行如下设置(location 内):
负载均衡 – ip_hash
hash 算法:用户ip哈希对服务端节点数取模获取下标:
hash(ip) % node_counts = index
数据库分表哈希算法同理,如将 ip 替换为 pid
配置:
nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c
... iphp->addrlen = 3; ... for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) { hash = (hash * 113 + iphp->addr[i]) % 6271; } ...
根据以上 Nginx 的源码文件可以分析出 ip_hash实际上取的是 IP 的前3段,因此通过内网(如hash( 192 168 1 ))将访问同一台主机。
注意:使用 ip_hash 如果有服务器出现故障不能直接移除,而是应将其标记为 down
一致性哈希算法
ip_hash 在有节点宕机时节点数就会发生变化,自然所有下标也即访问的主机也会发生变化 。这样用户会丢失原有的 session,缓存无效,基于这一缺点引入了一致性哈希算法。
一致性哈希算法在0到232-1之间,根据用户和服务器节点的哈希值按顺时针就近原则决定用户所访问的服务器节点,这样不论是增加服务器节点还是减少服务器节点,都只有少数用户受到影响,并且依然保持相同的原则。
负载均衡 – url_hash,least_conn
url_hash 是根据请求 url 进行哈希,然后与节点数取模得出下标
hash(url) % node_counts = index
url_hash 在 url 发生变化时(如请求链接后多一个/)请求的服务器就会发生变化
least_conn 是最小连接数,实际含义是将请求发送到 连接数/权重 值最小的服务器上,以避免有些服务器节点出现闲置的状况:
upstream xxx { least_conn; server ... }
缓存
- 静态资源缓存浏览器
expires 指令 - 上游服务器资源缓存到 Nginx端
Nginx配置SSL(HTTPS)
首先要确定 Nginx有没安装了ssl 模块
配置示例
动静分离
- 分布式
- 前后端解耦
- 静态归 Nginx
- 接口服务化
静态数据:css/js/html/images/audios/videos/…
动态数据:得到的响应可能会和上一次不同
实现方式
- CDN:将静态资源放到第三方CDN 平台
- Nginx:将静态资源放到 Nginx 服务器或上游集群服务器
动静分离的问题
- 跨域
- SpringBoot
- Nginx
- Jsonp
- 分布式会话
- 分布式缓存中间件Redis
Nginx高可用HA
主、备 Nginx
Keepalived:
- 解决单点故障
- 组件免费
- 可以实现高可用HA机制
- 基于VRRP协议(Virtual Router Redundancy Protocol)
- 解决内网单机故障的路由协议
- 构建有多个路由器 MASTER BACKUP
- 虚拟 IP – VIP(Virtual IP Address)
Keepalived安装
下载地址:keepalived.org
以当前版本2.0.19为例:
主要配置
启动和关闭服务
本地测试可通过绑定hosts 文件指向虚拟 IP 地址,备服参照主服配置,state 设置为BACKUP、权重设置低于主服务器即可
编写检测脚本/etc/keepalived/check_nginx_alive_or_not.sh,在 Nginx 中断时自动启动服务:
添加配置
Keepalived 双主热备
以上使用的Keepalived 双机主备一个主要的缺点是在MASTER 运行正常的情况下,从服务器将保持闲置的状态,因此让我们来了解一下双主热备,即互为主备:
通过设置多个虚拟 IP 并使用 DNS 轮询的方式实现(阿里、腾讯等平台的域名解析中均可将A记录如 www 解析到不同域名并设置权重)
配置类似前面,将原有的配置拷贝一份,比如在备用服务器上再使用另一个虚拟 IP 配置其为主服务器:
相应地原主服务器也需要再进行一份备用服务器的配置
LVS负载均衡
- Linux Virtual Server
- 章文嵩博士主导的开源负载均衡项目
- LVS(ipvs)已被集成到 Linux 内核中
- 负载均衡调度器(四层)
官方网站:http://linux-vs.org/
为什么要使用LVS+Nginx?
- LVS基于四层,工作效率高
- 单个 Nginx 承受压力有限,需要集群
- LVS 充当 Nginx集群的调度者
- Nginx 接受请求来回,LVS 可以只接受不响应
LVS 的三种模式
- NAT
请求通过 LVS,响应通过 LVS - TUN
请求(上行)经过 LVS,响应(下行)不经过 LVS,每个节点必须要有网卡,节点对公网暴露 - DR(Direct Routing)
请求经过 LVS,响应通过路由,推荐使用
LVS DR模式搭建
服务器示例如图所示
VIP:虚拟 IP
RIP:真实服务器 IP
注:云服务器需购买负载均衡或虚拟 IP 才可实现配置, Nginx 服务器配置对应本地回环(lo)的原因是其处理响应
LVS-DR模式的其它配置
arp-ignore:ARP 响应级别(处理请求)
- 0:只要本机配置了 ip,就能响应请求
- 1:请求的目标地址到达对应的网络接口,才会响应请求
推荐配置为1
arp-announce:ARP通告行为(返回响应)
- 0:本地上任何网络接口都向外通告,所有的网卡都能接收到通告
- 1:尽可能避免本网卡与不匹配的目标进行通告
- 2:只在本网卡通告
推荐配置为2
LVS配置
-A:添加集群
-t:tcp协议
ip地址:设定集群的访问ip,也就是LVS的虚拟ip
-s:设置负载均衡的算法,rr表示轮询
-p:设置连接持久化的时间,默认300秒
-a:添加真实服务器
-r:真实服务器的ip地址
-g:设定DR模式
Keepalived+LVS高可用
在主备 LVS 服务器上安装 Keepalived,方法参见上方Keepalived安装
以上即实现了高可用的 LVS+Keepalived 方案
LVS 负载均衡算法
静态算法
根据 LVS 自有固定算法分发用户请求
1、轮询(Round Robin – rr):平均分配请求(同 Nginx的轮询)
2、加权轮询(Weight Round Robin – wrr): 按照权重比例分配用户请求,权重越高,分配请求越多(同 Nginx 的权重)
3、源地址散列(Source Hash – sh):同 IP 用户由相同 RS 处理(同 Nginx 的 ip_hash)
4、目标地址散列(Destination Hash – dh):根据不同 url 请求不同的 RS(同 Nginx的 url_hash)
动态算法
根据流量或服务器压力不同分配用户请求
1、最小连接数(Least Connections – lc):将请求分配给连接最小的服务器
2、 加权最小连接数(Weight Least Connections – wlc):用数值表示服务器处理性能,将请求分发到性能好且空闲的服务器
3、 最短期望延迟(Shortest Expected Delay – sed):是一种特殊的 wlc 算法,将请求交给运算结果最小的服务器,设服务器 A、B、C的权重为1、2、3,计算方式如下:
- A: (1+1)/1=2
- B: (1+2)/2=3/2
- C: (1+3)/3=4/3
4、 最少队列调试(Never Queue = nq):如有 RS 的连接数等于0,直接将请求分配过去,无需排队等待运算
注:RS(Real Server)
LVS 最常使用的负载均衡算法为 wlc 或 wrr
常见问题
1、nginx: [error] open() “/var/run/nginx/nginx.pid” failed (2: No such file or directory)
2、nginx: [error] invalid PID number “” in “/var/run/nginx/nginx.pid”
3、默认 Docker 容器中没有 vi 等编辑器,可进行安装,也可在宿主机执行如下命令,然后根据返回的路径编辑容器中的文件
4、*** WARNING – this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.