带你走进 SpringCloud2.0(七):Zuul

背景

  • 当微服务数量非常多时,我们需要一个统一入口进行访问这些微服务的接口,这时我们就需要网关帮助我们将接口请求反向代理到目标服务。

网关

网关实现的功能

  • 网关对所有服务进行拦截。
  • 生成动态路由,进行反向代理。
  • 网关安全控制:统一异常处理、防止 xxs 攻击和 SQL 注入。
  • 权限控制、黑名单和白名单、性能监控、日志打印。

网关分类:内部网关和外部网关

  • 内部网关:网关服务不开放给外网。全部服务都部署在内网服务器上,只允许内网的服务才能访问当前网关。
  • 外部网关:网关服务开放给外网。网关服务外的其他服务,都部署在内网,外网无法方法。网关服务部署方式有 2 种

    • 网关服务也部署在内网,然后将网关服务开放给外网访问。
    • 网关服务也部署在内网,另需要 nginx 服务部署在外网,nginx 能够访问网关服务对网关服务实现反向代理,达到将将网关服务开放给外网的效果。

常用网关框架

  • Kong kong:是基于 Nginx + Lua 进行二次开发的网关框架。

    • 网址:konghq.com/

  • Zuul:Netflix 开发的网关框架。SpringCloud 整合了该网关。

    • 网址:github.com/Netflix/zuu…

  • orange:国人开发的一个开源网关框架。

    • 网址:orange.sumory.com/

API 网关与传统服务器网关对比

  • 服务器网关:电脑要配置服务器网关,对网络中发送过来的请求进行拦截和转发到目标电脑。
  • API 网关:对接收到的请求拦截和转发到目标服务。

Zuul 网关

简介

  • Zuul 网关是 SpringCloud 推荐的一个网关框架。
  • Zuul 实际是 netflix(美国知名视频网站) 开发的,SpringCloud 做了一个整合封装。
  • Zuul 默认集成了 Ribbon 和 Hystrix。

Zuul 和 Nginx 的区别

  • 相同点:Zuul 和 nginx 都可以实现反向代理、负载均衡、过滤请求、实现网关效果。

    • Nginx 通过 Nginx + Lua 实现网关功能。开发团队需要有 Lua 积累,不推荐。
    • 直接在 Nginx 基础上开发一个支持自动注册/注销服务的 Nginx API 网关。

  • 不同点

    • Zuul 采用 Java 语言编写,Nginx 采用 C 语言编写
    • Nginx 由 C 编写,采用 I/O 多路复用技术,性能比 Zuul 略高,支持的并发数默认要高出两个量级。

Zuul + Nginx 配合使用

  • Nginx 负载均衡能力更强,主要负责反向代理、负载均衡。
  • Zuul 对微服务实现请求拦截,智能路由,日志采集等功能。

整合 Zuul

Maven 依赖

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-zuul</artifactId>

</dependency>

application.yml 配置

### 配置网关反向代理

zuul:

routes:

### 定义转发规则。这个规则名称可以随意命名

api-a:

### 以 /api-member/ 访问转发到会员服务

path: /api-member/**

### 服务名称。Zuul 网关默认整合了 ribbon,ribbon + serverId 实现本地负载均衡方式调用接口

serviceId: member-server

api-b:

path: /api-order/**

serviceId: order-server

入口类添加注解

  • 注解启动 Zuul 框架的功能
    @EnableZuulProxy

Zuul + Apollo

简介

  • 在实际开发中,微服务中配置一般会放到分布式配置中心中。
  • Zuul 网关服务的动态路由配置,一般是放到分布式配置中心中的。这样可以在配置中心配置通过修改配置,添加或删除特定路由的配置,从而让 Zuul 不需要重启,就能动态进行路由的增减。

Zuul 整合 Apollo

  • Maven 依赖

    <dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>

    </dependency>

    <dependency>

    <groupId>com.ctrip.framework.apollo</groupId>

    <artifactId>apollo-client</artifactId>

    <version>1.1.0</version>

    </dependency>

    <dependency>

    <groupId>com.ctrip.framework.apollo</groupId>

    <artifactId>apollo-core</artifactId>

    <version>1.1.0</version>

    </dependency>

    <dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

    <scope>provided</scope>

    </dependency>

  • application.yml 配置

    server:

    port: 8500

    spring:

    application:

    name: zuul-server

    eureka:

    client:

    service-url:

    defaultZone: http://${eureka.instance.ip-address}:8000/eureka/,http://${eureka.instance.ip-address}:8001/eureka/,http://${eureka.instance.ip-address}:8002/eureka/

    instance:

    prefer-ip-address: true

    ip-address: 127.0.0.1

    app:

    ### portal 中新建 Application 的 AppId

    id: zuul_server_config

    apollo:

    ### configserver 的地址

    meta: http://${configserver.host}:8080

  • 启动类添加注解。

    @EnableApolloConfig

    @EnableZuulProxy

    @EnableEurekaClient

  • 添加动态路由刷新类。当 Apollo 修改配置,Zuul 服务内存中对应的配置会修改,但是我们动态路由对象不会重新根据内存中的配置更新路由,所以需要动态路由刷新类,根据路由配置,更新路由对象。

    @Component

    publicclassZuulProxyRefresherimplementsApplicationContextAware{

    private ApplicationContext applicationContext;

    @Autowired

    private RouteLocator routeLocator;

    @ApolloConfigChangeListener(value = "application")

    publicvoidonChange(ConfigChangeEvent changeEvent){

    boolean zuulProxyChanged = false;

    for (String changedKey : changeEvent.changedKeys()) {

    if (changedKey.startsWith("zuul.")) {

    zuulProxyChanged = true;

    break;

    }

    }

    if (zuulProxyChanged) {

    refreshZuulProxy(changeEvent);

    }

    }

    privatevoidrefreshZuulProxy(ConfigChangeEvent changeEvent){

    this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));

    this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator));

    }

    @Override

    publicvoidsetApplicationContext(ApplicationContext applicationContext)throws BeansException {

    this.applicationContext = applicationContext;

    }

    }

  • Portal 中路由配置,修改配置,会同时修改动态路由。如下图,我们故意将 order 服务的 serviceId 写错和纠正,来模拟路由是否生效。

GitHub 项目 demo

  • 整个 demo GitHub 地址

  • 项目运行测试:通过修改 portal 中网路路由配置信息,控制路由的添加和删减。

    • 先启动注册服务

    • 启动网关服务、会员服务、订单服务

    • 登录 Portal 管理端:http://${portal.ip}:8070,对路由信息进行操作。
    • 比如增加和删减订单服务路由,然后通过网关调用订单服务接口,判断路由是否根据 Portal 中配置实时更新。测试接口:
      localhost:8500/api-order/order/get

  • Zuul 例子的 GitHub 地址

以上是 带你走进 SpringCloud2.0(七):Zuul 的全部内容, 来源链接: utcz.com/a/20332.html

回到顶部