gorpc跨语言 跨语言开发平台

当前主流的RPC框架有哪些主流RPC框架你都可以百度或Google到 , 种类繁多 。RPC原理很简单,目的也很简单 , 依个人感觉来看,RPC框架慢慢分为了两个走向:1.跨语言调用型,就是你提到的Thrift,Grpc之类的;2.服务治理型的,典型代表就是Ali的Dubbo,最近新浪微博的Motan开源,也是偏向这一类型的 。哪个更容易上手的问题,我感觉需要看你更偏重于哪方面,如果需要服务发现服务治理之类的,当然用dubbox之类的啊 。总之一句话 , RPC的实质就是 , 咱俩虽然不在一起 , 但我要使用你,就衍生出了这一些列的框架了 。如果有说错的地方欢迎讨论 。
RPC协议及实现方式(分布式微服务治理的核心) 分布式微服务治理gorpc跨语言的核心在于:微服务和分布式
Remote Procedure Call,翻译过来应该是“远程程序调用” , 目前业内通用的翻译是“远程过程调用”,但是“过程”这个词很容易造成误解,翻译成“程序”更好理解RPC的意义 。
一般所谓的XX协议就是个文档,类似于gorpc跨语言我们的需求文档,只说gorpc跨语言了要做什么,但是具体怎么做是由各大开源大佬做的 。一般情况下都会实现核心功能,不同的开源在细节上实现都会不一样,这个需要注意gorpc跨语言!
RPC 这个概念术语在上世纪 80 年代由 Bruce Jay Nelson 提出的,在 Nelson 的论文 "Implementing Remote Procedure Calls" 中 , 他提到了几个 RPC的特点 :
除此之外,这位大佬还给出了实现RPC框架的 详细架构图 :
结合上图 , Nelson 的论文中指出实现 RPC 的程序包括 5 个部分:
所以这架构图的意思是:当 user 想发起一个远程调用时,它实际是通过本地调用 User-stub 。并通过本地的RPCRuntime传输。远端 RPCRuntime 实例收到请求后交给 Server-stub 进行解码后发起本地端调用,调用结果再返回给 User 端 。
看完协议内容,跟着就得实现这个协议啦,这时候你是不是发现了问题的严重性: 自!己!一!点!思!路!都!没!有!
所以我们需要再理解一下RPC协议,根据Nelson的论文知道我们要做的两件事:
上述两点其实是实现RPC协议的两大要素: 序列化协议和传输协议。
因为RPC本质上是进程间通信,而“本地调用和远程调用的对比”实际上就是“进程内通信和进程间通信的对比” 。通过两者的对比,我们才能理解到 序列化协议和传输协议 的作用,如下图:
最基本的RPC框架就是 单点式 的 , 因为A服务直接调用B服务,不经过第三方,这种是最简单的 。但是必须是A和B同时部署一套,A1只能调用B1,A2只能调用B2 。
所以需要一台A服务对多台B服务,利用第三方服务(注册中心)找到其他B服务 , 而不是写死B服务的地址 。这种RPC才是 分布式 RPC,也是业内主流 。
单点RPC框架只需要:
但是我们要做分布式的啊,所以需要:
实际上在生产环境中,我们需要实时监控服务的调用情况,所以需要一个微服务管理中心,甚至是一个自动化运维的管理中心 , 所以需要:
在文章的第二节我们看到大佬论文中对RPC的总结 , 其中一个很重要的一点:“通用” 。
所以我们需要:
对的 , 能实现上述五点的,才是一个合格的RPC框架,但还不是优秀,因为我们还要考虑下性能 。
先打个底,目前流行的RPC框架大多都是多管闲事,不单单只是RPC框架 , 你可以看看Dubbo和SpringCloud中除了RPC还有什么骚功能 。
可以看看别人的各种RPC框架总结:
在网上找到了个图,但是没有提到SpringCloud,暂且看看先,因为有些不认为是对的:
我们可以看到各个RPC框架使用的序列化协议,注册中心,管理中心,是否跨语言,但是传输协议没有提到 。
参考这篇博客:
综合来说,在性能上rpcx是首?。?但是考虑到框架的生态,其实还是推荐Dubbo或者SpringCloud的,因为除了性能 , 成本也是很重要的,无论是学习成本还是研发成本 。
一学就会,手把手教你用Go语言调用智能合约智能合约调用是实现一个 DApp 的关键,一个完整的 DApp 包括前端、后端、智能合约及区块 链系统,智能合约的调用是连接区块链与前后端的关键 。
我们先来了解一下智能合约调用的基础原理 。智能合约运行在以太坊节点的 EVM 中 。因此要 想调用合约必须要访问某个节点 。
以后端程序为例,后端服务若想连接节点有两种可能,一种是双 方在同一主机,此时后端连接节点可以采用 本地 IPC(Inter-Process Communication,进 程间通信)机制,也可以采用 RPC(Remote Procedure Call,远程过程调用)机制;另 一种情况是双方不在同一台主机,此时只能采用 RPC 机制进行通信 。
提到 RPC,读者应该对 Geth 启动参数有点印象,Geth 启动时可以选择开启 RPC 服务 , 对应的 默认服务端口是 8545 。。
接着,我们来了解一下智能合约运行的过程 。
智能合约的运行过程是后端服务连接某节点,将 智能合约的调用(交易)发送给节点 , 节点在验证了交易的合法性后进行全网广播,被矿工打包到 区块中代表此交易得到确认 , 至此交易才算完成 。
就像数据库一样,每个区块链平台都会提供主流 开发语言的 SDK(Software Development Kit,软件开发工具包),由于 Geth 本身就是用 Go 语言 编写的 , 因此若想使用 Go 语言连接节点、发交易,直接在工程内导入 go-ethereum(Geth 源码) 包就可以了,剩下的问题就是流程和 API 的事情了 。
总结一下,智能合约被调用的两个关键点是节点和 SDK 。
由于 IPC 要求后端与节点必须在同一主机 , 所以很多时候开发者都会采用 RPC 模式 。除了 RPC,以太坊也为开发者提供了 json- rpc 接口,本文就不展开讨论了 。
接下来介绍如何使用 Go 语言,借助 go-ethereum 源码库来实现智能合约的调用 。这是有固定 步骤的,我们先来说一下总体步骤,以下面的合约为例 。
步骤 01:编译合约 , 获取合约 ABI(Application Binary Interface,应用二进制接口) 。单击【ABI】按钮拷贝合约 ABI 信息,将其粘贴到文件 calldemo.abi 中(可使用 Go 语言IDE 创建该文件,文件名可自定义,后缀最好使用 abi) 。
最好能将 calldemo.abi 单独保存在一个目录下,输入“ls”命令只能看到 calldemo.abi 文件 , 参 考效果如下:
【gorpc跨语言 跨语言开发平台】步骤 02:获得合约地址 。注意要将合约部署到 Geth 节点 。因此 Environment 选择为 Web3 Provider 。
在【Environment】选项框中选择“Web3 Provider”,然后单击【Deploy】按钮 。
部署后,获得合约地址为:0xa09209c28AEf59a4653b905792a9a910E78E7407 。
步骤 03:利用 abigen 工具(Geth 工具包内的可执行程序)编译智能合约为 Go 代码 。abigen 工具的作用是将 abi 文件转换为 Go 代码 , 命令如下:
其中各参数的含义如下 。(1)abi:是指定传入的 abi 文件 。(2)type:是指定输出文件中的基本结构类型 。(3)pkg:指定输出文件 package 名称 。(4)out:指定输出文件名 。执行后,将在代码目录下看到 funcdemo.go 文件,读者可以打开该文件欣赏一下 , 注意不要修改它 。
步骤 04:创建 main.go , 填入如下代码 。注意代码中 HexToAddress 函数内要传入该合约部署后的地址,此地址在步骤 01 中获得 。
步骤 04:设置 go mod , 以便工程自动识别 。
前面有所提及,若要使用 Go 语言调用智能合约,需要下载 go-ethereum 工程,可以使用下面 的指令:
该指令会自动将 go-ethereum 下载到“$GOPATH/src/github.com/ethereum/go-ethereum” , 这样还算 不错 。不过 , Go 语言自 1.11 版本后,增加了 module 管理工程的模式 。只要设置好了 go mod,下载 依赖工程的事情就不必关心了 。
接下来设置 module 生效和 GOPROXY,命令如下:
在项目工程内,执行初始化 , calldemo 可以自定义名称 。
步骤 05:运行代码 。执行代码,将看到下面的效果,以及最终输出的 2020 。
上述输出信息中,可以看到 Go 语言会自动下载依赖文件,这就是 go mod 的神奇之处 。看到 2020,相信读者也知道运行结果是正确的了 。
主流的RPC框架有哪些?RPC是远程过程调用的简称,广泛应用在大规模分布式应用中 , 作用是有助于系统的垂直拆分,使系统更易拓展 。Java中的RPC框架比较多,各有特色,广泛使用的有RMI、Hessian、Dubbo等 。RPC还有一个特点就是能够跨语言 。
1、RMI(远程方法调用)
JAVA自带的远程方法调用工具 , 不过有一定的局限性,毕竟是JAVA语言最开始时的设计,后来很多框架的原理都基于RMI,RMI的使用如下:
对外接口
span style="font-size:12px;"public interface IService extends Remote {
public String queryName(String no) throws RemoteException;
}/span
服务实现
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// 服务实现
public class ServiceImpl extends UnicastRemoteObject implements IService {
/**
*/
private static final long serialVersionUID = 682805210518738166L;
/**
* @throws RemoteException
*/
protected ServiceImpl() throws RemoteException {
super();
}
/* (non-Javadoc)
* @see com.suning.ebuy.wd.web.IService#queryName(java.lang.String)
*/
@Override
public String queryName(String no) throws RemoteException {
// 方法的具体实现
System.out.println("hello"no);
return String.valueOf(System.currentTimeMillis());
}
}
RMI客户端
[java] view plain copy
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
// RMI客户端
public class Client {
public static void main(String[] args) {
// 注册管理器
Registry registry = null;
try {
// 获取服务注册管理器
registry = LocateRegistry.getRegistry("127.0.0.1",8088);
// 列出所有注册的服务
String[] list = registry.list();
for(String s : list){
System.out.println(s);
}
} catch (RemoteException e) {
}
try {
// 根据命名获取服务
IService server = (IService) registry.lookup("vince");
// 调用远程方法
String result = server.queryName("ha ha ha ha");
// 输出调用结果
System.out.println("result from remote : "result);
} catch (AccessException e) {
} catch (RemoteException e) {
} catch (NotBoundException e) {
}
}
}
RMI服务端
[java] view plain copy
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
// RMI服务端
public class Server {
public static void main(String[] args) {
// 注册管理器
Registry registry = null;
try {
// 创建一个服务注册管理器
registry = LocateRegistry.createRegistry(8088);
} catch (RemoteException e) {
}
try {
// 创建一个服务
ServiceImpl server = new ServiceImpl();
// 将服务绑定命名
registry.rebind("vince", server);
System.out.println("bind server");
} catch (RemoteException e) {
}
}
}
2、Hessian(基于HTTP的远程方法调用)
基于HTTP协议传输,在性能方面还不够完美,负载均衡和失效转移依赖于应用的负载均衡器,Hessian的使用则与RMI类似,区别在于淡化了Registry的角色,通过显示的地址调用 , 利用HessianProxyFactory根据配置的地址create一个代理对象,另外还要引入Hessian的Jar包 。
3、Dubbo(淘宝开源的基于TCP的RPC框架)
基于Netty的高性能RPC框架,是阿里巴巴开源的,总体原理如下:
微服务跨语言调用(摘?。?/h2>微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面 。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架 。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,python,go 多语言调用的问题 。
跨语言调用是一个很大的话题,也是一个很有挑战的技术活,目前业界经常被提及的解决方案有如下几种 , 不妨拿出来老生常谈一番:
当我们再聊跨语言调用时我们在聊什么?纵观上述几个较为通用,成熟的解决方案,可以得出结论:解决跨语言调用的思路无非是两种:
如果一个新型的团队面临技术选型,我认为上述的方案都可以纳入参考,可考虑到遗留系统的兼容性问题
旧系统的迁移成本
这也关键的选型因素 。我们做出的第一个尝试,便是在 RPC 协议上下功夫 。
通用协议的跨语言支持
springmvc的美好时代
springmvc
springmvc
在没有实现真正的跨语言调用之前,想要实现“跨语言”大多数方案是使用 http 协议做一层转换,最常见的手段莫过于借助 springmvc 提供的 controller/restController,间接调用 dubbo provider 。这种方案的优势和劣势显而易见
通用协议的支持
事实上,大多数服务治理框架都支持多种协议 , dubbo 框架除默认的 dubbo 协议之外,还有当当网扩展的 rest协议和千米网扩展的 json-rpc 协议可供选择 。这两者都是通用的跨语言协议 。
rest 协议为满足 JAX-RS 2.0 标准规范,在开发过程中引入了 @Path,@POST,@GET 等注解,习惯于编写传统 rpc 接口的人可能不太习惯 rest 风格的 rpc 接口 。一方面这样会影响开发体验,另一方面 , 独树一帜的接口风格使得它与其他协议不太兼容,旧接口的共生和迁移都无法实现 。如果没有遗留系统,rest 协议无疑是跨语言方案最简易的实现,绝大多数语言支持 rest 协议 。
和 rest 协议类似,json-rpc 的实现也是文本序列化http 协议 。dubbox 在 restful 接口上已经做出了尝试,但是 rest 架构和 dubbo 原有的 rpc 架构是有区别的 , rest 架构需要对资源(Resources)进行定义,需要用到 http 协议的基本操作 GET、POST、PUT、DELETE 。在我们看来,restful 更合适互联网系统之间的调用 , 而 rpc 更适合一个系统内的调用 。使用 json-rpc 协议使得旧接口得以兼顾,开发习惯仍旧保留,同时获得了跨语言的能力 。
千米网在早期实践中采用了 json-rpc 作为 dubbo 的跨语言协议实现,并开源了基于 json-rpc 协议下的 python 客户端 dubbo-client-py 和 node 客户端 dubbo-node-client,使用 python 和 nodejs 的小伙伴可以借助于它们直接调用 dubbo-provider-java 提供的 rpc 服务 。系统中大多数 java 服务之间的互相调用还是以 dubbo 协议为主,考虑到新旧协议的适配,在不影响原有服务的基础上,我们配置了双协议 。
dubbo 协议主要支持 java 间的相互调用,适配老接口;json-rpc 协议主要支持异构语言的调用 。
定制协议的跨语言支持
微服务框架所谓的协议(protocol)可以简单理解为:报文格式和序列化方案 。服务治理框架一般都提供了众多的协议配置项供使用者选择,除去上述两种通用协议,还存在一些定制化的协议 , 如 dubbo 框架的默认协议:dubbo 协议以及 motan 框架提供的跨语言协议:motan2 。
motan2协议的跨语言支持
motan2
motan2
motan2 协议被设计用来满足跨语言的需求主要体现在两个细节中—MetaData 和 motan-go 。在最初的 motan 协议中,协议报文仅由 Header Body 组成 , 这样导致 path,param,group 等存储在 Body 中的数据需要反序列得到,这对异构语言来说是很不友好的,所以在 motan2 中修改了协议的组成;weibo 开源了 motan-go ,motan-php , motan-openresty ,并借助于 motan-go 充当了 agent 这一翻译官的角色,使用 simple 序列化方案来序列化协议报文的 Body 部分(simple 序列化是一种较弱的序列化方案) 。
agent
agent
仔细揣摩下可以发现这么做和双协议的配置区别并不是大,只不过这里的 agent 是隐式存在的,与主服务共生 。明显的区别在于 agent 方案中异构语言并不直接交互 。
dubbo协议的跨语言支持
dubbo 协议设计之初只考虑到了常规的 rpc 调用场景 , 它并不是为跨语言而设计,但跨语言支持从来不是只有支持、不支持两种选择 , 而是要按难易程度来划分 。是的,dubbo 协议的跨语言调用可能并不好做,但并非无法实现 。千米网便实现了这一点,nodejs 构建的前端业务是异构语言的主战场 , 最终实现了 dubbo2.js,打通了 nodejs 和原生 dubbo 协议 。作为本文第二部分的核心内容,重点介绍下我们使用 dubbo2.js 干了什么事 。
Dubbo协议报文格式
dubbo协议
dubbo协议
dubbo协议报文消息头详解:
magic:类似java字节码文件里的魔数,用来判断是不是 dubbo 协议的数据包 。魔数是常量 0xdabb
flag:标志位, 一共8个地址位 。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为 1 表示是 request 请求,第二位为 1 表示双向传输(即有返回 response),第三位为 1 表示是心跳 ping 事件 。
status:状态位, 设置请求响应状态,dubbo 定义了一些响应的类型 。具体类型见com.alibaba.dubbo.remoting.exchange.Response
invoke id:消息 id, long 类型 。每一个请求的唯一识别 id(由于采用异步通讯的方式,用来把请求 request 和返回的 response 对应上)
body length:消息体 body 长度, int 类型,即记录 Body Content 有多少个字节
body content:请求参数 , 响应参数的抽象序列化之后存储于此 。
协议报文最终都会变成字节 , 使用 tcp 传输,任何语言只要支持网络模块,有类似 Socket 之类的封装 , 那么通信就不成问题 。那,跨语言难在哪儿?以其他语言调用 java 来说,主要有两个难点:
ps:dubbo 协议通讯demo()
gorpc跨语言的介绍就聊到这里吧 , 感谢你花时间阅读本站内容,更多关于跨语言开发平台、gorpc跨语言的信息别忘了在本站进行查找喔 。

    推荐阅读