一个开源分布式微服务rpc框架~正式发布(代码片段)

延年有余 延年有余     2022-12-01     219

关键词:

介绍

一个分布式微服务RPC框架 | 英文说明文档

1. 服务提供

  • 负载均衡策略
  • 序列化策略
  • 自动发现和注销服务
  • 注册中心

    2. 安全策略

  • 心跳机制
  • 信息摘要

    3. 设计模式

  • 单例模式
  • 动态代理
  • 静态工厂
  • 建造者
  • 策略模式
  • Future(观察者)

    亮点

    1. 信息摘要算法的应用

    对于信息摘要算法的使用,其实并不难,在数据包中添加 String 类型的成员变量 checkCode 用来防伪的就可以实现。

  • 原理

发送端把原信息用HASH函数加密成摘要,然后把数字摘要和原信息一起发送到接收端,接收端也用HASH函数把原消息加密为摘要,看两个摘要是否相同,若相同,则表明信息的完整.否则不完整。

  • 实现

客户端在发出 请求包,服务端会在该请求包在请求执行的结果的内容转成字节码后,使用 MD5 单向加密成为 唯一的信息摘要(128 比特,16 字节)存储到响应包对应的成员变量 checkCode 中,所以客户端拿到响应包后,最有利用价值的地方(请求要执行的结果被改动),那么 checkCode 将不能保证一致性,这就是信息摘要的原理应用。

安全性再增强

考虑到这只是针对客户需求的结果返回一致性,并不能确保请求包之间存在相同的请求内容,所以引入了请求 id

每个包都会生成唯一的 requestId,发出请求包后,该包只能由该请求发出的客户端所接受,就算两处有一点被对方恶意改动了,客户端都会报错并丢弃收到的响应包,不会拆包后去返回给用户。

如果不是单单改动了返回结果,而是将结果跟信息摘要都修改了,对方很难保证修改的内容加密后与修改后的信息摘要一致,因为要保证一致的数据传输协议和数据编解码。

2. 心跳机制

心跳机制的 RPC 上应用的很广泛,本项目对心跳机制的实现很简单,而且应对措施是服务端强制断开连接,当然有些 RPC 框架实现了服务端去主动尝试重连。

  • 原理

对于心跳机制的应用,其实是使用了 Netty 框架中的一个 handler 处理器,通过该 处理器,去定时发送心跳包,让服务端知道该客户端保持活性状态。

  • 实现

利用了 Netty 框架中的 IdleStateEvent 事件监听器,重写userEventTriggered() 方法,在服务端监听读操作,读取客户端的 写操作,在客户端监听写操作,监听本身是否还在活动,即有没有向服务端发送请求。

如果客户端没有主动断开与服务端的连接,而继续保持连接着,那么客户端的写操作超时后,也就是客户端的监听器监听到客户端没有的规定时间内做出写操作事件,那么这时客户端该处理器主动发送心跳包给服务端,保证客户端让服务端确保自己保持着活性。

3. IO 异步非阻塞

IO 异步非阻塞 能够让客户端在请求数据时处于阻塞状态,而且能够在请求数据返回时间段里去处理自己感兴趣的事情。

  • 原理

使用 java8 出世的 CompletableFuture 并发工具类,能够异步处理数据,并在将来需要时获取。

  • 实现

数据在服务端与客户端之间的通道 channel 中传输,客户端向通道发出请求包,需要等待服务端返回,这时可使用 CompletableFuture 作为返回结果,只需让客户端读取到数据后,将结果通过 complete()方法将值放进去后,在将来时通过get()方法获取结果。

快速开始

/**
     * 自定义对象头 协议 16 字节
     * 4 字节 魔数
     * 4 字节 协议包类型
     * 4 字节 序列化类型
     * 4 字节 数据长度
     *
     *       The transmission protocol is as follows :
     * +---------------+---------------+-----------------+-------------+
     * | Magic Number  | Package Type  | Serializer Type | Data Length |
     * | 4 bytes       | 4 bytes       | 4 bytes         | 4 bytes     |
     * +---------------+---------------+-----------------+-------------+
     * |                           Data Bytes                          |
     * |                       Length: $Data Length                  |
     * +---------------+---------------+-----------------+-------------+
     */

1.依赖

1.1 直接引入

首先引入两个jar包文件rpc-core-1.0.0.jarrpc-core-1.0.0-jar-with-dependencies.jar

jar包中包括字节码文件和java源码,引入后会自动把classsources一并引入,源码可作为参考

1.2 maven引入

引入以下maven,会一并引入rpc-common与默认使用的注册中心nacos-client相关依赖

<dependency>
    <groupId>cn.fyupeng</groupId>
    <artifactId>rpc-core</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>

2. 启动 Nacos

-m:模式standalone:单机

命令使用:

startup -m standalone

官方文档:https://nacos.io/zh-cn/docs/quick-start.html

Nacos 启动效果:

3. 提供接口

public interface HelloService 
    String sayHello(String message);

4. 启动服务

  • 真实服务
    @Service
    public class HelloServiceImpl implements HelloService 
    @Override
    public String sayHello(String message) 
        return "hello, here is service!";
    
    
  • 服务启动器
    @ServiceScan
    public class MyServer 
    public static void main(String[] args) 
        try 
            NettyServer nettyServer = new NettyServer("127.0.0.1", 5000, SerializerCode.KRYO.getCode());
            nettyServer.start();
         catch (RpcException e) 
            e.printStackTrace();
        
    
    

5. 启动客户端

初始化客户端时连接服务端有两种方式:

  • 直连
  • 使用负载均衡

    public class MyClient 
    public static void main(String[] args) 
        RoundRobinLoadBalancer roundRobinLoadBalancer = new RoundRobinLoadBalancer();
        NettyClient nettyClient = new NettyClient(roundRobinLoadBalancer, CommonSerializer.KRYO_SERIALIZER);
    
        RpcClientProxy rpcClientProxy = new RpcClientProxy(nettyClient);
        HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
        String result = helloService.sayHello("hello");
        System.out.println(result);
    
    

    5. 额外配置

logback 重写使用

在 resources 中加入 logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--%dateHH:mm:ss.SSS %c -->
            <pattern>%dateHH:mm:ss.SSS %c [%t] - %m%n</pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console"/>
    </root>
</configuration>

除此之外,框架还提供了 Socket 方式的 Rpc 服务

6. 场景应用

  • 支持 springBoot 集成

为了支持springBoot集成logback日志,继承rpc-netty-framework使用同一套日志,抛弃nacos-client内置的slf4j-apicommons-loging原有Jar包,因为该框架会导致在整合springboot时,出现重复的日志绑定和日志打印方法的参数兼容问题,使用jcl-over-slf4j-api可解决该问题;

springboot1.02.0版本中,不使用它默认版本的spring-boot-starter-log4j,推荐使用1.3.8.RELEASE
springboot简单配置如下

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <!-- 排除 springboot 默认的 logback 日志框架 -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
            <!-- 排除 springboot 默认的 commons-logging 实现(版本低,出现方法找不到问题) -->
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jcl</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- 与 logback 整合(通过 @Slf4j 注解即可使用) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    <!--引入log4j日志依赖,目的是使用 jcl-over-slf4j 来重写 commons logging 的实现-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j</artifactId>
    <version>1.3.8.RELEASE</version>
    </dependency>
</dependencies>

7. 异常解决

  • ServiceNotFoundException

抛出异常ServiceNotFoundException

解决真实服务不存在的情况,导致负载均衡中使用的策略出现异常的情况,修复后会强制抛出ServiceNotFoundException,或许大部分情况是服务未启动。

当然,推荐真实服务应该在服务启动器的内层包中,同层可能会不起作用。

除非使用注解注明包名@ServiceScan("com.fyupeng")

  • ReceiveResponseException

抛出异常data in package is modified Exception

信息摘要算法的实现,使用的是String类型的equals方法,所以客户端在编写Service接口时,如果返回类型不是八大基本类型 + String 类型,也就是复杂对象类型,那么要重写toString方法。

不使用Object默认的toString方法,因为它默认打印信息为16位的内存地址,在做校验中,发送的包和请求获取的包是需要重新实例化的,说白了就是深克隆,必须 重写Object原有toString方法。

为了避免该情况发生,建议所有PoJoVO类必须重写toString方法,其实就是所有真实业务方法返回类型的实体,必须重写toString方法。

  • RegisterFailedException

抛出异常Failed to register service Exception

原因是注册中心没有启动或者注册中心地址端口指定不明。

  • NotSuchMethodException
    抛出异常java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log

出现该异常的原因依赖包依赖了jcl-over-slf4jjar包,与springboot-starter-log4j中提供的jcl-over-slf4j重复了,建议手动删除rpc-core-1.0.0-jar-with-dependenceies.jarorg.apache.commons

  • DecoderException

抛出异常:com.esotericsoftware.kryo.KryoException: Class cannot be created (missing no-arg constructor): java.lang.StackTraceElement

主要是因为Kryo序列化和反序列化是通过无参构造反射创建的,所以使用到Pojo类,首先必须对其创建无参构造函数,否则将抛出该异常,并且无法正常执行。

  • InvocationTargetException

抛出异常:Serialization trace:stackTrace (java.lang.reflect.InvocationTargetException)

主要也是反射调用失败,主要原因还是反射执行目标函数失败,缺少相关函数,可能是构造函数或者其他方法参数问题。

8. 开发说明

有二次开发能力的,可直接对源码修改,最后在工程目录下使用命令mvn clean package,可将核心包和依赖包打包到rpc-netty-framework\\rpc-core\\target目录下,本项目为开源项目,如认为对本项目开发者采纳,请在开源后最后追加原创作者GitHub链接 https://github.com/fyupeng ,感谢配合

对于有兴趣从事开发开源组件,并且想与作者协同开发的,可告知开发者:fyp010311@126.com
RPC 微服务框架正式版本已发布,对于先前体验过程出现任何问题的,可及时与开发者联系,谢谢配合!

docker部署piggymetrics分布式微服务(代码片段)

...了如何在windows10下安装docker社区版。那如何利用docker落地一个分布式微服务架构的系统呢?github上有一个不错的开源项目PiggyMetrics,通过这个可以学习用docker和springcloud做分布式微服务架构。原项目地址:https://github.co 查看详情

rpc协议及实现方式(分布式微服务治理的核心)

...程序包括5个部分:所以这架构图的意思是:当user想发起一个远程调用时,它实际是通过本地调用User-stub。并通过本地的RPCRuntime传输。远端RPCRuntime实例收到请求后交给Server-stub进行解码后发起本地端调用,调用结果再返回给User... 查看详情

腾讯正式对外开源高性能rpc开发框架与微服务平台tars

...构TAF(TotalApplicationFramework)多年的实践成果总结而成的开源项目,目前已于4月10日正式对外开源。 作为支持多语言的高性能RPC开发框架和配套一体化的服务治理平台,Tars可以帮助企业或者用户以微服务的方式快速构建稳定可靠... 查看详情

分布式微服务springcloud框架搭建详细流程(代码片段)

什么是SpringCloud微服务架构文章目录什么是SpringCloud微服务架构前言一、什么是Spring-Cloud?二、提供的是一些快速构建微服务应用的工具三、搭建微服务项目项目总体结构介绍1.创建微服务注册中心Euerka项目工程2.创建微服务... 查看详情

云服务架构-honghu分布式微服务框架

今天正式给大家介绍了SpringCloud-HongHu企业分布式微服务云架构,我这边结合了当前大部分企业的通用需求,包括技术的选型比较严格、苛刻,不仅要用业界最流行的技术,还要和国际接轨,在未来的5~10年内不能out。作为公司的... 查看详情

谷歌发布编写分布式应用的框架serviceweaver(代码片段)

一个新的框架,在本地以模块化单体的形式运行,一旦部署,则为分布式微服务架构转载请注明来源:https://janrs.com/2023/03/谷歌发布编写分布式应用的框架service-weaver/感觉就像永远,总是在什么是更好的之间来来回回:单体还是... 查看详情

springcloud分布式微服务搭建(代码片段)

...者,同时提供负载均衡。一.API网关(摘自百度)API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,... 查看详情

springcloud分布式微服务搭建(代码片段)

本例子是一个springcloud的configserver,client例子利用git存储各个服务的配置文件server获取配置文件的仓库位置,并把server注册到eureka中,同时为了实现HA,多开几个serverclient通过server获得git的地址,运行时利用获得的git配置文件... 查看详情

分布式与微服务系列分布式rpc框架apachedubbo服务(代码片段)

分布式RPC框架ApacheDubbo服务一、ApacheDubbo概述1.1、Dubbo简介1.2、什么是RPC?1.3、什么是服务发现?1.3、Dubbo架构二、服务注册中心Zookeeper2.1、Zookeeper介绍2.2、安装Zookeeper2.3、启动、停止Zookeeper三、Dubbo快速入门3.1、服务提供... 查看详情

dubbo3.0.0正式发布,王者归来!(代码片段)

...Dubbo,先来一波扫盲:ApacheDubbo是一款高性能、轻量级的开源Java服务框架Dubbo的6大特性:1、面向接口代理的高性能RPC调用;2、服务自动注册与发现;3、智能负载均衡策略;4、高度可扩展能力;5、运行期流量调度;6、可视化的... 查看详情

自己动手从0开始实现一个分布式rpc框架(代码片段)

简介: 如果一个程序员能清楚的了解RPC框架所具备的要素,掌握RPC框架中涉及的服务注册发现、负载均衡、序列化协议、RPC通信协议、Socket通信、异步调用、熔断降级等技术,可以全方位的提升基本素质。虽然也有... 查看详情

微博轻量级rpc框架motan正式开源:支撑千亿调用

支撑微博千亿调用的轻量级RPC框架Motan正式开源了,项目地址为https://github.com/weibocom/motan。微博轻量级RPC框架Motan正式开源  Motan是微博技术团队研发的基于Java的轻量级RPC框架,已在微博内部大规模应用多年,每天稳定支撑微... 查看详情

分布式微服务治理框架-选型

分布式微服务治理框架-选型目录1、同类产品对比选型2、注册中心3、配置中心4、服务通信5、负载均衡6、降级机制7、服务网关1、同类产品对比选型降级框架主要有SpringCloudNetflix、Dubbo、SpringCloudAlibaba,当然我们也可以混用&#... 查看详情

转载分布式rpc框架性能大比拼

...an、rpcx、gRPC、thrift的性能比较Dubbo是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘... 查看详情

国内首个基于rust语言的rpc框架—volo正式开源!

...文会为大家简单介绍Volo及其相关生态,并为大家提供一个简单的Rust与Go的选型建议。01项目缘起其实Volo的创始成员来自于Kitex团队(CloudWeGo开源的GoRPC框架),当时我们在Go上做了非常深度的性能优化,也因此... 查看详情

设计一个分布式rpc框架(代码片段)

...究了解了下内部原理,突然来了兴趣,就想着自己也实现一个RPC框架,这样可以让自己在设计与实现RPC框架过程中,也能从中了解和解决一些问题,进而让自己能够更好的发展(哈哈,会不会说我有些剑走偏锋?不去解决问题,... 查看详情

分布式理论,架构设计自定义rpc(代码片段)

...务端代码客户端代码自定义RPC在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、Hessian、SOAP、ESB和JMS等。要实现网络机器 查看详情

分布式理论,架构设计自定义rpc(代码片段)

...务端代码客户端代码自定义RPC在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、Hessian、SOAP、ESB和JMS等。要实现网络机器 查看详情