Zuul是什么?

  • front door. API Gateway.Zuul is a JVM based router and server side load balancer by Netflix.
  • 所有请求的入口。
  • As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security. 作为边界应用服务,zuul能实现动态路由、监控、弹性与安全性。
  • 用groovy编写。

官网说明 Netflix uses Zuul for the following:

Authentication 认证
Insights 洞察力
Stress Testing 压力测试
Canary Testing 金丝雀测试
Dynamic Routing 动态路由
Service Migration 服务迁移
Load Shedding 减载
Security 安全
Static Response handling 静态响应处理
Active/Active traffic management

Zuul可以实现好些功能,路由功能是微服务的一部分,这里主要记录下使用zuul做负载均衡。

使用注意事项

  1. If you need your routes to have their order preserved you need to use a YAML file as the ordering will be lost using a properties file.如果你希望按照书写顺序来执行路由规则,则必须使用YAML文件,不能使用properties

 

具体配置如下:

在根目录spring_cloud中创建Maven Moudle模块:zuul-server

pom.xml

<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">
    <parent>
        <artifactId>spring-cloud</artifactId>
        <groupId>com.sam</groupId>
        <version>0.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>zuul-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
    </dependencies>

</project>

创建消费者服务启动类:ZuulApplication

package com.sam.zuul.server;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

/**
 * @ClassName: ZuulApplication 
 * @Description: Zuul路由服务
 * Zuul的主要功能是路由和过滤器。路由功能是微服务的一部分,zuul实现了负载均衡。
 * @author sam 
 * @date 2018年8月10日 上午11:38:24
 */
@SpringCloudApplication //这个注解整合了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreake
@EnableZuulProxy
public class ZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }

    @Bean
    public MyZuulFilter getZuulFilter(){
        return new MyZuulFilter();
    }
}

创建过滤器:MyZuulFilter

package com.sam.zuul.server;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

/**
 * @ClassName: MyZuulFilter
 * @Description: 自定义过滤器
 * @author sam
 * @date 2018年8月10日 上午11:23:11
 */
public class MyZuulFilter extends ZuulFilter {

	private static Logger log = LoggerFactory.getLogger(MyZuulFilter.class);

	/**
	 * 返回过滤器类型
	 * 
	 * @return pre:可以在请求被路由之前调用 routing:在路由请求时候被调用 post:在routing和error过滤器之后被调用
	 *         error:处理请求时发生错误时被调用
	 */
	@Override
	public String filterType() {
		return "pre";
	}

	/**
	 * 通过int值来定义过滤器的执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}

	/**
	 * 判断过滤器是否执行
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 过滤器的具体逻辑 ctx.setSendZuulResponse(false)令zuul不允许请求,
	 * ctx.setResponseStatusCode(401)设置了其返回的错误码
	 * ctx.setResponseBody(body)编辑返回body内容
	 * 
	 * @return
	 */
	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();

		HttpServletRequest request = ctx.getRequest();

		log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
		Object id = request.getParameter("id");
		if (id == null) {
			log.warn("id is null");
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			return null;
		}

		log.info("pass!");
		return null;
	}

}

创建配置文件:application.yml

spring:
  application:
    name: zuul

server:
  port: 8020

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8010/eureka/

zuul:
  routes:
    api-a:
      path: /service-producer/**
      serviceId: service-producer
    api-b:
      path: /service-producer-c/**
      serviceId: service-producer-c
  sensitive-headers:  #设置忽略的头信息,设置为空能解决会话保持问题
  add-host-header: true #设为true才能保持Host头信息处理正确

上面配置说明

把/service-producer/开头的所有请求都转发给service-producer服务执行,

把/service-producer-c/开头的所有请求都转发给service-producer-c服务执行,

PS: 由于用到新的一个生产者服务,于是创建一个新的生产者服务service-producer-c,直接从service-producer-A拷贝一份,修改端口名称,及服务名,其它的一致,其中配置文件application.yml如下:

spring:
  application:
    name: service-producer-c

server:
  port: 8813

eureka:
  client:
    serviceUrl:
          defaultZone: http://localhost:8010/eureka/ #eureka服务注册地址

注意名称是 service-producer-c 。

以上配置完成后,启动 zuul-server 等服务,如下图:

访问Zuul服务,
分别打开
http://localhost:8020/service-producer/hi?id=zuul

hi, zuul, service-producer:8811



http://localhost:8020/service-producer-c/hi?id=zuul

hi, zuul, service-producer-c:8813

可以看到Zuul已经实现了相应的路由规则,根据不同的访问路径进行动态 分发!

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐