首页 > 编程语言 >rpc项目中的负载均衡算法

rpc项目中的负载均衡算法

时间:2022-08-30 10:01:05浏览次数:63  
标签:负载 Exception String rpc SERVER 算法 client 地址 节点

一致性hash算法(根据IP一致性hash)

一致性哈希策略的实现方式:我们先把服务列表中的地址进行哈希计算,把计算后的值放到哈希环上,接收到请求后,根据请求的固定属性值来进行哈希计算,然后根据请求的哈希值在哈希环上顺时针寻找服务地址的哈希值,寻找到哪个服务地址的哈希值,就把请求分配给哪个服务。

步骤:

  • 首先获取到节点列表

  • 根据节点列表得到每一个节点的hash值,同时在增加一些虚拟节点,比如原始服务节点上192.168.0.3 那么虚拟节点就是192.168.0.3#1 和192.168.0.3#2 注意所有节点计算hash值都是用string类型的hashcode方法

  • 根据消费者的ip计算出消费者的节点请求的hash值,根据Map.tailMap()方法得到所有有大于 requestHash 的 key,取第一个

虚拟节点主要是解决服务节点hash分布不均匀的问题

/**
* 一致性哈希策略 Demo
*/
public class ConsistentHashingStrategy {
   public static void main(String[] args) {
       // 模拟 Server 地址列表
       String[] serverList = {"192.168.0.15", "192.168.0.30", "192.168.0.45"};
       // 新建 TreeMap 集合 ,以 Key,Value 的方式绑定 Hash 值与地址
       SortedMap<Integer, String> serverHashMap = new TreeMap<>();
       // 计算 Server 地址的 Hash 值
       for (String address : serverList) {
           int serverHash = Math.abs(address.hashCode());
           // 绑定 Hash 值与地址
           serverHashMap.put(serverHash, address);
      }
       // 模拟 Request 地址
       String[] requestList = {"192.168.0.10", "192.168.0.20", "192.168.0.40", "192.168.0.50"};
       // 计算 Request 地址的 Hash 值
       for (String request : requestList) {
           int requestHash = Math.abs(request.hashCode());
           // 在 serverHashMap 中寻找所有大于 requestHash 的 key
           SortedMap<Integer, String> tailMap = serverHashMap.tailMap(requestHash);
           //如果有大于 requestHash 的 key, 第一个 key 就是离 requestHash 最近的 serverHash
           if (!tailMap.isEmpty()) {
               Integer key = tailMap.firstKey();
               // 根据 key 获取 Server address
               String address = serverHashMap.get(key);
               System.out.println("请求 " + request + " 被分配给服务 " + address);
          } else {
               // 如果 serverHashMap 中没有比 requestHash 大的 key
               // 则直接在 serverHashMap 取第一个服务
               Integer key = serverHashMap.firstKey();
               // 根据 key 获取 Server address
               String address = serverHashMap.get(key);
               System.out.println("请求 " + request + " 被分配给服务 " + address);
          }
      }
  }
}

 

 

 

基于最小连接数的负载均衡算法()

 

服务提供者

注册临时节点到zookeeper 的时候增加一个data字段,初始化为0

/**
* 最小连接数策略 Demo
* Server 服务端注册地址
*/
@Component
public class MinimumConnectionsStrategyServer implements ApplicationRunner {

   @Autowired
   private CuratorService curatorService;

   // Curator 客户端
   public CuratorFramework client;
   // 当前服务地址的临时节点
   public static String SERVER_IP;
   // 当前服务地址临时节点的父节点,节点类型为持久节点
   public static final String IMOOC_SERVER = "/imooc-server";

   /**
    * 服务启动后自动执行
    *
    * @param args args
    * @throws Exception Exception
    */
   @Override
   public void run(ApplicationArguments args) throws Exception {
       // Curator 客户端开启会话
       client = curatorService.getCuratorClient();
       client.start();
       // 注册地址信息到 Zookeeper
       registerAddressToZookeeper();
  }

   /**
    * 注册地址信息到 Zookeeper
    * 服务启动时和服务手动上线时调用此方法
    *
    * @throws Exception Exception
    */
   public void registerAddressToZookeeper() throws Exception {
       // 判断父节点是否存在,不存在则创建持久节点
       Stat stat = client.checkExists().forPath(IMOOC_SERVER);
       if (stat == null) {
           client.create().creatingParentsIfNeeded().forPath(IMOOC_SERVER);
      }
       // 获取本机地址
       String address = InetAddress.getLocalHost().getHostAddress();
       // 创建临时节点,节点路径为 /IMOOC_SERVER/address,节点 data 为 请求会话数,初始化时为 0.
       // /imooc-server/192.168.0.77
       SERVER_IP = client.create()
              .withMode(CreateMode.EPHEMERAL)
              .forPath(IMOOC_SERVER + "/" + address, "0".getBytes());
  }

   /**
    * 注销在 Zookeeper 上的注册的地址
    * 服务手动下线时调用此方法
    *
    * @throws Exception Exception
    */
   public void deregistrationAddress() throws Exception {
       // 检查该节点是否存在
       Stat stat = client.checkExists().forPath(SERVER_IP);
       // 存在则删除
       if (stat != null) {
           client.delete().forPath(SERVER_IP);
      }
  }
}

 

消费者

在客户端的请求调用集群服务之前,先使用 Curator 获取 IMOOC_SERVER 下所有的临时节点,并寻找出 data 最小的临时节点,也就是最小连接数的服务。

在客户端发送请求时,我们可以让当前 Server 的请求会话数加 1,并更新到临时节点的 data,完成请求时,我们可以让当前 Server 的请求会话数减 1,并更新到临时节点的 data 。

/**
* 最小连接数策略 Demo
* Client 客户端发送请求
*/
@Component
public class MinimumConnectionsStrategyClient implements ApplicationRunner {

   @Autowired
   private CuratorService curatorService;

   // Curator 客户端
   public CuratorFramework client;
   // 服务列表节点的 父节点
   public static final String IMOOC_SERVER = "/imooc-server";

   @Override
   public void run(ApplicationArguments args) throws Exception {
       // Curator 客户端开启会话
       client = curatorService.getCuratorClient();
       client.start();
  }

   /**
    * 获取最小连接数的服务
    * 发送请求前调用此方法,获取服务地址
    *
    * @return String
    * @throws Exception Exception
    */
   public String getTheMinimumNumberOfConnectionsService() throws Exception {
       // 获取所有子节点
       List<String> list = client.getChildren().forPath(IMOOC_SERVER);
       // 新建 Map
       Map<String, Integer> map = new HashMap<>();
       // 遍历服务列表,保存服务地址与请求会话数的映射关系
       for (String s : list) {
           byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + s);
           int i = Integer.parseInt(new String(bytes));
           map.put(s, i);
      }
       // 寻找 map 中会话数最小的值
       Optional<Map.Entry<String, Integer>> min = map.entrySet().stream().min(Map.Entry.comparingByValue());
       // 不为空的话
       if (min.isPresent()) {
           // 返回 服务地址 ip
           Map.Entry<String, Integer> entry = min.get();
           return entry.getKey();
      } else {
           // 没有则返回服务列表第一个服务地址 ip
           return list.get(0);
      }
  }

   /**
    * 增加该服务的请求会话数量
    * 使用服务地址处理业务前调用此方法
    *
    * @param ip 服务地址
    * @throws Exception Exception
    */
   public void increaseTheNumberOfRequestedSessions(String ip) throws Exception {
       byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + ip);
       int i = Integer.parseInt(new String(bytes));
       i++;
       client.setData().forPath(IMOOC_SERVER + "/" + ip, String.valueOf(i).getBytes());
  }

   /**
    * 减少该服务的请求会话数量
    * 请求结束时调用此方法减少会话数量
    *
    * @param ip 服务地址
    * @throws Exception Exception
    */
   public void reduceTheNumberOfRequestedSessions(String ip) throws Exception {
       byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + ip);
       int i = Integer.parseInt(new String(bytes));
       i--;
       client.setData().forPath(IMOOC_SERVER + "/" + ip, String.valueOf(i).getBytes());
  }
}
 

 

标签:负载,Exception,String,rpc,SERVER,算法,client,地址,节点
From: https://www.cnblogs.com/jjjmk/p/16638268.html

相关文章

  • HCIA学习笔记二十六:手工负载分担模式二层链路聚合
    一、链路聚合的应用场景• 链路聚合一般部署在核心结点,以便提升整个网络的数据吞吐量。二、链路聚合• 链路聚合能够提高链路带宽,增强网络可用性,支持负载分担。三......
  • 机器学习算法在 IRIS 数据集上的可视化与应用
    机器学习算法在IRIS数据集上的可视化与应用五eri集由3种鸢尾花(IrisSetosa、IrisVirginia、IrisVersicolar)组成,每个品种有50个样本,共有150个数据。该数据集......
  • 【Vue面试题】谈谈你对Vue的diff算法的理解
    1diff算法到底是什么?diff算法是一种通过同层的树节点进行比较的高效算法,它可以不用频繁操作DOM,而是选用虚拟DOM节点操作,说人话就是专门用来处理虚拟DOM节点的。2操作......
  • KNP算法
    1.应用场景-字符串匹配问题字符串匹配问题::1)有一个字符串str1=""算算法算法你算算法你算法你算你好"",和一个子串str2="算法你算"2)现在要判断str1是否含有str2,......
  • 算法提高课 第四章 数据结构之并查集
    一、并查集1250.格子游戏思路O(mlog(n))将图中的每个点看作并查集的结点,每个被画的边看作合并相邻的点的操作将图中所有点按行或列优先,从1~n*m进行编号每次进行......
  • 【Perl】常见数据结构与算法
    #二分查找usestrict;subbinary_search{my($target,@v)=@_;my$left=0;my$right=@v-1;while($left<$right){my$mid=......
  • Python3处理grpc接口返回包含中文编码的protobuf数据时的显示问题
    [本文出自天外归云的博客园]当你用python调用grpc接口的时候,返回的protobuf数据中如果含有中文,会显示成编码模式,类似“\345\214\227\344\272\254”,如何显示成中文呢?这里有......
  • 大数据架构和算法实现之路:电商系统的技术实战 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1ed9wiUcGoxfSih5UYls5LQ点击这里获取提取码大数据架构和算法实现之路:电商系统的技术实战介绍了一些主流技术在商业项目中的......
  • JS/TS算法---dp和贪心
    一、动态规划动态规划(dynamicprogramming,DP)是一种将复杂问题分解成更小的子问题来解决的优化技术。注意,动态规划和分而治之是不同的方法。分而治之方法是把问题分解......
  • C++各个版本新增对于算法竞赛有用特性
    C++各个版本新增对于算法有用特性C++11auto与decltype类型推导(摘自程序喵大人)autoauto可以让编译器在编译器就推导出变量的类型,话不多说上代码:autoa=10;//10是in......