负载均衡演示

总述
在现代分布式系统中,负载均衡是确保系统高效运行的关键技术之一,通过将网络流量或计算任务分配到多个服务器或资源上,负载均衡能够优化资源使用、最大化吞吐量、减少响应时间,并提高系统的可靠性和可用性,本文将以一个“电子商务”应用为例,详细演示从一百个到千万级并发情况下服务端架构的演进过程,并介绍每个阶段遇到的相关技术和问题。
的详细叙述:
一、场景复现
为了更好地演示负载均衡的效果,我们可以模拟一个电子商务应用,其中订单服务需要调用商品服务来获取商品信息,为了实现这一目标,我们需要启动多个商品服务的实例,并通过负载均衡机制将请求分配到不同的实例上。
二、启动多个商品服务实例
我们需要启动多个商品服务(product-service)的实例,可以通过修改配置文件和端口号来实现这一点,假设我们启动了三个商品服务实例,分别监听不同的端口号。
启动第一个商品服务实例 java -jar product-service.jar --server.port=8081 启动第二个商品服务实例 java -jar product-service.jar --server.port=8082 启动第三个商品服务实例 java -jar product-service.jar --server.port=8083
启动后,我们可以观察到Eureka服务发现中有三个商品服务实例。
三、访问订单服务

我们访问订单服务,该服务会远程调用商品服务来获取商品信息,在初始情况下,所有的请求都会被路由到同一台机器上,这并不是我们期望的结果,我们希望请求能够均匀地分配到不同的商品服务实例上。
四、修改远程调用逻辑
为了实现负载均衡,我们需要修改订单服务中的远程调用逻辑,我们需要从Eureka服务发现中获取所有可用的商品服务实例,并根据某种算法选择一个实例进行调用,这里我们采用轮询算法作为示例。
代码示例:
package com.guan.order.service;
import com.guan.order.mapper.OrderMapper;
import com.guan.order.model.OrderInfo;
import com.guan.product.model.ProductInfo;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Service
@Slf4j
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Resource
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
private static AtomicInteger atomicInteger = new AtomicInteger(1);
private static List<ServiceInstance> instances;
@PostConstruct
public void init() {
// 根据应用名称获取服务列表
instances = discoveryClient.getInstances("product-service");
}
public OrderInfo selectOrderByID(Integer orderID) {
OrderInfo orderInfo = orderMapper.selectOrderById(orderID);
// 从Eureka获取服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
// 有多个服务,根据轮询获取
int index = atomicInteger.getAndIncrement() % instances.size();
String uri = instances.get(index).getUri().toString();
String url = uri + "/product/" + orderInfo.getProductId();
log.info("远程调用url:{}", url);
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
通过上述代码,我们实现了一个简单的轮询负载均衡机制,每次远程调用时,都会根据atomicInteger的值选择一个商品服务实例进行调用,从而实现请求的均匀分配。
五、负载均衡算法详解及Java代码演示
负载均衡算法可以分为静态负载均衡和动态负载均衡两大类,以及基于权重和基于性能的负载均衡,下面将详细介绍几种常见的负载均衡算法及其Java代码实现。
1. 轮询(Round Robin)
轮询算法是最简单的一种静态负载均衡算法,它按照顺序依次将请求分配给每个服务器,当到达列表末尾时,重新回到列表开头继续分配。

Java代码实现:
import java.util.ArrayList;
import java.util.List;
public class RoundRobinLoadBalancer {
private List<String> servers;
private int currentIndex;
public RoundRobinLoadBalancer(List<String> servers) {
this.servers = servers;
currentIndex = 0;
}
public String getNextServer() {
String server = servers.get(currentIndex);
currentIndex = (currentIndex + 1) % servers.size();
return server;
}
public static void main(String[] args) {
List<String> servers = new ArrayList<>();
servers.add("Server1");
servers.add("Server2");
servers.add("Server3");
RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(servers);
for (int i = 0; i < 10; i++) {
String server = loadBalancer.getNextServer();
System.out.println("Request " + i + " routed to " + server);
}
}
}
2. 随机(Random)
随机算法也是一种静态负载均衡算法,它随机选择一个服务器来处理请求,虽然简单,但在某些情况下可能会导致负载不均。
Java代码实现:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RandomLoadBalancer {
private List<String> servers;
private Random random;
public RandomLoadBalancer(List<String> servers) {
this.servers = servers;
random = new Random();
}
public String getRandomServer() {
int index = random.nextInt(servers.size());
return servers.get(index);
}
public static void main(String[] args) {
List<String> servers = new ArrayList<>();
servers.add("Server1");
servers.add("Server2");
servers.add("Server3");
RandomLoadBalancer loadBalancer = new RandomLoadBalancer(servers);
for (int i = 0; i < 10; i++) {
String server = loadBalancer.getRandomServer();
System.out.println("Request " + i + " routed to " + server);
}
}
}
3. 最小连接数(Least Connections)
最小连接数是一种动态负载均衡算法,它总是选择当前活动连接数最少的服务器来处理新的请求,这需要实时监控每个服务器的连接数。
Java代码实现:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class LeastConnectionsLoadBalancer {
private Map<String, AtomicInteger> serverConnections;
public LeastConnectionsLoadBalancer(List<String> servers) {
serverConnections = new HashMap<>();
for (String server : servers) {
serverConnections.put(server, new AtomicInteger(0));
}
}
public String getLeastConnectionsServer() {
String selectedServer = null;
int minConnections = Integer.MAX_VALUE;
for (Map.Entry<String, AtomicInteger> entry : serverConnections.entrySet()) {
int currentConnections = entry.getValue().get();
if (currentConnections < minConnections) {
minConnections = currentConnections;
selectedServer = entry.getKey();
}
}
serverConnections.get(selectedServer).incrementAndGet(); // 增加选中服务器的连接数
return selectedServer;
}
public void releaseServer(String server) {
serverConnections.get(server).decrementAndGet(); // 释放服务器连接数
}
public static void main(String[] args) {
List<String> servers = new ArrayList<>();
servers.add("Server1");
servers.add("Server2");
servers.add("Server3");
LeastConnectionsLoadBalancer loadBalancer = new LeastConnectionsLoadBalancer(servers);
for (int i = 0; i < 10; i++) {
String server = loadBalancer.getLeastConnectionsServer();
System.out.println("Request " + i + " routed to " + server);
// 模拟请求完成后释放连接
loadBalancer.releaseServer(server);
}
}
}
4. 最短响应时间(Least Response Time)
最短响应时间算法也是一种动态负载均衡算法,它选择当前响应时间最短的服务器来处理新的请求,这同样需要实时监控每个服务器的响应时间。
Java代码实现:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
public class LeastResponseTimeLoadBalancer {
private Map<String, AtomicLong> responseTimes;
private Map<String, AtomicInteger requestCounts;
private Map<String, Long lastResponseTimes;
private long startTime;
public LeastResponseTimeLoadBalancer() {
responseTimes = new ConcurrentHashMap<>();
requestCounts = new ConcurrentHashMap<>();
lastResponseTimes = new ConcurrentHashMap<>();
startTime = System.currentTimeMillis();
}
public void recordResponseTime(String server, long responseTime) {
responseTimes.computeIfAbsent(server, k -> new AtomicLong(0)).addAndGet(responseTime);
requestCounts.computeIfAbsent(server, k -> new AtomicInteger(0)).incrementAndGet();
lastResponseTimes.put(server, responseTime);
}
public String getLeastResponseTimeServer() {
long currentTime = System.currentTimeMillis();
return requestCounts.entrySet().stream()
.min((e1, e2) -> {
long avgTime1 = lastResponseTimes.get(e1.getKey()) / e1.getValue().get();
long avgTime2 = lastResponseTimes.get(e2.getKey()) / e2.getValue().get();
return Long.compare(avgTime1, avgTime2);
})
.map(Map.Entry::getKey)
.orElse(null);
}
public static void main(String[] args) {
List<String> servers = new ArrayList<>();
servers.add("Server1");
servers.add("Server2");
servers.add("Server3");
LeastResponseTimeLoadBalancer loadBalancer = new LeastResponseTimeLoadBalancer();
for (int i = 0; i < 10; i++) {
String server = loadBalancer.getLeastResponseTimeServer();
System.out.println("Request " + i + " routed to " + server);
// 模拟请求完成后记录响应时间(假设为100ms)
loadBalancer.recordResponseTime(server, 100);
}
}
}
5. 基于权重的负载均衡(Weighted Load Balancing)
基于权重的负载均衡算法允许为不同的服务器分配不同的权重,从而更灵活地控制负载分配,性能较好的服务器可以分配更高的权重。
Java代码实现:
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
import java.util.function.Function;import java.util.*;import java.util.concurrent.*;import java.util.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import java.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk.*;import jdk;;public class WeightedLoadBalancer { private Map<String, Integer> weights; public WeightedLoadBalancer(Map<String, Integer> weights) { this.weights = weights; } public String getWeightedServer() { // 将所有服务器按权重比例放入列表中 List<String> weightedList = new ArrayList<>(); for (Map.Entry<String, Integer> entry : weights.entrySet()) { for (int i = 0; i < entry.getValue(); i++) { weightedList.add(entry.getKey()); } Collections.shuffle(weightedList); return weightedList.isEmpty() ? null : weightedList.remove(0); }} public static void main(String[] args) { Map<String, Integer> weights = new HashMap<>(); weights.put("Server1", 1); weights.put("Server2", 3); weights.put("Server3", 5); WeightedLoadBalancer loadBalancer = new WeightedLoadBalancer(weights); for (int i = 0; i < 10; i++) { String server = loadBalancer.getWeightedServer(); System.out.println("Request " + i + " routed to " + server); } }}```
各位小伙伴们,我刚刚为大家分享了有关“负载均衡演示之”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!














