打开API网关设计的一扇窗

摘要

API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。

视频内容

背景

移动互联网时代的挑战

移动互联时代迭代速率对于后端开发带来了一些挑战。

在我们公司的商品详情页上,包含了商品信息、价格信息、促销信息和推荐列表四个部分。

在开发过程中,我们想要把这四个信息在一个接口访问中全部吐出来,尝试给出一个万能接口。

事实上,我们在第一次这样做的时候或许是靠谱的,但是当产品发生变更的时候,比如产品想把推荐列表换成热销榜,那么之前做的万能接口就已经不满足这个业务场景了,只能新开一个V2版本。

这样重复必然会导致接口的膨胀以及维护成本越来越高。

所以虽然我们都在追求一个万能的解,但这个“解”也许并不存在。

微服务时代的挑战

我们商品详情页的数据来自于商品系统、价格系统、推荐系统和营销系统。而对于客户端或用户而言,其实没有必要知道每个接口由哪个微服务提供的,只需得到数据即可。

所以我们面临的问题就是怎样避免让客户端感知微服务边界的存在,不同的后端、前端团队需要统一的接口设计、接入规范。

需求

使用API网关构建微服务

API网关是挡在所有微服务之前的一个透明层,是请求进入系统的唯一节点。基于这一点,一方面解决了对调用方隐藏微服务的系统边界问题,另一方面负责服务请求路由及协议转换。它可能还具有其它职责,如身份验证、权限控制、负载均衡、“请求整形”与管理。

实践落地

从HTTP到RPC

在我们的APP和WEB上,所有请求都基于HTTP,RPC服务是基于DUBBO的RPC框架来做。

API网关做的最简单的一件事就是能够让用户发起的请求通过API网关转成对RPC服务的调用,再回到用户的APP上。

主要解决了HTTP请求到RPC调用实例的映射,以及把无类型的参数转换为带类型的参数。

实现了一个轻量级的MVC框架,将请求转换为对RPC实例的调用。

从HTTP到RPC——定义好一个接口

我认为一个设计良好的接口一定包含了明确的异常编码,以及这个异常编码在什么业务场景上出现,这个异常编码怎样在客户端得到合适的处理。

还需要有一个明确的调用权限说明,和清晰的参数列表、返回结果。

示例

如图,这上面有一个ApiGroup,来描述业务模块的属性。

这是我们某个特定的方法,和control有些相似。包含了API的方案名、SecurityType是权限认证的level。

Designed ErrorCode是用来对客户端接口明确报出异常。

入参描述有ApiAutowired和ApiParameter两种类型。

从HTTP到RPC——API注册

在API注册流程中,我们首先做了ApiParser,用于解析API信息,解析完之后会得到接口的完备信息,包含了接口的描述及整个业务异常编码的描述。

第二步是要创建一个RPC调用实例,也就是RpcInvoker。

接下来需要创建一个服务的动态代理,来解决无类型参数到RPC接口上的有类型参数的转换。

最后是把proxy做一个缓存。

从HTTP到RPC——proxy实例

这是一个动态生成proxy的例子。

我们用ASM字节码框架在运行期动态生成proxy。图中函数是把string类型参数转换为强类型参数。

从HTTP到RPC——处理请求

第一步解析请求,在URL中需要描述清楚HTTP调用哪些接口,解析请求就是要pass出这些信息。

然后要做安全验证,以保证什么样的请求才可以被路由到微服务的请求。

第三步构建API调用的上下文。上下文里包含了用户ID等信息,这些信息来自于用户访问令牌解密之后。

接下来就是做代理的执行,最后对结果做序列化。

从HTTP到RPC——安全策略

做安全策略的大体上的处理方法就是设备识别、数字签名,也包括HTTPS。

设备识别主要是用于确认身份,依赖于一个叫token的访问令牌来做。

在APP上用户如果发起了登录,首先经过网关,然后到用户服务,登录完成后下发appSecret和token。

APP在调用API之前要做数字签名,需要一个签名的密钥,也就是下发的appSecret。

API到了网关,网关可以解析出用户身份对应的appSecret,所以它可以验证这个请求是不是正常的请求。验证通过后就到了业务系统。

中间人攻击是在APP发起请求离开设备以后,在网络传输过程中如果被第三方窃听,它会去尝试篡改请求。

中间人窃取到网络传输中的请求报文,虽然获得了token等关键信息,但由于签名密钥appSecret无法通过监听网络请求获得,所以中间人篡改请求却无法得到一个正确的数字签名。

组合式调用

虽然万能接口是不存在的,但我们尝试实现减轻一个接口中同时返回来自于不同微服务的信息的需求。基于这个需求,我们在API网关扩展出一个组合式调用的协议。

简单来说,这个协议是在一次HTTP请求中对RPC服务发起多次调用,在API网关做响应报文的整合,最后做返回。

组合式调用——Façade设计

用Façade设计模式为多个RPC服务的接口做了Façade,在Façade上把API做组装,统一暴露给客户端,让API网关成为API的Façade。

但我们之前尝试做的万能接口跟不上需求的变化,最终它带来的恶果就是代码难以维护。如果在API网关上去不停地为接口做Façade,API网关的代码必然也是很难维护的。

为了解决这个问题,我们让客户端去定义Façade,API网关只负责组装。

组合式调用——并行处理

使用异步并行方式,将组合式调用串行变并行。

首先是请求前置处理,实际调用则采用了dubbo async调用,是dubbo原生的调用方式。最后做请求后置处理。

但是Dubbo异步调用标识会通过attachment向下传递,污染调用链,导致后续调用链路都变成了异步方式。而且dubbo filter链机制在异步调用中具有局限性。

这两个问题都是最后改了dubbo的源码来解决的。

降低接入门槛

提供在线API文档和接入SDK。

但是变化总是存在,我们该如何解放生产力呢?

扩大API的影响力,基于API信息生成敏捷开发工具;强类型约束的SDK,及时暴露违背“契约”的行为。

这是我们做的一些敏捷开发的工具。

这是在线文档工具和调试工具。

定位请求

Dubbo attachment是一种隐式传参机制,具有传递性。

基于这个机制可以把请求标识在调用链路上一直做传递,调用链路上增加AOP、向日志上下文中传递traceid。

请求定位——elk+zabbix

在API网关落下的所有请求日志都会有相应的错误编码,可以做zabbix基于这个服务的远程报错。

我理解的API网关

从技术设计的角度上来说,API是一种抽象,它隔离了我们的使用以及实现;从开发管理的角度上来说,API是一种契约。

API网关是一种微服务的架构解决方案,服务于API“契约”精神,并尽可能的扩大这种契约的影响力,构建一种围绕API开发的“生态”。

展望

API网关前面是HTTP的传输,在这过程中不一定需要中心化的存储,可以尝试用CDN来做边界缓存。

热发布服务于所有微服务,微服务接口的变更怎样做到热重启,是一个比较有挑战性的事情。

我们之前做的事情只是日志定位,谈不上调用链路跟踪,调用链路跟踪有更专业的解决方案。

API网关目前做的只是权限验证,还没有和风控系统结合起来。

限流降级也还没有做。

在网关上做ab测试会是比较有意义的。

我今天的分享就到这里,谢谢大家!

原文发布于微信公众号 - IT大咖说(itdakashuo)

原文发表时间:2017-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java进阶干货

成为一名Java高级架构师你应该要学习的技术

953
来自专栏Java架构

华为8年架构专家总结:微服务架构中zuul的两种隔离机制实验

1726
来自专栏熊二哥

企业模式和设计模式快速入门

相信大家对GOF的23个设计模式和Martin Fowler的企业应用架构模式都有过了解,这部分的内容和知识非常驳杂,不过真正常用的模式并不多,比如单例模式、策...

1807
来自专栏zhisheng

具有一到五年开发经验的程序员该如何提升自己?

敢不敢不给涨薪就“挥一挥衣袖,不带走一个bug”?是不是提出要求后你的主管、经理立刻

1022
来自专栏架构师小秘圈

有经验的程序员应该如何提升自己

工作1-5年,当我们向老板提出加薪的时候,或者跳槽去“捡”offer的时候,我们底气够吗? 敢不敢不给涨薪,就“挥一挥衣袖,不带走一个bug”?是不是提出要求后...

3075
来自专栏吴伟祥

MVC模式与三层架构的区别 原

将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data acce...

582
来自专栏纯洁的微笑

从架构演进的角度聊聊Spring Cloud都做了些什么?

Spring Cloud作为一套微服务治理的框架,几乎考虑到了微服务治理的方方面面,之前也写过一些关于Spring Cloud文章,主要偏重各组件的使用,本篇主...

2985
来自专栏技术记录

Dubbo(一) 开始认识Dubbo,分布式服务框架

引言: 以前的车马很慢,一生只够爱一个人 以前的网站人很少,一个单应用服务着一个人 ———————————————————— 现在,动不动就谈什么高并发,千万级...

2256
来自专栏陈树义

数据库历险记(二) | Redis 和 Mecached 到底哪个好?

说起缓存框架,我们最常用的缓存框架有 memcached、Redis 这两个,但它们之间其实是有差异的。

712
来自专栏云计算D1net

OpenStack加入Apache顶级项目Cassandra

Apache Cassandra是极高性能、可扩展、分布式NoSQL数据库,使用灵活,简单分区行存储数据模型,可以对商业服务器和跨数据中心进行无单点故障的...

2766

扫码关注云+社区