目录
 
 
前言
 
- 本篇先介绍负载均衡的概念
 - 其次通过手动来实现负载均衡的算法:轮询、随机、故障转移、权重
 
 
一、负载均衡概念
 
- 1.负载均衡概念 
  
- 负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性
 
  - 2.消费者获取到注册中心多个地址,到底应该选择那个地址呢 
  
- 我们可以简单的设想使用轮询的方式,每个地址轮流使用一次
 - 也可以使用随机的方式来使用地址
 - 这样就能将负载分布到不同的地址也就是不同的服务器中
 
  - 3.负载均衡常用算法 
   
 
 
二、本地负载均衡-轮询算法
 
 
import org.springframework.cloud.client.ServiceInstance;
public interface LoadBalance {
    
    ServiceInstance getInstances(String serviceId);
}
 
- 2.轮询算法实现类RoundLoadBalance
 
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class RoundLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;
    private AtomicInteger atomicCount = new AtomicInteger(0);
    @Override
    public ServiceInstance getInstances(String serviceId) {
        
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        
        if (instances == null || instances.size() == 0) {
            return null;
        }
        
        int index = atomicCount.incrementAndGet() % instances.size();
        return instances.get(index);
    }
}
 
 
import com.sjyl.loadbalance.RoundLoadBalance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class OrderToMemberService {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RoundLoadBalance roundLoadBalance;
    @RequestMapping("/orderToMember")
    public String orderToMember() {
        
        ServiceInstance serviceInstance = roundLoadBalance.getInstances("sjyl-producer-member");
        
        String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
        return "订单服务调用会员服务:" + restTemplate.getForObject(memberUrl, String.class) + "...端口:" + serviceInstance.getPort();
    }
}
 
- 4.访问测试地址 
  
- 地址:http://127.0.0.1:8070/orderToMember
 - 可以看到每次访问端口都会在8080和8081之间轮询切换
 
  
 

 
三、本地负载均衡-随机算法
 
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;
@Component
public class RandomLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Override
    public ServiceInstance getInstances(String serviceId) {
        
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        
        if (instances == null || instances.size() == 0) {
            return null;
        }
        
        Random random = new Random();
        
        int index = random.nextInt(instances.size());
        return instances.get(index);
    }
}
 
 
import com.sjyl.loadbalance.RandomLoadBalance;
import com.sjyl.loadbalance.RoundLoadBalance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class OrderToMemberService {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RoundLoadBalance roundLoadBalance;
    @Autowired
    private RandomLoadBalance randomLoadBalance;
    @RequestMapping("/orderToMember")
    public String orderToMember() {
        
        ServiceInstance serviceInstance = randomLoadBalance.getInstances("sjyl-producer-member");
        
        String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
        return "订单服务调用会员服务:" + restTemplate.getForObject(memberUrl, String.class) + "...端口:" + serviceInstance.getPort();
    }
}
 
- 3.访问测试 
  
- 地址:http://127.0.0.1:8070/orderToMember
 - 随机在8080和8081端口
 
  
 
四、本地负载均衡-故障转移算法
 
- 1.思考 
  
- 假设消费者在拿到一个宕机地址后,RPC远程会产生什么问题?有什么解决方案?
 
  - 2.解决方案 
  
- 故障转移:遍历获取集群的地址,如果宕机就捕获异常,遍历下一个集群地址
 
  - 3.OrderToMemberService
 
 
    @RequestMapping("/orderToMember")
    public String orderToMember() {
        
        List<ServiceInstance> instances = discoveryClient.getInstances("sjyl-producer-member");
        for (ServiceInstance instance : instances) {
            try {
                String memberUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/" + "getMember";
                return "订单服务调用会员服务:" + restTemplate.getForObject(memberUrl, String.class);
            } catch (RestClientException e) {
                System.out.println("[rpc远程调用发生了故障 开始故障转移 切换下一个地址调用 ]" + e);
            }
        }
        return "fail";
    }
 
五、本地负载均衡-权重算法
 
- 1.权重算法的核心思想 
  
- 假设集群有2个ip和端口:127.0.0.1:8080、127.0.0.1:8081 
    
- 权重为1:1时设计数组:[127.0.0.1:8080,127.0.0.1:8081] 
      
- 第1次访问:index=1%1,第2次访问:index=2%1,第3次访问:index=3%1,第4次访问:index=4%1。。。省略
 
  - 权重为2:1时设计数组:[127.0.0.1:8080,127.0.0.1:8080,127.0.0.1:8081] 
      
- 第1次访问:index=1%2,第2次访问:index=2%2,第3次访问:index=3%2,第4次访问:index=4%2。。。省略
 
  - 权重为3:1时设计数组:[127.0.0.1:8080,127.0.0.1:8080,127.0.0.1:8080,127.0.0.1:8081] 
      
- 第1次访问:index=1%3,第2次访问:index=2%3,第3次访问:index=3%3,第4次访问:index=4%3。。。省略
 
  
  - 通过不同权重设计以上的数组,然后通过取余的算法,来确定本次需要使用的集群中的IP和端口的数组索引
 
  - 2.获取nacos的权重比例 
  
- nacos是支持权重比例配置的,通过编辑即可进行修改
 
  
 

 
 

 
- 4.创建权重算法实现类WeightLoadBalance
 
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class WeightLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;
    private AtomicInteger countAtomicInteger = new AtomicInteger(-1);
    @Override
    public ServiceInstance getInstances(String serviceId) {
        
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        if (instances == null) {
            return null;
        }
        ArrayList<ServiceInstance> newInstances = new ArrayList<>();
        instances.forEach((service -> {
            
            Double weight = Double.parseDouble(service.getMetadata().get("nacos.weight"));
            for (int i = 0; i < weight; ++i) {
                newInstances.add(service);
            }
        }));
        return newInstances.get(countAtomicInteger.incrementAndGet() % newInstances.size());
    }
}
 
- 5.设置nacos的8080权重为2,8081的权重为1 
  
- 测试地址:http://127.0.0.1:8070/orderToMember
 
  
 

 
