咱们接上回

上一节我们基于Sentinel实现了微服务体系下的限流和熔断,使得整个微服务架构的安全性和稳定性上升了一个台阶

篇尾我们引出了一个问题,众多的微服务节点,我们如何部署才能满足客户端简洁高效的访问需求?

—— 今天我们就来引入服务网关的概念

什么是服务网关?

服务网关是微服务体系下唯一的流量入口,对内实现内部架构统合,所有外来请求都要经由网关路由到对应的微服务节点,进而实现完整的业务逻辑

由于是每个外部请求的必经之路,因此除了路由之外,服务网关还可以胜任几乎所有的横切面功能,比如我们上一节提到的限流、熔断,以及统一的认证服务、日志监控等

使用服务网关的优势:

1. 客户端简化 —— 加入服务网关之后,客户端只需要知道服务网关的访问地址即可,而不再需要了解每个微服务的访问端口

2. 降低耦合度 —— 其他微服务节点有变动,我们只需要灵活调整服务网关的路由即可,不必每次都去修改客户端

3. 提升可维护性 —— 由服务网关统一实现路由、灰度发布、负载均衡、限流熔断等机制,开发人员更专注于业务实现

引入服务网关带来的弊端:

微服务架构讲求去中心化,而网关的引入使之变成了唯一的单点,其高可用性和可维护性变成了必须要解决的课题

如下是服务网关的基本功能以及常见的几种服务网关的对比:(图示来自:CSDN 张维鹏,感谢)

我们本节重点关注 SpringCloudGateway 的用法,其他感兴趣大家可以自行了解

新建nacos-sentinel-gateway模块

我们首先创建一个新模块并引入如下依赖项:

很多依赖项我们已经很熟悉了,这里重新说明一下他们的用途:

Nacos Service Discovery —— 基于Nacos实现服务发现

Nacos Configuration —— 基于Nacos实现配置中心

Spring Cloud Alibaba Sentinel —— Sentinel限流熔断组件,我们上一节的主要内容

Cloud Bootstrap —— bootstrap.yml 加载机制,实现Nacos云配置的关键

Gateway —— 即 SpringCloudGateway,我们本节关注的重点

Spring Cloud Alibaba Sentinel Gateway —— Sentinel组件对于SpringCloudGateway的适配机制,本节后半部分我们要用到

值得注意的是:SpringCloudGateway内部直接包含了spring-boot-starter-web依赖,如果你的工程中同时包含二者的引用,会报冲突错误

解决的办法是添加spring-cloud-starter-gateway的同时排除掉spring-boot-starter-web

<!-- 引入gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>

由于本节中不牵扯spring-boot-starter-web的使用,所以不存在这个问题,如下是本节的设计到的各个依赖项在pom中的声明:

        <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

项目工程目录如下:

   

本节相较于之前第一个不同点来了,配置文件不再是.properties,而是变成了.yml,后者比前者的表达能力更强,且比xml更简洁

.yml是yaml的一个变种(基本完全一样),非常适合作为配置文件,它不但可以表示变量,还可以声明数组及字典

这里给大家提供一个可以在线将.properties转换为.yml的工具,非常的方便,感谢BeJSON站长

====================================

在线properties转yaml、yml工具 - BeJSON.com

====================================

如下是转换完毕后的bootstrap.yml

spring:
cloud:
nacos:
config:
username:nacos
password:nacos
contextPath:/nacos
server-addr:127.0.0.1:8848

内容依然仅是nacos的声明,为便于测试效果,本节使用了本地的application.yml,因此bootstrap.yml中并未包含spring.application.name的声明

而如果我们打算将application.yml托管给nacos,则必须在bootstrap.yml中声明spring.application.name

然后我们来看application.yml的内容,这将是本节的重点

spring:
application:
name: nacos-sentinel-gateway
cloud:
gateway:
enabled: true
routes:
- id: dubbo-nacos-consumer
uri: http://127.0.0.1:8080
order: 1
predicates:
- Path=/consumer/**
filters:
- StripPrefix=1
server:
port: 8081

到这里,网关服务就可以直接跑起来了

啥?还没写代码呢!是的,一句代码不用写,来一个配置文件,你的服务网关就已经搭建起来了,非常方便对不?

我们分析下gateway的相关配置,不难看出其中的端倪:

1. route(路由)是gateway的基本配置单元,说白了就是搭建网关从设定路由规则开始

2. 每个route都包含四部分:

id —— 路由标识,自行命名,不重复即可

uri —— 请求转发的真实目标地址

order —— 优先级,数字越小代表优先级越高

predicates —— 断言(数组),用于判定转发规则是否成立

filters —— 过滤器(数组),请求url ---> 过滤器处理 --->目标url,定义了url的变换规则

我们以此来解读一下上述的网关路由到底定义了一个怎样的转发规则

id —— 和我们之前构建的dubbo-nacos-consumer同名,那下述转发规则自然与其有关

uri —— dubbo-nacos-consumer监听8080端口,因此我们打算将请求转发给dubbo-nacos-consumer服务

order —— 1代表高优先级

predicates —— Path=/consumer/**,代表请求路径中需要包含/consumer/的前缀,也就说我们会将路径中包含/consumer/的请求转发给dubbo-nacos-consumer服务

filters —— StripPrefix=1,是我们以后经常会遇到的一种过滤器,含义为过滤一级前缀,这里的前缀就是上边提到的/consumer前缀

这是什么意思?

我们网关监听的端口是8081,

假定我们的请求为 http://127.0.0.1:8081/consumer/person/select ,

因为满足包含前缀/consumer/的设定,请求被转发到 http://127.0.0.1:8080/consumer/person/select ,

而过滤器会过滤掉/consumer前缀,于是请求路径变为 http://127.0.0.1:8080/person/select

而这正是dubbo-nacos-consumer中的PersonController.select方法的有效映射

我们依次启动先前创建的 dubbo-nacos-provider 、dubbo-nacos-consumer 以及我们刚创建好的 nacos-sentinel-gateway

打开post执行请求验证下结果

结果证实了我们的猜想,这样一来我们就简单实现了服务网关的路由功能

虽然功能是实现了,但是你有没有发现,我们是直接指定了转发的目标地址,这种模式配置的路由规则存在几个非常大的弊端:

1. 网关必须知道所有微服务的地址,并且逐一配置

2. 微服务地址有任何变动,网关必须做同步更改

3. 无法实现负载均衡

那么有没有其他配置方式可以避开这些不足?当然是有的!

基于Nacos服务发现实现负载均衡

我们将app.yml的内容做如下改动:

spring:
application:
name: nacos-sentinel-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
enabled: true
routes:
- id: dubbo-nacos-consumer
uri: lb://dubbo-nacos-consumer
predicates:
- Path=/consumer/**
filters:
- StripPrefix=1
server:
port: 8081

相比于前一个版本,我们有两个地方的改动

首先,我们加入了基于Nacos的服务发现配置:

  cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848

其次,我们原有固定的转发地址改为了另一种形式:uri: lb://dubbo-nacos-consumer

这种模式遵循的固定格式为:lb://service-name

lb —— load balancing的缩写,即负载均衡

service-name —— Nacos中注册的服务名称,注意这里是名称,而并非ip

lb://dubbo-nacos-consumer 代表如果断言成立,则请求将均衡的分发至各个dubbo-nacos-consumer的服务实例

我们先在post中执行验证下结果:

结果跟前一个版本是一样的,印证了这种配置模式是有效的

但是由于我们的dubbo-nacos-cosumer服务只有一个实例,所以看不出来负载均衡的效果

幸运的是,在idea之下我们可以非常方便的配置另一个启动实例

为了便于对比,我们先把consumer的application.properties配置文件迁移回本地,并删除nacos的云端配置

而后我们创建另一个新的配置文件application-anotherr.properties,内容如下:

# 应用名称
spring.application.name=dubbo-nacos-consumer
# dubbo 协议
dubbo.protocol.id=dubbo
dubbo.protocol.name=dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
dubbo.protocol.port=-1
# Dubbo 消费端订阅服务端的应用名,多个服务提供者用逗号分隔
dubbo.cloud.subscribed-services=dubbo-nacos-provider
# dubbo 服务扫描基准包
dubbo.scan.base-packages=com.example.dubbonacosconsumer
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public # 应用服务 WEB 访问端口
server.port=8098 # sentinel看板配置
spring.cloud.sentinel.transport.dashboard = 127.0.0.1:9999
# 开启对sentinel看板的饥饿式加载。sentinel默认是懒加载机制,只有访问过一次的资源才会被监控,通过关闭懒加载,在项目启动时就连接sentinel控制台
spring.cloud.sentinel.eager = true

内容与application.properties基本相同,区别仅在于

# 应用服务 WEB 访问端口
server.port=8098

我们知道,同一台机器,同一个监听端口智能使用一次,因此如果想借用idea直接在开发环境下起另一个服务实例,则需要开启另一个不同的端口

然后我们创建一个新的启动配置

最关键的一句配置:

--spring.profiles.active=another

代表我们指定程序的启动配置文件为:application-anotherr.properties

为了与原始的consumer做区分,我们先启动consumer,然后改一下consumer的PersonController内容,再启动another-consumer

    @GetMapping("/select")
@SentinelResource(value = "person/select", blockHandler = "selectBlock")
public SelectRetVo select() {
SelectRetVo vo = new SelectRetVo();
vo.setPersons(service.select());
vo.setError("ok-another"); // another的区别
return vo;
}

此刻我们打开Nacos的服务中心,会看到dubbo-nacos-consumer存在两个运行中的实例

然后我们再次通过Post访问网关验证结果

 

返回结果中的 ok 和 ok-another 会交替出现

看到效果了吗?原始consumer和another-consumer都是动态启动的,而基于Nacos服务发现机制,

gateway在无感知的情况下,完全不做任何改动,就实现了多个consumer实例的动态负载均衡,是不是非常便捷?

那除了 lb://service-name 这种方式,还有没有更简单的办法?当然是有的!

基于Naocs的全自动路由配置

我们再次改动gateway的app.yml配置文件内容

spring:
application:
name: nacos-sentinel-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
enabled: true
discovery:
locator:
enabled: true
lower-case-service-id: true
server:
port: 8081

这一次我们没有特别指定下游节点的ip,也没有配置相关的负载均衡,那这样写实现了什么效果?

我先给大家看Post的测试结果:

我们来和前边的负载均衡示例做下对比:

前次的访问地址:http://localhost:8081/consumer/person/select

本地的访问地址:http://localhost:8081/dubbo-nacos-consumer/person/select

看到区别了吗?这样写相当于 lb://默认spring.application.name

仅是这样吗?其实还不止!仔细看,本次配置中我们并没有指定特定的service-name开负载均衡!

也就是说这种模式之下,所有注册到Nacos服务中心的外部可访问Web节点实例均启动负载均衡设定!

不信你可以仿照刚刚的consumer,自己再起一组支持web访问的实例,随便写几个controller测试方法,结果一试便知,gateway同样满足无感知访问

本节中我们对SpringCloudGateway分别进行了 从特定ip配置,到指定服务的负载均衡,再到全自动动态负载均衡 的一个统一的介绍,但SpringCloudGateway的使用其实还远不止这些

对 断言 和 过滤器 更加细化的定制还可以帮我们过滤掉各种场景下的外部非法访问,从而对整个内部集群的稳定性起到一个更加的有效的防护作用

但是我们要思考一个问题 —— 微服务体系下的不稳定因素仅来自于集群外部吗?答案显然不是!我们面临的业务需求是丰富多样的,集群内部同样可能出现性能消耗的热点

那么当问题发生在微服务体系内部时,我们如何实现问题及热点的精准定位呢?请看下回 —— 基于Spring Cloud Sleuth的链路追踪,敬请期待~

2流高手速成记(之九):基于SpringCloudGateway实现服务网关功能的更多相关文章

  1. 2流高手速成记(之七):基于Dubbo&Nacos的微服务简要实现

    本节内容会用到之前给大家讲过的这两篇: 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba 2流高手速成记(之三):SpringBoot整合mybatis/mybat ...

  2. 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba

    咱们接上回 2流高手速成记(之五):Springboot整合Shiro实现安全管理 - 14号程序员 - 博客园 (cnblogs.com) 身边常有朋友说:小项目用PHP.大项目用Java(这里绝无 ...

  3. 2流高手速成记(之八):基于Sentinel实现微服务体系下的限流与熔断

    我们接上回 上一篇中,我们进行了简要的微服务实现,也体会到了SpringCloudAlibaba的强大和神奇之处 我们仅改动了两个注释,其他全篇代码不变,原来的独立服务就被我们分为了provider和 ...

  4. 2流高手速成记(之三):SpringBoot整合mybatis/mybatis-plus实现数据持久化

    接上回 上一篇我们简单介绍了基于SpringBoot实现简单的Web开发,本节来看Web开发中必不可少的内容--数据持久化 先看项目结构: 1. 创建数据表 打开mysql,打开数据库 test (没 ...

  5. 2流高手速成记(之四):SpringBoot整合redis及mongodb

    最近很忙,好不容易才抽出了时间,咱们接上回 上次我们主要讲了如何通过SpringBoot快速集成mybatis/mybatis-plus,以实现业务交互中的数据持久化,而这一切都是基于关系型数据库(S ...

  6. 2流高手速成记(之五):Springboot整合Shiro实现安全管理

    废话不多说,咱们直接接上回 上一篇我们讲了如何使用Springboot框架整合Nosql,并于文章最后部分引入了服务端Session的概念 而早在上上一篇中,我们则已经讲到了如何使用Springboo ...

  7. 基于 orange(nginx+openresty) + docker 实现微服务 网关功能

    摘要 基于 orange(nginx+openresty) + docker 实现微服务 网关功能 ;以实现 docker 独立容器 来跑 独立语言独立环境 在 同一个授权下 运行相关组合程序..年初 ...

  8. 九、springcloud之服务网关zuul(二)

    一.路由熔断 当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级.Zuul给我们提供了这样的支持.当某个服务出现异常时,直接返回我们预设的信息. 我们通过自定义的 ...

  9. 高手速成android开源项目【导航篇】

    Android开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的一个 ...

  10. [js高手之路]Vue2.0基于vue-cli+webpack Vuex用法详解

    在这之前,我已经分享过组件与组件的通信机制以及父子组件之间的通信机制,而我们的vuex就是为了解决组件通信问题的 vuex是什么东东呢? 组件通信的本质其实就是在组件之间传递数据或组件的状态(这里将数 ...

随机推荐

  1. 配置联想IMM使用AD账户登录

    IMM是联想(IBM)服务器的管理卡Integrated Management Module的缩写,现在是第二个版本.通过它可以远程管理服务器,就像你在服务器面前操作一样.可以修改BIOS设置,可以重 ...

  2. 我的Vue之旅、02 ES6基础、模块、路径、IO

    自定义模块 为什么要模块?模块化源代码能给我们带来什么好处? 试想一个巨无霸网购平台,在没有模块化的情况下,如果出现bug,程序员就要在几百万行代码里调试,导致后期维护成本上升,为了解决问题,模块化按 ...

  3. Logstash:使用ELK堆栈进行API分析

  4. portainer 1.24.2 升级到 portainer-ce 最新版

    官方升级步骤文档: https://docs.portainer.io/v/ce-2.9/start/upgrade/docker 若是现在的版本是 portainer-ce 2.0.0 ,看Opti ...

  5. Elasticsearch的ETL利器——Ingest节点

    文章转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484473&idx=1&sn=1b3b07b ...

  6. IDE->Gitlab->Gitlab CI/CD->Docker->K8S流程

    前提条件: Gitlab,Gitlab CI/CD,Nexus,K8S 步骤流程: 1.开发人员IDE上传更新代码到Gitlab 2.Gitlab收到用户提交的更新后会自动CI/CD,并创建Docke ...

  7. 第三周python作业

    import datetime mot = ["今天星期一:\n坚持下去不是因为我很坚强,而是因为我别无选择.", "今天星期二:\n含泪播种的人一定会笑着收." ...

  8. 企业使用erp系统的好处及解决了什么问题?

    不是所有的企业使用ERP都能带来好处的,尤其是对于一些小微企业,带来的可能是灾难,而实施不适用的系统同样也会带来意想不到的后果,所以在ERP的使用方面得根据自己企业实际做决定.不同规模的企业选用不同的 ...

  9. 持续集成指南:GitLab 的 CI/CD 工具配置与使用

    前言 写代码这项工作,本质就是将工作自动化,减少手工操作提供效率,因为人的本质都是懒狗,程序员也不能例外,为了各种意义的效率提升(懒),我们需要持续集成工具,将代码测试.编译.发布这些重复性很高的工作 ...

  10. 在Linux/redhat中安装amazon-ssm-agent及注意事项

    操作系统:Red Hat Enterprise Linux Server release 7.9 (Maipo) 首先说明一下SSM是什么.引用官网的说明: AWS Systems Manager A ...