第一部分:尚硅谷周阳老师SpringCloud学习整理笔记第一部分
经过5天的学习,目前学到了P92,刚刚结束了SpringCloud Stream,由于还有一些别的事情所以进度有点慢,笔记也整理得有点潦草。第一部分篇幅逐渐臃肿,故下面的笔记,分享于这篇博客。
笔记供自己日后复习,若有需要也供大家参考。若有不足,还请指正。
十三、Hystrix
Hystrix介绍
在微服务场景中,通常会有很多层的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。我们需要一种机制,当底层服务不可用时,可以阻断故障的传播。这就是断路器的作用。他是系统服务稳定性的最后一重保障。
在springcloud中断路器组件就是Hystrix。Hystrix也是Netflix套件的一部分。他的功能是,当对某个服务的调用在一定的时间内(默认10s),有超过一定次数(默认20次)并且失败率超过一定值(默认50%),该服务的断路器会打开。返回一个由开发者设定的fallback。
fallback可以是另一个由Hystrix保护的服务调用,也可以是固定的值。fallback也可以设计成链式调用,先执行某些逻辑,再返回fallback。
Hystrix的作用
-
对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。
-
在复杂的分布式系统中阻止级联故障。
-
快速失败,快速恢复。
-
回退,尽可能优雅地降级。
-
启用近实时监控、警报和操作控制。
官网:https://github.com/Netflix/Hystrix/wiki
参考博客:https://www.cnblogs.com/cjsblog/p/9391819.html
https://blog.csdn.net/tongtong_use/article/details/78611225
服务降级
三种情况:
-
访问超时
-
运行错误
-
宕机
实例代码:
/**
* 访问超时 * * @param id * @return
*/
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 5;
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (Exception e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + "paymentinfo_Timeout,id:" + id + "\t" + "耗时(秒)" + timeNumber;
}
private String paymentInfo_TimeOutHandler(Integer id) {
return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOutHandler,id:" + id + "\t";
}
主启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreakerpublic
class PaymentHystrixMain8001 {
public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class, args); }
}
问题:
1、每个方法有一个对应的处理方法,代码膨胀。
2、处理方法和主业务逻辑混合在一起
解决方案:
@DefaultProperties(defaultFallback=“”)
1、类上加上注解:
@RestController@RequestMapping("/consumer")@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {}
2、默认全局处理方法
/** * 全局fallback方法 * * @return */private String payment_Global_FallbackMethod() { return "Global异常处理信息,请稍后再试。";}
3、@HystrixCommand//不加属性代表使用默认的全局处理方法。
服务熔断
//====服务熔断/** * 在10秒窗口期中10次请求有6次是请求失败的,断路器将起作用 * * @param id * @return */
@HystrixCommand( fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),// 时间窗口期/时间范文
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")// 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
if (id < 0) { throw new RuntimeException("*****id不能是负数"); }
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
return "id 不能负数,请稍后重试,o(╥﹏╥)o id:" + id;
}
Hystrix断路器使用时最常用的三个重要指标参数
在微服务中使用Hystrix 作为断路器时,通常涉及到以下三个重要的指标参数(这里是写在@HystrixProperties注解中,当然实际项目中可以全局配置在yml或properties中)
1、circuitBreaker.sleepWindowInMilliseconds
断路器的快照时间窗,也叫做窗口期。可以理解为一个触发断路器的周期时间值,默认为10秒(10000)。
2、circuitBreaker.requestVolumeThreshold
断路器的窗口期内触发断路的请求阈值,默认为20。换句话说,假如某个窗口期内的请求总数都不到该配置值,那么断路器连发生的资格都没有。断路器在该窗口期内将不会被打开。
3、circuitBreaker.errorThresholdPercentage
断路器的窗口期内能够容忍的错误百分比阈值,默认为50(也就是说默认容忍50%的错误率)。打个比方,假如一个窗口期内,发生了100次服务请求,其中50次出现了错误。在这样的情况下,断路器将会被打开。在该窗口期结束之前,即使第51次请求没有发生异常,也将被执行fallback逻辑。
综上所述,在以上三个参数缺省的情况下,Hystrix断路器触发的默认策略为:
在10秒内,发生20次以上的请求时,假如错误率达到50%以上,则断路器将被打开。(当一个窗口期过去的时候,断路器将变成半开(HALF-OPEN)状态,如果这时候发生的请求正常,则关闭,否则又打开)
十四、GateWay
暂时省略
十五、Spring Config
**简介:**在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。Spring Cloud Config项目是就是这样一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。
入门示例:
1、在github上新建一个仓库,如图所示
2、复制新建的git地址
3、在本地新建git仓库并clone
4、新建开发、生产、测试配置文件,并提交到github
参考下图:
命令:git add .
git commit
git push origin master
5、新建配置中心模块3344 cloud-config-center3344
添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>undefined</dependencies>
yml文件配置
server: port: 3344
spring: application:
name: cloud-config-center cloud: config: server: git: skipSslValidation: true # 跳过ssl认证 uri: https://github.com/Jiaru0314/springcloud-config.git search-paths: - springcloud-config label: mastereureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka
主启动类
@SpringBootApplication@EnableConfigServerpublic class MainConfigCenter3344 { public static void main(String[] args) { SpringApplication.run(MainConfigCenter3344.class, args); }}
Spring Cloud Config 有它的一套访问规则,我们通过这套规则在浏览器上直接访问就可以。
/{application}/{profile}[/{label}]/{application}-{profile}.yml/{label}/{application}-{profile}.yml/{application}-{profile}.properties/{label}/{application}-{profile}.properties
{application} 就是应用名称,对应到配置文件上来,就是配置文件的名称部分,例如我上面创建的配置文件。
{profile} 就是配置文件的版本,我们的项目有开发版本、测试环境版本、生产环境版本,对应到配置文件上来就是以 application-{profile}.yml 加以区分,例如application-dev.yml、application-sit.yml、application-prod.yml。
{label} 表示 git 分支,默认是 master 分支,如果项目是以分支做区分也是可以的,那就可以通过不同的 label 来控制访问不同的配置文件了。
访问:http://localhost:3344/config-dev.yml
结果:
config: info: master branch,springcloud-config/config-dev.yml version=7
配置成功,但是这样还存在一个问题,就是当我们github上更新配置后,我们的服务要重新启动才能使用新的配置,否则配置无法生效。解决方案就是动态的修改配置。
使用标签:@RefreshScope
步骤:
-
pom文件引入actuator依赖
-
修改yml,暴露监控端口
#暴露监控端点management: endpoints: web: exposure: include: "*"
-
@RefreshScope修饰控制类
-
cmd下 执行
curl -X POST "http://localhost:3355/actuator/refresh"
3355模块重新获取配置信息
十六、Bus消息中心
1、首先配置RabbitMQ
下载erlang 地址:http://erlang.org/download/otp_win64_21.3.exe 傻瓜式安装即可
下载RabbitMQ 地址:https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.2/rabbitmq-server-3.8.2.exe 傻瓜式安装即可
进入rabbitmq安装目录下的sbin目录:输入
rabbitmq-plugins enable rabbitmq_management
双击RabbitMQ service start
浏览器输入:localhost:15672 如果出现如下页面,则安装成功
输入账号和密码:guest、guest 可以看到RabbitMQ的主界面
2、参照3355模块新建3366模块
3344模块添加新依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency>
3344新添yml:
rabbitmq: host: localhost port: 5672 username: guest password: guest # 暴露bus刷新配置的端点management: endpoints: web: exposure: include: "bus-refresh"
3355、3366yml新增:
rabbitmq: #rabbitmq相关配置,15672是web管理端口,5672是mq访问端口 port: 5672 host: localhost username: guest password: guest #暴露监控端点management: endpoints: web: exposure: include: "*"
1、修改github中版本号
2、cmd 刷新3344
curl -X POST "http://localhost:3344/actuator/bus-refresh"
**结果:**3355、3366 都已经改变,一次修改、广播通知、到处运行。
上面是全局通知,但如果我们想定点通知该如何做呢?
**定点通知:**只通知3355,不通知3366
实现方法:cmd 刷新3344
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
第十五章 SpringCloud Stream
**问题:**为什么要引入SpringCloud Stream
举例:对于我们Java程序员来说,可能有时要使用ActiveMQ,有时要使用RabbitMQ,甚至还有RocketMQ以及Kafka,这之间的切换似乎很麻烦,我们很难,也没有太多时间去精通每一门技术,那有没有一种新技术的诞生,让我们不再关注具体MQ的细节,自动的给我们在各种MQ内切换。
简介:Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于 Spring Boot 来创建独立的、可用于生产的 Spring 应用程序。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。通过使用 Spring Cloud Stream,可以有效简化开发人员对消息中间件的使用复杂度,**让系统开发人员可以有更多的精力关注于核心业务逻辑的处理。**但是目前 Spring Cloud Stream 只支持 RabbitMQ 和 Kafka 的自动化配置。
**一句话:**屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型。
Binder Implementations 绑定器
通过绑定器Binder作为中间件,实现了应用程序与消息中间件细节的解耦。
Input对应消息生产者
Output对应消息消费者
入门案例
-
新建子模块
cloud-stream-rabbitmq-provider8801 消息生产模块
-
pom
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <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-stream-rabbit</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>
-
yml
server: port: 8801 spring: application: name: cloud-stream-provider cloud: stream: binders: # 在此处配置要绑定的rabbitMQ的服务信息 defaultRabbit: # 表示定义的名称,用于binding的整合 type: rabbit # 消息中间件类型 environment: # 设置rabbitMQ的相关环境配置 spring: rabbitmq: host: localhost port: 5672 username: guest password: guest bindings: # 服务的整合处理 output: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的exchange名称定义 content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain binder: defaultRabbit # 设置要绑定的消息服务的具体设置 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka instance: lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30 lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90 instance-id: send-8801.com # 主机名 prefer-ip-address: true # 显示ip
-
业务类
-
主启动类
-
IMessageProvider接口
-
public interface IMessageProvider { String send();}
-
MessageProviderImpl实现类
public class MessageProviderImpl implements IMessageProvider {@Overridepublic String send() { return null; }}
-
控制层
@RestControllerpublic class SendMessageController { @Autowired private IMessageProvider messageProvider; @GetMapping("/sendMessage") public String send() { return messageProvider.send(); }}
-
-
启动rabbitMQ,7001,8801 访问localhost:8801/sendMessage
返回结果:62b3cb3e-ca40-410e-a601-dc72dfd004b5
-
新建子模块
cloud-stream-rabbitmq-consumer8802 消息消费模块
-
pom文件同8801
-
yml文件
server: port: 8802spring: application: name: cloud-stream-consumer cloud: stream: binders: # 在此处配置要绑定的rabbitMQ的服务信息 defaultRabbit: # 表示定义的名称,用于binding的整合 type: rabbit # 消息中间件类型 environment: # 设置rabbitMQ的相关环境配置 spring: rabbitmq: host: localhost port: 5672 username: guest password: guest bindings: # 服务的整合处理 input: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的exchange名称定义 content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain binder: defaultRabbit # 设置要绑定的消息服务的具体设置 # group: spectrumrpcAeureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka instance: lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30 lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90 instance-id: receive-8802.com #主机名 prefer-ip-address: true # 显示ip
-
业务类
1. 主启动类
2. 服务类
```html
/** * @ClassName: ReceiveMessageListenerController * @description: * @author: XZQ * @create: 2020/3/10 15:34 **/@Component@EnableBinding(Sink.class)public class ReceiveMessageListenerController { @Value("${server.port}") private String serverPort; @StreamListener(Sink.INPUT) public void input(Message<String> message) { System.out.println("消费者1,-------" + message.getPayload() + "\t port:" + serverPort); } }
```
- 启动8802,8801发送消息,可以看到8802可以接受到消息,案例完成。
消息重复消费
不同的组存在重复消费,相同的组之间竞争消费。
-
参照8802建立8803模块
-
8802、8803yml加入组名 spectrumrpcA
bindings: # 服务的整合处理 input: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的exchange名称定义 content-type: application/json # 设置消息类型 binder: defaultRabbit # 设置要绑定的消息服务的具体设置 # group: spectrumrpcA
-
分别启动8802、8803
-
8801发送消息、发现只有一个模块收到消息
第十六章 SpringCloud Sleuth
未完待更新