使用 httputils + sbe (Simple Binary Encoding) 实现金融级 java rpc

1、认识 Simple Binary Encoding (sbe)

高性能Java库 Agrona 的主要目标是减少性能瓶颈,通过提供线程安全的直接和原子缓冲区、无装箱操作的原始类型列表、开散列映射和集合以及锁-free队列等,为开发者在处理并发和低延迟场景时提供强大工具。

Simple Binary Encoding (sbe) 是 Agrona 的一部分,也是高性能通讯框架 Aeron 的一部分。

2、什么是 rpc ?

一讲 rpc ,很多人会想到 dubbo (国产)和 grpc。估计还会联想到注册与发现服务;可能还会联想到微服务。可能就会觉得这个事儿“老重啦”,害怕!

其实很简单的,你请求一次 http 就是个 rpc 请求了(远程过程调用嘛)。最典型的就是 http + json 请求了。

3、现在讲 httputils + sbe

这里我们会用到两个重要的 solon 框架的插件:一个是 httputils 工具插件,一个是 abc + agrona 序列化插件(abc 适配了多个编解码方案)。

<!-- 这是 sbe 的编解码包装器 --> <dependency>     <groupId>org.noear</groupId>     <artifactId>solon-serialization-abc</artifactId> </dependency>  <dependency>     <groupId>org.agrona</groupId>     <artifactId>agrona</artifactId>     <version>${agrona-sbe.version}</version> </dependency>  <dependency>     <groupId>org.noear</groupId>     <artifactId>solon-net-httputils</artifactId> </dependency> 

这里要感谢 solon 框架,它强调三元合一(mvc 与 rpc 是自然一体的)。下面,开始干活啦...

  • 公用包(也可以在客户端,服务端分别定义实体类。只要实现 SbeSerializable 接口即可 )

这里定义一个 sbe 实体类。注意要实现 SbeSerializable 接口。

@Getter @Setter public class MessageDo implements SbeSerializable {     private long id;     private String title;      @Override     public void serializeRead(SbeInput in) {         id = in.readLong();         title = in.readString();     }      @Override     public void serializeWrite(SbeOutput out) {         out.writeLong(id);         out.writeString(title);     } } 
  • 服务端(只支持 @Body 数据接收,只支持实体类)

在 solon web 项目里,添加一个控制器(注解可以用 @Remoting@Controller)。使用 @Remoting 时,方法上不需要加 @Mapping 注解。

#添加插件 org.noear:solon-web org.noear:solon-serialization-abc org.agrona:agrona:${agrona-sbe.version} # 提供 sbe 序列化支持 
@Mapping("/rpc/demo") @Remoting public class HelloServiceImpl {     @Override     public MessageDo hello(@Body MessageDo message) { //还可接收路径变量,与请求上下文         return message;     } } 
  • 客户端应用 for HttpUtils(只支持 body 数据提交,只支持实体类)
#添加插件 org.noear:solon-net-httputils org.noear:solon-serialization-abc org.agrona:agrona:${agrona-sbe.version} # 提供 sbe 序列化支持 
//应用代码 @Component public class DemoCom {     public MessageDo hello() {         MessageDo message = new MessageDo();         message.setId(3);                  //指明请求数据为 ABC,接收数据要 ABC         return HttpUtils.http("http://localhost:8080/rpc/demo/hello")                 .serializer(AbcBytesSerializer.getInstance())                 .header(ContentTypes.HEADER_CONTENT_TYPE, ContentTypes.ABC_VALUE)                 .header(ContentTypes.HEADER_ACCEPT, ContentTypes.ABC_VALUE)                 .bodyOfBean(message)                 .postAs(MessageDo.class);     } } 

4、总结

总体上,跟 json 没什么大的区别。主要是指定了:序列化器、内容类型、接收类型,让各端能识别类据类型。

5、还可以使用“注解式 http 客户端”框架

肯定也会有人觉得,一个接口还好,如果有很多接口就要写很多重复的http请求代码了。所以,“注解式 http 客户端” 很重要,这也是很多 rpc 框架流行的原因,就像调用本地接口一样,使用远程接口。

nami 是 solon 框架的 rpc 客户端(或者,注解式 http 客户端),支持各种序列化。(只要是“支持序列化定制”的注解式 http 客户端,都可用!)

  • 添加两个依赖包
#添加插件 org.noear:nami-coder-abc # abc 编解码支持 org.noear:nami-channel-http     # http 请求通道支持,也可以是 socketd(支持 tcp, udp, ws) org.agrona:agrona:${agrona-sbe.version} # 提供 sbe 序列化支持 
  • 代码应用(只支持 body 数据提交,只支持实体类)
@NamiClient(url = "http://localhost:8080/rpc/demo", headers = {ContentTypes.ABC, ContentTypes.ABC_ACCEPT}) public interface HelloService {     MessageDo hello(@NamiBody MessageDo message);     //方法2     //方法3     //方法4     //方法5     //方法6 }  @Component public class DemoCom {     @NamiClient //注入     HelloService helloService;        public MessageDo hello() {          MessageDo message = new MessageDo();          message.setId(3);                   rerturn helloService.hello(message);     } } 

发表评论

相关文章