从我个人角度来说,可以从以下几个特性进行分析:
很多时候我们优先考虑的是系统有多大,扩张性要有多好,对内还是对外以及我们有多大的能力。很多时候这个东西并没有一个定论,更多是基于业务和团队人员组成而决定的。
一定要做的事情
不管接口是对内的还是对外的,我们都要做以下几件事情:
这些事情是我们在开始设计和实现接口的时候,必须要先想到的。但是不要认为我们想到了这些东西,我们就可以高枕无忧,然后事情就会像我们期待的那样发展下去。很多时候,接口都会变成像阿米巴原虫一样,不是圆的而是不规则的多边形。
对内的接口简单说就是 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 整体签名技术来防止重放攻击和进行限流保护。
转载自TTalkIM
1
m1911star 2017-08-04 16:44:48 +08:00 1
前排支持学长
|
2
ihuotui 2017-08-04 20:02:56 +08:00 via iPhone 1
微服务接口重要是低耦合,高内聚,单一原则。也不单单是架构师来考虑的,要和业务结合。
|
4
DavidGao OP @ihuotui 你说的很对,很多时候不单单是要架构师单方面考虑。但是这个话题比较宽泛,我在讨论这个问题的时候,提出了一个讨论范围,主要还是针对通用的接口设计范畴,而各个业务有其本身业务特性,很有可能已经超出我上面所提到的所有范畴。同时我对这种通用范畴的接口设计,大的观念还是减少对业务的侵入。
|
7
zjsxwc 2017-08-04 21:52:46 +08:00 1
学习了
|
8
YzSama 2017-08-05 07:41:34 +08:00 via iPhone 1
@DavidGao 我公司同事喜欢,使用一个对外接口,通过 method 参数来指定调用那个服务(他说好像是用反射)。虽然,总觉得不好,但也没错。。 按他说法:安全 维护简单 性能也没问题?
|
10
DavidGao OP @YzSama 你同事这么做也没有错,在 Restful 出现之前,就存在了很多对外接口设计方案,例如说 SOAP。你提到的设计,我的第一反应就是类 SOAP 设计,并且 SOAP 是一个非常强大的企业级设计,虽不轻量级,但是很完整。
回到你这个具体案例上,单一 URI 并不会对性能造成影响,因为可以实用 nginx 随机负载到业务前端机上,后面在放置业务集群。安全性,可以在 Nginx 和业务前端机上进行统一处理和验证,所以参数定义明确且规范,安全措施有在做,就不是问题了。 你感觉不太好是很正常的一个情况,因为现在随着 Restful 的推进,很少再能看到 SOAP 或类 SOAP 设计了。我曾经也使用 SOAP 和类 SOAP 设计,接触 Restul 后感觉这类设计确实有点怪怪的感觉。 |
11
leeg810312 2017-08-05 20:04:31 +08:00 via Android 1
我觉得现在很多时候只考虑 restful 风格的 API 不考虑 rpc 风格的 API 是非常有问题的。我认为读写资源用 restful 设计比较好,而操控资源用 rpc 风格比较好,我要的不是资源本身,而是操控资源的结果以及一些状态,现在云服务商提供的接口 2 种风格设计都有
|
12
DavidGao OP @leeg810312 非常赞同你的说法,根据业务不同尽可能的针对性设计比较好。因为操控资源的 RPC 直接使用 Restful 很多时候让人感到迷惑,但是选择这样做的很大原因是,为了接口统一,开发统一。如果在条件容许的条件的情况下,尽可能明确和分开是很好的选择。
|