/ShadowRPC

一个基于netty的高性能rpc框架,简单易用,零配置,可异步,可全双工通信,可保持状态

Primary LanguageJava

ShadowRPC

一个基于netty的rpc开源框架,简单易用,零配置,可同步和异步调用,不断更新完善中...

主要模块

  • protocol : 协议层,包含应用层通信协议,以及序列化/反序列化,支持kryo和protobuf
  • registry : 注册模块,基于zookeeper作为注册中心,包含注册服务和服务发现
  • server : 服务端
  • client : 客户端
  • client-mini : 不依赖任何包的客户端,基于NIO

使用步骤

注: 所有使用案例都在client和server的单测里面

1.定义实体, 加上注解

@ShadowEntity
public class MyMessage {
    @ShadowField(1)
    private String content;

    @ShadowField(2)
    private int num;
}

如果是protobuf方式,编写proto文件

message MyMessage {
    string content = 1;
    int32 num = 2;
}

然后直接用maven插件protobuf-maven-plugin生成实体


2.编写接口加上@ShadowInterface注解

@ShadowInterface
public interface IHello {
    String hello(String msg);
    MyMessage say(MyMessage message);
}

如果采用protobuf作为通信协议,由于可实现跨语言,所以所有函数参数类型和返回类型都必须是proto文件定义的类型

@ShadowInterface
public interface IHelloProto {
    MyMessageProto.MyMessage say(MyMessageProto.MyMessage message);
}

然后编写服务实现类

@ShadowService(serviceName = "helloservice")
public class HelloService implements IHello {
    @Override
    public String hello(String msg) {
        return "Hello,"+msg;
    }
    @Override
    public MyMessage say(MyMessage message) {
        MyMessage message1 = new MyMessage();
        message1.setContent("hello received "+"("+message.getContent()+")");
        message1.setNum(message.getNum()+1);
        return message1;
    }
}

3.指定序列化类型和端口,启动服务端

单点启动模式如下:

ServerConfig serverConfig = new ServerConfig();
        serverConfig.setQpsStat(true); //统计qps
        serverConfig.setPort(2023);

ServerBuilder.newBuilder()
        .serverConfig(serverConfig)
        .addPackage("rpctest.hello")
        .build()
        .start();

使用zk作为集群模式启动

String ZK_URL = "localhost:2181";
ServerConfig serverConfig = new ServerConfig();
serverConfig.setGroup("DefaultGroup");
serverConfig.setPort(2023);
serverConfig.setRegistryUrl(ZK_URL);
serverConfig.setQpsStat(true); //统计qps
serverConfig.setSerializer(SerializerEnum.KRYO.name());
ServerBuilder.newBuilder()
                .serverConfig(serverConfig)
                .addPackage("rpctest.hello")
                .build()
                .start();

4.客户端用调用远程rpc接口

ModulePool.getModule(ClientModule.class).init(new ClientConfig());

ShadowClient shadowClient = new ShadowClient("127.0.0.1",2023);
shadowClient.init();

IHello helloService = shadowClient.createRemoteProxy(IHello.class,"shadowrpc://DefaultGroup/helloservice");

logger.info("发送 hello 消息");
String helloResponse = helloService.hello("Tom");
logger.info("hello 服务端响应:"+helloResponse);

MyMessage message = new MyMessage();
message.setNum(100);
message.setContent("Hello, Server!");

System.out.printf("发送请求 : %s\n",message);
MyMessage response = helloService.say(message);
System.out.printf("接收服务端消息 : %s\n",response);

使用zk作为服务发现负载均衡调用各个服务器:

ClientConfig config = new ClientConfig();
config.setSerializer(SerializerStrategy.KRYO.name());
ModulePool.getModule(ClientModule.class).init(config);
String ZK_URL="localhost:2181";
ShadowClientGroup shadowClientGroup = new ShadowClientGroup(ZK_URL);
shadowClientGroup.init();

IHello helloService = shadowClientGroup.createRemoteProxy(IHello.class, "shadowrpc://DefaultGroup/helloservice");
List<ShadowClient> shadowClientList = shadowClientGroup.getShadowClients("DefaultGroup");

System.out.println("所有服务器: "+shadowClientList.stream().map(c-> c.getRemoteIp()+":"+c.getRemotePort()).collect(Collectors.toList()));

for(int i = 0 ;i<shadowClientList.size() * 5; i++) {
    String hello = helloService.hello(i + "");
    System.out.println(hello);
}