Spring Cloud 系列之 Netflix Zuul 服务网关(四)

本篇文章为系列文章,未读前几集的同学请猛戳这里:

本篇文章讲解 Zuul 和 Sentinel 整合,实现网关限流和容错以及高可用网关环境搭建。

  

1|0Zuul 和 Sentinel 整合

  

  点击链接观看:Zuul 和 Sentinel 整合视频(获取更多请关注公众号「哈喽沃德先生」)

  

  Sentinel 支持对 Spring Cloud Gateway、Netflix Zuul 等主流的 API Gateway 进行限流。

  官网文档:

  

1|1网关限流和容错

  

创建项目

  

  创建 zuul-server-sentinel 项目。

  

添加依赖

  

  单独使用添加 sentinel-zuul-adapter 依赖即可。

  若想跟 Sentinel Starter 配合使用,需要加上 spring-cloud-alibaba-sentinel-gateway 依赖,同时需要添加 spring-cloud-starter-netflix-zuul 依赖来让 spring-cloud-alibaba-sentinel-gateway 模块里的 Zuul 自动化配置类生效。

  同时请将 spring.cloud.sentinel.filter.enabled 配置项置为 false(若在网关流控控制台上看到了 URL 资源,就是此配置项没有置为 false)。

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>zuul-server-sentinel</artifactId> <version>1.0-SNAPSHOT</version> <!-- 继承父依赖 --> <parent> <groupId>com.example</groupId> <artifactId>zuul-demo</artifactId> <version>1.0-SNAPSHOT</version> </parent> <!-- 项目依赖 --> <dependencies> <!-- spring cloud netflix zuul 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!-- netflix eureka client 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- 单独使用 --> <!-- sentinel zuul adapter 依赖 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-zuul-adapter</artifactId> </dependency> <!-- 和 Sentinel Starter 配合使用 --> <!-- <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> </dependency> --> </dependencies> </project>

  

配置文件

  

server: port: 9001 # 端口 spring: application: name: zuul-server-sentinel # 应用名称 cloud: sentinel: filter: enabled: false # 配置 Eureka Server 注册中心 eureka: instance: prefer-ip-address: true # 是否使用 ip 地址注册 instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port client: service-url: # 设置服务注册中心地址 defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

  

网关服务配置类

  

  配置网关服务过滤器和网关限流规则。

package com.example.config; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter; import com.netflix.zuul.ZuulFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.Set; /** * 网关服务配置类 */ @Configuration public class ZuulConfig { // 底层继承了 ZuulFilter @Bean public ZuulFilter sentinelZuulPreFilter() { // We can also provider the filter order in the constructor. return new SentinelZuulPreFilter(); } // 底层继承了 ZuulFilter @Bean public ZuulFilter sentinelZuulPostFilter() { return new SentinelZuulPostFilter(); } // 底层继承了 ZuulFilter @Bean public ZuulFilter sentinelZuulErrorFilter() { return new SentinelZuulErrorFilter(); } /** * Spring 容器初始化的时候执行该方法 */ @PostConstruct public void doInit() { // 加载网关限流规则 initGatewayRules(); } /** * 网关限流规则 */ private void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); /* resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称 count:限流阈值 intervalSec:统计时间窗口,单位是秒,默认是 1 秒 */ rules.add(new GatewayFlowRule("order-service") .setCount(3) // 限流阈值 .setIntervalSec(60)); // 统计时间窗口,单位是秒,默认是 1 秒 // 加载网关限流规则 GatewayRuleManager.loadRules(rules); } }

  

启动类

  

  ZuulServerSentinelApplication.java

package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication // 开启 Zuul 注解 @EnableZuulProxy // 开启 EurekaClient 注解,目前版本如果配置了 Eureka 注册中心,默认会开启该注解 //@EnableEurekaClient public class ZuulServerSentinelApplication { public static void main(String[] args) { SpringApplication.run(ZuulServerSentinelApplication.class, args); } }

  

访问

  

  多次访问:http://localhost:9001/order-service/order/1 触发限流后会返回固定的提示:

  

自定义限流处理(网关熔断)

  

  发生限流之后的处理流程 :

  • 发生限流之后可自定义返回参数,通过实现 ZuulBlockFallbackProvider 接口,默认的实现是 DefaultBlockFallbackProvider
  • 默认的 fallback route 的规则是 route ID 或自定义的 API 分组名称。

  

编写限流处理类

  

  OrderBlockFallbackProvider.java

package com.example.fallback; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 对订单服务做服务容错处理 */ public class OrderBlockFallbackProvider implements ZuulBlockFallbackProvider { private Logger logger = LoggerFactory.getLogger(OrderBlockFallbackProvider.class); @Override public String getRoute() { return "order-service"; // 服务名称 } @Override public BlockResponse fallbackResponse(String route, Throwable cause) { logger.error("{} 服务触发限流", route); if (cause instanceof BlockException) { return new BlockResponse(429, "服务访问压力过大,请稍后再试。", route); } else { return new BlockResponse(500, "系统错误,请联系管理员。", route); } } }

  

将限流处理类注册至 Zuul 容器

  

  ZuulConfig.java

// Spring 容器初始化的时候执行该方法 @PostConstruct public void doInit() { // 注册 FallbackProvider ZuulBlockFallbackManager.registerProvider(new OrderBlockFallbackProvider()); // 加载网关限流规则 initGatewayRules(); }

  

  多次访问:http://localhost:9001/order-service/order/1 触发限流后返回自定义提示:

  

2|0高可用网关

  

  业内通常用多少 9 来衡量网站的可用性,例如 QQ 的可用性是 4 个 9,就是说 QQ 能够保证在一年里,服务在 99.99% 的时间是可用的,只有 0.01% 的时间不可用,大约最多 53 分钟。

  对于大多数网站,2 个 9 是基本可用;3 个 9 是叫高可用;4 个 9 是拥有自动恢复能力的高可用。

  实现高可用的主要手段是数据的冗余备份服务的失效转移,这两种手段具体可以怎么做呢,在网关里如何体现?主要有以下几个方向:

  • 集群部署
  • 负载均衡
  • 健康检查
  • 节点自动重启
  • 熔断
  • 服务降级
  • 接口重试

  

2|1Nginx + 网关集群实现高可用网关

  

  

下载

  

  官网:http://nginx.org/en/download.html 下载稳定版。为了方便学习,请下载 Windows 版本。

  

安装

  

  解压文件后直接运行根路径下的 nginx.exe 文件即可。

  Nginx 默认端口为 80,访问:http://localhost:80/ 看到下图说明安装成功。

  

配置网关集群

  

  进入 Nginx 的 conf 目录,打开 nginx.conf 文件,配置网关集群:

http { ... # 网关集群 upstream gateway { server 127.0.0.1:9000; server 127.0.0.1:9001; } server { listen 80; server_name localhost; ... # 代理网关集群,负载均衡调用 location / { proxy_pass http://gateway; } ... } ... }

  

访问

  

  启动两台网关服务器 http://localhost:9000/http://localhost:9001/ 和相关服务。

  访问:http://localhost/product-service/product/1 实现高可用网关。

  

总结

  

  一个请求过来,首先经过 Nginx 的一层负载,到达网关,然后由网关负载到真实后端,若后端有问题,网关会进行重试访问,多次访问后仍返回失败,可以通过熔断或服务降级立即返回结果。而且,由于是负载均衡,网关重试时不一定会访问到出错的后端。

  至此 Zuul 服务网关所有的知识点就讲解结束了。

posted @ 2020-05-11 10:13  YoungDeng  阅读(203)  评论(0编辑  收藏  举报