1.前言
最近参加一个笔试的面试,题目很简单,就是简述负载均衡的原理,以及你用过的哪些中间件实现了负载均衡,怎么实现的,以及对应的负载策略,题目看似简单,其实不然,如果你是一个高级或者资深java研发的话,并不应该止于表面,一个合格的高级java研发,一定是一个业务的多面手,一定可以结合实际业务给出合适的解决方案;
2.负载均衡的由来
在业务初期,我们一般会先使用单台服务器对外提供服务。随着业务流量越来越大,单台服务器无论如何优化,无论采用多好的硬件,总会有性能天花板,当单服务器的性能无法满足业务需求时,就需要把多台服务器组成集群系统提高整体的处理性能;
基于上述需求,我们要使用统一的流量入口来对外提供服务,本质上就是需要一个流量调度器,通过均衡的算法,将用户大量的请求流量均衡地分发到集群中不同的服务器上
使用负载均衡可以给我们带来的几个好处:
1.提高了系统的整体性能;
2.提高了系统的扩展性;
3.提高了系统的可用性;
3.负载均衡的类型
广义上的负载均衡器大概可以分为 3 类,包括:DNS 方式实现负载均衡、硬件负载均衡、软件负载均衡。
4. DNS实现负载均衡
DNS 实现负载均衡是最基础简单的方式。一个域名通过 DNS 解析到多个 IP,每个 IP 对应不同的服务器实例,这样就完成了流量的调度,虽然没有使用常规的负载均衡器,但实现了简单的负载均衡功能
通过 DNS 实现负载均衡的方式,最大的优点就是实现简单,成本低,无需自己开发或维护负载均衡设备,不过存在一些缺点:
- 服务器故障切换延迟大,服务器升级不方便。(例如:业务服务故障,DNS修改或者摘除故障服务器,需要经过运营商的DNS缓存,时效性会很慢)
- 流量调度不均衡,粒度太粗(地区运营商不可能只服务你一家,背后服务了多少用户,也会造成流量调度的不均匀)
- 流量分配策略太简单,支持的算法太少。(DNS一般只支持轮询的方式,流量分配策略比较简单,不支持权重、Hash调度等算法)
- DNS 支持的 IP 列表有限制(比如阿里的DNS 系统针对同一个域名支持配置 10 个不同的 IP 地址)
备注:实际上生产环境中很少使用这种方式来实现负载均衡,毕竟缺点很明显。文中之所以描述 DNS 负载均衡方式,是为了能够更清楚地解释负载均衡的概念;
但是像 BAT 体量的公司一般会利用 DNS 来实现地理级别的全局负载均衡,实现就近访问,提高访问速度,这种方式一般是入口流量的基础负载均衡,下层会有更专业的负载均衡设备实现的负载架构
5.硬件负载均衡
硬件负载均衡是通过专门的硬件设备来实现负载均衡功能,是专用的负载均衡设备。目前业界典型的硬件负载均衡设备有两款:F5 和 A10
这类设备性能强劲、功能强大,但价格非常昂贵,一般只有土豪公司才会使用此类设备,中小公司一般负担不起,业务量没那么大,用这些设备也是挺浪费的。
硬件负载均衡的优点:
- 功能强大:全面支持各层级的负载均衡,支持全面的负载均衡算法。
- 性能强大:性能远超常见的软件负载均衡器。
- 稳定性高:商用硬件负载均衡,经过了良好的严格测试,经过大规模使用,稳定性高。
- 安全防护:还具备防火墙、防 DDoS 攻击等安全功能,以及支持 SNAT 功能。
SNAT(源地址转换):是源地址转换,其作用是将ip数据包的源地址转换成另外一个地址
硬件负载均衡的缺点也很明显:
价格贵;
扩展性差,无法进行扩展和定制;
调试和维护比较麻烦,需要专业人员;
6.软件负载均衡(重点)
软件负载均衡,可以在普通的服务器上运行负载均衡软件,实现负载均衡功能。目前常见的有 Nginx、HAproxy、LVS。
下面只介绍Nginx,原因是国内公司使用最多,其他只做了解即可;
nginx应用场景之一就是负载均衡。在访问量较多的时候,可以通过负载均衡,将多个请求分摊到多台服务器上,相当于把一台服务器需要承担的负载量交给多台服务器处理,进而提高系统的吞吐率;另外如果其中某一台服务器挂掉,其他服务器还可以正常提供服务,以此来提高系统的可伸缩性与可靠性
6.1 nginx负载均衡
6.1 Nginx负载均衡策略
以下截图为nginx官网文档
nginx内置负载均衡策略主要分为三大类,分别是轮询、最少连接和ip hash
1.轮询:以循环方式分发对应用服务器的请求,将请求平均分发到每台服务器上。
1.1轮询实现方案
1.1.1普通轮询方式
该方式是默认方式,轮询适合服务器配置相当,无状态且短平快的服务使用。另外在轮询中,如果服务器挂掉,会自动剔除该服务器。
http {
# 定义转发分配规则
upstream myapp1 {
server srv1.com; # 要转发到的服务器,如ip、ip:端口号、域名、域名:端口号
server srv2.com:8088;
server 192.168.0.100:8088;
}
server {
listen 80; # nginx监听的端口
location / {
# 使用myapp1分配规则,即刚自定义添加的upstream节点
# 将所有请求转发到myapp1服务器组中配置的某一台服务器上
proxy_pass http://myapp1;
}
}
}
1.1.2权重轮询方式
如果在 upstream 中配置的server参数后追加 weight 配置,则会根据配置的权重进行请求分发。此策略可以与least_conn和ip_hash结合使用,适合服务器的硬件配置差别比较大的情况。
# 定义转发分配规则
upstream myapp1 {
server srv1.com weight=1; # 该台服务器接受1/6的请求量
server srv2.com:8088 weight=2; # 该台服务器接受2/6的请求量
server 192.168.0.100:8088 weight=3; # 该台服务器接受3/6的请求量;
}
2.最少连接
轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果,适合请求处理时间长短不一造成服务器过载的情况。
# 定义转发分配规则
upstream myapp1 {
least_conn; # 把请求分派给连接数最少的服务器
server srv1.com;
server srv2.com:8088;
server 192.168.0.100:8088;
}
3.ip hash (有针对的场景:)
这个方法确保了相同的客户端请求一直发送到相同的服务器,这样每个访客都固定访问一个后端服务器。如用户需要分片上传文件到服务器下,然后再由服务器将分片合并,这时如果用户的请求到达了不同的服务器,那么分片将存储于不同的服务器目录中,导致无法将分片合并,该场景则需要使用ip hash策略。
备注:需要注意的是,ip_hash不能与backup同时使用,另外当有服务器需要剔除,必须手动down掉,此模式适合有状态服务,比如session
# 定义转发分配规则
upstream myapp1 {
ip_hash; # #保证每个请求固定访问一个后端服务器
server srv1.com;
server srv2.com:8088;
server 192.168.0.100:8088;
}
参考链接:https://blog.csdn.net/guo_ridgepole/article/details/124517113