19微服务网关如何作为服务端统一入口点?
文章目录
在单体架构中,客户端在向服务端发起请求时,会通过类似 Nginx 的负载均衡组件获取到多个相同的应用程序实例中的一个。请求由该服务实例进行处理,服务端处理完之后返回响应给客户端。
而在微服务架构下,原来的单体应用拆分成了多个业务微服务。此时,直接对外暴露这些业务微服务,必然会存在一些问题。客户端直接向每个微服务发送请求,其问题主要如下:
API 粒度的问题,客户端需求和每个微服务暴露的细粒度可能存在 API 不匹配的情况。
微服务之间的调用可能不仅仅基于 HTTP 的方式,还有可能使用 Thrift、gRPC 和 AMQP 消息传递协议,这些 API 无法暴露出去。
直接对外暴露接口,使得微服务难以重构,特别是服务数量达到一个量级,这类重构就非常困难了。
如上问题,解决的方案是使用微服务网关。网关在一个 API 架构中的作用是保护、增强和控制外部请求对于 API 服务的访问。
什么是微服务网关
在微服务架构中,网关位于接入层之下和业务服务层之上。微服务网关是微服务架构中的一个基础服务,从面向对象设计的角度看,它与外观模式类似。
微服务架构图
微服务网关封装了系统内部架构,为每个客户端提供一个定制的 API,用来保护、增强和控制对于微服务的访问。换句话来讲,微服务网关就是一个处于应用程序或服务之前的系统,用来管理授权、访问控制和流量限制等,这样微服务就会被微服务网关保护起来,对所有的调用者透明。因此,隐藏在微服务网关后面的业务系统就可以更加专注于业务本身。
微服务网关的功能特性
作为连接服务消费方和服务提供方的中间件系统,微服务网关将各自业务系统的演进和发展做了天然的隔离,使业务系统更加专注于业务服务本身,同时微服务网关还可以为服务提供和沉淀更多附加功能。
微服务网关的主要功能特性如下图所示:
网关的功能特性示意图
结合该图,我们就来具体介绍下这四类功能。
请求接入。管理所有接入请求,作为所有 API 接口的请求入口。在生产环境中,为了保护内部系统的安全性,往往内网与外网都是隔离的,服务端应用都是运行在内网环境中,为了安全,一般不允许外部直接访问。网关可以通过校验规则和配置白名单,对外部请求进行初步过滤,这种方式更加动态灵活。
统一管理。可以提供统一的监控工具、配置管理和接口的 API 文档管理等基础设施。例如,统一配置日志切面,并记录对应的日志文件。
解耦。可以使得微服务系统的各方能够独立、自由、高效、灵活地调整,而不用担心给其他方面带来影响。软件系统的整个过程中包括不同的角色,有服务的开发提供方、服务的用户、运维人员、安全管理人员等,每个角色的职责和关注点都不同。微服务网关可以很好地解耦各方的相互依赖关系,让各个角色的用户更加专注自己的目标。
拦截插件。服务网关层除了处理请求的路由转发外,还需要负责认证鉴权、限流熔断、监控和安全防范等,这些功能的实现方式,往往随着业务的变化不断调整。这就要求网关层提供一套机制,可以很好地支持这种动态扩展。拦截策略提供了一个扩展点,方便通过扩展机制对请求进行一系列加工和处理。同时还可以提供统一的安全、路由和流控等公共服务组件。
实战案例:自己动手实现一个网关
API 网关最基础的功能是对请求进行路由转发,根据配置的转发规则将请求动态地转发到指定的服务实例。动态是指与服务发现结合,如 Consul、ZooKeeper 等组件,我们在前面的“服务注册与发现”模块已详细讲解。本课时我们将会使用 Go 实现一个简易的 API 网关。
API 网关根据客户端 HTTP 请求,动态查询注册中心的服务实例,通过反向代理实现对后台服务的调用。
API 网关将符合规则的请求路由调用对应的后端服务。这里的规则可以有很多种,如 HTTP 请求的资源路径、方法、头部和参数等。这里我们以最简单的请求路径为例,规则为 :/{serviceName}/#。即:路径第一部分为注册中心服务实例名称,其余部分为服务实例的 REST 路径。如:
|
|
其中:
/cargo-service 为服务名称;
/locations 为 cargo-service 服务提供的接口。
1. 实现思路
客户端向网关发起请求,网关解析请求资源路径中的信息,根据服务名称查询注册中心的服务实例;然后使用反向代理技术把客户端请求转发至后端真实的服务实例,请求执行完毕后,再把响应信息返回客户端。
自定义网关的调用请求示意图
我们设计实现的网关的功能主要包含如下几点:
HTTP请求的规则遵循 /{serviceName}/#,否则不予通过。
使用 Go 提供的反向代理包 httputil.ReverseProxy 实现一个简单的反向代理,它能够对请求实现负载均衡,随机地把请求发送给服务实例。
使用 Consul 客户端 API 动态查询服务实例。
2. 编写反向代理方法
创建目录 gateway,然后新建 main.go 文件。NewReverseProxy 方法接受两个参数:Consul 客户端对象 api.Client 和日志记录工具 log.Logger,返回反向代理对象。该方法的实现过程如下:
获取请求路径,检查是否符合规则,不符合规则直接返回;
解析请求路径,获取服务名称(请求路径的第一部分);
使用 Consul 客户端查询服务实例,若查询到结果,则随机选择一个作为目标实例;
根据选定的目标实例,设置反向代理参数 Schema、Host 和 Path。
|
|
在反向转发处理的时候,我们只是根据请求中的服务名直接转发,如果需要对外屏蔽服务名的话,这样的路由转发规则显然是不够的。为了增加路由配置的多样性,我们可以抽出路由配置层,根据指定的规则进行路由转发,如根据配置名称、头部的信息、请求的参数、请求的 body 等规则转发到指定的服务。
3. 编写入口方法
main 方法的主要任务是创建 Consul 连接对象、创建日志记录对象和开启反向代理 HTTP 服务。整个过程与前面课时创建用户服务类似,代码如下(为了测试方便,直接指定了 Consul 服务地址信息):
|
|
如上的代码实现,为了创建反向代理,需要先创建日志组件和 Consul 连接对象。反向代理处理器一般还可以使用装饰者模式封装,如增加中间件 Hystrix 断路器、链路追踪 Tracer(Zipkin、Jaeger)组件等。
4. 运行货运与网关服务
做好如上的准备步骤之后,我们开始运行货运服务。为了测试负载均衡效果,启动两个实例。这里我们是在一台主机上测试,所以需要使用不同的端口。首先编译货运服务:
|
|
在 cmd 目录下生成了 cargo 可执行文件,下面我们就分别来启动两个货运服务实例:
|
|
启动成功并注册到 Consul,控制台输出如下:
|
|
再切换至目录 gateway,执行 go build 完成编译,最后启动网关服务。
|
|
5. 测试
网关服务和两个货运服务实例启动好之后,我们通过命令行请求货运服务的接口 /cargos,以获取指定 Id 的货运信息,请求如下:
|
|
同时,在终端可以看到如下输出,说明多次请求访问了不同的服务实例:
|
|
本案例我们使用反向代理技术,并结合注册中心 Consul 实现了简单的 API 网关。Go 提供了反向代理工具包,使得整个实现过程变得比较简单。实际项目中使用的产品,如 Zuul、Nginx 等,还包含了限流、请求过滤、身份认证等功能。该网关虽然仅仅实现了请求的代理,但重点在于帮助你了解了网关实现的基本原理,从而为后续网关功能的扩增打下基础。
小结
本课时我们首先介绍了微服务网关产生的背景及其相关概念,然后还介绍了微服务网关在微服务架构中的职能。作为服务端的统一入口点,微服务网关主要用来实现接入请求、统一管理、解耦和配置拦截策略等功能。最后,为便于你更加详细地了解网关组件相关功能的实现原理,我们还自己动手实现了一个 Go 微服务网关,你可以跟着上手实操下。
学完本课时,你可以结合自己的实践经验,思考下我们实现的简易网关还需要承担哪些微服务架构中的职责。欢迎你在留言区积极发言和讨论。
-– ### 精选评论 ##### **玉: > 讲解的真全面,很好,有收获!!😀
文章作者 anonymous
上次更新 2024-06-10