负载均衡算法也是分布式系统中的重要组成部分,用于将来自客户端的请求分配到不同的后端服务器上,以达到提高系统吞吐量、减轻服务器负担、提高系统可用性等目的
1、轮询法
轮询法是最简单、最常见的负载均衡算法之一,其实现思路也非常简单:按照事先规定的顺序依次将请求转发至后端服务器。例如,若有4台服务器,则第1个请求会被分配到第1台服务器上,第2个请求会被分配到第2台服务器上,第3个请求会被分配到第3台服务器上,第4个请求又会被分配到第1台服务器上,以此类推
//定义一个全局计数器,每次调用累加
private static AtomicInteger atomicInteger = new AtomicInteger(0);
//定义服务器列表
private static List<String> serverList = new ArrayList<>();
public static String roundRobin() {
//获取服务器数量
int serverCount = serverList.size();
//获取当前请求应该转发到哪台服务器
int currentServerIndex = atomicInteger.incrementAndGet() % serverCount;
//返回对应的服务器地址
return serverList.get(currentServerIndex);
}
核心就在于根据服务器的数量来进行取模运算
优点:简单高效,易于水平扩展,每个节点满足字面意义上的均衡;
缺点:没有考虑机器的性能问题,根据木桶最短木板理论,集群性能瓶颈更多的会受性能差的服务器影响
2、加权轮询法
加权轮询法是在轮询法的基础上进行改进,其思路是在服务器的选择中,根据服务器的处理能力或负载情况分配不同的权重,以使处理能力较强或负载较轻的服务器获得更多的请求。例如,若存在2台服务器,其中第1台服务器负载比较重,则应当将更多的请求分配给第2台服务器
public class WeightedRoundRobinLoadBalancer {
// 服务器列表及其服务的权重
private static final Map<String, Integer> serverWeights = new HashMap<>();
private static final List<String> servers = new ArrayList<>();
// 计数器
private static final AtomicInteger index = new AtomicInteger(0);
public static String getNextServer() {
int current = index.getAndIncrement();
int serverCount = servers.size();
// 计算权重总和
int totalWeight =serverWeights.values().stream()
.mapToInt(Integer::intValue)
.sum();
int currentIndex = current % totalWeight;
// 遍历服务器列表,根据服务器权重值选择对应地址
for (String server : servers) {
int weight = serverWeights.get(server);
if (currentIndex < weight) {
return server;
}
currentIndex -= weight;
}
// unreachable code
return null;
}
}
优点:可以将不同机器的性能问题纳入到考量范围,集群性能最优最大化;
缺点:生产环境复杂多变,服务器抗压能力也无法精确估算,静态算法导致无法实时动态调整节点权重,只能粗糙优化
3、随机法
随机法是指将请求随机分配至后端服务器的负载均衡算法。该算法实现简单,但分配效果不可控,难以保证后端服务器的负载均衡。因此,随机法通常被用作测试或压力测试等临时场景下的负载均衡算法
//定义服务器列表
private static List<String> serverList = new ArrayList<>();
public static String random() {
//获取服务器数量
int serverCount = serverList.size();
//如果没有可用的服务器返回null
if (serverCount == 0) {
return null;
}
//生成一个随机数
int randomIndex = new Random().nextInt(serverCount);
//返回对应的服务器地址
return serverList.get(randomIndex);
}
优缺点和轮询相似
4、加权随机法
加权随机法是在随机法的基础上进行改进,其思路是在服务器的选择中,根据服务器的处理能力或负载情况分配不同的权重,以使处理能力较强或负载较轻的服务器获得更多的请求
(代码参考加权轮询即可)
5、源地址哈希法
源地址哈希算法就是使用客户端 IP 地址作为哈希键。负载均衡器将哈希值映射到可用服务器中的一个,然后将请求发送到这个服务器处理。如果客户端 IP 地址发生改变(比如重启后重新分配 IP 地址),那么将会被分配到其他服务器上
//定义服务器列表
private static List<String> serverList = new ArrayList<>();
public static String hash(String clientIP) {
//获取服务器数量
int serverCount = serverList.size();
//如果没有可用的服务器返回null
if (serverCount == 0) {
return null;
}
//将客户端IP地址进行哈希计算
int hashCode = clientIP.hashCode();
//根据哈希值计算需要转发到哪台服务器上
int serverIndex = hashCode % serverCount;
//返回对应的服务器地址
return serverList.get(serverIndex);
}
优点:可以避免某些客户端被重定向到不同的服务器,对于同一IP地址的请求,总是会被分配到同一台服务器上,因此可以在一定程度上提高缓存命中率等性能指标,
缺点:如果有很多请求来自相同的 IP 地址,那么可能会导致某个服务器负载过高。另外,由于服务器数量的变化,哈希值映射也会发生变化,这可能会导致缓存无效,并且需要重新分配所有请求