《轻量级分布式 RPC 框架》笔记 (源码+注释)

导读:本篇文章讲解 《轻量级分布式 RPC 框架》笔记 (源码+注释),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

在学习RPC的时候发现了一个很不错的项目,以下是我在学习这个项目的过程中遇到的疑问和问题的答案。

目录

原文

项目地址:

项目概括:

如何把这个项目跑起来?

一个RPC请求之后会发生什么?

项目的先修知识

spring如何去实现依赖注入?

spring的注解如何发挥作用,如何自定义注解?

Netty 学习

Protostuff

ZooKeeper

其他问题

编码和序列化的区别?

这个项目和之前写的RPC有什么区别?

改进点


原文

轻量级分布式 RPC 框架 – 黄勇 – OSCHINA – 中文开源技术交流社区RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样。 RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC。会两方面会直接影响 RPC 的性能,一是传输方式,二是序列化。 众所…《轻量级分布式 RPC 框架》笔记 (源码+注释)https://my.oschina.net/huangyong/blog/361751

项目地址:

原项目的地址:

rpc: 轻量级分布式 RPC 框架《轻量级分布式 RPC 框架》笔记 (源码+注释)http://git.oschina.net/huangyong/rpc加了注释的项目地址:

RPCfromHY: 这个项目主要来自https://my.oschina.net/huangyong/blog/361751 http://git.oschina.net/huangyong/rpc (原版项目地址)在此基础上加了一些注释,方便理解。

项目概括:

本文通过 Spring + Netty + Protostuff + ZooKeeper 实现了一个轻量级 RPC 框架,使用 Spring 提供依赖注入与参数配置,使用 Netty 实现 NIO 方式的数据传输,使用 Protostuff 实现对象序列化,使用 ZooKeeper 实现服务注册与发现。使用该框架,可将服务部署到分布式环境中的任意节点上,客户端通过远程接口来调用服务端的具体实现,让服务端与客户端的开发完全分离,为实现大规模分布式应用提供了基础支持。

如何把这个项目跑起来?

首先下载和学习ZooKeeper ,参考这篇文章

Zookeeper基本原理+通俗理解+安装使用_trigger的博客-CSDN博客

1.启动ZooKeeper 的服务器,这样服务注册和发现中心就启动了,如果要使用该服务,只需要访问127.0.0.1:2181即可。

《轻量级分布式 RPC 框架》笔记 (源码+注释)

2.启动红字所标识的 rpc-sample-server,命令行窗口会出现:

start server
connect zookeeper
create address node: /registry/com.xxx.rpc.sample.api.HelloService/address-0000000001
register service: com.xxx.rpc.sample.api.HelloService => 127.0.0.1:8000
create address node: /registry/com.xxx.rpc.sample.api.HelloService-sample.hello2/address-0000000001
register service: com.xxx.rpc.sample.api.HelloService-sample.hello2 => 127.0.0.1:8000
server started on port 8000

3.启动rpc-sample-client中的第一个测试类即可。

《轻量级分布式 RPC 框架》笔记 (源码+注释)

 会出现:

connect zookeeper
get only address node: address-0000000001
discover service: com.xxx.rpc.sample.api.HelloService => 127.0.0.1:8000
time: 653ms
Hello! World
connect zookeeper
get only address node: address-0000000001
discover service: com.xxx.rpc.sample.api.HelloService-sample.hello2 => 127.0.0.1:8000
time: 17ms
你好! 世界

这样就启动了这个项目。

一个RPC请求之后会发生什么?

这个项目总的流程是:

ZooKeeper启动,rpcServer启动,把特定目录下的远程服务加入到handlerMap(本地缓存)中,同时利用zk客户端向zk中注册这些服务,之后监听对应的端口8000。

客户端发起请求之前,首先需要获取动态代理对象,这个对象里面有zk客户端(可以通过它获得服务的地址)。

在调用这个动态代理对象的某一个方法时,会先利用zk客户端去zk中查找是否有这个服务,如果有,得到其地址端口比如127.0.0.1:8000,新建一个rpcClient,绑定对应的地址端口,连接rpcServer,发送相应的信息请求服务。

rpc-sample-client包下的HelloClient类是一个客户端类,用来测试。

具体测试代码为

public class HelloClient {

    public static void main(String[] args) throws Exception {

        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        RpcProxy rpcProxy = context.getBean(RpcProxy.class);

        HelloService helloService = rpcProxy.create(HelloService.class);
        String result = helloService.hello("World");
        System.out.println(result);

    }
}

前两行代码获得了rpcProxy,debug如下,运行完create对象后,知道了服务的地址在127.0.0.1:8000端口。

《轻量级分布式 RPC 框架》笔记 (源码+注释)

String result = helloService.hello(“World”);

这句代码调用了invoke函数,
函数中生成了一个rpcClient,首先把要访问的函数和输入参数等信息包装成RpcRequest“请求消息”对象,序列化之后发送给rpcServer并等待结果。

rpcserver始终在监听着8000端口,有消息过来,先进行解码(反序列化),得到RpcRequest“请求消息”对象,将其中的信息(函数,输入参数等)取出,进行反射调用得到结果,再把这个结果包装成RpcResponse“响应消息”对象,发回给客户端。

项目的先修知识

这个项目的技术选型是Spring + Netty + Protostuff + ZooKeeper,所以这四个是需要掌握的,其中Protostuff 不需要很多时间,大概了解一下即可。

spring如何去实现依赖注入?

Spring5之IOC详解_trigger的博客-CSDN博客

代码中主要的依赖注入有两处,一处是测试类获得rpcClient,另一处是rpcServer启动的时候,在启动时采用rpcClient、rpcServer中的属性都是通过xml文件配置的方式注入的。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:rpc.properties"/>
<!--一个zk的服务发现对象serviceDiscovery,该对象是ZooKeeperServiceDiscovery的实例化,可以实现 服务发现功能
构造函数需要传入 zk的地址和端口 用字符串传入 也就是127.0.0.1:2181
这个值是在 rpc.properties配置好了 -->
    <bean id="serviceDiscovery" class="com.xxx.rpc.registry.zookeeper.ZooKeeperServiceDiscovery">
        <constructor-arg name="zkAddress" value="${rpc.registry_address}"/>
    </bean>
<!-- 生成rpcProxy,用来远程调用对应的服务,构造函数的输入参数是 一个zk的服务发现对象serviceDiscovery
调用serviceDiscovery的discover方法就能远程获取相应的服务-->
    <bean id="rpcProxy" class="com.xxx.rpc.client.RpcProxy">
        <constructor-arg name="serviceDiscovery" ref="serviceDiscovery"/>
    </bean>

</beans>

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context.xsd">    <context:component-scan base-package="com.xxx.rpc.sample.server"/>    <context:property-placeholder location="classpath:rpc.properties"/><!--导入 一个serviceRegistry进行服务注册 构造函数的输入参数是 zk的ip + port -->    <bean id="serviceRegistry" class="com.xxx.rpc.registry.zookeeper.ZooKeeperServiceRegistry">        <constructor-arg name="zkAddress" value="${rpc.registry_address}"/>    </bean><!--根据serviceAddress 8000 serviceRegistry 2181 构建RpcServer如果客户端有请求  只需要访问 ip+8000 就能获得服务-->    <bean id="rpcServer" class="com.xxx.rpc.server.RpcServer">        <constructor-arg name="serviceAddress" value="${rpc.service_address}"/>        <constructor-arg name="serviceRegistry" ref="serviceRegistry"/>    </bean></beans>

spring的注解如何发挥作用,如何自定义注解?

java注解详解和自定义注解_不积跬步,无以至千里-CSDN博客《轻量级分布式 RPC 框架》笔记 (源码+注释)https://blog.csdn.net/u010902721/article/details/52576624/在这里定义了RpcService 注解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RpcService {
    /**
     * 服务接口类
     */
    Class<?> value();
    /**
     * 服务版本号
     */
    String version() default "";
}

在服务器启动之后就会扫描这样的注解进行注册。debug如下。

《轻量级分布式 RPC 框架》笔记 (源码+注释)

 

《轻量级分布式 RPC 框架》笔记 (源码+注释)

Netty 学习

参考 B站黑马的视频

Protostuff

初探Protostuff的使用_LuoLiangDSGA的博客-CSDN博客_protostuff《轻量级分布式 RPC 框架》笔记 (源码+注释)https://blog.csdn.net/oppo5630/article/details/80173520

ZooKeeper

Zookeeper基本原理+通俗理解+安装使用_trigger的博客-CSDN博客《轻量级分布式 RPC 框架》笔记 (源码+注释)https://blog.csdn.net/weixin_40757930/article/details/122993927

其他问题

编码和序列化的区别?

序列化是编码过程的一个示例;它将复杂的数据结构转换为单个文本字符序列。 然后可以将该字符序列进一步编码成某种二进制表示,以实现更紧凑的存储或更快的传输。

参见

编码和序列化_小豆角的博客-CSDN博客_序列化和编码的区别《轻量级分布式 RPC 框架》笔记 (源码+注释)https://blog.csdn.net/u013755520/article/details/99938337

这个项目和之前写的RPC有什么区别?

之前写的RPC:

手写RPC框架(文末附代码)_trigger的博客-CSDN博客《轻量级分布式 RPC 框架》笔记 (源码+注释)https://blog.csdn.net/weixin_40757930/article/details/122908918

之前的项目只能算作一个RPC调用,不能称之为RPC框架,因为服务注册、服务发现是基于一个map实现的。

改进点

一个轻量级分布式RPC框架–NettyRpc – 阿凡卢 – 博客园《轻量级分布式 RPC 框架》笔记 (源码+注释)https://www.cnblogs.com/luxiaoxun/p/5272384.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92874.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!