SpringCloud学习笔记
代码 gitee仓库地址
https://gitee.com/lu-yi1104/spring-cloud_-study.git/
上半场 (一)地址
https://blog.csdn.net/weixin_43691773/article/details/109167048
文章目录
SpringCloud Alibaba 简介


官网地址
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
依赖 父工程已经导入了 

Spring Cloud Alibaba Nacos服务注册中心和配置中心
简介





下载地址
https://github.com/alibaba/Nacos
nacos下载和安装

下载解压
修改startup.cmd MODE 由cluster改为单机版
启动
访问 localhost:8848/nacos 出现界面代表成功 默认账号密码 nacos/nacos
Nacos作为服务注册中心
Nacos之服务提供者注册
新建模块 9001
跟着官网来
https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_nacos_discovery
pom文件
在父工程pom文件加入 springcloud alibaba的依赖
<!--spring cloud alibaba 2.1.0.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
9001 pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.luyi.cloud</artifactId>
<groupId>com.luyi.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-provider-payment9001</artifactId>
<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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
</dependencies>
</project>
yml文件
server:
port: 9001
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置Nacos地址
# 暴露要监控的
management:
endpoints:
web:
exposure:
include: '*'
主启动类
package com.luyi.sprinhcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author 卢意
* @create 2020-11-06 11:25
*/
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class, args);
}
}
controller层
package com.luyi.sprinhcloud.alibaba.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 卢意
* @create 2020-11-06 11:27
*/
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/payment/nacos/{id}")
public String getPyment(@PathVariable("id") Integer id){
return "nacos register ,serverPort: "+serverPort+"\t id: "+id;
}
}
测试 首先启动nacos注册中心
再启动9001
为了演示nacos的负载均衡、参照9001侯建9002 (也可以直接拷贝9001的虚拟端口映射)


启动

Nacos之服务消费者注册
新建order83模块
pom文件与上面相同
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-privider
主启动类
package com.luyi.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author 卢意
* @create 2020-11-06 11:56
*/
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83 {
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain83.class, args);
}
}
新建上下文配置类
package com.luyi.springcloud.alibaba.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;
/**
* @author 卢意
* @create 2020-11-06 13:34
*/
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced// resttemplate 结合ribbon做负载均衡的时候 要加入注解
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller类
package com.luyi.springcloud.alibaba.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-11-06 13:37
*/
@RestController
@Slf4j
public class OrderNacosController {
@Resource
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverUrl;
@GetMapping(value = "/consumer/payment/nacos/{id}")
public String paymeentInfo(@PathVariable("id") Long id){
return restTemplate.getForObject(serverUrl+"/payment/nacos/"+id,String.class );
}
}
启动83
访问成功 并带有负载均衡效果

Nacos之自带负载均衡

Nacos 服务中心对比提升

Nacos支持Cp+Ap的切换


Nacos之服务配置中心–基础配置
新建配置中心 3377
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.luyi.cloud</artifactId>
<groupId>com.luyi.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-config-nacos-client3377</artifactId>
<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>
<!--nacos-config-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
</dependencies>
</project>
两个yml文件
bootstrap文件
# nacos 配置
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务注册中心地址
config:
server-addr: localhost:8848 # Nacos作为服务中心的地址
file-extension: yaml # 指定Yaml格式的配置 3377就可以去配置中心读指定后缀名是yaml的文件
# ${spring.application.name}-${spring.profile.active}.${Spring.cloud.nacos.config.file.extension}
application.yml
spring:
profiles:
active: dev # 表示开发环境
主启动类
package com.luyi.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author 卢意
* @create 2020-11-06 17:04
*/
@EnableDiscoveryClient
@SpringBootApplication
public class NacosClientConfigMain3377 {
public static void main(String[] args) {
SpringApplication.run(NacosClientConfigMain3377.class, args);
}
}
重复投入
package com.luyi.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 卢意
* @create 2020-11-06 17:10
*/
@RestController
@RefreshScope //支持Nacos动态刷新功能
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo(){
return configInfo;
}
}
nacos中的配置规则


${spring.application.name}
${spring.profile.active}
${Spring.cloud.nacos.config.file.extension}
配置新增




测试

启动发现报错了 我丢 但是不要紧张阳哥 也报了
原因
解决 吧yml 都改成yaml


Nacos之服务配置中心–分类配置
问题
Nacos之命名空间分组和 Goup Data ID三者之间的关系


大致架构


Data ID方案

新建dev 配置DataID


修改application.yml
重启3377开测
Group方案





Namespace命名空间方案



对应 DEV命名空间ID






Nacos集群和持久化配置 (重要)
官网说明




Nacos持久化切换配置





spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456


Linux版本安装

官网下载tar包

Nacos集群配置

执行数据库文件



所以需要修改sh脚本和conf

编辑startup脚本

1.4的nacos -p 已经有了 所以我换成port

nginx配置
启动三个nacos

启动nginx
这里我测试失败了 应该是版本问题 1.4版本的太新了 伪集群会出现绑定的问题 有时间再去试一下 1.3版本的吧
Sentinel
介绍



下和安装
https://github.com/alibaba/Sentinel/releases
本次不搞七搞八的 V1.7就好了

localhost:8080
用户密码 sentinel/sentinel

初始化监控
新建模块8491
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.luyi.cloud</artifactId>
<groupId>com.luyi.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-sentinel-service8401</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--sentinel datasource nacos 持久化会用到-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
</dependencies>
</project>
yml文件
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
# Nacos作为服务中心的地址
server-addr: localhost:8848
sentinel:
transport:
# 配置Sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,加入被占用 自动+1寻找未被占用的端口
port: 8719
#监控
management:
endpoints:
web:
exposure:
include: '*'
主启动类
package com.luyi.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author 卢意
* @create 2020-11-22 13:48
*/
@SpringBootApplication
@EnableDiscoveryClient // 可以注册进注册中心
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class,args);
}
}
controller层
package com.luyi.springcloud.alibaba.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 卢意
* @create 2020-11-22 13:50
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA()
{
return "------------------testA";
}
@GetMapping("/testB")
public String testB()
{
return "------------------testB";
}
}
启动nacos 启动sentinel 在启动8401
sentinel页面还没有东西 因为 它是懒加载模式
访问两次后 有流量通过 就会显示了 Sentinel正在监控8401

流控规则简介



QPS(每秒请求数)直接失败
直接失败


超过阈值(当前配置一秒一次) 就会失败
线程数直接失败

系统一次只能处理${单机阈值}个线程数 超过则新进来的线程请求失败

让线程睡0.8秒

关联失败





链路失败
设置资源路口 /testA /testB是统一个资源路口 testA被限制失败之后 testB也会失败

例如 开始设置的阈值为10 设置时间为5秒 冷加载因子(threshold迷人值是3)最初的阈值就是10/3 大致为3 五秒 之后 慢慢阈值升到10
预热


排队等待



这里用testA做 测试

降级规则



sentinel的断路器是没有半开状态的 而Hystrix有
RT

平均响应时间0.2秒 等待回复时间1秒
新建testD
测试



异常比例

设置异常率为20% 超过该异常率 则熔断降级
这边是100%的异常率
压测
停止则正常报错

异常数



启动五次时 就会熔断 过1分钟才会正常报错
热点key限流
操作
根据请求传入的参数进行限流


首先这是默认相应
第0个参数 的访问次数超过QPS的阈值 触发熔断降级

p2一直点则没事
不使用 b
如果将 blockHandler去掉
异常会显示到页面 blockHandler是一个兜底的方法
参数例外项
特殊情况
记得点添加

注意事项
加入异常
这个异常类无法被blockHandler 兜底

sentinel系统规则


总的系统规则 QPS 对cloudalibaba-sentinel-service系统中的所有请求应用都生效
@SentinelResource的配置
修改 8401的pom文件
<!--引入自己定义的api通用包, 可以使用Payment支付Entity-->
<dependency>
<groupId>com.luyi.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
新建一个Controller类
package com.luyi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author 卢意
* @create 2020-11-22 17:33
*/
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value="byResource",blockHandler = "handleException")
public CommonResult byResource(){
return new CommonResult(200,"按资源名称限流OK",new Payment());
}
public CommonResult handleException(BlockException exception){
return new CommonResult(404,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
}

注意选择下面那个 资源名称


新增一个业务没有兜底的方法 使用系统默认


面临的一些问题

客户自定义限流处理逻辑
步骤
package com.luyi.springcloud.alibaba.myHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.luyi.consumer.api.entity.CommonResult;
/**
* @author 卢意
* @create 2020-11-23 13:50
*/
public class CustomerBlockHandler {
public static CommonResult handlerException1(BlockException exception){
return new CommonResult(444,"按客户自定义,global handlerException-----1");
}
public static CommonResult handlerException2(BlockException exception){
return new CommonResult(444,"按客户自定义,global handlerException-----12");
}
}
二号方法兜底
启动8401
正常访问一次http://localhost:8401/rateLimit/customerBlockHandler 让他被sentinel监控
sentinel新增流控规则

兜底的是自定义的方法2
进一步说明
更多属性说明
详细看官网吧




Sentinel服务熔断
Ribbon环境预说明
sentinel整合ribbon+openfeign+fallback

新建 9003 9004
pom文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--sentinel datasource nacos 持久化会用到-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--引入自己定义的api通用包, 可以使用Payment支付Entity-->
<dependency>
<groupId>com.luyi.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
</dependencies>
yml文件
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
# Nacos\u4F5C\u4E3A\u670D\u52A1\u4E2D\u5FC3\u7684\u5730\u5740
server-addr: localhost:8848
management:
endpoints:
web:
exposure:
include: '*'
主启动类
package com.luyi.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author 卢意
* @create 2020-11-23 14:30
*/
@SpringBootApplication
@EnableDiscoveryClient
public class Payment9003 {
public static void main(String[] args) {
SpringApplication.run(Payment9003.class, args);
}
}
Controller层
package com.luyi.springcloud.alibaba.controller;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
* @author 卢意
* @create 2020-11-23 14:31
*/
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
public static HashMap<Long,Payment> hashMap=new HashMap<>();
static {
hashMap.put(1L, new Payment(1L,"199811046510"));
hashMap.put(2L, new Payment(2L,"199811046511"));
hashMap.put(3L, new Payment(3L,"199811046512"));
}
@GetMapping(value = "/payment/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id")Long id){
Payment payment=hashMap.get(id);
CommonResult<Payment> result=new CommonResult(200,"from mysql ,serverport: "+serverPort ,payment);
return result;
}
}
只有3条记录 当Id等于4时为null

新建 消费者 84
pom文件和上面一样
yml文件
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认端口 加入8719被占用 会自动+1扫描直到找到没有被占用的端口
port: 8719
service-url:
nacos-user-service: http://nacos-payment-provider
RestTemplate配置类
package com.luyi.springcloud.alibaba.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author 卢意
* @create 2020-11-23 14:50
*/
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller类
package com.luyi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-11-23 14:51
*/
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL="http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback") //没有配置
public CommonResult<Payment> fallback(@PathVariable Long id){
CommonResult<Payment> result=restTemplate.getForObject(SERVICE_URL, "/payment/"+id,
CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常.....");
}else if(result.getData()==null){
throw new NullPointerException("NullPointerException,该Id没有对应记录.空指针异常.....");
}
return result;
}
}


sentinel 服务熔断无配置
启动84 9003,9004
测试 业务类和 负载均衡无问题

没有设置blockHandler
id3以上都是异常页面

sentinel 服务熔断只配置fallback
修改业务类代码
package com.luyi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-11-23 14:51
*/
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL="http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
public CommonResult<Payment> fallback(@PathVariable Long id){
CommonResult<Payment> result=restTemplate.getForObject(SERVICE_URL+"/payment/"+id,
CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常.....");
}else if(result.getData()==null){
throw new NullPointerException("NullPointerException,该Id没有对应记录.空指针异常.....");
}
return result;
}
//本例是fallback的兜底
public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常类handlerFallback,Exception内容: "+ e.getMessage(),payment);
}
}


结论 fallback可以管理Java的运行异常
sentinel 服务熔断只配置blockHandler
修改业务类
package com.luyi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-11-23 14:51
*/
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL="http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
@SentinelResource(value = "fallback",blockHandler = "blockHandler") // blockHandler 只负责sentinel控制台配置违规
public CommonResult<Payment> fallback(@PathVariable Long id){
CommonResult<Payment> result=restTemplate.getForObject(SERVICE_URL+"/payment/"+id,
CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常.....");
}else if(result.getData()==null){
throw new NullPointerException("NullPointerException,该Id没有对应记录.空指针异常.....");
}
return result;
}
//本例是fallback的兜底
/*public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常类handlerFallback,Exception内容: "+ e.getMessage(),payment);
}*/
//本例是blockHandler的兜底
public CommonResult blockHandler(@PathVariable Long id, BlockException e){
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"blockHandler-sentinel限流,无此流水,BlockException: "+ e.getMessage(),payment);
}
}
新增sentinel降级规则
错误两次以上降级

sentinel 服务熔断blockHandler和fallback都配置
修改业务类
package com.luyi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 卢意
* @create 2020-11-23 14:51
*/
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL="http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") // blockHandler 只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler") //都配置
public CommonResult<Payment> fallback(@PathVariable Long id){
CommonResult<Payment> result=restTemplate.getForObject(SERVICE_URL+"/payment/"+id,
CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常.....");
}else if(result.getData()==null){
throw new NullPointerException("NullPointerException,该Id没有对应记录.空指针异常.....");
}
return result;
}
//本例是fallback的兜底
public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常类handlerFallback,Exception内容: "+ e.getMessage(),payment);
}
//本例是blockHandler的兜底
public CommonResult blockHandler(@PathVariable Long id, BlockException e){
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水,BlockException: "+ e.getMessage(),payment);
}
}
新增流控规则
限流
fallback
点快了又走 blockHandler 流控规则
exceptionToIgnore(异常忽略属性)

OpenFeign

引入openfeign
application加入

主启动类
新增service接口
feign 接口+注解
package com.luyi.springcloud.alibaba.service;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author 卢意
* @create 2020-11-23 15:58
*/
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallBackService.class)
public interface PaymentService {
@GetMapping("/payment/{id} ")
public CommonResult<Payment> payment(@PathVariable("id") Long Id);
}
兜底 实现类
package com.luyi.springcloud.alibaba.service;
import com.luyi.consumer.api.entity.CommonResult;
import com.luyi.consumer.api.entity.Payment;
import org.springframework.stereotype.Component;
/**
* @author 卢意
* @create 2020-11-23 16:02
*/
@Component
public class PaymentFallBackService implements PaymentService{
@Override
public CommonResult<Payment> payment(Long id) {
return new CommonResult<>(444444,"服务降级返回,----PaymentFallBackService",new Payment(id, "errorSerial"));
}
}
controller类加入新代码
启动测试
正常测试无异常


熔断框架的比较


规则持久化

其实只要有持久化的文件都能保存 如redis等等 官方推荐nacos
修改 8401
pom文件 新增 下面依赖
<!--sentinel datasource nacos 持久化会用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
application.yml文件加入下列配置
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow


[
{
"resource":"/byResource",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}
]
json说明
启动8401 当前没有规则


Seata处理分布式事务
分布式事务问题的由来



一次业务操作需要跨多少个数据源或需要跨多少个系统进行远程调用,就会产生分布式事务问题
Seata术语

安装
1.1.0



修改file.conf


创建数据库seata
创建表
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
修改register.conf
启动nacos 在启动SeaTa
业务数据库准备


Create DATABASE seata_order;
CREATE DATABASE seata_storage;
CREATE DATABASE seata_account;
t_account
t_order
t_storage

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = INNODB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
最终效果
业务微服务准备
order


pom 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.luyi.cloud</artifactId>
<groupId>com.luyi.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-order-service2001</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusion>
<artifactId>seata-all</artifactId>
<groupId>io.seata</groupId>
</exclusion>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.1.0</version>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--引入自己定义的api通用包, 可以使用Payment支付Entity-->
<dependency>
<groupId>com.luyi.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</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>
</dependency>
</dependencies>
</project>
Order 实体类
package com.luyi.springcloud.alibaba.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author 卢意
* @create 2020-11-23 19:24
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Long id;
private Long userId;
private Long ProductId;
private Integer count;
private BigDecimal money;
/**
* 订单状态: 0创建中 1已完成
*/
private Integer status;
}
CommonResult.class
package com.luyi.springcloud.alibaba.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 卢意
* @create 2020-11-23 19:48
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message){
this(code,message,null);
}
}
application.yml
server:
port: 2001
spring:
application:
name: seata-order-service
cloud:
alibaba:
seata:
# 自定义事务组名称需要与seata-server中对应
tx-service-group: luyi_tx_group
nacos:
discovery:
server-addr: localhost:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/seata_order
username: root
password: 123456
feign:
hystrix:
enabled: false
logging:
level:
io:
seata: info
mybatis:
mapper-locations: classpath:mapper/*.xml
新建 file.conf
transport {
# tcp udt unix-domain-socket
type = "TCP"
#NIO NATIVE
server = "NIO"
#enable heartbeat
heartbeat = true
# the client batch send request enable
enableClientBatchSendRequest = false
#thread factory for netty
threadFactory {
bossThreadPrefix = "NettyBoss"
workerThreadPrefix = "NettyServerNIOWorker"
serverExecutorThreadPrefix = "NettyServerBizHandler"
shareBossWorker = false
clientSelectorThreadPrefix = "NettyClientSelector"
clientSelectorThreadSize = 1
clientWorkerThreadPrefix = "NettyClientWorkerThread"
# netty boss thread size,will not be used for UDT
bossThreadSize = 1
#auto default pin or 8
workerThreadSize = "default"
}
shutdown {
# when destroy server, wait seconds
wait = 3
}
serialization = "seata"
compressor = "none"
}
# service configuration, only used in client side
service {
#transaction service group mapping
# vgroupMapping.my_test_tx_group = "default"
vgroupMapping.luyi_tx_group = "default"
#only support when registry.type=file, please don't set multiple addresses
default.grouplist = "127.0.0.1:8091"
#degrade, current not support
enableDegrade = false
#disable seata
disableGlobalTransaction = false
}
#client transaction configuration, only used in client side
client {
rm {
asyncCommitBufferLimit = 10000
lock {
retryInterval = 10
retryTimes = 30
retryPolicyBranchRollbackOnConflict = true
}
reportRetryCount = 5
tableMetaCheckEnable = false
reportSuccessEnable = false
sqlParserType = druid
}
tm {
commitRetryCount = 5
rollbackRetryCount = 5
}
undo {
dataValidation = true
logSerialization = "jackson"
logTable = "undo_log"
}
log {
exceptionRate = 100
}
}
## transaction log store, only used in server side
store {
## store mode: file、db
mode = "db"
## file store property
file {
## store location dir
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
maxBranchSessionSize = 16384
# globe session size , if exceeded throws exceptions
maxGlobalSessionSize = 512
# file buffer size , if exceeded allocate new buffer
fileWriteBufferCacheSize = 16384
# when recover batch read size
sessionReloadReadSize = 100
# async, sync
flushDiskMode = async
}
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
datasource = "dbcp"
## mysql/oracle/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://127.0.0.1:3306/seata"
user = "root"
password = "123456"
minConn = 1
maxConn = 10
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
}
}
## server configuration, only used in server side
server {
recovery {
#schedule committing retry period in milliseconds
committingRetryPeriod = 1000
#schedule asyn committing retry period in milliseconds
asynCommittingRetryPeriod = 1000
#schedule rollbacking retry period in milliseconds
rollbackingRetryPeriod = 1000
#schedule timeout retry period in milliseconds
timeoutRetryPeriod = 1000
}
undo {
logSaveDays = 7
#schedule delete expired undo_log in milliseconds
logDeletePeriod = 86400000
}
#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
maxCommitRetryTimeout = "-1"
maxRollbackRetryTimeout = "-1"
rollbackRetryTimeoutUnlockEnable = false
}
## metrics configuration, only used in server side
metrics {
enabled = false
registryType = "compact"
# multi exporters use comma divided
exporterList = "prometheus"
exporterPrometheusPort = 9898
}
注意这里
新建 register.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "localhost:8848"
namespace = ""
cluster = "default"
}
eureka {
serviceUrl = "http://localhost:8761/eureka"
application = "default"
weight = "1"
}
redis {
serverAddr = "localhost:6379"
db = "0"
}
zk {
cluster = "default"
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 2000
}
consul {
cluster = "default"
serverAddr = "127.0.0.1:8500"
}
etcd3 {
cluster = "default"
serverAddr = "http://localhost:2379"
}
sofa {
serverAddr = "127.0.0.1:9603"
application = "default"
region = "DEFAULT_ZONE"
datacenter = "DefaultDataCenter"
cluster = "default"
group = "SEATA_GROUP"
addressWaitTime = "3000"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "file"
nacos {
serverAddr = "localhost"
namespace = ""
group = "SEATA_GROUP"
}
consul {
serverAddr = "127.0.0.1:8500"
}
apollo {
app.id = "seata-server"
apollo.meta = "http://192.168.1.204:8801"
namespace = "application"
}
zk {
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 2000
}
etcd3 {
serverAddr = "http://localhost:2379"
}
file {
name = "file.conf"
}
}
dao接口及实现
package com.luyi.springcloud.alibaba.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @author 卢意
* @create 2020-11-23 19:52
*/
@Mapper
public interface Order {
// 新建订单
void create(Order order);
// 更新订单状态 0变1
void update(@Param("userId") Long userId,@Param("status") Integer status);
}
太多了我放弃了 无脑抓图











storage

pom文件和2001一样









Account








@GlobalTransaction验证



数据库内容每错

openfeign会报超时异常

状态为0
库存被扣了
账户也被扣钱了


测试没有问题
seata原理简介





是什么
一阶段




debug看看

分支号不同 xid相同
rollback_info格式化查看一下
已经将前置和后置快照保存好,便于数据更新和回滚恢复


反向补偿或者正常提交 会批量删除相印的UNDO LOG记录
补充

ok结束 不得不说阳哥是我听过讲的最好的老师了 感谢指导 我会好好温故而知新 慢慢深入理解.



