SpringCloud微服务体系中,一种常见的负载均衡的方式是,客户端的请求先通过负载均衡(Zuul+Ngnix),再达到服务网关(Zuul集群),然后才到具体的服务器。
服务统一注册到服务注册中心集群,服务的所有配置文件由配置服务管理。
一、Zuul介绍
Zuul的主要功能是路由转发和过滤器。路由是微服务的一部分,比如/api/user转发到user服务,/api/shop转发到shop服务。
Zuul默认和Ribbon实现了负载均衡。
Zuul有以下功能:
- Authentication(身份验证)
- Insights
- Stress Testing(压力测试)
- Canary Testing(最先测试)
- Dynamic Routing(动态路由)
- Service Migration(服务迁移)
- Load Shedding(甩负荷)
- Security(安全性)
- Static Response handling(静态响应处理)
- Active/Active traffic management
二、创建zuul工程,服务路由
1.创建SpringBoot工程,引入eureka、zuul、web依赖。
2. 在启动类开启@EnableEurekaClient注解和@EnableZuulProxy注解
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
3. 修改配置
配置注册中心地址;设置zuul服务端口、服务名;配置网关,这里将所有/api-ribbon/开头的请求都转发给service-ribbon服务,将所有/api-feign/开头的请求都转发给service-feign服务。
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8766
spring:
application:
name: service-zuul
zuul:
routes:
api-ribbon:
path: /api-ribbon/**
serviceId: service-ribbon
api-feign:
path: /api-feign/**
serviceId: service-feign
4. 访问zuul服务
http://localhost:8766/api-ribbon/say?name=longtian
http://localhost:8766/api-feign/hello?name=longtian
三、服务过滤
创建Zuul服务过滤器需要继承抽象类com.netflix.zuul.ZuulFileter,该类实现了com.netflix.zuul.IZuulFilter,有两个抽象方法:
public abstract String filterType(); public abstract int filterOrder();
以及IZuulFilter接口的两个方法:
boolean shouldFilter(); Object run() throws ZuulException;
1. filterType()返回一个字符串代表过滤器的类型。zuul定义了四种不同生命周期的过滤器:
pre:路由之前
routing:路由时
post:路由之后
error:发送错误时调用
2. filterOrder(),过滤的顺序
3. shouldFileter(),这里可以写逻辑判断,是否要过滤。true,永远过滤。
4. run(),过滤器的具体逻辑。可能很复杂,包括查sql、缓存等去判断到底有没有访问权限。
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
public String filterType(){
return "pre";
}
public int filterOrder(){
return 0;
}
public boolean shouldFilter(){
return true;
}
public Object run(){
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
if(StringUtils.isEmpty(token)) {
log.error("accepted token is null");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("token error");
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
log.info("ok");
return null;
}
}
访问 http://localhost:8766/api-ribbon/say?name=longtian
访问 http://localhost:8766/api-ribbon/say?name=longtian&token=1