本文共 5881 字,大约阅读时间需要 19 分钟。
网关也要注册到注册中心上,从注册中心获取服务节点列表,使用内置的Ribbon进行负载均衡,确定路由到服务集群的哪个节点。
网关的功能
1、统一接入
2、流量监控
3、安全防护
主流的网关
1、新建子模块api-gateway,创建时只需勾选Spring Cloud Discovery -> Eureka Discovery Client ,Spring Cloud Routing -> Routing[Maintenance]
也可以手动添加依赖org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-netflix-zuul
Zuul的依赖中已经包含了Hystrix的依赖,可以使用hystrix在网关处进行限流
2、引导类上加
3、application.yml
server: port: 9000spring: application: name: api-gateway servlet: multipart: #请求的最大尺寸,默认10M max-request-size: 1024MB #上传所允许的单个文件的最大尺寸,默认1M max-file-size: 1024MBeureka: client: serviceUrl: defaultZone: http://127.0.0.1:8761/eureka/zuul: #在服务名前加前缀,这样可以用/api-gateway/拦截所有请求 prefix: /api-gateway/ #zuul默认会过滤请求头,剔除请求头中的sensitive-headers部分(默认为Cookie、Set-Cookie、Authorization)后,再将请求转发给服务,在服务中是取不到cookie的 #取消对请求头的默认过滤,不设置值即为null sensitive-headers: ##默认按服务名进行路由,可以取消原来的映射规则,自定义路由规则,但不推荐这样做# ignored-patterns: /*-service/**# routes:# user-service: /api-gateway/user-service/**# order-service: /api-gateway/order-service/**
使用网关之后,所有请求都要应该通过网关来访问,比如通过网关来访问user-service:127.0.0.1:9000/api-gateway/user-service/api/v1/user/…
网关集群后,使用nginx做负载均衡,所有请求都应该发给nginx。
通过网关访问服务也是服务调用,zuul本身已经集成了hystrix,同样可以设置容错保护,设置相关配置
zuul: host: connect-timeout-millis: 100000 socket-timeout-millis: 100000ribbon: ReadTimeout: 100000 ConnectTimeout: 100000hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 100000
import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@Component //放到spring容器中public class ValidateFilter extends ZuulFilter { //继承抽象类ZuulFilter /* 指定过滤类型(时机),"pre"是路由转发之前,"routing"是路由转发之时,"post"是返回响应给浏览器之前,"error"是发生错误时 前处理用pre,后处理用post */ @Override public String filterType() { return "pre"; } /* 要执行多个拦截器,需要指定这些拦截器调用的先后顺序,数值越小,优先级越高、越先执行 可以在FilterConstants类中查看Zuul自带的拦截器的Order,自定义拦截器的Order要参考它们进行设置,不能想设置多大就设置多大 前处理一般设置为0~9 */ @Override public int filterOrder() { return 0; } /* 是否要使用此过滤器,默认false,改为true 如果要关闭此拦截器,改为false即可 */ @Override public boolean shouldFilter() { return true; } /* 核心方法,用来过滤请求 */ @Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext(); //前处理,获取request HttpServletRequest request = currentContext.getRequest(); //获取参数 String token = request.getParameter("token"); //token要和数据库查到的进行比较,此处随便写一个代替 if (token==null || !token.equals("123456")) { //如果token错误,直接返回响应,不转发给服务。只是不转发给服务,此方法后面部分的代码还是会执行 currentContext.setSendZuulResponse(false); currentContext.setResponseStatusCode(400); //输出信息到浏览器 try { currentContext.getResponse().getWriter().write("token is invalid"); } catch (IOException e) { e.printStackTrace(); } } // 有时候可能要对指定的url进行拦截处理 String requestURI = request.getRequestURI(); if (requestURI.contains("/api-gateway/user-service/......")){ //...... } if (requestURI.equals("/api-gateway/user-service/.....")){ //...... } return null; }}
不建议使用大量的过滤器,因为会加大时间开销,拉低性能。
网关中写通用的过滤,比如校验用户是否登录;如果是对部分服务进行过滤,尽量在shouldFilter()中就判断请求地址;如果只是个别服务的过滤,写在服务自身中。
系统性能有限,过多请求会冲垮系统,所以一般都要做限流。一般用hystrix做服务层限流,zuul可以用谷歌的guava框架实现网关层限流,nginx上也可以限流。
zuul集成了hystrix,可以在过滤器中使用hystrix限流,在回退方法中写代替方案。zuul也集成了guava,可以在过滤器中用guava限流,直接用即可。guava用得更多。
在过滤器中使用guava限流
import com.google.common.util.concurrent.RateLimiter;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Componentpublic class LimitFilter extends ZuulFilter { //RateLimiter是com.google.common.util.concurrent.RateLimiter,不要导错了 //指定最大访问量,数值一般是压测得到的qps上限,此处设置为1000 private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { //限流的过滤器放在自定义前处理的最前面 return -4; } @Override public boolean shouldFilter() { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); String requestURI = request.getRequestURI(); //只限流指定服务,此处限流的服务是user-service,通过zuul请求user-service的qps不能超过1000 //各个服务能承受的最大qps不同,一般要分开设置。如果多个服务能承载的最大qps差不多,可以一起设置 if (requestURI.contains("/api-gateway/user-service/")){ return true; } return false; } @Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext(); //如果超过设置的上限,直接返回响应,不转发给服务 if (!RATE_LIMITER.tryAcquire()){ currentContext.setSendZuulResponse(false); //返回给浏览器的状态码是429 过多请求 currentContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); } return null; } }
转载地址:http://ykhlb.baihongyu.com/