分布式API设计 上

原创
11/27 10:20
阅读数 1.6K
AI总结

背景

 
  • 当作为一个架构师,选择分布式API框架,你需要注意哪些事项
  • 当你作为一个服务提供者,提供分布式API,你需要注意哪些事项,至少有10点。
  • 当你需要调用一个分布式API,你需要注意哪些事项,至少有10点。
  • 当调用出现故障或者性能优化问题,有哪些思路解决
 

分布式API

软件世界,是通过API互相链接,这些API或者是进程内的API,或者是分布式API,通过这些API,构造出精彩的复杂的企业应用,互联网世界,物联网世界。学习完本节后,当你是调用一个分布式API的时候,你会掌握API调用最佳实践,当你提供一个分布式API时候,你会清楚API设计原则,本章覆盖如下内容
  • 分布式API的技术选型
  • REST API 设计原则 (参考 远程调用API设计 下:REST,待定)

面向架构质量的设计

我们知道,架构主要目标是对软件系统分解成较小更容易实现的元素,如模块或者子系统,并能让这些元素协同完成业务需求,对于通常的程序员视角来说,架构貌似就是画几个框,然后连上线即可。
如下是一个分布式系统最简单的架构。看着很简单的俩框一线,但架构师却需要考虑的非常多,这也是架构师和普通程序员区别
 
A 服务的架构师需要考虑
  • 如果服务 B 不可用,服务 A 如何保证高可用。比如宕机,故障,虚机漂移,网络故障
  • 如果服务 B 出现阻塞,性能下降,服务 A 如何保性能不受影响
  • 服务 A 调用服务 B,是否一定需要等待服务 B 的响应,能否解耦 A 和 B 调用,避免前面 2 个问题
  • 服务 A 如果是通过其寻址服务到 B,如果寻址服务不可用,如何调用服务 B
  • 如果服务B更新了API,服务A未同步更新(兼容)
B 服务作为服务提供者,架构师需要考虑的更多
  • 如何保证服务 B 支持大并发的操作,包括自身支持大并发,以及依赖的下游支持
  • 如何保证服务 B 支持大流量操作,甚至是不正常突发高流量下仍然可用,比如断网恢复后的高流量
  • 如果服务 B 的下游不可用,如何给服务 A 提供可用接口
  • 服务 B 的更新重启,会对服务 A 产生什么样的影响
  • 如何可观测服务 B 的调用
  • 如果服务 B 是公网服务,如何保证安全,数据被授权用户获取
  • 如果服务B更新了API,服务A未及时更新(兼容考虑)
B 服务架构师还需要考虑意外情况,如服务 A 的 BUG
  • 服务 A 应该只调用服务 B 一次,但实际服务 A 调用了多次
  • 服务 A 调用频率应该是 1 分钟一次,但实际 1 秒一次
  • 服务 A 应该先后顺序调用 B 俩次不同接口,但调用顺序相反。这种可能是 A 的 Bug,或者是事件驱动架构里顺序问题。
对这种 “俩框一线” 如此简单的架构,可以看到架构师相比于初级程序员,需要考虑较多,需要考虑 10 + 种情况。这种考虑其实也不是架构师挠秃头发想到的,而是基于技术架构的架构质量考虑的,有种说法,说是架构质量驱动了架构设计(ADD)。

分布式API的架构

分布式API建立在俩类协议基础上:
  • TCP协议,使用这类协议的分布式API有Dubbo,RMI(EJB),gRPC,Thrift等,这列分布式API具有良好的性能,延迟都在1毫秒级,适用于系统内部微服务之间调用。其缺点是不易被观察。
  • 基于HTTP协议,比如REST,SOAP建立在HTTP协议基础上,HTTP协议高可用和高性能,内置安全,并且支持跨内外网调用。而且HTTP上的调用易于被观测,如,通过HTTP代理观测,或者HTTP日志进行业务统计。因此基于HTTP的REST等API技术框架逐渐成为现在流行的分布式调用方式,适用于系统之间,用户和系统之间的调用。 基于REST调用延迟通常相对TCP方式的协议较大,即使内网之间调用,延迟在10+毫秒。对于需要毫秒级延迟的场景,REST协议不合适
分布式API 通常有如下协议栈
 
  • Client API ,以Java接口形式体现
  • Client Stub,扮演了客户端的Gateway,通常会将调用的目标类,参数等封装成指定协议的报文,调用底层transport。Client Stub有负责寻址,调用分布式服务端的节点,并等待返回结果返回调用者
  • Client Transport: 负责传输部分,客户端报文到服务器端
  • Server Transport 负责接收客户端报文
  • Server Skeleton:负责把报文反序列化成调用参数,并调用实际的实现类Service Impl
  • Service Impl:接口实现类

分布式API设计通用考虑

下面列出了系统常使用的分布式API技术的公共特性
API技术
 
基础协议
 
报文格式
 
语言支持
性能
内网/外网
可观测
 
通信方式
API Schema
负载均衡
 
REST
 
HTTP
JSON
 
通用
一般
内网/外网
 
容易
 
同步
 
支持
 
Nginx等HTTP代理
Spring Feigh
HTTP
JSON
 
通用
一般
内网/外网
 
容易
 
同步
 
支持
 
客户端
RMI
TCP/HTTP
RMI
Java
一般
内网/外网
二次开发
同步
支持
客户端
gRPC
 
TCP/ HTTP
 
Protobuf
常用语言支持
 
内网/外网
 
二次开发
同步,异步,服务端推送
支持
 
客户端或者代理
Dubbo
TCP/HTTP
多种
 
常用语言支持
内网/外网
 
二次开发
同步,异步
 
客户端或者代理
SOAP
HTTP
XML
通用
一般
内网/外网
容易
同步,异步
支持
Nginx等HTTP代理
WebSocket
HTTP
文本或者二进制,XML/JSON
通用
内网/外网
容易
同步,异步
Nginx等HTTP代理
 
  • 基础协议: 通常区分TCP或者HTTP,构建在HTTP基础上的分布式API,适用于系统之间或者内外网之间调用,直接构建在TCP上的协议通常性能更好,适用于内网之间调用,构建在TCP协议上的分布式API通常有更好的性能。目前基于TCP的分布式API都开始支持基于HTTP,以方便互联网调用而不是企业内网的调用。如RMI,Dubbo,gRPC
  • 报文格式:通常文本格式更方便阅读,二进制格式性能更好。JSON相比与XML文本格式,性能也更好。报文格式以影响兼容性,这点非常重要,XML和JSON方式天然能实现向前,向后兼容,二进制则依赖序列化协议是否支持兼容。比如Hession,gPRC支持兼容,fury依赖配置以是否支持兼容。兼容性是选择序列化协议的一个考虑点
  • 编程语言支持: 由于HTTP协议是一种非常成熟协议,因此所有语言都支持。gRpc和Dubbo等API框架,流行语言都支持,RMI则只有Java支持。广泛的编程语言支持,能保证异构系统之间的互相调用。
  • 性能:当考虑到性能的时候,推荐基于TCP实现的分布式API框架。随着HTTP/2和HTTP/3的推出,HTTP协议也有较高的性能
  • 内网/外网:如果分布式API暴漏给外网,则需要考虑到能穿透防火墙,通常HTTP协议比较适合,这也是REST,SOAP比较适合对外提供API或者系统(云)之间的调用
  • 可观测,基于HTTP协议的分布式API有较好的可观测,通过网关,或者HTTP日志。基于TCP的分布式API则需要框架支持或者二次开发支持。
  • 通信方式,包括同步和异步调用,以及服务端推送。比如gPRC同时支持这三种方式
  • API Schema: 通常分布式API都会提供Schema来说明API的调用地址endpoint,入参,出参,以及参数校验规则。这些Schema除了能当做API文档外,还能生成客户端或者服务端代码,或者生成客户端或者服务测试代码和数据。Open API提供了REST调用的Schema。WSDL提供了SOPA调用的Schema,gRPC则使用protobuf
  • 网关支持: API网关可以提高架构的高可用和可观测,大部分布式API都支持网关,以HTTP协议为基础的API天然支持通过Apache,Nginx,HAProxy等作为网关,或者Spring Cloud Gateway 。 对于Dubbo,则可以使用Apache Shengyu网关, 或者二次开发Spring Cloud Gateway,将REST请求转化为Dubbo请求。

分布式API 设计其他考虑

在选择API框架,以及使用API过程中,还需要如下考虑
 
特性
说明
安全调传输协议
是否支持安全调传输协议,系统之间,或者是内外网之间可以采用SSL传输协议。基于HTTP的API框架天然支持SSL
安全支持
安全支持,API框架是否允许携带额外的安全信息,并进行认证和鉴权。比如REST通常使用JWT协议,在HTTP Header中携带加密的用户,角色等信息,REST服务端会解密这些信息并认证或者授权用户是否能调用此API
降级说明
API可能不会按照预期调用,比如因为限流,或者下游不可用,应该提供降级的指示,并要求客户端稍后按照规定的方式重试,最常见的是退避指数间隔重试。有的分布式API框架内置限流降级功能,有的则需要服务提供者实现,或者按照业务优先级区分限流降级
性能说明
API 应该通过文档申明哪些参数会影响性能
幂等说明
API一般要求幂等,既同样参数,多次调用的结果应该是一样的。比如订单API,用户多次点击,应该只生成一个订单,而不是多次订单。 如果提供的API不能实现幂等,需要在API文档中说明多次调用的结果
是否支持泛化调用
分布式API框架通常通过Schema生成客户端SDK(client stub),客户端依赖SDK调用微服务,但有些情况,强依赖SDK并不是个好主意,比如测试平台,或者API网关。 这些系统不会使用客户端SDK。那么就要求API分布式框架支持泛化调用,即客户端可以提供类名和方法名,以及JSON作为参数。dubbo支持泛化调用,而gRpc,Thrift不直接支持
批量调用API
API是否还有批量调用API,比如,查询单个设备是否在线和批量查询多个设备是否在,查询单个商品库存,和批量查询商品库存。批量API有助于提升性能
传输数据压缩
API框架是否支持传输数据压缩,压缩有助于提高性能。比如HTTP协议天然支持报文压缩,有些分布框架采用的序列化协议也支持压缩功能
API 超时设定
API框架默认的超时时间都比较保守,gRCP,Thrift默认超时时间不设置,dubbo为例子则默认为1S。建议为每一个API设定超时时间
重试策略
大部分API框架的重试间隔时间都采用退避指数,以避免频繁重拾导致服务器压力过大,甚至无法恢复到正常状态,linux的TCP重传间隔1S,2S,4S,8S,16S。 如果你作为客户端,调用分布式API,失败情况下想重试,应该考虑重试策略
 
 
我参与物联云系统遇到过3个跟重试相关问题
1 jedis早期版本的发送数据到redis,会不间隔重试.导致迅速失败
2 弱网环境,操作系统使用退避指数间隔重试,导致弱网通信耗时较长
3 主网关和接入网关在重启后,访问量较大,导致所有访问都失败。怀疑设备是不断重试
 
有了如上知识,可以分析SSE,GraphQL和MQTT,Thrift
API技术
 
基础协议
 
报文格式
 
语言支持
性能
内网/外网
可观测
 
通信方式
API Schema
负载均衡
 
SSE
HTTP
同WebSocket
通用
内网/外网
服务器推送
Nginx等HTTP代理
GraphQL
HTTP
JSON
通用
一般
内网/外网
容易

 

同步
支持
Nginx等HTTP代理
MQTT
TCP
MQTT
通用
外网
异步
Thrift
TCP
二进制
通用
内网
同步,异步
支持
Nginx,HAProxy,客户端自研
 

参考

2 各个框架的官网功能特性

 

展开阅读全文
加载中
点击加入讨论🔥(4) 发布并加入讨论🔥
4 评论
2 收藏
0
分享
AI总结
返回顶部
顶部