-->
侧边栏壁纸
博主头像
断钩鱼 博主等级

行动起来,活在当下

  • 累计撰写 28 篇文章
  • 累计创建 34 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

SpringCloud Netflix

halt
2020-01-13 / 0 评论 / 0 点赞 / 2138 阅读 / 0 字

Spring Cloud 对比 Dubbo

SpringCloud

  • 基于HTTP协议
  • 一个框架集
  • 提供了一整套微服务解决方案(全家桶)

Dubbo

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

Spring Cloud 技术组成

  • eureka
    微服务治理、注册与发现
  • ribbon
    负载均衡、请求重试
  • hystrix
    断路器: 服务降级、熔断
  • feign
    ribbon + hystrix 集成,并提供声明式客户端
  • hystrix dashboard 和 turbine
    hystrix 微服务监控
  • zuul
    API 网关,提供微服务的统一入口,并提供统一的权限验证
  • config
    配置中心
  • bus
    消息总线,配置刷新
  • sleuth+zipkin
    链路跟踪

Eureka

  • eureka基本特性:
    l 服务启动时,连接 eureka 服务器,把自己的地址向其他 eureka 注册
    l 如果注册失败,等30秒再重新注册,直到注册成功
    l 微服务每30秒重新从eureka拉取注册表
    l 微服务每30秒向 eureka服务器 发送一次心跳数据
    l eureka连续三次收不到心跳数据,会认为微服务挂了
    l 一个服务不可用时,eureka会进入保护模式,不删除该服务的注册信息
  • eureka 自我保护模式: 心跳失败的比例,在15分钟内微服务心跳是否低于85%,如果出现了低于的情况,Eureka Server会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。也就是不会注销任何微服务,因为可能会因为网络原因导致心跳数据丢失等情况。
    .

Eureka 客户端配置(单独项目)

  • 导入依赖 可以在创建项目时直接选择依赖即可 若没有再去pom.xml文件中添加
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  • 配置文件
eureka:
  server:
  	# 注册中心清理无效节点信息间隔 默认60000 单位 ms 即 60s
  	eviction-interval-timer-in-ms: 60000
    enable-replicated-request-compression: false # 测试环境下需要频繁启动、停止,所以关闭eureka保护模式
# 注册中心配置 客户端
 instance: 
 	# 表示eureka服务器自上一次收到注册服务的心跳超时时间 单位 s 默认90s 当超过这个时间后还是没有收到服务心跳数据则认为服务不可用 可以删除
 	lease-expiration-duration-in-seconds: 90
 	# 心跳数据发送间隔 单位 s 向注册中心发送自己的心跳证明自己服务可用
   lease-renewal-interval-in-seconds: 30 # 默认配置
 	# 服务名 唯一
   hostname: eurekaA
# 微服务端 服务提供者
 client:
    register-with-eureka: true# 是否向其他eureka注册 没有erueka集群时需要关闭 默认开启
    fetch-registry: true       # 是否拉取其他eureka注册中心注册表信息 没有erueka集群时需要关闭 默认开启
    # 向其他eureka注册中心拉取微服务注册信息间隔 单位s
    registry-fetch-interval-seconds: 30
    # 向其他 eureka 注册中心注册自身 
    service-url: 
    # defaultZone: 默认时区 若为云实例时 可设置为云服务商提供的时区 例如 beiJing shangHai shenZhen 等
    	defaultZone: http://127.0.0.1:2002/eureka,http://127.0.0.1:2003/eureka
  • Java文件配置
    在启动类上加入注解:@EnableEurekaServer
//Eureka 注解 启用 eureka 客户端
@EnableEurekaServer 
@SpringBootApplication
public class SpringBootRun {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootRun .class, args);
	}
}

Eureka微服务端配置

  • 添加依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • yml配置
eureka:
# 微服务端 服务提供者
   client:
     register-with-eureka: true # 是否向其他eureka注册 没有erueka集群时需要关闭 默认开启
     fetch-registry: true       # 是否拉取其他eureka注册中心注册表信息 没有erueka集群时需要关闭 默认开启
     # 向eureka注册中心拉取微服务注册信息间隔 单位s
     registry-fetch-interval-seconds: 30
     
     # 一般只需配置到下面内容即可 上面也是默认配置 写不写都一样 只是列举了常用配置
     # 向 eureka 注册中心注册 
     service-url: 
     # defaultZone: 默认时区 若为云实例时 可设置为云服务商提供的时区例如 beiJing shangHai shenZhen 等
     	# http://域名||ip/eureka,....多个
     	defaultZone: http://127.0.0.1:2001/eureka,http://127.0.0.1:2002/eureka,http://127.0.0.1:2003/eureka
  • Java配置
    启动类添加注解 @EurekaDiscoveryClient
//Eureka 注解 启用发现 eureka 客户端
@EurekaDiscoveryClient
@SpringBootApplication
public class SpringBootRun {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootRun .class, args);
	}
}
  • 访问 Eureka 客户端查看注册信息是否完整
    eureka面板

Eureka 和 zookeeper区别

  • eureka特点:
    • AP 结构 注重可用性
    • 集群:对等结构 每一个都可以理解为为主机 相互注册自身信息 相互拉取注册表信息
  • zookeeper特点:
    • CP 结构 注重一致性
    • 集群: 主从结构 一个主机有多个从机 从机同步主机数据

微服务调用工具

RestTemplate

  • RestTemplate 介绍:
    String Boot提供的工具,类似 HttpClient, Jsoup,是一个http远程连接,远程调用工具
  • 特点:
    不用繁杂的配置,功能比较单一,简单易用。
  • 常用方法:
    l getForObject(url, 转换的类型, 提交的参数)
    l postForObject(url, 提交的数据, 转换的类型)
  • 使用:
    写一个返回值为RestTemplate的方法 交给Spring容器管理,调用时@Autowired注入即可,需要指定名称注入时可以联合使用Spring注解@Auotwired+@Qualifier("具体接口实现类") 或者@Resource

Ribbon

配置&使用

  • hystrix 起步依赖(可选)
  • ribbon 起步依赖已经包含在了eureka依赖中可以不用添加
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

主要功能:负载均衡和重试

负载均衡

  1. 需要在交由Spring容器管理的RestTemmplate方法上标明注解 @LoadBalanced
@LoadBalanced //负载均衡注解
@Bean
public RestTemplate getRestTemplate() {
	return new RestTemplate();
}
  1. 使用RestTemmplate调用微服务时访问域名不要填写真实域名使用 微服务服务名 即 yml文件中配置的 spring.application.name: 的值
spring:
  application:
    name: user-server
@PostMapping("/item-service/login/{userInfo}")
public JsonResult login(@RequestBody List<User> userInfo) {
	// {1}为占位符
	return rt.postForObject("http://user-server/login/{1}", userInfo, JsonResult.class);
}

重试

在异常、超时等调用异常的情况下执行·

  1. 添加 retry 依赖
<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>
  1. 配置yml
ribbon:
  MaxAutoRetriesNextServer: 2
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true
  • yml 可能没有提示 有点 emm...
    ConnectionTimeout 连接超时
    ReadTimeout 读取资源超时
    上面连个参数不能在yml中配置
    MaxAutoRetriesNextServer 失败后向后请求几台服务器
    MaxAutoRetries 每台服务器请求失败向后再请求几次
    OkToRetryOnAllOperations 是否对所有请求都重试

默认false GET请求无论是连接超时还是读取超时,都会进行重试非GET方式请求,只有连接超时时,才会进行重试 慎用 当 POST 或者 PUT 等提交操作时时可能因为网络延时原因导致重试 从而进行了多次的更改数据

  • 配置超时
    在RestTemplate 交由 bean 管理方法中添加 SimpleClientHttpRequestFactory 工厂对象进行构建
@LoadBalanced //启用负载均衡 ribbon 对RestTemplate进行了增强AOP增加了 负载均衡和重试策略
@Bean
public RestTemplate restTemplate() {
	/*设置超时时间*/
	SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
	factory.setConnectTimeout(300); //设置建立连接超时时间 ms
    factory.setReadTimeout(300);    //设置建立连接到读取到资源的超时时间 ms
    /*将超时时间配置存入RestTemplate中*/
    return new RestTemplate(factory);
}
  • ribbon的重试机制,在 feign 和 zuul 中进一步进行了封装,后续可以使用feign或zuul的重试机制

Hystrix 断路器

降级和熔断

配置&使用

  • hystrix 起步依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- 如果没有@HystrixCommand 注解加此依赖 -->
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>RELEASE</version>
</dependency>
  • 主程序添加@EnableCircuitBreaker注解启用 hystrix 断路器

//@EnableCircuitBreaker // 启用断路器
//@EnableDiscoveryClient // 启用发现 eureka 客户端
//@SpringBootApplication // SpringBoot启动注解
//以上三个注解可以简化为 SpringCloudApplication 
@SpringCloudApplication
public class SpringBootRun{

	@LoadBalanced // ribbon 负载均衡
	@Bean
	public RestTemplate getRestTemplate() {
		SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
		f.setConnectTimeout(1000);
		f.setReadTimeout(1000);
		return new RestTemplate(f);
		
		//RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,
		//未启用超时,也不会触发重试
		//return new RestTemplate();
	}
	public static void main(String[] args) {
		SpringApplication.run(SpringBootRun.class, args);
	}
}

降级

当后台服务不可用、执行超时,或执行失败后执行降级方法(备用方法)来向客户端返回结果

在需要降级的方法·上添加 @HystrixCommand(fallbackMethod = "降级方法()")

/*主方法*/
@HystrixCommand(fallbackMethod = "loginFB")
@PostMapping("/item-service/login/{userInfo}")
public JsonResult login(@RequestBody List<User> userInfo) {
	// {1}为占位符
	return rt.postForObject("http://user-server/login/{1}", userInfo, JsonResult.class);
}
/*降级方法*/
public JsonResult loginFB(List<User> userInfo) {
	return JsonResult.err("抱歉,服务器正忙!");
}

熔断

1.在 10s 内 20 次请求 并且有 50% 的请求失败执行了降级 则触发熔断 后续请求不再请求服务提供者的服务器 直接执行降级方法
2.熔断的 5s 后熔断处于半开状态 会尝试性的去请求 如果请求成功 则断路器关闭 请求不成功 断路器继续保持熔断状态
Hystrix的逻辑,先判断是否满足第一个条件,再判断第二个条件,如果两个条件都满足,则会开启断路器

Hystrix常用 yml 配置参数

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
请求超时时间,超时后触发失败降级 默认1000ms
hystrix.command.default.circuitBreaker.requestVolumeThreshold
10秒内请求数量,默认20,如果没有达到该数量,即使请求全部失败,也不会触发断路器打开
hystrix.command.default.circuitBreaker.errorThresholdPercentage
失败请求百分比,达到该比例则触发断路器打开 默认50%
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
断路器打开多长时间后,再次允许尝试访问(半开),仍失败则继续保持打开状态,如成功访问则关闭断路器,默认 5000ms

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            # 请求超时后降级 默认 1s 单位 ms
            timeoutInMillisecond: 1000
      circuitBreaker:
        # 熔断后多久允许半开 尝试访问 默认 5s 单位 ms
        sleepWindowInMilliseconds: 5000
        # 失败请求百分比 默认 50%
        errorThresholdPercentage: 50
        # 10s 请求数量 默认20
        requestVolumeThreshold: 20
  • 需要进行监控的项目添加actuator依赖 和 hystrix 依赖
    actuator 是SpringBoot 中的依赖 主要用于健康检查、统计等等
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 如果没有hystrix.stream 端口添加下面的依赖-->
<dependency>
		<groupId>com.netflix.hystrix</groupId>
		<artifactId>hystrix-metrics-event-stream</artifactId>
</dependency>
  • 添加yml配置 暴露监控端点hystrix.stream 暴露所有*
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream
  • 监控端点是hystrix的监控信息,只会监控@HystrixCommand或者@FeignClient
  • 启用启动类 启用发现注册中心Hystrix
  • @EnableDiscoveryClient 或者 @EnableEurekaClient 因为SpringCloud 支持多种注册中心 前者启用多种都可以 后者仅启用Eureka
  • @EnableHystrix 中包含了 @EnableCircuitBreaker 都可以启用 hystrix
@EnableHystrix
@SpringBootApplication
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class, args);
    }
}

hystrix 监控面板 HystrixDashboard

  • 监控面板为单独项目 只需新建单独项目 添加eureka微服务端依赖 注解启用 发现客户端
  • 添加依赖
<!-- 仪表盘依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- eureka发现客户端依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • yml 配置
spring:
  application:
    name: hystrix-dashboard
server:
  port: 4001
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:2001/eureka, http://127.0.0.1:2002/eureka

  • 添加启动注解
@EnableHystrixDashboard // 启用Hystrix仪表板
@EnableDiscoveryClient  // 启用发现客户端
@SpringBootApplication
public class Sp08HystrixDashboardApplication {
	public static void main(String[] args) {
		SpringApplication.run(Sp08HystrixDashboardApplication.class, args);
	}
}
  • 访问 hystrix dashboard
    地址:http://XXX/hystrix
    在此输入监控端点信息

  • 填入 hystrix 的监控端点,开启监控
    地址:http://XXX/actuator/hystrix.stream 需要进行监控的项目地址+健康检查地址
    填入地址

  • 监控信息
    监控面板
    面板具体信息

Feign

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

配置&使用

  • hystrix 起步依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 在启动类上加@EnableFeignClients
// 启用Feign客户端
@EnableFeignClients
// 启用发现eureka服务
@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootRun {

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

feign 声明式客户端

feign 利用了我们熟悉的 spring mvc 注解来对接口方法进行设置,降低了我们的学习成本。

通过这些设置,feign可以拼接后台服务的访问路径和提交的参数
@FeignClient(name = "用户微服务") 标记在接口上 具体的访问路径和参数与Controller层使用方法一致
例如:

@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);
  • 声明式客户端 接口
//声明访问的路径 路径为服务提供者的spring.application.name
//声明降级类 降级类需要实现此接口 然后交给spring管理 当服务器响应超时时会直接去访问 实现接口的对应方法
@FeignClient(name = "item-service",fallback = ItemServiceFallBack.class)
public interface ItemService {
	//具体的访问路径 使用的是spring注解 将调用方法传入时的参数通过反射机制拿到 orderId值再赋值给注解 然后拼接类注解值得到具体路径
	@GetMapping("/{orderId}")
	JsonResult<List<Item>> getItems(@PathVariable String orderId);
	
	//@RequestBody 注解是将传过来的json解析为对象再赋值
	@PostMapping("/decreaseNumber")
	JsonResult decreaseNumber(@RequestBody List<Item> items);
}

feign + ribbon 负载均衡和重试

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

  • application.yml 配置 ribbon 超时和重试
    • ribbon.xxx 全局配置
    • item-service.ribbon.xxx 对特定服务实例的配置
# 全局配置
ribbon:
  # 建立连接超时时间
  ConnectTimeout: 1000
  # 读取到资源超时时间
  ReadTimeout: 1000
# 只针对于请求指定微服务时  
item-service:
  ribbon:
    ConnectTimeout: 500
    ReadTimeout: 1000
    # 请求失败后最大向后请求实例
    MaxAutoRetriesNextServer: 2
    # 请求失败后每个实例最多重试次数
    MaxAutoRetries: 1

feign + hystrix 降级

  • feign 默认没有启用 hystrix 需要 yml 配置启用
feign:
  hystrix:
    enabled: true # 启用 hystrix 
  • 降级实现:继承声明式客户端接口 降级会找指定的实现方法 实现类必须要要用 @Component 交由Spring容器 管理
  • 接口
//声明访问的路径 路径为服务提供者的spring.application.name
//声明降级类 降级类需要实现此接口 然后交给spring管理 当服务器响应超时时会直接去访问 实现接口的对应方法
@FeignClient(name = "item-service",fallback = ItemServiceFallBack.class)
public interface ItemService {
	//具体的访问路径 使用的是spring注解 将调用方法传入时的参数通过反射机制拿到 orderId值再赋值给注解 然后拼接类注解值得到具体路径
	@GetMapping("/{orderId}")
	JsonResult<List<Item>> getItems(@PathVariable String orderId);
	
	//@RequestBody 注解是将传过来的json解析为对象再赋值
	@PostMapping("/decreaseNumber")
	JsonResult decreaseNumber(@RequestBody List<Item> items);
}
  • 实现类
    具体的实现类就是降级类 实现方法就是对应的降级方法
package com.tedu.sp09.service.fallback;

import java.util.List;

import org.springframework.stereotype.Component;

import com.tedu.sp01.pojo.Item;
import com.tedu.sp09.service.ItemService;
import com.tedu.web.util.JsonResult;
@Component
public class ItemServiceFallBack implements ItemService {

	@Override
	public JsonResult<List<Item>> getItems(String orderId) {
		// TODO Auto-generated method stub
		return JsonResult.err("服务器正忙!");
	}

	@Override
	public JsonResult decreaseNumber(List<Item> items) {
		// TODO Auto-generated method stub
		return JsonResult.err("服务器正忙!");
	}

}

feign + hystrix 监控和熔断(断路器)

  • feign 虽然整合了 ribbon 和 hystrix 但是并不包含hystrix 完整依赖 若要启用监控和熔断仍需添加 hystrix 完整依赖
  • 添加依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>
		spring-cloud-starter-netflix-hystrix
	</artifactId>
</dependency>
  • 启动类添加注解 @EnableCircuitBreaker 启用 hystrix 断路器
@EnableFeignClients     //启用feign客户端
//@EnableCircuitBreaker   //启用断路器
//@EnableDiscoveryClient  //启用发现客户端(eureka)
//@SpringBootApplication
@SpringCloudApplication  //代替上面三个注解可以
public class SpringBootRun {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootRun.class, args);
	}
}
  • 确认actuator 健康检查依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 暴露hystrix.stream监控端点
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream
  • 启动 hystrix dashboard 仪表盘项目
  • 访问 http://XXX/hystrix
  • 填入需要进行监控的项目 http://XXX/actuator/hystrix.stream
  • 访问微服务 查看监控数据
    监控面板
  • 测试断路器
    使用 Apache 的 ab 工具进行压力测试
  • 以并发50,来发送20000个请求
ab -n 20000 -c 50 http://localhost:3001/item-service/35
  • 断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法
    在这里插入图片描述

Hystrix常用 yml 配置参数

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
请求超时时间,超时后触发失败降级 默认1000ms
hystrix.command.default.circuitBreaker.requestVolumeThreshold
10秒内请求数量,默认20,如果没有达到该数量,即使请求全部失败,也不会触发断路器打开
hystrix.command.default.circuitBreaker.errorThresholdPercentage
失败请求百分比,达到该比例则触发断路器打开 默认50%
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
断路器打开多长时间后,再次允许尝试访问(半开),仍失败则继续保持打开状态,如成功访问则关闭断路器,默认 5000ms

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            # 请求超时后降级 默认 1s 单位 ms
            timeoutInMillisecond:
      circuitBreaker:
        # 熔断后多久允许半开 尝试访问 默认 5s 单位 ms
        sleepWindowInMilliseconds: 5000
        # 失败请求百分比 默认 50%
        errorThresholdPercentage: 50
        # 10s 请求数量 默认20
        requestVolumeThreshold: 20

hystrix + turbine 集群聚合监控

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

  • 新建 turbine 并添加依赖
<!-- turbine依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<!-- eureka发现客户端依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 启动类配置启用依赖注解
@EnableDiscoveryClient  //启用发现eureka客户端
@EnableTurbine  //启用turbine
@SpringBootApplication
public class TurbineApplication {
	public static void main(String[] args) {
		SpringApplication.run(TurbineApplication.class, args);
	}
}
  • yml配置
spring:
  application:
    name: turbine
server:
  port: 5001
eureka:
  client:
    service-url:
      defaultZone: http:127.0.0.1:2001/eureka,http://127.0.0.1:2002/eureka
# turbine 配置
turbine:
  aggregator:
    # 指定聚合哪些集群,多个使用","分割,默认为default。 
    cluster-config: default
  # 配置 需要聚合信息的 服务名
  app-config: order-server, feign-server
  # 需要聚合的集群的名字
  cluster-name-expression: new String("default")
  • 启动项目访问测试
  • turbine 监控路径
    http://XXX/turbine.stream
  • hystrix dashboard 监控面板路径
    http://XXX/hystrix
  • 在 hystrix dashboard 监控面板中填入 turbine 监控路径
    在这里插入图片描述
  • 进行访问微服务产生监控信息 再返回监控面板查看有误信息 信息是否完整
    监控信息这样就可以监控多个微服务

Zuul

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

Zuul API 网关

  • 依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • yml配置
    zuul 自身也需要注册到注册中心 也会对从注册中心拉取数据 如果微服务名与期望的访问路径一致 此配置时缺省的
zuul:
  routes:
  	# 微服务名     映射路径
    item-service: /item-service/**
    user-service: /user-service/**
    order-service: /order-service/**
  • 启动类添加注解
    @EnableZuulProxy 它是 @EnableZuulServer 的增强版
@EnableZuulProxy   //启用Zuul服务端 spring基于 @EnableZuulServer的增强
@EnableDiscoveryClient  //启用发现eureka注册中心客户端
@SpringBootApplication
public class ZuulApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication.class, args);
	}
}

访问路径为:http://zuul地址/映射路径

Zuul + Ribbon 负载均衡

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

Zuul+Ribbon 重试

  • 添加依赖 retry依赖
<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>
  • 配置zuul开启重试 并配置ribbon超时重试参数
# 开启重试
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 降级 和 熔断

  • 熔断参考上文中的 Hystrix 熔断 的配置配置即可
  • 降级类需要实现接口 FallbackProvider
    getRoute() 方法中指定应用此降级类的服务id,星号或null值可以通配所有服务
  • 降级类示例代码
// log4j
@Slf4j
// 交由spring管理
@Component
public class ItemServiceFallback implements FallbackProvider {
	@Override
	public String getRoute() {
	    //当执行item-service失败,
	    //应用当前这个降级类
	    
	    //星号和null都表示所有微服务失败都应用当前降级类
		//"*"; //null;
		return "item-service"; 
	}

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

	private ClientHttpResponse response() {
        return new ClientHttpResponse() {
            //下面三个方法都是协议号
            //获取http响应状态代码
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            //获取http状态代码
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }
            //获取http响应相应报文
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }
			// 关闭方法一般不用谢任何代码
            @Override
            public void close() {
            }
			//http响应体
            @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;
            }
        };
    }
}
  • 配置文件
# 启用重试
zuul:
  retryable: true
# 重试参数
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1
  
# 超时时间 一般来说应该比 重试的总耗时长一点 这样等待重试都完成后进行降级
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

Zuul 的请求过滤

zuul 请求过滤需要继承 ZuulFilter 类 无需进行多余配置 只需将过滤类交给Spring容器管理即可

  • shouldFilter() 方法判断需要进行过滤的请求 返回值为true时表示需要进行过滤执行 run()方法 false 则不进行过滤直接执行业务调用
  • run()方法中进行过滤操作 例如是否允许登录等等
  • filterType()方法指定需要在那个过滤器中进行过滤 例如FilterConstants.PRE_TYPE 前置过滤器 大部分为前置过滤器
  • filterOrder() 过滤器执行顺序 数字越小等级越高
    示例: 当URl请求中没有token参数返回未登陆 当然token在不应该在url中直接进行明文传输 这里只做演示
@Component
public class TokenFilter extends ZuulFilter {
	
	/**
	   *  判断是否执行过滤器
	 */
	@Override
	public boolean shouldFilter() {
		// TODO Auto-generated method stub
		// 获取请求上下文
		RequestContext currentContext = RequestContext.getCurrentContext();
		// 从请求上下文中获取 serviceId
		Object serviceId = currentContext.get(FilterConstants.SERVICE_ID_KEY);
		// 当是需要过滤的id时执行过滤器
		if (serviceId.equals("item-service")) {
			return true;
		}
		//否则返回 false
		return false;
	}
	/**
	    *  过滤器
	 */
	@Override
	public Object run() throws ZuulException {
		// TODO Auto-generated method stub
		// 获取当前请求上下文
		RequestContext currentContext = RequestContext.getCurrentContext();
		// 获取request 对象
		HttpServletRequest request = currentContext.getRequest();
		// 从request域中取值
		String token = request.getParameter("token");
		//判断值是否为空 空:true 
		if (token==null||token.length()==0) {
			//阻止执行,直接向客户端返回结果
			currentContext.setSendZuulResponse(false);
			//设置response响应状态
			currentContext.setResponseStatusCode(200);
			//通过全局json响应进行封装
			currentContext.setResponseBody(JsonResult.err("没有登录!").code(JsonResult.NOT_LOGIN).toString());
		}
		// zuul 为了以后升级预留返回值 至今没用
		return null;
	}
	
	/**
	   *   设置过滤类型 ——> 前置过滤
	 */
	@Override
	public String filterType() {
		// TODO Auto-generated method stub
		return FilterConstants.PRE_TYPE;
	}
	
	/**
	 *  设置过滤器顺序 
	 */
	@Override
	public int filterOrder() {
		// PRE_DECORATION_FILTER_ORDER 属于pre最重要的过滤器,基本的路由转发配置,请求修饰都在这里完成。
		// 他的等级是 5 我们所需要的拿到的 微服务id也在这层过滤去进行装饰 所以我们的等级要比他低 +1  
		// 等级:6
		return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
	}
}

PRE_DECORATION_FILTER_ORDER 属于pre最重要的过滤器,基本的路由转发配置,请求修饰都在这里完成,他的等级是 5 我们所需要的拿到的 微服务id也在这层过滤去进行装饰 所以我们的等级要比他低 所及进行了 +1 也就是等级为 6

  • 一般来说不会让 Zuul实现太多功能 例如重试、降级、熔断 交由微服务自己独立完成即可 Zuul也可以搭建集群那就需要用 Nginx 或者其他工具、硬件等 进行反向代理、负载均衡

Config 配置中心

  • yml 配置文件保存到 git 服务器,例如 github.comgitee.com 微服务启动时,从服务器获取配置文件。
  • config 服务器启动时下载 配置文件 微服务启动时从 config服务器 获取配置文件
  • 从config 配置中心获取的 配置文件 比 application.yml 优先级高 当两个配置冲突时 优先使用 配置中心获取的文件

config 服务端

  • 添加依赖
<!-- config-server 服务端依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- eureka 微服务端依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 配置文件
    配置文件推荐存放位置 Git 服务器
    放在本地时必须配置 spring.profiles.active=native 来激活本地文件系统
spring:
  # 服务 id
  application:
    name: config-server
  # 启用本地存放配置文件
  #profiles:
    #active: native
  cloud:
    config:
      server:
      	# 配置存放在本地
        #native:
          # 路径 resource 文件夹下
          #search-locations: classpath:/config
        # 配置存放在 git 服务器 官方推荐
        git:
          uri: 配置文件仓库路径
          searchPaths: config
          # 当时私有仓库时需要 用户名密码
          #username: 用户名
          #password: 密码
          #basedir: #通过basedir指定本地分支存放的文件夹
  # 配置连接信息
  rabbitmq:
  	# 地址
    host: 192.168.64.140
    # 端口
    port: 5672
    username: admin
    password: admin
    
server:
  port: 6001
# 向 eureka 服务器注册
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

  • 启动类标识注解 启用服务
  1. 启用config配置中心服务@EnableConfigServer
  2. 启用发现客户端 @EnableDiscoveryClient
@EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConfigApplication.class, args);
	}
}

config 客户端

  • 添加客户端依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
  • 配置文件
    添加 bootstrap.yml 文件 bootstrap 文件加载比 application 早
    编辑 bootstrap.yml 文件
spring: 
  cloud:
    config:
      discovery:
        enabled: true
        # 配置中心服务器 id
        service-id: config-server
      # 需要拉取的文件名
      name: item-server
      # 环境名 例如 item-server-dev.yml
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
  • 官方推荐 git 中的配置文件名以文件名-环境名.后缀名 来命名
  • 开发环境:dev
  • 测试环境:test
  • 生产环境:prod

动态刷新配置文件

  • 访问端点手动刷新服务器配置文件 只能刷新单个服务
    http://域名/actuator/refresh

  • 一般只能刷新自定义的配置 例如服务端口号等 无法刷新

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

  • 添加依赖 健康检查

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>=
  • 配置文件 暴露端口、自定义配置等
    例如: 新的配置修改了自定义配置 但是服务器在启动状态
# 自定义配置
user:
  userInfo: "[{\"id\":1,\"nickname\":\"祈风\", \"username\":\"root\",\"password\":\"root\"}]"
# spring 配置
spring: 
  cloud:
    config:
      discovery:
        enabled: true
        # 配置中心服务器 id
        service-id: config-server
      # 需要拉取的文件名
      name: user-server
      # 环境名 例如 item-server-dev.yml
      profile: dev
# 向注册中心注册     
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
# 健康检查 暴露监控端点 
management:
  endpoints:
    web:
      exposure:
        include: refresh

Java 文件

@RefreshScope
@RestController
@RequestMapping("/user")
public class UserInfo{
	// 重新获取配置文件时 动态刷新值 重新注入
	@Value("${user.userInfo}")
	private User userInfo;
	@GetMapping("/getUserInfo")
	public String getUserInfo(){
		return userInfo;
	}
}

Bus

Bus + RabbitMQ 消息总线配置刷新

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

安装 RabbitMQ

在centos7上安装rabbitmq

  1. 安装erlang语言库
    RabbitMQ使用了Erlang开发语言,Erlang是为电话交换机开发的语言,天生自带高并发光环,和高可用特性
    下载&安装
    # 下载
    wget https://github.com/rabbitmq/erlang-rpm/releases/download/v21.2.6/erlang-21.2.6-1.el7.x86_64.rpm
    # 安装
    rpm -ivh erlang-21.2.6-1.el7.x86_64.rpm --force --nodeps
    
  2. 安装socat依赖
    	# 下载 socat rpm
    	wget http://mirror.centos.org/centos/7/os/x86_64/Packages/socat-1.7.3.2-2.el7.x86_64.rpm
    	# 安装 socat 依赖包
    	rpm -ivh socat-1.7.3.2-2.el7.x86_64.rpm
    
  3. 安装rabbitmq
    	# 下载 rpm 包
    	wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.13/rabbitmq-server-3.7.13-1.el7.noarch.rpm
    	# 安装 rpm 包
    	rpm -ivh rabbitmq-server-3.7.13-1.el7.noarch.rpm
    
  4. rabbitmq 开机启动&启动&停止
    	# 设置服务,开机自动启动
    	chkconfig rabbitmq-server on
    
    	# 启动服务
    	service rabbitmq-server start
    
    	# 停止服务
    	service rabbitmq-server stop
    
  5. 启用UI管理界面
    	# 开启管理界面插件
    	rabbitmq-plugins enable rabbitmq_management
    	# 防火墙打开 15672 管理端口
    	firewall-cmd --zone=public --add-port=15672/tcp --permanent
    	firewall-cmd --reload
    

    访问:http://XXX:15672 登录 分配权限

  6. 添加用户 并赋予权限
    账号:admin 密码:admin
    	# 添加用户
    	rabbitmqctl add_user admin admin
    
    	# 新用户设置用户为超级管理员
    	rabbitmqctl set_user_tags admin administrator
    
  7. 开放连接端口
    	# 打开客户端连接端口
    	firewall-cmd --zone=public --add-port=5672/tcp --permanent
    	firewall-cmd --reload
    

添加 bus、rabbitmq 依赖

每个需要刷新配置的微服务都需要进行 添加依赖 添加配置文件

<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
		<groupId>org.springframework.amqp</groupId>
		<artifactId>spring-rabbit-test</artifactId>
		<scope>test</scope>
</dependency>

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

配置 RabbitMQ 连接信息 并暴露端点用来刷新配置

暴露刷新端点 只需暴露一个微服务即可 例如: 暴露 ConfigServer 配置中心服务器端点

spring:
  # 服务 id
  application:
    name: config-server
    
  # 配置连接信息
  rabbitmq:
  	# 地址
    host: 192.168.64.140
    # 端口
    port: 5672
    username: admin
    password: admin
    
  cloud:
    config:
      server:
        git:
          uri: 配置文件仓库路径
          searchPaths: config
          # 当时私有仓库时需要 用户名密码
          #username: 用户名
          #password: 密码
          #basedir: #通过basedir指定本地分支存放的文件夹
    
server:
  port: 6001
# 向 eureka 服务器注册
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

POST访问 http://XXX/actuator/bus-refresh 即可刷新全部微服务配置
POST访问 http://XXX/actuator/bus-refresh/XXX 即可刷新指定微服务配置

Sleuth 链路跟踪

sleuth 可以收集调用的链路信息

  • 在需要进行跟踪的微服务添加依赖
<!-- sleuth 依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- zipkin 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
  • 访问服务并查看控制台
  • [服务id,请求id,span id,是否发送到zipkin]
    链路跟踪数据
  • 链路数据默认只有10%发送到Zipkin
  • 可以修改发送数据量
spring:
  sleuth:
    sampler:
      # 发送 10%
      probability: 0.1

Sleuth + Zipkin 链路分析

zipkin 下载

https://github.com/openzipkin/zipkin
下载

  • 启动 zipkin 并连接到 rabbitmq
    java -jar zipkin-server.jar --zipkin.collector.rabbitmq.uri=amqp://账号:密码@rabbitmq 地址
    例如:java -jar zipkin-server-2.12.9-exec.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.140:5672
  • 访问zipkin
    http://XXX/zipkin

0
博主关闭了所有页面的评论