Zuul1.0的通信模型
Zuul2.0的通信模型
Zuul是通过Servlet来实现的(Servlet 会为每个请求绑创建一个线程,而线程上线文切换,内存消耗大),Zuul通过自定义的ZuulServlet(类似于Spring MVC的DispatcherServlet)来对请求进行控制(一系列过滤器处理Http请求)。
所有的Request都要经过ZuulServlet的处理,三个核心的方法preRoute(),route(), postRoute(),zuul对request处理逻辑都在这三个方法里,ZuulServlet交给ZuulRunner去执行。
ZuulRunner直接将执行逻辑交由FilterProcessor处理,ZuulServlet、ZuulRunner、FilterProcessor都是单例。
FilterProcessor对filter的处理逻辑。
1.根据Type获取所有输入该Type的filter,List
2.遍历该list,执行每个filter的处理逻辑,processZuulFilter(ZuulFilter filter)。
3.RequestContext对每个filter的执行状况进行记录,此处的执行状态主要包括其执行时间、以及执行成功或者失败,若失败则对异常封装后抛出。
4.zuul框架对每个filter的执行结果都没有太多的处理,没把上一filter的执行结果交由下一个将要执行的filter,仅记录执行状态,如果执行失败抛出异常并终止执行。
1.身份验证和安全性 - 确定每个资源的身份验证要求并拒绝不满足这些要求的请求。
2.洞察和监控 - 在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图。
3.动态路由 - 根据需要动态地将请求路由到不同的后端群集。
4.压力测试 - 逐渐增加群集的流量以衡量性能。
5.负载分配 - 为每种类型的请求分配容量并删除超过限制的请求。
6.静态响应处理 - 直接在边缘构建一些响应,而不是将它们转发到内部集群。
1.PRE: 在请求被路由之前调用。可在集群中选择请求的微服务、认证鉴权,限流等。
2.ROUTING: 将请求路由到微服务。可构建发送给微服务的请求,并使用Apache HttpClient或 Ribbon请求微服务,现在也支持OKHTTP。
3.POST: 在路由到微服务以后执行。可在这种过滤中处理逻辑,如收集统计信息和指标、将响应从微服务发送给客户端等。
4.ERROR: 在其他阶段发生错误时执行该过滤器。可做全局异常处理。
1.配置
server: port: 80 spring: application: name: demo-zuul eureka: client: enabled: true #该客户端是否可用 service-url: defaultZone: http://localhost:8761/eureka #注册中心地址 register-with-eureka: true #注册该服务,默认为true fetch-registry: true #获取服务列表,默认为true
2.启动类
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableZuulProxy//开启网关功能 public class DemoZuulApplication { public static void main(String[] args) { SpringApplication.run(DemoZuulApplication.class, args); } //配置动态路由规则 @Bean public PatternServiceRouteMapper getPatternServiceRouteMapper() { return new PatternServiceRouteMapper("(?^.+)", "${name}"); } }
3.写自己的过滤器
import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; @Component public class TokenFilter extends ZuulFilter { /** * 拦截类型,4种类型 pre route error post */ @Override public String filterType() { // FilterConstants.PRE_TYPE; // FilterConstants.ROUTE_TYPE; // FilterConstants.ERROR_TYPE; // FilterConstants.POST_TYPE; return FilterConstants.PRE_TYPE; } /** * 该过滤器在所有过滤器的执行顺序值,值越小,越前面执行 */ @Override public int filterOrder() { return 0; } /** * 是否拦截 */ @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); // RequestContext ctx = RequestContext.getCurrentContext(); // ctx.getBoolean("isOk"); HttpServletRequest request = ctx.getRequest(); String requestURI = request.getRequestURI(); //排除拦截的url if (requestURI.equals("/demo-member/user/loadBalance")) { return false; } return true; } /** * 过滤器具体的业务逻辑 */ @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String token = request.getParameter("token"); // ctx.set("isOk",true); // 可以在上下文里面设置一个key,在下一次拦截时,就可以获取到 if (null == token) { ctx.setResponseBody("token is null"); ctx.setResponseStatusCode(400); ctx.setSendZuulResponse(false); return null; } if (!"123456".equals(token)) { ctx.setResponseBody("token is error"); ctx.setResponseStatusCode(400); ctx.setSendZuulResponse(false); return null; } ctx.setSendZuulResponse(true); return null; } }
spring cloud gateway 的核心是一系列过滤器,可将客户端的请求转到不同服务器,可简称为过滤和路由。与Zuul的主要的区别在底层的通信框架上,Gateway 底层使用通信框架Netty提供非阻塞异步请求处理,内嵌 Hystrix 断路器。
(1)基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0。
(2)集成 Hystrix 断路器。
(3)集成 Spring Cloud DiscoveryClient。
(4)Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters。
(5)具备一些网关的高级功能:动态路由、限流、路径重写。
GateWay的通信模型
GateWay的路由流程
GateWay内部工作流程
1.路由 Route
id:路由标识,要求唯一,名称任意(默认uuid)。
uri:请求最终被转发到的目标地址。
order: 路由优先级,数字越小,优先级越高。
predicates:断言数组,即判断条件,如果返回值是boolean,则转发请求到 uri 属性指定的服务中。
filters:过滤器,在请求传递过程中,可做一些逻辑处理。
2.断言 Predicate
接受一个输入参数,返回一个布尔值结果。用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
过滤器 filter:
生命周期:
PRE:在路由之前调用。可实现身份验证、在集群中选择请求的微服务、记录调试信息等。
POST:在路由到微服务后调用。可用来为响应添加标准的 HTTP Header、收集统计信息和指标等。
作用范围
GatewayFilter:单个路由或一个组的路由上(要在配置文件中配置)。
GlobalFilter:所有的路由上(无需配置,全局生效)。
1.配置
spring: cloud: gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Method=GET,POST - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 - After=2022-05-05T02:00:00.000+08:00[Asia/Shanghai] # 路由指定时间后生效、还有其他的参数(Before、Between) filters: #过滤器 - AddResponseHeader=X-Response-test1, test1 # - RewritePath=/service1/(?.*), /$\{segment} # 重写路由地址,http://127.0.0.1:21000/service1/hystrix/calculate 会转发到 http://127.0.0.1:20004/hystrix/calculate,由于 YAML 规范,$ 被 $\ 取代。 - RewritePath=/service1/(? .*), /service1/$\{segment} # - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=123456 # 重写 response 请求头 - StripPrefix=0 # 过滤器StripPrefix,作用是去掉请求路径的最前面n个部分截取掉。StripPrefix=1就代表截取路径的个数为1,比如前端过来请求/test/good/1/view,匹配成功后,路由到后端的请求路径就会变成http://localhost:8888/good/1/view - AddRequestHeader=Accept-Language, zh,zh-CN;q=0.9 # 将 Accept-Language=zh,zh-CN;q=0.9 添加到所有匹配请求的 header中 - AddRequestParameter=host, 127.0.0.1 # 将 host=127.0.0.1 添加到所有匹配请求的 Param 参数中 - AddResponseHeader=X-Response-Foo, Bar # 将X-Response-Foo:BarHeaders 添加到所有匹配请求的下游响应的 Headers 中。 - PrefixPath=/mypath # 将/mypath作为所有匹配请求的路径的前缀。因此,对 /service1 的请求将发送到 /mypath/service1。 - RedirectTo=302, https://blog.csdn.net/qq_41538097/article/details/124626658 # 所有匹配到的请求都重定向到该地址 - RemoveRequestHeader=X-Request-Foo # 这将删除 Request Headers 中的 X-Request-Foo,然后将其发送到下游 - RemoveResponseHeader=X-Response-Foo # 这将从响应中删除 Response Headers 中的 X-Response-Foo,然后将其返回给网关 Client 端。 - RemoveRequestParameter=red # 将 red 参数发送到下游之前将其删除 - SetPath=/{segment} # 请求路径/red/blue 设置为 /blue 发送到下游请求 - SetRequestHeader=X-Request-Red, Blue # 注意:替换(而不是添加),替换 Request Header 的 X-Request-Red=Blue - SetResponseHeader=X-Response-Red, Blue # 注意:替换(而不是添加),替换 Response Header 的 X-Response-Red=Blue - SetStatus=401 # 无论哪种情况,响应的 HTTP 状态都设置为 401。也可以是枚举的字符串:NOT_FOUND - name: RequestRateLimiter # 令牌桶算法,IP 限流 args: redis-rate-limiter.replenishRate: 20 # 每秒允许多少个请求 redis-rate-limiter.burstCapacity: 10 # 允许用户在一秒钟内执行的最大请求数,将此值设置为零将阻止所有请求。 - name: Retry args: retries: 3 # 请求失败重试 3 次 statuses: BAD_GATEWAY methods: GET,POST backoff: firstBackoff: 10ms maxBackoff: 50ms factor: 2 basedOnPreviousValue: false # 降级配置 - name: Hystrix args: name: testOne # 降级接口的地址 fallbackUri: forward:/junFallback - name: RequestSize # 限制请求大小,超过则拒绝,如果未配置,则默认请求大小设置为 5 MB。 args: maxSize: 500MB # 单位默认B,支持 B、KB、MB、GB、TB - name: SetRequestHostHeader # 覆盖主机标头(HTTP/1.1 请求头 Headers 默认包含 Host 头,可以是 IP,域名) args: host: 127.0.0.1 - id: order-service # 路由id,自定义,只要唯一即可 uri: lb://order-service order: 8003 predicates: - Path=/order-service/oauth/token filters: - AddResponseHeader=X-Response-test2, test2 # hystrix 信号量隔离,2秒后自动超时 hystrix: command: default: execution: isolation: strategy: SEMAPHORE thread: timeoutInMilliseconds: 2000 shareSecurityContext: true
2.全局过滤器
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * 自定义过滤器 */ @Component public class AuthorizeFilter implements GlobalFilter, Ordered { @Override public Monofilter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1.获取请求参数 MultiValueMap params = exchange.getRequest().getQueryParams(); // 2.获取authorization参数 String auth = params.getFirst("authorization"); // 3.校验 if ("admin".equals(auth)) { // 放行 return chain.filter(exchange); } // 4.拦截 // 4.1.禁止访问,设置状态码 exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 4.2.结束处理 return exchange.getResponse().setComplete(); } @Override public int getOrder() { return -1; } }
/** * 降级配置 */ @RestController public class JunHystrixController { @RequestMapping("/junFallback") public MapjunFallback(){ System.err.println("服务降级中"); Map map = new HashMap<>(); map.put("resultCode","fail"); map.put("resultMessage","服务异常"); map.put("resultObj","null"); return map; } }
1、计数器算法:以QPS为100举例,如果1秒钟内钱200ms请求数量到达了100,后面800ms中的请求都会被拒绝,这种情况称为”突刺现象“
2、漏桶算法:可以解决突刺现象。比如创建一个很大的队列来接收请求,一个较小的线程池来处理请求。但是也有极限情况,当队列满了时, 请求也会拒绝掉。
3、令牌桶算法:可以说是漏桶算法的改进。在桶中放令牌,请求获取令牌后才能继续执行。如果桶中无令牌,请求可以选择进行等待或直接拒绝。
(1)轮询策略
将请求均匀地分配到每个服务器上。请求量增加时,会导致某些服务器的负载过高。
(2)加权轮询策略
在轮询策略的基础上加了权重的概念,每个服务器都有一个权重值,权重值越高的服务器会被分配更多的请求,动态地调整权重值。
(3)IP哈希策略
通过哈希算法将客户端IP地址转换为一个数字,根据该数字来选择服务器。