LBaaS v2
Neutron 包含负载均衡服务, 即 LBaaS. 负载均衡器可以将用户的访问流量通过算法均摊到多台主机实例上, 实现以 Scale-out 的方式扩容应用的性能. Neutron LBaaS 包含以下核心的概念:
服务器池 Pool: 服务器池内包含了多个服务器成员, 同一个池内的服务器至少包含一种统一的对外服务.
服务器成员 Member: 服务器成员, 包含服务器的 IP 和端口.
监听器 Listener: 监听器将持续监听指定的端口上的连接请求. 一个负载均衡器中允许存在多个监听器, 同时通过共享服务器池, 多个监听器也可以关联到同一个服务器池.
健康监控 Health monitor: 检查服务器池中成员的状态, 以及服务器的加入, 离开.
之所以称之为 lbaas v2, 是因为 Neutron 的负载均衡的模型有过一次如上图的进化, 在 v2 的版本中, neutron 对负载均衡的架构有了一次非常大的调整, v2 版本变得更符合行业标准, 且驱动和功能扩展变得更为简单, 除此之外新版本还允许一个负载均衡器下添加多组 Listener 监听服务, 以及加入了 TLS.Lbaas v2 无法和 lbaas v1 同时运行, 开启 lbaas v2 需要停止 lbaas v1.
改进后的 LBaaS v2 经过了更为全面的测试, 并且加入了更多的 HTTP 层代理的特性. 并开始支持 Active-Standby 部署模式, 后续版本中将进一部支持 Active-Active. 新版可以说是负载均衡架构和功能的一次飞跃.
负载均衡概念
服务器池 Pool
服务器池即后端一组提供服务的实例, 每个成员都是一个 IP 地址 + 4 层的端口. 例如, 常见的提供 web 服务的实例, 在服务器池中表示为: 192.168.1.1:80. 提供的服务不同则端口号也不相同. 池内的服务器都统一对外提供某一种服务. 例如:
服务器 1:192.168.1.1:80
服务器 2:192.168.1.3:80
服务器 3:192.168.1.4:80
负载均衡器通过 VIP 统一对前端提供服务, 用户向虚拟 IP 发起连接请求, 监听器监听到对应端口的请求后, 通过负载均衡算法将请求转发到后端服务池中的一个成员上. 然后成员对用户请求的资源进行响应, 这样整个过程对于用户来说是透明的. 包括后端服务器的增加, 减少以应对用户规模的增缩, 都不会对已经建立的连接产生影响.
监听器 Listener
监听器即一个不断在端口上检查连接请求的进程, 一旦发现客户端的连接请求, 则会按照你设定的规则将连接请求转发给后端的服务器池. 一个监听器关联一个端口, 如: HTTP(80),HTTPS(443), 当使用 HTTPS, 则需要上传用于 https 加密和解密的证书到监听器中.
L7 转发策略 l7 policy
l7 策略转发流程
LBaaS v2 支持 L7 的转发策略, 每个监听器上都可以配置多条转发策略 (L7 Policy). 策略由由规则(rule) 和操作组成, 类似 if...then... 的条件语句, 当有流量匹配了 rule 的条件时, 就按照策略中的操作转发. 否则就继续向下匹配. 规则可以匹配 HTTP 请求中的特殊字段或 URL, 这给业务带来了极大的灵活性.
rule 支持的匹配项包括:
Hostname,L7 rule 支持匹配 HTTP/1.1 请求中的 host 字段
path,HTTP URI 中路径的部分
file_type, 请求的文件类型
header,HTTP 头中其他字段
cookie,cookie 的值
需要注意的是, 同一个 policy 下的 rule 是 "与" 的关系, 即策略下的所有 rule 都匹配的情况下, 才会按照策略的操作转发. 其中任何一条不匹配都会跳过该策略向下匹配.
匹配的算法包括:
regex, 正则表达式, 非的意思
starts_with, 字符串开头
ends_with, 字符串结尾
contains, 字符串中包含的值
equal_to, 等于
L7 policy 的操作支持:
block, 请求将直接被拒绝;
redirect_to_url, 重定向用户的 url;
redirect_to_pool, 重定向到后端特定的主机池内.
例如: 可以在监听器上添加两条 rule, 一条匹配 HTTP 请求中 file_type 包含: jgp,PNG,gif,zip,txt 的请求转发给 image pool. 另一条一条匹配 URI 中 path 以 "*/login" 开头的请求转发给 App pool.
这样就简单的实现了网站上静态内容 (图片) 与动态内容 (用户登录) 的分流处理, 这能在不改变应用架构的情况下, 减轻 Web 服务的负载. 对于云原生应用来说, 这样的功能非常重要.
L7 策略配置示例如下:
- neutron --policy policy1 lbaas-create-l7policy --name "policy1" --description "My Description" --listener "listener1" --action redirect_to_pool --pool "pool1" --position 1 (创建 L7 策略, 命名为 "policy1" 描述为 "lb 策略", 并关联 "listener 1", 策略的动作是将匹配的流量转发到 "pool1")
- neutron lbaas-create-l7rule rule1 --rule-type path --compare-type starts_with --value "/api" --policy policy (在 "policy 1" 下添加一条规则, 匹配所有 URL 中以 "/api" 开头的请求)
可见到 LBaaS v2 可根据业务需求制定出非常灵活的 7 层转发策略.
负载均衡算法 Algorithms
本身 Neutron 支持的负载均衡算法包括: 轮询, 最少连接, 源 IP.
轮询 Round robin, 是最普遍的算法, 每当有一个新的请求来临, 负载均衡器都会按顺序选择服务器池中的一台设备来响应. 有点类似音乐播放软件的列表循环. 这种模式下服务器池中的每一个服务器都能均匀地分配到相同的访问请求数, 而不会管服务器繁忙程度, 服务器配置的高低. 比较适用于服务器池内的服务器配置相同, 用户访问习惯相同的业务. 加权轮询是改进的负载均衡算法, 当后端服务器池中设备配置高低不一时, 可根据服务器处理能力的高低分配服务器的权值, 权值高的服务器会被分配更多的用户请求.
最少连接算法 Least connections, 负载均衡器收到新的请求时, 都会从当前服务器池中挑选一个当前并发连接数最少的服务器来负责. 最少连接算法考虑的服务器的实时负载情况, 尽量保证了任务分配的平均, 防止单个服务器超出负载, 但是当后端服务器池中存在高处理能力的服务器时, 这个处理能力高的设备始终无法获得更多的工作负载, 存在性能的浪费. 最少连接算法有优化后的加权最小连接算法
IP hash, 负载均衡器在收到主机的连接请求后, 会根据数据包的源 IP 地址字段的 hash 值, 同时按照轮询的方式为客户端分配主机, 当负载均衡器再次收到同一 IP 的请求时, 则会按照之前的记录为客户端分配上次建立连接的主机. 这样保证了当同一个 IP 的用户, 多次独立的访问都能由同一台服务器来处理, 适用于服务器需要临时记录或保存客户信息的应用中.
健康监测 Monitor
健康检测的机制是指是负载均衡器通过定期的心跳信号检测服务器池中的服务器运行状态, 从而排除掉后端故障的主机, 保证服务整体正常.
Neutron 支持的健康检测方式包括 ICMP,TCP,HTTP 几种.
ICMP 是最简单的, 通过 ping 和 echo 的方式, 看根据服务器是否响应. 只要服务器操作系统 TCP/IP 协议栈运行正常, 网卡不出问题, 服务器到负载均衡之间的网络正常, ICMP 的方式都起到良好的作用, 但以上情况都不能代表服务器上面运行的应用是正常的.
TCP 是 4 层的检测方式, 相比 ICMP,TCP 会请求主机的特定端口, 看特定的端口能否正常响应.
HTTP 的方式则更进一筹, 会通过 get 特定的页面, 根据 HTTP 的返回代码来判断应用是否正常.
健康监测的指标越精确, 越能反映服务的实际响应情况, 如果是 Web 服务, 最好是使用 HTTP 的方式, 这样检测结果更可信.
会话保持 Session persistence
会话保持功能常用于有状态的服务中, 比如服务器通过 session 来维护用户连接的状态, 因为 session 保存在服务器本地, 如果不断地通过网络来在服务器池中同步 session 的话, 会消耗服务器的带宽和处理能力, 所以这时会选择使用负载均衡器的会话保持功能. 它能保证同一个用户的请求会被发送到同一台服务器.
Lbaas v2 支持的会话保持的类型为:
源 IP: 源 IP 即 IP hash 算法, 根据 IP 地址来识别客户. 负载均衡器在收到请求后会计算数据包头源 IP 地址的 hash 值, 并按照轮询的方式给该客户端分配一个服务器, 同时将两者的对应关系记录到表中, 当再次收到同一源 IP 发来的请求时, 则查找到之前的服务器进行转发. 但是当客户端通过 NAT, 或代理的方式上网时, 源 IP 的方式就可能导致多个客户端被分配到同一个主机. 顺便一提, 去年在公司用 12306 在高峰期抢车票时, 刚打开网站就被提示 "您的操作频率过快", 即很有可能 12306 后端也是判断同一个 IP 提交的访问请求过多, 从而误把新接入用户当作了已访问过的用户.
HTTP_cookie: 该模式下会根据浏览器中缓存的 cookie 来识别用户, cookie 里面一般都缓存了计算机信息和浏览器的信息以及用户认证的信息. Lbaas v2 中负载均衡器会在服务器第一次返回给客户端的回应中插入 "SRV" 的 cookie 值, 标识了回复的服务器. 当再次收到客户端发起的 HTTP 请求时, lbaas v2 会找出 cookie 中的 "SRV" 字段, 并剥离掉后转发给之前回复的服务器. HTTP_cookie 的问题在于, 有可能一些用户会禁用掉浏览器上的 cookies, 这种情况下基于 cookies 的会话保持就将失效了.
App_cookie: 该模式下需要在负载均衡器中预先定义各个后端中设置的 cookie, 并将对应关系存储到表中, 当收到客户端的请求时, 检查请求中是否有预先定义的 cookie, 如果有, 则转发到对应的服务器.
虽然当今互联网应用中通过 token 来实现用户的识别和鉴权已经比较常见了, 但负载均衡的会话保持能够很好弥补通过 seesion 识别用户的应用的不足. 但是基于 cookie 的会话保持无法支持服务器直接返回的部署模式, 即服务器返回给用户的流量不经过负载均衡器, 而是直接上行转发出去. 所以在某些大流量的应用中, 负载均衡器可能成为性能的瓶颈.
非对称流量中, 服务器直接返回到客户端, 上行流量不经过负载均衡器, LBaaS v2 暂时还不支持这种部署模式.
实现
Neutron 中 LBaaS v2 有两种实现方式,
一是: 使用 HAproxy 作为负载均衡器, 在网络节点上运行 LBaaS agent,agent 会完成节点上的 Haproxy 的创建和配置工作. 这也是目前较为成熟的使用方式.
二是: 使用 Octavia 作为负载均衡器, Octavia 是在 LBaaS v2 中加入到 openstack 中的, 官方对它的定位不是要代替 HAproxy 在 neutron 中的地位, 而是作为一个可选开源的 LB 服务提供者, 类似 LVS+F5 等. Octavia 的架构是全新设计的, 而且在一开始就立志成为运营级的负载均衡解决方案. 只是目前 Octavia 还是远谈不上成熟, 官方推荐只在 Devstack 中使用.
HAproxy + keepalive
比较常用的开源负载均衡器有 LVS,Nginx,HAproxy, 其中 LVS 只能做到四层的负载均衡, 即只能依据 IP + 端口的方式进行转发, 不支持 L7 的转发策略, Nginx 不仅能做 Web 服务器, 同时也能作为负载均衡器使用; HAproxy 和 Nginx 都能基于 L7 策略进行转发. LVS 也经常和 HAproxy,Nginx 混用, 在大流量的集群中, 先由 LVS 将流量分摊到不同的 Nginx/HAproxy 集群, 再由 Nginx/HAproxy 做 L7 转发. 除此之外 Neutron 也支持 Ctrix,F5,Radware 等公司的插件, 从而通过专用的负载均衡硬件来实现.
LBaaS v2 的经典实现方式就是在网络节点上部署 HAproxy+Keepalive 实现负载均衡服务. 其中 HAproxy 提供 L7 的负载均衡, Keepalive 用于实现高可用方案.
HAproxy
HAproxy 能够为服务器池提供 7 层的负载均衡功能, 即能根据 HTTP 请求头中的内容来执行负载均衡算法. 而且作为开源软件, 被广泛使用.
1. 启用 lbaas v2 首先需要修改 neutron 的配置文件, 加入插件:
- /etc/neutron/neutron.conf
- service_plugins = [existing service plugins],neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2
2. 在 lbaas 的配置文件中添加 lbaas v2:
- /etc/neutron/neutron_lbaas.conf
- service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
3. 选择 2 层设备的驱动:
- /etc/neutron/lbaas_agent.INI
- [DEFAULT]
- interface_driver = openvswitch
根据实际, 选择 ovs 或者 Linux bridge, 需要与节点上的 2 层设备类型匹配.
4. 开启数据库迁移
neutron-db-manage --subproject neutron-lbaas upgrade head
5. 启动 lbaas v2 agent.
neutron-lbaasv2-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/lbaas_agent.INI
- neutron lbaas-listener-create \ // 添加监听器
- --loadbalancer my-lb \ // 关联之前创建的负载均衡器
- --protocol HTTP \ // 选择监听器协议, TCP\HTTP\HTTPS
- --protocol-port 80 \ // 选择监听器对外监听的端口(即向用户开放的端口)
- --name webservice-listener \ // 设置监听器名称
- neutron lbaas-pool-create --lb-algorithm ROUND_ROBIN \ // 选择负载均衡算法, 支持上文中提到的轮询, 最少连接, IP hash 等
- --listener LISTENER_1_NAME \ // 关联监听器
- --protocol HTTP \ // 服务器池使用的协议
- --name LB_POOL_1 // 服务器名称
- neutron lbaas-member-create --subnet <subnet-id> --address <server 1 IP> \ // 将后端服务器添加到地址池中
- --protocol-port 80 <pool name> // 后端服务器上服务所使用的端口, 可以与前端的端口不一致
- neutron lbaas-member-create \
- --subnet <subnet-id> --address <server 2 IP> --protocol-port 80 <pool name>
- neutron lbaas-healthmonitor-create --delay DELAY_IN_SECONDS // 设置心跳检测发送到服务器成员的周期, 单位为秒. 需避免过于频繁的心跳检测, 以及检测不及时的情况出现, 达到平衡. 对可用性要求高可以设置为 3~5 秒,
- --type [HTTP | TCP] // 选择心跳检测的协议, 如果 TCP 则只检测服务器上端口是否开启, HTTP 则支持检测 Web 服务的状态. 当选择 HTTP 时, 可以指定 http 的方法, 默认是 get 一个特定的页面. 同时还能指定服务器正常响应对应的 HTTP 状态码, 如返回 200 时, 代表 Web 服务正常, 200 以外的值, 如 404,408 等则代表异常. 可通过 expected_codes 设置. url_path 则用来指定 health monitor 请求的页面.
- --max-retries NUMBER \ // 设置在改变服务器可用状态之前, 等待服务器的应答的次数. 假设为 n, 如果是 n 次未响应, 则切换为 inactive, 之后如果 n 次正常响应, 则切换为 active. 推荐为 3
- --timeout TIMEOUT_IN_SECONDS // 设置超时的时长, 当超过该时长服务器都没有回应, 则认为服务器此次心跳监测为故障.
- --pool LBAAS_POOL // 将健康监测配置关联到服务器池.
- http://502245466.blog.51cto.com/7559397/1303506
- Load Balancing as a Service : Liberty and Beyond
- NAT-->(DNAT)
- DR
- TUN
- FULLNAT(貌似没有)
- ipvsadm -A|E -t|u|f service-address [-s scheduler]
- [-p [timeout]] [-M netmask]
- ipvsadm -a|e -t|u|f service-address -r server-address
- [-g|i|m] [-w weight]
- [[email protected] ~]# sysctl -a | grep.NET.ipv4.ip_forward
- sysctl: reading key "net.ipv6.conf.all.stable_secret"
- net.ipv4.ip_forward = 1
- echo 1> /proc/sys.NET/ipv4/ip_forward
- sysctl -p // 立即生效
- [[email protected] ~]# grep -E -i "ipvs|IP_VS" /boot/config-3.10.0-862.11.6.el7.x86_64
- CONFIG_NETFILTER_XT_MATCH_IPVS=m
- CONFIG_IP_VS=m
- CONFIG_IP_VS_IPV6=y
- # CONFIG_IP_VS_DEBUG is not set
- CONFIG_IP_VS_TAB_BITS=12
- # IPVS transport protocol load balancing support
- CONFIG_IP_VS_PROTO_TCP=y
- CONFIG_IP_VS_PROTO_UDP=y
- CONFIG_IP_VS_PROTO_AH_ESP=y
- CONFIG_IP_VS_PROTO_ESP=y
- CONFIG_IP_VS_PROTO_AH=y
- CONFIG_IP_VS_PROTO_SCTP=y
- # IPVS scheduler
- CONFIG_IP_VS_RR=m
- CONFIG_IP_VS_WRR=m
- CONFIG_IP_VS_LC=m
- CONFIG_IP_VS_WLC=m
- CONFIG_IP_VS_LBLC=m
- CONFIG_IP_VS_LBLCR=m
- CONFIG_IP_VS_DH=m
- CONFIG_IP_VS_SH=m
- CONFIG_IP_VS_SED=m
- CONFIG_IP_VS_NQ=m
- # IPVS SH scheduler
- CONFIG_IP_VS_SH_TAB_BITS=8
- # IPVS application helper
- CONFIG_IP_VS_FTP=m
- CONFIG_IP_VS_NFCT=y
- CONFIG_IP_VS_PE_SIP=m
- [[email protected] ~]# ipvsadm -Ln --rate
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port CPS InPPS OutPPS InBPS OutBPS
- -> RemoteAddress:Port
- TCP 10.0.0.50:80 1 5 5 449 550
- -> 192.168.1.51:80 0 3 2 228 275
- -> 192.168.1.52:8080 0 3 2 221 275
- # 保存 ipvsadm 规则至 / etc/sysconfig/ipvsadm 文件中
- [[email protected] ~]# ipvsadm -S >/etc/sysconfig/ipvsadm
- [[email protected] ~]# cat /etc/sysconfig/ipvsadm
- # 从文件中重载所有规则
- [[email protected] ~]# ipvsadm -R </etc/sysconfig/ipvsadm
- class LvsDriver(agent_device_driver.AgentDeviceDriver):
- [[email protected] ~]# ipvsadm -C
- [[email protected]node0~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- [[email protected]node0~]# ipvsadm -A -u 10.33.46.64:9999 -s sh -p 120
- [[email protected]node0~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 0 0 0 0 0
- [[email protected] ~]# ipvsadm -a -u 10.33.46.64:9999 -r 10.33.46.68:9999 -m -w 1
- [[email protected] ~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 0 0 0 0 0
- -> 10.33.46.68:9999 0 0 0 0 0
- [[email protected] ~]# arping -c 1 10.33.46.68
- ARPING 10.33.46.68 from 10.33.46.64 tap85d707e7-35
- Unicast reply from 10.33.46.68 [FA:16:3E:0D:A6:AB] 1.310ms
- Sent 1 probes (1 broadcast(s))
- Received 1 response(s)
- [[email protected] ~]# netcat -uvz -w 1 10.33.46.68 9999
- [[email protected] ~]# netcat -uvz -w 1 10.33.46.64 9999
- Warning: Host 10.33.46.64 isn't authoritative! (direct lookup mismatch)
- 10.33.46.64 -> mgm-net0 BUT mgm-net0 -> 172.30.65.2
- [[email protected] ~]# netcat -uvz -w 1 10.33.46.68 9990
- [[email protected] ~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 2 2 0 64 0
- -> 10.33.46.68:9999 2 2 0 64 0
- [[email protected] ~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 2 3 0 111 0
- -> 10.33.46.68:9999 2 3 0 111 0
- [[email protected] ~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 2 4 0 142 0
- -> 10.33.46.68:9999 2 4 0 142 0
- [[email protected] ~]# nc -ul 10.33.46.68 9999
- [[email protected] ~]# ipvsadm -Z ==== 清空统计数据
- [[email protected] ~]# ipvsadm -ln --stats == 查看统计 IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 0 0 0 0 0
- -> 10.33.46.68:9999 0 0 0 0 0
- [[email protected] ~]# echo "hello word"|nc -nuv 10.33.46.64 9999
- Ncat: Version 7.50 ( https://nmap.org/ncat )
- [[email protected] ~]# nc -ul 10.33.46.68 9999
- hello Word
- [[email protected] ~]# ipvsadm -ln --stats
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
- -> RemoteAddress:Port
- UDP 10.33.46.64:9999 1 1 0 39 0
- -> 10.33.46.68:9999 1 1 0 39 0
来源: http://www.bubuko.com/infodetail-3100043.html