ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从头开始写一个简单RPC——第1天

2021-03-31 11:01:45  阅读:183  来源: 互联网

标签:从头开始 address public RPC Channel 简单 new 远程 channel


gitee地址

项目基于guide-rpc-framwork 拆解,完整框架请参考guide-rpc-framwork

上篇地址:day0

本篇主要内容:

  • 解决Channel 复用问题
  • 使用kryo 序列化替代JDK 自身的序列化
  • 优化远程服务实现方法

先简单介绍下最开始这个RPC的使用方式:

服务端发布服务:

public class HelloServerTest {
    public static void main(String[] args) throws Exception {
        ServiceProvider.publishService("HelloService", new HelloService());
        NettyRpcServer server = new NettyRpcServer();
        server.start();
    }
}

客户端调用服务:

public class ClientTest {
    public static void main(String[] args) {
    	// HelloService.hello 表示要调用HelloService 这个实例的hello 方法
        Object hello = ServiceConsumer.invoke("HelloService.hello", "miemie");
        System.out.println(hello);
    }
}

先基于这种最简单的实现方式,通过手动填写远程服务名,来发布和调用远程服务,后续会进行改造,模拟dubbo 实现方式,基于注解自动发布和调用服务。

解决Channel 复用问题:

在day0 获取channel 的实现方式是这样的:

private Channel getChannel(InetSocketAddress address) {
        CompletableFuture<Channel> completableFuture = new CompletableFuture<>();
        bootstrap.connect(address).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                log.info("The client has connected [{}] successful!", address.toString());
                completableFuture.complete(future.channel());
            } else {
                throw new IllegalStateException();
            }
        });
        return completableFuture.get();
    }

这样的实现方式,每调用一次远程服务,都要创建一个channel,严重损耗消费者和生产者的资源。
基于Netty的实现,我们在整个消费者的生命周期中,对于每一个生产者,我们可以保持一个Channel 即可。

//获取Channel,先去容器中判断Channel 存不存在,不存在再建立连接
private Channel getChannel(InetSocketAddress address) {
        Channel channel = channelProvider.get(address);
        if(channel == null) {
            synchronized (this) {
                channel = channelProvider.get(address);
                if(channel == null) {
                    //do connect
                    CompletableFuture<Channel> completableFuture = new CompletableFuture<>();
                    bootstrap.connect(address).addListener((ChannelFutureListener) future -> {
                        if (future.isSuccess()) {
                            log.info("The client has connected [{}] successful!", address.toString());
                            completableFuture.complete(future.channel());
                        } else {
                            throw new IllegalStateException();
                        }
                    });
                    channel = completableFuture.get();
                    channelProvider.put(address, channel);
                }
            }
        }
        return channel;
    }

// Channel 容器
public class ChannelProvider {
    private final Map<String, Channel> channelMap = new ConcurrentHashMap<>();
    ...
}

使用kryo 序列化替代JDK 自身的序列化:

在day0 使用的是Netty 自带的编解码器,底层用的是JDK 自带的序列化方式,性能差,如下:

p.addLast(new ObjectEncoder());
p.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

这里我们使用自定义的编解码器,底层使用Kryo 序列化方式(当然,也可以改成hessian2,参考SerializerFactory),如下:

p.addLast(new CustomObjectEncoder());
p.addLast(new CustomObjectDecoder());

对此,读者需要了解如何在Netty 中自定义帧的格式,可以查看Netty 粘包解决方案

优化远程服务实现方法

在day0 中,要实现一个远程方法,需要实现RemoteService 接口,接口如下:

public interface RemoteService {
    Object invoke(Object ... params);
}

此时一个远程服务类只能提供一个远程方法调用,十分难用,因此本次改造,直接去掉RemoteService.invoke() 方法,每个远程服务类不限制存在多少个远程方法。

/**
 * mark interface
 * 标记这是一个远程服务,无其他左右,后续结合spring 自动注入可以用注解替代
 */
public interface RemoteService {
}

而此时消费者调用远程服务时,不仅需要提供远程服务实例名,还要提供要调用的方法信息,如下:

Object hello = ServiceConsumer.invoke("HelloService.hello", "miemie");

接下来要优化的点

1、使用zookeeper 作为服务注册中心
2、客户端调用远程服务的时候进行负载均衡

标签:从头开始,address,public,RPC,Channel,简单,new,远程,channel
来源: https://blog.csdn.net/a469517790/article/details/115344325

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有