前言
开放平台设计系列第一篇主要写了开放平台功能方面的设计,原计划写3篇,一篇介绍功能,一篇介绍架构,一篇介绍使用的技术。写了第一篇功能后,发现架构和技术可以合并写,这样看起来更方便些,所以本篇就把架构和技术合并了。合并起来还有一方面是因为涉及到公司实施细节不能把架构的细节写出来,只能简化的描述下架构,这样架构的概述就太少了没办法撑起一篇文章,在后面技术实现会讲解下各个功能模块的实现方式。
1. 总架构概述
下面直接上架构图来描述下通用版开放平台的架构,这里已经删掉了所有涉及到公司隐私的信息。架构上总体上分为以下几部分:
互联网接入web server(web server):负责互联网外部请求的接入,webserver一般使用nginx负责负载和反代,一般都是将webserver部署在两层防火墙包围的DMZ区用来内外网的安全隔离;
开放平台接入网关(openapi gateway):负责接收互联网接入转发的交易请求,网关是线型集群部署在内网,负责请求的限流、熔断、计费等功能;
开放平台门户(openapi portal):门户主要负责提供给开发者使用的门户页面和服务申请、应用管理等功能。门户也是采用了集群部署的应用服务;
开放平台内管(openapi management):内管主要提供给管理员进行内部服务、应用审核、基本维护使用,也是集群部署的应用服务;
服务注册发现中心(service center):服务注册中心是整个服务化的核心,这里服务发现中心主要实现了服务路由和内部服务注册、发现的功能,这里也是采用了集群部署;
安全服务:安全服务因为是基础服务,所以将所有服务都注册到了service center供所有系统使用;
oauth服务:oauth因为也属于开放平台基础服务,所以这里将oauth所有服务都注册到了service center;
开放平台服务组合(BIM):服务组合对原子基础服务进行组合后再发布到service center,也是一个比较核心的模块,有的公司将服务组合从开放平台中剥离出来单独作为一个服务组合系统。BIM也是采取了线性集群部署的方式。
开放平台内部服务管理(openapi server):内部服务管理主要实现了所有开放平台服务元数据的管理、服务接口的配置、应用元数据管理等。
2. 服务接入网关
服务网关的实现比较简单,主要有几个关键点,下面介绍下:
- 外部服务接入:服务接入功能其实比较简单,一般都是使用Spring MVC或者SpringBoot直接定义Controller来实现服务接入,但是这样会导致,如果有多少服务对外开放就要定义多少个Controller,如果使用springcloud的话可以使用类似zuul这样的透传网关来实现,当然也可以自己实现一个通用的接入controller,然后根据请求uri来实现其他的接入路由、限流等功能。
- 服务限流、熔断:作为一个开放平台的接入网关,还需要有限流和熔断的功能,目前比较成熟的方案就是Hystrix,通过Hystrix可以很方便的实现服务限流和熔断,具体实现可以参考我之前写的关于Hystrix的文章。当然如果不使用Hystrix的话,也可以自己实现,限流主要分两个纬度一个是并发限流,一个是指定时间内总调用次数限流,实现并发限流可以通过线程池方案,对于每个商户每个服务创建一个线程池,通过线程池机制来实现并发控制,看过Hystrix源码的同学应该知道Hystrix实现并发限流也是通过线程池方案进行隔离。对于并发限流还可以通过Token池方案进行控制,其实原理和线程池类似,但是token池方案更加轻量级,为每个商户每个服务创建一个token池,如果有服务请求则从token池中拿一个token占用,服务调用完成后归还token,如果所有token被占用则不能再调用服务。实现了限流实现熔断其实就比较简单了,当判断出来触发服务熔断后会自动进行降级处理,如果接口定义了降级策略则固定返回降级报文即可。
- 服务计费:服务计费其实是基于服务次数限流实现的,通过对服务次数的统计实现即可,服务次数统计为了保证性能一般都是通过内存计数或者redis计数,用内存计数存在一个问题就是如何保证HA,所以推荐使用redis集群来进行服务计数;
- 服务分布式扩展:服务接入网关的压力是非常大的,所以要支持分布式线性扩展,要实现线性扩展就要求所有的交易都是无状态的短连接,使用访问令牌的方式来保证登陆有效性检查;
3. 服务组合
服务组合是开放平台中比较常见的功能模块,服务组合一般有两类,服务接口顺序、并行组合,自定义逻辑接口组合。
- 顺序接口组合:这里说的顺序接口组合其实指的是狭义的顺序接口组合就是先调用接口1然后将接口1的返回报文中的部分字段作为接口2的请求字段,再继续调用接口2以此类推,顺序接口组合在实际使用中其实遇到的不多,大部分的接口组合要么是并发调用结果聚合返回,要么是存在很多自定义逻辑,需要对每个接口的返回报文加工后再调用下一个接口的场景。顺序接口组合实现起来其实也比较简单,其实就是在接口配置表中配置好接口依赖关系和输入输出字段对应,在收到组合接口请求后由一个线程根据接口配置表的元数据串型依次调用接口;
- 并行接口组合:并行接口组合其实使用场景比较多,尤其是在移动端场景,经常在移动端的页面存在多个重复的接口调用,这时服务组合其实可以进行并行组合后将结果聚合返回,这样就可以避免前端多次发起网络连接请求数据,前端只需要发送一次请求,由服务组合模块根据请求并发发起服务调用,服务端调用都是内网调用速度比无线调用要快好几个数量级,服务端并发调用有结果返回后再将结果进行聚合返回给前端。这里并行接口调用可以使用java.concurrent库中的fork/join来实现,但是要注意处理并发组合接口某个接口调用异常的处理;
- 自定义逻辑接口组合:自定义逻辑接口组合目前主流的有两种方式,一种是纯编码实现所有的组合逻辑,还有一种是定义一个服务组合接口,开发者只需要实现接口并实现代码片段就可以了,这其实和目前流行的serverless一样。
4. oauth
oauth是开放平台一个不可或缺模块,oauth具体有什么功能这里我就不介绍了,可以参考之前转发的一篇关于oauth的文章,这里主要说下oauth的实现方式,如果是实现标准的oauth的3种模式,可以基于spring security和Apache的Shrio这两套框架来实现,但是目前我了解下来还是有很多公司实现的oauth协议其实加了很多自己的定制化需求,如果有很多定制化需求的建议还是自己实现一套,实现难度其实不大,主要就是实现token发放、token校验、token有效期处理、token更换等基础功能,纯自研的话功能肯定没有用框架那么丰富,但是所有代码可控自主性更高。
5. 服务注册管理
服务注册管理的实现其实没什么好说的,用的技术其实就是传统的java web,服务注册管理其实就是对开放平台所有的应用、服务、接口配置等元数据进行统一管理的模块,只要需求功能清晰,按需求实现就可以了。
6. 服务注册发现中心
服务注册发现中心不是简单的服务路由分发、服务注册、服务发现,其实还涉及到服务的可用性管理、服务监控等等内容,这里推荐使用现成的,不要重复造轮子,可以使用zookeeper或者eureka,笔者之前所在的项目分别使用过dubbo+zk的组合和springboot+eureka的组合,两种各有优缺点,这里更加推荐使用后者,目前springcloud有一统微服务江湖的趋势,而且更新越来越快,虽然阿里又对dubbo重新进行维护,但是担心阿里开源的尿性,小东西用用没问题,像服务治理框架这样的还是算了,万一出问题想死的心都有了。
7. 安全
上一篇文章里说过开放平台的核心其实不是开放接口而是如何保证安全,开放平台的安全其实涉及到以下几方面需要考虑的地方:
- 服务报文加解密:服务报文加解密主要思路就是秘钥通过非对称加密来保证安全,业务报文或者关键字段使用对称加密来保证安全,还可以通过白盒加密等技术来加强安全,因为安全这块内容涉及到很多方案和实现方式,后续单独写一篇关于加解密的文章,详细说说里面的东东;
- 交易签名:通过交易签名来防交易被篡改,交易签名一般使用非对称加密+散列算法来实现;
- 应用秘钥管理:对于使用到的对称秘钥或者非对称公私钥都要进行管理,如果已经有了CA系统,可以直接复用CA中心的秘钥管理,也可以自建密钥管理,自建一般安全性方面会存在很多安全问题,但是可以实现基本功能;
- 应用接口权限控制:对于每个开发者调用接口的权限控制,其实就是一个1对N的关系映射,实现方面没有什么可说的;
- oauth令牌机制:上文已经说了;
- 黑白名单:黑白名单也是安全防护的基础功能,其实核心就是在交易调用的时候进行黑白名单的判断,这里要保证的就是性能问题,可以通过将黑白名单保存在内存或者redis中来缓存保证读取性能;
- 字段脱敏还原:对于一些敏感字段需要进行脱敏后返回给前端,脱敏简单,难的是还原,对于内部系统存储的数据一定是还原后的数据,所以只有在请求进来的时候要对报文解密后对脱敏字段进行还原后再进行持久化或者发给源系统;
- 交易反欺诈:以前做的开放平台一般都没有反欺诈模块,最近两年大数据火了以后,基于大数据的交易反欺诈也火了起来,很多开放平台也做起了交易反欺诈,交易反欺诈目前大部分都是事后黑名单机制,每笔交易关键要素都会送反欺诈系统,反欺诈系统会通过storm这类实时计算出可疑交易名单,并将名单和黑名单联动,后续再有黑名单中交易发起时就会触发反欺诈动态安全策略。
8. 沙箱
沙箱主要实现的功能就是服务模拟,沙箱实现要注意以下几点:
- 报文模拟:报文模拟可以使用类似MockServer这样的报文模拟工具,其实有很多类似的报文模拟工具,甚至可以自己实现一个简单的报文模拟工具;
- 测试数据初始化:对于一些智能沙箱,需要对测试数据进行初始化,初始化后可以进行重新的测试,这样可以保证脏数据的及时清理;
- 测试帐号管理:对于使用沙箱的开发者也需要有一个测试帐号的管理功能,可以方便开发者自己创建一些测试帐号;
- docker:如果使用了docker的公司可以考虑使用docker来实现测试环境数据的清理,目前我也在测试使用容器化技术来快速创建测试环境。
9. 门户、内管
门户和内管其实没什么好说的其实都是一些portal,只是针对的用户不一样,实现的技术也就是传统的java web技术,如果前端要显示的酷炫一些就使用一些H5的技术。因为在门户和内管中还会涉及到一些监控的功能,监控模块这里就不单独弄一节描述了,其实监控可以借助于一些三方组件来实现,目前主流的实现方案主要是将各个系统的服务接口调用都推送到一个监控平台,由监控平台根据推送过来的数据进行实时数据展示。
总结
本文对于开放平台一些核心内容如何实现做了简要介绍,每部分其实都可以单写一篇文章,开放平台中其实涉及到的技术还是很多的,希望大家慢慢体会。