像架构师一样来思考微服务接口设计
随着微服务的兴起,在工作当中会涉及到很多接口互相调用的情况,本文从宏观上介绍了微 服的接口设计原则。
为什么做接口设计
我们在工作的时候一般都是面一个大型项目,随着微服务的兴起,不单单要设计模块之间的 接口,还要考虑各个微服务之间的接口。这篇文章就是针对如何去做微服务之间的接口设计 的思考。
如何做接口的设计
从笔者个人角度来说,可以从以下几个特性进行分析:
- 大规模系统和小规模系统
- 面向内部系统接口和面向外部系统的接口
- 大数据传输的接口和小数据传输的接口
- 长链接的接口和短链接的接口
很多时候我们优先考虑的是系统有多大,扩张性要有多好,对内还是对外以及我们有多大的 能力。很多时候这个东西并没有一个定论,更多是基于业务和团队人员组成而决定的。
接口的实施
不管接口是对内的还是对外的,我们都要做以下几件事情:
- 接口功能定义是否明确,是否有功能重复的地方
- 接口的升级机制,是否能兼容以前的数据
- 接口的数据量是多少,是否需要使用传输压缩机制
- 接口的熔断点在何处,何时该降级或停止服务
- 接口的安全机制是怎么样的,如何将非法调用隔离开来
这些事情是我们在开始设计和实现接口的时候,必须要先想到的。但是不要认为我们想到了 这些东西,我们就可以高枕无忧,然后事情就会像我们期待的那样发展下去。很多时候,接 口都会变成像阿米巴原虫一样,不是圆的而是不规则的多边形。
对内的接口
对内的接口简单说就是SOA,但是SOA也有很多种做法,例如常见的dubbo框架。在dubbo框架 下,我们所做的事情完全可以说是在dubbo框架下进行业务开发,并定义interface然后暴露 出去,我们此时貌似没有进行接口设计,但是实际上我们是完全按照dubbo的规范完成了接 口的定义,没错就是那个interface。看起来对内部的接口完全非常明确了,没什么可讲的, 但是其中还是有很多东西可讲的,我先讲讲我们常见的。
对服务发现的方案选择:
- 使用主动推送的方式,注册中心每次发生变化都会推送最新的列表给服务的使用者
- 使用被动拉取的方式,注册中心每次变化都保存好,然后使用者每次调用服务者的时候,先到注册中心查询一次
好了,让我分别来说说这两个方案
使用主动推送
可以让使用者很快的更新服务者信息,使用者调用服务者的时候只需要在本地的一个hash表 中查询一下即可,并且注册中心挂掉了之后,也不影响使用者调用服务者,看起来不错吧。 那么让我来说说这方案的弊端,首先要实现watch-notify机制,大概有人会说不是有 Zookeeper吗?自带该机制和数据冗余机制,那么我想说的是,当业务量起来的时候, Zookeeper的watch机制真的能顶住吗?接着是,服务者的负载均衡并不好处理。那么有没有 解决方法,这个可以参看dubbo中的注册中心是如何玩耍的。
使用被动拉取
这个好像很直观,但是每次都查询注册中心,这性能,注册中心能处理的了吗?大家不妨想 一下DNS服务器,其实该方案完全可以使用简单的内部DNS实现。那么该方案的好处不言而喻, 负载均衡好处理,并且非常简单。但是问题呢,性能和稳定性是要深入考虑的事情。
传输协议
剩下的就是需要考虑的传输协议了,为什么要考虑传输协议?原因很简单:
- 接口平均传输的数据量和自己的内网带宽的平衡
- 是否要跨语言协作
- 是否侵入业务了
为何考虑带宽
虽然注册中心第一步解决了我们的快速扩张的问题,但是呢,内网带宽毕竟是有限的。随着 服务数量增多和调用量的增加,有时候我们会发现,同一个服务我们明明增加了N台部署响 应时间却下降了很多,按照公式应该响应时间不变的呀?这个时候,我们可能猛然看到监控 上我们的内网带宽已经跑满了。
为何考虑跨语言
难道一个公司不就是一种后端语言?其实不然,我曾见面试过一个公司,内部的业务之复杂, 语言使用之繁多。很多时候,我们需要站在一个公司发展的角度上考虑这个问题,而不是一 个纯技术的细节上考虑这个问题。
为什么要考虑是否侵入业务
不侵入业务,就是尽可能的封装底层的实现,让业务线更少的去考虑底层发生什么了。很多 人说,这对业务线的人不公平,阻碍了他们的技术发展。其实不然,让业务线的同仁们更多, 更深入的思考业务发展是非常重要的事情,我个人认为研发分两类,一类是玩算法和底层的, 另一类就是深入业务的,他们都有自己的长处和短处。其实减少业务的侵入是为了更快的实 现产品功能,让产品上线,让公司的业务快速迭代起来,这样对任何人都是有好处的。
接口升级
这个与其说是升级,不如说是怎么做不同版本的数据共存和A/B测试。一般在很多成行的SOA 系统中,已经很完善了,我没必要在这里面多废话。但是还是要多说一句,数据多版本不易, 且升且小心。
对外接口
对外接口,大家很快就会想到Restful。随着现在创业的兴起,应当说是智能手机和Web2.0 的兴起(更应该说的本质是,网络带宽变好,手机流量降价)。但是对外接口并不限于 Restful,还有大家不愿意谈的纯Socket接口。对外接口可讲的东西非常多,不过思路上基 本上和对内接口没太大的差别,所以我这里就主要讲下为什么选择纯Socket的接口。
我们不愿意面对的长链接,很多研发,甚至公司级别,都不愿意去尝试这个技术。原因嘛, 请看下面:
- 调试复杂,研发成本高
- 国内网络环境复杂,加重了第一条
- 国内用户对流量敏感,长链接心跳控制不好,容易被认为是偷流量
- 协议设计比较复杂,对研发的要求上升了很多
但是长链接真的就那么难嘛,其实不然。更多时候,是产品层面用不上,一般只有IM类型的 应用或者实时对战类的游戏才会选择长链接。当然偶尔我们也想提供一些高互动的交互,如 果只是在应用内短暂使用,完全可以选择websocket(不过面对中国强大的高铁和运营商基 础建设的规划TT)。
接口的保护
安全保护
当我们面对很多外部接口的时候,我们需要考虑数据的安全性。为什么要考虑安全性:
- 包含用户数据
- 包含交易数据
- 以及甚至你不想让用户自己知道的数据
保护接口的方式最基本的是SSL/TLS,然后呢:
- 对称加密的方式
- 非对称加密的方式
- 动态秘钥
先说下我们为什么要在SSL/TLS下面再次进行加密呢?大家可能听说过以色列一个网络安全 公司的事情了,换句话说一旦根证书被释放出去了,分分钟可以做SSL/TLS的man in middle 的攻击。同时有些稍微高级的用户,会针对你的接口进行刷接口的行为。
对称加密
简单且易用。但是问题也明显,一旦秘钥泄漏或者被用户强猜出来了,那么影响还是很大的。
非对称加密的方式
实现略复杂,同样也面临第一种方式的问题。但是可以有一个专门的秘钥管理人员,生成公 钥和秘钥对后,将公钥交付给客户端,将秘钥交付给服务器端,大大减少了泄漏的可能性。 同时用户即便猜出了客户端的公钥,也无法解密别的用户提交的数据,而只能伪造请求。
动态秘钥
机器在运行的时候,定期自动和秘钥管控中心进行秘钥交换,每台机器在交互的时候使用的 秘钥都不同。虽然可以带来一定的安全性,但是会给秘钥管理中心带来巨大的压力,同时调 试也比较麻烦。这种方式个人认为适合使用在,传统小交易量的行业中,例如说银行的ATM 机。
熔断保护
内部接口需要吗?
我们可以假定一个场景,服务者A有10个服务器,但是由于使用者B的算法错误,总是先选择 服务者A的某台服务器,那么我们可以想象到服务者A的某台服务器压力非常大,然后逐步的 就失去了响应,接着就会被认为被离线,接着使用者B又同样的方式打掉了第二台服务器。 带来的影响就是,轻者响应速度很慢,严重的就是整个系统雪崩性的逐个崩溃停止服务。
一般怎么做
不管对内部还是对外部,我们都可以选择使用漏桶和令牌桶等算法来保护接口。对外部,我 们还可以通过使用时间戳加整个URL整体签名技术来防止重放攻击和进行限流保护。