20190117 负载均衡分享
架构 刘宇帅 5年前 阅读量: 1807
什么是负载均衡
负载均衡就是用多台服务器对外提供单一服务,通常用于提高网站、应用、数据库或其他服务的性能和可用性,负载均衡是高可用网络架构的关键组件。
没有负载均衡的架构
有负载均衡的架构
为什么要负载均衡
配置再强的服务器都有服务上限,当单台的服务器无法支持所有用户请求的时候就扩充机器到到几台、几十台甚至更多来提供服务,这个时候需要我们合理的把用户请求分发到各个服务器,这就是负载均衡。 负载均衡要理解最重要的一点,我这里用了“合理的分发”而不是平均分发,因为负载均衡并不是简简单单的均分流量,我们需要考虑到不同的服务器硬件配置、网络情况来合理的分配分配流量以达到各个服务器均不超载、合理利用集群资源达到最佳的服务质量。当然当我们用多台服务器做负载均衡时一般会选用相同规格的机器,但是不排除网络延迟、机器突发故障灯引起的单台服务器负载飙升处理能力下降等情况。
负载均衡方案
DNS 层
当客户端访问站点的时候,会查询 DNS,我们可以通过在 DNS 配置多条解析让 DNS 服务器通过轮询返回 IP 实现负载均衡。
优点:
- 通过 DNS 服务器实现负载均衡,减少自身机器压力
- DNS 服务器本身会根据用户 IP 智能分配里用户最近的 IP
- 动态更新,当服务器 IP 变更时,只需要修改 DNS 记录即可更新
缺点:
- 动态更新时存在延迟,由于延迟引起的问题时更难追查
- 特定用户问题不好追查,不知道用户被 DNS 分配到了那个服务器,当然这是可以通过技术解决的
- 策略单一,无法根据请求类型设置调度策略或者配置权重等,当然阿里云等一些服务商有提供这方面的服务,但是相对也比较单一
总结:
客户端-DNS 层综合来说非常不适合做负载均衡的,但是还是要根据具体业务分析。
LVS(Linux Virtual Server) 软件负载均衡
LVS-DR
LVS-DR 叫做直接路由,直接路由是工作在数据链路层的二层负载均衡方案,LVS 和 上游服务器共享同一个 VIP,直接路由通过修改数据包的 MAC 地址将数据转发到上游服务器上。
ipvsadm 可用来配置 LVS-DR,具体可参考其文档。
优点:
- 上游服务器直接响应报文到客户端,响应不经过 LVS 可以避免单一 LVS 带宽及性能限制
缺点:
- LVS 和上游服务器必须在同一子网,这样会限制网站架构,一般会在 LVS-DR 后添加 nginx 等四层或七层负载均衡器解决跨网和性能问题。
总结: LVS-DR 是非常适合搭建可扩展的负载均衡系统。
LVS-NAT
LVS-NAT 叫做 IP 负载均衡,NAT 是工作在传输层的四层负载均衡方案,它通过修改发送过来的 IP 数据包,将数据包的目标 IP 修改为上游服务器 IP。ipvsadm 可用来配置 LVS-DR,具体可参考其文档。
优点:
- 没有 LVS-DR 的子网限制
缺点:
- 所有流量均流经 NAT 服务器,服务器的网络带宽及性能会影响服务能力
总结: 除了 NAT 带宽性能的影响外,LVS-NAT 是比较适合搭建负载均衡系统的。
LVS-TUN
LVS-TUN 叫做 IP 隧道负载均衡,TUN 是工作在网络层的三层负载均衡方案,他通过封装 IP 数据包到一个新的 IP 数据包并转发给上有服务器实现。
优点:
- TUN 服务器和上游服务器不需要再同一个子网
- 上有服务器直接响应报文到客户端,服务能力不会受 TUN 服务器的带宽和性能的影响
- 可以根据需求把服务器部署在不同的区域可以提高服务器响应速度
总结: LVS-TUN 是非常适合做负载均衡系统的。
F5
硬件负载均衡器,性能高,扩展难,成本高。起到和 LVS 同样的功能,但是性能会比 LVS 高。扩展性比 LVS 差。
七层负载均衡
七层负载均衡是比较常见的负载均衡方案,一般的站点都会有七层负载均衡,它是工作在应用层的七层负载均衡方案。常见的方案就是基于 nginx、HAProxy、apache 等。
优点:
- 丰富的调度策略,可根据后台服务器响应时间、负载情况、流量等做调度
缺点:
- 承受所有的流量,对带宽和性能要求高
- 工作在应用层处理效率低,需要处理 HTTP 协议层的各种信息包括 HTTP 头部信息,cookie 等
总结:
反向代理是常见的负载均衡方案,一般是必不可少的,一般用于配合 LVS 层负载均衡实现高可用的负载均衡架构。
保持用户会话
负载均衡需要处理的问题就是处理会话,一般方案如下:
- 将一个用户会话中的所有请求都发送到同一个后台服务器(session Id hash等)。不足之处在于无法容错,如果后台服务器故障,回话信息会丢失。
- 加密存放到 cookie ,这种不适合存放数据较大及安全性要求比较高的场景
- 会话信息保存到三方存储中,如 redis、数据库等,这种要保证三方存储高可用
- 共享网络文件系统,各个服务器设置同一个目录保存会话信息
常见的高可用负载均衡架构
nginx 中负载均衡算法
负载均衡算法就是为了实现其合理的分发
轮询(round-robin)
轮询就是以轮询的方式把请求发送到上游服务器。 nginx 默认的算法就是轮询,配置如下: 配置upstream
upstream backend {
server 10.1.1.2:8080;
server 10.1.1.3:8080;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
server liuyushuai.com;
}
转发用户请求
location / {
proxy_pass http://backend;
}
- 如果命中的 server 出现异常就会使用下一个 server 去处理,直到轮询完仍然没有成功的则会返回最后一个 server 处理的结果。
- 域名配置必只在 nginx 加载配置的时候把域名解析成 ip ,如果域名解析调整 nginx 不会去更新。商业版支持动态更新。
基于权重的轮询
upstream backend {
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weight=2;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
IP hash
upstream backend {
ip_hash;
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
hash key
对某一个 key 进行 哈希 或则一致性哈希。哈希最大的问题当服务器增加或则减少一个时会有大量的被重新分配到不同的机器,而一致性哈希只会有少量的 key 被分配到新的机器上。
hash
根据uri进行hash
upstream backend {
hash $uri;
server 10.1.1.2:8080 weight=2;
server 10.1.1.3:8080;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
一致性哈希
upstream backend {
hash $consistent_key consistent;
server 10.1.1.2:8080 weight=2;
server 10.1.1.3:8080;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
#指定 hash key 的值
location / {
set $consistent_key $request_uri;
#set $consistent_key $arg_uuid;
}
least_conn
最少连接数
upstream backend {
last_conn;
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
least_time
最小平均响应时间
upstream backend {
last_conn;
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2;
server unix:/tmp/backend3;#unix domain socket tcp 可混合使用
}
动态负载均衡
- 配置中心实现(etcd+confd consul+consul-template等+nginx reload)
- openRestry 非 reload
nginx 其他配置
重试
fail_timeout 时间内失败 max_fails 次则摘除,再在 fail_timeout 后加入重试,slow_start 表示当 server 可用后在 slow_start 时间内慢慢恢复 server 的权重。
server backend2.example.com:8080 max_fails=3 fail_timeout=5s slow_start=30s;
健康检查
nginx_upstream_check_module 支持
TCP 检查
upstream backend {
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2;
check interval=3000 rise=1 fail=3 timeout=2000 type=tcp;
}
interval: 检查周期,单位 ms rise: 检查成功几次后标记成功 fail: 检查失败多少次后标记不成功 timeout: 检查请求超时时间
HTTP 检查
upstream backend {
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2;
check interval=3000 rise=1 fail=3 timeout=2000 type=http;
check_http_send "HEAD /hello HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
backup
备用服务器,其他服务器均失败时转发到备用服务器。
upstream backend {
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2 backup;
}
down
标记服务器不可用
upstream backend {
server 10.1.1.2:8080 weight=4;
server 10.1.1.3:8080 weigth=2 down;
}
会话关联
srv_id 是 server 的地址的 MD5 值,如果 server 配置包含 route 参数那么 srv_id 是 route 的值。
upstream backend {
server 10.1.1.2:8080 weight=4; # route = a
server 10.1.1.3:8080 weigth=2; # route = b
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
nginx 四层负载均衡
Nginx 1.9.0 支持四层负载均衡
worker_processes auto;
error_log /var/log/nginx/error.log info;
events {
worker_connections 1024;
}
stream { # 四层负载均衡必须在 stream 下
upstream backend {
hash $remote_addr consistent;
server backend1.example.com:12345 weight=5;
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns {
server 192.168.0.1:53535;
server dns.example.com:53;
}
server {
listen 12345;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass backend;
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}