分享 像架构师一样来思考微服务接口设计

davidgao · 2017年08月04日 · 8984 次阅读

如何做接口的设计

从我个人角度来说,可以从以下几个特性进行分析:

  1. 大规模系统和小规模系统
  2. 面向内部系统接口和面向外部系统的接口
  3. 大数据传输的接口和小数据传输的接口
  4. 长链接的接口和短链接的接口

很多时候我们优先考虑的是系统有多大,扩张性要有多好,对内还是对外以及我们有多大的能力。很多时候这个东西并没有一个定论,更多是基于业务和团队人员组成而决定的。

接口的实施

一定要做的事情

不管接口是对内的还是对外的,我们都要做以下几件事情:

  1. 接口功能定义是否明确,是否有功能重复的地方
  2. 接口的升级机制,是否能兼容以前的数据
  3. 接口的数据量是多少,是否需要使用传输压缩机制
  4. 接口的熔断点在何处,何时该降级或停止服务
  5. 接口的安全机制是怎么样的,如何将非法调用隔离开来

这些事情是我们在开始设计和实现接口的时候,必须要先想到的。但是不要认为我们想到了这些东西,我们就可以高枕无忧,然后事情就会像我们期待的那样发展下去。很多时候,接口都会变成像阿米巴原虫一样,不是圆的而是不规则的多边形。

对内的接口

对内的接口简单说就是 SOA,但是 SOA 也有很多种做法,例如常见的 dubbo 框架。在 dubbo 框架下,我们所做的事情完全可以说是在 dubbo 框架下进行业务开发,并定义 interface 然后暴露出去,我们此时貌似没有进行接口设计,但是实际上我们是完全按照 dubbo 的规范完成了接口的定义,没错就是那个 interface。看起来对内部的接口完全非常明确了,没什么可讲的,但是其中还是有很多东西可讲的,我先讲讲我们常见的。

对服务发现的方案选择:

  1. 使用主动推送的方式,注册中心每次发生变化都会推送最新的列表给服务的使用者
  2. 使用被动拉取的方式,注册中心每次变化都保存好,然后使用者每次调用服务者的时候,先到注册中心查询一次

好了,让我分别来说说这两个方案

使用主动推送

可以让使用者很快的更新服务者信息,使用者调用服务者的时候只需要在本地的一个 hash 表中查询一下即可,并且注册中心挂掉了之后,也不影响使用者调用服务者,看起来不错吧。那么让我来说说这方案的弊端,首先要实现 watch-notify 机制,大概有人会说不是有 Zookeeper 吗?自带该机制和数据冗余机制,那么我想说的是,当业务量起来的时候,Zookeeper 的 watch 机制真的能顶住吗?接着是,服务者的负载均衡并不好处理。那么有没有解决方法,这个可以参看 dubbo 中的注册中心是如何玩耍的。

使用被动拉取

这个好像很直观,但是每次都查询注册中心,这性能,注册中心能处理的了吗?大家不妨想一下 DNS 服务器,其实该方案完全可以使用简单的内部 DNS 实现。那么该方案的好处不言而喻,负载均衡好处理,并且非常简单。但是问题呢,性能和稳定性是要深入考虑的事情。

传输协议

剩下的就是需要考虑的传输协议了,为什么要考虑传输协议?原因很简单:

  1. 接口平均传输的数据量和自己的内网带宽的平衡
  2. 是否要跨语言协作
  3. 是否侵入业务了

为何考虑带宽

虽然注册中心第一步解决了我们的快速扩张的问题,但是呢,内网带宽毕竟是有限的。随着服务数量增多和调用量的增加,有时候我们会发现,同一个服务我们明明增加了 N 台部署响应时间却下降了很多,按照公式应该响应时间不变的呀?这个时候,我们可能猛然看到监控上我们的内网带宽已经跑满了。

为何考虑跨语言

难道一个公司不就是一种后端语言?其实不然,我曾见面试过一个公司,内部的业务之复杂,语言使用之繁多。很多时候,我们需要站在一个公司发展的角度上考虑这个问题,而不是一个纯技术的细节上考虑这个问题。

为什么要考虑是否侵入业务

不侵入业务,就是尽可能的封装底层的实现,让业务线更少的去考虑底层发生什么了。很多人说,这对业务线的人不公平,阻碍了他们的技术发展。其实不然,让业务线的同仁们更多,更深入的思考业务发展是非常重要的事情,我个人认为研发分两类,一类是玩算法和底层的,另一类就是深入业务的,他们都有自己的长处和短处。其实减少业务的侵入是为了更快的实现产品功能,让产品上线,让公司的业务快速迭代起来,这样对任何人都是有好处的。

接口升级

这个与其说是升级,不如说是怎么做不同版本的数据共存和 A/B 测试。一般在很多成行的 SOA 系统中,已经很完善了,我没必要在这里面多废话。但是还是要多说一句,数据多版本不易,且升且小心。

对外接口

对外接口,大家很快就会想到 Restful。随着现在创业的兴起,应当说是智能手机和 Web2.0 的兴起(更应该说的本质是,网络带宽变好,手机流量降价)。但是对外接口并不限于 Restful,还有大家不愿意谈的纯 Socket 接口。对外接口可讲的东西非常多,不过思路上基本上和对内接口没太大的差别,所以我这里就主要讲下为什么选择纯 Socket 的接口。

我们不愿意面对的长链接,很多研发,甚至公司级别,都不愿意去尝试这个技术。原因嘛,请看下面:

  1. 调试复杂,研发成本高
  2. 国内网络环境复杂,加重了第一条
  3. 国内用户对流量敏感,长链接心跳控制不好,容易被认为是偷流量
  4. 协议设计比较复杂,对研发的要求上升了很多

但是长链接真的就那么难嘛,其实不然。更多时候,是产品层面用不上,一般只有 IM 类型的应用或者实时对战类的游戏才会选择长链接。当然偶尔我们也想提供一些高互动的交互,如果只是在应用内短暂使用,完全可以选择 websocket(不过面对中国强大的高铁和运营商基础建设的规划 TT)。

接口的保护

安全保护

当我们面对很多外部接口的时候,我们需要考虑数据的安全性。为什么要考虑安全性:

  1. 包含用户数据
  2. 包含交易数据
  3. 以及甚至你不想让用户自己知道的数据

保护接口的方式最基本的是 SSL/TLS,然后呢:

  1. 对称加密的方式
  2. 非对称加密的方式
  3. 动态秘钥

先说下我们为什么要在 SSL/TLS 下面再次进行加密呢?大家可能听说过以色列一个网络安全公司的事情了,换句话说一旦根证书被释放出去了,分分钟可以做 SSL/TLS 的 man in middle 的攻击。同时有些稍微高级的用户,会针对你的接口进行刷接口的行为。

对称加密

简单且易用。但是问题也明显,一旦秘钥泄漏或者被用户强猜出来了,那么影响还是很大的。

非对称加密的方式

实现略复杂,同样也面临第一种方式的问题。但是可以有一个专门的秘钥管理人员,生成公钥和秘钥对后,将公钥交付给客户端,将秘钥交付给服务器端,大大减少了泄漏的可能性。同时用户即便猜出了客户端的公钥,也无法解密别的用户提交的数据,而只能伪造请求。

动态秘钥

机器在运行的时候,定期自动和秘钥管控中心进行秘钥交换,每台机器在交互的时候使用的秘钥都不同。虽然可以带来一定的安全性,但是会给秘钥管理中心带来巨大的压力,同时调试也比较麻烦。这种方式个人认为适合使用在,传统小交易量的行业中,例如说银行的 ATM 机。

熔断保护

内部接口需要吗?

我们可以假定一个场景,服务者 A 有 10 个服务器,但是由于使用者 B 的算法错误,总是先选择服务者 A 的某台服务器,那么我们可以想象到服务者 A 的某台服务器压力非常大,然后逐步的就失去了响应,接着就会被认为被离线,接着使用者 B 又同样的方式打掉了第二台服务器。带来的影响就是,轻者响应速度很慢,严重的就是整个系统雪崩性的逐个崩溃停止服务。

一般怎么做

不管对内部还是对外部,我们都可以选择使用漏桶和令牌桶等算法来保护接口。对外部,我们还可以通过使用时间戳加整个 URL 整体签名技术来防止重放攻击和进行限流保护。

转载自TechTalk

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号