(三)SpringCloud 熔断器Netflix Hystrix、服务网关Netflix Zuul、分布式配置Spring Cloud Config、消息总线Spring Cloud Bus

实战项目代码:SpringCloud_Test_GitHub

上一章:(二)SpringCloud 服务发现Netflix Eureka 和 服务调用Netflix Feign


在该章我们介绍剩余的SpringCloud组件

1.熔断器——Netflix Hystrix

在第一章我们已经大致说了一下熔断器的作用——防止服务器雪崩
那么现在我们就介绍一下Hystrix熔断器,Hystrix 能使你的系统在出现依赖服务失效的时候,通过隔离系统所依赖的服务,防止服务级联失败,同时提供失败回退机制,更优雅地应对失效,并使你的系统能更快地
从异常中恢复。
工作模式:
在这里插入图片描述

1.1 快速入门

模拟情况:我们在上章中使用Teacher服务调用了Student服务,如果Student服务挂了,我们再次使用Teacher服务调用Student服务,就会失败。
关闭Student服务,使用postman发送请求给http://localhost:9002/teacher/student/1

{
    "timestamp": "2019-08-03T06:43:43.280+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "connect timed out executing GET http://student/student/1",
    "path": "/teacher/student/1"
}

这不仅消耗时间,而且返回的消息十分不友好,下面我们来使用熔断器

Feign 本身支持Hystrix,不需要额外引入依赖。

  1. 在配置文件中打开Feign
#开启熔断器
feign:
  hystrix:
    enabled: true
  1. 创建StudentClient的接口实现类StudentClientImpl,com.springcloud.teacher.client.impl.StudentClientImpl
@Component
public class StudentClientImpl implements StudentClient {
    @Override
    public Result findById(int studentid) {
        return new Result("熔断器触发了");
    }
}
  1. 修改StudentClient接口的注解
@FeignClient(value = "student",fallback = StudentClientImpl.class)
  1. 重新启动Teacher服务,再次使用postman测试,返回如下消息
{
    "message": "熔断器触发了",
    "data": null
}
  1. 我们在不重启Teacher服务的情况下,启动Student服务,再次使用postman测试,返回如下消息
{
    "message": "查询成功",
    "data": {
        "id": 1,
        "name": "小明",
        "age": 10
    }
}

也就是说Hystrix会判断Student服务是否在运行,如果在运行则走Student服务,如果没有运行则走本地的方法,这是一个动态的过程,因为他不用Teacher服务重新编译启动,非常智能。

2.服务网关——Netflix Zuul

Zuul就像一个总管,他管理则有关的服务,只向外暴露一个接口,消费者通过这个接口可以访问所有他管理的服务
在这里插入图片描述
Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求
  • 动态路由:动态将请求路由到不同后端集群
  • 压力测试:逐渐增加指向集群的流量,以了解性能
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
  • 静态响应处理:边缘位置进行响应,避免转发到内部集群
  • 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化

当然你不用了解上面所有的功能,你只要知道zuul有路由、过滤的作用就行了。

2.1 快速入门

  1. 创建manager子工程
  2. 向子工程中导入坐标
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>
  1. 编写配置信息application.yml
server:
  port: 9011
spring:
  application:
    name: manager
eureka:
  client:
    serviceUrl: #Eureka客户端与Eureka服务端进行交互地址
      defaultZone: http://127.0.0.1:9010/eureka/
  instance:
    prefer-ip-address: true
zuul:
  routes:
    student: #线路名称
      path: /student/** #线路url配置规则
      serviceId: student #调用服务的ID
    teacher:
      path: /teacher/**
      serviceId: teacher
  1. 编写ManagerApplication启动类,com.springcloud.manager.ManagerApplication
@SpringBootApplication
@EnableZuulProxy //启动Zull代理
public class ManagerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ManagerApplication.class,args);
    }
}
  1. 编写ManagerFiler过滤器com.springcloud.manager.Filer.ManagerFiler
@Component
public class ManagerFiler extends ZuulFilter {
    //设置是在请求前(pre)执行过滤器还是请求后(post)
    @Override
    public String filterType() {
        return "pre";
    }

    //有多个过滤器时的执行顺序,数值越小越先执行
    @Override
    public int filterOrder() {
        return 0;
    }

    //设置该过滤器是否可用
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //具体逻辑,返回object即为放行(null也是object类型)
    @Override
    public Object run() throws ZuulException {
        //终止运行方法
//        RequestContext requestContext = RequestContext.getCurrentContext();
//        requestContext.setSendZuulResponse(false);
       
        System.out.println("进过了过滤器.....");
        return null;
    }
}
  1. 启动Zuul服务,需要重启Student服务和Teacher服务,使用postman进行测试http://localhost:9011/teacher/teacher/student/1 第一个teacher是告诉zuul请求需要访问的服务名

:zuul转发是不会携带消费者发送过来的头信息,需要自己手动在run()方法中转发,requestContext可以获得request,使用request获取头信息中的信息,使用requestContext.addZuulRequestHeader()设置转发头信息。

3.分布式配置——Spring Cloud Config

当我们的服务越来越多的时候,配置文件的管理会非常麻烦,因为代码一般上线不会改变,但是配置信息是有可能会改变的,所有我们需要将配置文件集中起来统一管理。

在Spring Cloud中,有分布式配置中心组件spring cloudconfig ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置文件内容,也可以使用SVN存储,或者是本地文件存储。
Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。微服务在启动时会请求Config Server获取配置文件的内容,请求到后再启动容器。

本次我们使用“码云”来作为远端Git 存放配置信息

3.1 上次服务配置信息

  1. 注册码云帐号
  2. 创建仓库
    在这里插入图片描述
  3. 将Student中application.yml复制出来更名为student-test.yml,上传到刚刚创建的仓库(这里我只做student服务的,其他服务请自行修改)
    文件命名规则:
    {application}-{profile}.yml或{application}-{profile}.properties
    application为应用名称 profile指的开发环境(用于区分开发环境,测试环境、生产环境
    等)
    4.复制仓库地址

3.2 配置中心服务端

  1. 创建子工程config,导入坐标
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>
  1. 创建配置文件application.yml
server:
  port: 12000
spring:
  application:
    name: config
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/dreamylois/springcloud_test.git #填写刚刚复制的仓库地址
  1. 创建启动类com.springcloud.config.ConfigApplication
@SpringBootApplication
@EnableConfigServer //开启配置服务
public class ConfigApplication {
    public static void main(String[] args) {
         SpringApplication.run(ConfigApplication.class,args);
    }
}
  1. 启动服务,在浏览器中输入http://localhost:12000/student-test.yml,可看见该配置文件的信息

3.3 配置客户端

  1. 向student项目中pom添加坐标
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
  1. 删除student项目中的application.yml配置文件,创建bootstrap.yml(名称固定,不能修改)
spring:
  cloud:
    config:
      name: student
      profile: test
      label: master
      uri: http://localhost:12000

name:远端配置文件名称前半段,profile:远端配置文件名称后半段,uri:config服务地址

  1. 重启Student服务,使用postman发送请求http://localhost:9001/student/1,返回信息正常

4.消息总线——Spring Cloud Bus

我们使用Spring Cloud Config将配置信息放在了远端git上面,但是我们修改git上的配置信息是不会影响到已经在运行的服务,只有重启才能改变配置,而重启这件事情是非常麻烦的事情。所有我们希望能够修改git上面的配置信息来自动更新已经运行的服务,那么我们的Spring Cloud Bus就该登场了。

4.1 配置服务端

使用Bus需要rabbitMQ消息中间件,如果没有安装可以参考我博客中相关文章

  1. 向config项目的pom中添加坐标
 	<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-bus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
     </dependency>
  1. 修改config项目的配置文件application.yml,rabbitmq需要在spring中
  rabbitmq:
    host: 127.0.0.1
management: # 暴露触发消息总线的地址
  endpoints:
    web:
      exposure:
        include: "bus-refresh"

4.2 配置客户端

这里我们还是用Student服务为例

  1. 修改student项目中的pom,添加如下坐标
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-bus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
        </dependency>
  1. 修改码云上的student-test.yml文件,添加如下配置信息,rabbitmq还是要在spring中
  rabbitmq:
    host: 127.0.0.1

4.3 测试

  1. 依次重启eureka、config和student服务
  2. 创建另一个数据库和表,建表语句如下
create database `springcloudtest1`;
use `springcloudtest1`;
drop table if exists `tb_student`;
create table `tb_student`(
	`id` int PRIMARY KEY AUTO_INCREMENT ,
	`name`varchar(100) DEFAULT NULL COMMENT '姓名',
	`age`int DEFAULT 0 COMMENT '年龄'
);
insert into `tb_student`(`name`,`age`) values('测试信息111',10);
insert into `tb_student`(`name`,`age`) values('测试信息222',12);
  1. 使用postman发送请求http://localhost:9001/student/,返回如下信息
{
    "message": "查询成功",
    "data": [
        {
            "id": 1,
            "name": "小明",
            "age": 10
        },
        {
            "id": 2,
            "name": "小王",
            "age": 12
        }
    ]
}
  1. 修改码云上student的配置信息,将数据库的url改为如下,访问springcloudtest1数据库
url: jdbc:mysql://127.0.0.1:3306/springcloudtest1?characterEncoding=UTF8
  1. 重点:使用postman访问“http://127.0.0.1:12000/actuator/bus-refresh” 访问方式:post,返回消息空白即为成功。
  2. 再次使用postman访问http://localhost:9001/student/,返回信息如下
{
    "message": "查询成功",
    "data": [
        {
            "id": 1,
            "name": "测试信息111",
            "age": 10
        },
        {
            "id": 2,
            "name": "测试信息222",
            "age": 12
        }
    ]
}

4.4 访问自定义配置信息

上面我们使用的自动更新只会自动更新框架内的信息,如果我们在配置文件中写了一些自己的字段,是不会进行自动更新的。

  1. 向码云student配置信息添加如下内容
message: 11111
  1. 修改StudentController中相关内容
    @Value("${message}") //获取配置文件中的信息
    private String message;

    @RequestMapping(method = RequestMethod.GET)
    public Result findAll(){
        System.out.println(message); //打印信息
        return new Result("查询成功",studentService.findAll());
    }
  1. 重启Student服务,使用postman发送请求http://localhost:9001/student/
  2. 修改码云中的student配置信息中的message为22222
  3. 使用postman发送请求更新配置信息,再次向Student发送请求http://localhost:9001/student/
  4. 观察控制台输出,发现两次输出都是“11111”,表示并没有自动更新
    如何解决这个问题呢?
  5. 我们只需要在StudentController类上加上注解@RefreshScope即可
  6. 重启Student服务,向服务发送请求,控制台打印为22222
  7. 更新码云上的配置message为11111,使用postman发送更新配置信息请求
  8. 再次向Student服务发送请求,控制台打印11111

上一章:(二)SpringCloud 服务发现Netflix Eureka 和 服务调用Netflix Feign


相关内容:
(一)初见SpringCloud、主要框架简介、与SpringBoot版本对应关系,实战环境搭建

(二)SpringCloud 服务发现Netflix Eureka 和 服务调用Netflix Feign

(三)SpringCloud 熔断器Netflix Hystrix、服务网关Netflix Zuul、分布式配置Spring Cloud Config、消息总线Spring Cloud Bus

RabbitMQ简单入门教程(安装及工作模式介绍)图文教学通俗易懂

作者编写不易,转载请注明我的博客,如果觉得写的不错的话,请随手点个赞,谢谢!!!
作者编写不易,转载请注明我的博客,如果觉得写的不错的话,请随手点个赞,谢谢!!!
作者编写不易,转载请注明我的博客,如果觉得写的不错的话,请随手点个赞,谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值