让我们聊聊接口设计这件事情

万事皆有因

这次换个大号一点的字体,因为后面会讲很多乱七八糟的事情。在自己公司做业务和帮朋友们解决问题的时候,问题都出在接口方面。很多时候Java的SOA的治理方案都会选择透明代理这种模式(例如dubbo这个SOA治理框架),但是当我们面对跨语言的时候这似乎不是个好方法了。


接口的设计

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

  1. 大规模系统和小规模系统

  2. 面向内部系统接口和面向外部系统的接口

  3. 大数据传输的接口和小数据传输的接口

  4. 长链接的接口和短链接的接口

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

我后面的话题更多是站在对内和对外接口两种设计前提下进行设计和实施。


接口的实施

一定要做的事情

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

  1. 接口功能定义是否明确,是否有功能重复的地方

  2. 接口的升级机制,是否能兼容以前的数据

  3. 接口的数据量是多少,是否需要使用传输压缩机制

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

对内的接口

对内的接口简单说就是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. 非对称加密的方式

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

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

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


量级保护

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

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



你可能感兴趣的:(分布式,安全,SOA,防攻击,接口设计)