通常我们如果有一个服务,会部署到多台服务器上,这些微服务如果都暴露给客户,是非常难以管理的,我们系统需要有一个唯一的出口,API网关是一个服务,是系统的唯一出口。API网关封装了系统内部的微服务,为客户端提供一个定制的API。客户端只需要调用网关接口,就可以调用到实际的微服务,实际的服务对客户不可见,并且容易扩展服务。

API网关可以结合ribbon完成负载均衡的功能,可以自动检查微服务的状况,及时剔除或者加入某个微服务到可用服务列表。此外网关可以完成权限检查、限流、统计等功能。下面我们将一一完成上面的功能。注意微服务只是提供rest的接口,不会有额外的组件依赖,不需要eureka等。只需要两个工程,一个是微服务,我们可以部署到多台服务器,那么只是访问的ip不同,在演示的时候,我们在本机演示,修改端口,达到启动多个微服务的目的,另一个就是网关,主要是spring cloud gateway 和 ribbon两大组件来实现网关和负载均衡等功能。

GitHub代码

1、rest服务构建


1、创建一个父工程

删除src目录

pom文件增加如下内容:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>

2、新建一个module

3、修改pom.xml文件,增加如下内容:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

4、在resources文件夹下面增加一个application.yml文件,内容为:

server:
port: 1001

5、新增一个主入口类Provider1001Application,内容如下

package com.yefengyu.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class Provider1001Application
{
public static void main(String[] args)
{
SpringApplication.run(Provider1001Application.class, args);
}
}

6、新增一个rest接口HelloWorldController,内容如下:

package com.yefengyu.cloud.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; @RestController
public class HelloWorldController
{
@GetMapping("/hello")
@ResponseBody
public String hello()
{
return "hello spring cloud, 1001";
}
}

7、启动main方法,在浏览器输入http://localhost:1001/hello可以看到:

8、同理,我们再建立2个rest服务,步骤如下

(1)新增module,参考第二小节,主要把名称改为:

  • provider1002

  • provider1003

(2)pom.xml文件参考第三小节,加上即可。

(3)参考第四小节,新建application.yml文件,注意端口改为

  • 1002

  • 1003

(4)参考第五小节,新建一个主启动类,名称为如下,内容都一样。

  • Provider1002Application

  • Provider1003Application

(5)参考第六小节,新增一个HelloWorldController接口,其中只有下面这句中的 1001 改为 1002 或 1003,方便测试观察结果

return "hello spring cloud, 1001";

(6)参考第7小节测试成功新增的两个服务即可。

(7)现在的工程如下:

2、spring cloud gateway


Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。

  • 路由:Gateway的基础构建模块。它包括一个ID,一个目标URL,一个断言集合和一个过滤器集合。如果断言判断为真,则路由匹配。

  • 断言:这是Java8的新增功能,输入的类型为Spring框架的ServerWebExchange。它可以匹配HTTP请求中的任何东西,比如:请求头或者参数。
  • 过滤器:是Spring框架的GatewayFilter,请求和响应都可以被Filter修改。

1、新建一个module,按照上面的方式,名称叫: gateway

2、添加依赖

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
</dependencies>

3、新建一个主启动类 GatewayApplication

package com.yefengyu.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class GatewayApplication
{
public static void main(String[] args)
{
SpringApplication.run(GatewayApplication.class, args);
}
}

4、新增一个application.yml文件,内容如下:

server:
port: 8080
spring:
application:
name: gateway_server
cloud:
gateway:
default-filters:
routes:
- id: my_route
uri: http://localhost:1001/
predicates:
- Path=/gateway/**
filters:
- StripPrefix=1

5、测试

访问 http://localhost:8080/gateway/hello

上面只是简单的路由转发,可以先了解下工作原理:

url 中的 http://localhost:8080/ 会访问到gateway这个服务,spring cloud gateway会在配置的路由中做谓词匹配,也就是url中的gateway匹配到了id为my_route的路由,就会把http://localhost:8080/替换为http://localhost:1001/,并且filters中的规则(StripPrefix)会把http://localhost:8080/gateway/hello中的gateway去掉,那么http://localhost:8080/gateway/hello实际就会去访问http://localhost:1001/hello,也就是访问到了provider1001服务。

疑问?

上面的uri只配置了provider1001服务,如何使用geteway访问三个服务呢?需要使用负载均衡ribbon

3、ribbon负载均衡


下面的操作都是在gateway这个服务操作的:

1、添加依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>

2、修改配置文件,增加或者修改见红色部分

server:
port: 8080
spring:
application:
name: gateway_server
cloud:
gateway:
default-filters:
routes:
- id: my_route
uri: lb://my-load-balanced-service
predicates:
- Path=/gateway/**
filters:
- StripPrefix=1
my-load-balanced-service:
ribbon:
listOfServers: localhost:1001, localhost:1002,localhost:1003
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

3、重启gateway服务,不断访问 http://localhost:8080/gateway/hello,发现可以不断访问的时候在三个服务中来回切换,达到了负载均衡的目的。上面我们使用了轮询的负载均衡策略。

注意:

  • listOfServers:配置的微服务的服务器ip端口

  • NFLoadBalancerRuleClassName:使用的负载均衡策略,默认提供了几种,也可以自己实现(后续讲解),默认提供的如下:

疑问:

如果上面listOfServers中的任何一个服务关闭了,然后使用gateway访问,会出现什么情况?

事实是这样的:

比如provider1003服务宕机。那么使用轮询算法的时候,不断访问gateway,会出现:

provider1001 正常,provider1002 正常,provider1003 异常,provider1001 正常,provider1002 正常,provider1003 异常。。。

provider1003 已经宕机,但是请求还是不断转发到该服务上,导致服务访问的过程中,部分请求异常。

我们需要有这样的功能,如果某个服务宕机,那么请求就不会发送到该服务器上,如果宕机的服务器恢复了,那么请求又可以发送到该服务器上,要实现这个功能,需要ribbon对服务进行健康检查。

(1)首先微服务需要有个rest接口,就叫做heath接口吧,调用heath接口返回ok表明服务正常。

(2)gateway需要有调用heath接口的功能,并且配置到ribbon可以不断调用该接口,时刻检查服务的状态,如果有服务器挂掉,可以很快感知到,并把该服务剔除可用服务列表。

4、健康检查


1、provider1001,provider1002,provider1003增加一个rest接口HealthController

package com.yefengyu.cloud.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; @RestController
public class HealthController
{
@GetMapping("/heath")
@ResponseBody
public String heath()
{
return "ok";
}
}

2、在gateway工程里面做如下修改

(1)新建一个Config类

package com.yefengyu.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate; @Configuration
public class MainConfig
{
@Bean
public RestTemplate restTemplate()
{
return new RestTemplate();
}
}

(2)新建一个健康检查的类,主要是调用heath接口。

package com.yefengyu.gateway.loadbanlance;

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate; @Component
public class HealthExamination implements IPing
{
@Autowired
private RestTemplate restTemplate; @Override
public boolean isAlive(Server server)
{
String url = "http://" + server.getId() + "/heath";
try
{
ResponseEntity<String> heath = restTemplate.getForEntity(url, String.class);
if (heath.getStatusCode() == HttpStatus.OK)
{
System.out.println("ping " + url + " success and response is " + heath.getBody());
return true;
}
System.out.println("ping " + url + " error and response is " + heath.getBody());
return false;
}
catch (Exception e)
{
System.out.println("ping " + url + " failed");
return false;
}
}
}

上面代码继承IPing接口,判断服务是否可用。我们在微服务中增加heath接口,在gateway中调用该接口,如果返回正常则认为微服务可用。

(3)修改配置文件,注意最后一行,这是唯一增加的。

server:
port: 8080
spring:
application:
name: gateway_server
cloud:
gateway:
default-filters:
routes:
- id: my_route
uri: lb://my-load-balanced-service
predicates:
- Path=/gateway/**
filters:
- StripPrefix=1
my-load-balanced-service:
ribbon:
listOfServers: localhost:1001,localhost:1002,localhost:1003
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
NFLoadBalancerPingClassName: com.yefengyu.gateway.loadbanlance.HealthExamination

3、重新启动微服务和gateway服务,然后通过网关访问,可以看到可以正常访问,如果此时把某一台微服务停掉,访问的时候开始可能会报错,但是随着健康检查的运行,检测到该服务不可用,则会把该服务剔除,以后只会访问正常运行的服务。当宕机的服务重启,健康检查还会把该服务加入到可用服务列表,下次请求就会再次发送到该服务上。

5、自定义负载均衡策略


上面演示了随机、轮询等负载均衡算法,我们可以自定义负载均衡算法。需求是:每个服务器访问三次再跳转到下一个服务器。

只需要在gateway项目中实现AbstractLoadBalancerRule抽象类,然后配置到下面即可

1、负载均衡算法(参考RandomRule)

package com.yefengyu.gateway.loadbanlance;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server; import java.util.ArrayList;
import java.util.List; public class MyRule extends AbstractLoadBalancerRule
{
private volatile int total; private volatile int index; List<Server> upList = new ArrayList<>(); public MyRule()
{
} public Server choose(ILoadBalancer lb, Object key)
{
if (lb == null)
{
return null;
}
else
{
Server server = null; while (server == null)
{
if (Thread.interrupted())
{
return null;
} List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0)
{
return null;
} if (total == 0)
{
upList = lb.getReachableServers();
} if (total < 3)
{
if (upList.size() !=
lb.getReachableServers().size())
{
index = 0
;
}
server =
lb.getReachableServers().get(index);
total++
;
}
else

{
total
= 0;
index++
;
if (index >=
lb.getReachableServers().size())
{
index = 0
;
}
}
if (server == null)
{
Thread.yield();
}
else
{
if (server.isAlive())
{
return server;
} server = null;
Thread.yield();
}
} return server;
}
} public Server choose(Object key)
{
return this.choose(this.getLoadBalancer(), key);
} public void initWithNiwsConfig(IClientConfig clientConfig)
{
}
}

2、修改配置

3、重启gateway,然后访问http://localhost:8080/gateway/hello不断点击,发现点击三次就会调整到下一个服务。

API网关spring cloud gateway和负载均衡框架ribbon实战的更多相关文章

  1. Spring Cloud 微服务三: API网关Spring cloud gateway

    前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...

  2. 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析

    API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...

  3. 【Spring Cloud】客户端负载均衡组件——Ribbon(三)

    一.负载均衡 负载均衡技术是提高系统可用性.缓解网络压力和处理能力扩容的重要手段之一. 负载均衡可以分为服务器负载均衡和客户端负载均衡,服务器负载均衡由服务器实现,客户端只需正常访问:客户端负载均衡技 ...

  4. 负载均衡框架 ribbon 二

    Ribbon 负载均衡机制 官方文档地址:https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers 1. Ribbon 内置 ...

  5. 微服务网关 Spring Cloud Gateway

    1.  为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...

  6. spring cloud:服务网关 Spring Cloud GateWay 入门

    Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使 ...

  7. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负责均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  8. 微服务架构 - 网关 Spring Cloud Gateway

    Spring Cloud Gateway 工作原理 客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则将其发送到网关 Web 处理程序,此处理程序运行特 ...

  9. springcloud(十七):服务网关 Spring Cloud GateWay 熔断、限流、重试

    上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...

随机推荐

  1. 2019长安大学ACM校赛网络同步赛C LaTale (树上DP)

    链接:https://ac.nowcoder.com/acm/contest/897/C来源:牛客网 LaTale 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32768K,其他语 ...

  2. GUI学习之十八——QDateTimeEdit学习总结

    在前面两章我们总结了QSpinBox和QDoubleSpinBox的用法,今天来总结一下QDateTimeEdit控件的基本用法 一.描述 1.QDateTimeEdit是一个用来编辑日期和时间的单行 ...

  3. jemter简单测试方式

    一.简介 Jmeter是一款优秀的开源测试工具, 是每个资深测试工程师,必须掌握的测试工具,熟练使用Jmeter能大大提高工作效率. **开源,他是一款开源的免费软件,使用它你不需要支付任何费用, * ...

  4. 关于sass、scss、less的概念性知识汇总

    这篇文章主要解答以下几个问题,供前端开发者的新手参考. 1.什么是Sass和Less? 2.为什么要使用CSS预处理器? 3.Sass和Less的比较 4.为什么选择使用Sass而不是Less? 什么 ...

  5. Python操作 Excel表格

    python 读写 excel 有好多选择,但是,方便操作的库不多,在我尝试了几个库之后,我觉得两个比较方便的库分别是 xlrd/xlwt.openpyxl. 我使用openpyxl 安装: pip ...

  6. MongoDB之$关键字,以及$修饰器$set,$inc,$push,$pull,$pop

    一.查询中常见的 等于 大于 小于 大于等于 小于等于 等于:在MongoDB中,什么字段等于什么值就是" : ",比如 "name":"路飞学城&q ...

  7. GDKOI2016总结——被虐之旅

    前言 一个被虐的旅程... 这次GDKOI的比赛虽然基本全上暴力,但是居然只有两道题得了分:30+30=60!我感觉整个人都不好了... day0 在去广州的路上,本来心情很好,但是坐在我斜后面的那位 ...

  8. java 8 接口默认方法

    解决问题:在java8 之前的版本,在修改已有的接口的时候,需要修改实现该接口的实现类. 作用:解决接口的修改与现有的实现不兼容的问题.在不影响原有实现类的结构下修改新的功能方法 案例: 首先定义一个 ...

  9. 3D Computer Grapihcs Using OpenGL - 08 Text File Shaders

    使用之前的方法写Shader是一件很痛苦的事情,把Shader代码直接卸载C++文件中,需要使用很多引号来包裹,既不美观也不方便. 我们这节的目的是使用纯文本文件保存Shader. 首先在工程中创建两 ...

  10. struct files_struct

    内核利用文件描述符(file descriptor)来访问文件.文件描述符是非负整数.它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表.当程序打开一个现有文件或者创建一个新文件时,内 ...