欢迎光临
我们一直在努力

负载均衡演示之,如何实现高效稳定的流量分配?

负载均衡演示

负载均衡演示之

总述

在现代分布式系统中,负载均衡是确保系统高效运行的关键技术之一,通过将网络流量或计算任务分配到多个服务器或资源上,负载均衡能够优化资源使用、最大化吞吐量、减少响应时间,并提高系统的可靠性和可用性,本文将以一个“电子商务”应用为例,详细演示从一百个到千万级并发情况下服务端架构的演进过程,并介绍每个阶段遇到的相关技术和问题。

的详细叙述:

一、场景复现

为了更好地演示负载均衡的效果,我们可以模拟一个电子商务应用,其中订单服务需要调用商品服务来获取商品信息,为了实现这一目标,我们需要启动多个商品服务的实例,并通过负载均衡机制将请求分配到不同的实例上。

二、启动多个商品服务实例

我们需要启动多个商品服务(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);        }    }}```

各位小伙伴们,我刚刚为大家分享了有关“负载均衡演示之”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!

赞(0)
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《负载均衡演示之,如何实现高效稳定的流量分配?》
文章链接:https://yuyunkj.com/article/27447.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发