仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法

这篇具有很好参考价值的文章主要介绍了仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

仿 gRPC功能实现像调用本地方法一样调用其他服务器方法

简介

在介绍gRPC简介之前我们先了解一写概念:

单体架构

单体架构简单理解就是所有的业务代码都在一台服务器上,一旦某个服务宕机,会引起整个应用不可用,隔离性差。只能整体应用进行伸缩,例如整体打包部署一台或多台服务器,浪费资源,可伸缩性差。代码耦合在一起,可维护性差。

微服务架构

解决了单体架构的弊端。可按需拆成多个服务,例如针对用户的请求非常多,针对支付的请求少,可以将用户业务功能拆为多个服务器,支付业务功能拆为单个服务器。

也有一些弊端,例如代码冗余,同样的代码在多个服务器上都要写,例如接口等。服务与服务之间存在调用关系,服务拆分之后,就是服务和服务之间发生是进程与进程之间的调用,服务器与服务器之间的调用。

这时候就需要发起网络调用, 网络调用一般使用HTTP,但是在微服务架构中,HTTP虽然方便,但性能较低,这时候就需要引入RPC(远程过程调用),通过自定义协议发起TCP调用,来加快传输效率。

RPC

RPC的全称是Remote Procedure Call,远程过程调用。这是一种协议,是用来屏蔽分布式计算中的各种调用细节使得你可以像是本地调用一样直接调用一个远程的函数。

gPRC

gRPC 是一个高性能、开源和通用的RPC 框架,面向移动和 HTTP/2 设计。目前提供 CJavaGo 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHPC# 支持。

中文文档:http://doc.oschina.net/grpc

gRPC中,我们称调用方为client,被调用方为server。跟其他的RPC框架一样,gRPC也是基于服务定义的思想。简单的来讲,就是我们通过某种方式来描述一个服务,这种描述方式是语言无关的。在这个服务定义的过程中,我们描述了我们提供的服务服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。

也就是说,在定义好了这些服务、这些方法之后,gRPC会屏蔽底层的细节,client只需要直接调用定义好的方法,就能拿到预期的返回结果。对于server端来说,还需要实现我们定义的方法。同样的,gRPC也会帮我们屏蔽底层的细节,我们只需要实现所定义的方法的具体逻辑即可。

可以发现,在上面的描述过程中,所谓的服务定义,就跟定义接口的语义是很接近的。我更愿意理解为这是一种"约定”,双方约定好接口,然后server实现这个接口,client调用这个接口的代理对象。到于其他的细节,交给gRPC

gRPC交互逻辑

服务端逻辑
  • 创建gRPC Server对象,可以理解为它是Server端的抽象对象。
  • server(其包含需要被调用的服务端接口)注册到gRPC Server的内部注册中心。
    • 这样可以在接受到请求时,通过内部的服务发现。发现该服务端接口并转接进行逻辑处理。
  • 创建Listen,监听TCP端口。
  • gRPC Server开始lis.Accept,直到Stop
客户端逻辑
  • 创建与给定目标服务端的连接交互。
  • 创建server的客户端对象。
  • 发送RPC请求,等待同步响应,得到回调后返回响应结果。
  • 输出响应结里。
示例图

如下图:业务服务器调用登录业务服务器,支付服务器,库存服务器。

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法,M 使用方案,IRIS,Cache,M,gRPC,socket

原生实现仿gRPC框架

因为gRPC框架目前不支持IRIS/Caché,所以这里我们了解gRPC原理后,仿造gRPC框架实现类似的功能。通过正常编写代码无感知的情况下调用其他服务器上的代码方法。

注:为了显示这里使用Caché作为客户端,IRIS作为服务端。

编写客户端方法
  1. 首先在客户端也就是调用端创建客户端类Util.RPC.Client,代码如下:
    • %DispatchClassMethod - 动态派发方法是实现无感知的关键。
    • SERVERIP - 目标服务端的IP地址。
    • PORT - 目标服务端的端口号。
Class Util.RPC.Client Extends %RegisteredObject
{

Parameter SERVERIP = "127.0.0.1";

Parameter PORT = 7788;

ClassMethod %DispatchClassMethod(class As %String, method As %String, args...) [ ServerOnly = 1 ]
{
	
	#; 客户端通信、客户端需要设置服务器IP与端口号
	#dim clientSocket As %IO.Socket = ##class(%IO.Socket).%New()
	s host = ..#SERVERIP
	s port = ..#PORT
	s clientSocket.TranslationTable = "UTF8"
	
	d clientSocket.Open(host, port, .sc)
	
	s obj = {}	//注释1
	s obj.class = class
	s obj.method = method
	
	s params = []
	
	s i = ""
	for {
		s i = $o(args(i))
		q:(i = "")
		d params.%Push(args(i))
	}
	
	s obj.params = params
	d clientSocket.WriteLine(obj.%ToJSON())	//注释2
	
	while (1) {

		s data = clientSocket.ReadLine() 
		if (data '= "" ){	//注释3
			ret data
		}
		
	}
	
	q $$$OK
}

}
  1. 创建空类M.LoginM.PayM.Stock分别继承Util.RPC.Client
    • 目的是模拟交互接口,因为要调用其他服务器方法,首先要确定要调用的服务器接口名称。

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法,M 使用方案,IRIS,Cache,M,gRPC,socket

  1. 按照常规调用方法的模式,来编写方法。

    • 这里实际上是没有LoginPayStock方法的,因为上一步创建的类为空类。

    • 如果按照常规直接调用方法肯定会提示方法不存在的错误,这里实际上我们调用的是服务端的方法。

    • 可以观察到,这里是按照正常调用类方法的方式编写的代码,并没有其他额外的操作。

Class M.RPC Extends %RegisteredObject
{

/// d ##class(M.RPC).Biz()
ClassMethod Biz()
{
	w ##class(M.Login).Login("yx","123456"),!
	w ##class(M.Pay).Pay(100),!
	w ##class(M.Stock).Stock(3),!
}

}
编写服务端方法
  1. 创建服务端监听Util.RPC.Server类,这里模拟的是gRPC 创建Server对象,创建Listen,监听TCP端口。代码如下:
    • 参数PORT为服务端监听和开启的接口。
Class Util.RPC.Server Extends %RegisteredObject
{

Parameter PORT = 7788;

/// d ##class(Util.RPC.Server).ServerRPC()
ClassMethod ServerRPC()
{
	#; 服务端通信、服务端需要打开端口,等待客户端通信
	#dim severSocket As %IO.ServerSocket = ##class(%IO.ServerSocket).%New()
	s port = ..#PORT
	s severSocket.TranslationTable="UTF8"
	s severSocket.ConnectionQueueSize = 2
	
	d severSocket.Open(port, 10, .sc)
	q:($$$ISERR(sc)) "Open:" _ $System.Status.GetOneErrorText(sc)
	
	d severSocket.Listen(10, .sc)
	q:($$$ISERR(sc)) "Listen:" _ $System.Status.GetOneErrorText(sc)
	
	while (1) {
		s data =  severSocket.ReadLine()
		if (data '= "") {
			s obj = {}.%FromJSON(data)	//注释1
			s arg = obj.params.%Size()
			for i = 1 : 1 : arg{
				s arg(i) = obj.params.%Get(i - 1)
			}
			s ret = $classmethod(obj.class, obj.method, arg...)	//注释2
			d severSocket.WriteLine(ret)	//注释3
		}
	}

	q $$$OK
}

}
  1. 编写服务端M.LoginLogin方法,M.PayPay方法,M.StockStock方法。

    • 这里使用IRIS当服务端,实现的方法都在服务端,客户端是没有该方法的。

    • 客户端调用的方法实际上是服务端的上的方法。

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法,M 使用方案,IRIS,Cache,M,gRPC,socket

综合演示
  1. IRIS服务端开启监听方法。

  2. 客户端Caché调用无感知业务逻辑业务员Biz()方法。

    • 可观察到客户端直接调用到了服务端的方法,并且编码方式跟正常编写代码并无差别。

    • 客户端不需要了解底层的细节,client只需要直接调用定义好的方法。

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法,M 使用方案,IRIS,Cache,M,gRPC,socket

通过这种方式我们就实现了类似gRPC的功能,像正常编写代码一样调用服务端的程序。

创造价值,分享学习,一起成长,相伴前行,欢迎大家提出意见,共同交流。文章来源地址https://www.toymoban.com/news/detail-702864.html

到了这里,关于仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包