一、注册中心

在微服务架构的项目中,注册中心 是其最核心的模块之一,注册中心 实现了各个微服务的服务注册与发现,从而实现了微服务之间的动态发现与连接,增强了微服之间的去中心化。

在单体项目中,一个项目会存在多个模块,例如:订单模块、支付模块、仓储模块。模块与模块之前必然存在着 相互依赖 的关系,对于单体项目而言,这种依赖关系就体现各个模块的 service(函数)的引用,这种引用完全属于服务的 内部直接引用

在微服务项目中,一个项目会存在多个服务,例如:订单服务,支付服务,仓储服务等。正如单体项目中一样,各个服务之间必然存在着相互依赖关系,不同于单体项目,这种依赖关系并不是 service(函数)的引用。显而易见,我们无法在一个独立的项目中直接运行另一个项目的代码 ,有些小伙伴可能要讲了,我们可以通过接口调用来实现?对,这是一个解决方案,但是不够健全,需要解决两个最直接的问题:

  1. 如何解决 高性能、低延迟 的问题( http 协议显然不是一个理想的选择)。
  2. 如果一个服务出现了 IP 漂移(IP 发生了变化),如何能够以最快且最优雅的方式完成IP的切换。

对于上面的 第 1 个问题 的解决方案,微服务之间的通信不会使用传统的 http 协议,而是使用了更加高效的 grpc 协议。相比于传统放入 http 协议,grpc 协议 有更高性能的传输,grpc 的请求与响应的数据格式不同于传统的 http(文本格式),其使用的是二进制格式的请求与响应,并支持多路复用与流式传输。

对于上面 第 2 个问题 的解决方案,注册中心的服务注册与发现,在微服务项目中要求每个微服务必须向注册中心注册自己的服务名(可以理解为一个域名),注册中心会维护(心跳检测,即时刷新,负载均衡)一个服务名与 IP的注册表。

这就意味着,各个微服务之间的接口调用无需关注 IP,IP 是由各个微服务与注册中心进行的维护的,这样就解决的微服务的 IP 漂移 的问题。值得注意的是多个不同的微服务的服务名必须不同,相同服务名的微服务会被维护到一个分组中,并采用负载均衡的策略进行访问。

如上所属,结合 grpc(例如成熟的框架 feign)和注册中心,我们就能实现微服务之间的接口调用就像调用函数一样方便。

二、微服务网关

上面我们讨论了服务之间的交互通信问题,下面我们来探讨一下前端(WEB、桌面、APP 等)与服务端的交互通信问题。

在微服务项目中,必然采用的是前后端分离的设计方案。如上可知,一个项目会存在多个服务(例如:订单服务,支付服务,仓储服务等),在前端项目中存在与各个微服务的直接交互,那么这样就带来了一个问题:前端应该如何处理微服务项目的多IP问题?

对于订单服务的 IP 可能是 192.168.32.110 ,对于支付服务的 IP 可能是 192.168.32.111 ,对于仓储服务的 IP 可能是 192..168.32.112 。前端需要与订单服务、支付服务、仓储服务进行直接的交互,难道前端需要通过不同的 IP 访问不同的服务吗?显然是不可接受的。因此微服务网关孕育而生。

在探讨微服务网关之前,如果排除微服务网关的方案,我们可以如何解决这个问题。

  1. 第 1 种方案,就是上面阐述的前端通过不同的 IP 直接访问各个微服务,显然是可能接收的,因为对于 IP 漂移服务的扩缩容 都是一个头疼的问题。
  2. 第 2 种方案,我们可能通过引入反向代理(Nginx),前端通过访问 Nginx 的宿主机的 IP 以及 Nginx 监听的端口,来实现统一 IP,通过 子请求前缀 把请求分发到 不同的微服务 ,从而实现前端服务与多个微服务的直接交互,通过 Nginx 的 LB 策略实现请求的负载均衡。该方案看起来是一个不错的方案,但是对于微服务的 IP漂移微服务的扩缩容 场景,需要修改 Nginx 的配置问题并重载。
  3. 第 3 种方案,在一个微服务项目中新增一个微服务,其目的是通过 grpc注册中心 实现对各个微服务接口的访问,并暴露出 http 接口供前端进行使用。这是同时解决了 多IPIP漂移微服务的扩缩容 问题。看似理想其实是存在问题的,其最大的问题就是难以维护。在一般项目中,会存在成百上千个接口,在大型项目中会存在成千上万个接口,难道需要一个一个的写映射关系吗?显然是不合理的。

我们讨论了 3 种方案,都存在这大大小小的弊端,都不是一个理想的解决方案,因此诞生了微服务网关。微服务网关也是一个微服务,区别于我们上面讨论的第 3 种解决方案,微服务网关无需写接口映射,所有的外部请求都要通过微服务网关,其作用是整合整个微服务形成一套系统,实现日志统一记录、用户操作跟踪、限流操作和用户权限认证等。

微服务网关对前端的转发与响应过程:

  1. 接收请求, 前端应用发送请求到微服务网关,通常使用 http 或 https 协议。微服务网关接收并解析请求,包括请求的方法、头部、路径等信息。
  2. 路由与转发,微服务网关根据配置的路由规则将前端请求转发到相应的后端微服务。路由规则可以基于 路径匹配(常用方式)、请求头、请求参数等条件进行配置。
  3. 请求转发,微服务网关将前端请求转发给后端的目标微服务实例。这个转发可以是直接的代理转发,也可以是通过调用服务发现机制动态发现目标服务的位置并转发请求。
  4. 协议转换(非必须),前端应用和后端微服务之间可能使用不同的通信协议。微服务网关可能需要进行协议转换。
  5. 请求增强,微服务网关可以对前端请求进行增强,例如添加 身份验证信息请求参数校验限流 等。
  6. 请求转换(非必须),微服务网关可能需要对前端请求进行转换,以符合后端微服务的要求。例如,将请求参数进行重组或者格式转换。
  7. 转发请求,微服务网关将经过处理和转换的请求发送给后端微服务。
  8. 等待响应,微服务网关等待后端微服务处理完请求并返回响应。
  9. 响应增强,微服务网关可以对后端微服务返回的响应进行增强,例如添加额外的响应信息、处理错误码等。
  10. 协议转换, 如果需要,微服务网关可以将后端微服务返回的响应进行协议转换,以符合前端应用的要求。
  11. 返回响应,微服务网关将经过处理的响应返回给前端应用,通常也是通过 http 或 https 协议。

三、API网关

在项目实施过程中,难免会对接第三方系统,给第三方系统提供 API 服务,通常的方案是给对方一个 token 地址,对方想要使用我发的系统,需要通过 token 地址获取 token ,在目标请求的请求头中携带上 token,从而获取 API 访问权限。

这样带来的问题是 token 的颗粒度整个项目的API ,即只要带上 token,即可访问相关系统的接口,之所以会造成该问题的原因是通常整个项目对 API 进行了统一鉴权(一般是在 API 网关中进行统一鉴权)。

对于另一些系统,他们可能在接口权限方面会有更加细致的控制,例如通过在 controller 层的接口方法上添加注解配合用户角色生成含有权限信息的 token ,从而实现 API 接口的权限控制。该方案也存在问题,例如:硬编码导致的配置不灵活、 token 的 ttl 的不灵活、调用限流的不灵活、接口下线难等诸多问题。

为了解决上述的诸多问题,有了 API 网关的诞生。API 网关为接口的 访问控制权限分配流量限制黑白名单日志采集 等进行赋能。我认为 API 网关最重要的功能之一是对接口的颗粒度控制 ,API 网关对接口的颗粒度控制是到接口的,这点与微服务网关有着很大的区别。下面我会阐述一下 API 网关的接口的细粒度控制的设计方案。

API 网关对接口的细粒度控制与业务系统对用户的菜单控制很像,用户的菜单控制一般是,用户获得一(多)个角色,一(多)个角色分配多(一)个菜单,当想给用户添加(减少)菜单权限时,只需要重新勾选角色的菜单分配即可。

从上面的描述不难发现,API 网关可以类比成菜单控制系统,那么其需要有如下的组成部分: 接口的动态代理 (类似于菜单配置)、 客户端配置 (类似于角色)用于配置API接口权限和一个 前端可视化操作界面

接口的动态代理:我们 提供给第三方 的接口服务必然是 已经存在的接口服务 ,但是我们并不能直接通过该接口给第三方提供服务(因为访问控制很难),所以需要一层 接口代理 ,我们通过动态配置提供给第三方新的接口(该接口只是对已存在服务接口的代理),实现接口代理的方案有很多,不是我们讨论的主题,不过多赘述。

客户端配置:我们对 代理接口的访问控制 就是基于 客户端管理 实现的,第三方调用 代理接口 时是需要 携带 token 的,第三方需要通过客户端编号获取访问 token ,通过客户端编号获取的 token 会携带客户端信息,使得 API 网关服务可以通过访问 token 直接解析出 客户端状态客户端ttltoken的ttl客户端的接口权限 等客户端的附庸属性。我们团队的方案是 token 中只携带客户端编号以及一些必要的标识,将客户端附庸属性(客户端编号对应的客户端状态、 客户端ttl、 token的ttl 、 客户端的接口权限等)保存到内存中,便于当修改 ttl 和接口权限后可立即生效,不受token获取时间的影响。

前端可视化界面:上述的动态代理以及客户端配置肯定是通过前端图形化界面进行操作的,所以我们需要一套完成的API网关管理界面,使得非专业人员可方便的进行配置,进一步提高了API网关的易用性。

Logo

一起探索未来云端世界的核心,云原生技术专区带您领略创新、高效和可扩展的云计算解决方案,引领您在数字化时代的成功之路。

更多推荐