Java学习笔记-Day90 Spring Cloud框架


一、Spring Cloud的简介


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

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

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

Spring Cloud 提供了一系列工具,可以帮助开发人员迅速搭建分布式系统中的公共组件(比如:配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,主节点选举, 分布式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、简单介绍


为了创建 Spring Cloud 的服务中心,需要用组件上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文件。在默认情况下,Eureka 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注解(Mybatis的配置)。

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信息。

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

5、 高可用的Eureka Server


上面实现了单节点的Eureka Server的服务注册与服务发现功能。Eureka Client会定时连接Eureka Server,获取注册表中的信息并缓存到本地。微服务在消费远程API时总是使用本地缓存中的数据。因此一般来说,即使Eureka Server发生宕机,也不会影响到服务之间的调用。但如果Eureka Server宕机时,某些微服务也出现了不可用的情况,Eureka Server的缓存若不被刷新,就可能会影响到微服务的调用,甚至影响到整个应用系统的高可用。因此,在生产环境中,通常会部署一个高可用的Eureka Server集群。

Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署,Eureka Server实例会彼此增量地同步信息,从而确保所有节点数据一致。事实上,节点之间相互注册是Eureka Server的默认行为。

(1)准备多个Eureka Serve,Eureka Server间的相互注册。

修改Eureka Server工程中的yml配置文件:

  • application.yml(eurekaServer1配置)
#指定应用名称
spring:
	application:
		name: eureka-server
#eureka的配置信息
server:
	port: 8000
eureka:
	client:
		service-url:
			defaultZone: http://localhost:9000/eureka
  • application.yml(eurekaServer2配置)
#指定应用名称
spring:
	application:
		name: eureka-server
#eureka的配置信息
server:
	port: 9000
eureka:
	client:
		service-url:
			defaultZone: http://localhost:8000/eureka

使用IDEA启动两次EurekaServerApplicaion,分别激活eurekaServer1和eurekaServer2配置。访问http://localhost:8000和http://localhost:9000,会发现注册中心 EUREKA-ERVER 已经有两个节点。
在这里插入图片描述
(2)将微服务注册到多个Eureka Server。
将微服务注册到多个Eureka Server只需要修改yml配置文件:

  • application.yml
eureka:
	client:
		service-url:
			defaultZone: http://localhost:8000/eureka/,http://localhost:9000/eureka/

修改defaultZone配置添加多个Eureka Server的地址,使用逗号隔开。

6、监控页面管控台显示服务ip


在这里插入图片描述
配置方式如下,在服务提供者中通过eureka.instance.instance-id手动配置服务ip。

  • application.yml
eureka:
	client:
		serviceUrl:
			defaultZone: http://localhost:8790/eureka/
	instance:
		#使用ip地址注册
		prefer-ip-address: true
		#向注册中心注册服务id
		#	spring.cloud.client.ip-address:获取ip地址
		#	server.port:获取端口
		instance-id: ${spring.cloud.client.ip-address}:${server.port}

7、Eureka服务剔除问题


在服务提供者中设置发送心跳时间和续约到期时间(建议在生产环境使用默认的时间配置)。

  • application.yml
eureka:
	client:
		serviceUrl:
			defaultZone: http://localhost:8790/eureka/
	instance:
		#使用ip地址注册
		prefer-ip-address: true
		#向注册中心注册服务id
		instance-id: ${spring.cloud.client.ip-address}:${server.port}
		#设置发送心跳续约间隔(默认30秒)
		lease-renewal-interval-in-seconds: 5 
		#设置eureka client发送心跳给server端后,续约到期时间(默认90秒)
		lease-expiration-duration-in-seconds: 10 

8、Eureka自我保护机制


在这里插入图片描述
自我保护模式是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。

自我保护机制的工作机制是:如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:

  1. Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
  2. Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
  3. 当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像zookeeper那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

Eureka自我保护机制通过 eureka.server.enable-self-preservationtrue打开/false禁用 )来配置自我保护机制,默认打开状态,建议生产环境打开此配置。

Eureka Server注册中心配置关闭自我保护,设置剔除无效节点的时间间隔(建议在生产环境使用默认的时间配置):
在这里插入图片描述
application.yml

eureka:
	instance:
		hostname: eureka-server
	client:
		service-url:
			defaultZone: http://localhost:8790/eureka/
	server:
		enable-self-preservation: false #关闭自我保护
		eviction-interval-timer-in-ms: 4000 #剔除服务的时间间隔,单位:毫秒

五、Ribbon

1、Ribbon概述


Ribbon是 Netflixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中,Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的列表信息,并基于内置的负载均衡算法请求服务。

2、Ribbon主要作用

2.1、服务调用


基于Ribbon实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助RestTemplate 最终进行调用。

(1)在创建RestTemplate方法上添加 @LoadBalanced 注解。

package com.etc.eurekaclientgoods.config;

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

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

(2)使用RestTemplate调用远程服务,不需要拼接微服务的url,以待请求的服务名替换ip地址。

package com.etc.eurekaclientgoods.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
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 RestTemplate restTemplate;

    @GetMapping("/restuser/{userid}")
    public String listuser(@PathVariable Long userid){
        return restTemplate.getForObject("http://eureka-microservice-users/user/"+userid,String.class);
    }
}

在这里插入图片描述

2.2、负载均衡


当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址。

服务端负载均衡:先发送请求到负载均衡服务器或者软件,然后通过负载均衡算法,在多个服务器之间选择一个进行访问。即在服务器端再进行负载均衡算法分配。

客户端负载均衡:客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡。即在客户端就进行负载均衡算法分配。

Ribbon是一个典型的客户端负载均衡器,Ribbon会获取服务所有的地址,根据内部的负载均衡算法获取本次请求的有效路径。

package com.etc.eurekaclientuser.controller;

import com.etc.eurekamicroserviceusers.entity.User;
import com.etc.eurekamicroserviceusers.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

@RestController
public class UserController {
    @Autowired
    private UserService userService;

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

    @Value("${spring.cloud.client.ip-address}")
    private String ip;

    @GetMapping("/user/{userid}")
    public User listuser(@PathVariable Long userid){
        User user = userService.getUserById(userid);
        user.setUsername("访问的服务地址"+ip + ":" + port);
        return user;
    }
}
  • application.yml
server:
  port: 8000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7890/eureka
  instance:
    prefer-ip-address: true
    #向注册中心注册服务id
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
#    #设置发送心跳续约间隔(默认30秒)
#    lease-renewal-interval-in-seconds: 3
#    #设置eureka client发送心跳给server端后,续约到期时间(默认90秒)
#    lease-expiration-duration-in-seconds: 6
spring:
  application:
    name: eureka-microservice-users
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/zmall?serverTimezone=Asia/Shanghai
    username: root
    password: root
mybatis:
  mapper-locations: classpath:/mapper/*.xml
logging:
  level:
    com.etc.eurekauserclient.mapper: debug
  pattern:
    console: '%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n'

  • application.yml
server:
  port: 9000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7890/eureka
  instance:
    prefer-ip-address: true
    #向注册中心注册服务id
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
#    #设置发送心跳续约间隔(默认30秒)
#    lease-renewal-interval-in-seconds: 3
#    #设置eureka client发送心跳给server端后,续约到期时间(默认90秒)
#    lease-expiration-duration-in-seconds: 6
spring:
  application:
    name: eureka-microservice-users
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/zmall?serverTimezone=Asia/Shanghai
    username: root
    password: root
mybatis:
  mapper-locations: classpath:/mapper/*.xml
logging:
  level:
    com.etc.eurekauserclient.mapper: debug
  pattern:
    console: '%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n'

在MyConfiguration的restTemplate方法上使用@LoadBalanced注解,开启了Ribbon的负载均衡,默认采用的是轮询方式,分别使用以上两种配置文件启动两次服务器验证效果,并查看两个访问结果,发现以轮询的方式调用了用户服务。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
负载均衡策略

Ribbon内置了多种负载均衡策略,内部负责负载均衡的顶级接口为com.netflix.loadbalancer.IRule,实现方式如下:

com.netflix.loadbalancer.RoundRobinRule :以轮询的方式进行负载均衡。
com.netflix.loadbalancer.RandomRule :随机策略
com.netflix.loadbalancer.RetryRule :重试策略。
com.netflix.loadbalancer.WeightedResponseTimeRule :权重策略。会计算每个服务的权
重,越高的被调用的可能性越大。
com.netflix.loadbalancer.BestAvailableRule :最佳策略。遍历所有的服务实例,过滤掉
故障实例,并返回请求数最小的实例返回。
com.netflix.loadbalancer.AvailabilityFilteringRule :可用过滤策略。过滤掉故障和请
求数超过阈值的服务实例,再从剩下的实例中轮询调用。

在服务消费者的application.yml配置文件中修改负载均衡策略:

  • application.yml
eureka-goods-client: ##eureka-goods-client是需要调用的微服务名称
	ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

策略选择:
1、如果每个机器配置一样,则建议不修改策略 (推荐)。
2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule。

2.3、重试机制


当请求一个微服务超过设置的连接超时时间,就会切换到另一个有相同功能的微服务中去访问。

(1)在服务消费者中引入spring的重试组件。

<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>

(2)在服务消费者中对Ribbon进行重试配置。

eureka-goods-client: ##eureka-goods-client是需要调用的微服务名称
	ribbon:
		ConnectTimeout: 250 # Ribbon的连接超时时间
		ReadTimeout: 1000 # Ribbon的数据读取超时时间
		OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
		MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
		MaxAutoRetries: 1 # 对当前实例的重试次数

六、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的注解。Spring Cloud Feign使用非常简单,先创建一个接口,并在接口上添加一些注解,代码就完成了。

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

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

2、Feign和Ribbon的联系


Ribbon是一个基于 HTTP 和 TCP 客户端 的负载均衡的工具。它可以在客户端配置RibbonServerList(服务端列表),使用 HttpClient 或 RestTemplate 模拟http请求,步骤相当繁琐。

Feign 是在 Ribbon 的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的
方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方
法即可, 不需要自己构建http请求。然后就像是调用自身工程的方法调用,而感觉不到是调用远程方
法,使得编写客户端变得非常容易。

3、微服务加入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文件中添加openfeign依赖。

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

2.配置调用接口
创建一个Feign接口,此接口是在Feign中调用微服务的核心接口。

在服务消费者中添加一个UserFeginClient接口,并添加一个@FeignClient的注解。@FeignClient注解通过name指定需要调用的微服务的名称用于创建Ribbon的负载均衡器,所以Ribbon会把 eureka-user-client 解析为注册中心的服务。

定义各参数绑定时,@PathVariable、@RequestParam、@RequestHeader等可以指定参数属性,在Feign中绑定参数必须通过value属性来指明具体的参数名,不然会抛出异常。

  • UserFeignClient.java
//指定需要调用的微服务名称
@FeignClient("eureka-user-client")
public interface UserFeginClient {
    //调用的请求路径
    @RequestMapping(value="/user/{userid}", method = RequestMethod.GET)
    public User listuser(@PathVariable Long userid);
}

3.通过自动的接口调用远程微服务
修改RestUserController,添加UserFeginClient的自动注入,并在listuser方法中使用
UserFeginClient完成微服务的调用(这样就可以不使用RestTemplate来发送Http请求去调用其他微服务)。

  • 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;

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

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

4.在服务消费者的启动类上激活feign

  • 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 // 激活Feign
public class EurekaclientGoodsOpenfeignApplication {

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

}

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

在这里插入图片描述

4、Feign的配置


从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的FeignClient(例如该Feign Client的名称为feignName ),Feign支持如下配置项:

feign:
    client:
        config:
            feignName: ##定义FeginClient的名称
                connectTimeout: 5000 # 相当于Request.Options
                readTimeout: 5000 # 相当于Request.Options
                # 配置Feign的日志级别,相当于代码配置方式中的Logger
                loggerLevel: full
                # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
                errorDecoder: com.example.SimpleErrorDecoder
                # 配置重试,相当于代码配置方式中的Retryer
                retryer: com.example.SimpleRetryer
                # 配置拦截器,相当于代码配置方式中的RequestInterceptor
                requestInterceptors:
                    - com.example.FooRequestInterceptor
                    - com.example.BarRequestInterceptor
                decode404: false

feignName:FeginClient的名称
connectTimeout : 建立链接的超时时长
readTimeout : 读取超时时长
loggerLevel: Fegin的日志级别
errorDecoder :Feign的错误解码器
retryer : 配置重试
requestInterceptors : 添加请求拦截器
decode404 : 配置熔断不处理404异常

5、Ribbon负载均衡器


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

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

在 Spring Cloud中可以单独配置Ribbon,也可以配置Feign(在Feign中默认就支持Ribbon)。因为Feign中本身已经集成了Ribbon依赖和自动配置,所以也是客户端的负载均衡,因此不需要额外引入依赖,也不需要再注册 RestTemplate 对象,可以像前面那样去配置Ribbon,可以通过 ribbon.xx 来进行全局配置,也可以通过 服务名.ribbon.xx 来对指定服务配置。启动两个服务提供者 ,重新测试可以发现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语句,说明实现了负载均衡。

在这里插入图片描述

6、请求与响应的压缩


Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能。

feign:
    compression:
        request:
        	enabled: true # 开启请求压缩
        response:
        	enabled: true # 开启响应压缩

也可以对请求的数据类型以及触发压缩的大小下限进行设置。

feign:
    compression:
        request:
            enabled: true # 开启请求压缩
            mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
            min-request-size: 2048 # 设置触发压缩的大小下限

上面的数据类型、压缩大小下限均为默认值。

7、Feign的日志管理


在开发或者运行阶段往往希望看到Feign请求过程的日志记录,默认情况下Feign的日志是没有开启的。要想用属性配置方式来达到日志效果,只需在application.yml 中添加配置内容。

# 配置feign日志的输出
feign:
  client:
    config:
      eureka-user-client: # 指定需要调用的微服务名称
        loggerLevel: FULL
logging:
  level:
    com.etc.eurekaclientgoods.feign.UserFeignClient: debug # 接口所在的位置

logging.level.xx : debug : Feign日志只会对日志级别为debug的做出响应。

Feign的日志处理非常灵活,我们可以为每个客户端设置日志记录策略,为每个客户端可以创建一个Logger,为每个客户端配置各自的Logger.level对象,从而告知Feign记录哪些日志,Logger.Level的值有以下选择。

Logger.Level的值意义
NONE(性能最佳,适用于生产)不记录任何日志(默认)
BASIC(适用于生产环境追踪问题)仅记录请求方法,url,响应状态代码和执行时间
HEADERS在记录BASIC级别的基础上,记录请求和响应的header
FULL(比较适用于开发及测试环境定位问题)记录请求和响应的header,body和元数据

实现步骤:

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

# 配置feign日志的输出
feign:
  client:
    config:
      eureka-users-client: # 指定需要调用的微服务名称
        loggerLevel: FULL
logging:
  level:
    com.etc.eurekaclientgoods.feign.UserFeignClient: debug # 接口所在的位置

(2)访问地址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,成功读取配置中心的内容。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值