本文总结
很是相似于API Manager提供的多租户订阅服务的功能。
将应用程序构建为一组微服务时,须要肯定应用程序客户端
如何与微服务交互。本文中,咱们将讨论一下这对客户端与应用程序之间的通讯有什么影响,并提出一种使用API网关的方法。
当使用微服务架构时,产品详情页面显示的数据归多个微服务全部。
客户端与微服务直接通讯
从理论上讲,客户端能够直接向每一个微服务发送请求。每一个微服务都有一个公开的端点(https ://<serviceName>.api.company.name)。该URL将映射到微服务的负载均衡器,由它负责在可用实例之间分发请求。为了获取产品详情,移动客户端将逐一贯上面列出的N个服务发送请求。
遗憾的是,这种方法存在挑战和局限。一个问题是客户端需求和每一个微服务暴露的细粒度API不匹配。在这个例子中,客户端须要发送7个独立请求。在更复杂的应用程序中,可能要发送更多的请求。例如,按照Amazon的说法,他们在显示他们的产品页面时就调用了数百个服务。然而,客户端经过LAN发送许多请求,这在公网上可能会很低效,而在移动网络上就根本不可行。这种方法还使得客户端代码很是复杂。
客户端直接调用微服务的另外一个问题是,部分服务使用的协议不是Web友好协议。一个服务可能使用Thrift二进制RPC,而另外一个服务可能使用AMQP消息传递协议。无论哪一种协议都不是浏览器友好或防火墙友好的,最好是内部使用。在防火墙以外,应用程序应该使用诸如HTTP和WebSocket之类的协议。
这种方法的另外一个缺点是,它会使得微服务难以重构。随着时间推移,咱们可能想要更改系统划分红服务的方式。例如,咱们可能合并两个服务,或者将一个服务拆分红两个或更多服务。然而,若是客户端与微服务直接通讯,那么执行这类重构就很是困难了。
因为这些问题的存在,客户端与微服务直接通讯不多是合理的。
使用API网关
API网关是一个服务器,是系统的惟一入口。从面向对象设计的角度看,它与外观模式相似。API网关封装了系统内部架构,为每一个客户端提供一个定制的API。它可能还具备其它职责,如身份验证、监控、负载均衡、缓存、“请求整形(request shaping)”与管理、静态响应处理。
API网关负责服务请求路由、组合及协议转换。客户端的全部请求都首先通过API网关,而后由它将请求路由到合适的微服务。API网关常常会经过调用多个微服务并合并结果来处理一个请求。它能够在Web协议(如HTTP与WebSocket)与内部使用的非Web友好协议之间转换。
API网关还能为每一个客户端提供一个定制的API。一般,它会向移动客户端暴露一个粗粒度的API。例如,考虑下产品详情的场景。API网关能够提供一个端点(/productdetails?productid=xxx),使移动客户端能够经过一个请求获取全部的产品详情。API网关经过调用各个服务(产品信息、推荐、评论等等)并合并结果来处理请求。
Netflix API网关是一个很好的API网关实例。Netflix流服务提供给数以百计的不一样类型的设备使用,包括电视、机顶盒、智能手机、游戏系统、平板电脑等等。最初,Netflix试图为他们的流服务提供一个通用的API。然而他们发现,因为各类各样的设备都有本身独特的需求,这种方式并不能很好地工做。现在,他们使用一个API网关,经过运行特定于设备的适配器代码来为每一个设备提供一个定制的API。一般,一个适配器经过调用平均6到7个后端服务来处理每一个请求。Netflix API网关天天处理数十亿请求。
API网关的优势和不足
如你所料,使用API网关有优势也有不足。使用API网关的最大优势是,它封装了应用程序的内部结构。客户端只须要同网关交互,而没必要调用特定的服务。API网关为每一类客户端提供了特定的API。这减小了客户端与应用程序间的交互次数,还简化了客户端代码。
API网关也有一些不足。它增长了一个咱们必须开发、部署和维护的高可用组件。还有一个风险是,API网关变成了开发瓶颈。为了暴露每一个微服务的端点,开发人员必须更新API网关。API网关的更新过程要尽量地简单,这很重要。不然,为了更新网关,开发人员将不得不排队等待。不过,虽然有这些不足,但对于大多数现实世界的应用程序而言,使用API网关是合理的。
实现API网关
到目前为止,咱们已经探讨了使用API网关的动机及其优缺点。下面让咱们看一下须要考虑的各类设计问题。
性能和可扩展性
只有少数公司有Netflix的规模,天天须要处理数十亿请求。无论怎样,对于大多数应用程序而言,API网关的性能和可扩展性一般都很是重要。所以,将API网关构建在一个支持异步、I/O非阻塞的平台上是合理的。有多种不一样的技术能够用于实现一个可扩展的API网关。在JVM上,可使用一种基于NIO的框架,好比Netty、Vertx、Spring Reactor或JBoss Undertow中的一种。一个很是流行的非JVM选项是Node.js,它是一个以Chrome JavaScript引擎为基础构建的平台。
另外一个选项是使用NGINX Plus。NGINX Plus提供了一个成熟的、可扩展的、高性能Web服务器和一个易于部署的、可配置可编程的反向代理。NGINX Plus能够管理身份验证、访问控制、负载均衡请求、缓存响应,并提供应用程序可感知的健康检查和监控。
使用响应式编程模型
API网关经过简单地将请求路由给合适的后端服务来处理部分请求,而经过调用多个后端服务并合并结果来处理其它请求。对于部分请求,好比产品详情相关的多个请求,它们对后端服务的请求是独立于其它请求的。为了最小化响应时间,API网关应该并发执行独立请求。然而,有时候,请求之间存在依赖。在将请求路由到后端服务以前,API网关可能首先须要调用身份验证服务验证请求的合法性。相似地,为了获取客户意愿清单中的产品信息,API网关必须首先获取包含那些信息的客户资料,而后再获取每一个产品的信息。关于API组合,另外一个有趣的例子是Netflix Video Grid。
使用传统的异步回调方法编写API组合代码会让你迅速坠入回调地狱。代码会变得混乱、难以理解且容易出错。一个更好的方法是使用响应式方法以一种声明式样式编写API网关代码。响应式抽象概念的例子有Scala中的Future、Java 8中的CompletableFuture和JavaScript中的Promise,还有最初是微软为.NET平台开发的Reactive Extensions(RX)。Netflix建立了RxJava for JVM,专门用于他们的API网关。此外,还有RxJS for JavaScript,它既能够在浏览器中运行,也能够在Node.js中运行。使用响应式方法将使你能够编写简单但高效的API网关代码。
服务调用
基于微服务的应用程序是一个分布式系统,必须使用一种进程间通讯机制。有两种类型的进程间通讯机制可供选择。一种是使用异步的、基于消息传递的机制。有些实现使用诸如JMS或AMQP那样的消息代理,而其它的实现(如Zeromq)则没有代理,服务间直接通讯。另外一种进程间通讯类型是诸如HTTP或Thrift那样的同步机制。一般,一个系统会同时使用异步和同步两种类型。它甚至还可能使用同一类型的多种实现。总之,
API网关须要支持多种通讯机制。
服务发现
API网关须要知道它与之通讯的每一个微服务的位置(IP地址和端口)。在传统的应用程序中,或许能够硬连线这个位置,但在现代的、基于云的微服务应用程序中,这并非一个容易解决的问题。基础设施服务(如消息代理)一般会有一个静态位置,能够经过OS环境变量指定。可是,肯定一个应用程序服务的位置没有这么简单。应用程序服务的位置是动态分配的。并且,单个服务的一组实例也会随着自动扩展或升级而动态变化。总之,像系统中的其它服务客户端同样,API网关须要使用系统的
服务发现机制,能够是服务器端发现,也能够是客户端发现。下一篇文章将更详细地描述服务发现。如今,须要注意的是,若是系统使用客户端发现,那么API网关必须可以
查询服务注册中心,这是一个包含全部
微服务实例及其位置的数据库。
处理局部失败
在实现API网关时,还有一个问题须要处理,就是局部失败的问题。该问题在全部的分布式系统中都会出现,不管何时,当一个服务调用另外一个响应慢或不可用的服务,就会出现这个问题。API网关永远不能由于无限期地等待下游服务而阻塞。不过,如何处理失败取决于特定的场景以及哪一个服务失败。例如,在产品详情场景下,若是推荐服务无响应,那么API网关应该向客户端返回产品详情的其它内容,由于它们对用户依然有用。推荐内容能够为空,也能够,好比说,用一个固定的TOP 10列表取代。不过,若是产品信息服务无响应,那么API网关应该
向客户端返回一个错误信息。
若是缓存数据可用,那么API网关还能够返回缓存数据。例如,因为产品价格不常常变化,因此若是价格服务不可用,API网关能够返回缓存的价格数据。数据能够由API网关本身缓存,也能够存储在像Redis或Memcached那样的外部缓存中。经过返回默认数据或者缓存数据,API网关能够确保系统故障不影响用户的体验。
在编写代码调用远程服务方面,Netflix Hystrix是一个异常有用的库。Hystrix会将超出设定阀值的调用超时。它实现了一个“断路器(circuit breaker)”模式,能够防止客户端对无响应的服务进行没必要要的等待。若是服务的错误率超出了设定的阀值,那么Hystrix会切断断路器,在一个指定的时间范围内,全部请求都会当即失败。Hystrix容许用户定义一个请求失败后的后援操做,好比从缓存读取数据,或者返回一个默认值。若是你正在使用JVM,那么你绝对应该考虑使用Hystrix。而若是你正在使用一个非JVM环境,那么你应该使用一个等效的库。
小结
对于大多数基于微服务的应用程序而言,实现一个API网关是有意义的,它能够做为
系统的惟一入口。
API网关负责
服务请求路由、组合及协议转换。它为每一个应用程序客户端提供一个定制的API。API网关还能够经过返回缓存数据或默认数据
屏蔽后端服务失败。在本系列的下一篇文章中,咱们将探讨服务间通讯。
网址