SpringCloud
简介
用于微服务开发,是一系列框架的有序集合,整合其他微服务框架
微服务架构定义
将一个独立的系统拆分成若干个小的服务,比如订单、用户管理等。这些小的服务独立部署,服务与服务之间采用http轻量协议传输数据,每个服务独立性强。这样的设计实现了单个服务的高内聚,服务于服务之间低耦合的效果,我们把这些一个一个小的服务成为微服务。
服务可用不同的语言开发,使用不同的数据存储技术。
微服务优缺点
优点
1.降低耦合度
2.便于服务横向扩容 (如:网购服务 分为 订单、用户、交易等模块,双十一时只是订单会猛增,所以只要单独多部署订单就可以)
3.单个服务更易于开发、维护
缺点
多服务,随着服务的增加,运维困难越大
数据一致性
springCloud定义:是一些组件的集合
组件:注册中心、配置中心、熔断器、网关、负载均衡、消息总线、数据监控等
特点:
1.基于spring boot 开发的 回顾视频,此处不完整
SpringCloud的两个事实
1. Feign 集成过 Ribbon 默认开启轮询
2. Feign 集成过 Hytricx 默认关闭 需要开启才能生效
springcloud与dubbo区别❤️
(面试题)
1.dubbo基于RPC协议实现远程调用,要求所用语言必须是java
2.springcloud规定服务之间通过http协议通信,支持跨语言特性
3.都是微服务的工具,由于协议不同,RPC是基于socket,导致dubbo性能高但是功能少于cloud
服务治理(注册中心)
dubbo与eureka的区别
dubbo的远程调用是使用的@reference注解
eureka的远程调用是使用的RestTemplate模板对象调用方法传值
@SpringBootApplication功能:把这个入口方法类定义为一个核心配置类
@PathVariable(“xxx”) : 将访问路径中{xxx}占位符的值同步到方法参数上赋值
@GetMapping("/good/#{id}")
public void show(@PathVariable("id") int id ){
}
Eureka❤️
Eureka和ZK区别
1.ZooKeeper保证的是CP,Eureka保证的是AP
ZooKeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用的
Eureka各个节点是平等关系,只要有一台Eureka就可以保证服务可用,而查询到的数据并不是最新的
自我保护机制会导致:
Eureka不再从注册列表移除因长时间没收到心跳而应该过期的服务
Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点(高可用)
当网络稳定时,当前实例新的注册信息会被同步到其他节点中(最终一致性)
Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper一样使得整个注册系统瘫痪
2.ZooKeeper有Leader和Follower角色,Eureka各个节点平等
3.ZooKeeper采用过半数存活原则,Eureka采用自我保护机制解决分区问题
4.Eureka本质上是一个工程,而ZooKeeper只是一个进程
基础介绍
Netflix公司开源的一个服务注册与发现的组件
远程对象RestTemplate 封装了三个网络请求 是spring提供的简单便捷的模板类。用于在java代码中访问restful服务。开机自启。
如果要切换为其他请求。则new 一个spring提供的对应请求工厂类。由于okttp和httpclient是三方,所以还需要导包!
RestTemplate作用:提供了统一的封装
1.默认 URLConnection
2.Okhttp 是安卓上的协议,性能最好
3.HttpClient apache最早提供的协议
Eureka配置原理
心跳默认30秒一次
服务器未收到心跳90s后才会删除对应客户端
入门案例
默认服务端口号8761
服务端:
1.导包 (netflix-rureka-server)
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2.在客户端和服务器工程中添加@EnableEurekaClient/@EnableEurekaServer注解
3.在客户端和服务器工程中配置文件
4.启动类添加eureka启动注解
<!-- 注意:如果没有设置实例名 访问主页看到实例名字都是unkown,所以要设置实例名,将来要使用该名称来当作对应的访问路径 -->
<!-- 名字不可以重复 -->
5.导入discoveryClient 使用@EnableDiscoveryClient来开启该功能
#结论:
eureka 配置
eureka 一共有4部分 配置
1. dashboard:eureka的web控制台配置
2. server:eureka的服务端配置
3. client:eureka的客户端配置
4. instance:eureka的实例配置
客户端
1.消费方
提供方与消费方导包都是客户端包
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
/**
* 服务的调用方
*/
@RestController
@RequestMapping("/order")
public class OrderController {
//此对象不会预读到ioc中
//要自行定义核心配置类,存入@Bean存入ioc中
@Autowired
private RestTemplate restTemplate;
//通过此对象在eureka中获取远程连接的必要信息,此对象会被springboot通过依赖预读到IOC中
//所以自动注入即可
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
System.out.println("findGoodsById..."+id);
/*
//远程调用Goods服务中的findOne接口
使用RestTemplate
1. 定义Bean restTemplate
2. 注入Bean
3. 调用方法
*/
/*
动态从Eureka Server 中获取 provider 的 ip 和端口
1. 注入 DiscoveryClient 对象.激活
2. 调用方法
*/
//演示discoveryClient 使用
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");//通过提供方名获取
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0); //获得实例对象
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
//打印输出
System.out.println(host);
System.out.println(port);
//拼接url
String url = "http://"+host+":"+port+"/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class); //到那个地方去访问,以什么类来封装结果
//回传
return goods;
}
}
核心配置类
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
启动类
@EnableDiscoveryClient // 激活DiscoveryClient 此注解用于从服务器上获取远程调用所必要的信息
@EnableEurekaClient // 开启此注解表示该工程为客户端(可省略)
@SpringBootApplication // 启动类
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
yml配置文件
server:
port: 9000 # 端口号
eureka:
# 实例主机名可省略
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用名称。会在eureka中Application显示。
# 综合归纳:
# 1.指定默认的服务器连接地址,以获取提供方信息
# 2.定义该工程名,在服务器中以显示
# 3.指定端口号(端口号的指定是由于在同一台电脑上模拟,生产时由于分布式所以不需要指定)
Goods对象
package com.itheima.consumer.domain;
/**
* 商品实体类
*/
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
//构造器已省略
// getter/setter 已省略
}
2.提供方
控制层
/**
* Goods Controller 服务提供方
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/findOne/{id}")
public Goods findOne(@PathVariable("id") int id){
Goods goods = goodsService.findOne(id); //调用业务层,业务层调用数据库。已省略
return goods;
}
}
yml配置文件
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名 (默认名字。如果不该localhost可以不写)
prefer-ip-address: true # 将当前实例的ip注册到eureka server中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
# 提供方才需要有这个配置,因为要向服务器传输数据
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~(eureka有保护机制,如果开启则不会立即关闭,默认开启)
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
# 综合归纳:
# 1.指定端口号(端口号的指定是由于在同一台电脑上模拟,生产时由于分布式所以不需要指定)
# 2.实例信息
# 3.心跳包(发送条件&超时判断)
# 4.访问服务器地址
# 5.项目名
服务器
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
启动类
@SpringBootApplication
// 启用EurekaServer
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
yml配置文件
registry改为false 表示关闭所有与注册中心的功能
server:
port: 8761 #(默认端口)
eureka:
instance:
hostname: localhost # 主机名
#设置客户端与服务器的通信地址
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
# 下列两句是可以省略的
register-with-eureka: false # 是否将自己的路径注册到eureka上。eureka server 不需要的,eureka provider client才需要
fetch-registry: false # 是否需要从eureka中抓取路径。同上,不需要。默认为true。所以消费方没有进行设置
server:
enable-self-preservation: false # 关闭自我保护机制(调试时才关闭,方便调试)
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
# 综合归纳:
# 1.对外访问端口号(有默认值)
# 2.外部访问地址
# 3.保护机制,检测服务间隔(有默认值)
Eureka相关配置及特性
一、instance
1.instance-id: 默认使用
spring:
application:
name:hello的配置
2.
二、server
生产环境使自我保护机制开启,测试环境可以选择关闭。默认开启
Eureka集群配置
相互注册即可搭建集群,相互注册即把自己当做客户端注册到对方服务端去
由于相互注册,所以resgister-with-euraka=true和fetch-registry: true(相互都要抓取对方信息)
注意:要修改win的system32文件修改本机默认访问名localhost,如果名字不为localhost
相互注册是使用,分割
由于是单机模拟
在C:\Windows\System32\drivers\etc\hosts 文件中 修改对应的主机名localhost1、localhost2 为127.0.0.1的回环地址
注意:1.由于是集群操作,当启动服务器的时候会有一定的连接信息报错,只要全部开启后就可以消除
2.单击模拟,端口不可以冲突,要修改。以后是以ip来区分,所以以后端口是一致的
3.集群操作每个服务器的defaultZone要配置所有的访问地址
配置服务器1
server:
port: 8762 #(端口要不一致)
eureka:
instance:
hostname: localhost1 # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka, http://localhost:8762/eureka # 要配置自带的所有 如果是三台集群此处应为三台的地址
#都要设置为true 因为对方都要注册到eureka上 并且拉取到对方的信息
register-with-eureka: true
fetch-registry: true
spring:
application:
name: eureka-server-ha # 应用名要相同
配置服务器2
server:
port: 8761 #(端口要不一致)
eureka:
instance:
hostname: localhost2 # 主机名
client:
service-url:
defaultZone: http://localhost:8762/eureka,http://localhost:8761/eureka # 要配置自带的所有 如果是三台集群此处应为三台的地址
#都要设置为true 因为对方都要注册到eureka上 并且拉取到对方的信息
register-with-eureka: true
fetch-registry: true
spring:
application:
name: eureka-server-ha # 应用名要相同
客户端
只要是客户端,都要配置每一个服务器的访问地址,相互注册使用,隔开
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
项目中导入父工程两种方式
若工程只是使用SpringBoot那么仅使用即可将springBoot的依赖导入
由于一个工程只能有一个parent标签,所以当使用SpringCloud的时候,就要使用import的方式进行导入
<!--spring boot 环境 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<!--版本控制 -->
<properties>
<spring-boot-admin.version>2.1.5</spring-boot-admin.version>
</properties>
<!--引入Spring Cloud 依赖-->
<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>
Consul(历史项目)
由HashiCorp基于go语言开发
官网:www.consul.io
1.导包
消费方,提供方都要导入下包,且必须有actuator的包
<dependencies>
<!--consul 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2.开启服务
1.解压consul的文件,在consul.exe存在的目录执行该服务器 consul.exe
.\consul agent -dev 由localhost:8500 访问主页
2.启动提供方,消费方
3.定义提供方和消费方yml文件
逻辑代码与上述eureka差不多
server:
port: 8000
spring:
cloud:
consul:
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consul-provider # 应用名称
server:
port: 9000
spring:
cloud:
consul:
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consul-consumer # 应用名称
Nacos
nacos包含eureka和spring config两个功能的整合。此处只使用注册中心功能
国产阿里出品,是erueka的替代品,eruka已停更
是注册地中心+配置中心
server-addr: ip:port
1.导包
<dependencies>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
2.开启
1.解压nacos的文件,在bin目录存在的startup文件,执行即可开启服务器。(进入账户密码 默认nacos)
http://192.168.14.28:8848/nacos/index.html 访问主页
2.启动提供方,消费方
3.定义提供方和消费方yml文件
与consul一致。只是server-addr处要配置ip和端口号
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
application:
name: nacos-consumer # 服务名称 此处要区分消费方和提供方
4.注意事项
1.子父工程中 不可有其他eureka的相关组件
2.出现依赖报错,优先删除依赖重新下载
Ribbon(负载均衡)
简介
Netflix 提供的一个HTTP和TCP的客户端负载均衡工具
定义:解决eureka客户端服务负载均衡算法处理器
作用:配置和使用负载均衡,简化代码写法(从端口和ip变量–>服务名称)。
ribbon依赖在eureka依赖中已经存在
注意:是在消费方模块中进行配置!!!
使用:
1.在定义RestTemplate的@Bean处开启负载均衡功能
@LoadBalanced
2.编码时使用eureka的服务名称当作访问提供方的地址
http://服务名称/访问地址
例:http://provider/login
3.选择算法
4.启动类上方配置@RibbonClient注解或yml配置文件配置
修改负载均衡策略
配置负载均衡用哪种算法
//定义核心配置类,如果已经存在核心配置,则直接配置bean
@Configuration
public class MyRule{
//配置bean
@Bean
public IRule rule(){
return new RandomRule();
}
}
启动类上方具体配置哪个服务器要指定负载均衡策略
1.代码方式
@RibbonClient(name="eureka服务名称",configuration=自定义类.class) //省略启动类
2.yml配置方式
eureka服务名称1:
ribbon:
NFloadBalancerRuleClassName: 对应策略的全路径名
eureka服务名称2:
ribbon:
NFloadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule
//默认轮询
策略定义:
响应时间: 每个服务器都丢一个标识, 谁先响应就用谁
轮询重试: 轮询一次都失败的话,不慌响应失败。再次轮询一次,还失败则响应失败。
Feign(声明式服务调用)❤️
简介
方便实现客户端的调用,基于接口的注解方式
定义:是微服务之间通过http协议调用的工具
作用:简化消费方的restTemplat+ribbon的操作,连接
Feign是不兼容MVC注解的,所以Cloud对Feign进行了封装,为open-feign
使用方式
规范:所有的接口名、返回值和提供方一模一样。
1.导包(消费端集成openfeign)【哪里需要用远程调用就在哪里导包】此处在消费端导包
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.配置(超时配置)
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
3.编码
1) 入口类上开启Feign功能
@EnableFeignClients //开启Feign的功能
2) 编写feign接口,带返回值,告知feign用什么封装返回值
3) 在此接口上添加@Feignlient("服务名称")
作用:指定当前类的方法都从Eureka中对应的服务去调用
4) 定义方法
作用:通过该方法,最终实现与提供方的连接
//定义接口,配置注解
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class) //映射该核心类,其中可以指定日志
public interface GoodsFeignClient {
//定义方法,方法名、参数、返回值要与提供方一致(规范)
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
5) 在controller层定义接口对象,自动注入
作用:调用提供方
//在controller中自动注入,调用方法
@Autowired
private GoodsFeignClient goodsFeignClient;
编写Feign接口
// 指定当前类的方法都从Eureka中对应的服务去调用
@FeignClient("服务的名称")
public interface ProviderService {
// 通过Controller的地址映射注解告诉Feign该类findOne2方法从服务提供者的/findOne/{id}地址获取信息
// 通过Controller的参数获取注解告诉Feign的参数信息
// 通过返回值告诉Feign应该返回的参数应该封装的格式
@GetMapping("/goods/findOne/{id}")
public Goods findOne(@PathVariable("id") int id);
}
//启动类
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class,args);
}
}
其他功能
1.超时设置
feign在调用远程调用提供方时,默认超时时间时1s(Ribbon提供)。如果超时则报错
修改超时时间
在yml文件中修改
要开启注解才生效
@EnableFeignClients
//不能与hystrix的配置同时使用,否则ribbon超时不生效,均默认1s
feign:
hystrix:
enabled: true //此配置的含有是 在消费方使用降级处理,优先级大于ribbon
ribbon:
#以下两个注解会显示警告错误的颜色。不用管
connectTimeout: 1000 # 连接超时时间 消费与提供的连接时间
ReadTimeout: 3000 # 逻辑处理超时时间,连接后提供方处理时间
2.日志功能
feign只能记录debug级别的日志信息
使用
必须开启对应feign接口包的日志为debug
1.配置文件中定义日志是全部/部分开启
2.核心配置类中定义Logger.Level的@Bean对象
3.在启动类上定义@FeignClient(configuration=核心配置类.class)
开启全部(调试)
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
root: debug
开启部分(生产)
logging:
level:
com.XXX: debug # 指定某个包,仅对该包进行debug日志输出
编码
1.定义日志级别(4个级别)
/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据
所有等级都向上包含
*/
@Configuration
public class FeignLogConfig {
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
2.配置生效
// Feign接口上方配置 configuration属性
@FeignClient(value = "FEIGN-PROVIDER",configuration = 核心配置类.class)
Hystrix熔断器
简介
Netflix 开源的一个延迟和容错库
作用:用于隔离访问远程服务,用来在微服务中防止出现级联调用引起雪崩的技术工具(预防雪崩)
功能概述
1.隔离:防止被一锅端。隔离不同调用链之间相互不受影响
线程池隔离:把线程池数量按照eureka客户端个数分为不同的小池子,即使一个池子线程用完不会影响其他小池子
信号量隔离: 指定一个eureka客户端的可访问人数,全部挂掉则均不再对其进行访问
2.降级:封装友好的错误提示并返回。
分为提供方降级方案(内部异常时给出的降级提示)和消费方自己的降级方案(网络不好时给出的降级提示)
作用: 遇到异常,超时的时候,可以对请求有所返回
3.熔断:某一时间内,错误请求数量溢出,自动降级熔断
4.限流:合理分配每个调用的并发请求数量
主要使用
降级、熔断功能
1.降级
消费方降级
导包
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
配置
//在核心配置类上开启降级功能
@EnableCircuitBreaker
编码
1.提供降级方法
2.在要降级的方法上配置对应降级方法注解
降级规则:
1.降级方法必须和正常处理方法返回值和参数一致
2.正常处理方法出现异常或超时时进行降级
3.可以设置,不是所有的异常都要降级处理。注解中有一个ignoreException属性
/**
* Goods Controller 服务提供方
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
//自动注入业务层对象
@Autowired
private GoodsService goodsService;
@Value("${server.port}")
private int port;
/**
* 降级:
* 1. 出现异常
* 2. 服务调用超时
* * 默认1s超时
*
* @HystrixCommand(fallbackMethod = "findOne_fallback")
* fallbackMethod:指定降级后调用的方法名称
*/
//定义次方法的@HystrixCommand注解,错误回调方法
// 双击shitf中 搜索 HystrixCommandProperties 可以查看更多与timeoutInMilliseconds配置相关的定义
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,熔断默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//监控时间 默认5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败次数。默认20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失败率 默认50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
public Goods findOne(@PathVariable("id") int id){
//1.造个异常
int i = 3/0;
try {
//2. 休眠2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//调用业务层
Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
return goods;
}
/**
* 定义降级方法:
* 1. 方法的返回值需要和原方法一样
* 2. 方法的参数需要和原方法一样
*/
public Goods findOne_fallback(int id){
Goods goods = new Goods();
goods.setTitle("降级了~~~");
return goods;
}
}
提供方降级
由于提供方需要使用feign调用消费发,而feign内部已经集成了hystrix
如果未使用feign,那么使用上面的方法即可实现降级
yml文件开启降级处理(开启hystrix功能)
# 开启feign对hystrix的支持 默认为false
feign:
hystrix:
enabled: true
定义feign接口和实现类
注意:
0.在核心配置类上开启降级功能@EnableCircuitBreaker
1.实现类要@Component存入容器
2.接口中定义实现类,定义注解属性
3.如果提供方已经配置过降级策略,那么消费方就不会生效【优先在提供方配置降级】(因为已经在提供方处返回了一个正确结果对象)
//核心配置类
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient //eureka客户端
@SpringBootApplication
@EnableFeignClients //开启Feign的功能
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
//定义feign接口
//定义feign注解,指定从eruka中获取ip,错误时的回调
@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {
//定义调用提供方方法,此处的路径是由前端调用的id--> {id}--> 通过该路径传输到提供方调用
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
//feign接口实现类
@Component //存入ioc中方便自动注入
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public Goods findGoodsById(int id) {
Goods goods = new Goods();
goods.setTitle("又被降级了~~~");
return goods;
}
}
2.熔断
熔断无需配置,底层已经自动封装配置成为一种机制。熔断后再来的请求会执行降级方法!
熔断机制概念
注意: 想要实现熔断机制,必须要开启hytrix注解
//在核心配置类上开启降级功能
@EnableCircuitBreaker
当失败情况达到预定的阈值(5秒内20次请求,50%失败),会打开断路器,拒绝所有请求,以降级的方法返回(熔断器打开)默认5s,默认时间后会放行一些请求(熔断器半开)测试是否恢复正常,不正常继续拒绝请求5s,直到服务恢复正常为止(熔断器关闭)。
// XXXPorperties类中查看所有属性值(HystrixCommandProperties含有所有属性)
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//监控时间 默认5000 秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败次数。默认20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失败率 默认50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
熔断监控
用于实时监控微服务运行状态
dashboard 监控一个
Turbine 聚合监控
资料中有搭建步骤
gateway网关❤️
为微服务架构提供一种简单又有效的API路由管理方式
三次握手。四次挥手
文档网址
https://blog.csdn.net/sinat_41144773/article/details/88314735
//两种协议的区别
TCP 和 UDP是网络协议的传输层上的两种不同的协议。TCP的特点是面向连接的、可靠的字节流服务。客户端需要和服务器之间建立一个TCP连接,之后才能传输数据。数据到达之前对方就一直在等待,除非对方直接关闭连接,数据有序,先发先到。UDP是一种无连接、不可靠的数据发送协议。发送方根据对方的ip地址发送数据包,但是不保证接收发接包的质量,数据无序还容易丢包。虽然UDP协议不稳定但是在即时通讯(QQ聊天、在线视频、网络语音电话)的场景下,可以允许偶尔的断续,但是这种协议速度快。
//握手
第一次握手:
客户端发送第一个包,其中SYN标志位为1, ACK=0,发送顺序号sequence=X(随机int)。客户端进入SYN发送状态,等待服务器确认。
第二次握手:
服务器收到这个包后发送第二个包,其中包SYN、ACK标志位为1,发送顺序号seq=Y(随机int),接收顺序号ACK=X+1,此时服务器进入SYN接收状态。
第三次握手:
客户端收到服务器传来的包后,向服务器发送第三个包,SYN=0, ACK=1,接收顺序号ACK = Y+1,发送顺序号seq=X+1。此包发送完毕,客户端和服务器进入ESTABLISHED建立成功状态,完成三次握手。
//挥手
四次握手是指终止TCP连接协议时,需要在客户端和服务器之间发送四个包
第一次挥手:主动关闭方发送第一个包,其中FIN标志位为1,发送顺序号seq为X。
第二次挥手:被动关闭方收到FIN包后发送第二个包,其中发送顺序号seq为Z,接收顺序号ack为X+1。
第三次挥手:被动关闭方再发送第三个包,其中FIN标志位为1,发送顺序号seq为Y,接收顺序号ack为X。
第四次挥手:主动关闭方发送第四个包,其中发送顺序号为X,接收顺序号为Y。至此,完成四次挥手。
为什么必须是三次握手,不能用两次握手进行连接?
记住服务器的资源宝贵不能浪费! 如果在断开连接后,第一次握手请求连接的包才到会使服务器打开连接,占用资源而且容易被恶意攻击!防止攻击的方法,缩短服务器等待时间。两次握手容易死锁。如果服务器的应答分组在传输中丢失,将不知道S建立什么样的序列号,C认为连接还未建立成功,将忽略S发来的任何数据分组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
定义
是前端js页面与后台沟通的桥梁,由网关来进行通信
定义:前端统一访问微服务的入口
作用:提供认证、鉴权、日志、监控、缓存、负载均衡、流量控制功能
(由于是入口,所以关系着网络请求速度,添加功能的时候要三思)
使用步骤
创建一个网关工程
1.导包
<dependencies>
<!--引入gateway 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka-client 从注册中心获取提供方信息-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2.配置
告诉网关哪些请求转发到哪儿去,ip从eureka获取
server:
port: 80
spring:
application:
name: api-gateway-server # 网关在服务器中显示的名字
cloud:
# 网关配置
gateway:
# 路由配置:转发规则
routes: #集合。
# id: 唯一标识。默认是一个UUID
# uri: 当前路由转发的路径
# predicates: 条件,用于请求网关路径的匹配规则
# filters:配置局部过滤器的
- id: gateway-provider
# 静态路由
# uri: http://localhost:8001/
# 动态路由
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters:
- AddRequestParameter=username,zhangsan
# - AddRequestParameter=age,23
- id: gateway-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
# 微服务名称配置(了解) 【作用:在访问路径前加上自己的eureka服务器名称】
# discovery:
# locator:
# enabled: true # 设置为true 请求路径前可以添加微服务名称
# lower-case-service-id: true # 允许为小写
# 配置网关从eureka获取信息的地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
静动态路由
# 静态路由
uri: http://localhost:8001/ # 写死就是静态路由
# 动态路由
uri: lb://GATEWAY-PROVIDER # 使用lb协议:// 服务名称 为动态路由
网关过滤器
作用:对请求做过滤增强(认证、设置凭证信息等)
具体配置方式在使用步骤中可以查看
注意:
网关过滤器的默认端口是80
如果要使用网关访问,那么必须用该端口来访问
localhost:80/goods/2
-
局部过滤器:只对配置的路由进行生效
-
org.springframework.cloud.gateway.filter.factory.过滤器名称GatewayFilterFactory
#在yml文件中,使用过滤器名称进行配置 # 过滤器 此处含义是为原始请求添加请求参数 filters: - AddRequestParameter=username,zhangsan - AddRequestParameter=age,23
-
-
全局过滤器:所有请求都生效(常用)
- GlobalFilter
- Ordered指定过滤器执行的顺序,越小越先执行)
- 不放行如何?
实现接口 GloblFilter
Ordered 按照该接口的重写方法来判定那个过滤器先后执行
步骤:
1.定义实现类 实现 GlobalFilter, Ordered接口
2.在重写方法中写代码逻辑
3.将该实现类存入ioc中
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定义全局过滤器执行了~~~");
return chain.filter(exchange);//放行
}
/**
* 过滤器排序
* @return 数值越小 越先执行
*/
@Override
public int getOrder() {
return 0;
}
}
官方文档
查看所有网关的过滤器
- https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#_gatewayfilter_factories
- 查看笔记文档
config❤️
定义: 在分布式场景下统一管理和维护配置的系统
作用:1.通过配置文件动态更新配置的属性
2.配置信息改变时,不需要重启即可更新配置信息
使用步骤
1.环境搭建
1)导包
注意:如果是公有仓库,要使用http的传输格式,而不是SSH
<!-- 导包 -->
服务端 config-server
<!-- config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
客户端 provider/consumer
<!--config client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
克隆到本地仓库
2)localrepository–>gitee
必须以此文件名格式定义: config-dev.yml 格式必须是yml
(config默认8888端口)
# 1.创建文件夹从远程仓库中克隆,使该文件夹成为初始化仓库。
上传对应配置文件到码云中 # 文件名格式 config-dev.yml
# 访问: http://localhost:9527/master/config-dev.yml
2.客户端搭建
client–>config --> gitee 客户端启动时从config中获取文件,config根据客户端的bootstrap文件从gitee获取yml
# 1.在对应的客户端上导入 config依赖
# 2.配置bootstrap.yml文件( 读取顺序: bootstrap > application)
1.configserver的url
2.需要使用的文件名称 name: config
3.profile: 环境名 dev
4.lable: 分支名 master
测试时,启动eureka,否则会报错
# 客户端
# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
cloud:
config:
# 配置config-server地址,客户端自动去该地址获取配置文件
uri: http://localhost:9527
# 配置获得配置文件的名称等信息
# 文件名称 config-dev.yml 可以分解为如下信息 底层会对如下信息进行拼接处理
name: config # 文件名
profile: dev # profile指定
label: master # 分支名
# 暴露,此处*已经含有refresh的功能
management:
endpoints:
web:
exposure:
include: '*'
3.服务端搭建
配置文件
config --> gitee 服务端获取gitee仓库地址
#服务端
server:
port: 9527 # 默认8888
spring:
application:
name: config-server
# spring cloud config
cloud:
config:
server:
# git 的 远程仓库地址
git:
uri: https://gitee.com/itheima_cch/itheima-configs.git
label: master # 分支配置
开启服务
# 启动类上开启config服务
@EnableConfigServer
4.客户端刷新
此刷新必须手动刷新,如果要自动刷新需要配合bus一起使用才能完成
如果不配置刷新功能,配置文件修改后,只更新config-server,不会更新客户端(除非重启)
可以刷新的必要条件
1.客户端必须导入actuator依赖
2.添加注解@RefreshScope(哪里需要从码云上获取配置,就在哪里加注解)
3.客户端暴露refresh配置
4.输出指令 curl -X POST htppt://ip名:客户端端口/actuator/fresh 【回车后出现一个数组[]的内容,则表示成功】
//在客户端启动类上开启刷新注解
//(哪里需要从码云上获取配置,就在哪里加注解,此处是controller上加注解,因为需要用到配置中的常量信息)
@RequestMapping("/goods")
@RefreshScope // 开启刷新功能
public class GoodsController {
@Autowired
private GoodsService goodsService;
@Value("${server.port}")
private int port;
@Value("${itheima}")
private String itheima;
}
Bus❤️
定义:属于spring cloud 的一个组件,微服务之间进行通信的组件(用轻量的消息中间件将分布式的节点连接起来)
作用:用于广播配置文件的更改或者服务的监控管理(通过bus组件对所有下属模块进行操作)
Spring Cloud Bus 可选的消息中间件包括 RabbitMQ 和 Kafka
Bus与Feign的区别
bus基于http协议 feign是消息协议。消息协议有很多
通信原理
与config-server结合使用(运维发送消息给config,config传送信息给MQ–> 给bus 再全局对客户端进行更新操作)
此图中的ABC和Config-server都是被eureka所管理的
使用步骤
1.导包
该包已集成 MQ
只要是有配置文件的 都需要导入bus依赖
<!-- bus -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.客户端配置
在config的配置文件中中配置MQ信息、暴露endpoints
# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
cloud:
config:
# 配置config-server地址
# uri: http://localhost:9527 由于已经被eureka所管理,所以直接从eureka获取地址
# 配置获得配置文件的名称等信息
name: config # 文件名
profile: dev # profile指定, config-dev.yml
label: master # 分支
# 从注册中心去寻找config-server地址
discovery:
enabled: true
service-id: CONFIG-SERVER # 根据在eureka中的应用名来获取config-server地址
#配置rabbitmq信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# 暴露 含bus-refresh
management:
endpoints:
web:
exposure:
include: '*'
3.服务端配置
server:
port: 9527
spring:
application:
name: config-server
# spring cloud config
cloud:
config:
server:
# git 的 远程仓库地址
git:
uri: https://gitee.com/itheima_cch/itheima-configs.git
label: master # 分支配置
#配置rabbitmq信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# 将自己注册到eureka中
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
# 暴露bus的刷新端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
4.使用命令
作用:刷新消息总线
注意:在config-server服务器的地址中输入命令
curl -X POST htppt://ip名:客户端端口/actuator/bus-fresh 【回车后出现一个数组[]的内容,则表示成功】
Stream
定义
一个SpringCloud的组件,是对消息中间件进一步的统一封装。构建消息驱动微服务应用的框架。
作用
简化消息中间件的使用过程,使其标准统一。(JDBC也是一种对不同的数据库访问做的统一封装)。如果要更换消息中间件,可以无改动的实现与MQ和kafka的切换。因为Steam目前只对这两种中间件进行了封装
(由于要对消息中间件做不同程度的优化,所以在工作中会直接使用消息中间。【了解】)
Stream组成原理
使用binder绑定中间件服务Middleware,通过input读取消息,再使用output发送消息。通过NIO中的channel来通信,每一个channel就是途中的一个管道(input: source接口; output:sink接口)
Sleuth+Zipkin 链路追踪
定义与作用
sleuth是Sring Cloud的一个工具。根据捕获的数据,用Zipkin生成一个调用链的视图。
Zipkin是推特的一个开源项目。一款视图工具 ,把数据进行展示。
入门
服务端(zipkin)
java -jar 运行该zipkin的jar包
运行成功就可以进入 http://localhost:9411/
客户端(sleuth)
1.导zipkin包(其中已经依赖sleuth)
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-consumer # 设置当前应用的名称。
#以下是zipkin、sleuth配置信息
zipkin:
base-url: http://localhost:9411/ # 设置zipkin的服务端路径 在哪里找到zipkin
# sleuth的采样率(根据需求,批准请求能够进入zipkin内部转换为图表显示的占比)
sleuth:
sampler:
probability: 1 # 采集率 默认 0.1 百分之十。
cloud:
config:
server:
# git 的 远程仓库地址
git:
uri: https://gitee.com/itheima_cch/itheima-configs.git
label: master # 分支配置
#配置rabbitmq信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
将自己注册到eureka中
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
暴露bus的刷新端点
management:
endpoints:
web:
exposure:
include: ‘bus-refresh’
#### 4.使用命令
作用:刷新消息总线
注意:在config-server服务器的地址中输入命令
```shell
curl -X POST htppt://ip名:客户端端口/actuator/bus-fresh 【回车后出现一个数组[]的内容,则表示成功】
Stream
定义
一个SpringCloud的组件,是对消息中间件进一步的统一封装。构建消息驱动微服务应用的框架。
作用
简化消息中间件的使用过程,使其标准统一。(JDBC也是一种对不同的数据库访问做的统一封装)。如果要更换消息中间件,可以无改动的实现与MQ和kafka的切换。因为Steam目前只对这两种中间件进行了封装
(由于要对消息中间件做不同程度的优化,所以在工作中会直接使用消息中间。【了解】)
Stream组成原理
[外链图片转存中…(img-G4YMfDB0-1602550851504)]
使用binder绑定中间件服务Middleware,通过input读取消息,再使用output发送消息。通过NIO中的channel来通信,每一个channel就是途中的一个管道(input: source接口; output:sink接口)
Sleuth+Zipkin 链路追踪
定义与作用
sleuth是Sring Cloud的一个工具。根据捕获的数据,用Zipkin生成一个调用链的视图。
Zipkin是推特的一个开源项目。一款视图工具 ,把数据进行展示。
入门
服务端(zipkin)
java -jar 运行该zipkin的jar包
运行成功就可以进入 http://localhost:9411/
客户端(sleuth)
1.导zipkin包(其中已经依赖sleuth)
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-consumer # 设置当前应用的名称。
#以下是zipkin、sleuth配置信息
zipkin:
base-url: http://localhost:9411/ # 设置zipkin的服务端路径 在哪里找到zipkin
# sleuth的采样率(根据需求,批准请求能够进入zipkin内部转换为图表显示的占比)
sleuth:
sampler:
probability: 1 # 采集率 默认 0.1 百分之十。