微服务6:通信之网关

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 微服务6:通信之网关

1 概述

回顾下前面几篇关于微服务的介绍,我们可以了解到从当单体系统到微服务,再到服务网格的演进过程。那单体系统和微服务相比,有哪些区别呢,下面是对功能性的对比?

单体系统

微服务系统

程序、数据、配置集中管理

按照功能拆分、微服务化、松耦合

开发效率低下

分模块快速迭代

发布全量,启动慢

平滑发布,快速启动

可靠性差

熔断、限流、降级,超时重试,异常离群

服务内直接调用

轻量级通信

技术单一

跨语言

微服务有诸多的有利条件,但是如果微服务的粒度比较细(按照业务功能拆分),则他们之间服务调用就会比较复杂,链路会比较长。

 

image.png

比如上图中,我们按照职能将服务进行了拆分,这时候从不同的客户端(如Web、App、3rd)访问,就有可能访问不同的服务。而服务与服务之间又有上下游的协作,调用就变得错综复杂。

因此,在微服务架构体系下,服务间的通讯就显得非常重要。

你可能需要关注很多问题,包括不同的技术栈不同的开发语言之间的上下游交互,服务之间的注册与发现,请求认证,接入授权。

下游对上游进行调用的时候,上游怎么做负载均衡、故障注入、超时重复、熔断、降级、限流、ABTesting等,端到端之间如何实现监控和trace,这些都是微服务体系下需要去思考的问题。

要解决上面这些问题,微服务通信可以从三个方面进行讨论

细化服务颗粒:按照功能拆分、微服务化、松耦合

分模块快速迭代:可以将应用程序拆分为核心和非核心模块。非核心模块出现问题的时候,核心模块不会受到影响。

参考这篇《微服务3:微服务拆分策略

流量管理:金丝雀发布,ABTesting

实现服务的高可用治理:熔断、限流、降级,超时重试,异常离群

轻量级通信,使用 RESTful API 或者 RPC 进行接口访问

跨语言,语言有特定的应用场景,比如go和Java、c++适合不同的业务方向,开发语言不同,但是遵循同一套标准,

使用轻量级的API进行通信,实现服务语言上的解耦。

2 服务之间的通信方式

而微服务的通信,是在服务之间增加一个间接的中间层来完成服务间的通信过程。目前微服务的通信方式有以下三种:

1、基于网关的通信

2、基于RPC的通信

3、基于ServiceMesh的数据面(SideCar)的通信

接下来逐一介绍这三种通信方式的具体实现,本文先介绍基于网关的通信方式。

2.1 基于网关的通信

我们先看看,在没有网关的情况下,服务是怎么通信的?

 

image.png

如上图有3个客户端,在调用4个服务的接口。这种直连调用的方式有很多问题:客户端需要保存所有服务的地址,同时也需要实现一些系统级的容错策略。

比如负载均衡、超时重试、服务熔断等,非常复杂,并且难以维护。因为是在各客户端保存的服务地址,一旦某个服务端出现问题或者发生迁移,所有的客户端都需要修改并且升级。

另外如果再增加一个E svc,所有的客户端也需要升级。而且在某些场景下存在跨域请求的问题,每个服务都需要实现独立的身份和权限认证等等。

这些问题导致 服务间的通信过于复杂,对于开发和维护都不优化。

如果我们在客户端和服务端增加一层网关,所有请求都经过网关转发到对应的下游服务,客户端只需要保存网关的地址并且只和网关进行交互,这样就大大简化了客户端的开发。

 

image.png

如果需要访问用户服务,只需要构造右边这个请求发给网关,然后由网关将请求转发给对应的下游服务。

可以将网关简单理解为:路由转发+治理策略,治理策略是指和业务无关的一些通用策略,包括:负载均衡,安全认证,身份验证,系统容错等等

网关作为一个 API 架构层,用来保护、增强和控制对服务的访问。

2.1.1 网关的主要功能

请求接入

1、为各种应用提供统一的服务接入

2、管理所有的接入请求:提供流量分流、代理转发、延迟、故障注入等能力

安全防护

用户认证、权限校验、黑白名单、请求过滤、防web攻击

治理策略

负载均衡、接口限流、超时重试、服务熔断、灰度发布、协议适配、流量监控、日志统计等

统一管理

1、提供配置管理工具

2、对所有服务进行统一管理

3、对中介策略进行统一管理

2.1.2 网关使用场景

蓝绿部署

 

image.png

我们前面看到,在单体应用中,部署是一件比较麻烦的事情,每次的改动,都需要把整个应用程序都发布启动一次。而且系统规模越大,部署过程越复杂,时间越长。

而在微服务架构中,模块部署起来相对更快,更容易。你可以在短时间内对于同一个模块做多次部署,网关可以帮你实现蓝绿部署。

如图所示之前的用户服务版本是V1.0,然后部署V1.1版本,在网关上只需要做一个转发配置的修改,就可以迅速的将所有流量都流到新版本。

灰度发布

 

image.png

类似金丝雀的理念,你对一次性升级版本感到担忧,可以先配置5%的流量达到新版本,让部分人试用一下,等线上观察一段时间后,可以逐步增加对新版本的流量百分比,最终实现百分之百切流。

负载均衡

 

image.png

此能力需要依赖服务注册和服务发现。

服务熔断

image.png

网关还可以实现断路器的功能;如果某个下游忽然返回了大量错误,原因有可能是服务挂了或者网络问题或者服务器负载太高,如果此时继续给这个问题服务转发流量就可能会产生级联故障。

出问题的服务有可能产生雪崩,雪崩会沿着调用链向上传递,导致整个服务链都崩溃。

断路器可以停止向问题模块转发流量,在业务层面可以给用户返回一个服务降级之后的页面,开发人员就有相对充分的时间来定位和解决问题。

2.1.3 开源网关

image.png

目前常见的开源网关按照语言大概分为上图的五种,如果按照使用数量和成熟度来划分的话,主流有4个,分别是 OpenResty、Kong、Zull和Spring Cloud。

其中 Zull 和Spring Cloud 是用java 实现,前两种是用Nginx+Lua实现的,其中,OpenResty 是一个基于Nginx+Lua实现的一个高性能web 平台,它集成了大量的第三方模块和lua库,用于方便的搭建高性能扩展性强的web 应用服务或者网关,

Kong 是一个基于OpenResty实现的一个高性能可扩展的API网关。从性能上来说:Kong的性能是最好的,其次分别是OpenResty、Spring Cloud 和Zuul。

2.1.4 Nginx介绍

大家熟悉的Nginx是用C语言实现的一个开源、跨平台、高性能的HTTP和反向代理Web服务器,具有高度模块化、扩展性强、轻量级、资源消耗少、高并发、高性能等特点。

Nginx进程模型

 

image.png

 

Nginx是一个多进程模型,包含一个master 进程和多个worker 进程。

master 进程主要负责接收外部信号,向各个worker 进程发送信号,监控worker 进程的状态。当worker 进程异常退出后,服务不会中断的。master 进程会迅速拉起新的worker 进程来工作。基本的网络事件比如读写,都是在worker 进程来实现。

多个worker 进程是相互独立的,他们共同竞争来自客户端的请求,一个请求只能在一个worker 中进行处理。

Nginx网络模型

image.png

首先,master 进程会listen socket,然后再fork出多个worker 进程,每个worker 进程都可以去accept 这个socket。

Nginx 提供了一把共享accept mutex锁来保证只有一个worker 进程可以把这个请求accept 成功。当这个worker 进程accept 连接成功之后,就可以进行请求的解析读取。

大概数据流:master 先 fork 多个worker 进程,然后当有client 来的时候,client 会连接到一个worker 进程里面,发送消息request。worker 进程再去读取、解析并处理,最终把response 返回给客户端。

那么大家可以想一下这个问题,Nginx 采用了一个多worker 的方式来处理请求,每个worker 里面其实是只有一个主线程,那么它是怎么实现高并发的呢?

答案是采用异步非阻塞的方式;什么是异步非阻塞?

举个例子,当worker 收到一个来自client request 时,就会有一个worker 进程去处理它。但这个worker 进程并不是全程处理,worker 会处理到请求可能会发生阻塞的地方。比如它向后端服务器转发的这个request,并等待请求的返回,

worker 进程不会同步的等待,而是注册一个事件,如果下游返回了,再继续处理这个事件。如果有新的请求再进来,它就可以很快按照这种方式再进行处理。这其实就是非阻塞和IO多路复用。

一旦服务端返回了,就会触发worker 刚才注册的回调事件,worker 才会继续接手这个request。  

2.2 Zuul实战

刚才前面已经说过,网关是客户端和服务器之间的中间层,作为系统唯一对外的入口,能够处理流量治理、安全访问等工作。

功能类型

功能说明

统一接入

智能路由

AB测试、灰度测试

负载均衡、容灾处理

日志埋点(类似Nignx日志)

流量监控

限流处理

服务降级

安全防护

鉴权处理

监控 

 机器网络隔离

 

业内主要的网关有如下几种:1、zuul:是Netflix开源的微服务网关,可以和Eureka,Ribbon,Hystrix等组件配合使用,Zuul提供了动态路由、监控、弹性负载和安全功能。

2、kong: 由Mashape公司开源的,基于OpenResty(Nginx+Lua)的 API gateway。

3、Nginx + Lua:高性能的HTTP和反向代理服务器,Lua作为脚本语言,为Nginx提供执行程序,可以高并发、非阻塞的处理各种请求

下面我们以Zuul为案例,来测试下网关的使用。

2.2.1 配置路由规则

新建一个spring-clouid项目,导入Maven 依赖:

image.png

1  <!-- eureka client -->  2         <dependency>  3             <groupId>org.springframework.cloud</groupId>  4             <artifactId>spring-cloud-netflix-eureka-server</artifactId>  5         </dependency>  6         <!-- zuul网关 -->  7         <dependency>  8             <groupId>org.springframework.cloud</groupId>  9             <artifactId>spring-cloud-starter-netflix-zuul</artifactId> 10             <version>2.2.10.RELEASE</version> 11         </dependency>

image.png

配置yaml文件:

image.png

1 server:  2   port: 1002  3 spring:  4   application:  5     name: zuul-proxy # 服务的名称  6 eureka:  7   instance:  8     hostname: localhost  9   client: 10     service-url:  # 这边就保证了注册到 eureka-service 这个注册中心去 11       defaultZone: http://localhost:1000/eureka/ 12  13 #自定义路由映射 14 zuul: 15   routes: #路由规则 16     key-v1:  #自定义key 17       path: /proxy/**   # 匹配路径,/proxy/ 会路由到 zuul-proxy服务 18       serviceId: zuul-proxy 19       url: http://${eureka.instance.hostname}:${server.port}/zuulservice/api/v1.0/  # 只要路径匹配,就转到这个服务对应路径下

image.png

Application中启动网关代理:

image.png

1 @SpringBootApplication 2 @EnableZuulProxy // 开启网关代理 3 public class ZuulGatewayApplication { 4     public static void main(String[] args) { 5         SpringApplication.run(ZuulGatewayApplication.class, args); 6         System.out.println("start zuulgateway!"); 7     } 8 }

image.png

接口实现:

image.png

1 /**  2  * @author brand  3  * @Description:  4  * @Copyright: Copyright (c) 2021  5  * @Company: Helenlyn, Inc. All Rights Reserved.  6  * @date 2021/12/5 12:30 下午  7  * @Update Time:  8  * @Updater:  9  * @Update Comments: 10  */ 11 @Controller 12 @RequestMapping("/zuulservice/api/v1.0") 13 public class ZuulServiceController { 14  15     /** 16      * 获取注册服务信息 17      */ 18     @RequestMapping(value = "/serviceinfo", method = {RequestMethod.GET}) 19     @ResponseBody 20     public String getServiceInfo() { 21         return  "serviceinfo:v1.0,instance 1";    

image.png

 

查看效果,proxy路由成功了:

image.png

 

 

image.png

2.2.2 测试负载均衡

我们在添加一个端口为1003的服务,跟端口为1002做zuul-proxy服务做负载均衡,这时候先修改 zuul-proxy 的yaml配置。

image.png

1 # 自定义路由映射  2 zuul:  3   routes: # 路由规则  4     key-v1:  # 自定义key  5       path: /proxy/**   # 匹配路径,/proxy/ 会路由到 zuul-proxy服务  6       serviceId: zuul-proxy  7 ribbon:  8   eureka:  9     enabled: true # 允许Ribbon使用Eureka 10 zuul-proxy: 11   ribbon: 12     listOfServers: localhost:1002,localhost:1003 # 这边需要建立两个服务 1002,1003,在这两个服务间做负载均衡

image.png

创建一个module,命名zuul-client,增加注册依赖

1         <!-- eureka client --> 2         <dependency> 3             <groupId>org.springframework.cloud</groupId> 4             <artifactId>spring-cloud-netflix-eureka-server</artifactId> 5         </dependency>

配置zuul-client的yaml文件:

image.png

1 server: 2   port: 1003 # 这边注意,端口为1003,跟上面对应起来了 3 spring: 4   application: 5     name: zuul-client # 服务的名称 6 eureka: 7   client: 8     service-url:  # 这边就保证了注册到 eureka-service 这个注册中心去 9       defaultZone: http://localhost:1000/eureka/

image.png

补充一个接口,注意返回的信息不一样:

image.png

1 /**  2  * @author brand  3  * @Description:  4  * @Copyright: Copyright (c) 2021  5  * @Company:Helenlyn, Inc. All Rights Reserved.  6  * @date 2021/12/5 3:52 下午  7  * @Update Time:  8  * @Updater:  9  * @Update Comments: 10  */ 11 @Controller 12 @RequestMapping("/zuulservice/api/v1.0") 13 public class ZuulServiceController { 14     /** 15      * 获取注册服务信息 16      */ 17     @RequestMapping(value = "/serviceinfo", method = {RequestMethod.GET}) 18     @ResponseBody 19     public String getServiceInfo() { 20         return  "serviceinfo:v1.0,instance 2"; 21     } 22 }

image.png

网关 zuul-proxy 和 服务zuul-client都启动起来,可以看到如下的效果:

image.png

 

image.png

 

 

image.png

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
1月前
|
API
阿里云微服务引擎及 API 网关 2024 年 2 月产品动态
阿里云微服务引擎及 API 网关 2024 年 2 月产品动态
|
4月前
|
Java 数据安全/隐私保护 数据格式
Spring Cloud Gateway 网关整合 Knife4j 4.3 实现微服务接口文档聚合
Spring Cloud Gateway 网关整合 Knife4j 4.3 实现微服务接口文档聚合
|
1月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
101 0
|
10天前
|
API
阿里云微服务引擎及 API 网关 2024 年 3 月产品动态
阿里云微服务引擎及 API 网关 2024 年 3 月产品动态。
|
11天前
|
监控 JavaScript 安全
构建微服务架构下的API网关
【4月更文挑战第15天】在微服务架构中,API网关扮演着至关重要的角色。它作为系统的唯一入口,不仅负责请求的路由、负载均衡和认证授权,还涉及到监控、日志记录和服务熔断等关键功能。本文将探讨如何构建一个高效且可靠的API网关,涵盖其设计原则、核心组件以及实现策略,旨在为后端开发人员提供一套实用的指导方案。
26 4
|
1月前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
1月前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。
|
1月前
|
运维 Cloud Native 应用服务中间件
阿里云微服务引擎 MSE 及 API 网关 2024 年 02 月产品动态
阿里云微服务引擎 MSE 面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka )、云原生网关(原生支持Higress/Nginx/Envoy,遵循Ingress标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。API 网关 (API Gateway),提供 APl 托管服务,覆盖设计、开发、测试、发布、售卖、运维监测、安全管控、下线等 API 生命周期阶段。帮助您快速构建以 API 为核心的系统架构.满足新技术引入、系统集成、业务中台等诸多场景需要。
|
1月前
|
缓存 监控 负载均衡
构建微服务架构下的API网关实践指南
【2月更文挑战第22天】在现代的软件开发实践中,微服务架构因其灵活性和可扩展性而成为众多企业的首选。随着服务数量的增长,有效地管理这些服务的入口——API网关,成为了确保系统稳定性和效率的关键。本文将探讨如何在微服务环境中构建一个高性能、可扩展的API网关,以及它如何帮助实现请求路由、负载均衡、认证授权和监控等功能,同时提供了一系列实施的最佳实践和面临的挑战解决方案。
|
1月前
|
消息中间件 缓存 API