底层通信选型

设计一个微服务框架的起始点,是确定底层通信的方式。因为上层的服务治理,都是建立在这个基础之上。

可行的选择是:

  • 直接使用 gRPC直接
  • 使用 HTTP
  • 设计自己的 RPC 协议:实践中建议直接使用 gRPC 或者 HTTP

RPC要解决的核心问题

RPC的全称是Remote Procedure Call,即远程过程调用。核心就是:如同本地调用一般调用服务器上的方法。

调用信息

要完成这种映射,首先要解决第一个问题:映射什么?

举个例子,假如说我们在客户端调用的是userService.GetByld,传入的参数是 int 类型的值 123。那么服务端究竟怎么知道客户端调用的是userService.GetByld,参数是 int 类型的 123?

rpc项目创建 如何设计rpc_客户端

那么调用信息需要包含什么?
服务名:也就是userService
方法名:GetByld
参数值:123
要不要参数类型?如果你在支持重载的语言上设计微服务框架,并且决定支持重载,那么你就需要传递参数类型,否则你不需要传递参数类型。

重载是什么?同名方法,有不同参数

RPC协议 不需要传参数类型,如果硬要传就可以实现重载的功能。

服务名是什么?
以前Dubbo 接口名注册 gRPC 应用名注册

客户端捕捉本地调用

既然要传递调用信息,那么问题就在于:RPC 客户端怎么获得这些调用信息?这个问题是指:用户调用的是userService.GetByld(123),我底层框架怎么知道 userService, GetByld, 123这种信息?

做法1: 代码生成策略,如gRPC、go-micro

rpc项目创建 如何设计rpc_RPC_02


代码生成策略,代码写死的

做法2: 代理机制,如Dubbo

Go不支持动态代理,不支持动态生成新的类型,不支持动态加载。

代理模式

这里就要用到代理模式了:
定义一个结构体,为结构体里面的方法类型字段,注入调用逻辑。

要记住,Go 是没有办法修改方法实现的,所以我们只能迂回救国

rpc项目创建 如何设计rpc_客户端_03

我们约定:

  • 方法参数的第一个必须是 context.Context,
    第二个就是请求结构体指针,
    并且只有这两个参数;
  • 方法返回值的第一个是响应,并且必须是指针,
    第二个是 error,
    并且只有这两个返回值。

这种限制主要就是为了简化微服务框架的代码,在真实生产里面,你可以保持这个限制,也可以考虑去掉。