微服务的调用和接口

来源:互联网 发布:海岛奇研究所升级数据 编辑:程序博客网 时间:2024/04/20 04:17

微服务的调用和接口

 

 

微服务的调用:

 

微服务也是服务,我们一般认为微服务都是不同的实例提供的。这些实例通常和调用者运行在不同的进程中(根据部署模式不同,多个微服务实例到是有可能在一个进程中部署)。

 

当然,服务的消费者和服务实例本身,也可能是运行在同一个进程中,出现这种情况的目的可能是因为性能的需要,在J2EE、CORBA等时代,这些也是要设计和考虑的,但是,作为架构模式,微服务本来就是一种解耦的架构模式,大家也就基本上不考虑这种情况了。

 

在知道服务实例的位置的前提下,单纯从服务的消费者发起调用,到服务实例提供服务,再到服务消费者拿到结果的侠义范围来看,微服务其实就类似我们传统的RPC调用。微服务的范围当然包含更广泛的内容,我们把其他的先放在一边,先从PRC这个维度研究一下微服务的知识。

 

典型的调用过程如下:


服务函数下面的生命周期管理,序列化机制,应用层承载协议,以及TCP/IP通信都是为了模拟函数本地的调用场景,最终都是为调用一次服务函数而服务。

 

而举一个典型的本地调用函数的例子就类似:

function method_a(param1 : type1, param2 : type2) :type-of-result

 

对照上图,“数据序列化机制”就是负责将type1,type2, type-of-result的数据结构转换为网络上的传送格式,以及从网络上的传送格式转换为本地可调用的格式。

“应用层承载协议”负责界定那些数据是一次调用,区分到底调用的是那个函数,以及上述的各类序列化的数据结构如何放在一起,和别的调用区分出来,从而组成一个整体的通信数据块。并还有机制将返回的结果数据和调用数据关联起来。

“TCP/IP”通信负责将数据传送到服务提供方的机器,并将结果数据返回给调用方,它并不理解这些数据有什么特别的地方。当然“TCP/IP”只是常见选择,如果考虑到调用效率和时延,或者广播场景,选用“UDP”或别的通信协议也是可以的。

上述几层的常见实现如下:

能力

常见实现

数据序列化机制

Xml, json, thrift, protobuf, avro, 或者自定义格式

应用层承载协议

http, https, 自定义协议

Tcp/ip通信

各类通信库,例如:Netty,Mina,或者自己定制通信服务器

注:

1.      xml + http的组合,有SOAP规范;

2.      json+http的组合,有REST规范;

3.      Java二进制序列化+自定义协议的组合,有Java RMI规范。

 

微服务的接口:

 

说到微服务的接口,就不得不说到多编程语言(多语言)的问题了。为了支持多语言,我们看一下多语言场景对我们开发有什么影响:还是以上面的例子为例,看看不同语言下这个函数长啥样子:

C语言:

struct type-of-result method_a(type1 param1, type2 param2);

Java语言:

type-of-result method_a(type1 param1, type2 param2);

Go 语言:

func method_a(param1 type1, param2 type2) type-of-result;

 

可以看出来,虽然意思相同,不同的语言,这个函数长的样子还是差别蛮大的。

 

而不同语言调用远程的微服务的时候,总是有一个本地的函数对应才方便。借用RPC的概念,总是有一个对应的本地桩函数,这个桩函数长的和远程的函数样子一样,只是底层将能力委托给通信程序了。有了这个桩函数(接口),编译程序就能进行相关的类型检查,并安排调用了。当然,没有这个本地的桩函数理论上也是可以调用的,有了更加让人容易理解。如果是一个通用的RPC的测试工具,动态的调用各类函数,这种情况下恐怕就得动态的模拟各类调用了。

 

微服务接口的开发过程:

 

如果跨多语言场景下,该怎么给每种语言生成桩函数呢?

 

大家都想到了吧,能不能搞一个通用的描述语言呢,这个语言用于描述接口,并且用个工具一次性生成别的各种语言的函数原型以及数据结构原型多好!这就是通用的IDL接口定义语言,目前常见的通用IDL语言有如下的几种:

1.      微软的IDL

2.      OMG接口定义语言(RPM/COM/CORBA)

3.      Avro的IDL

4.      Thrift 的IDL

5.      Protobuf的IDL

6.      gRPC的IDL

7.      WSDL也是一种类似中立的IDL定义语言


好多呀,看起来学习一种编程语言还不够呀,还得学习IDL语言,好困难的样子。作为一个通用的多语言工具,定义一种新的IDL是个不错的想法,但是现实中的某一个应用(我是指实际的某个应用),恐怕也就两三种语言吧。这种情况下,每次都修改IDL,生成一遍各类代码,再修改相应的实现,有点麻烦。

 

如果都是一种语言的话,直接定义函数,然后做一些标志,如果就能发布服务的话,肯定方便很多。就类似Java的Spring框架,添加几个特殊的注释,框架就能识别你的意图,将剩下的事情干完了。或者约定一个目录,放进去的函数系统能自动的知道他们就是需要发布的函数,也很不错呀。这种方式比起上述的IDL方式肯定快捷许多。

我们来看看这种开发模式:


和上述先生成IDL再生成各语言代码的方式流程明显的不同之处在于:每个开发人员都按照自己熟悉的方式开发代码就可以了,想修改接口,直接改代码,立即编译就能看到结果。而各个接口之间的兼容性,就交给工具去做吧。这个工具可以在如下几个时候进行接口兼容性验证:

1.      每次编译代码时候;

2.      上传软件仓库时候;

3.      集成测试的时候;

4.      部署应用之前;

 

0 0