负载均衡集群
比较三种负载均衡
LVS包括三层结构:负载调度器,真实服务池,共享存储(保证请求的数据同步、一致) LVS由两部分程序组成:工作在内核空间的ipvs(真正生效实现调度的代码),工作在用户看见的ipvsadm(为ipvs内核框架编写规则)
LVS、haproxy、nginx的区别
Nginx:
+ 工作在应用层,'1.9版本开始支持四层代理' 。
+ 正则表达式强大。
+ 支持上万的高并发。
+ 应用层代理仅支持http、https、mail协议,应用面小。
+ 监控检查仅通过端口,无法使用url检查。
LVS(Linux Virtual Server):
+ 负载能力强,'工作在传输层' ,对内存、CPU消耗低,适用于大型系统。
+ 应用面广,几乎可以为所有应用提供负载均衡。
+ 支持多种负载均衡调度算法。
+ 不支持正则表达式,不能实现动静分离。
+ 如果网站架构庞大,LVS-DR的配置比较繁琐。
HAProxy:
+ 支持session、cookie功能。
+ 'HAProxy支持传输层(tcp),也支持应用层(http)' 。
+ 支持多种负载均衡调度算法。
+ 相对于Nginx和LVS,HAProxy在处理大量连接时消耗的内存稍高一些。
+ HAProxy不直接支持HTTP加密,需要与其他工具配合使用。
比较
+ 工作层:
+ 四层:LVS、Nginx、HAProxy(mode tcp)
+ 七层:Nginx、HAProxy(mode http) 注意:七层负载均衡可以有效防止DDOS攻击
+ '负载均衡性能:LVS > HAProxy > Nginx'
+ 大规模集群:LVS
+ 中小型系统:HAProxy、Nginx
+ HAProxy和LVS的区别:
+ LVS'转发' 客户端的请求,真实服务器服务日志(` /var/log/nginx/access.log` )看到的是'客户端的IP地址' 。转发没有高并发瓶颈。
+ Nginx和HAProxy'代理' 客户端请求服务,真实服务器服务日志看到的是'HAProxy服务器的IP地址' 。代理由于要给客户端请求分配一个临时端口,因此有64k瓶颈(端口数量2的16次方65536个,64k)
+ HAProxy不需要VIP,真实服务器也就不需要修改内核参数。
nginx和LVS的对比
nginx与LVS的对比:
'nginx工作在网络的第7层,所以它可以针对http应用本身来做分流策略,比如针对域名、目录结构 等' ,相比之下lvs并不具备这样的功能,所以nginx单凭这点可以利用的场合就远多于lvs了;但nginx有用的这些功能使其可调整度要高于lvs,所以经常要去触碰,触碰多了,人为出现问题的几率也就会大。
nginx对网络的依赖较小,理论上只要ping得通,网页访问正常,nginx就能连得通,nginx同时还能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;lvs就比较依赖于网络环境,目前来看服务器在同一网段内并且lvs使用direct方式分流,效果较能得到保证。另外注 意,lvs需要向托管商至少申请多于一个ip来做visual ip。
nginx安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。lvs的安装和配置、测试就要花比较长的时间,因为同上所述,'lvs对网络依赖性比较大' ,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦的多。
nginx也同样能承受很高负载且稳定,但负载度和稳定度差lvs还有几个等级:nginx处理所有流量 所以受限于机器IO和配置;本身的bug也还是难以避免的;nginx没有现成的双机热备方案,所以 跑在单机上还是风险比较大,单机上的事情全都很难说。
nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会 把返回错误的请求重新提交到另一个节点。目前lvs中ldirectd也能支持针对服务器内部的情况来监控,但lvs的原理使其不能重发请求。比如用户正在上传一个文件,而处理该上传的节点刚好在上传 过程中出现故障,nginx会把上传切到另一台服务器重新处理,而lvs就直接断掉了。
两者配合使用:nginx用来做http的反向代理,能够upsteam实现http请求的多种方式的均衡转发。由于采用的是异步转发可以做到如果一个服务器请求失败,立即切换到其他服务器,直到请求成功或者最后一台服务器失败为止。这可以最大程度的提高系统的请求成功率。
lvs采用的是同步请求转发的策略。这里说一下同步转发和异步转发的区别。同步转发是在lvs服务器接收到请求之后,立即redirect到一个后端服务器,由客户端直接和后端服务器建立连接。异步转发是nginx 在保持客户端连接的同时,发起一个相同内容的新请求到后端,等后端返回结果后,由nginx返回给客户端。进一步来说:'当做为负载均衡服务器的nginx和lvs处理相同的请求时,所有的请求和响应流量都会经过nginx;但是使用lvs时,仅请求流量经过lvs的网络,响应流量由后端服务器的网络返回' 。也就是,'当作为后端的服务器规模庞大时,nginx的网络带宽就成了一个巨大的瓶颈' 。 但是仅仅使用lvs作为负载均衡的话,一旦后端接受到请求的服务器出了问题,那么这次请求就失败了。 但是如果'在lvs的后端在添加一层nginx(多个),每个nginx后端再有几台应用服务器' ,那么结合两者的 优势,既能避免单nginx的流量集中瓶颈,又能避免单lvs时一锤子买卖的问题。
nginx与LVS的对比: nginx工作在网络的第7层,所以它可以针对http应用本身来做分流策略,比如针对域名、目录结构 等,相比之下lvs并不具备这样的功能,所以nginx单凭这点可以利用的场合就远多于lvs了;但 nginx有用的这些功能使其可调整度要高于lvs,所以经常要去触碰,由lvs的第2条优点来看,触碰 多了,人为出现问题的几率也就会大。 nginx对网络的依赖较小,理论上只要ping得通,网页访问正常,nginx就能连得通,nginx同时还 能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;lvs就比较依赖于网 络环境,目前来看服务器在同一网段内并且lvs使用direct方式分流,效果较能得到保证。另外注 意,lvs需要向托管商至少申请多于一个ip来做visual ip。 nginx安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。lvs的安装 和配置、测试就要花比较长的时间,因为同上所述,lvs对网络依赖性比较大,很多时候不能配置成 功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦的多。 nginx也同样能承受很高负载且稳定,但负载度和稳定度差lvs还有几个等级:nginx处理所有流量 所以受限于机器IO和配置;本身的bug也还是难以避免的;nginx没有现成的双机热备方案,所以 跑在单机上还是风险比较大,单机上的事情全都很难说。 nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会 把返回错误的请求重新提交到另一个节点。目前lvs中ldirectd也能支持针对服务器内部的情况来监 控,但lvs的原理使其不能重发请求。比如用户正在上传一个文件,而处理该上传的节点刚好在上传 过程中出现故障,nginx会把上传切到另一台服务器重新处理,而lvs就直接断掉了。 两者配合使用: nginx用来做http的反向代理,能够upsteam实现http请求的多种方式的均衡转发。由于采用的是异步转发可以做到如果一个服务器请求失败,立即切换到其他服务器,直到请求成功或者最后一台服务器失败 为止。这可以最大程度的提高系统的请求成功率。 lvs采用的是同步请求转发的策略。这里说一下同步转发和异步转发的区别。同步转发是在lvs服务器接收 到请求之后,立即redirect到一个后端服务器,由客户端直接和后端服务器建立连接。异步转发是nginx 在保持客户端连接的同时,发起一个相同内容的新请求到后端,等后端返回结果后,由nginx返回给客户 端。 进一步来说:当做为负载均衡服务器的nginx和lvs处理相同的请求时,所有的请求和响应流量都会经过 nginx;但是使用lvs时,仅请求流量经过lvs的网络,响应流量由后端服务器的网络返回。 也就是,当作为后端的服务器规模庞大时,nginx的网络带宽就成了一个巨大的瓶颈。 但是仅仅使用lvs作为负载均衡的话,一旦后端接受到请求的服务器出了问题,那么这次请求就失败了。 但是如果在lvs的后端在添加一层nginx(多个),每个nginx后端再有几台应用服务器,那么结合两者的 优势,既能避免单nginx的流量集中瓶颈,又能避免单lvs时一锤子买卖的问题。
LVS NAT模式和DR模式的优缺点
DS:Director Server。指的是前端负载均衡器节点。
RS:Real Server。后端真实的工作服务器。
VIP:Virtual IP 向外部直接面向用户请求,作为用户请求的目标的IP地址。
DIP:Director Server IP,主要用于和内部主机通讯的IP地址。
RIP:Real Server IP,后端服务器的IP地址。
CIP:Client IP,访问客户端的IP地址。
LVS-NAT模式的原理
( a) . 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。此时报文的源IP为CIP,目标IP为VIP
( b) . PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链
( c) . IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标IP地址为后端服务器RIP, 然后将数据包发至POSTROUTING链。此时报文的源IP为CIP,目标IP为RIP
( d) . POSTROUTING链通过选路,将数据包发送给Real Server
( e) . Real Server比对发现目标为自己的IP,开始构建响应报文发回给Director Server。此时报文的源IP为RIP,目标IP为CIP
( f) . Director Server在响应客户端前,此时会将源IP地址修改为自己的VIP地址,然后响应给客户端。 此时报文的源IP为VIP,目标IP为CIP
LVS-NAT模型的特性
RS应该使用私有地址,RS的网关必须指向DIP
DIP和RIP必须在同一个网段内
请求和响应报文都需要经过Director Server,高负载场景中,Director Server易成为性能瓶颈
支持端口映射
RS可以使用任意操作系统
缺陷:对Director Server压力会比较大,请求和响应都需经过Director server
LVS-DR模式原理
( a) 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP
( b) PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链
( c) IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文中的源MAC地址修改为DIP的MAC地址,将目标MAC地址修改RIP的MAC地址,然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址
( d) 由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server。
( e) RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文。处理完成之后,将响应报文通过lo接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP
( f) 响应报文最终送达至客户端
LVS-DR模型的特性
保证前端路由将目标地址为VIP报文统统发给Director Server,而不是RS
RS可以使用私有地址;也可以是公网地址,如果使用公网地址,此时可以通过互联网对RIP进行直接访问
RS跟Director Server必须在同一个物理网络中
所有的请求报文经由Director Server,但响应报文必须不能经过Director Server
不支持地址转换,也不支持端口映射
RS可以是大多数常见的操作系统
RS的网关绝不允许指向DIP( 因为我们不允许他经过director)
RS上的lo接口配置VIP的IP地址
缺陷:RS和DS必须在同一机房中
NAT模式(基于网络层,IP)
DR模式(基于数据链路层,MAC)
NAT模式的优点:
NAT模式可以隐藏后端服务器的真实IP地址,增加安全性。
NAT模式可以进行负载均衡,分摊流量压力到多台后端服务器上。
NAT模式可以通过配置不同的外部端口映射到不同的内部服务器,提高灵活性。
NAT模式的缺点:
NAT模式需要额外的设备进行地址转换,增加了网络的复杂性和成本。
NAT模式可能会成为性能瓶颈,降低网络传输的效率。
NAT模式可能会导致单点故障,一旦NAT设备发生故障,整个网络服务将中断。
DR模式的优点:
DR模式在数据转发时直接将数据包转发给后端服务器,减少了中间设备的负担,提高了系统性能,效率最高。
DR模式可以实现无感知的服务器故障切换,提高了系统的稳定性和可用性。
DR模式减少了单一设备的压力,提高了整个系统的吞吐量和处理能力。
DR模式的缺点:
DR模式对后端服务器的网络环境要求较高,后端服务器需要配置正确的网络环境和路由表。
DR模式无法隐藏后端服务器的真实IP地址,增加了网络安全风险。
DR模式需要更多的管理和维护,配置和调试相对复杂。
LVS负载均衡
LVS(ipvsadm)的负载均衡调度算法-s的取值:
+ ` rr` (轮询,Round-robin)
+ ` wrr` (加权轮询,Weighted Round-robin)
+ ` lc` (最少连接,Least Connection):将请求发送到当前具有最少活动连接数的服务器。
+ ` wlc` (加权最少连接,Weighted Least Connection)
+ ` dh` (目标地址散列,Destination Hashing):根据请求的目标IP地址的哈希值来确定将请求转发到哪个服务器。相同的目标IP地址将始终发送到同一个服务器。
+ ` sh ` (源地址散列,Source Hashing):根据请求的源IP地址的哈希值来确定将请求转发到哪个服务器。相同的源IP地址将始终发送到同一个服务器。
+ ` wsh` (加权源地址散列,Weighted Source Hashing)
+ ` sed ` (最短预期延迟,Shortest Expected Delay):根据每个服务器的平均响应时间来选择最短预期延迟的服务器,以实现负载均衡。
+ ` ssed` (源地址最短预期延迟,Source Shortest Expected Delay):类似于最短预期延迟,但根据请求的源IP地址来选择最短预期延迟的服务器。
+ ` dst` (最小连接数,Least Connection on Destination IP)
+ ` ipvsadm -A -t或u 虚拟服务器IP:端口号 -s 调度算法` :添加虚拟服务器并指定调度算法。
` ipvsadm -E -t或u 虚拟服务器IP:端口号 -s 调度算法` :修改虚拟服务器调度算法。
` ipvsadm -D -t或u 虚拟服务器IP:端口号` :删除虚拟服务器并指定调度算法。
+ ` ipvsadm -a -t或u 虚拟服务器IP:端口号 -r 真实服务器IP:端口号 -w 权重 -m或-g` :添加真实服务器。RIP
` ipvsadm -e -t或u 虚拟服务器IP:端口号 -r 真实服务器IP:端口号 -w 权重 -m或-g` :修改真实服务器。
` ipvsadm -d -t或u 虚拟服务器IP:端口号 -r 真实服务器IP:端口号` :删除真实服务器。
+ ` ipvsadm -Ln ` :查看IPVS配置。
ipvsadm命令选项:
+ ` -A ` :添加虚拟服务器(Virtual Server,也叫负载均衡器)。
` -E ` :编辑虚拟服务器。
` -D ` :删除虚拟服务器。
` -t ` :指定虚拟服务器端口为tcp协议。
` -u ` :指定虚拟服务器端口为udp协议。
` -s ` (scheduler):指定调度算法。` rr` 表示轮询,` wrr` 表示加权轮询,` lc` 表示最少连接,` wlc` 表示加权最少连接。
+ ` -a ` :添加虚拟服务器后,向该虚拟服务器中加入真实服务器(Real Server,也叫真实服务器)。
` -e ` :修改真实服务器。
` -d ` :删除真实服务器。
+ ` -r ` :指定真实服务器。
` -w ` :设置真实服务器的权重。
` -m ` :指定工作模式为NAT。
` -g ` :指定工作模式为DR。
+ ` -L ` (list):查看列表。
` -n ` (numeric):以数字显示IP地址和端口号。
NAT模式举例:VIP和RIP在不同网段
ipvsadm -A -t VIP:80 -s 调度算法
ipvsadm -a -t VIP:80 -r RIP -w 权重 -m
DR模式举例:VIP和RIP在同一个网段
ipvsadm -A -t VIP:80 -s 调度算法
ipvsadm -a -t VIP:80 -r RIP -w 权重 -g
nginx四层代理和七层代理
nginx负载均衡可用的调度算法
轮询(默认)
weight权重
ip_hash
fair( 第三方插件)
url_hash(第三方插件)
例如
http {
……省略一万字
upstream webs {
server 192.168 .88.101 weight = 1 max_fails = 3 fail_timeout = 5 ;
server 192.168 .88.102 weight = 2 max_fails = 3 fail_timeout = 5 ;
}
server {
listen 100 ;
location / {
proxy_pass http://webs;
root html;
index index.html;
}
}
……省略一万字
}
yum install -y nginx-mod-stream
stream {
upstream webs {
server 192.168 .88.101:80 weight = 1 max_fails = 3 fail_timeout = 5 ;
server 192.168 .88.102:80 weight = 2 max_fails = 3 fail_timeout = 5 ;
}
server {
listen 100 ;
proxy_pass webs;
}
upstream ssh {
server 192.168 .88.101:22 weight = 1 max_fails = 3 fail_timeout = 5 ;
server 192.168 .88.102:22 weight = 2 max_fails = 3 fail_timeout = 5 ;
}
server {
listen 123 ;
proxy_pass ssh ;
}
}
http {
……省略一万字
}
高可用负载均衡的搭建
主机清单
ansible控制端(control 192.168 .88.240,192.168.99.240):
[ root@control ~]
[ root@control lb]
[ defaults]
inventory = hostlist
host_key_checking = no
EOF
[ root@control lb]
[ web1]
192.168 .88.81
[ web2]
192.168 .88.82
[ web3]
192.168 .88.83
[ web:children]
web1
web2
web3
[ lvs1]
192.168 .88.11 hostname = lvs1 state = MASTER priority = 110
[ lvs2]
192.168 .88.12 hostname = lvs2 state = BACKUP priority = 100
[ lvs:children]
lvs1
lvs2
[ haproxy1]
192.168 .88.21 hostname = haproxy1 state = MASTER priority = 110
[ haproxy2]
192.168 .88.22 hostname = haproxy2 state = BACKUP priority = 100
[ haproxy:children]
haproxy1
haproxy2
[ nginx1]
192.168 .88.31 hostname = nginx1 state = MASTER priority = 110
[ nginx2]
192.168 .88.32 hostname = nginx2 state = BACKUP priority = 100
[ nginx:children]
nginx1
nginx2
[ all:vars]
ansible_ssh_user = root
ansible_ssh_pass = a
EOF
[ root@control lb]
Web集群启用Web服务
[ root@control lb]
[ root@control lb]
---
- name: configure nginx
hosts: web
vars:
- nginx_index: 'nginx_index.html'
tasks:
- name: remove nginx
yum:
name: nginx
state: absent
- name: install nginx
yum:
name: nginx
state: latest
update_cache: yes
- name: start nginx and enable
service:
name: nginx.service
state: started
enabled: yes
- name: template index.html
template:
src: '{{ nginx_index }}'
dest: /usr/share/nginx/html/index.html
EOF
[ root@control lb]
[ root@control lb]
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
keepalived+LVS(DR模式)
调度器(高可用)+ Web集群(负载均衡)
目标:客户端访问调度器的VIP,可以访问到Web集群的Web服务。当主调度器故障时,会切换备用调度器。 环境:调度器(两台),Web集群(三台),客户端:
Web集群、调度器(一张网卡)处于同一个网段 Web集群、调度器(一张网卡)、客户端可以相互ping通,简化情况下,处于同一网段。 DR模式配置步骤:Web集群部署Web服务——》Web集群的lo网卡配置VIP,并修改内核参数不响应对VIP的ARP请求——》调度器配置keepalived和IPVS(keepalived配置文件中可以配置IPVS) 。 keepalived可以实现本VRRP实例的高可用[,通过跟踪脚本实现服务的高可用]。 keepalived可以提供VIP,配置IPVS规则,对后端服务器做健康检查以更新IPVS规则。
Web集群配置VIP和内核参数
[ root@control lb]
---
- name: DR mode configure vip and sysctl
hosts: web
gather_facts: no
vars:
- VIP: '192.168.88.10'
- sysctl_parameters:
- { name: "net.ipv4.conf.all.arp_ignore" , value: "1" }
- { name: "net.ipv4.conf.lo.arp_ignore" , value: "1" }
- { name: "net.ipv4.conf.all.arp_announce" , value: "2" }
- { name: "net.ipv4.conf.lo.arp_announce" , value: "2" }
tasks:
- name: install network-scripts,net-tools
yum:
name: network-scripts,net-tools
state: present
update_cache: yes
- name: rm ifcfg-lo:0
file:
path: /etc/sysconfig/network-scripts/ifcfg-lo:0
state: absent
- name: add lo:0 set vip
copy:
dest: /etc/sysconfig/network-scripts/ifcfg-lo:0
content: |
DEVICE = lo:0
NAME = lo:0
IPADDR = { { VIP } }
PREFIX = 32
NETWORK = { { VIP } }
BROADCAST = { { VIP } }
ONBOOT = yes
force: yes
backup: no
notify:
- activate lo:0
- autoconnect lo:0
- chmod +x
- set sysctl
handlers:
- name: activate lo:0
shell: ifup lo:0
async: 60
poll: 0
- name: autoconnect lo:0
lineinfile:
path: /etc/rc.d/rc.local
line: 'ifup lo:0'
- name: chmod +x
shell: chmod +x /etc/rc.d/rc.local
register: result
- name: set sysctl
sysctl:
name: '{{ item.name }}'
value: '{{ item.value }}'
state: present
reload: yes
loop: '{{ sysctl_parameters }}'
when: result.rc == 0
EOF
[ root@control lb]
[ root@web1~3 ~]
lo:0: flags = 7 3 < UP,LOOPBACK,RUNNING> mtu 65536
inet 192.168 .88.10 netmask 255.255 .255.255
loop txqueuelen 1000 ( Local Loopback)
调度器配置keepalived和IPVS
keepalived配置文件
[ root@control lb]
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0 .0.1
smtp_connect_timeout 30
router_id { { hostname} }
}
vrrp_instance VI_1 {
state { { state} }
interface { { interface} }
virtual_router_id { { VRRP_id} }
priority { { priority} }
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{ { VIP} }
}
}
virtual_server { { VIP} } { { lvs_port} } {
delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 0
protocol TCP
real_server { { RIP01} } { { lvs_port} } {
weight { { weight01} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
real_server { { RIP02} } { { lvs_port} } {
weight { { weight02} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
real_server { { RIP03} } { { lvs_port} } {
weight { { weight03} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
}
EOF
调度器配置keepalived和IPVS
[ root@control lb]
---
- name: configure keepalived and ipvsadm
hosts: lvs
gather_facts: no
vars:
- keepalived_config: './keepalived_ipvsadm_DR.conf'
- VRRP_id: '10'
- interface: 'eth0'
- VIP: '192.168.88.10'
- lvs_port: '80'
- RIP01: '192.168.88.81'
- weight01: '1'
- RIP02: '192.168.88.82'
- weight02: '2'
- RIP03: '192.168.88.83'
- weight03: '1'
tasks:
- name: remove keepalived,ipvsadm
yum:
name: keepalived,ipvsadm
state: absent
- name: install keepadlived,ipvsadm
yum:
name: keepalived,ipvsadm
state: present
- name: template keepalived.conf
template:
src: '{{keepalived_config}}'
dest: /etc/keepalived/keepalived.conf
force: yes
backup: no
mode: 0644
- name: start keepalived and enabled
service:
name: keepalived.service
state: started
enabled: yes
EOF
[ root@control lb]
[ root@lvs1 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:c4:96:4b brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.11/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168 .88.10/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::79c3:82e6:9396:e1c1/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@lvs1 ~]
IP Virtual Server version 1.2 .1 ( size= 4096 )
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168 .88.10:80 wrr
-> 192.168 .88.81:80 Route 1 0 0
-> 192.168 .88.82:80 Route 2 0 0
-> 192.168 .88.83:80 Route 1 0 0
[ root@lvs2 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:78:7f:d6 brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.12/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::198b:22f4:8592:4a9a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@lvs2 ~]
IP Virtual Server version 1.2 .1 ( size= 4096 )
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168 .88.10:80 wrr
-> 192.168 .88.81:80 Route 1 0 0
-> 192.168 .88.82:80 Route 2 0 0
-> 192.168 .88.83:80 Route 1 0 0
[ root@control lb]
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
局限性
lvs(ipvsadm)的转发是同步的,如果客户端通过VIP访问lvs从而获取服务的这个过程中,后端的Web服务器故障,则VIP无法提供服务。
例如,ipvsadm将此次访问请求转发给web1,但web1故障,则此次访问请求无法获取服务。如果web1故障,ipvsadm通过健康检查将web1剔除出集群之后,客户端访问VIP,则ipvsadm不会将该访问请求转发给web1。因此,可以缩短健康检查的间隔,或者客户端刷新访问,或者在前面增加nginx反向代理ipvsadm。
还原Web集群
[ root@control lb]
---
- name: reset web for ipvsadm DR
hosts: web
gather_facts: no
vars:
- sysctl_parameters:
- { name: "net.ipv4.conf.all.arp_ignore" , value: "0" }
- { name: "net.ipv4.conf.lo.arp_ignore" , value: "0" }
- { name: "net.ipv4.conf.all.arp_announce" , value: "0" }
- { name: "net.ipv4.conf.lo.arp_announce" , value: "0" }
tasks:
- name: deactivate lo:0
shell: 'ifdown lo:0'
register: result
ignore_errors: yes
- name: disable lo:0
lineinfile:
path: /etc/rc.d/rc.local
regexp: 'lo:0'
state: absent
- name: rm lo:0
file:
path: /etc/sysconfig/network-scripts/ifcfg-lo:0
state: absent
- name: remove network-scripts
yum:
name: network-scripts
state: absent
when: result.rc == 0
- name:
sysctl:
name: '{{ item.name }}'
value: '{{ item.value }}'
state: present
reload: yes
loop: '{{ sysctl_parameters }}'
EOF
[ root@control lb]
keepalived+LVS(NAT模式)
调度器(高可用)+ Web集群(负载均衡)
目标:客户端访问调度器的VIP,可以访问到Web集群的Web服务。当主调度器故障时,会切换备用调度器。 环境:调度器(两台),Web集群(三台),客户端:
Web集群、客户端处于不同网段,调度器和Web集群处于同一网段,且Web集群的网关是调度器。 调度器(两张网卡)可以ping通客户端。简化情况下,调度器和客户端处于同一网段。 NAT模式配置步骤:Web集群(网关为VIP)部署Web服务——》调度器开启路由转发功能——》调度器配置keepalived和IPVS(keepalived配置文件中可以配置IPVS,此时客户端可以访问VIP来访问Web集群) 。 keepalived可以实现本VRRP实例的高可用[,通过跟踪脚本实现服务的高可用]。 keepalived可以提供VIP,配置IPVS规则,对后端服务器做健康检查以更新IPVS规则。
主机清单
调度器(lvs3、lvs4):
eth0 192.168 .88.13~14/24(VIP 192.168 .88.10)
eth1 192.168 .99.13~14/24(VIP 192.168 .99.10)
Web集群(web1、web2、web3):
eth0 192.168 .88.81~83/24 网关192.168.88.10
客户端(client):
eth1 192.168 .99.250/24
ansible控制端(control 192.168 .88.240,192.168.99.240):
[ root@control ~]
[ root@control lb]
[ defaults]
inventory = hostlist_nat
host_key_checking = no
EOF
[ root@control lb]
[ web1]
192.168 .88.81
[ web2]
192.168 .88.82
[ web3]
192.168 .88.83
[ web:children]
web1
web2
web3
[ lvs3]
192.168 .88.13 hostname = lvs3 state = MASTER priority = 110
[ lvs4]
192.168 .88.14 hostname = lvs4 state = BACKUP priority = 100
[ lvs:children]
lvs3
lvs4
[ all:vars]
ansible_ssh_user = root
ansible_ssh_pass = a
EOF
[ root@control lb]
[ root@control lb]
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
调度器开启路由转发功能
[ root@control lb]
---
- name: NAT mode configure ip_forward
hosts: lvs
gather_facts: no
tasks:
- name: set net.ipv4.ip_forward = 1
sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
reload: yes
EOF
[ root@control lb]
调度器配置keepalived和IPVS
keepalived配置文件
[ root@control lb]
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0 .0.1
smtp_connect_timeout 30
router_id { { hostname} }
}
vrrp_instance VI_1 {
state { { state} }
interface { { interface01} }
virtual_router_id { { VRRP_id01} }
priority { { priority} }
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{ { VIP01} }
}
}
vrrp_instance VI_2 {
state { { state} }
interface { { interface02} }
virtual_router_id { { VRRP_id02} }
priority { { priority} }
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{ { VIP02} }
}
}
virtual_server { { VIP02} } { { lvs_port} } {
delay_loop 6
lb_algo wrr
lb_kind nat
persistence_timeout 0
protocol TCP
real_server { { RIP01} } { { lvs_port} } {
weight { { weight01} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
real_server { { RIP02} } { { lvs_port} } {
weight { { weight02} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
real_server { { RIP03} } { { lvs_port} } {
weight { { weight03} }
TCP_CHECK {
connect_timeout 2
nb_get_retry 3
delay_before_retry 3
}
}
}
EOF
调度器配置keepalived和IPVS
[ root@control lb]
---
- name: configure keepalived and ipvsadm
hosts: lvs
gather_facts: no
vars:
- keepalived_config: './keepalived_ipvsadm_NAT.conf'
- VRRP_id01: '88'
- interface01: 'eth0'
- VIP01: '192.168.88.10'
- VRRP_id02: '99'
- interface02: 'eth1'
- VIP02: '192.168.99.10'
- lvs_port: '80'
- RIP01: '192.168.88.81'
- weight01: '1'
- RIP02: '192.168.88.82'
- weight02: '2'
- RIP03: '192.168.88.83'
- weight03: '1'
tasks:
- name: remove keepalived,ipvsadm
yum:
name: keepalived,ipvsadm
state: absent
- name: install keepadlived,ipvsadm
yum:
name: keepalived,ipvsadm
state: present
- name: template keepalived.conf
template:
src: '{{keepalived_config}}'
dest: /etc/keepalived/keepalived.conf
force: yes
backup: no
mode: 0644
- name: start keepalived and enabled
service:
name: keepalived.service
state: started
enabled: yes
EOF
[ root@control lb]
[ root@lvs3 ~]
1 : lo: < LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0 .0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:5c:7a:0b brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.13/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168 .88.10/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::6f22:6fb:a3de:bd2b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3 : eth1: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:5c:7a:15 brd ff:ff:ff:ff:ff:ff
inet 192.168 .99.13/24 brd 192.168 .99.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet 192.168 .99.10/32 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::4aca:dfb4:bb47:e7d/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@lvs3 ~]
IP Virtual Server version 1.2 .1 ( size= 4096 )
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168 .99.10:80 wrr
-> 192.168 .88.81:80 Masq 1 0 0
-> 192.168 .88.82:80 Masq 2 0 0
-> 192.168 .88.83:80 Masq 1 0 0
[ root@lvs4 ~]
1 : lo: < LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0 .0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:2c:99:11 brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.14/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::267:f548:bb9a:7b7a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3 : eth1: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:2c:99:1b brd ff:ff:ff:ff:ff:ff
inet 192.168 .99.14/24 brd 192.168 .99.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::bee7:4d11:d800:4083/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@lvs4 ~]
IP Virtual Server version 1.2 .1 ( size= 4096 )
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168 .99.10:80 wrr
-> 192.168 .88.81:80 Masq 1 0 0
-> 192.168 .88.82:80 Masq 2 0 0
-> 192.168 .88.83:80 Masq 1 0 0
[ root@client ~]
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
keepalived+haproxy
调度器(高可用)+ Web集群(负载均衡)
目标:客户端访问调度器,可以访问到Web集群的Web服务。当主调度器故障时,会切换备用调度器。 环境:调度器(两台),Web集群(三台),客户端:
Web集群、调度器、客户端可以相互ping通,简化情况下,处于同一网段。 配置步骤:Web集群部署Web服务——》调度器配置haproxy开启负载均衡功能(此时客户端可以访问调度器来访问Web集群)——》调度器配置keepalived实现高可用,编写脚本让keepalived跟踪haproxy服务,实现haproxy的高可用(此时haproxy服务故障会切换主服务器) 。 keepalived可以实现本VRRP实例的高可用,通过跟踪脚本实现服务的高可用。
haproxy配置文件
HAProxy配置文件
工作模式mode的取值:
+ ` http` :只适用于http,即Web服务。HAProxy对于http相关服务做了特别优化。
+ ` tcp` :适用于各种tcp端口的服务,也适用于Web服务(` http` 性能更佳)。
+ ` health` :仅做健康检查,很少使用
负载均衡调度算法balance的取值:
+ ` roundrobin` (轮询):将请求依次发送到每个服务器,以实现请求的均衡分布。
+ ` leastconn` (最小连接数):将请求发送到当前具有最少活动连接数的服务器,以实现连接的均衡负载。
+ ` static-rr` (静态轮询):类似轮询,但具有固定的服务器顺序。每个新连接将按顺序分配给下一个服务器。
+ ` source ` (源地址哈希):根据源IP地址的哈希值来确定将请求转发到哪个服务器。相同的源IP地址将始终发送到同一个服务器。
+ ` uri` (URI哈希):根据请求的URI的哈希值来确定将请求转发到哪个服务器。相同的URI将始终发送到同一个服务器。
+ ` url_param` (URL参数哈希):根据请求URL中的参数值的哈希值来确定将请求转发到哪个服务器。相同的URL参数将始终发送到同一个服务器。
+ ` hdr( name) ` (HTTP头部哈希):根据指定的HTTP请求头部的哈希值来确定将请求转发到哪个服务器。相同的HTTP头部值将始终发送到同一个服务器。
+ ` rdp-cookie( name) ` (RDP Cookie哈希):根据指定的RDP Cookie的哈希值来确定将请求转发到哪个服务器。相同的RDP Cookie将始终发送到同一个服务器。
[ root@control lb]
global
log 127.0 .0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
ssl-default-bind-ciphers PROFILE = SYSTEM
ssl-default-server-ciphers PROFILE = SYSTEM
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0 .0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen myweb
bind 0.0 .0.0:{ { web_port} }
balance roundrobin
server web1 { { RIP01} } :{ { RIP_port} } weight { { weight01} } check inter 1000 rise 2 fall 3
server web2 { { RIP02} } :{ { RIP_port} } weight { { weight02} } check inter 1000 rise 2 fall 3
server web3 { { RIP03} } :{ { RIP_port} } weight { { weight03} } check inter 1000 rise 2 fall 3
listen show
bind 0.0 .0.0:{ { stats_port} }
stats refresh 15s
stats uri /show
stats auth admin:admin
EOF
调度器配置haproxy
[ root@control lb]
---
- name: configue haproxy
hosts: haproxy
gather_facts: no
vars:
- haproxy_config: './haproxy.cfg'
- web_port: '80'
- RIP_port: '80'
- RIP01: '192.168.88.81'
- weight01: '1'
- RIP02: '192.168.88.82'
- weight02: '2'
- RIP03: '192.168.88.83'
- weight03: '1'
- stats_port: '1080'
tasks:
- name: remove haproxy
yum:
name: haproxy
state: absent
- name: install haproxy
yum:
name: haproxy
state: latest
update_cache: yes
- name: template haproxy.cfg
template:
src: '{{haproxy_config}}'
dest: /etc/haproxy/haproxy.cfg
force: yes
backup: no
mode: '0644'
- name: start haproxy and enabled
service:
name: haproxy.service
state: started
enabled: yes
EOF
[ root@control lb]
[ root@control lb]
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
[ root@control lb]
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
keepalived配置文件
1 . keepalived配置文件
[ root@control lb]
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0 .0.1
smtp_connect_timeout 30
router_id { { hostname} }
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 1
}
vrrp_instance VI_1 {
state { { state} }
interface { { interface} }
virtual_router_id { { VRRP_id} }
priority { { priority} }
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{ { VIP} }
}
track_script {
check_haproxy
}
}
EOF
2 . keepalived检查haproxy的脚本
[ root@control lb]
ss -ntulp | grep :1080 > /dev/null
if [ [ \ $? == 0 ] ]
then
exit
else
for i in \ $( seq 1 2 )
do
systemctl restart haproxy.service > /dev/null
ss -ntulp | grep :1080 > /dev/null
if [ [ \ $? == 0 ] ]
then
break
fi
done
ss -ntulp | grep :1080 > /dev/null && exit || exit 1
fi
EOF
调度器配置keepalived
[ root@control lb]
---
- name: configure keepalived
hosts: haproxy
gather_facts: no
vars:
- keepalived_config: './keepalived_haproxy.conf'
- check_haproxy: './check_haproxy.sh'
- VRRP_id: '20'
- interface: 'eth0'
- VIP: '192.168.88.20'
tasks:
- name: remove keepalived
yum:
name: keepalived
state: absent
- name: install keepalived
yum:
name: keepalived
state: latest
update_cache: yes
- name: copy check_haproxy.sh
copy:
src: '{{check_haproxy}}'
dest: /etc/keepalived/check_haproxy.sh
force: yes
backup: no
mode: '0755'
- name: template keepalived.conf
template:
src: '{{keepalived_config}}'
dest: /etc/keepalived/keepalived.conf
force: yes
backup: no
mode: '0644'
- name: start keepalived and enabled
service:
name: keepalived.service
state: started
enabled: yes
EOF
[ root@control lb]
[ root@haproxy1 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:28:2a:f7 brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.21/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168 .88.20/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::267:f548:bb9a:7b7a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@haproxy2 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:7c:b5:83 brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.22/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::79c3:82e6:9396:e1c1/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@control lb]
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web3 on 192.168 .88.83! !
若主调度器haproxy1的haproxy故障,则VIP会切换到备用调度器haproxy2成为主调度器,haproxy1的haproxy恢复后,VIP重新切换到haproxy1,实现调度器的高可用,不影响Web集群的负载均衡。
keepalived+nginx
调度器(高可用)+ Web集群(负载均衡)
目标:客户端访问调度器,可以访问到Web集群的Web服务。当主调度器故障时,会切换备用调度器。 环境:调度器(两台),Web集群(三台),客户端:
Web集群、调度器、客户端可以相互ping通,简化情况下,处于同一网段。 配置步骤:Web集群部署Web服务——》调度器配置nginx开启负载均衡功能(此时客户端可以访问调度器来访问Web集群)——》调度器配置keepalived实现高可用,编写脚本让keepalived跟踪nginx服务,实现nginx的高可用(此时nginx服务故障会切换主服务器) 。 keepalived可以实现本VRRP实例的高可用,通过跟踪脚本实现服务的高可用。
nginx和keepalived的配置文件
1 . nginx配置文件
[ root@control lb]
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024 ;
}
stream {
log_format main '\$remote_addr \$upstream_addr - [\$time_local] \$status \$upstream_bytes_sent' ;
access_log /var/log/nginx/web-access.log main;
upstream myweb {
server { { RIP01} } :{ { RIP_port} } weight = { { weight01} } max_fails = 3 fail_timeout = 30s;
server { { RIP02} } :{ { RIP_port} } weight = { { weight02} } max_fails = 3 fail_timeout = 30s;
server { { RIP03} } :{ { RIP_port} } weight = { { weight03} } max_fails = 3 fail_timeout = 30s;
}
server {
listen { { web_port} } ;
proxy_pass myweb;
}
}
http {
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;
tcp_nodelay on;
keepalive_timeout 65 ;
types_hash_max_size 2048 ;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 default_server;
server_name _;
location / {
}
}
}
EOF
2 . keepalived配置文件,使用变量
[ root@control lb]
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0 .0.1
smtp_connect_timeout 30
router_id { { hostname} }
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state { { state} }
interface { { interface} }
virtual_router_id { { VRRP_id} }
priority { { priority} }
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{ { VIP} }
}
track_script {
check_nginx
}
}
EOF
3 . keepalived检查nginx工作状态的脚本
[ root@control lb]
counter = \ $( ps -ef | grep nginx | grep sbin | egrep -cv "grep" )
if [ \ $counter -eq 0 ] ; then
service nginx start
sleep 2
counter = \ $( ps -ef | grep nginx | grep sbin | egrep -cv "grep" )
if [ \ $counter -eq 0 ] ; then
service keepalived stop
fi
fi
EOF
调度器配置nginx和keepalived
[ root@control lb]
---
- name: configure nginx and keepalived
hosts: nginx
gather_facts: no
vars:
- nginx_conf: './nginx.conf'
- keepalived_conf: './keepalived_nginx.conf'
- check_nginx_sh: './check_nginx.sh'
- web_port: '10080'
- RIP_port: '80'
- RIP01: '192.168.88.81'
- weight01: '1'
- RIP02: '192.168.88.82'
- weight02: '2'
- RIP03: '192.168.88.83'
- weight03: '1'
- VRRP_id: '30'
- interface: 'eth0'
- VIP: '192.168.88.30'
tasks:
- name: remove nginx,keepalived
yum:
name: nginx,keepalived
state: absent
- name: install nginx,keepalived
yum:
name: nginx,keepalived
update_cache: yes
- name: config nginx
template:
src: '{{nginx_conf}}'
dest: /etc/nginx/nginx.conf
force: yes
backup: no
owner: nginx
group: nginx
mode: '0755'
- name: config keepalived
template:
src: '{{keepalived_conf}}'
dest: /etc/keepalived/keepalived.conf
force: yes
backup: no
mode: '0644'
- name: copy check_nginx.sh
copy:
src: '{{check_nginx_sh}}'
dest: /etc/keepalived/check_nginx.sh
force: yes
backup: no
mode: '0755'
- name: start nginx and keepalived
service:
name: '{{ item }}'
state: started
enabled: yes
loop:
- nginx.service
- keepalived.service
EOF
[ root@control lb]
[ root@nginx1 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:24:d2:f8 brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.31/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168 .88.30/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::ca3a:810f:bbd:ce74/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@nginx2 ~]
2 : eth0: < BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:96:4a:8e brd ff:ff:ff:ff:ff:ff
inet 192.168 .88.32/24 brd 192.168 .88.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::6f22:6fb:a3de:bd2b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[ root@control lb]
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web2 on 192.168 .88.82! !
Welcome to web1 on 192.168 .88.81! !
Welcome to web3 on 192.168 .88.83! !
Welcome to web2 on 192.168 .88.82! !
问题
脑裂
什么是脑裂?
在高可用系统(keepalived)中,当联系2个节点的“心跳线”(VRRP实例)断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。
由于相互失去了联系,都以为是对方出了故障。两个节点上的HA软件像“裂脑人”一样,争抢“共享资源”、争起“应用服务”,就会发生严重后果。共享资源被瓜分、两边“服务”都起不来了;或者两边“服务”都起来了,但同时读写“共享存储”,导致数据损坏。
脑裂的原因:
1 .网线导致的网络故障
2 .交换机故障导致的网络故障
3 .网卡故障导致的网络故障
4 .网卡驱动故障导致的网络故障
5 .IP配置及冲突等导致的网络故障
6 .防火墙或iptables等拦截了心跳消息的传输
7 .其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件Bug等。
解决脑裂问题:
1 .保持网络通信正常
2 .防火墙或iptables等不拦截心跳消息
3 .其它检测方式保证节点间的心跳检测
web服务
nginx、apache、tomcat
nginx采用的是epoll模型和kqueue网络模型,而apache采用的是select模型
epoll:在Linux系统上使用,由于采用了红黑树的数据结构,具有较高的性能,支持水平触发和边缘触发。
kqueue:在BSD和MacOS系统上使用,也支持水平触发和边缘触发,性能较epoll略低一些。
select:在多个操作系统上都通用,性能相对较差,适用于连接数较少的情况。
> 假设你在大学读书,住的宿舍楼有很多间房间,你的朋友要来找你。
select版宿管大妈就会带着你的朋友挨个房间去找,直到找到你为止。
而epoll版宿管大妈会先记下每位同学的房间号,
你的朋友来时,只需告诉你的朋友你住在哪个房间即可,不用亲自带着你的朋友满大楼找人。
如果来了10000个人,都要找自己住这栋楼的同学时,select版和epoll版宿管大妈,谁的效率更高,不言自明。
同理,在高并发服务器中,轮询I/O是最耗时间的操作之一,select和epoll的性能谁的性能更高,同样十分明了。
select 采用的是轮询的方式来处理请求,轮询的次数越多,耗时也就越多。
Nginx
轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源
抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是'异步非阻塞' 的,负载能力比apache 高很多,而 apache 则是'阻塞型' 的。在高并发下 nginx 能保持低资源低消耗高性能 ,而apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。
nginx 处理静态文件好,静态处理性能比 apache 高三倍以上
nginx 的设计高度模块化,编写模块相对简单
nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃
nginx 作为负载均衡服务器,支持 7 层负载均衡,'七层负载可以有效的防止ddos攻击'
nginx本身就是一个反向代理服务器,也可以作为邮件代理服务器来使用
Apache
apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache
apache 发展到现在,模块超多,基本想到的都可以找到
apache 更为成熟,少 bug ,nginx 的 bug 相对较多
apache 对 PHP 支持比较简单,nginx 需要配合其他后端用
apache 在处理动态请求有优势,nginx 在这方面是鸡肋,'一般动态请求要 apache' 去做,'nginx 适合静态和反向' 。
apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区
两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程。
需要'稳定用apache' ,需要'高性能用nginx'
Tomcat作为web的优缺点?
缺点:tomcat 只能用做java服务器,处理静态请求的能力不如nginx和apache。,高并发能力有限
优点:动态解析容器,处理动态请求,是编译JSP/Servlet的容器,轻量级
cgi和fastcgi
CGI ( Common Gateway Interface) 是一种协议,用于建立Web服务器和外部程序之间的通信,以动态生成Web页面。它的工作方式是web服务器每次接收请求都创建一个新的进程来处理,并在处理完请求后将结果发送给客户端并退出。
FastCGI 是对CGI 的改进和扩展,它web服务启动时就开启了若干个持续的进程,在处理多个请求也不会立即退出,避免了CGI 中频繁创建和退出进程的开销,从而提高了性能。
因此,主要的区别在于CGI 每次请求都创建一个新的进程,而FastCGI 可以在持续的进程中处理多个请求,提高了性能。
正向代理和反向代理
正向代理,其实是"代理服务器" 代理了"客户端" ,去和"目标服务器" 进行交互。
正向代理的用途:
提高访问速度
隐藏客户真实IP
反向代理:
反向代理是 在服务端的,不需要访问用户关心。用户访问服务器A, A服务器是代理服务器,将用户服务再转发到服务器B.这就是反向代理
反向代理的作用:
1 .缓存,将服务器的响应缓存在自己的内存中,减少服务器的压力。
2 .负载均衡,将用户请求分配给多个服务器。
3 .访问控制
如何在Nginx中设置缓存时间和大小:
http {
proxy_cache_path /path/to/cache levels = 1 :2 keys_zone = my_cache:10m max_size = 100m inactive = 1d;
}
server {
location / {
proxy_pass http://backend/;
proxy_cache my_cache;
proxy_cache_valid 200 304 1h;
}
}
在上述示例中,我们定义了名为"my_cache" 的缓存路径,缓存大小为100MB,有效时间为1小时。根据实际需求和服务器性能,可以根据情况调整缓存路径、缓存大小、以及缓存的有效时间参数。
在示例中,proxy_cache_valid 200 304 1h; 中的200和304表示了响应状态码。具体解释如下:
200 :表示成功响应,即服务器成功返回请求的数据。
304 :表示无需返回内容,客户端可以使用缓存的响应。
因此,在这个示例中,我们设置了对于返回状态码为200(成功响应)和304(无需返回内容)的请求,缓存的有效时间为1小时。这样可以有效地控制缓存的过期时间,以提高性能并降低服务器的负载。
Squid、Varinsh、Nginx 有什么区别?
三者都实现缓存服务器的作用
Nginx本来是反向代理/web服务器,用了插件可以做做这个副业( 缓存服务器) 。但本身支持的特性不是很多,只能缓存静态文件
varinsh 和squid是专业的cache服务,而nginx这些需要使用第三方模块
varinsh本身在技术上的优势要高于squid,它采用了可视化页面缓存技术。
要做 cache 服务的话,我们肯定是要选择专业的 cache 服务,优先选择Squid 或者 Varnish