2流高手速成记(之九):基于SpringCloudGateway实现服务网关功能
咱们接上回
上一节我们基于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实现服务网关功能的更多相关文章
- 2流高手速成记(之七):基于Dubbo&Nacos的微服务简要实现
本节内容会用到之前给大家讲过的这两篇: 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba 2流高手速成记(之三):SpringBoot整合mybatis/mybat ...
- 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba
咱们接上回 2流高手速成记(之五):Springboot整合Shiro实现安全管理 - 14号程序员 - 博客园 (cnblogs.com) 身边常有朋友说:小项目用PHP.大项目用Java(这里绝无 ...
- 2流高手速成记(之八):基于Sentinel实现微服务体系下的限流与熔断
我们接上回 上一篇中,我们进行了简要的微服务实现,也体会到了SpringCloudAlibaba的强大和神奇之处 我们仅改动了两个注释,其他全篇代码不变,原来的独立服务就被我们分为了provider和 ...
- 2流高手速成记(之三):SpringBoot整合mybatis/mybatis-plus实现数据持久化
接上回 上一篇我们简单介绍了基于SpringBoot实现简单的Web开发,本节来看Web开发中必不可少的内容--数据持久化 先看项目结构: 1. 创建数据表 打开mysql,打开数据库 test (没 ...
- 2流高手速成记(之四):SpringBoot整合redis及mongodb
最近很忙,好不容易才抽出了时间,咱们接上回 上次我们主要讲了如何通过SpringBoot快速集成mybatis/mybatis-plus,以实现业务交互中的数据持久化,而这一切都是基于关系型数据库(S ...
- 2流高手速成记(之五):Springboot整合Shiro实现安全管理
废话不多说,咱们直接接上回 上一篇我们讲了如何使用Springboot框架整合Nosql,并于文章最后部分引入了服务端Session的概念 而早在上上一篇中,我们则已经讲到了如何使用Springboo ...
- 基于 orange(nginx+openresty) + docker 实现微服务 网关功能
摘要 基于 orange(nginx+openresty) + docker 实现微服务 网关功能 ;以实现 docker 独立容器 来跑 独立语言独立环境 在 同一个授权下 运行相关组合程序..年初 ...
- 九、springcloud之服务网关zuul(二)
一.路由熔断 当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级.Zuul给我们提供了这样的支持.当某个服务出现异常时,直接返回我们预设的信息. 我们通过自定义的 ...
- 高手速成android开源项目【导航篇】
Android开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的一个 ...
- [js高手之路]Vue2.0基于vue-cli+webpack Vuex用法详解
在这之前,我已经分享过组件与组件的通信机制以及父子组件之间的通信机制,而我们的vuex就是为了解决组件通信问题的 vuex是什么东东呢? 组件通信的本质其实就是在组件之间传递数据或组件的状态(这里将数 ...
随机推荐
- Dart 2.18 正式发布
互操作性增强.平台特定的网络组件.优化类型推断,以及空安全语言里程碑的近期更新 文/ Michael Thomsen, Google Flutter & Dart 产品经理 Dart 2.18 ...
- 为中小企业打造的数字化采购SaaS平台的特点与必要性
激烈的市场竞争.复杂的国际环境.以及疫情的常态化将企业的供应链推向风口浪尖.供应链管理(SCM, Supply Chain Management).供应商关系管理(SRM,Supplier Rela ...
- winfrom杀死进程及关闭进程
ProcessStartInfo process = new ProcessStartInfo(); process.FileName = AppDomain.CurrentDomain.BaseDi ...
- flink-cdc同步mysql数据到hive
本文首发于我的个人博客网站 等待下一个秋-Flink 什么是CDC? CDC是(Change Data Capture 变更数据获取)的简称.核心思想是,监测并捕获数据库的变动(包括数据 或 数据表的 ...
- Alertmanager篇
报一直是整个监控系统中的重要组成部分,Prometheus监控系统中,采集与警报是分离的.警报规则在 Prometheus 定义,警报规则触发以后,才会将信息转发到给独立的组件 Alertmanage ...
- LeetCode - 数组遍历
1. 485. 最大连续 1 的个数 1.1 分析题意 首先:我们求的是连续的1的个数,所以我们不能也没必要对数组进行排序: 其次:只要求求出最大连续1的个数,并不要求具体的区间数目,所以我们只需要用 ...
- 一个终端工具竟然有AI功能?使用了1天我立马把其他终端全卸载了!太香了!
前言 平常工作需要频繁使用终端工具,有一个好的命令行终端工具是非常重要的. 尤其是使用mac的小伙伴,估计不少人都觉得iterm2才是最好的终端工具. 其实起初我也是这么觉得的,但是最近直到我使用了这 ...
- POJ1734 Sightseeing trip (Floyd求最小环)
学习了一下用Floyd求最小环,思路还是比较清晰的. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring ...
- 这些不知道,别说你熟悉 Spring
大家好,这篇文章跟大家来聊下 Spring 中提供的常用扩展点.Spring SPI 机制.以及 SpringBoot 自动装配原理,重点介绍下 Spring 基于这些扩展点怎么跟配置中心(Apoll ...
- YOLOv5】LabVIEW+OpenVINO让你的YOLOv5在CPU上飞起来
前言 上一篇博客给大家介绍了使用opencv加载YOLOv5的onnx模型,但我们发现使用CPU进行推理检测确实有些慢,那难道在CPU上就不能愉快地进行物体识别了吗?当然可以啦,这不LabVIEW和O ...