这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记
RPC是什么
RPC全称为(Remote Procedure Call),是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议,简单理解就是让开发者能够像调用本地服务一样调用远程服务。
RPC可以分为两部分:用户调用接口 + 具体网络协议。前者为开发者需要关心的,后者由框架来实现。
举个例子,我们定义一个函数,我们希望函数如果输入为“Hello World”的话,输出给一个“OK”,那么这个函数是个本地调用。如果一个远程服务收到“Hello World”可以给我们返回一个“OK”,那么这是一个远程调用。我们会和服务约定好远程调用的函数名。因此,我们的用户接口就是:输入、输出、远程函数名,比如用 SRPC 开发的话,client端的代码会长这样:
int main()
{
Example::SRPCClient client(IP, PORT);
EchoRequest req; // 用户自定义的请求结构
EchoResponse resp; // 用户自定义的回复结构
req.set_message("Hello World");
client.Echo(&req, &resp, NULL); // 调用远程函数名为Echo
return 0;}
组成
我们可以从SRPC的架构层次上来看,RPC框架有哪些层,以及SRPC目前所横向支持的功能是什么: 用户代码(client的发送函数/server的函数实现) IDL序列化(protobuf/thrift serialization) 数据组织 (protobuf/thrift/json) 压缩(none/gzip/zlib/snappy/lz4) 协议 (Sogou-std/Baidu-std/Thrift-framed/TRPC) 通信 (TCP/HTTP)
压缩层、序列化层、协议层其实是互相解耦打通的,在SRPC代码上实现得非常统一,横向增加任何一种压缩算法或IDL或协议都不需要也不应该改动现有的代码,才是一个精美的架构~
实例
我们用一个完整的 server 例子,来看一下用户调用接口的使用方式,以及如何跨协议使用HTTP作为client进行调用。
#include "example.srpc.h"
#include "workflow/WFFacilities.h"
using namespace srpc;
static WFFacilities::WaitGroup wait_group(1);
void sig_handler(int signo)
{
wait_group.done();
}
class ExampleServiceImpl : public Example::Service
{
public:
void Echo(EchoRequest *request, EchoResponse *response, srpc::RPCContext *ctx) override
{
response->set_message("OK"); // 具体逻辑在这里添加,我们简单地回复一个OK
}};
int main()
{
unsigned short port = 80; // 因为要启动Http服务
SRPCHttpServer server; // 我们需要构造一个SRPCHttpServer
ExampleServiceImpl example_impl;
server.add_service(&example_impl);
server.start(port);
wait_group.wait();
server.stop();
return 0;
}
之后发起一个简单的请求
$ curl -i 127.0.0.1:80/Example/Echo -H 'Content-Type: application/json' -d '{message:"Hello World"}'
HTTP/1.1 200 OK
SRPC-Status: 1
SRPC-Error: 0
Content-Type: application/json
Content-Encoding: identity
Content-Length: 16
Connection: Keep-Alive
应用前景
随着公司规模的扩大,以及业务量的激增,单体应用逐步演化为服务/微服务的架构模式, 服务之间的调用大多采用rpc的方式调用,或者消息队列的方式进行解耦。几乎每个大厂都会创建自己的rpc框架,或者基于知名的rpc框架进行改造。
目前, rpc框架主要沿着两条路线发展,一个是目标为了跨语言,服务端可以用不同的语言实现,客户端也可以用不同的语言实现,不同的语言实现的客户端和服务器端可以互相调用。很显然,要支持不同的语言,需要基于那种语言实现相同协议的框架,并且协议设计应该也是跨语言的,其中比较典型的是 grpc,基于同一个IDL,可以生成不同语言的代码,并且语言的支持也非常的多。
另一个rpc框架发展的目标是支持服务治理,主要的精力放在服务发现、路由、容错处理等方面,主要围绕一个语言开发,可能也有一些第三方曲折的实现服务的调用和服务的实现,这其中的代表,也是比较早的开源的框架就是阿里巴巴的dubbo。
有些rpc框架协议的涉及一开始就没有考虑的跨语言,其中使用了语言的一些特有的属性,比如Java的 ObjectInputStream/ObjectOutputStream, Golang的Gob等,有些在协议的设计上就考虑了通用性, 使用JSON或者Protobuffer作为数据序列化。
在实际开发中,我们可以使用开源且相对成熟的RPC框架解决微服务架构下的远程通信问题,常见的rpc框架:
- Thrift:thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。
- Dubbo:Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用。