目录
IP透传
一:讲解部分
1.负载均衡
定义:
负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展
为什么用负载均衡:
HAProxy的作用实现负载均衡,将请求分发到多个服务器上,从而提高系统的可用性和性能。它可以根据不同的负载均衡算法(如轮询、加权轮询、IP哈希等)来分配请求,并支持会话保持、健康检查、SSL终止等功能。此外,HAProxy还可以实现反向代理、SSL加速、HTTP压缩等功能,使其成为一款功能强大的代理软件。
- Web服务器的动态水平扩展–>对用户无感知
- 增加业务并发访问及处理能力–>解决单服务器瓶颈问题
- 节约公网IP地址–>降低IT支出成本
- 隐藏内部服务器IP–>提高内部服务器安全性
- 配置简单–>固定格式的配置文件
- 功能丰富–>支持四层和七层,支持动态下线主机
- 性能较强–>并发数万甚至数十万
负载均衡类型:
根据OSI模型可将负载均衡分为二层负载均衡(一般是用虚拟mac地址方式,外部对虚拟MAC地址请求,负载均衡接收后分配后端实际的MAC地址响应),三层负载均衡(一般采用虚拟IP地址方式,外部对虚拟的ip地址请求,负载均衡接收后分配后端实际的IP地址响应),四层负载均衡(在三次负载均衡的基础上,用 ip+port 接收请求,再转发到对应的机器),七层负载均衡(根据虚拟的url或是IP,主机名接收请求,再转向相应的处理服务器)。
硬件负载均衡:
F5 美国F5网络公司 https://f5.com/zh
Netscaler 美国思杰公司 https://www.citrix.com.cn/products/citrix-adc/
Array 华耀 https://www.arraynetwaorks.com.cn/
AD-1000 深信服 http://www.sangfor.com.cn/
四层负载均衡:
四层的负载均衡就是基于IP+端口的负载均衡:在三层负载均衡的基础上,通过发布三层的IP地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT处理,转发至后台服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
对应的负载均衡器称为四层交换机(L4 switch),主要分析IP层及TCP/UDP层,实现四层负载均衡。此种负载均衡器不理解应用协议(如HTTP/FTP/MySQL等等),常见例子有:LVS,F5。
七层负载均衡
七层的负载均衡就是基于虚拟的URL或主机IP的负载均衡:在四层负载均衡的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个Web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。
对应的负载均衡器称为七层交换机(L7 switch),除了支持四层负载均衡以外,还有分析应用层的信息,如HTTP协议URI或Cookie信息,实现七层负载均衡。此种负载均衡器能理解应用协议,常见例子有: haproxy,MySQL Proxy。
四层和七层负载均衡的区别:
所谓的四到七层负载均衡,就是在对后台的服务器进行负载均衡时,依据四层的信息或七层的信息来决 定怎么样转发流量
四层的负载均衡,就是通过发布三层的IP地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT处理,转发至后台服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
七层的负载均衡,就是在四层的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个Web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。
所谓四层负载均衡,也就是主要通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。
以常见的TCP为例,负载均衡设备在接收到第一个来自客户端的SYN 请求时,即通过上述方式选择一个最佳的服务器,并对报文中目标IP地址进行修改(改为后端服务器IP),直接转发给该服务器。TCP的连接建立,即三次握手是客户端和服务器直接建立的,负载均衡设备只是起到一个类似路由器的转发动作。在某些部署情况下,为保证服务器回包可以正确返回给负载均衡设备,在转发报文的同时可能还会对报文原来的源地址进行修改。
所谓七层负载均衡,也称为“内容交换”,也就是主要通过报文中的真正有意义的应用层内容,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。
以常见的TCP为例,负载均衡设备如果要根据真正的应用层内容再选择服务器,只能先代理最终的服务器和客户端建立连接(三次握手)后,才可能接受到客户端发送的真正应用层内容的报文,然后再根据该报文中的特定字段,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。负载均衡设备在这种情况下,更类似于一个代理服务器。负载均衡和前端的客户端以及后端的服务器会分别建立TCP连接。所以从这个技术原理上来看,七层负载均衡明显的对负载均衡设备的要求更高,处理七层的能力也必然会低于四层模式的部署方式。
2.HAProxy:
HAProxy是法国开发者威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件,是一款具备高并发(万级以上)、高性能的TCP和HTTP负载均衡器。支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统计。
企业版网站:https://www.haproxy.com
社区版网站:http://www.haproxy.org
github:https://github.com/haprox
haproxy基本配置信息:
global:全局配置段
- 进程及安全配置相关的参数
- 性能调整相关参数
- Debug参数
参数说明:
proxies:代理配置段
- defaults:为frontend,backend,listen提供默认配置
- frontend:前端,相当于nginx中的server {}
- backend:后端,相当于nginx中的upstream {}
- listen:同时拥有前端和后端配置,配置简单,生产推荐使用
参数说明:
haproxy的算法
HAProxy通过固定参数balance指明对后端服务器的调度算法
balance参数可以配置在listen或backend选项中
HAProxy的调度算法分为静态和动态调度算法
有些算法可以根据参数在静态和动态算法中相互转换
静态算法
静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度等,且无法实时修改权重(只能为0和1,不支持其它值),只能靠重启HAProxy生效。
static-rr:基于权重的轮询调度:
- 不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)
- 不支持端服务器慢启动(慢启动是指在服务器刚刚启动时不会把它所应该承担的访问压力全部给它,而是先给一部分,当没有问题后再给一部分)
- 其后端主机数量没有限制,相当于LVS中的wrr
first(很少用):
- 根据服务器在列表中的位置,自上而下进行调度
- 其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
- 其会忽略服务器的权重设置
- 不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效
动态算法
- 基于后端服务器状态进行调度适当调整
- 新请求将优先调度至当前负载较低的服务器
- 权重可以在haproxy运行时动态调整无需重启
- 静态算法后端Real Server个数不限
roundrobin(使用最多)
基于权重的轮询动态调度算法
支持权重的运行时调整,不同于Ivs中的rr轮训模式
HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数)
其每个后端backend中最多支持4095个real server
支持对real server权重动态调整
roundrobin为默认调度算法,此算法使用广泛
优先把流量给权重高且负载小的主机,以负载为主
leastconn
- leastconn加权的最少连接的动态
- 支持权重的运行时调整和慢启动(相当于LVS的wlc),即:根据当前连接最少的后端服务器而非权重进行优先调度(新客户端连接)【当两个主机的连接数都差不多的时候给权重高的,权重是次考虑的】
- 比较适合长连接的场景使用,比如:MySQL等场景。
其他算法(既可作为静态算法,又可以通过选项成为动态算法)
其他算法既可以当作静态算法,又可以通过选项变成动态算法
静态:取模法通过权重进行取模来决定发往的后端服务器,会被权重的变化和主机的崩溃影响。
通过设置一致性hash:hash-type consistent
来变成动态算法
默认不写就是hash-type map-base的静态,hash-type consistent 就是动态的。
source
源地址hash,依据请求的源IP地址进行哈希,从而将所有来自相同IP的请求总是转发到同一台后端服务器。那么如何选取后端服务器呢?其中有两种方法分别是取模法和一致性hash
map-base 取模法
对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。
此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度。
缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变,hash-type指定的默认值为此算法。
所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3
map-based算法:基于权重取模,hash(source_ip)%所有后端服务器相加的总权重。
map-base 取模法是用于将客户端请求分配到后端服务器的一种算法策略。 具体来说,当使用 map-base 取模法时,HAProxy 会根据客户端请求的某些特征(例如源 IP 地址)进行计算,并通过取模运算来确定将请求转发到后端的哪一台服务器。 例如,如果后端有 5 台服务器,HAProxy 对客户端源 IP 地址进行某种处理后得到一个数值,然后将这个数值对 5 取模,得到的结果(0 到 4 之间)就决定了将请求发送到对应的服务器。 这种方法的优点在于实现相对简单,并且在一定程度上能够平均地分配请求。 但它也有一些潜在的问题: 1. 如果后端服务器的数量发生变化(例如新增或移除服务器),那么取模的结果就会发生较大变化,可能导致部分请求的分配路径突然改变,影响服务的稳定性。 2. 当客户端的分布不均匀时(例如来自某些特定网段的客户端请求特别多),可能会导致后端服务器的负载不均衡。
一致性hash
在 Linux 中,HAProxy 中的一致性哈希(Consistent Hashing)是一种用于负载均衡的算法。 一致性哈希的主要思想是将后端服务器和客户端请求(通常基于某种特征,如源 IP 地址)映射到一个环形的哈希空间中。 比如说,这个哈希空间是从 0 到 2^32 - 1 的一个整数范围。每台后端服务器根据其标识(如 IP 地址或名称)计算出一个哈希值,并对应到这个环上的一个位置。客户端请求也通过类似的方式计算出哈希值,并在环上顺时针查找遇到的第一个服务器节点,该服务器就负责处理这个请求。 一致性哈希的优点在于: 当后端服务器数量发生变化时,例如新增或移除服务器,只有环上相邻的一小部分请求的分配会受到影响,而不是像传统的取模算法那样可能导致大部分请求的分配路径发生改变。 例如,如果原本有服务器 A、B、C 分布在环上,当新增服务器 D 时,只有原本会分配到服务器 A 与服务器 C 之间的那部分请求会被重新分配到服务器 D 上,其余请求的分配路径不变。 这就大大减少了因服务器数量变动而导致的请求重新分配的范围,提高了系统的稳定性和可扩展性。 同时,一致性哈希对于客户端请求分布的不均匀性也有更好的适应性,能够在一定程度上避免某些服务器负载过高或过低的情况。
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动hash (o) mod n
该hash算法是动态的,支持使用socat等工具进行在线权重调整,支持慢启动
计算方法:
- key1=hash(source_ip)%(2^32)
- keyA=hash(后端服务器虚拟ip)%(2^32) [0—4294967295]
- 将key1和keyA都放在hash环上,将用户请求调度到离key1最近的keyA对应的后端服务器
解决hash环偏斜问题
增加虚拟节点数量
首先,确定每个物理节点需要创建的虚拟节点数量。这个数量可以根据实际情况进行设定,通常会根据物理节点的数量、系统的规模和负载均衡的要求来决定。 然后,为每个物理节点生成相应数量的虚拟节点标识。这些标识可以通过在物理节点的标识基础上添加一些后缀或前缀来创建,以确保虚拟节点标识的唯一性。 接下来,计算虚拟节点的哈希值。使用与计算物理节点哈希值相同的哈希函数,对虚拟节点标识进行计算,得到对应的哈希值。 将虚拟节点的哈希值映射到一致性哈希环上。这些虚拟节点的哈希值会均匀地分布在哈希环上,从而增加了物理节点在哈希环上的“密度”。 在处理请求时,按照一致性哈希的规则,先计算请求的哈希值,然后在哈希环上顺时针查找最近的节点。由于虚拟节点的存在,请求更有可能被分配到不同的物理节点上,从而实现更均匀的负载分布。 例如,假设有 3 台物理服务器 A、B、C,决定为每台服务器创建 10 个虚拟节点。 服务器 A 的标识为 A,则生成的 10 个虚拟节点标识可以是 A-1、A-2、A-3 … A-10。 计算这些虚拟节点标识的哈希值,并映射到哈希环上。 当有新的请求到来时,计算其哈希值,在哈希环上查找最近的节点。此时,很可能会找到某个服务器 A 的虚拟节点,从而将请求分配到服务器 A 上。 通过这种方式,增加了服务器 A 在哈希环上的“存在范围”,提高了其获得请求分配的机会,使得负载能够在多台物理服务器之间更加均衡地分布。
uri
缓存服务器,CDN服务商,百度、阿里云、腾讯
基于对用户请求的URI的左半部分或整个uri做hash,再将hash结果对总权重进行取模后,根据最终结果将请求转发到后端指定服务器,适用于后端是缓存服务器场景,默认是静态算法,也可以通过hash-type指定map-based和consistent,来定义使用取模法还是一致性hash。
注意:此算法基于应用层,所以只支持 mode http ,不支持 mode tcp
url_param
可以实现session保持
url_param对用户请求的url中的 params 部分中的一个参数key对应的value值(路径中的?形式)作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server,如果无没key,将按roundrobin算法。
hdr
基于客户端请求报文头部做下一步处理
针对用户每个 http 头部(header)请求中的指定信息做 hash,此处由 name 指定
的 http 首部将会被取出并做 hash 计算,然后由服务器总权重相除以后派发至某
挑出的服务器,假如无有效的值,则会使用默认的轮询调度。
算法总结:
hash法:绑定session会话
source:对源地址进行hash(目的绑定源地址)
uri:对uri的左半部分或者全部进行hash(访问的路径进行绑定)
url:对user的key对的值进行hash(绑定用户)
hdr:对包头进行hash(绑定头部信息如浏览器,域名等)
挑选服务器:
取模法:利用权重对hash值进行取余,缺点当权重变化或者服务器死机时。绑定的服务器会变化
一致性hash法:在hash环上先选取服务器的点再选取客户端的点,顺时针选取最近的服务器进行绑定
二:实战部分
环境:
三台虚拟机,一台windows端
三台虚拟机:
Web1(服务器)(ip=172.25.25.250.10)
Web2(服务器)(ip=172.25.25.250.20)
HAProxy(haproxy调度端)(ip=172.25.25.250.100)
windows:
用来访问测试(ip=172.25.25.250.1)
两台服务器下载nginx用于配置Web
HAProxy的高级使用方法:
HAProxy状态页
通过web界面,显示当前HAProxy的运行状态
状态页配置项
stats enable #基于默认的参数启用stats page
stats hide-version #将状态页中haproxy版本隐藏
stats refresh <delay> #设定自动刷新时间间隔,默认不自动刷新
stats uri <prefix> #自定义stats page uri,默认值:/haproxy?stats
stats auth <user>:<passwd> #认证时的账号和密码,可定义多个用户,每行指定一个用户
#默认:no authentication
stats admin { if | unless } <cond> #启用stats page中的管理功能
使用状态页
进入 vim /etc/haproxy/haproxy.cfg配置文件添加
listen stats
bind *:7777
mode http
stats enable
log global
stats uri /status
stats auth wang:wang
登录状态页
使用浏览器访问状态页
IP透传
P 透传(IP Transparency)指的是在代理服务器处理请求和响应的过程中,能够将客户端的真实 IP 地址传递到后端服务器,使得后端服务器能够获取到客户端的原始 IP 而不是代理服务器的 IP 地址。
web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景。
IP透传分为四层和七层
tcp协议为四层,httpd的为七层
当透传为七层时使用nginx的时候:默认参数是开着的可以直接查看
先访问web2:
查看日志,看web1的日志是否记载了源IP:
四层穿透时候:
需要进行以下操作
在web上配置:
vim /etc/nginx/nginx.conf
在haproxy上配置:
重启服务
再访问:
ACL控制列表
访问控制列表ACL,Access Control Lists)
是一种基于包过滤的访问控制技术
它可以根据设定的条件对经过服务器传输的数据包进行过滤(条件匹配)即对接收到的报文进行匹配和过 滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL、文件后缀等信息内 容进行匹配并执行进一步操作,比如允许其通过或丢弃。
ACL配置选项
域名匹配
frontend wang
bind *:80
mode http
acl set_host hdr_dom(host) -i www.wang.org #匹配的域名
use_backend web1 if set_host #匹配到alc使用的backend
default_backend web2 #没匹配到默认backend
backend web1
balance roundrobin
server static 172.25.250.10:80 check
backend web2
balance roundrobin
server static 172.25.250.20:80 check
测试:
注意需要在Windows下做本地解析
基于源IP或子网调度访问
frontend wang
bind *:80
mode http
acl set_ip src 172.25.250.1
use_backend web1 if set_ip
default_backend web2
backend web1
balance roundrobin
server static 172.25.250.10:80 check
backend web2
balance roundrobin
server static 172.25.250.20:80 check
测试:
基于源地址的访问控制
拒绝指定IP或者IP范围访问
frontend wang
bind *:80
mode http
acl set_ip src 172.25.250.1
http-request deny if set_ip
default_backend web2
backend web1
balance roundrobin
server static 172.25.250.10:80 check
backend web2
balance roundrobin
server static 172.25.250.20:80 check
测试:
匹配浏览器类型
匹配客户端浏览器,将不同类型的浏览器调动至不同的服务器组、
范例: 拒绝curl和wget的访问
frontend wang
bind *:80
mode http
acl user_agent hdr_sub(User-Agent) -i curl wget
http-request deny if user_agent
default_backend web2
backend web1
balance roundrobin
server static 172.25.250.10:80 check
backend web2
balance roundrobin
server static 172.25.250.20:80 check
测试:
基于文件后缀名实现动静分离
下载php
[root@web1 ~]# yum install php -y
编辑php首页
vim /usr/share/nginx/html/index.php
重启nginx
修改策略
frontend wang
bind *:80
mode http
acl url_php path_end -i .php
use_backed web1 if url_php
default_backend web2
backend web1
balance roundrobin
server static 172.25.250.10:80 check
backend web2
balance roundrobin
server static 172.25.250.20:80 check
测试:
自定义HAProxy 错误界面
关闭两个web的服务使得访问他出现503
[root@web1 ~]# systemctl stop nginx.service
[root@web2 ~]# systemctl stop nginx.service
测试:
HAProxy 四层负载配置数据库
针对除HTTP以外的TCP协议应用服务访问的应用场景
MySQL Redis Memcache RabbitMQ
四层负载示例
首先准备的环境:
两个web服务器和haproxy上下载mariadb
yum install mariadb-server-galera.x86_64
然后在两个web上分别配置mariadb:
首先设置两个数据的id用于验证时候的区分
vim /etc/my.cnf.d/mariadb-server.cnf
然后分别在两个服务器上创建wang这个用户
MariaDB [(none)]> create user wang@'%' identified by 'wang';
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> grant all on *.* to wang@'%'
-> ;
Query OK, 0 rows affected (0.001 sec)
修改haproxy配置:
listen webserver_80
bind *:3306
mode tcp
#balance static-rr
balance roundrobin
#cookie wang insert nocache indirect
server web1231 172.25.250.10:3306 check
server web32313 172.25.250.20:3306 check
然后重启服务
systemctl restart haproxy.service
测试:
exit
HAProxy七层配置https
haproxy可以实现https的证书安全,从用户到haproxy为https,从haproxy到后端服务器用http通信 但基于性能考虑,生产中证书都是在后端服务器比如nginx上实现
#配置HAProxy支持https协议,支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
#指令 crt 后证书文件为PEM格式,需要同时包含证书和所有私钥
cat demo.key demo.crt > demo.pem
#把80端口的请求重向定443
bind *:80
redirect scheme https if !{ ssl_fc }
证书制作
[root@haproxy ~]# mkdir /etc/haproxy/certs/
[root@haproxy ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/wang.org.key -x509 -days 365 -out /etc/haproxy/certs/wang.org.crt
[root@haproxy certs]# cat wang.org.crt wang.org.key > wang.org.pem将证书和钥匙放入PEM格式的文件里
配置代理:
frontend webserver
bind *:80
redirect scheme https if !{ ssl_fc }
mode http
use_backend wang
frontend webservser_https
bind *:443 ssl crt /etc/haproxy/certs/wang.org.pem
mode http
use_backend wang
backend wang
mode http
balance roundrobin
server web1 172.25.250.10:80 check inter 3s fall 3 rise 5
server web2 172.25.250.20:80 check inter 3s fall 3 rise 5
全站加密
redirect scheme https if !{ ssl_fc }
加上这条命令就会自动将80端口的请求重定向到443
测试: