一文了解RPC框架原理

本文介绍了RPC框架的概念,作为微服务实现的关键技术,RPC通过网络调用远程服务,简化系统维护。接着详细解析了RPC调用流程,包括客户端调用、动态代理、网络传输、服务端数据接受和真实调用等步骤,强调了动态代理、序列化、反射和Netty在其中的作用。最后总结了掌握RPC框架原理的重要性,并鼓励读者阅读源码和动手实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.RPC框架的概念

RPC(Remote Procedure Call)–远程过程调用,通过网络通信调用不同的服务,共同支撑一个软件系统,微服务实现的基石技术。使用RPC可以解耦系统,方便维护,同时增加系统处理请求的能力。
在这里插入图片描述

上面是一个简单的软件系统结构,我们拆分出来用户系统和订单系统做为服务存在,让不同的站点去调用。

只需要引入各个服务的接口包,在代码中调用RPC服务就跟调用本地方法一样,我刚接触到这种调用方式的时候颇为惊奇,我明明调用的就是java语言方法啊(以java为例,现在RPC框架一般都支持多语言),怎么就调用了远程的服务了呢??

2.RPC框架的原理解析

2.1 流程纵览

在这里插入图片描述

如上图所示,我将一个RPC调用流程概括为上图中5个流程,左边3个为客户端流程,右边两个为服务端流程。下面就各流程进行解析

2.2 客户端调用

服务调用方在调用服务时,一般进行相关初始化,通过配置文件/配置中心 获取服务端地址 用户调用:

// 用户服务接口
public interface UserService {
 
 public User genericUser(Integer id,String name,Long phone);
 
}


//调用方
//服务初始化
KRPC.init("D:\\krpc\\service\\demo\\conf\\client.xml");
UserService service = ProxyFactory.create(UserService.class, "demo","demoService");
User user = service.genericUser(1, "yasin", 1888888888L);

一开始接触RPC调用方法肯定就有疑惑,它不是一个接口吗,直接调用应该没啥效果啊,我也没有引入实现包。

带着这个疑惑,我们就进入下一个知识点,动态代理

2.3动态代理

动态代理这东西意如其名,它代理你帮你做事情。上面我们不说直接调用一个接口中的方法,并且没有用该接口的实现类调用,那么方法是怎么生效的呢?

可以看到这个用户服务这个service是由ProxyFactory代理工程创造的,在该ProxyFactory#create()方法中就跟一个代理处理器绑定在一起了

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    //构造请求request
    Request request = new Request();
    ....

   return RequestHandler.request(serviceName, request,returnClass);
}

这个类实现了InvocationHandler接口(JDK提供的动态代理技术),每次去调用接口方法,最终都交由该handler进行处理。这个环节一般会获取方法的一些信息,例如方法名,方法参数类型,方法参数值,返回对象类型。

同时这个环节会提供序列化功能,一般的RPC网络传输使用TCP(哪怕使用HTTP)传输,这里也要将这些参数进行封装成我们定义的数据接口进行传输。

2.4网络传输

我们通过将方法参数进行处理后,就要使用发起网络请求,使用tcp传输的就利用socket通信进行传输,这一块我开源项目中使用的同步堵塞的方案进行请求,也可以使用一些非堵塞方案进行请求,效率会更高一些。

2.5服务端数据接受

这一块使用netty,可以快速一个高性能、高可靠的一个服务端。

public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf buf = (ByteBuf)msg;  
        byte[] bytes = new byte[buf.readableBytes()];  
        buf.readBytes(bytes);  

        byte[] responseBytes = RequestHandler.handler(bytes);
        ByteBuf resbuf = ctx.alloc().buffer(responseBytes.length);
        resbuf.writeBytes(responseBytes);
        ctx.writeAndFlush(resbuf);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}

上面代码是我项目中使用的服务端代码。关于netty网上学习的资料很多,这里也只是宏观的讲解RPC原理,就不展开。

2.6真实调用

服务端获取客户端请求的数据后, 调用请求中的方法,方法参数值,通过反射调用真实的方法,获取其返回值,将其序列化封装,通过netty进行数据返回,客户端在接受数据并解析,这就完成了一次rpc请求调用的全过程。

method = clazz.getMethod(request.getMethodName(),requestParamTypes);
method.setAccessible(true);
result = method.invoke(service, requestParmsValues)

上面代码片段为通过反射调用真实方法

2.7 服务端的动态加载

通过2.2到2.6的说明,一次RPC请求过程大致如此,但是一个RPC框架会有很多细节需要处理。

其实在一次请求调用前,服务端肯定要先启动。

服务端作为一个容器,跟我们熟知的tomcat一样,它可以动态的加载任何项目。所以在服务端启动的时候,必须要进行一个动态加载的过程。在KRPC中,我使用了URLClassLoader动态加载一个指定路径的jar包,任何业务服务的实现所依赖的jar包都可以放入该路径中。

3.总结

一个RPC框架大致需要动态代理、序列化、网络请求、网络请求接受(netty实现)、动态加载、反射这些知识点。现在开源及各公司自己造的RPC框架层出不穷,唯有掌握原理是一劳永逸的。掌握原理最好的方法莫不是阅读源码,自己动手写是最快的。

最后

感谢大家看到这里,文章有不足,欢迎大家指出;如果你觉得写得不错,那就给我一个赞吧。

也欢迎大家关注我的公众号:程序员麦冬,麦冬每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

### Transformers框架原理 Transformers框架的核心基于Transformer架构,这是一种由Vaswani等人于2017年提出的神经网络模型[^4]。该架构主要分为两个部分:Encoder(编码器)和Decoder(解码器)。然而,在实际应用中,某些变体可能仅使用其中一个部分。 #### 输入表示 对于像BERT这样的模型,其输入是由三种嵌入向量相加构成的:Token Embeddings、Positional Embeddings以及Segment Embeddings[^1]。这种组合允许模型不仅学习单词的意义及其位置关系,还能区分不同句子片段间的差异。 #### 架构组成 - **自注意力层**:这是Transformer的关键创新之一,它让模型可以关注到输入序列的不同部分,从而捕捉更丰富的语义信息[^3]。 - **前馈神经网络**:应用于每一个位置上的独立转换操作,增加了表达能力。 - **归一化与残差连接**:通过加入这些技术来改善深层结构的学习效果并防止梯度消失问题的发生[^3]。 ### 使用教程 要开始使用Transformers库来进行自然语言处理任务,可以从安装Hugging Face提供的`transformers`包入手: ```bash pip install transformers ``` 加载预训练好的模型非常简便,比如下面是如何加载BERT用于分词的例子: ```python from transformers import BertTokenizer, TFBertModel tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') model = TFBertModel.from_pretrained("bert-base-uncased") inputs = tokenizer("Hello world!", return_tensors="tf") outputs = model(inputs) print(outputs.last_hidden_state) ``` 这段代码展示了如何初始化一个BERT tokenizer 和对应的TF (TensorFlow) 版本的 BERT 模型,并对一句话进行了编码得到隐藏状态作为输出。 ### 实战案例 - 计算词语相似度 如果想探索词汇间的关系,则可以通过Word Embedding实现这一点。这里给出一段简单的Python脚本来展示这一过程[^5]: ```python from gensim.models import KeyedVectors # 加载Google News pre-trained vectors word_vectors = KeyedVectors.load_word2vec_format('./GoogleNews-vectors-negative300.bin', binary=True) similar_words = word_vectors.most_similar('king', topn=5) for w,score in similar_words: print(f"{w}: {score}") ``` 此示例说明了如何利用预先训练好的谷歌新闻数据集中的词向量找到最接近给定单词的概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值