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内部封装了的包可以实现负载均衡
-
追一下源码
最终追入结果,可得对应的实例
-
-
此次更新最终
- 通过注解实现负载均衡 用户自由选择,并实现新的负载均衡方法,随机法🐕
- 实现nacos的注册中心,并使用了nacos的负载均衡
- 通过注解反射实现了用户自由选择注册中心