微服务与RPC问题汇总
微服务与RPC问题汇总
1. 什么是微服务?
wiki:微服务(英语:Microservices)是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic)的API集相互通信。
简单来说,微服务的架构风格就是将单个应用程序作为一组小型服务来开发,每个服务程序都在自己的进程中运行,并以轻量级通信方式进行通信。这些服务可以使用不同的编程语言编写,使用不同的数据存储技术,并尽量不用集中式方式进行管理。
用一句话来概括就是“分而治之,合而用之”。
2. 微服务与单体架构的对比?
单体架构的缺点如下:
- 复杂度随时间不断变大,代码量到几十万行的大项目难以维护;
- 技术债务逐渐上升,留下的bug越来越多;
- 耦合度太高,维护成本大——修复bug的时候引入新的bug;
- 部署、交付的时间长,新人熟悉环境、业务的时间越来越长;
- 技术选型成本高,后面想要引入新的技术或框架,成本和风险都很高;
- 可扩展性差。
微服务架构的优点如下:
- 单一职责。每个服务都有自己独立的业务逻辑,是一个高内聚、低耦合、单一原则的单元。
- 轻量级通信。服务之间用过轻量级的通信机制实现互联互通,通常是语言无关、平台无关的交互方式;
- 独立性。每个服务可以独立地进行开发、测试和部署;
- 进程隔离。每个服务高度自治,可以部署到不同的主机上。当其中一个服务挂掉时,不会影响其他服务。
当然,微服务也有它的不足之处:
- 运行维护困难,任意一个模块的问题,可能会影响整个项目,debug困难;
- 分布式的复杂性。会使得项目变得更复杂;
- 接口成本高,若接口发生大变动,所有依赖的微服务都要发生调整;
- 重复劳动。某段业务多个模块共同使用,如果是单体架构,可以抽象为一个工具类。但是微服务架构中每个服务都可能需要,会导致代码重复;
- 业务不好分离。程序员对业务理解可能不同。
3. 什么是RPC?
RPC(Remote Procedure Call Protocol)是远程过程调用的缩写。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。
比如,我们写这样一个代码:
1 |
|
它会调用远程的(另一个进程,很可能在另一台服务器上)函数:
1 |
|
4. 为什么微服务需要RPC
使用微服务的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现公司跨团队的技术解耦。但是这样子,如果没有一个统一的服务框架——RPC框架,则各个团队需要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理等业务之外的重复技术劳动。统一RPC框架将上述的劳动进行了统一处理。
5. RPC的底层原理
一个完整的RPC主要包括三部分:
服务注册中心(Registry),负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。
服务提供者(RPC Server),负责提供服务接口定义与服务实现类。
服务消费者(RPC Client),负责通过远程代理对象调用远程服务。
服务提供者(Server)启动后主动向服务注册中心(Registry)注册机器IP、端口以及提供的服务列表;服务消费者(Client)启动时向服务注册中心(Registry)获取服务提供方地址列表;服务注册中心(Registry)可实现负载均衡和故障切换。

RPC调用过程为:
- 客户端想要发起一个远程过程调用,首先通过调用本地客户端Stub程序的方式调用想要使用的功能方法名;
- 客户端Stub程序接收到了客户端的功能调用请求,将客户端请求调用的方法名,携带的参数等信息做序列化操作,并打包成数据包。
- 客户端Stub查找到远程服务器程序的IP地址,调用Socket通信协议,通过网络发送给服务端。
- 服务端Stub程序接收到客户端发送的数据包信息,并通过约定好的协议将数据进行反序列化,得到请求的方法名和请求参数等信息。
- 服务端Stub程序准备相关数据,调用本地Server对应的功能方法进行,并传入相应的参数,进行业务处理。
- 服务端程序根据已有业务逻辑执行调用过程,待业务执行结束,将执行结果返回给服务端Stub程序。
- 服务端Stub程序将程序调用结果按照约定的协议进行序列化,并通过网络发送回客户端Stub程序。
- 客户端Stub程序接收到服务端Stub发送的返回数据,对数据进行反序列化操作,并将调用返回的数据传递给客户端请求发起者。
- 客户端请求发起者得到调用结果,整个RPC调用过程结束。
RPC要面临的三个问题:
(1)Call ID映射。本地调用中,函数体是直接通过函数指针来指定的,调用函数时,编译器会自动调用它相应的函数指针。但在远程调用中,函数指针是不行的,因为两个进程的地址空间完全不一样。所以,在RPC中所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个 {函数 :Call ID} 的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查该表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
(2)序列化和反序列化。客户端如何将参数值传给远程的函数就成了一个问题在本地调用中,只需要把参数压到栈里,函数自己去栈里读即可。在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化(也叫编码和解码)。同理,从服务端返回的值也需要序列化反序列化的过程。
(3)网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而gRPC干脆就用了HTTP2,Java的Netty也属于这层的东西。
RPC与HTTP协议的对比
RPC | HTTP | |
---|---|---|
传输协议 | 可以基于TCP协议,也可以基于HTTP协议 | 基于HTTP协议 |
传输效率 | RPC使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率 | 如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装一下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理 |
性能消耗 | 可以基于thrift实现高效的二进制传输 | 大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能 |
负载均衡 | 基本都自带了负载均衡策略 | 需要配置Nginx,HAProxy来实现 |
服务治理 | 能做到自动通知,不影响上游 | 需要事先通知,修改Nginx/HAProxy配置 |
总结 | 主要用于公司内部的服务调用,性能消耗低,传输效率高,服务治理方便。 | 主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。 |
6. 什么是ProtoBuf
Protocol Buffers (Protobuf) 是一种谷歌开发的二进制通信格式,用于序列化结构数据,截至目前,谷歌使用 protobuf 已经超过十年了。 Protobuf 的出现并不是为了解决新的问题,而是用更加现代的方式让网络传输更加高效,总的来说它有如下几个特点:
- 是二进制格式,而不是像 JSON 与 XML 是基于文本的,因此非常节省空间。
- 对各种模式丰富且易上手的支持。
- 支持多种语言下的解析。
原理:
使用varint来表示数字,越小的数字占用越少的字节数。
使用msb(最高有效位)来进行标识,当msb为1时,下一个字节继续表示这个数字;当msb为0时,这是最后一个字节。
对于字符串而言,不需要msb,因为有表示string长度的字段。
具体流程(以数字2009为例):
将2009 转换为二进制 11111011001
将其分割为 0001111 1011001
反转其顺序 1011001 0001111
添加 MSB 标识为 01011001 00001111
设置MSB ,11011001 00001111
最后用16进制表示为 D9 0F
小结:
- 在微服务之间通信时,protobuf 更合适,在公开 API 或与浏览器通信时JSON 与 xml 更合适。
- protobuf 更加节省空间,高效。
- protobuf 放弃了可读性。
- protobuf 使用的编码方式可以使数据更加紧凑。
- protobuf 依赖生成的代码,需要一个protobuf 编译器根据你编写的 .proto 定义的数据生成,也称作消息。
- 你可以根据生成的代码初始化或解析发生的数据或接受的数据。
7. 几种框架的对比
待续
参考资料
[1] https://blog.csdn.net/weixin_46742102/article/details/112169275
[2] https://blog.csdn.net/weixin_41667472/article/details/124703669
[3] https://zh.wikipedia.org/zh-cn/%E5%BE%AE%E6%9C%8D%E5%8B%99