其实OpenAPI和RPC本质上是一样的,只是由于OpenAPI是对外开放的,而RPC一般是内部服务调用。两者的考虑点不同,所以在通信协议和序列化方式上有些不同。
作为一个RPC框架或者一个OpenAPI容器,它是连接服务消费者和服务器提供者的桥梁。他其实只是一个请求的转发而已。他的服务质量取决与服务提供者的服务质量。然而因为是一个容器,为了保证消费者的权利,同时也是为了保证其他服务提供者的稳定性和服务质量,必须指定服务规范,避免短板效应和害群之马。这就是为什么要引入SLA的原因。同时,由于服务之间有轻重之分,简单的大锅饭显然不利于资源的最大化利用以及对外提供最佳服务(性能与可靠性)。所以,服务提供者也可以通过QoS协议向容器声明自己的要求和权利,这就是QoS的作用。
首先一个服务一般以一个约定的独一无二的key作为服务标识,这个key一般是业务模块名称+服务名称+服务版本号。不过服务的版本号其实往往仅仅是一个标识而已,因为实际操作中,服务升级几乎都是要求兼容升级的,不会同时存在新老版本服务,因为这很难控制,带来的复杂性更多。
一般来说,容器会要求服务提供者对他提供的服务进行如下SLA声明:
- 服务可靠性: 成功率有多高?
- 服务的响应速度如何:多久可以完成一个请求?
- 服务的吞吐率是多少:可以同时并发处理多少个请求?
- 服务的等级和安全性:是否需要鉴权、黑白名单、灰度(路由)策略
- 是否关键路径:非核心服务(关键路径)则可以自动服务降级。
- 读写接口
- 同步异步
同时,一般来说,服务提供者可以要求容器为其提供特殊的QoS保障:
- 线程数量
- 队列优先级
- 调用失败时的处理:忽略,重试,补偿,等等.
实际操作中,SLA和QoS其实挺相似的,所以经常不做特别的区分,统一称之为SLA。
有了这些SLA和QoS信息,容器就可以比较自动化和智能的进行服务调度和负载均衡。比如说:需要为一个服务分配多少资源?调用这个服务timeout是多少?是同步调用还是异步调用?服务失败了怎么处理?失败多少次就可以认为服务宕掉了,从而将其摘除?设置多大的频率限制进行过载保护?等等。
实际例子
现在ECC的app-platform在实现的时候没有考虑SLA,所以会导致一些耦合的代码。比如timeout,由于IDL没有这个元数据,配置中心也没有这个元数据,导致所有的服务调用需要调用代码中写死私下约定好的超时时间(无法自动化),否者就都走默认的timeout。OpenAPI这块就好很多了,是否需要鉴权、频率限制、timeout都是通过元数据指定(SLA)。API容器可以根据这些元数据信息自动的进行协议转换和转发。当然,现在考虑的比较多的SLA,并没有考虑QoS,这块后续会进行优化。