程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Java学习笔记-Day90 Spring Cloud框架

发布于2021-05-29 20:47     阅读(928)     评论(0)     点赞(17)     收藏(1)



一、Spring Cloud的简介


Spring Cloud 是一套完整的微服务解决方案,基于 Spring Boot 框架,准确的说,它不是一个框架,而是一个大的容器,它将市面上较好的微服务框架集成进来,从而简化了开发者的代码量。

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。

Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。Spring Cloud 并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。

Spring提供了一系列工具,可以帮助开发人员迅速搭建分布式系统中的公共组件(比如:配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,主节点选举, 分布式session, 集群状态)。协调分布式环境中各个系统,为各类服务提供模板性配置。使用Spring Cloud, 开发人员可以搭建实现了这些样板的应用,并且在任何分布式环境下都能工作得非常好,小到笔记本电脑, 大到数据中心和云平台。
在这里插入图片描述

二、集群和分布式


集群是物理形态,将同一个业务部署在多台服务器上。分布式是工作方式,将一个业务分拆成多个子业务,分别部署在不同的服务器上。

集群是指将多台服务器都实现同一个业务,分布式是指将不同的业务部署在不同的服务器。分布式中的每一个节点,都可以做集群,而集群并不一定就是分布式的。

如果访问的人数非常多,可以做一个群集,前面放一个响应服务器,后面多台服务器完成同一个业务,如果有业务访问的时候,响应服务器会看一下哪台服务器的负载不是很重,然后就将这个业务访问给这台服务器去完成。

分布式的组织比较松散,不像集群那样有组织性(如果一台服务器垮了,其它的服务器可以顶上来),分布式的每一个节点,都完成不同的业务,如果一个节点垮了,那这个业务就不能访问。

三、Spring Cloud的优缺点


Spring Cloud的优点有:
(1)集大成者:Spring Cloud 包含了微服务架构的方方面面。
(2)约定优于配置:基于注解,没有配置文件。
(3)轻量级组件:Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者。
(4)开发简便:Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。
(5)开发灵活:Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。

Spring Cloud的缺点有:
(1)项目结构复杂:每一个组件或者每一个服务都需要创建一个项目。
(2)部署门槛高:典型项目部署需要配合 Docker 等容器技术进行集群部署。

四、服务注册与发现

1、简单介绍


为了创建SpringCloud的服务中心,需要用的的组件上Spring Cloud Netflix的Eureka 。Eureka是Spring Cloud默认的服务注册和发现模块,是一个高可用的组件,它没有后端缓存(因此可以在内存中完成),每一个实例注册之后需要向注册中心发送心跳,在默认情况下Eureka server也是一个Eureka client,必须要指定一个和Dubbo的Dubbo Admin类似的server,Eureka也提供了一个基于WEB的管理界面,用于查看管理目前已经注册运行的服务。
在这里插入图片描述
Eureka中非常重要的两个部分:Eureka Server和Eureka Client。Eureka Server提供了服务发现的能力,当每个微服务启动的时候,会向Eureka Server注册自己的信息,这些信息包含微服务的地址,端口,名称等,Eureka Server会存储这些信息。Eureka Client是一个java的客户端。默认情况下,Eureka Server同时也是一个Eureka Client。多个Eureka Server实例,相互之间通过复制,实现注册表之间的数据同步。每个微服务启动后,会周期性的(30秒)向Eureka Server发送心跳,来续约自己的租期,如果在一定的周期内(90秒)没有接收到某个微服务实例的心跳,则Eureka Server会注销该实例。

2、实现流程


(1)New -> Project -> 选择Empty Project -> Next -> 输入项目名springcloud1和项目所在的位置。
在这里插入图片描述
(2)创建服务注册中心:创建Eureka Server的模块,选择Modules,点击+号,选择New Module,选择Spring Initializr,点击Next,输入项目名和包名,选择对应的jdk,点击Next,选择Web的Spring Web和Spring Cloud Discovery的Eureka Server,点击Next,输入模块名和模块的存储位置,点击Finish。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建一个服务注册中心,只需要添加一个注解@EnableEurekaServer,这个注解需要添加在SpringBoot工程的启动application类上。

package com.etc.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaserverApplication {

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

}

在resource包中添加application.yml文件。在默认情况下,Erureka Server也是一个Eureka Client,所以必须要指定一个服务器地址。通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明这是一个Erureka Server,registerWithEureka为false表示不需要将自己注册到服务注册中心,fetchRegistry为false表示这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据。serverUrl后的地址是服务与Eureka Server交互的地址,查询服务和注册服务都要依赖这个地址,设置默认地址为: http://localhost:8761/eureka。

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serverUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

运行Spring Boot的启动类,访问地址 http://127.0.0.1:8761/ ,Application中为空则表示无任何的微服务注册到Eureka Server。

在这里插入图片描述

(3)将微服务注册到Eureka Server:创建第一个Eureka Client模块,选择Modules,点击+号,选择New Module,选择Spring Initializr,点击Next,输入项目名和包名,选择对应的jdk,点击Next,选择Web的Spring Web、SQL的MySQL Driver和MyBatis framework、Spring Cloud Discovery的Eureka Discovery Client,点击Next,输入模块名和模块的存储位置,点击Finish。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在启动类前添加@EnableEurekaClient(表示这是一个Eureka的client)和@MapperScan注解。

package com.etc.eurekaclientuser;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.etc.eurekaclientuser.mapper")
public class EurekaclientUserApplication {

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

}

在resource包中添加application.yml文件,server :port 表示的当前这个微服务的端口。defaultZone 表示的是当前的微服务注册到Eureka Server的地址。instance:prefer-ip-address 表示将ip地址注册到Eureka Server。application-name 表示的是当前应用的name,用于注册到Eureka Server 。

server:
  port: 8762

eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: eureka-user-client
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/userdb?serverTimezone=Asia/Shanghai
    username: root
    password: root
mybatis:
  mapper-locations: classpath:/mapper/*.xml
logging:
  level:
    com.etc.eurekaclientuser.mapper: debug
  pattern:
    console: '%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n'

idea连接MySQL数据库,通过MyBatisX插件生成user表的mapper层和entity层的代码文件。
在这里插入图片描述
创建com.etc.eurekaclientuser.service包,在该包下创建impl文件夹,再创建service层的代码文件。

  • UserService.java
package com.etc.eurekaclientuser.service;

import com.etc.eurekaclientuser.entity.User;

public interface UserService {
    User getUserById(Long id);
}
  • UserServiceImpl.java
package com.etc.eurekaclientuser.service.impl;

import com.etc.eurekaclientuser.entity.User;
import com.etc.eurekaclientuser.mapper.UserMapper;
import com.etc.eurekaclientuser.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Long id) {
        return userMapper.selectByPrimaryKey(id);
    }
}

创建com.etc.eurekaclientuser.controller包,再创建controller层的代码文件。

  • UserController.java
package com.etc.eurekaclientuser.controller;

import com.etc.eurekaclientuser.entity.User;
import com.etc.eurekaclientuser.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    private UserServiceImpl userServiceImpl;

    @GetMapping("/user/{userid}")
    public User listUser(@PathVariable Long userid) {
        return userServiceImpl.getUserById(userid);
    }
}

运行Spring Boot的启动类,访问地址 http://127.0.0.1:8761/

在这里插入图片描述
访问地址http://127.0.0.1:8762/user/2,就可以查看从数据库中获取的数据。
在这里插入图片描述

在启动当前的微服务之后,会在Eureka Server的控制台中看到当前的微服务注册的信息。

在这里插入图片描述

创建第二个Eureka Client模块(只是用来调用另外一个Eureka Client模块的业务,暂时先不连接数据库):选择Modules,点击+号,选择New Module,选择Spring Initializr,点击Next,输入项目名和包名,选择对应的jdk,点击Next,选择Web的Spring Web、Spring Cloud Discovery的Eureka Discovery Client,点击Next,输入模块名和模块的存储位置,点击Finish。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在启动类前添加@EnableEurekaClient注解。

package com.etc.eurekaclientgoods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class EurekaclientGoodsApplication {

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

}

在resource包中添加application.yml文件。

server:
  port: 8763

eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: eureka-goods-client

创建com.etc.eurekaclientgoods.config包,在该包下创建配置文件MyConfiguration(用于RestTemplate的自动注入)。

  • MyConfiguration.java
package com.etc.eurekaclientgoods.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class MyConfiguration {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

创建com.etc.eurekaclientgoods.controller包,在该包中创建controller层的代码。

  • GoodsController.java
package com.etc.eurekaclientgoods.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GoodsController {

    @GetMapping("/goods/list")
    public String goodslist(){
        return "goodslist";
    }

}

  • GoodsController.java
package com.etc.eurekaclientgoods.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RestUserController {
    private final String url="http://127.0.0.1:8762";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/restuser/{userid}")
    public String listUser(@PathVariable Long userid){
        return restTemplate.getForObject(url+"/user/"+userid,String.class);
    }
}

运行Spring Boot的启动类,访问地址 http://127.0.0.1:8761/
在这里插入图片描述
访问地址http://127.0.0.1:8763/restuser/2,就可以调用第一个Eureka Client模块的Controller。
在这里插入图片描述

3、Eureka Server的用户认证


上述的案例中,访问Eureka Server 是匿名的。现在构建一个需要登录才能访问的Eureka Server。
(1)在Eureka Server模块的pom.xml文件中添加以下依赖。

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

(2)修改Eureka Server模块的application.yml文件。

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serverUrl:
      # 增加验证 admin:123456@
      defaultZone: http://admin:123456@localhost:8761/eureka

spring:
  security:
    user:
      name: admin
      password: 123456

(3)修改Eureka Client模块的application.yml文件中的defaultZone。

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:123456@localhost:8761/eureka

4、加入actuator监控系统


actuator是SpringBoot程序的监控系统,可以实现健康检查、info信息等。在使用之前需要引入spring-boot-starter-actuator,并做简单的配置。

(1)在Eureka Client的pom.xml加入以下依赖。

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

(2)在Eureka Client的配置文件application.yml/application.properties加入以下配置。

如果是yml文件,则添加以下内容

info:
  app: @project.artifactId@
  encoding: @project.build.sourceEncoding@
  java:
    javahome: @java.home@
    javaversion: @java.version@

如果是properties文件,则添加以下内容

info.app=@project.artifactId@
info.encoding=@project.build.sourceEncoding@
info.java=@java.home@
info.javaversion=@java.version@

(3)点击Status下面的链接,就可以查看该Eureka Client的info信息。

在这里插入图片描述
在这里插入图片描述

五、Feign

1、简单介绍


Feign是Netflix开发的声明式、模板化的HTTP客户端, 可以更快捷、优雅地调用HTTP API。

Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。

Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud Feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。Spring Cloud Feign具备可插拔的注解支持,支持Feign注解、JAX-RS注解和Spring MVC的注解。

OpenFeign是Spring Cloud在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

Spring Cloud F及F版本以上、Spring Boot 2.0以上 基本上是使用OpenFeign。

2、微服务加入OpenFeign


(1)创建 eurekaclient-goods-openfeign 微服务。

复制一份 eurekaclient-goods 项目,修改该项目的相关信息(pom.xml、application.yml、启动类名、项目名),将 eurekaclient-goods 项目变成 eurekaclient-goods-openfeign 项目。然后在springcloud1项目中将 eurekaclient-goods-openfeign 项目作为Module导入。

  • pom.xml

在这里插入图片描述

  • application.yml
server:
  port: 8764

eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://admin:123456@localhost:8761/eureka

spring:
  application:
    name: eureka-goods-openfeign-client
  • 启动类
@SpringBootApplication
@EnableEurekaClient
public class EurekaclientGoodsOpenfeignApplication {

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

}

(2)在 eurekaclient-goods-openfeign 微服务中整合OpenFeign。

1.在pom.xml文件中加入以下依赖。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

2.创建Feign接口,并添加一个@FeignClient的注解。@FeignClient(name = “eureka-user-client”) 表示的是一个任意的客户端名称,用于创建Ribbon负载均衡器,而name参数的值是其他微服务的名字。

  • UserFeignClient.java
package com.etc.eurekaclientgoods.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name="eureka-user-client")
public interface UserFeignClient {
    // 使用spring mvc的相关注解
    @GetMapping("/user/{userid}")
    public String listUser(@PathVariable Long userid);
}

3.创建一个控制器用来调用Feign接口。.

  • RestUserController.java
package com.etc.eurekaclientgoods.controller;

import com.etc.eurekaclientgoods.feign.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RestUserController {
    @Autowired
    private UserFeignClient userFeignClient;

    @GetMapping("/restuser/{userid}")
    public String listUser(@PathVariable Long userid){
        return userFeignClient.listUser(userid);
    }
}

4.在启动类前加上@EnableFeignClients注解。

  • EurekaclientGoodsOpenfeignApplication.java
package com.etc.eurekaclientgoods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaclientGoodsOpenfeignApplication {

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

}

(3)访问地址http://127.0.0.1:8764/restuser/2

在这里插入图片描述

3、Ribbon负载均衡器


Ribbon是Netflix发布的负载均衡器,是基于HTTP和TCP客户端的负载均衡器。为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,例如:轮询,随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。

在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。

在 Spring Cloud中可以单独配置Ribbon,也可以配置Feign(在Feign中默认就支持Ribbon)。接下来修改上面整合了Feign的微服务启动方式,测试该微服务是否能支持Ribbon。

(1)修改 eurekaclient-user 微服务(提供者): 增加关于随机端口的方法,这样可以多次启动同一个微服务,从而模拟测试一个微服务的多个实例。

1.创建 com.etc.eurekaclientuser.config 包,并在该包下创建 PortConfig 类。在运行启动类时,会使用一个在8001~8999之间的随机端口号,每次启动时都会产生一个新的实例。

package com.etc.eurekaclientuser.config;

import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.SocketUtils;

@Configuration
public class PortConfig {
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                int port = SocketUtils.findAvailableTcpPort(8001, 8999);
                factory.setPort(port);
                System.getProperties().put("server.port", port);

            }
        };
    }
}

2.在idea中默认不允许一个项目多个实例,所以要先将启动的选项设置为允许启动多个实例。

在这里插入图片描述

在这里插入图片描述
(2)运行多次 eurekaclient-user 的启动类,每次启动后,会发现控制台的端口不同,在注册中心也有多个实例启动。

在这里插入图片描述
在这里插入图片描述
(3)访问地址http://127.0.0.1:8764/restuser/2,刷新网页5次,网页上得到相同的数据,但发现在不同微服务实例的控制台出现查询sql语句,说明实现了负载均衡。

在这里插入图片描述

4、Feign的日志管理


在很多场景中,需要对Feign处理请求的细节进行查看和分析,此时需要用到Feign的日志管理。Feign的日志处理非常灵活,我们可以为每个客户端设置日志记录策略,为每个客户端可以创建一个Logger,为每个客户端配置各自的Logger.level对象,从而告知Feign记录哪些日志,Logger.Level的值有以下选择。

Logger.Level的值意义
NONE不记录任何日志(默认)
BASIC仅记录请求方法,url,响应状态代码和执行时间
HEADERS在BASIC的基础上,记录请求和响应的header
FULL记录请求和响应的header,body和元数据

(1)在eurekaclient-goods-openfeign模块的 com.etc.eurekaclientgoods.config 包中创建 LoggerConfig 类。

package com.etc.eurekaclientgoods.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LoggerConfig {
    @Bean
    public Logger.Level getLoggerLevel(){
        return Logger.Level.FULL;
    }
}

(2)在eurekaclient-goods-openfeign模块的application中添加以下配置。

logging:
  level:
    com.etc.eurekaclientgoods.feign.UserFeignClient: debug

(3)访问地址http://127.0.0.1:8764/restuser/2,在eurekaclient-goods-openfeign的控制台中会出现如下信息。

在这里插入图片描述

六、HyStrix容错处理

1、简单介绍


在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 雪崩效应,为了解决这个问题,业界提出了断路器模型。断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决,如果问题已经得到纠正,应用程序可以尝试调用操作。

Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。 在微服务架构中,一个请求需要调用多个服务是非常常见的。较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystrix 是5秒20次) 断路器将会被打开。

Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。

Hystrix主要通过以下几点实现延迟和容错:
(1)包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用了设计模式中的“命令模式”。
(2)跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
(3)资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
(4)监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
(5)回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如值返回一个缺省。
(6)自我修复:断路器打开一段时间后,会自动进入“半开”状态。

2、Feign方式整合Hystrix


(1)创建eurekaclient-goods-openfeign-hystrix微服务。

复制一份 eurekaclient-goods-openfeign 项目,修改该项目的相关信息(pom.xml、application.yml、启动类名、项目名),将 eurekaclient-goods-openfeign 项目变成eurekaclient-goods-openfeign-hystrix项目。然后在springcloud1项目中将 eurekaclient-goods-openfeign-hystrix 项目作为Module导入。

  • pom.xml

在这里插入图片描述

  • application.yml
server:
  port: 8765

eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://admin:123456@localhost:8761/eureka

spring:
  application:
    name: eureka-goods-openfeign-hystrix-client

logging:
  level:
    com.etc.eurekaclientgoods.feign.UserFeignClient: debug
  • EurekaclientGoodsOpenfeignHystrixApplication.java
package com.etc.eurekaclientgoods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient //eureka的客户端
@EnableFeignClients//支持Feign
public class EurekaclientGoodsOpenfeignHystrixApplication {

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

}

(2)在 eurekaclient-goods-openfeign-hystrix 微服务中加入Hystrix的支持。

1.在pom.xml文件中加入以下依赖。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

2.在UserFeignClient接口的@FeignClient注解中添加一个fallback属性,再创建UserFeignClient接口的实现类HystrixFallBack。

  • UserFeignClient.java
package com.etc.eurekaclientgoods.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

//HystrixFallBack.class 自定义的回退逻辑
@FeignClient(name = "eureka-user-client",fallback = HystrixFallBack.class)
public interface UserFeignClient {
    //使用spring mvc的相关注解
    @GetMapping("/user/{userid}")
    public String listUser(@PathVariable Long userid);
}

@Component
class HystrixFallBack implements UserFeignClient {
    @Override
    public String listUser(Long userid) {
        return "hystrix user:"+userid;
    }
}

3.在application.yml中加入hystrix的支持。

feign:
  hystrix:
    enabled: true

4.在启动类前加入@EnableHystrix注解。

package com.etc.eurekaclientgoods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient //eureka的客户端
@EnableFeignClients//支持Feign
@EnableHystrix//支持Hystrix
public class EurekaclientGoodsOpenfeignHystrixApplication {

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

}

(3)分别启动eurekaserver微服务(注册中心)、 eureka-user微服务(提供者)、eureka-goods-feign-hystrix微服务(消费者),访问网址 http://127.0.0.1:8765/restuser/2

在这里插入图片描述
然后关闭eureka-user微服务,刷新网页。eurekaclient-goods-openfeign-hystrix微服务作为消费者,eureka-user微服务作为提供者,关闭eureka-user微服务,由于现在使用的是回退机制,所以此时会返回一个缺省的值。

在这里插入图片描述

3、Feign项目的Hystrix监控


(1)在启动类前加入@EnableCircuitBreaker注解。

  • EurekaclientGoodsOpenfeignHystrixApplication.java
package com.etc.eurekaclientgoods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient //eureka的客户端
@EnableFeignClients//支持Feign
@EnableHystrix//支持Hystrix
@EnableCircuitBreaker
public class EurekaclientGoodsOpenfeignHystrixApplication {

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

}

(2)在MyConfiguration类中加入以下配置代码。

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

(3)访问网址http://localhost:8765/hystrix.stream

在这里插入图片描述
刷新网页 http://127.0.0.1:8765/restuser/2 ,则 http://localhost:8765/hystrix.stream 会出现数据。以上的数据能够展示请求的相关信息,但是不够友好。

在这里插入图片描述

4、使用Hystrix Dashboard可视化监控数据


上面的Hystrix监控虽然能够监控数据,但是/hystrix.stream获得的数据是以文字形式展现的,如果想使用更为直观的图形化界面展示数据,可以使用Hystrix Dashboard。

为了更好的显示结果,扩展程序,我们新建一个新的项目,专门用来监控其他微服务的状况。

(1)新建一个叫eureka-hystrix-dashboard的模块,选择的依赖有Web的Spring Web、Spring Cloud Circuit Breaker的Hystrix和Hystrix Dashboard(可视化界面)。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)在application.yml中加入以下配置。

server:
  port: 9090

hystrix:
  dashboard:
    proxy-stream-allow-list: localhost

(3)在启动类前加入@EnableHystrixDashboard注解。

  • EurekaHystrixDashboardApplication.java
package com.etc.eurekahystrixdashboard;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class EurekaHystrixDashboardApplication {

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

}

(4)访问网址 http://localhost:9090/hystrix。输入监控的地址,将http://localhost:8765/hystrix.stream输入到文本框,点击Monitor Stream按钮,进入dashboard页面,刷新网页 http://127.0.0.1:8765/restuser/2,dashboard页面将会展示数据。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

七、Zuul路由网关

1、简单介绍


在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul集群),然后再到具体的服务,服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在Git仓库,方便开发人员随时更改配置。

Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。Zuul默认和Ribbon结合实现了负载均衡的功能。

微服务网关Zuul封装了应用程序的内部结构,客户端只需要和Zuul网关交互,而无需调用特定微服务的接口,开发得到了简化。除此之外,还有如下功能:易于监控、易于认证、有效的减少了客户端与每个微服务交互的次数。

Zuul是Netflix出品的微服务网关,可以和Eureka、Ribbon、HyStrix等组件配合使用,Zuul的核心是一系列的过滤器,可以完成以下功能。

  • 身份认证与安全:识别每个资源的验证要求,拒绝与要求不符的请求。
  • 审查与监控:边缘位置追踪有意义的数据和统计结果。
  • 动态路由:动态的请求路由到不同的后端集群。
  • 压力测试:逐渐增加指向集群的流量,了解其性能指标。

2、实现过程


新建项目,增加zuul的支持,由于该服务也要向Eureka Server注册,所以要加入eureka-client的支持。

(1)创建eureka-zuul-demo模块,选择依赖Web的Spring Web、Spring Cloud Discovery的Eureka Discovery Client、Spring Cloud Routing的Zuul。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)在启动类添加注解@EnableEurekaClient和@EnableZuulProxy。

  • EurekaZuulDemoApplication.java
package com.etc.eurekazuuldemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class EurekaZuulDemoApplication {

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

}

(3)在application.yml中加入以下配置代码。

server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:123456@localhost:8761/eureka
  instance:
    prefer-ip-address: true

spring:
  application:
    name: eureka-zuul-demo

(4)分别启动eurekaserver微服务(注册中心)、 eureka-user微服务(提供者)、eureka-goods-feign-hystrix微服务(消费者)、eureka-zuul-demo微服务(路由网关)。

在这里插入图片描述

访问 eureka-user微服务(http://localhost:8005/user/2)、eureka-goods-feign-hystrix微服务(http://localhost:8765/restuser/2)。 注意:eureka-user微服务的端口8005是一个随机的端口。

在这里插入图片描述
在这里插入图片描述

通过eureka-zuul-demo微服务来访问 eureka-user 微服务 (http://localhost:9999/eureka-user-client/user/2)和 eureka-goods-feign-hystrix 微服务(http://localhost:9999/eureka-goods-openfeign-hystrix-client/restuser/2)。

在这里插入图片描述

在这里插入图片描述

由此可以验证,Zuul的规则如下:

http://zuul主机名:zuul端口/微服务在EurekaServer上的注册名[小写]/user/2

会转发到 微服务在EurekaServer上的注册名[小写]/user/2 对应的微服务:

http://微服务在EurekaServer上的注册名:8005/user/2

3、自定义微服务的访问路径


方式一:

自定义微服务的访问路径,在application.yml中加入以下配置。

zuul:
  routes:
    eureka-user-client: /users/**  #由eureka-user-client微服务转发到/users/**

此时访问 http://localhost:9999/users/user/2http://localhost:9999/eureka-user-client/user/2,这两个网页都能成功显示数据。

在这里插入图片描述
在这里插入图片描述

方式二:

忽略指定的微服务(ignored-services),在application.yml中加入以下配置。

zuul:
  routes:
    eureka-user-client: /users/**  #由eureka-user-client微服务转发到/users/**
  ignored-services: eureka-user-client #忽略掉这个微服务,直接通过users访问

此时访问 http://localhost:9999/users/user/2http://localhost:9999/eureka-user-client/user/2,只有 http://localhost:9999/users/user/2 能成功显示数据。
在这里插入图片描述
在这里插入图片描述

方式三:

忽略所有服务,指定路由其中某个服务,在application.yml中加入以下配置。

zuul:
  ignored-services: '*' #忽略所有微服务
  routes:
    eureka-user-client: /users/**  #由eureka-user-client微服务转发到/users/**

在这里插入图片描述
在这里插入图片描述

方式四:

同时指定微服务的 serviceId和对应的路径,在application.yml中加入以下配置。

zuul:
  routes:
    users-route: #自定义route名字
      service-id: eureka-user-client
      path: /users/**
    goods-route: #自定义route名字
      service-id: eureka-goods-openfeign-hystrix-client
      path: /goods/**
  ignored-services: '*' #忽略所有微服务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

八、Spring Cloud Config

1、简单介绍


在Spring Cloud中,有分布式配置中心组件Spring Cloud Config,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色:config server和config client。

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决上百个配置文件的管理(每个微服务都带着一个application.yml)问题。

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

2、作用


集中管理配置文件、不同环境不同配置,动态化的配置更新,分环境部署比如:dev/test/prod/beta/release等。运行期间动态调整配置,不再需要在每一个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。当配置发生变化时,服务不需要重启即可感知到配置的变化并应用新的配置、将配置信息以rest接口形式暴露。

3、实现过程


(1)先在码云中建立配置文件。

1.在码云上创建一个springcloud-config-demo的仓库。

在这里插入图片描述
在这里插入图片描述
2.创建一个springcloudconfig文件夹,在DOS窗口中进入该文件夹,再通过git命令将springcloud-config-demo下载到本地。

git clone 仓库地址

在这里插入图片描述
3.在springcloud-config-demo文件夹中创建application.yml,在DOS窗口中进入springcloud-config-demo文件夹中,再通过git命令将application.yml上载到仓库中。

  • application.yml
spring: 
  profiles: 
    active: dev
---
spring: 
  profiles: dev
  application: 
    name: springcloud-config-dev
---
spring: 
  profiles: test
  application: 
    name: springcloud-config-test
---
spring: 
  profiles: prod
  application: 
    name: springcloud-config-prod

git add .
git commit -m "初始化文件"
git push origin master

在这里插入图片描述
4.刷新码云仓库的页面,就会看到上传的文件。
在这里插入图片描述
(2)创建配置中心服务端。

1.创建一个springcloud-config的模块,依赖选择Web的Spring Web、Spring Cloud Config的Config Server。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
2.在resources中创建application.yml。

server:
  port: 1234
spring:
  cloud:
    config:
      server:
        git:
          password: 码云账号的密码
          username: 码云账号
          uri: 仓库地址

3.在启动类前加入@EnableConfigServer注解。

  • SpringcloudConfigApplication.java
package com.etc.springcloudconfig;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class SpringcloudConfigApplication {

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

}

4.运行启动类启动微服务,访问网址 http://localhost:1234/application-dev.ymlhttp://localhost:1234/application-test.ymlhttp://localhost:1234/application-prod.yml。通过访问以上地址,如果可以正常返回数据,则说明配置中心服务端一切正常。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
(3)创建配置中心客户端,使用配置。

1.修改在(1)中springcloud-config-demo文件夹里创建的application.yml的文件名为application.yml_bak,再创建springcloud-config-client.yml文件。

在这里插入图片描述

  • springcloud-config-client.yml
spring:
  profiles:
    active:
    - dev
---
server: 
  port: 8701 
spring:
   profiles: dev
   application: 
      name: springcloud-config-client
eureka: 
  client: 
    service-url: 
      defaultZone: http://localhost:8761/eureka/  
---
server: 
  port: 8702 
spring:
  profiles: test
  application: 
    name: springcloud-config-client
eureka: 
  client: 
    service-url: 
      defaultZone: http://localhost:8761/eureka/
---
server: 
  port: 8703 
spring:
  profiles: prod
  application: 
    name: springcloud-config-client
eureka: 
  client: 
    service-url: 
      defaultZone: http://localhost:8761/eureka/

2.通过git命令将这两个文件上传到远程仓库中。

在这里插入图片描述
3.创建一个springcloud-config-client的模块,依赖选择Web的Spring Web、Spring Cloud Config的Config Client。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.在resources中创建application.yml、bootstrap.yml。

  • application.yml
spring:
  application:
    name: springcloud-config-client
server:
  port: 1235
  • bootstrap.yml
spring:
  cloud:
    config:
      name: springcloud-config-client #需要从github上读取的资源名称,注意没有yml后缀名
      profile: test   #本次访问的配置项  dev为8701  test为8702
      label: master
      uri: http://127.0.0.1:1234  #本微服务启动后先去找1234端口服务,通过SpringCloudConfig获取GitHub的服务地址

5.要读取配置中心的内容,需要增加相关的配置类,Spring Cloud Config 读取配置中心内容的方式和读取本地配置文件中的配置是相同的,可以通过 @Value 来获取。创建com.etc.springcloudconfigclient.controller包,在该包中创建ConfigClient.java文件。

  • ConfigClient.java
package com.etc.springcloudconfigclient.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConfigClient {
    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServers;

    @Value("${server.port}")
    private String port;

    @RequestMapping("/config")
    public String getConfig() {
        String str = "applicationName: " + applicationName + "\t eurekaServers:" + eurekaServers + "\t port: " + port;
        System.out.println("******str: " + str);
        return "applicationName: " + applicationName + "\t eurekaServers:" + eurekaServers + "\t port: " + port;
    }
}

6.运行启动类启动项目,访问网址http://localhost:8702/config,成功读取配置中心的内容。

在这里插入图片描述



所属网站分类: 技术文章 > 博客

作者:我是小豆丁

链接:http://www.javaheidong.com/blog/article/207499/f10cf917bf66283b2912/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

17 0
收藏该文
已收藏

评论内容:(最多支持255个字符)