Spring Cloud微服务框架相关

目录

介绍

spring cloud 技术组成

Spring Cloud 对比 Dubbo

Spring MVC 接收参数的几个注解

 eureka 注册与发现

依赖

 配置文件

注解       @EnableEurekaServer

修改 hosts 文件,添加 eureka 域名映射

服务注册到eureka服务器

依赖

主程序启用服务注册发现客户端

eureka 高可用

配置文件

配置启动参数 --spring.profiles.active 和 --server.port

eureka客户端注册时,向多个服务器注册

ribbon服务消费者

依赖

RestTemplate

ribbon 负载均衡和重试

 Ribbon 负载均衡

RestTemplate 设置 @LoadBalanced

访问路径设置为服务id

ribbon 重试

 依赖

配置文件

主程序设置 RestTemplate 的请求工厂的超时属性

Hystrix 断路器

 微服务宕机时,ribbon 无法转发请求

依赖

配置文件

主程序添加 @EnableCircuitBreaker 启用 hystrix 断路器

@SpringCloudApplication 

RibbonController 中添加降级方法

注解

hystrix 超时设置

hystrix dashboard 断路器仪表盘

添加 actuator,并暴露 hystrix 监控端点

添加依赖

修改配置文件

Hystrix dashboard 仪表盘

 依赖

配置文件

主程序添加 @EnableHystrixDashboard 和 @EnableDiscoveryClient

访问 hystrix dashboard

 填入 hystrix 的监控端点,开启监控

 hystrix 熔断

使用 apache 的并发访问测试工具 ab

 hystrix 配置

feign 声明式客户端接口

 依赖

 配置文件

主程序添加 @EnableDiscoveryClient 和 @EnableFeignClients

feign 声明式客户端

注解  @FeignClient

调用流程

 feign + ribbon 负载均衡和重试

application.yml 配置 ribbon 超时和重试

feign + hystrix 降级

feign 启用 hystrix

可以添加配置,暂时减小降级超时时间,以便后续对降级进行测试

feign 远程接口中指定降级类

降级类

feign + hystrix 监控和熔断测试

添加 hystrix 起步依赖

主程序添加 @EnableCircuitBreaker

配置 actuator,暴露 hystrix.stream 监控端点

actuator 依赖

application.yml 暴露 hystrix.stream 端点

熔断测试

 hystrix + turbine 集群聚合监控

依赖

 配置文件

主程序

zuul API网关

依赖

 配置文件

主程序

zuul + ribbon 负载均衡

zuul + ribbon 重试

pom.xml 添加 spring-retry 依赖

配置 zuul 开启重试,并配置 ribbon 重试参数

zuul + hystrix 降级

修改配置降低 hystrix 超时时间,以便测试降级

zuul + hystrix 数据监控

暴露 hystrix.stream 监控端点

开启监控

zuul + turbine 聚合监控

 熔断测试

 zuul 请求过滤

 定义过滤器,继承 ZuulFilter

zuul Cookie过滤

config 配置中心

github 上存放配置文件

禁止配置中心的配置信息覆盖客户端配置

将 config 项目上传到 github

config 服务器

依赖

 配置文件

主程序添加 @EnableConfigServer 和 @EnableDiscoveryClient

从配置中心获取配置信息的服务添加 config 客户端依赖

添加 bootstrap.yml

配置刷新

yml 配置文件中暴露 refresh 端点

UserServiceImpl 添加 @RefreshScope 注解

config bus + rabbitmq 消息总线配置刷新

需要动态更新配置的微服务,添加 spring cloud bus 依赖,并添加 rabbitmq 连接信息

依赖

配置文件中添加 rabbitmq 连接信息

config-server 暴露 bus-refresh 刷新端点

config 本地文件系统

把配置文件保存到 sp12-config 项目的 resources/config 目录下

修改 application.yml 激活 native profile,并指定配置文件目录

sleuth 链路跟踪

微服务中添加 spring cloud sleuth 依赖

在控制台查看链路跟踪日志

sleuth + zipkin 链路分析

链路数据抽样比例

zipkin 服务

下载 zipkin 服务器

 启动 zipkin 时,连接到 rabbitmq

 http://localhost:9411/zipkin​

微服务添加 zipkin 起步依赖

启动并访问服务,访问 zipkin 查看链路分析

 向eureka注册正确的ip地址

选择正确网卡

注册ip地址,而不是主机名


介绍

spring cloud 是一系列框架的集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。spring cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 spring boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

spring cloud 技术组成

Spring Cloud

eureka
微服务治理,服务注册和发现

ribbon
负载均衡、请求重试

hystrix
断路器,服务降级、熔断

feign
ribbon + hystrix 集成,并提供声明式客户端

hystrix dashboard 和 turbine
hystrix 数据监控

zuul
API 网关,提供微服务的统一入口,并提供统一的权限验证

config
配置中心

bus
消息总线, 配置刷新

sleuth+zipkin
链路跟踪

Spring Cloud 对比 Dubbo

Spring Cloud对比Dubbo

  • Dubbo

    • Dubbo只是一个远程调用(RPC)框架
    • 默认基于长连接,支持多种序列化格式
  • Spring Cloud

    • 框架集
    • 提供了一整套微服务解决方案(全家桶)
    • 基于http调用, Rest API

Spring MVC 接收参数的几个注解

接收参数

 eureka 注册与发现

依赖

<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

添加依赖

 配置文件

spring:
  application:
    name: eureka-server
    
server:
  port: 2001
  
eureka:
  server:
    enable-self-preservation: false
  instance:
    hostname: eureka1
  client:
    register-with-eureka: false
    fetch-registry: false
  

eureka 集群服务器之间,通过 hostname 来区分

eureka.server.enable-self-preservation

eureka 的自我保护状态:心跳失败的比例,在15分钟内是否超过85%,如果出现了超过的情况,Eureka Server会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。也就是不会注销任何微服务

eureka.client.register-with-eureka=false

不向自身注册

eureka.client.fetch-registry=false

不从自身拉取注册信息

eureka.instance.lease-expiration-duration-in-seconds

最后一次心跳后,间隔多久认定微服务不可用,默认90

注解       @EnableEurekaServer

主启动类上添加@EnableEurekaServer注解

修改 hosts 文件,添加 eureka 域名映射

C:\Windows\System32\drivers\etc\hosts

127.0.0.1       eureka1
127.0.0.1       eureka2

服务注册到eureka服务器

依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

配置文件

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka

eureka.instance.lease-renewal-interval-in-seconds
心跳间隔时间,默认 30 秒

defaultZone,默认位置,可以修改为具体地理位置,比如:beiJing, shangHai, shenZhen 等,表示 eureka 服务器的部署位置, 需要云服务器提供

eureka.client.registry-fetch-interval-seconds
拉取注册信息间隔时间,默认 30 秒

主程序启用服务注册发现客户端

主程序添加 @EnableDiscoveryClient 注解

eureka 高可用

配置文件

eureka:
  instance:
    hostname: eureka1
  client:
    register-with-eureka: true  #profile的配置会覆盖公用配置
    fetch-registry: true        #profile的配置会覆盖公用配置
    service-url: 
      defaultZone: http://eureka2:2002/eureka  #eureka1启动时向eureka2注册





eureka:
  instance:
    hostname: eureka2
  client:
    register-with-eureka: true  #profile的配置会覆盖公用配置
    fetch-registry: true        #profile的配置会覆盖公用配置
    service-url: 
      defaultZone: http://eureka1:2001/eureka  #eureka2启动时向eureka1注册

配置启动参数 --spring.profiles.active 和 --server.port

--spring.profiles.active=eureka1 --server.port=2001





--spring.profiles.active=eureka2 --server.port=2002

启动参数

eureka客户端注册时,向多个服务器注册

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

当一个 eureka 服务宕机时,仍可以连接另一个 eureka 服务

ribbon服务消费者

ribbon 提供了负载均衡和重试功能, 它底层是使用 RestTemplate 进行 Rest api 调用

依赖

  • eureka-client 中已经包含 ribbon 依赖

RestTemplate

RestTemplate 是SpringBoot提供的一个Rest远程调用工具

它的常用方法:

  • getForObject() - 执行get请求
  • postForObject() - 执行post请求

创建 RestTemplate 实例

//创建 RestTemplate 实例,并存入 spring 容器
	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}

ribbon 负载均衡和重试

Ribbon

 Ribbon 负载均衡

负载均衡

 添加 ribbon 起步依赖(可选)

  • eureka 依赖中已经包含了 ribbon

RestTemplate 设置 @LoadBalanced

@LoadBalanced 负载均衡注解,会对 RestTemplate 实例进行封装,创建动态代理对象,并切入(AOP)负载均衡代码,把请求分发到集群中的服务器

@LoadBalanced //负载均衡注解
	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}

访问路径设置为服务id

@GetMapping("/item-service/{orderId}")
	public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
	    //这里服务器路径用 service-id 代替,ribbon 会向服务的多台集群服务器分发请求
		return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
	}

ribbon 重试

重试

 依赖

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

配置文件

spring:
  application:
    name: ribbon
    
server:
  port: 3001
  
eureka:
  client:    
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetriesNextServer: 2
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true

ConnectionTimeout
ReadTimeout
OkToRetryOnAllOperations=true
默认只对GET请求重试, 当设置为true时, 对POST等所有类型请求都重试
MaxAutoRetriesNextServer
更换实例的次数
MaxAutoRetries
当前实例重试次数,尝试失败会更换下一个实例

主程序设置 RestTemplate 的请求工厂的超时属性

@LoadBalanced
	@Bean
	public RestTemplate getRestTemplate() {
		SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
		f.setConnectTimeout(1000);
		f.setReadTimeout(1000);
		return new RestTemplate(f);
		
		//RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,
		//未启用超时,也不会触发重试
		//return new RestTemplate();
	}

通过 ribbon 访问 service,当超时,ribbon 会重试请求集群中其他服务器

ribbon的重试机制,在 feign 和 zuul 中进一步进行了封装,后续可以使用feign或zuul的重试机制

Hystrix 断路器

Hystrix

 微服务宕机时,ribbon 无法转发请求

依赖

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

配置文件


spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:    
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetries: 1
  MaxAutoRetriesNextServer: 2
  OkToRetryOnAllOperations: true

主程序添加 @EnableCircuitBreaker 启用 hystrix 断路器

启动断路器,断路器提供两个核心功能:

  • 降级,超时、出错、不可到达时,对服务降级,返回错误信息或者是缓存数据

  • 熔断,当服务压力过大,错误比例过多时,熔断所有请求,所有请求直接降级

@SpringCloudApplication 

可以使用 @SpringCloudApplication 注解代替三个注解

RibbonController 中添加降级方法

注解

添加 @HystrixCommand 注解,指定降级方法名

    @GetMapping("/item-service/{orderId}")
	@HystrixCommand(fallbackMethod = "getItemsFB") //指定降级方法的方法名
	public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
		return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
	}

hystrix 超时设置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds

hystrix等待超时后, 会执行降级代码, 快速向客户端返回降级结果, 默认超时时间是1000毫秒

为了测试 hystrix 降级,我们把 hystrix 等待超时设置得非常小(500毫秒)

spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetriesNextServer: 2
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500
            

hystrix dashboard 断路器仪表盘

dashboard

 hystrix 对请求的降级和熔断,可以产生监控信息,hystrix dashboard可以实时的进行监控

添加 actuator,并暴露 hystrix 监控端点

actuator 是 spring boot 提供的服务监控工具,提供了各种监控信息的监控端点

management.endpoints.web.exposure.include 配置选项,
可以指定端点名,来暴露监控端点

如果要暴露所有端点,可以用 “*”

Actuator

添加依赖

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

修改配置文件

spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

Hystrix dashboard 仪表盘

dashboard

 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.tedu</groupId>
	<artifactId>sp08-hystrix-dashboard</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>sp08-hystrix-dashboard</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
	</properties>

	<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-hystrix-dashboard</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

配置文件

spring:
  application:
    name: hystrix-dashboard
    
server:
  port: 4001

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

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

主程序添加 @EnableHystrixDashboard 和 @EnableDiscoveryClient

@EnableDiscoveryClient
@EnableHystrixDashboard
@SpringBootApplication
public class Sp08HystrixDashboardApplication {
	public static void main(String[] args) {
		SpringApplication.run(Sp08HystrixDashboardApplication.class, args);
	}
}

访问 hystrix dashboard

dashboard

 填入 hystrix 的监控端点,开启监控

开启监控

 通过 hystrix 访问服务多次,观察监控信息

监控界面

 监控界面

 hystrix 熔断

整个链路达到一定的阈值,默认情况下,10秒内产生超过20次请求,则符合第一个条件。
满足第一个条件的情况下,如果请求的错误百分比大于阈值,则会打开断路器,默认为50%。
Hystrix的逻辑,先判断是否满足第一个条件,再判断第二个条件,如果两个条件都满足,则会开启断路器

断路器打开 5 秒后,会处于半开状态,会尝试转发请求,如果仍然失败,保持打开状态,如果成功,则关闭断路器

使用 apache 的并发访问测试工具 ab

http://httpd.apache.org/docs/current/platform/windows.html#downhttp://httpd.apache.org/docs/current/platform/windows.html#down下载Apache

 用 ab 工具,以并发50次,来发送20000个请求

ab -n 20000 -c 50 http://localhost:3001/item-service/35

断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法

熔断

 hystrix 配置

Configuration · Netflix/Hystrix Wiki · GitHubhttps://github.com/Netflix/Hystrix/wiki/Configuration

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
请求超时时间,超时后触发失败降级

hystrix.command.default.circuitBreaker.requestVolumeThreshold
10秒内请求数量,默认20,如果没有达到该数量,即使请求全部失败,也不会触发断路器打开

hystrix.command.default.circuitBreaker.errorThresholdPercentage
失败请求百分比,达到该比例则触发断路器打开

hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
断路器打开多长时间后,再次允许尝试访问(半开),仍失败则继续保持打开状态,如成功访问则关闭断路器,默认 5000

feign 声明式客户端接口

微服务应用中,ribbon 和 hystrix 总是同时出现,feign 整合了两者,并提供了声明式消费者客户端

用 feign 代替 hystrix+ribbon

feign

 依赖

在这里插入图片描述

 配置文件

spring:
  application:
    name: feign
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

主程序添加 @EnableDiscoveryClient 和 @EnableFeignClients

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
	public static void main(String[] args) {
		SpringApplication.run(Sp09FeignApplication.class, args);
	}
}

feign 声明式客户端

feign 利用了我们熟悉的 spring mvc 注解来对接口方法进行设置,降低了我们的学习成本。
通过这些设置,feign可以拼接后台服务的访问路径和提交的参数

例如

@GetMapping("/{userId}/score") 
JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);

当这样调用该方法:

service.addScore(7, 100);

那么 feign 会向服务器发送请求:

http://用户微服务/7/score?score=100

注意:如果 score 参数名与变量名不同,需要添加参数名设置

@GetMapping("/{userId}/score") 
JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s);

注解  @FeignClient

package cn.tedu.sp09.service;

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

import cn.tedu.sp01.pojo.User;
import cn.tedu.web.util.JsonResult;

@FeignClient("user-service")
public interface UserFeignService {
	@GetMapping("/{userId}")
	JsonResult<User> getUser(@PathVariable Integer userId);

    // 拼接路径 /{userId}/score?score=新增积分
	@GetMapping("/{userId}/score") 
	JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);
}

注意,如果请求参数名与方法参数名不同,@RequestParam不能省略,并且要指定请求参数名:
@RequestParam("score") Integer s

调用流程

流程

 feign + ribbon 负载均衡和重试

无需额外配置,feign 默认已启用了 ribbon 负载均衡和重试机制。可以通过配置对参数进行调整

重试的默认配置参数:

ConnectTimeout=1000
ReadTimeout=1000
MaxAutoRetries=0
MaxAutoRetriesNextServer=1

application.yml 配置 ribbon 超时和重试

  • ribbon.xxx 全局配置
  • item-service.ribbon.xxx 对特定服务实例的配置
spring:
  application:
    name: feign
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 1000
  
item-service:
  ribbon:
    MaxAutoRetries: 1
    MaxAutoRetriesNextServer: 2
    ConnectTimeout: 1000
    ReadTimeout: 500

feign + hystrix 降级

feign 启用 hystrix

feign 默认没有启用 hystrix,添加配置,启用 hystrix

feign.hystrix.enabled=true

feign:
  hystrix:
    enabled: true

默认1秒会快速失败,没有降级方法时,会显示白板页

可以添加配置,暂时减小降级超时时间,以便后续对降级进行测试

......

feign:
  hystrix:
    enabled: true
    
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500



feign 远程接口中指定降级类

远程调用失败, 会执行降级类中的代码.例如

...
@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)
public interface ItemFeignService {
...

降级类

降级类需要实现远程接口

@Component
public class ItemFeignServiceFB implements ItemFeignService {

feign + hystrix 监控和熔断测试

监控

添加 hystrix 起步依赖

feign 没有包含完整的 hystrix 依赖

编辑起步依赖,添加hystrix依赖

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

主程序添加 @EnableCircuitBreaker

@EnableCircuitBreaker
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
	public static void main(String[] args) {
		SpringApplication.run(Sp09FeignApplication.class, args);
	}
}

配置 actuator,暴露 hystrix.stream 监控端点

actuator 依赖

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

application.yml 暴露 hystrix.stream 端点

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

启动 hystrix dashboard 服务,填入 feign 监控路径,开启监控

熔断测试

用 ab 工具,以并发50次,来发送20000个请求

ab -n 20000 -c 50 http://localhost:3001/item-service/35

断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法

压力测试

 hystrix + turbine 集群聚合监控

turbine

 hystrix dashboard 一次只能监控一个服务实例,使用 turbine 可以汇集监控信息,将聚合后的信息提供给 hystrix dashboard 来集中展示和监控

依赖

选择依赖

 配置文件

spring:
  application:
    name: turbin
    
server:
  port: 5001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
turbine:
  app-config: order-service
  cluster-name-expression: new String("default")

主程序

添加 @EnableTurbine 和 @EnableDiscoveryClient 注解

zuul API网关

zuul

 zuul API 网关,为微服务应用提供统一的对外访问接口。
zuul 还提供过滤器,对所有微服务提供统一的请求校验。

依赖

添加依赖

 配置文件

zuul 路由配置可以省略,缺省以服务 id 作为访问路径

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  routes:
    item-service: /item-service/**
    user-service: /user-service/**
    order-service: /order-service/**

主程序

添加 @EnableZuulProxy 和 @EnableDiscoveryClient 注解

zuul + ribbon 负载均衡

zuul 已经集成了 ribbon,默认已经实现了负载均衡

zuul + ribbon 重试



pom.xml 添加 spring-retry 依赖

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

配置 zuul 开启重试,并配置 ribbon 重试参数

需要开启重试,默认不开启

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  retryable: true

#  routes:
#    item-service: /item-service/**
#    user-service: /user-service/**
#    order-service: /order-service/**
    
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 1000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1

zuul + hystrix 降级

getRoute() 方法中指定应用此降级类的服务id,星号或null值可以通配所有服务

例如

package cn.tedu.sp11.fallback;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import cn.tedu.web.util.JsonResult;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class ItemServiceFallback implements FallbackProvider {
	@Override
	public String getRoute() {
	    //当执行item-service失败,
	    //应用当前这个降级类
		return "item-service";
		//星号和null都表示所有微服务失败都应用当前降级类
		//"*"; //null;
	}

    //该方法返回封装降级响应的对象
    //ClientHttpResponse中封装降级响应
	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return response();
	}

	private ClientHttpResponse response() {
        return new ClientHttpResponse() {
            //下面三个方法都是协议号
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {
            }

            @Override
            public InputStream getBody() throws IOException {
            	log.info("fallback body");
            	String s = JsonResult.err().msg("后台服务错误").toString();
                return new ByteArrayInputStream(s.getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

修改配置降低 hystrix 超时时间,以便测试降级

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  retryable: true
    
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500

zuul + hystrix 数据监控



暴露 hystrix.stream 监控端点

zuul 已经包含 actuator 依赖

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

开启监控

启动 shystrix-dashboard,填入 zuul 的监控端点路径,开启监控

监控

 必须通过zuul网关访问后台服务才会长生监控数据

zuul + turbine 聚合监控

修改 turbine 项目,聚合 zuul 服务实例

配置文件修改


spring:
  application:
    name: turbin
    
server:
  port: 5001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
turbine:
  app-config: order-service, zuul
  cluster-name-expression: new String("default")

使用hystrix仪表盘, 对 turbine 监控端点进行监控, 此端点聚合了订单服务和zull网关服务的监控数据

监控

 熔断测试

ab -n 20000 -c 50 http://localhost:3001/order-service/123abc

熔断

 zuul 请求过滤

zuul过滤器

 定义过滤器,继承 ZuulFilter

package cn.tedu.sp11.filter;

import javax.servlet.http.HttpServletRequest;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import cn.tedu.web.util.JsonResult;

@Component
public class AccessFilter extends ZuulFilter{
	@Override
	public boolean shouldFilter() {
	    //对指定的serviceid过滤,如果要过滤所有服务,直接返回 true
	    
		RequestContext ctx = RequestContext.getCurrentContext();
		String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
		if(serviceId.equals("item-service")) {
			return true;
		}
		return false;
	}

	@Override
	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest req = ctx.getRequest();
		String token = req.getParameter("token");
		if (token == null) {
			//此设置会阻止请求被路由到后台微服务
			ctx.setSendZuulResponse(false);
			//向客户端的响应
			ctx.setResponseStatusCode(200);
			ctx.setResponseBody(JsonResult.err().code(JsonResult.NOT_LOGIN).toString());
		}
		//zuul过滤器返回的数据设计为以后扩展使用,
		//目前该返回值没有被使用
		return null;
	}

	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

	@Override
	public int filterOrder() {
	    //该过滤器顺序要 > 5,才能得到 serviceid
		return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
	}
}

zuul Cookie过滤

zuul 会过滤敏感 http 协议头,默认过滤以下协议头:

  • Cookie
  • Set-Cookie
  • Authorization

可以设置 zuul 不过滤这些协议头

zuul:
  sensitive-headers: 

config 配置中心

配置中心

yml 配置文件保存到 git 服务器,例如 github.com 或 gitee.com

微服务启动时,从服务器获取配置文件

github 上存放配置文件

禁止配置中心的配置信息覆盖客户端配置

默认配置中心配置优先级高,配置中心配置会覆盖客户端的所有配置,包括命令行参数配置,这样我们在item-service和order-service中配置的端口号启动参数会无效.我们可以设置禁止配置中心的配置将客户端配置覆盖掉.在配置文件中添加下面的配置

spring:
  ......
  cloud:
    config:
      override-none: true

将 config 项目上传到 github

config 服务器

config 配置中心从 git 下载所有配置文件。

而其他微服务启动时从 config 配置中心获取配置信息。

依赖

选择依赖

 配置文件

spring:
  application:
    name: config-server
  
  cloud:
    config:
      server:
        git:
          uri: https://github.com/你的个人路径/sp-config
          searchPaths: config
          #username: your-username
          #password: your-password
    
server:
  port: 6001
    
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

主程序添加 @EnableConfigServer 和 @EnableDiscoveryClient

从配置中心获取配置信息的服务添加 config 客户端依赖

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

添加 bootstrap.yml

bootstrap.yml,引导配置文件,先于 application.yml 加载

spring: 
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      name: item-service
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

配置刷新

spring cloud 允许运行时动态刷新配置,可以重新从配置中心获取新的配置信息

以 user-service 为例演示配置刷新

user-service 的 pom.xml 中添加 actuator 依赖

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

yml 配置文件中暴露 refresh 端点

修改 config 项目中的 user-service-dev.yml,并提交推送到远程仓库

sp:
  user-service:
    users: "[{\"id\":7, \"username\":\"abc\",\"password\":\"123\"},{\"id\":8, \"username\":\"def\",\"password\":\"456\"},{\"id\":9, \"username\":\"ghi\",\"password\":\"789\"}]"

spring:
  application:
    name: user-service
  cloud:
    config:
      override-none: true
    
server:
  port: 8101
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka  

management:
  endpoints:
    web:
      exposure:
        include: refresh

UserServiceImpl 添加 @RefreshScope 注解

只允许对添加了 @RefreshScope  @ConfigurationProperties 注解的 Bean 刷新配置,可以将更新的配置数据注入到 Bean 中

config bus + rabbitmq 消息总线配置刷新

bus

 post 请求消息总线刷新端点,服务器会向 rabbitmq 发布刷新消息,接收到消息的微服务会向配置服务器请求刷新配置信息

需要动态更新配置的微服务,添加 spring cloud bus 依赖,并添加 rabbitmq 连接信息

依赖

 busrabbitmq

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</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>
		<dependency>
			<groupId>org.springframework.amqp</groupId>
			<artifactId>spring-rabbit-test</artifactId>
			<scope>test</scope>
		</dependency>

配置文件中添加 rabbitmq 连接信息

  • 连接信息请修改成你的连接信息
  • config项目需要提交
spring:
  ......
  rabbitmq:
    host: 192.168.64.140
    port: 5672
    username: admin
    password: admin

config-server 暴露 bus-refresh 刷新端点

修改 sp12-config 项目的 application.yml, 暴露bus-refresh端点

management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

config 本地文件系统

可以把配置文件保存在配置中心服务的 resources 目录下,直接访问本地文件

把配置文件保存到 sp12-config 项目的 resources/config 目录下

修改 application.yml 激活 native profile,并指定配置文件目录

必须配置 spring.profiles.active=native 来激活本地文件系统

本地路径默认[classpath:/, classpath:/config, file:./, file:./config]

spring:
  application:
    name: config-server
  profiles:
    active: native
  
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/config

#        git:
#          uri: https://github.com/你的用户路径/sp-config
#          searchPaths: config
#          username: your-username
#          password: your-password
        
    
  rabbitmq:
    host: 192.168.64.140
    port: 5672
    username: admin
    password: admin

    
server:
  port: 6001
    
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

sleuth 链路跟踪

随着系统规模越来越大,微服务之间调用关系变得错综复杂,一条调用链路中可能调用多个微服务,任何一个微服务不可用都可能造整个调用过程失败

spring cloud sleuth 可以跟踪调用链路,分析链路中每个节点的执行情况

微服务中添加 spring cloud sleuth 依赖

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

在控制台查看链路跟踪日志

通过 zuul 网关,访问 service

微服务的控制台日志中,可以看到以下信息:
[服务id,请求id,span id,是否发送到zipkin]

  • 请求id:请求到达第一个微服务时生成一个请求id,该id在调用链路中会一直向后面的微服务传递
  • span id:链路中每一步微服务调用,都生成一个新的id

sleuth + zipkin 链路分析

zipkin 可以收集链路跟踪数据,提供可视化的链路分析

链路数据抽样比例

默认 10% 的链路数据会被发送到 zipkin 服务。可以配置修改抽样比例

spring:
  sleuth:
    sampler:
      probability: 0.1

zipkin 服务

下载 zipkin 服务器

https://github.com/openzipkin/zipkinhttps://github.com/openzipkin/zipkin

下载zipkin

 启动 zipkin 时,连接到 rabbitmq

java -jar zipkin-server-2.12.9-exec.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.140:5672

启动

 http://localhost:9411/zipkinzipkin

微服务添加 zipkin 起步依赖

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

如果没有配置过 spring cloud bus,还需要添加 rabbitmq 依赖和连接信息

启动并访问服务,访问 zipkin 查看链路分析

  • 刷新访问多次,链路跟踪数据中,默认只有 10% 会被收集到zipkin

  • 访问 zipkin

zipkin

 zipkin

 zipkin

 向eureka注册正确的ip地址

eureka客户端向eureka注册时, 会自动选择网卡, 并可能注册主机名而不是ip地址.

下面配置可以选择正确网卡的ip向eureka进行注册.

选择正确网卡

服务器有多块网卡,要选择正确网卡的ip地址向eureka进行注册

修改 bootstrap.yml

spring:
  cloud:
    inetutils:
      ignored-interfaces: # 忽略的网卡
        - VM.*
      preferred-networks: # 要是用的网卡的网段
        - 192\.168\.0\..+

注册ip地址,而不是主机名

注册时,有可能自动选择主机名进行注册,而不使用ip地址. 主机名在局域网内有可能不会被正确的解析

最好使用ip地址进行注册,而不注册主机名

在应用配置application.yml中配置:

eureka:
  instance:
    prefer-ip-address: true # 使用ip进行注册
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} # 界面列表中显示的格式也显示ip
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud是一个基于Spring Boot微服务框架,它提供了一系列工具和组件,用于快速构建分布式系统的微服务架构。Spring提供了诸如服务注册与发现、负载均衡、断路器、分布式配置等功能,使得开发者可以更加方便地构建和管理微服务应用。 使用Spring Cloud开发微服务应用,通常需要以下步骤: 1. 创建Spring Boot项目:使用Spring Initializr或手动创建一个基于Spring Boot的项目。 2. 添加Spring Cloud依赖:在项目的pom.xml文件中添加Spring Cloud相关的依赖,如spring-cloud-starter-netflix-eureka、spring-cloud-starter-config等。 3. 配置服务注册与发现:使用Eureka、Consul等服务注册与发现组件,配置微服务的注册与发现。 4. 实现微服务:编写各个微服务的业务逻辑代码,并通过注解@EnableDiscoveryClient将微服务注册到服务注册中心。 5. 配置服务调用:使用Feign、Ribbon等组件实现微服务之间的调用和负载均衡。 6. 实现断路器:使用Hystrix等组件实现微服务的断路器功能,防止故障扩散。 7. 配置分布式配置中心:使用Spring Cloud Config等组件实现分布式配置的集中管理和动态刷新。 8. 部署与监控:将微服务部署到云端或容器中,使用Spring Cloud Sleuth、Zipkin等组件进行链路追踪和监控。 以上是使用Spring Cloud开发微服务应用的一般步骤,具体的实现细节可以参考Spring Cloud官方文档和相关教程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值