手写RPC框架(七)

v1.5

更新事项 尝试将注册中心换成nacos 将负载均衡策略提取出来 同时新创建随机均衡策略,这是供如果是zk为注册中心使用的,倘若是nacos为注册中心的话用 nacos的工具类中自带负载均衡

  • 提取负载均衡策略 新增随机策略

    • 新建接口 接口的作用定义方法

      package loadbalance;
      
      
      import annotation.LoadBalanceMethodImpl;
      import org.apache.zookeeper.KeeperException;
      import org.apache.zookeeper.ZooKeeper;
      
      //实现不同的负载均衡策略
      @LoadBalanceMethodImpl(chosenMethod = AccessBalance.class)
      public interface LoadBalance {
          //通过负载均衡策略返回相应地址
          String loadBalance(ZooKeeper zooKeeper, String path) throws InterruptedException, KeeperException;
      }
      
    • 新建注解 定义在接口之上用来判断此时应该使用哪个实现类

      package annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      //注解的参数直接是要传入什么类
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface LoadBalanceMethodImpl {
          Class chosenMethod();
      }
      
    • 根据反射获取对应的负载方法,通过传递信息,实现方法调用获得经过负载均衡后得到的地址。

      //v1.5修改使用负载均衡策略 根据接口上注解选择的实现类进行调用
              LoadBalanceMethodImpl annotation = LoadBalance.class.getAnnotation(LoadBalanceMethodImpl.class);
              Class methodClass = annotation.chosenMethod();
              Method method = methodClass.getMethod("loadBalance", new Class[]{ZooKeeper.class, String.class});
              //被选中的负载均衡实现类的对象  通过反射执行  获取对应的地址
              Object methodChosenClass = methodClass.newInstance();
              String address = (String) method.invoke(methodChosenClass,zooKeeper,prePath);
      
              return address;
      
    • 写一个随机访问负载均衡方法

      package loadbalance;
      
      import org.apache.zookeeper.KeeperException;
      import org.apache.zookeeper.ZooKeeper;
      
      import java.nio.charset.StandardCharsets;
      import java.util.List;
      import java.util.Random;
      
      public class RandomBalance implements LoadBalance{
          @Override
          public String loadBalance(ZooKeeper zooKeeper, String path) throws InterruptedException, KeeperException {
              List<String> children = zooKeeper.getChildren(path, null,null);
              if (children.isEmpty())
              {
                  System.out.println("当前没有服务器提供该服务 请联系工作人员");
              }
              int size = children.size();
              Random random = new Random();
              //这是应该处于0——size-1之间
              int randomIndex = random.nextInt(size);
              String chooseNode = children.get(randomIndex);
              byte[] data = zooKeeper.getData(path + "/" + chooseNode, null, null);
              int visitedCount = Integer.valueOf(new String(data));
              ++visitedCount;
              zooKeeper.setData(path+"/"+ chooseNode, String.valueOf(visitedCount).getBytes(StandardCharsets.UTF_8),-1);
              return chooseNode;
          }
      }
      
  • 问题

    • Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
      
      

      努力寻找中,从昨天排查到现在 就是一个bug 我把我zookeeper中的test删除 就成功了

  • 尝试使用新的注册中心nacos
    安装步骤见技术选型的注册中心那里

    服务注册和服务发现模仿给的示例代码

    public class App {
        public static void main(String[] args) throws NacosException {
          Properties properties = new Properties();
            properties.setProperty("serverAddr", "21.34.53.5:8848,21.34.53.6:8848");
          properties.setProperty("namespace", "quickStart");
            NamingService naming = NamingFactory.createNamingService(properties);
            naming.registerInstance("nacos.test.3", "11.11.11.11", 8888, "TEST1");
            naming.registerInstance("nacos.test.3", "2.2.2.2", 9999, "DEFAULT");
          System.out.println(naming.getAllInstances("nacos.test.3"));
        }
    
    • 将服务端的服务注册进nacos

    • 设置nacos连接地址常数

        //Nacos服务器连接地址  后面的服务名和地址再拼接
            public static String NACOS_ADDRESS = "http://192.168.18.128:8848/nacos/v1/ns/instance?";
      
      • 因为要向远端发送注册服务命令 所以用到了HttpClient或者nacos封装的命令功能
        官方给的请求方式

        curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
        
      • nacos服务注册

        package provider.nacosService;
        
        import com.alibaba.nacos.api.NacosFactory;
        import com.alibaba.nacos.api.exception.NacosException;
        import com.alibaba.nacos.api.naming.NamingService;
        import constants.RpcConstants;
        
        import java.util.Properties;
        
        public class NacosServiceRegistry {
            //直接进行注册
            public static void register(String RpcServiceName,String hostname,int port) throws NacosException {
                Properties properties = RpcConstants.propertiesInit();
              //创建namingService
                NamingService namingService = NacosFactory.createNamingService(properties);
              //进行注册
                namingService.registerInstance(RpcServiceName, hostname, port, "DEFAULT");
              System.out.println("服务端:"+hostname+":"+port+":"+RpcServiceName+"方法在nacos中注册完毕");
            }
        }
        
      • 非阻塞服务器端修改

        //将服务注册进Nacos中  进行改造
                NacosServiceRegistry.register(method,"127.0.0.1",port);
      
  • 通过nacos获取对应的服务

    • 因为要向远端获取服务 所以用到了HttpClient功能
      官方给的请求方式 我们进行改造

      curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
      
      • nacos服务发现

        package consumer.servicediscovery;
        
        import com.alibaba.nacos.api.NacosFactory;
        import com.alibaba.nacos.api.exception.NacosException;
        import com.alibaba.nacos.api.naming.NamingService;
        import com.alibaba.nacos.api.naming.pojo.Instance;
        import constants.RpcConstants;
        import consumer.nio.NIONonBlockingClient12;
        import exception.RpcException;
        import org.apache.zookeeper.KeeperException;
        
        import java.io.IOException;
        import java.lang.reflect.InvocationTargetException;
        import java.util.List;
        import java.util.Properties;
        
        public class NacosServiceDiscovery {
            public static String getMethodAddress(String methodName) throws NacosException, RpcException {
                Properties properties = RpcConstants.propertiesInit();
                NamingService namingService = NacosFactory.createNamingService(properties);
        
                //这个方法内部实现了负载均衡
              Instance instance = namingService.selectOneHealthyInstance(methodName);
                if (instance==null)
              {
                    System.out.println("没有提供该方法");
                    throw new RpcException("没有对应的方法");
              }
                String ip = instance.getIp();
                int port = instance.getPort();
                String methodAddress = ip+":"+port;
              return methodAddress;
            }
        
            public static String getStart(String methodName,String msg) throws IOException, RpcException,NacosException {
                //获取相应的远端地址
                String methodAddress = getMethodAddress(methodName);
                //进行连接
                String[] strings = methodAddress.split(":");
                //启动
                String address = strings[0];
                int port = Integer.valueOf(strings[1]);
                return NIONonBlockingClient12.start(address,port,msg);
            }
        }
        
        
      • 非阻塞客户端改造 和之前一样 就不copy代码出来了

  • 通过注解的形式,供客户选择的方式选择注册中心使用

    • 截一个服务提供端的注解方式 客户消费端同理

      • 自定义注解

        package annotation;
        
        import java.lang.annotation.ElementType;
        import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
        import java.lang.annotation.Target;
        
        //注册中心选择  默认采用zookeeper
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface RegistryChosen {
            String registryName() default "zookeeper";
        }
        
      • 创建一个接口在上面注解 所用启动类都需要实现该接口

        package provider.bootstrap.nio;
        
        import annotation.RegistryChosen;
        
        //注册中心的选择 启用的是nacos 目前
        @RegistryChosen(registryName = "zookeeper")
        public interface NIOProviderBootStrap {
        }
        
      • 创建了一个工具类进行判断并实现往哪个注册中心注册

        package provider.utils;
        
        import annotation.RegistryChosen;
        import com.alibaba.nacos.api.exception.NacosException;
        import exception.RpcException;
        import org.apache.zookeeper.KeeperException;
        import provider.bootstrap.nio.NIOProviderBootStrap;
        import provider.serviceregistry.NacosServiceRegistry;
        import provider.serviceregistry.ZkServiceRegistry;
        
        import java.io.IOException;
        
        //直接实现启动类根据启动类接口上的注解选择对应需要选取的方法
        public class MethodRegister implements NIOProviderBootStrap {
            /**
             * 实际进行注册的方法
             * @param method 方法名字
             * @param ip  对应的ip
             * @param port    对应的port
             */
            public static void register(String method, String ip, int port) throws NacosException, RpcException, IOException, InterruptedException, KeeperException {
        
                RegistryChosen annotation = MethodRegister.class.getInterfaces()[0].getAnnotation(RegistryChosen.class);
        
                switch (annotation.registryName())
                {
                    case "nacos":
                        NacosServiceRegistry.registerMethod(method,ip, port);
                        break;
                    case "zookeeper":
                        ZkServiceRegistry.registerMethod(method,ip,port);
                        break;
                    default:
                        throw new RpcException("不存在该注册中心");
                }
            }
        }
        
        
  • 负载均衡策略 这块就用自己实现负载均衡策略了 nacos内部封装了的包可以实现负载均衡

    • 追一下源码

      在这里插入图片描述

      在这里插入图片描述

      最终追入结果,可得对应的实例

  • 此次更新最终

    1. 通过注解实现负载均衡 用户自由选择,并实现新的负载均衡方法,随机法🐕
    2. 实现nacos的注册中心,并使用了nacos的负载均衡
    3. 通过注解反射实现了用户自由选择注册中心
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值