Quarkus
- GreetingResourceTest是在jvm中测试
面试常问
CAP理论:任何一个分布式系统都无法做到一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)全部满足。
- C数据一致
- A读写操作必须都能成功
- P分区容错,当分布式系统节点之间出现网络故障导致节点之间无法通信,导致出现了分区 必须要满足的
BASE理论:
- 基于BASE理论的柔性事务,不同于ACID的刚性事务,通过一些新的方案,只要保证最终一致性即可
AP:无需锁定数据,实现最终一致即可
CP:各个子事务执行后不要提交,锁定资源,不允许其他人访问。
SpringCloud
分布式事务:
- 接口幂等性:接口的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。
- XA/两阶段提交:
- 第一阶段:存在一个负责协调各个本地资源管理的事务管理器,事务管理器在第一阶段询问各个资源管理器是否就绪,如果收到的没辙资源的回复都是yes,在在第二阶段提交事务时,任意一个回复no就回滚事务
- 第二阶段:事务管理器根据所有本地资源管理器的返回,通知所有本地资源管理器,步调一致的在所有分支上提交或者回滚事务
- 缺点:
- 同步阻塞:当参与事务者存在占用公共资源的情况,齐总一个占用了资源,其他参与者只能等待资源释放,处于阻塞装填。
- 单点故障:一旦事务管理器故障,整个系统都不可用了
- 数据不一致:在阶段二如果事务管理器只发送了部分commit消息,如果出现网络异常,那么只有部分参与者会提交事务
- 不确定性:当协事务管理器发送 commit 之后,并且此时只有一个参与者收到了 commit,那么当该参与者与事务管理器同时宕机之后,重新选举的事务管理器无法确定该条消息是否提交成功。
- TCC Try-Confirm-Cancel
- Try 阶段:尝试执行,完成所有业务检查(一致性), 预留必须业务资源(准隔离性)
- Confirm 阶段:确认执行真正执行业务,不作任何业务检查,只使用 Try 阶段预留的业务资源,Confirm 操作满足幂等性。要求具备幂等设计,Confirm 失败后需要进行重试。
- Cancel 阶段:取消执行,释放 Try 阶段预留的业务资源 Cancel 操作满足幂等性 Cancel 阶段的异常和 Confirm 阶段异常处理方案基本上一致。
- 本地消息表:依靠MQ实现
路由:
- gateway
- 配置
id
:路由的唯一标示predicates
:路由断言,其实就是匹配条件filters
:路由过滤条件,后面讲uri
:路由目标地址,lb://
代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。
- 配置
- gateway
Nacos:
- namespace:用于环境隔离
- 分级模型:
- namespace 命名空间
- group分组
- 服务service
- 集群cluster 对应不同的机房/ip
- 实例instance:
- 集群cluster 对应不同的机房/ip
- 服务service
- group分组
- namespace 命名空间
- Nacos挂了能不能正常访问:答案是能,Nacos会把注册的服务的地址推送给他们,他们各自维护一个列表,所以Nacos挂了也不影响调用
- nacos和eureka的区别:
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被删除,非临时实例不会呗删除
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos默认使用AP方式,
- nacos读取配置的流程
- 配置热更新:
- namespace:用于环境隔离
OpenFeign:
- 执行过程:
- 获取请求中的serviceId
- 根据serviceId负载均衡,找到一个可用的服务实例
- 利用服务实例ip和port信息重构url
- 向真正的url发起请求
- 执行过程:
负载均衡:
- 使用LoadBalancer实现负载均衡
- 使用Ribbon组件实现:发起远程调用时,ribbon先从注册中心拉取服务地址列表,然后按照一定的路由策略选择一个发起远程调用,
- Ribbon发负载均衡策略: 已经被集成到Eureka-client和Nacos-Discovery中,后来被废弃,使用LoadBalancer了,OpenFeign也整合了LoadBalancer
- 轮询,根据权重选择,随机选择一个可用的,
- 区域敏感策略,以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询(默认)
服务保护
- Sentinel:
- 线程隔离:
- 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身进行隔离
- 支持主动超时,支持异步调用
- 缺点是线程的额外开销较大
- 使用场景低扇出
- 信号量隔离:不创建线程池而是使用计数器模式,记录业务使用的线程数量,打到信号量上限时,禁止新的请求
- 优点:轻量级,无额外开销
- 缺点:不支持主动超时,不支持异步调用
- 适合高频调用高扇出(一个服务需要调用其他许多服务,那么我们就可以说这个服务有高扇出)
- 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身进行隔离
- 限流:
- 滑动窗口算法:
- 令牌桶算法:
- 固定速率生成令牌,桶满了就舍弃,每个请求必须向桶中获取令牌才能被处理,没有获得令牌的请求等待或者丢弃
- 一般情况下每秒产生的令牌数量就是QPS上限,但是当前这一秒没有请求进入,下一半秒涌入了超过2N个请求,然后这一秒生成了N个令牌,所以放行了2N个请求,超过了阈值,所以要预留一定的波动空间
- 漏桶算法:请求放入队列中,以固定的速率去取出并处理请求。
- 线程隔离:
- 限流:
- 使用nginx基于漏桶实现限流
- 使用gateway 的令牌桶算法,根据ip或者路径进行限流
- Feign整合sentinel,在配置文件中开启即可
- 熔断:对于超过QPS上限的请求或者延迟较高的请求,对其进行熔断,同时设置一个降级处理逻辑。
- closed关闭装填,放行所有请求,并开始统计异常比例、满请求比例,超过阈值切换到open
- open服务调用被熔断,访问这个被熔断的请求会被拒绝,快速失败,走降级逻辑。持续一段时间之后转到half-open
- half-open 半开模式,放行一次请求,根据执行结果来判断接下来的操作
- 请求成功:切换到closed状态
- 请求失败:切换到open状态
- Sentinel:
分布式事务:
- 使用seata解决分布式事务:
- seata有三个重要角色:
- TC 事务协调者:维护全局和分支失物的状态,协调全局事务的
- TM 事务管理器:定义全局事务的范围,开始全局事务,提交或回滚全局事务
- RM 资源管理器:管理分支事务,与TC交谈以注册分之十五和报告分支事务的状态,并驱动分支事务的提交和回滚
- xa模式:
- RM一阶段工作:
- 注册分支事务到TC
- 执行分支事务sql但不提交
- 报告执行状态到TC
- TC二阶段工作:
- TC检测各分支事务执行状态
- 如果都成功则通知所有RM提交事务
- 如果都失败则通知所有RM回滚事务
- TC检测各分支事务执行状态
- RM二阶段工作:
- 接收TC指令,提交或回滚事务
- 优点:强一致性,没有代码侵入
- 缺点:一阶段需要锁定数据库资源,等待二阶段结束才释放,性能差
- 依赖关系型数据库实现事务
- RM一阶段工作:
- at模式:
- 阶段一RM:
- 注册分支事务,
- 记录undo-log 快照数据
- 执行业务sql并提交
- 报告事务状态
- 二阶段
- 阶段而提交时RM工作:删除undo-log
- 回滚时,RM工作:根据undo-log恢复数据到更新前
- 阶段一RM:
- 两者区别:
- XA一阶段不提交事务,锁定资源,AT一阶段提交事务,不锁定资源
- XA模式伊利数据库实现回滚,AT模式利用数据快照实现数据回滚
- XA模式强一致性,AT模式最终一致
- TCC模式:TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复。需要实现三个方法:
try
:资源的检测和预留;confirm
:完成资源操作业务;要求try
成功confirm
一定要能成功。cancel
:预留资源释放,可以理解为try的反向操作。- 优点:一阶段完成直接提交事务,释放资源,无需快照,无需依赖数据库事务,可用于关系型数据库
- 缺点:代码侵入严重,软状态,事务最终一致
- seata有三个重要角色:
- 使用seata解决分布式事务:
接口幂等性:
- 使用token+redis实现接口幂等性,第二次请求之后每次请求都会携带之前的token,后台先对redis进行验证,如果存在token则执行业务,同时删除token,如果不存再则直接返回,保证了幂等性,保证了同一个token只处理一次业务
MQ:
- 组成
- producer消息的生产者
- broker 消息的保存
- consumer 消息的消费者
- 选择:
Kafka面试题
- 如何保证消息不丢失:
- producer时,可以使用异步回调发送,如果消息发送失败,我们可以通过回调获取失败后的消息信息,可以重试或者记录日志,也可以后续进行不成
- broker中消息丢失,通过kafka的复制机制来保证消息不丢失,在生产者发送消息的时候,可以设置一个acks的参数位all,这样就会在broker的leader和foller分区都保存确认,只有所有的副本都确认之后才算是成功过发送了消息
- consumer时使用pull,还是push:
- Kafka使用了pull模式,consumer可以自主决定是否批量从broker拉取数据。push为了避免consumer崩溃而采用较低的推送速率,到一次只推送较少的消息造成浪费,pull模式下,consumer可以根据自己的消费能力而去决定如何拉取消息
- 缺点:如果broker没有提供可消费的消息,将导致consumer不断循环中轮询,直到最新消息到达。
- Kafka可以有个参数可以让consumer阻塞知道新消息的到达,或者阻塞直到消息的数量到达某个特定的量就可以批量发送。
- Kafka将Topic分成了若干分区,每个分区同一时间只能被有一个consumer消费,意味着每个分区被消费的消息在日志中的位置仅仅是有一个简单的整数:offset ,consumer可以把offset调成一个较老的值,从而重新消费老消息
- 主从复制:一个topic可以有多个副本
- 主节点将消息写入本地日志,从节点从主节点拉取信息,写入本地日志,之后向主节点发送确认消息,如果主节点收到所有从节点的确认消息,该消息就会被认为是已提交的,主节点会更新自己的高水位,消费者只能消费已提交的消息
- 优点:保证了主节点崩溃消息也不会丢失
- 脑裂问题:
- 只有领导者负责处理生产者和消费者的读写请求,追随者只能从领导者那里复制数据
- Kafka的选举是由ZooKeeper协调的,ZooKeeper可以保证在任何时候只有一个领导者被选举出来
- Zookeeper是如何做到的?
- 当Zookeeper启动或者领导者崩溃时,所有的Zookeeper节点都会进入选举状态
- 投票阶段:每个节点会将自己作为领导者后端,然后发送投票信息给其他节点,当一个节点收到其他节点的投票信息是,如果ZXID更大,也就是收到的消息更,会更新自己的投票信息,并将新的投票信息发送给其他节点
- 确定阶段:当一个节点收到超过半数节点的相同投票信息中,他就认为选举结束,选举出的领导者就是投票信息中的候选节点,然后将结果发送给其他节点。
- 消息重复消费如何解决
- kafka都是按照offset进行标记消费的,消费者默认是自动按期提交已经消费的偏移量,如果出现重复消费的问题,我们需要禁用自动提交offset,改为手动提交,消费成功后报告给broker,为了维护消息的幂等性,我们可以设置唯一主键进行区分,或者是枷锁,数据库的锁或者是Redis的分布式锁都能解决幂等问题。
- 如何保证消息的顺序性:
- 将消息都存储在同一个分区下
- 发送消息时按照相同的业务设置相同的key,默认的分区是通过key的hashcode值来选择分区的,如果hash值一样,分区也是一样的。
- 高可用:
- 集群:多个broker,即使一台宕机,其他可以继续服务
- broker如何实现消息同步?
- 主从同步,Leader Broker接受消息后,将消息写入本地日志,Follower拉取消息,写入本地日志,当所欲的ISR(同步复制保存的follower)都完成,Leader就会向生产者发送确认消息。
- 通过过程中Leader宕机了,该怎么办?
- Kafka回从ISR列表中选择一个新的Leader,ISR列表中的都是已经同步最新数据的副本,当Follower同步完成后,会重新加入到ISR列表中。
- broker如何实现消息同步?
- 数据清洗:
- 日志清洗:
- 根据消息保留时间,超过指定时间触发清洗,默认是168小时
- 根据topic存储的数据大小,大于一定法制,开始删除最久的消息,默认关闭。
- 日志清洗:
- 高性能设计:
- 消息分区:不受单台服务器限制,处理更多数据
- 顺序读写:顺序读写,提高读写效率
- 页缓存:磁盘中的数据缓存到内存,把磁盘的访问变为对内存的访问
- 零拷贝:减少上下文切换及数据拷贝
- 消息压缩:减少磁盘IO和网络IO
- 分批发送:分批发送,将消息打包批量发送,减少网络开销
- 集群:多个broker,即使一台宕机,其他可以继续服务
SpringCloud
注册中心
- 方便更改微服务的ip和 端口号
- 如果存在多个服务,可以配置负载均衡
- 方便维护
服务注册中心:实现微服务之间的动态注册与发现
consul
功能:
- 服务发现 支持 http和dns
- 健康监测
- KV存储 配置
- 多数据中心
- 可视化Web界面
在main方法上使用 @EnableDiscoveryClient
controller 层上public static final String PaymentSrv_URL = "http://cloud-payment-service";//服务注册中心上的微服务名称
consul agent -dev 进入开发者模式 localhost:8500
<!--SpringCloud consul discovery --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>
RestTemplate提供了多种便捷访问远程Http服务的方法,####Spring Cloud Consul for Service Discovery spring: cloud: # 服务注册 consul: # consul注册中心 host: localhost # consul地址 port: 8500 # consul端口 discovery: # 服务发现 service-name: ${spring.application.name} # 服务名称
是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集
applicaiton.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更加高
Spring Cloud会创建一个“Bootstrap Context”,作为Spring应用的Application Context
的父上下文。初始化的时候,Bootstrap Context
负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment
。
Bootstrap
属性有高优先级,默认情况下,它们不会被本地配置覆盖。 Bootstrap context
和Application Context
有着不同的约定,所以新增了一个bootstrap.yml
文件,保证Bootstrap Context
和Application Context
配置的分离。
spring:
application:
name: cloud-payment-service
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
config:
profile-separator: '-' # default value is ",",we update '-'
format: YAML
# config/cloud-payment-service/data
# /cloud-payment-service-dev/data
# /cloud-payment-service-prod/data
application.yml文件改为bootstrap.yml,这是很关键的或者两者共存
因为bootstrap.yml是比application.yml先加载的。bootstrap.yml优先级高于application.yml
- consul kv写法
- config/配置文件/data 里面写配置
- 动态刷新:在main上写 : @RefreshScope
问题: 重启consul之后,配置丢失,如何持久化配置?
负载均衡
- 客户端负载和服务器负载
loadbalancer本地负载均衡客户端 VS Nginx服务端负载均衡区别
Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求,即负载均衡是由服务端实现的。
loadbalancer本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。
- LoadBalancer 在工作时分成两步:
第一步,先选择ConsulServer从服务端查询并拉取服务列表,知道了它有多个服务(上图3个服务),这3个实现是完全一样的,
默认轮询调用谁都可以正常执行。类似生活中求医挂号,某个科室今日出诊的全部医生,客户端你自己选一个。
第二步,按照指定的负载均衡策略从server取到的服务注册列表中由客户端自己选择一个地址,所以LoadBalancer是一个客户端的负载均衡器。
<!--loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
访问时即可在多个服务器中切换
均衡算法默认为轮询:
可以切换为随机算法:
修改RestTemplateConfig:
@Configuration
@LoadBalancerClient(
//下面的value值大小写一定要和consul里面的名字一样,必须一样
value = "cloud-payment-service",configuration = RestTemplateConfig.class)
public class RestTemplateConfig
{
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
OpenFeign
Feign是一个声明性web服务客户端。它使编写web服务客户端变得更容易。使用Feign创建一个接口并对其进行注释。它具有可插入的注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud添加了对Spring MVC注释的支持,以及对使用Spring Web中默认使用的HttpMessageConverter的支持。Spring Cloud集成了Eureka、Spring Cloud CircuitBreaker以及Spring Cloud LoadBalancer,以便在使用Feign时提供负载平衡的http客户端。
OpenFeign能干什么
前面在使用SpringCloud LoadBalancer+RestTemplate时,利用RestTemplate对http请求的封装处理形成了一套模版化的调用方法。**但是在实际开发中,**
由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,OpenFeign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在OpenFeign的实现下,我们只需创建一个接口并使用注解的方式来配置它(在一个微服务接口上面标注一个**_@FeignClient_**注解即可),即可完成对服务提供方的接口绑定,统一对外暴露可以被调用的接口方法,大大简化和降低了调用客户端的开发量,也即由服务提供者给出调用接口清单,消费者直接通过OpenFeign调用即可,O(∩_∩)O。
OpenFeign同时还集成SpringCloud LoadBalancer
可以在使用OpenFeign时提供Http客户端的负载均衡,也可以集成阿里巴巴Sentinel来提供熔断、降级等功能。而与SpringCloud LoadBalancer不同的是,通过OpenFeign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
- 引入依赖:
<!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
- 配置文件
main函数上使用server: port: 80 spring: application: name: cloud-consumer-openfeign-order ####Spring Cloud Consul for Service Discovery cloud: consul: host: localhost port: 8500 discovery: prefer-ip-address: true #优先使用服务ip进行注册 service-name: ${spring.application.name}
api接口上使用:@EnableDiscoveryClient //该注解用于向使用consul为注册中心时注册服务 @EnableFeignClients//启用feign客户端,定义服务+绑定接口,以声明式的方法优雅而简单的实现服务调用
@FeignClient(value = “xxx”) - 超时控制
sspring: cloud: openfeign: client: config: # default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间 default: #连接超时时间 connectTimeout: 4000 #读取超时时间 readTimeout: 4000 # 为serviceC这个服务单独配置超时时间,单个配置的超时时间将会覆盖全局配置 serviceC: #连接超时时间 connectTimeout: 2000 #读取超时时间 readTimeout: 2000
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以,
通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
CircuitBreaker 断路器
配置参考
断路器的状态:
- CLOSED
- OPEN
- HALF_OPEN 半开
pox<!--resilience4j-circuitbreaker--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency> <!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
分布式链路追踪
原因:
ZipKin概述
Zipkin是一种分布式链路跟踪系统图形化的工具,Zipkin 是 Twitter 开源的分布式跟踪系统,能够收集微服务运行过程中的实时调用链路信息,并能够将这些调用链路信息展示到Web图形化界面上供开发人员分析,开发人员能够从ZipKin中分析出调用链路中的性能瓶颈,识别出存在问题的应用程序,进而定位问题和解决问题
运行: java -jar zipkin-server-3.0.0-rc0-exec.jar
网关
执行流程:
- 路由判断:用户端的请求到达网关之后,根据Gateway Handler Mapping 处理,会进行断言判断
- 路由过滤:很多Handler 组成的Fileter Chain
- 服务处理:后端服务会对请求进行处理
- 响应过滤:返回给-Gateway的过滤器会再次进行处理,逻辑上可以乘坐Post-Filters
- 响应返回:响应经过过处理之后,返回给客户端
- 作用
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
Spring Cloud Gateway如何实现动态路由
可以使用Nacos作为注册中心去动态更改
配置的路由断言类型
Gateway过滤器的类型
- Pre类型:在请求被转发到微服务之前及逆行拦截和修改
- Post : 微服务处理请求之后,返回响应给网关,网关可以再次进行处理,例如修改相应内容或者响应头,日志输出,流量监控
或者 - GatewayFilter:局部过滤器,应用在单个路由或者一组路由上的过滤器
- GlobalFilter:全局过滤器
pom
yml<!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
server: port: 9527 spring: application: name: cloud-gateway #以微服务注册进consul或nacos服务列表内 cloud: consul: #配置consul地址 host: localhost port: 8500 discovery: prefer-ip-address: true service-name: ${spring.application.name} gateway: routes: - id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由id: pay_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/info/** # 断言,路径相匹配的进行路由
SpringCloud
- 功能
- 组件
服务注册 Nacos == consul
注意是根据ID来区分的不是根据名字来区分命名空间的,所以ID要填自己想填的
命令行
startup.cmd -m standalone
服务提供者
pom:<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
yml
server: port: 9001 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #配置Nacos地址
main函数上使用@EnableDiscoveryClient
业务类示范消费者
pom<!--nacos-discovery--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--loadbalancer--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
xml
server: port: 83 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 #消费者将要去访问的微服务名称(nacos微服务提供者叫什么你写什么) service-url: nacos-user-service: http://nacos-payment-provider
main上也使用@EnableDiscoveryClient
restTemplate配置
ackage com.atguigu.cloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @auther zzyy
* @create 2023-11-23 17:20
*/
@Configuration
public class RestTemplateConfig
{
@Bean
@LoadBalanced //赋予RestTemplate负载均衡的能力
public RestTemplate restTemplate()
{
return new RestTemplate();
}
}
- Nacos作为配置中心,进行动态配置
导入pom
为什么进行两个配置? bootstrap和application?<!--bootstrap--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <!--nacos-config--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
Nacos同Consul一样,在项目初始化时,要保证先从配置中心进行配置拉取,
拉取配置之后,才能保证项目的正常启动,为了满足动态刷新和全局广播通知
springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application
bootstrap
application# nacos配置 spring: application: name: nacos-config-client cloud: nacos: discovery: server-addr: localhost:8848 #Nacos服务注册中心地址 config: server-addr: localhost:8848 #Nacos作为配置中心地址 file-extension: yaml #指定yaml格式的配置 # nacos端配置文件DataId的命名规则是: # ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension} # 本案例的DataID是:nacos-config-client-dev.yaml
controller层上使用@RefreshScope //在控制器类加入@RefreshScope注解使当前类下的配置支持Nacos的动态刷新功能。server: port: 3377 spring: profiles: active: dev # 表示开发环境 #active: prod # 表示生产环境 #active: test # 表示测试环境
问题1:
实际开发中,通常一个系统会准备
dev开发环境
test测试环境
prod生产环境。
如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢?
问题2:
一个大型分布式微服务系统会有很多微服务子项目,
每个微服务项目又都会有相应的开发环境、测试环境、预发环境、正式环境……
那怎么对这些微服务配置进行分组和命名空间管理呢?
Sentinel 等价于 Circuit Breaker 自己去官网看
pom
<!--SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
- 流控规则
- 熔断降级
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,
让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。、
如何处理分布式 事务
Seata
去官网看
面试题:
分布式详细
[分布式ID](### 分布式ID https://javaguide.cn/distributed-system/distributed-id-design.html)
需求:
- 全局唯一
- 高可用
- 高性能
- 安全
- 方便易用
解决方式:
推荐使用雪花算法
分布式锁
Redis实现
setnx
Redisson
可重入锁
一个线程中可以多次获取同一把锁,例如,方法又调用了另一个需要相同锁的方法。
可以使用红锁
ZooKeeper
https://javaguide.cn/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.html
Redis的性能更好,但是Zookeeper的可靠性更高。
推荐使用 Curator 来实现 ZooKeeper 分布式锁。