聊聊六种负载均衡算法

聊聊六种负载均衡算法

负载均衡(Load Balancing)是一种计算机网络和服务器管理技术,旨在分配网络流量、请求或工作负载到多个服务器或资源,以确保这些服务器能够高效、均匀地处理负载,并且能够提供更高的性能、可用性和可扩展性。

这篇文章,我们聊聊六种通用的负载均衡算法。

1 轮询 (Round Robin)轮询是指将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

示例代码:

代码语言:javascript代码运行次数:0运行复制import java.util.List;

import java.util.concurrent.atomic.AtomicInteger;

publicclass RoundRobin {

privatefinal List servers;

privatefinal AtomicInteger index = new AtomicInteger(0);

public RoundRobin(List servers) {

this.servers = servers;

}

public String getServer() {

int currentIndex = index.getAndIncrement() % servers.size();

return servers.get(currentIndex);

}

}

2 粘性轮询 (Sticky Round-Robin)粘性轮询是标准轮询算法的一个变种,它通过记住客户端与服务实例的映射关系,确保来自同一客户端的连续请求会被路由到同一个服务实例上。

它的特点是:

会话保持:一旦客户端首次请求被分配到某个服务实例,后续请求会"粘"在这个实例上客户端识别:通常基于客户端IP、会话ID或特定HTTP头来识别客户端故障转移:当目标服务实例不可用时,系统会重新分配客户端到其他可用实例示例代码:

代码语言:javascript代码运行次数:0运行复制import java.util.List;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.atomic.AtomicInteger;

publicclass StickyRoundRobin {

privatefinal List servers;

privatefinal AtomicInteger index = new AtomicInteger(0);

privatefinal Map clientToServer = new ConcurrentHashMap<>();

public StickyRoundRobin(List servers) {

this.servers = servers;

}

public String getServer(String clientId) {

return clientToServer.computeIfAbsent(clientId,

k -> servers.get(index.getAndIncrement() % servers.size()));

}

}

3 加权轮询 (Weighted Round-Robin)加权轮询是标准轮询算法的增强版本,它允许管理员为每个服务实例分配不同的权重值。权重越高的实例处理越多的请求,从而实现更精细的负载分配。

它的特点是:

权重分配:每个服务实例都有对应的权重值比例分配:请求按权重比例分配到不同实例动态调整:权重可以动态修改以适应不同场景示例代码:

代码语言:javascript代码运行次数:0运行复制private static Map serverMap = new ConcurrentHashMap<>();

//记录服务器权重总和

privatestaticint totalWeight = 0;

public static String weightRandom() {

//获取服务器数量

int serverCount = serverMap.size();

//如果没有可用的服务器返回null

if (serverCount == 0) {

returnnull;

}

//在此处为避免多线程并发操作造成错误,在方法内部进行锁操作

synchronized (serverMap) {

//计算服务器权重总和

for (Map.Entry entry : serverMap.entrySet()) {

totalWeight += entry.getValue();

}

//生成一个随机数

int randomWeight = new Random().nextInt(totalWeight);

//遍历服务器列表,根据服务器权重值选择对应地址

for (Map.Entry entry : serverMap.entrySet()) {

String serverAddress = entry.getKey();

Integer weight = entry.getValue();

randomWeight -= weight;

if (randomWeight < 0) {

return serverAddress;

}

}

}

//默认返回null

returnnull;

}

publicclass WeightRandomLoadBalancer implements LoadBalancer {

private List servers = new ArrayList<>();

private Map weightMap = new HashMap<>();

public WeightRandomLoadBalancer(Map servers) {

this.servers.addAll(servers.keySet());

for (String server : servers.keySet()) {

int weight = servers.get(server);

weightMap.put(server, weight);

}

}

@Override

public String chooseServer() {

int weightSum = weightMap.values().stream().reduce(Integer::sum).orElse(0);

int randomWeight = ThreadLocalRandom.current().nextInt(weightSum) + 1;

for (String server : servers) {

int weight = weightMap.get(server);

if (randomWeight <= weight) {

return server;

}

randomWeight -= weight;

}

returnnull;

}

}

4 源地址哈希法 (Hash)源地址哈希法是一种基于客户端 IP 地址的负载均衡算法,通过哈希函数将客户端IP映射到特定的服务器,确保来自同一IP的请求总是被转发到同一台服务器。

示例代码:

代码语言:javascript代码运行次数:0运行复制import java.util.List;

import java.util.zip.CRC32;

publicclass SourceIPHashLoadBalancer {

privatefinal List servers;

public SourceIPHashLoadBalancer(List servers) {

this.servers = servers;

}

public String getServer(String clientIP) {

if (servers.isEmpty()) {

returnnull;

}

// 计算IP的哈希值

long hash = calculateHash(clientIP);

// 取模确定服务器索引

int index = (int) (hash % servers.size());

return servers.get(Math.abs(index));

}

private long calculateHash(String ip) {

CRC32 crc32 = new CRC32();

crc32.update(ip.getBytes());

return crc32.getValue();

}

}

5 最少连接 (Least Connections)最少连接算法是一种动态负载均衡策略,它会将新请求分配给当前连接数最少的服务器,以实现更均衡的服务器负载分配。

它的特点是:

实时监控:跟踪每台服务器的活跃连接数动态决策:新请求总是分配给当前连接数最少的服务器自适应:自动适应不同请求处理能力的服务器示例代码:

代码语言:javascript代码运行次数:0运行复制import java.util.List;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.atomic.AtomicInteger;

publicclass LeastConnectionsLoadBalancer {

privatefinal List servers;

privatefinal ConcurrentHashMap connectionCounts;

public LeastConnectionsLoadBalancer(List servers) {

this.servers = servers;

this.connectionCounts = new ConcurrentHashMap<>();

servers.forEach(server -> connectionCounts.put(server, new AtomicInteger(0)));

}

public String getServer() {

if (servers.isEmpty()) {

returnnull;

}

// 找出连接数最少的服务器

String selectedServer = servers.get(0);

int minConnections = connectionCounts.get(selectedServer).get();

for (String server : servers) {

int currentConnections = connectionCounts.get(server).get();

if (currentConnections < minConnections) {

minConnections = currentConnections;

selectedServer = server;

}

}

// 增加选中服务器的连接数

connectionCounts.get(selectedServer).incrementAndGet();

return selectedServer;

}

public void releaseConnection(String server) {

connectionCounts.get(server).decrementAndGet();

}

}

6 最快响应时间 (Least Response Time)最快响应时间(Least Response Time,LRT)通过选择当前响应时间最短的服务器来处理新请求,从而优化整体系统性能。

LRT 算法基于以下核心判断标准:

实时性能监控:持续跟踪每台服务器的历史响应时间动态路由决策:新请求总是分配给响应最快的可用服务器自适应学习:根据服务器性能变化自动调整流量分配示例代码:

代码语言:javascript代码运行次数:0运行复制import java.util.*;

import java.util.concurrent.*;

import java.util.concurrent.atomic.*;

publicclass LeastResponseTimeLoadBalancer {

privatefinal List servers;

privatefinal ConcurrentHashMap serverStats;

// 响应时间统计结构

staticclass ResponseTimeStats {

privatefinal AtomicInteger totalRequests = new AtomicInteger(0);

privatefinal AtomicLong totalResponseTime = new AtomicLong(0);

privatevolatileboolean isHealthy = true;

public void recordResponseTime(long responseTimeMs) {

totalRequests.incrementAndGet();

totalResponseTime.addAndGet(responseTimeMs);

}

public double getAverageResponseTime() {

int requests = totalRequests.get();

return requests == 0 ? 0 : (double)totalResponseTime.get() / requests;

}

}

public LeastResponseTimeLoadBalancer(List servers) {

this.servers = new CopyOnWriteArrayList<>(servers);

this.serverStats = new ConcurrentHashMap<>();

servers.forEach(server -> serverStats.put(server, new ResponseTimeStats()));

}

public String getServer() {

if (servers.isEmpty()) returnnull;

return servers.stream()

.filter(server -> serverStats.get(server).isHealthy)

.min(Comparator.comparingDouble(server ->

serverStats.get(server).getAverageResponseTime()))

.orElse(null);

}

public void updateResponseTime(String server, long responseTimeMs) {

ResponseTimeStats stats = serverStats.get(server);

if (stats != null) {

stats.recordResponseTime(responseTimeMs);

}

}

public void markServerDown(String server) {

ResponseTimeStats stats = serverStats.get(server);

if (stats != null) stats.isHealthy = false;

}

public void markServerUp(String server) {

ResponseTimeStats stats = serverStats.get(server);

if (stats != null) stats.isHealthy = true;

}

}

相关推荐

文件同步软件哪个好用?这4款高效工具值得尝试!
365bet的官网是多少

文件同步软件哪个好用?这4款高效工具值得尝试!

📅 10-25 👁️ 1664
剑网3捏脸数据导入方法及捏脸技巧有啥?
365bet娱乐场平台

剑网3捏脸数据导入方法及捏脸技巧有啥?

📅 10-07 👁️ 9929
四大古城——四川阆(làng)中古城
365bet的官网是多少

四大古城——四川阆(làng)中古城

📅 09-01 👁️ 5113
电子协议怎么签?分享8款具有法律效力的在线电子合同平台
全民奇迹觉醒石怎么获得6
365bet的官网是多少

全民奇迹觉醒石怎么获得6

📅 10-26 👁️ 3602
电脑桌组合安装技巧,轻松搞定办公空间布置
365bet娱乐场平台

电脑桌组合安装技巧,轻松搞定办公空间布置

📅 10-28 👁️ 7496