以zookeeper为注册中心实现RPC框架

原理图

这里写图片描述
大致思路:假设服务端是一个由10台机器构成的集群节点,每台机器在启动发布服务时,都会将各自的ip地址及端口号往zookeeper中注册。之后客户端会从zookeeper中拿到所有该服务注册的节点地址,并根据负载均衡算法,选取其中一个服务进行远程调用。

核心代码-服务端

注册中心

/**
 * 1.zookeeper连接
 * 2.注册服务
 */
public class RegisterCenterImpl implements IRegisterCenter {

    private CuratorFramework curatorFramework;


    //连接zookeeper
    {
        curatorFramework= CuratorFrameworkFactory.builder().
                connectString(com.ft.rmi.zk.ZkConfig.CONNECTION_STR).
                sessionTimeoutMs(4000).
                retryPolicy(new ExponentialBackoffRetry(1000,10)).build();
        curatorFramework.start();
    }


    public void register(String serviceName, String serviceAddress) {
        //注册相应的服务
        try {
            //例:servicePath=/registrys/com.ft.rmi.TaofutHelloWorld
            String servicePath= ZkConfig.ZK_REGISTER_PATH + "/" +serviceName;
            //如果节点不存在,则创建
            if(curatorFramework.checkExists().forPath(servicePath)==null){
                curatorFramework.create().creatingParentsIfNeeded().
                        withMode(CreateMode.PERSISTENT).forPath(servicePath,"0".getBytes());
            }
            //例:addressPath=/registrys/com.ft.rmi.TaofutHelloWorld/127.0.0.1:8080
            String addressPath=servicePath+"/"+serviceAddress;
            //创建临时节点:/registrys/com.ft.rmi.TaofutHelloWorld/127.0.0.1:8080
            String rsNode=curatorFramework.create().withMode(CreateMode.EPHEMERAL).
                    forPath(addressPath,"0".getBytes());
            System.out.println("服务注册成功:"+rsNode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

服务发布

/**
 * 用来对外发布一个服务,并且监听客户端发来的请求
 */
public class RpcServer {

    //定义一个线程池
    private static final ExecutorService executorService= Executors.newCachedThreadPool();

    private IRegisterCenter registerCenter;//注册中心
    private String serviceAddress;//服务发布地址

    //存放服务名称和服务对象之间的关系
    Map<String,Object> handlerMap=new HashMap();

    public RpcServer(IRegisterCenter registerCenter, String serviceAddress) {
        this.registerCenter = registerCenter;
        this.serviceAddress = serviceAddress;
    }

    /**
     * 绑定服务名称和服务对象
     * @param services
     */
    public void bind(Object... services){
        for(Object service:services){
            RpcAnnotation annotation=service.getClass().getAnnotation(RpcAnnotation.class);
            //例:serviceName=com.ft.rmi.TaofutHelloWorld
            String serviceName=annotation.value().getName();
            String version=annotation.version();
            if(version!=null&&!version.equals("")){
                serviceName=serviceName+"-"+version;
            }
            //例:com.ft.rmi.TaofutHelloWorld,实例
            handlerMap.put(serviceName,service);//绑定服务接口名称对应的服务
        }
    }

    /**
     * 发布服务
     */
    public void publisher(){
        ServerSocket serverSocket=null;
        try {
            String[] addrs=serviceAddress.split(":");
            serverSocket=new ServerSocket(Integer.parseInt(addrs[1]));//启动一个服务监听

            for(String interfaceName:handlerMap.keySet()){
                registerCenter.register(interfaceName,serviceAddress);
                System.out.println("服务注册成功:"+interfaceName+"->"+serviceAddress);
            }
            while (true){
                Socket socket=serverSocket.accept();
                //开启线程去处理客户端发来的请求
                executorService.execute(new ProcessorHandler(socket,handlerMap));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

处理客户端请求

/**
 * 处理客户端发来的请求
 */
public class ProcessorHandler implements Runnable {

    private Socket socket;
    Map<String,Object> handlerMap;

    public ProcessorHandler(Socket socket, Map<String,Object> handlerMap) {
        this.socket = socket;
        this.handlerMap = handlerMap;
    }

    public void run() {
        //处理socket请求,服务端接收数据,从输入流里读
        ObjectInputStream objectInputStream=null;
        ObjectOutputStream outputStream=null;
        try {
            objectInputStream=new ObjectInputStream(socket.getInputStream());
            RpcRequest rpcRequest=(RpcRequest) objectInputStream.readObject();
            Object result=invoke(rpcRequest);

            //将服务端执行的结果 通过socket回传给客户端
            outputStream=new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(result);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(objectInputStream!=null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 客户端:发来请求告诉服务端,我要调用你这个服务里面的xx方法,并将xx方法的详细信息传递给服务端。
     * 服务端:收到请求及参数后,利用反射去执行了xx方法,并将执行的结果返回给客户端。
     * @param rpcRequest
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
    private Object invoke(RpcRequest rpcRequest) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Object[] args=rpcRequest.getParameters();
        Class<?>[] types=new Class[args.length];
        for(int i=0;i<args.length;i++){
            types[i]=args[i].getClass();
        }
        String serviceName=rpcRequest.getClassName();
        String version=rpcRequest.getVersion();
        if(version!=null&&!version.equals("")){
            serviceName=serviceName+"-"+version;
        }
        //中handlerMap中,根据客户端请求的地址,去拿到响应的服务,通过反射发起调用
        Object service=handlerMap.get(serviceName);
        Method method=service.getClass().getMethod(rpcRequest.getMethodName(),types);
        return method.invoke(service,args);
    }
}
核心代码-客户端

服务发现

/**
 * 1.zookeeper连接
 * 2.服务发现,并且根据负载均衡算法选择一个服务节点
 */
public class ServiceDiscoveryImpl implements IServiceDiscovery {

    private List<String> repos=new ArrayList();
    private CuratorFramework curatorFramework;
    private String address;

    public ServiceDiscoveryImpl(String address) {
        this.address = address;
        curatorFramework= CuratorFrameworkFactory.builder().
                connectString(address).
                sessionTimeoutMs(4000).
                retryPolicy(new ExponentialBackoffRetry(1000,10)).build();
        curatorFramework.start();
    }


    public String discover(String serviceName) {
        String path=ZkConfig.ZK_REGISTER_PATH+"/"+serviceName;
        try{
            repos=curatorFramework.getChildren().forPath(path);
        }catch (Exception e){
            throw new RuntimeException("获取子节点异常:"+e);
        }
        //动态发现服务节点的变化(监听)
        registerWatcher(path);

        //负载均衡机制-随机选择一个服务进行调用
        LoadBalance loadBalance=new RandomLoadBalance();
        return loadBalance.selectHost(repos);
    }

    private void registerWatcher(final String path){
        PathChildrenCache childrenCache=new PathChildrenCache(curatorFramework,path,true);

        PathChildrenCacheListener pathChildrenCacheListener=new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                repos=curatorFramework.getChildren().forPath(path);
            }
        };

        childrenCache.getListenable().addListener(pathChildrenCacheListener);
        try {
            childrenCache.start();
        } catch (Exception e) {
            throw new RuntimeException("注册PathChild Watcher异常:"+e);
        }
    }
}

发起远程调用

/**
 * 传递调用参数,封装RpcRequest
 */
public class RemoteInvocationHandler implements InvocationHandler {

    private IServiceDiscovery serviceDiscovery;
    private String version;

    public RemoteInvocationHandler(IServiceDiscovery serviceDiscovery,String version) {
        this.serviceDiscovery = serviceDiscovery;
        this.version=version;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcRequest rpcRequest=new RpcRequest();
        //例:className=com.ft.rmi.TaofutHelloWorld
        rpcRequest.setClassName(method.getDeclaringClass().getName());
        //例:methodName=sayHello
        rpcRequest.setMethodName(method.getName());
        //例:parameters=我是架构师
        rpcRequest.setParameters(args);
        rpcRequest.setVersion(version);
        //通过接口名称拿到对应的服务地址
        String serviceAddress=serviceDiscovery.discover(rpcRequest.getClassName());
        //传输
        TCPTransport tcpTransport=new TCPTransport(serviceAddress);
        //向服务端发送请求,并且传输 rpcRequest
        return tcpTransport.send(rpcRequest);
    }


}

传输和接收过程

/**
 * Socket编程
 */
public class TCPTransport {
    private String serviceAddress;

    public TCPTransport(String serviceAddress) {
        this.serviceAddress=serviceAddress;
    }

    public Socket newSocket(){
        System.out.println("创建一个新的连接");
        Socket socket=null;
        try {
            //与服务端建立连接
            String[] addrs=serviceAddress.split(":");
            socket=new Socket(addrs[0],Integer.parseInt(addrs[1]));
            return socket;
        } catch (IOException e) {
            throw new RuntimeException("连接建立失败");
        }

    }

    /**
     * 与服务端建立连接,并且向服务端传输 rpcRequest(服务端需要执行的方法详细信息)
     * 收到服务端执行完方法的结果
     * @param rpcRequest
     * @return
     */
    public Object send(RpcRequest rpcRequest){
        Socket socket=null;
        try {
            socket=newSocket();
            ObjectOutputStream outputStream=new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(rpcRequest);//rpcRequest序列化传输
            outputStream.flush();

            ObjectInputStream inputStream=new ObjectInputStream(socket.getInputStream());
            Object result=inputStream.readObject();
            inputStream.close();
            outputStream.close();
            return result;
        } catch (Exception e) {
            throw new RuntimeException("发起远程调用异常",e);
        } finally {
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

源代码地址:https://github.com/taofut/zookeeper_code

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值