概述
主要包含以下组件
Sentinel 流量控制和服务降级
Nacos 服务注册与发现
Nacos 分布式配置中心
RocketMQ 消息驱动
Seate 分布式事务
Dubbo RPC通信
OSS 阿里云对象存储
springboot自动装配原理
eg:将redis整合到springboot中:
1.添加starter依赖:spring-boot-starter-data-redis
2.在application.properties中配置redis数据源
3.使用@Autowried引入redisTemplate
4.使用
当使用@Autowried注入redisTemplate实例时.说明IOC容器中已经存在RedisTemplate,这是Springboot自动装配而来的
所以,存在一个机制,这个机制的实现基于某种约定或者规范,只要Starter组件符合SpringBoot中自动装配的规范,就能实现自动装配
自动装配的实现
自动装配在SpringBoot中是通过@EnableAutoConfiguration注解开启的,这个注解声明在@SpringBootApplication中
@Enable注解:主要作用是把相关组件的Bean转配到IOC容器中
@Enable注解对JavaConfig进一步完善,常见的@Enable注解有
@EnableWebMvc和@EnableScheduling等
每个@Enable类的注解都包含@Import
@ImportSelector的作用
自动装配的核心是扫描约定目录下的文件进行解析,解析完成后把得到的Configuration配置类通过ImportSelector进行导入,从而完成Bean的自动装配过程
SpringFactoriesLoaderss是Spring内部提供的一种预定俗成的加载方式,类似于Java中的SPI,它会扫描classpath下的METE-INF/spring.factories文件,这个文件的数据由key=value方式存储
Conditional条件注解
- springboot中的@Conditional做了一些扩展
手工实现一个starter
1.命名规范:
官方: spring-boot-starter-模块名称
自定义: 模块名称-spring-boot-starter
官方命名模块名称放最后,自定义模块名称放前面
2.创建一个工程,命名为redis-spring-boot-starter
3.添加jar包依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.1</version>
</dependency>
4.定义属性
@ConfigurationProperties(prefix = "gp.redisson")
public class RedissonProperties {
private String host = "localhost";
private String password;
private int port = 6379;
private int timeout;
private boolean ssl;
public String getHost() {return host;}
public void setHost(String host) {this.host = host;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public int getPort() {return port;}
public void setPort(int port) {this.port = port;}
public boolean isSsl() {return ssl;}
public void setSsl(boolean ssl) {this.ssl = ssl;}
public int getTimeout() {return timeout;}
public void setTimeout(int timeout) {this.timeout = timeout;}
}
5.定义需要自动装配的配置类,主要是把RedissonClient装配到IOC容器
@ConditionalOnClass(Redisson.class)表示只有classpath下存在Redisson这个类,RedissonAutoConfiguration 才会实现自动装配
@Configuration
@ConditionalOnClass(Redisson.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonAutoConfiguration {
@Autowired
RedissonProperties redissonProperties;
@Bean
RedissonClient redissonClient(){
Config config=new Config();
String prefix="redis://";
if(redissonProperties.isSsl()){
prefix="rediss://";
}
SingleServerConfig singleServerConfig=config.useSingleServer()
.setAddress(prefix+redissonProperties.getHost()+":"+redissonProperties.getPort())
.setConnectTimeout(redissonProperties.getTimeout());
if(!StringUtils.isEmpty(redissonProperties.getPassword())){
singleServerConfig.setPassword(redissonProperties.getPassword());
}
return Redisson.create(config);
}
}
6.在resource下创建METE-INF/spring.factories文件,使得SpringBoot程序可以扫描到该文件完成自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.gupaoedu.book.RedissonAutoConfiguration
7.使用的时候,直接添加依赖
<groupId>com.gupaoedu.book</groupId>
<artifactId>redis-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
8.添加属性
gp.redisson.host=192.168.56.111
gp.redisson.port=6379
springboot集成dubbo
- 生产者
1.启动方法要加上@DubboComponentScan
2.服务加上@Service注解,该注解是dubbo包下的,不是spring的
3.添加dubbo依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
4.加上配置文件
dubbo.application.name=springboot-provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.registry.address=N/A
- 消费者
声明服务时使用@Reference注解获取一个远程代理对象
@Reference(url = "dubbo://127.0.0.1:20880/com.gupaoedu.book.dubbo.IHelloService")
private IHelloService helloService;
- dubbo使用nacos作为注册中心
1.依赖nacos组件
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.4</version>
</dependency>
2.dubbo注册地址加上nacos协议
dubbo.registry.address=nacos://192.168.56.111:8848
3.启动类加上Dubbo注解
@DubboComponentScan
- dubbo使用nacos作为注册中心
1.依赖nacos组件
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.4</version>
</dependency>
2.dubbo注册地址加上nacos协议
dubbo.registry.address=nacos://192.168.56.111:8848
3.启动类加上Dubbo注解
@DubboComponentScan
- springcloud使用nacos作为注册中心
1.引入服务发现依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>
2.配置
spring.cloud.nacos.discovery.server-addr=192.168.56.111:8848
Nacos服务注册与发现实现原理
nacos源码分析
- 服务注册
- 服务地址获取
- 服务地址变化感知
spring-cloud-common中有个ServiceRegistry接口,是服务注册的标准
package org.springframework.cloud.client.serviceregistry;
public interface ServiceRegistry<R extends Registration> {
void register(R registration);
void deregister(R registration);
void close();
void setStatus(R registration, String status);
<T> T getStatus(R registration);
}
其中一个实现类是NacosServiceRegistry
在spring-cloud-commons包的META-INF/spring.factories中包含自动装配信息
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration,
com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration,
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
sentinel微服务熔断和限流
1.限流规则配置
public class FlowRuleInitFunc implements InitFunc{
@Override
public void init() throws Exception {
List<FlowRule> rules=new ArrayList<>();
FlowRule rule=new FlowRule();
rule.setCount(1);
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
2.请求方法设置限流注解,增加限流后返回的方法
@RestController
public class HelloController {
@SentinelResource(value = "hello",blockHandler = "blockHandlerHello")
@GetMapping("/say")
public String hello(){
return "hello ,Mic";
}
public String blockHandlerHello(BlockException e){
return "被限流了";
}
}
3.在META-INF.services增加限流类,设置扩展点
com.gupaoedu.book.springcloud.sentinel.springcloudsentinelsample.FlowRuleInitFunc
4.添加限流依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
5.将一类url归类为一个
@Service
public class CustomerUrlCleaner implements UrlCleaner{
@Override
public String clean(String originUrl) {
if(StringUtils.isEmpty(originUrl)){
return originUrl;
}
if(originUrl.startsWith("/clean/")){
return "/clean/*";
}
return originUrl;
}
}
- Sentinel集成Nacos动态流控规则
1.nacos配置
[{
"resource":"/dynamic",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}]
2.项目配置文件中配置
spring:
application:
name: spring-cloud-sentinel-dynamic
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:7777
datasource:
- nacos:
server-addr: 192.168.56.111:8848
data-id: ${spring.application.name}-sentinel-flow
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
3.在sentinel控制台可以看到规则
现在不支持在控制台修改规则同步到nacos
可以通过修改源码,对控制台的curd操作的结果保存到nacos实现将控制台的规则持久化到nacos中
Sentinel工作原理
分布式事务
分布式事务指事务的参与者,支持事务的服务器分别位于不同的节点上
分布式事务常见解决方案:
1.两阶段提交协议
第一阶段是事务准备阶段
第二阶段是事务提交或者回滚阶段
准备阶段:事务管理器(TM)通知资源管理器(RM)准备分支事务,记录事务日志,并告知事务管理器准备结果
提交/回滚阶段:如果所有资源管理器(RM)在准备阶段都明确返回成功,则事务管理器向所有资源管理器发起事务提交指令完成数据变更,反之,如果任何一个资源管理器明确返回失败,则事务管理器向所有资源管理器发送事务回滚指令
缺点: 同步阻塞,过于保守(任意一个节点失败都会回滚)
事务协调者单点故障:如果协调者第二阶段出现故障,那么其他参与者会处于锁定状态
脑裂导致数据不一致: 在第二阶段中,事务协调者向所有参与者发送commit请求
发生局部网络异常导致只有一部分参与者收到commit请求,这部分参与者收到请求后会执行commit操作,但是未收到commit请求的节点由于事务无法提交
导致数据出现不一致问题
2.三阶段提交协议
比二阶段多一个询问阶段
事务协调者向参与者发送事务执行请求,询问是否可以执行指令
Base理论
通过牺牲数据的强一致性来获取高可用性
Base Avaliable(基本可用): 出现故障时,允许损失一部分功能可用性,保证核心功能可用
Soft State(软状态) : 允许系统中数据存在中间状态,这个状态不影响系统可用性,就是允许系统中不同节点的数据副本存在延时
Eventually Consistent(最终一致性):中间状态数据经过一段时间之后达到最终数据一致性
分布式事务常见解决方案
- TCC补偿型方案(属于两段式)(关键字:事先冻结):
2.基于可靠性消息的最终一致性方案(基于中间件实现)
支付服务的本地事务与发送消息这个操作的原子性问题:
1.先发送消息,再执行数据库事务
会出现消息发送成功但是本地事务更新失败的情况
2.先执行数据库事务,再发送消息
出现mq响应超时导致异常,从而将本地事务回滚,但消息可能已经发送成功,也存在数据不一致问题
最大努力通知型
分布式事务框架seata
AT模式
分为三大模块:TM(事务管理器) RM(资源管理器) TC(事务控制器),
TM: 负责向TC注册一个全局事务,并生成一个全局唯一的XID
在AT模式下,每个数据库资源被当做一个RM,在业务层面通过JDBC标准接口访问RM时,Seata会对所有的请求进行拦截,每个本地事务提交时,RM会向TC注册一个分支事务
Saga模式
把一个业务流程中的长事务分为多个本地短事务,业务流程中每个参与者都提交真实的提交给本地短事务,
当其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的参与者
常见两种协调方式
- 事件/编排式
- 命令/协调式
Seata AT实现原理
AT模式是基于XA事务模型演进而来,所以它的整体机制也是一个改进版的两阶段提交协议
第一阶段: 业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
第二阶段: 提交异步化,非常快速完成,回滚通过第一阶段的回滚日志进行反向补偿