# spring-cloud
**Repository Path**: qiao_jin_zhou/spring-cloud
## Basic Information
- **Project Name**: spring-cloud
- **Description**: 后端java项目学习代码【SpringCloud】
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-02-11
- **Last Updated**: 2025-04-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: SpringCloud, 学习
## README
# Spring Cloud 系列教程
1. Spring Cloud Consul^Alibaba Nacos 服务注册与发现
2. Spring Cloud LoadBalancer^Spring Cloud OpenFeign 服务调用和负载均衡
3. Alibaba Seata 分布式事务
4. Spring Cloud Circuit Breaker Resilience4J^Alibaba Sentinel 服务熔断和降级
5. Spring Cloud Sleuth^Micrometer Tracing 服务链路追踪
6. Spring Cloud Gateway 服务网关
7. Alibaba Nacos 分布式配置管理
## Spring Cloud Consul 服务注册与发现
_[Consul官方安装地址](https://developer.hashicorp.com/consul/install)_
### consul pom 依赖
``` xml
org.springframework.cloud
spring-cloud-starter-consul-discovery
commons-logging
commons-logging
org.springframework.cloud
spring-cloud-starter-bootstrap
org.springframework.cloud
spring-cloud-starter-consul-config
commons-logging
commons-logging
```
#### consul 启动本地服务
``` shell
consul agent -dev
```
#### consul 本地持久化服务
* ##### 创建consul-config.json文件,内容如下:
``` json
{
"data_dir": "/Users/qiaojinzhou/Desktop/项目软件/project-01/consul-data",
"ui": true,
"server": true,
"bootstrap_expect": 1,
"bind_addr": "127.0.0.1",
"client_addr": "127.0.0.1",
"retry_join": ["provider=virtualbox"]
}
```
* ##### 启动consul自定义配置服务
``` shell
consul agent -config-file=consul-config.json
```
#### consul 查看文件路径
``` shell
brew --prefix consul
```
#### consul yml 配置
* ##### 消费者服务配置 application.yml
``` yml
spring:
application:
name: cloud-consumer-feign-order
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true # 访问地址用ip地址
service-name: ${spring.application.name}
```
* ##### 提供者服务配置 bootstrap.yml
``` yml
spring:
application:
name: cloud-payment-service
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
config:
profile-separator: '-'
format: YAML
watch:
wait-time: 1 # consul监听超时时间 默认55s
```
#### consul 开启服务发现
``` java
@EnableDiscoveryClient
```
#### consul 动态刷新配置
``` java
@RefreshScope
```
#### consul 开启负载均衡
###### 使用@LoadBalanced注解的RestTemplate进行服务调用
``` java
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
```
## Spring Cloud LoadBalancer^Spring Cloud OpenFeign 服务调用和负载均衡
_[LoadBalancer官网文档](https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html)_
### loadbalancer pom 依赖
``` xml
org.springframework.cloud
spring-cloud-starter-loadbalancer
```
#### loadbalancer 指定负载均衡算法
* ##### 自定义负载均衡算法
``` java
@LoadBalancerClient(value = "cloud-payment-service", configuration = RestTemplateConfig.class)
```
* ##### 负载均衡算法配置
``` java
@Bean
ReactorLoadBalancer randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
```
#### loadbalancer 方法调用
* ##### 获取所有服务实例
``` java
List services = discoveryClient.getServices();
```
* ##### 获取指定服务实例
``` java
List instances = discoveryClient.getInstances("cloud-payment-service");
```
* ##### 获取指定服务实例信息 地址 端口 主机名 服务id
``` java
instances.get(0).getServiceId() + ":" + instances.get(0).getPort() + "\t" + instances.get(0).getUri() + "\t" + instances.get(0).getHost();
```
### openfeign pom 依赖
``` xml
org.springframework.cloud
spring-cloud-starter-openfeign
```
#### openfeign 开启服务调用
``` java
@EnableFeignClients
```
#### openfeign 指定服务调用
``` java
@FeignClient(value = "cloud-payment-service")
public interface PayFeignApi {
}
```
#### openfeign 超时时间配置
###### default(全局配置) cloud-payment-service(指定配置)
``` yml
spring:
cloud:
openfeign:
client:
config:
default:
connect-timeout: 3000
read-timeout: 3000
cloud-payment-service:
connect-timeout: 3000
read-timeout: 3000
```
#### openfeign 超时重试机制策略
``` java
@Configuration
public class FeignConfig {
@Bean
public Retryer feignRetryer() {
//return Retryer.NEVER_RETRY; //默认配置不走重试策略
//重试间隔时间,重试次数,重试最大时间
return new Retryer.Default(100, 1, 3);
}
}
```
#### openfeign apache httpclient5 pom依赖
###### 替换默认的openfeign HttpUrlConnection为apache httpclient5
``` xml
org.apache.httpcomponents.client5
httpclient5
5.3
io.github.openfeign
feign-hc5
13.1
```
#### openfeign apache httpclient5 开启配置
``` yml
spring:
cloud:
openfeign:
httpclient:
hc5:
enabled: true
```
#### openfeign compression 压缩配置
``` yml
spring:
cloud:
openfeign:
compression:
request:
enabled: true # 开启请求压缩
mime-types: application/json,text/xml,application/xml # 压缩类型
min-request-size: 2048 # 压缩最小值
response:
enabled: true # 开启响应压缩
```
#### openfeign 日志配置
* ##### 开启日志配置 feign 设置日志级别
###### NONE 不记录任何信息
###### BASIC 只记录请求方法、URL以及响应状态码和执行时间
###### HEADERS 除了记录基本信息外,还会记录请求和响应的头信息
###### FULL 记录所有请求和响应的明细,包括头信息、请求体、元数据等
``` java
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; //默认配置打印所有请求
}
}
```
* ##### feign日志以什么级别监控那个接口
``` yml
logging:
level:
com:
qiaojinzhou:
test:
apis:
PayFeignApi: debug
```
## Spring Cloud Circuit Breaker Resilience4J 服务熔断和降级
_[Circuit Breaker](https://spring.io/projects/spring-cloud-circuitbreaker)_
### Circuit Breaker resilience4j pom 依赖
``` xml
org.springframework.cloud
spring-cloud-starter-circuitbreaker-resilience4j
org.springframework.boot
spring-boot-starter-aop
```
#### Circuit Breaker resilience4j circuitbreaker 开启断路器和断路器配置 按照请求次数配置
``` yml
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true # 开启断路器
group:
enabled: true # 开启断路器组
resilience4j: # resilience4j 断路器配置 按照请求次数配置
circuitbreaker:
configs:
default: # 默认配置
failureRateThreshold: 50 # 失败率达到多少后熔断
slidingWindowType: COUNT_BASED # 滑动窗口类型
slidingWindowSize: 6 # 滑动窗口大小
minimumNumberOfCalls: 6 # 最小请求数
automaticTransitionFromOpenToHalfOpenEnabled: true # 开启自动切换半开状态
waitDurationInOpenState: 5s # 熔断持续时间
permittedNumberOfCallsInHalfOpenState: 2 # 半开状态允许的请求数
recordExceptions: # 哪些异常需要记录
- java.lang.Exception # 记录所有异常
instances: # 实例配置
cloud-payment-service: # 服务名
baseConfig: default # 使用默认配置
```
#### Circuit Breaker resilience4j circuitbreaker 开启断路器和断路器配置 按照时间配置
``` yml
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true # 开启断路器
group:
enabled: true # 开启断路器组
resilience4j: # resilience4j 断路器配置 按照时间配置
timelimiter: # resilience4j 超时配置
configs:
default: # 默认配置
timeoutDuration: 10s # 超时时间
circuitbreaker:
configs:
default: # 默认配置
failureRateThreshold: 50 # 失败率达到多少后熔断
slowCallDurationThreshold: 2s # 慢调用时长
slowCallRateThreshold: 30 # 慢调用比例
slidingWindowType: TIME_BASED # 滑动窗口类型
slidingWindowSize: 2 # 滑动窗口大小
minimumNumberOfCalls: 2 # 最小请求数
waitDurationInOpenState: 5s # 熔断持续时间
permittedNumberOfCallsInHalfOpenState: 2 # 半开状态允许的请求数
recordExceptions: # 哪些异常需要记录
- java.lang.Exception # 记录所有异常
instances: # 实例配置
cloud-payment-service: # 服务名
baseConfig: default # 使用默认配置
```
#### Circuit Breaker resilience4j circuitbreaker 熔断降级接口服务调用
``` java
@RestController
public class OrderCircuitController {
@Resource
private PayFeignApi payFeignApi;
@GetMapping("/feign/pay/circuit/{id}")
@CircuitBreaker(name = "cloud-payment-service", fallbackMethod = "myCircuitBreakerFallback")
public String myCircuitBreaker(@PathVariable("id") Integer id) {
return payFeignApi.myCircuit(id);
}
// 熔断降级兜底方法
public String myCircuitBreakerFallback(Integer id ,Throwable throwable) {
// 熔断降级处理逻辑
return "myCircuitBreakerFallback: " + throwable.getMessage();
}
}
```
#### Circuit Breaker resilience4j bulkhead 引入pom依赖 (舱壁隔离)
``` xml
io.github.resilience4j
resilience4j-bulkhead
```
#### Circuit Breaker resilience4j bulkhead 舱壁隔离配置 信号量配置
``` yml
resilience4j: # resilience4j 舱壁隔离 信号量配置
bulkhead: # bulkhead 熔断配置
configs:
default:
maxConcurrentCalls: 2 # 最大并发数
maxWaitDuration: 1s # 最大等待时间
instances:
cloud-payment-service: # 服务名
baseConfig: default # 使用默认配置
timelimiter: # resilience4j 超时配置
configs:
default:
timeoutDuration: 20s # 超时时间
```
#### Circuit Breaker resilience4j bulkhead 舱壁隔离接口服务调用 (Semaphore 信号量隔离)
``` java
@RestController
public class OrderCircuitController {
@Resource
private PayFeignApi payFeignApi;
// 舱壁隔离 SEMAPHORE=信号量
@GetMapping("/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadFallback", type = Bulkhead.Type.SEMAPHORE)
public String myBulkhead(@PathVariable("id") Integer id) {
return payFeignApi.myBulkhead(id);
}
// 舱壁隔离兜底方法
public String myBulkheadFallback(Integer id ,Throwable throwable) {
//舱壁隔离处理逻辑
return "myBulkheadFallback: " + throwable.getMessage();
}
}
```
#### Circuit Breaker resilience4j bulkhead 舱壁隔离配置 线程池配置
###### spring.cloud.openfeign.circuitbreaker.group.enabled 请设置为false 新线程隔离不支持断路器组
``` yml
resilience4j: # resilience4j 舱壁隔离 线程池配置
timelimiter: # resilience4j 超时配置
configs:
default:
timeoutDuration: 10s # 超时时间
thread-pool-bulkhead: # 线程池配置
configs:
default:
maxThreadPoolSize: 1 # 最大线程数
coreThreadPoolSize: 1 # 核心线程数
queueCapacity: 1 # 队列容量
instances:
cloud-payment-service: # 服务名
baseConfig: default # 使用默认配置
```
#### Circuit Breaker resilience4j bulkhead 舱壁隔离接口服务调用 (ThreadPool 线程池隔离)
``` java
@RestController
public class OrderCircuitController {
@Resource
private PayFeignApi payFeignApi;
// 舱壁隔离 THREADPOOL=线程池
@GetMapping("/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadPoolFallback", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture myBulkheadPool(@PathVariable("id") Integer id) {
return CompletableFuture.supplyAsync(() -> payFeignApi.myBulkhead(id));
}
// 舱壁隔离兜底方法
public CompletableFuture myBulkheadPoolFallback(Integer id ,Throwable throwable) {
// 舱壁隔离处理逻辑
return CompletableFuture.supplyAsync(() -> "myBulkheadPoolFallback: " + throwable.getMessage());
}
}
```
#### Circuit Breaker resilience4j rateLimiter 引入pom依赖 (限流器)
``` xml
io.github.resilience4j
resilience4j-ratelimiter
```
#### Circuit Breaker resilience4j rateLimiter 限流器配置
``` yml
resilience4j: # resilience4j 限流配置
ratelimiter:
configs:
default:
limitForPeriod: 2 # 每秒最多调用次数
limitRefreshPeriod: 1s # 时间窗口
timeoutDuration: 1 # 超时时间
instances:
cloud-payment-service:
baseConfig: default
```
#### Circuit Breaker resilience4j rateLimiter 限流器接口服务调用
``` java
@RestController
public class OrderCircuitController {
@Resource
private PayFeignApi payFeignApi;
// 服务限流
@GetMapping("/feign/pay/ratelimit/{id}")
@RateLimiter(name = "cloud-payment-service", fallbackMethod = "myRatelimitFallback")
public String myBulkhead(@PathVariable("id") Integer id) {
return payFeignApi.myRatelimit(id);
}
// 服务限流兜底方法
public String myRatelimitFallback(Integer id ,Throwable throwable) {
// 服务限流处理逻辑
return "myRatelimitFallback: " + throwable.getMessage();
}
}
```
## Spring Cloud Micrometer Tracing 微服务链路追踪(ZipKin 图形展示& Micrometer 数据采集)
### ZipKin 链路追踪图形化工具
_[zipkin官方安装地址](https://zipkin.io/pages/quickstart.html)_
#### ZipKin 启动命令
``` shell
java -jar zipkin-server-3.5.0-exec.jar
```
### Micrometer 引入pom父依赖(父工程)
``` xml
io.micrometer
micrometer-tracing-bom
1.2.0
pom
import
io.micrometer
micrometer-tracing
1.2.0
io.micrometer
micrometer-tracing-bridge-brave
1.2.0
io.micrometer
micrometer-observation
1.12.0
io.github.openfeign
feign-micrometer
12.5
io.zipkin.reporter2
zipkin-reporter-brave
2.17.0
```
#### Micrometer 引入pom子依赖 (子工程)
``` xml
io.micrometer
micrometer-tracing
io.micrometer
micrometer-tracing-bridge-brave
io.micrometer
micrometer-observation
io.github.openfeign
feign-micrometer
io.zipkin.reporter2
zipkin-reporter-brave
```
#### Micrometer yml 配置 (子工程)
``` yml
management: # 监控配置
zipkin: # 链路追踪
tracing: # 采样
endpoint: http://localhost:9411/api/v2/spans # 链路追踪地址
tracing:
sampling:
probability: 1.0 # 采样率
```
## Spring Cloud Gateway 服务网关
_[Gateway官方文档地址](https://spring.io/projects/spring-cloud-gateway)_
### Gateway 引入pom依赖
``` xml
org.springframework.cloud
spring-cloud-starter-gateway
```
### Gateway yml 配置
``` yml
spring:
cloud:
gateway:
routes:
- id: pay_route1
uri: lb://cloud-payment-service
predicates:
- Path=/pay/gateway/get/**
- My=diamond
- id: pay_route2
uri: lb://cloud-payment-service
predicates:
- Path=/pay/gateway/info/**
- My=diamond
ilters:
- AddRequestHeader=X-Request-Id1,Id1
- AddRequestHeader=X-Request-Id2,Id2
- My=qiaojinzhou
```
### Gateway Predicate 自定义断言
``` java
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory {
public MyRoutePredicateFactory() {
super(MyRoutePredicateFactory.Config.class);
}
@Setter
@Getter
@Validated
public static class Config {
@NotEmpty
private String userType;
}
@Override
public List shortcutFieldOrder() {
return Collections.singletonList("userType");
}
@Override
public Predicate apply(MyRoutePredicateFactory.Config config) {
return new Predicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
return config.getUserType().equals(userType);
}
};
}
}
```
### Gateway Filter 自定义全局过滤器
``` java
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
public static final String BEGIN_VISIT_TIME = "begin_visit_time";
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
if (beginVisitTime != null) {
log.info("请求地址:{}", exchange.getRequest().getURI());
log.info("请求方法:{}", exchange.getRequest().getMethod());
log.info("请求参数:{}", exchange.getRequest().getQueryParams());
log.info("请求耗时:{}", System.currentTimeMillis() - beginVisitTime);
log.info("=================================");
System.out.println();
}
})
);
}
@Override
public int getOrder() {
return 0;
}
}
```
### Gateway Filter 自定义局部过滤器
``` java
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory {
public MyGatewayFilterFactory() {
super(MyGatewayFilterFactory.Config.class);
}
@Override
public GatewayFilter apply(MyGatewayFilterFactory.Config config) {
return new GatewayFilter() {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
System.out.println("MyGatewayFilterFactory.Config.status = " + config.getStatus());
if (request.getQueryParams().containsKey("qiaojinzhou")) {
return chain.filter(exchange);
} else {
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
}
};
}
@Override
public List shortcutFieldOrder() {
ArrayList list = new ArrayList<>();
list.add("status");
return list;
}
@Getter
@Setter
public static class Config {
private String status;
}
}
```
## Spring Cloud Alibaba
_[Alibaba官方文档地址](https://github.com/alibaba/spring-cloud-alibaba/blob/2023.x/README-zh.md)_
### Nacos 服务注册与发现
_[Nacos官方文档地址](https://nacos.io/)_
#### Nacos 启动命令&关闭命令
``` shell
sh startup.sh -m standalone
sh shutdown.sh
```
#### Nacos 登陆地址
```
地址:http://localhost:8848/nacos/
账户:nacos
密码:nacos
```
#### Nacos 引入pom依赖(生产者)
``` xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
```
#### Nacos 引入pom依赖(消费者)
``` xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-loadbalancer
```
#### Nacos yml 配置(生产者)
``` yml
server:
port: 9001
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
```
#### Nacos yml 配置(消费者)
``` yml
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
```
#### Nacos 配置管理 开启负载均衡(消费者)
``` java
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
```
#### Nacos 配置管理 ConfigClient 3377
##### NacosConfigClient
``` java
@RestController
@RefreshScope // 监听Nacos配置中心
public class NacosConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
```
##### bootstrap.yml
``` yml
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务注册中心地址
config:
server-addr: localhost:8848 # Nacos配置中心地址
file-extension: yaml # 配置后缀名
group: DEFAULT_GROUP # 配置分组
namespace: public # 命名空间
```
##### application.yml
``` yml
server:
port: 3377
spring:
profiles:
active: dev # 激活开发环境配置
```
### Sentinel 服务熔断和降级
_[Sentinel官方地址](https://sentinelguard.io/zh-cn/)_
_[下载包zipkin-server-3.5.0-exec.jar地址](https://github.com/alibaba/Sentinel/releases)_
#### Sentinel 引入pom依赖
``` xml
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
```
#### Sentinel 配置
``` yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务端地址
sentinel:
transport: #配置Sentinel dashboard地址
dashboard: localhost:8080 #监控地址
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
web-context-unify: false # 默认为true,如果为true,则所有请求都会被拦截,包括/actuator/sentinel/**,如果为false,则/actuator/sentinel/**不会被拦截,但/act
```
#### Sentinel 自定义限流规则
``` java
@RestController
@Slf4j
public class RateLimitController {
@GetMapping("/rateLimit/byResource")
@SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleBlockHandler")
public String byResource() {
return "byResource 限流测试";
}
public String handleBlockHandler(BlockException blockException) {
return "handleBlockHandler 服务不触发了 SentinelResource启动";
}
}
```
#### Sentinel 自定义降级规则
``` java
@RestController
@Slf4j
public class RateLimitController {
@GetMapping("/rateLimit/byResource")
@SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleBlockHandler", fallback = "handleFallback")
public String byResource(@PathVariable("p1") Integer p1) {
if (p1 == 0) {
throw new RuntimeException("p1不能为0");
}
return "byResource";
}
public String handleBlockHandler(@PathVariable("p1") Integer p1, BlockException b) {
return "handleBlockHandler 服务不触发了 SentinelResource启动:" + b.getMessage();
}
public String handleFallback(@PathVariable("p1") Integer p1, Throwable t) {
return "handleFallback 服务异常了:" + t.getMessage();
}
}
```
#### Sentinel 热点参数限流
``` java
@RestController
@Slf4j
public class RateLimitController {
// 热点参数限流
@GetMapping("/rateLimit/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "dealHandle_testHotKey")
public String testHotKey (
@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "testHotKey";
}
public String dealHandle_testHotKey(String p1, String p2, BlockException e) {
return "dealHandle_testHotKey";
}
}
```
#### Sentinel 自定义授权规则
``` java
@Component
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
return httpServletRequest.getParameter("serverName");
}
}
```
#### Sentinel 自定义规则持久化
``` xml
com.alibaba.csp
sentinel-datasource-nacos
```
``` yml
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务端地址
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848 # Nacos服务端地址
dataId: ${spring.application.name} # 默认为${spring.application.name}-sentinel
groupId: DEFAULT_GROUP # 默认为DEFAULT_GROUP
data-type: json # 默认为json
rule-type: flow # 规则类型,支持flow(流量控制)、degrade(熔断降级)、authority(授权规则)、param-flow(热点参数限流)
```
### Seata 分布式事务
_[Seata官方地址](https://seata.apache.org/zh-cn/)_
_[Seata下载地址](https://github.com/apache/incubator-seata/releases)_
_[Seata数据表地址](https://github.com/apache/incubator-seata/blob/v2.0.0/script/server/db/mysql.sql)_
#### Seata 文件配置 (seata/conf/application.yml)
``` yml
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
username: nacos
password: nacos
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
username: nacos
password: nacos
cluster: default
store:
# support: file 、 db 、 redis 、 raft
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
username: qiaojinzhou
password: qiaojinzhou
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 1000
max-wait: 5000
```
#### Seata 数据库表
``` mysql
CREATE DATABASE seata;
USE seata;
```
[seata锁表地址](https://github.com/apache/incubator-seata/blob/2.0.0/script/server/db/mysql.sql)
``` mysql
create database seata_order;
create database seata_storage;
create database seata_account;
```
[回滚日志表地址](https://github.com/apache/incubator-seata/blob/2.0.0/script/client/at/db/mysql.sql)
#### Seata 脚本SQL
###### 分别为order,storage,account 创建对应业务表 t_order,t_storage,t_account
``` mysql
create table t_order(
`id` bigint(11) not null auto_increment primary key,
`user_id` bigint(11) default null comment '用户ID',
`product_id` bigint(11) default null comment '产品ID',
`count` int(11) default null comment '数量',
`money` decimal(11,0) default null comment '金额',
`status` int(1) default null comment '订单状态:0=创建中,1=已完成'
)engine=innodb auto_increment=1 default charset=utf8;
select * from t_order;
```
``` mysql
create table t_account(
`id` bigint(11) not null auto_increment primary key comment 'id',
`user_id` bigint(11) default null comment '用户ID',
`total` decimal(10,0) default null comment '总额度',
`used` decimal(10,0) default null comment '已用额度',
`residue` decimal(10,0) default '0' comment '剩余额度'
)engine=innodb auto_increment=2 default charset=utf8;
INSERT INTO t_account(`id`,`user_id`,`total`,`used`,`residue`)VALUES('1','1','1000','0','1000');
select * from t_account;
```
``` mysql
create table t_storage(
`id` bigint(11) not null auto_increment primary key comment 'id',
`product_id` bigint(11) default null comment '产品ID',
`total` int(11) default null comment '总库存',
`used` int(11) default null comment '已用库存',
`residue` int(11) default '0' comment '剩余库存'
)engine=innodb auto_increment=1 default charset=utf8;
INSERT INTO t_storage(`id`,`product_id`,`total`,`used`,`residue`)VALUES('1','1','100','0','100');
select * from t_storage;
```
#### Seata 命令行启动
``` shell
sh seata-server.sh -h localhost -p 8091 -e
sh seata-server.sh -p 8091 -h 127.0.0.1 -m file
```
#### Seata 命令行停止
``` shell
sh seata-server.sh stop
```
#### Seata 登陆地址
```
地址:http://127.0.0.1:7091/
账户:seata
密码:seata
```
#### Seata 引入pom依赖
``` xml
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
```
#### Seata 配置
``` yml
seata: #seata配置
registry: #注册中心配置
type: nacos #注册中心类型
nacos: #nacos注册中心配置
server-addr: localhost:8848 #nacos地址
namespace: "" #默认值public
group: SEATA_GROUP #默认值DEFAULT_GROUP
application: seata-server #服务名称
tx-service-group: default_tx_group #事务组
service: #服务配置
vgroup-mapping: #服务虚拟分组到事务服务组的映射关系
default_tx_group: default #默认的事务服务组
data-source-proxy-mode: AT #AT模式
```
#### Seata AT模式 开启事物锁
``` java
@GlobalTransactional(name = "fsp-create-order", rollbackFor = Exception.class)
public void create(Order order) {
// 此处省略业务代码
}
```