微服务深入浅出(7)-- 网关路由Zuul
Zuul用于构建边界服务,致力于动态路由,过滤,监控,弹性伸缩和安全等方向。
1、Zuul+Ribbon+Eureka结合,可以实现智能路由和负载均衡
2、网关将所有服务的API接口统一聚合统一暴露
3、网关统一爆率接口后,可以做身份和权限认证
4、实现监控功能,实时日志输出
5、流量监控,实现降级和限流
6、方便测试
1、网关存在的必要性
不同的微服务有不同的请求地址,如果一个客户端需要访问多个接口才能完成一个业务需求的话,可能存在以下问题:
# 客户端会多次请求不同微服务,增加客户端的复杂性
# 存在跨域请求,在一定场景下处理相对复杂
# 认证复杂,每一个服务都需要独立认证
# 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通信,那么重构会难以实施
# 某些微服务可能使用了其他协议,直接访问有一定困难
而微服务网关可以很好的解决这个问题:
这样客户端只需要和网关交互,而无需直接调用特定微服务的接口,而且方便监控,易于认证,减少客户端和各个微服务之间的交互次数。
2、主流解决方案
# Spring Cloud Gateway
# Zuul
Zuul基于 servlet 2.5(使用3.x),使用阻塞API。 它不支持任何 长连接 ,如 web sockets。而Gateway建立在Spring Framework 5,Project Reactor和Spring Boot 2之上,使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的开发体验。
参考:https://juejin.im/post/5aa4eacbf265da237a4ca36f
3、模拟场景
客户端请求后端服务,网关提供后端服务的统一入口。后端的服务都注册到Zookeeper、Consul或者Eureka (服务发现、配置管理中心服务)。网关通过负载均衡。转发到具体的后端服务。
4、Zuul
Zuul 提供了四种过滤器的 API,动态读取、编译和运行这些过滤器。过滤器之间不能相互通讯,只能通过RequestContext对象共享数据。
# 前置(Pre)鉴权、请求转发、增加请求参数等行为
一般来说整个服务的鉴权逻辑可以很复杂。
- 客户端:App、Web、Backend
- 权限组:用户、后台人员、其他开发者
- 实现:OAuth、JWT
- 使用方式:Token、Cookie、SSO
而对于后端应用来说,它们其实只需要知道请求属于谁,而不需要知道为什么,所以 Gateway 可以友善的帮助后端应用完成鉴权这个行为,并将用户的唯一标示透传到后端,而不需要、甚至不应该将身份信息也传递给后端,防止某些应用利用这些敏感信息做错误的事情。Zuul 默认情况下在处理后会删除请求的 Authorization
头和 Set-Cookie
头,也算是贯彻了这个原则。
# 后置(Post)统计返回值和调用时间、记录日志、增加跨域头等行为
使用 Gateway 做跨域相比应用本身或是 Nginx 的好处是规则可以配置的更加灵活。例如一个常见的规则。
对于任意的 AJAX 请求,返回
Access-Control-Allow-Origin
为*
,且Access-Control-Allow-Credentials
为true
,这是一个常用的允许任意源跨域的配置,但是不允许请求携带任何 Cookie如果一个被信任的请求者需要携带 Cookie,那么将它的
Origin
增加到白名单中。对于白名单中的请求,返回Access-Control-Allow-Origin
为该域名,且Access-Control-Allow-Credentials
为true
,这样请求者可以正常的请求接口,同时可以在请求接口时携带 Cookie对于 302 的请求,即使在白名单内也必须要设置
Access-Control-Allow-Origin
为*
,否则重定向后的请求携带的Origin
会为null
,有可能会导致 iOS 低版本的某些兼容问题
Gateway 可以统一收集所有应用请求的记录,并写入日志文件或是发到监控系统,相比 Nginx 的 access log,好处主要也是二次开发比较方便,比如可以关注一些业务相关的 HTTP 头,或是将请求参数和返回值都保存为日志打入消息队列中,便于线上故障调试。也可以收集一些性能指标发送到类似 Statsd 这样的监控平台。
# 路由(Route)一般只需要选择 Zuul 中内置的即可
#错误(Error)一般只需要一个,这样可以在 Gateway 遇到错误逻辑时直接抛出异常中断流程,并直接统一处理返回结果
错误过滤器的主要用法就像是 Jersey 中的 ExceptionMapper
或是 Spring MVC 中的 @ExceptionHandler
一样,在处理流程中认为有问题时,直接抛出统一的异常,错误过滤器捕获到这个异常后,就可以统一的进行返回值的封装,并直接结束该请求。
总结关键特性:
1、Type,规定类型
2、Execution Order,规定执行顺序,Order值越小越优先
3、Criteria,规定执行所需要的条件
4、Action,如果符合条件,则执行Action
一个请求会先按顺序通过所有的前置过滤器,之后在路由过滤器中转发给后端应用,得到响应后又会通过所有的后置过滤器,最后响应给客户端。在整个流程中如果发生了异常则会跳转到错误过滤器中。
5、注解配置
/** * 这个接口需要鉴权,鉴权方式是 OAuth */@Authorization(OAuth)@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)public void del(@PathVariable int id) { //... } /** * 这个接口可以缓存,并且每个 IP/User 每秒最多请求 10 次 */@Cacheable@RateLimiting(limit = "10/1s", scope = {IP, USER})@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)public void info(@PathVariable int id) { //... }
6、稳定性
# 隔离机制
在 Zuul 中,每一个后端应用都称为一个 Route,为了避免一个 Route 抢占了太多资源影响到其他 Route 的情况出现,Zuul 使用 Hystrix 对每一个 Route 都做了隔离和限流。
Hystrix 的隔离策略有两种,基于线程或是基于信号量。Zuul 默认的是基于线程的隔离机制,这意味着每一个 Route 的请求都会在一个固定大小且独立的线程池中执行,这样即使其中一个 Route 出现了问题,也只会是某一个线程池发生了阻塞,其他 Route 不会受到影响。一般使用 Hystrix 时,只有调用量巨大会受到线程开销影响时才会使用信号量进行隔离策略,对于 Zuul 这种网络请求的用途使用线程隔离更加稳妥。
# 重试机制
Zuul 的路由主要有 Eureka 和 Ribbon 两种方式,简单介绍下 Ribbon 支持哪些容错配置。
重试的场景分为三种:
okToRetryOnConnectErrors
:只重试网络错误okToRetryOnAllErrors
:重试所有错误OkToRetryOnAllOperations
:重试所有操作(这里不太理解,猜测是 GET/POST 等请求都会重试)
重试的次数有两种:
MaxAutoRetries
:每个节点的最大重试次数MaxAutoRetriesNextServer
:更换节点重试的最大次数
一般来说我们希望只在网络连接失败时进行重试、或是对 5XX 的 GET 请求进行重试(不推荐对 POST 请求进行重试,无法保证幂等性会造成数据不一致)。单台的重试次数可以尽量小一些,重试的节点数尽量多一些,整体效果会更好。
如果有更加复杂的重试场景,例如需要对特定的某些 API、特定的返回值进行重试,那么也可以通过实现 RequestSpecificRetryHandler
定制逻辑(不建议直接使用 RetryHandler
,因为这个子类可以使用很多已有的功能)。
7、Tomcat
Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能和CPU数量都有很大关系的。更好的硬件,更多的处理器都会使Tomcat支持更多的并发。
Tomcat 默认的HTTP实现是采用阻塞式的Socket通信,每个请求都需要创建一个线程处理,当一个进程有500个线程在跑的话,那性能已经是很低很低了。Tomcat默认配置的最大请求数是150,也就是说同时支持150个并发。具体能承载多少并发,需要看硬件的配置,CPU越多性能越高,分配给JVM的内存越多性能也就越高,但也会加重GC的负担。当某个应用拥有 250个以上并发的时候,应考虑应用服务器的集群。操作系统对于进程中的线程数有一定的限制:
Windows 每个进程中的线程数不允许超过 2000
Linux 每个进程中的线程数不允许超过 1000
在Java中每开启一个线程需要耗用1MB的JVM内存空间用于作为线程栈之用,此处也应考虑。
8、实际应用
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
启动类开启zuul代理:
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);} }
配置文件配置路由信息:
server:port: 9009 spring:application:name: zuul-client eureka:client:service-url:defaultZone: http://localhost:9001/eureka/ zuul:routes:hiapi:path: /hiapi/**serviceId: hi-service
访问:http://localhost:9009/hiapi/hi,如果hi-service部署了多个实例,那么zuul在路由转发就做了负载均衡。
当然也可以使用url属性代替serviceId属性,通过指定ip+port的方式的url地址来直接访问(当然这种情况很少出现)
如果想自己维护负载均衡的服务列表,可以使用如下方式:
zuul:routes:hiapi:path: /hiapi/**serviceId: hiapi-v1 ribbon:eureka:enabled: false hiapi-v1:ribbon:listOfServers: http://localhost:9007,http://localhost:9008,http://localhost:9009/hiapi/hi
配置API接口的版本号:
zuul:routes:hiapi:path: /hiapi/**serviceId: hi-service prefix: v1
那么访问路径将变为:http://localhost:9009/v1/hiapi/hi
集成Hystrix实现熔断器:
@Component public class MyFallbackProvider implements FallbackProvider {@Overridepublic String getRoute() {return "hi-service"; // 应用名称或者serviceId,或者是正则表达式,如*}@Overridepublic ClientHttpResponse fallbackResponse(String route, final Throwable cause) {if (cause instanceof HystrixTimeoutException) {return response(HttpStatus.GATEWAY_TIMEOUT);} else {return response(HttpStatus.INTERNAL_SERVER_ERROR);}}private ClientHttpResponse response(final HttpStatus status) {return new ClientHttpResponse() {@Overridepublic HttpStatus getStatusCode() throws IOException {return status;}@Overridepublic int getRawStatusCode() throws IOException {return status.value();}@Overridepublic String getStatusText() throws IOException {return status.getReasonPhrase();}@Overridepublic void close() {}@Overridepublic InputStream getBody() throws IOException {return new ByteArrayInputStream("fallback".getBytes());}@Overridepublic HttpHeaders getHeaders() {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);return headers;}};} }
在Zuul中使用过滤器:
@Component public class MyFilter extends ZuulFilter {@Overridepublic String filterType() {return FilterConstants.PRE_TYPE; // 前置过滤器
}@Overridepublic int filterOrder() {return 0; // 优先级为0,数字越大,优先级越低}@Overridepublic boolean shouldFilter() {return true; // 是否执行该过滤器,此处为true,说明需要过滤}@Overridepublic Object run() throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();String token = request.getParameter("token");if (StringUtils.isBlank(token)) {ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(401);try {ctx.getResponse().getWriter().write("token is empty");} catch (IOException e) { }}return null;} }
转载于:https://www.cnblogs.com/ijavanese/p/9198203.html
微服务深入浅出(7)-- 网关路由Zuul相关推荐
- 搭建springcloud微服务下的网关Netfilx Zuul
原创文章转载请注明来源:https://blog.csdn.net/weixin_41756573/article/details/88689617 1.pom.xml(基于springboot2.0 ...
- 认识微服务(七)之 Zuul 网关
认识微服务(七)之 Zuul 网关 1 简介 2 Zuul 加入后的架构 3 快速入门 3.1 新建工程 3.2 编写启动类 3.3 编写配置 3.4 编写路由规则 3.5 启动测试 4 面向服务的路 ...
- gateway动态路由_微服务中的网关技术:Gateway
技术/杨33 一.Gateway是什么 为微服务提供一种简单有效的统一的API路由管理方式. Gateway是基于WebFlux框架实现的,而WebFlux框架底层使用了高性能的Reactor模式通讯 ...
- 微服务之API网关接口设计
微服务之API网关接口设计 API网关,顾名思义,就是外部到内部的一道门,其主要功能: 服务路由:将前段应用的调用请求路由定位并负载均衡到具体的后端微服务实例,对于前端应用看起来就是1个应用提供的服务 ...
- gateway sentinel 熔断 不起作用_微服务Gateway新一代网关
上篇: https://zhuanlan.zhihu.com/p/183930681zhuanlan.zhihu.com 一.概述简介 1.官网 上一代zuul 1.x:Netflix/zuul 当 ...
- 微服务之API网关:Kong:概要与安装
Kong是一个基于Apache License 2.0的开源项目,是一个云原生的快速可扩的分布式微服务抽象层,应用场景为微服务的API网关,类似于spring cloud的zuul. 概要信息 项目 ...
- 【云原生微服务>SCG网关篇十二】Spring Cloud Gateway集成Sentinel API实现多种限流方式
文章目录 一.前言 二.Gateway集成Sentinel API 0.集成Sentinel的核心概念 1)GatewayFlowRule 和 ApiDefinition 2)GatewayFlowR ...
- AspNetCore微服务下的网关-Kong(一)
Kong是Mashape开源的高性能高可用API网关和API服务管理层.它基于OpenResty,进行API管理,并提供了插件实现API的AOP.Kong在Mashape 管理了超过15,000 个A ...
- nginx工作笔记005---nginx配置负载均衡_在微服务中实现网关集群_实现TCP传输层协议__http协议的负载均衡
技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 我们在微服务中,由于网关的存在,后来,在nginx中都不需要在配置其他服务的地址了,只需要,配置一 ...
- 《企业IT架构转型之道》随笔之SOA、ESB、微服务、API网关(2019-08-07)
<企业IT架构转型之道>随笔之SOA.ESB.微服务.API网关(2019-08-07) 名词注释 为什么会进化 展望 作者在本章中提到的"烟筒式"系统建设模式,在目前 ...
最新文章
- “年轻”有价值,才是本钱
- R语言ggplot2可视化:ggplot2可视化两个水平条形图(horizontal)、并设置两个条形图使用共享的X轴、使用类似population pyramid可视化的方式绘制共享X轴的水平条形图
- Python学习笔记:类
- Link State ID
- 列注释_机器学习 Pandas 03:基础 前16题 ( 带答案、注释 )
- 云服务器拷贝文件大小,如何从云服务器上拷贝大文件
- 于掌控板实现简单的抢答器系统
- 消息中间件学习总结(22)——MQ 面试专题
- Vue入门之animate过渡动画效果
- Ajax不起作用....
- python中怎么替换字母_python去除拼音声调字母,替换为字母的方法
- odoo pivot中去掉求和_JDK 7 中的 Fork/Join 模式
- 【原创】MySQL 模拟PostgreSQL generate_series 表函数
- python文章伪原创_文章伪原创工具制作
- 基于Android 平台简易即时通讯的研究与设计
- 陪我到可可西里看一看海,不要未来,只要你来。——大冰 《陪我到可可西里去看海》
- LoadRunner--并发测试(多用户)
- 【Linux系统】第10节 linux系统文件及目录权限详解
- 关于js文本框数字校验
- python数据分析建模-十分钟搞懂“Python数据分析”
热门文章
- Codeforces Round #645 (Div. 2)(AB)
- Deep GSP : 面向多目标优化的工业界广告智能拍卖机制
- blp模型 上读下写_Golang 并发模型系列:1. 轻松入门流水线模型
- Guice使用入门以及整合Redis
- FreeMaker+Xml导出word(含图片)
- pl/sql中文显示为乱码解决
- C++双冒号和单冒号的用法区别
- C# 中的char 和 byte
- mac中修改系统限制量--ulimit和sysctl
- word插入参考文献、目录及公式对齐方法