Nacos,Sentinel,Seata

Spring Cloud Netflix项目进入到维护模式,SpringCloud和Alibaba整合了,来代替之前的Netflix。
所用到的项目,请参考这里
.
spring-cloud-alibaba 版本说明

Nacos

Nacos 源码分析:Nacos 源码解读

spring-cloud-alibaba-nacos
服务注册和配置中心
2020-05-26 13:50:51

Nacos简介

1)、为什么叫Nacos?
Nameing Configuration Service

2)、是什么?
一个更易于构建原生应用的动态服务发现、配置管理和服务管理平台
Nacos就是注册中心,配置中心的组合:Nacos = Eureka + Config + Bus

3)、能干嘛?
、替代Eureka做服务注册中心
、替代Config做服务配置中心

4)、相关文档
https://nacos.io/zh-cn/
https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
https://github.com/alibaba/Nacos
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_nacos_discovery

5)、各种注册中心对比

注册中心 CAP对比

在这里插入图片描述

安装并运行Nacos

这里使用Docker安装Nacos单机版

服务注册中心演示

Nacos作为服务注册中心演示

1)、提供者9001
注意:父POM也要引入对应的spring-cloud-alibaba-dependencies依赖
在这里插入图片描述

2)、copy配置,在9011端口启动项目。
在这里插入图片描述

3)、提供者9002
为了后面的演示使用。
建立同9001,只是端口号配置不同。

在这里插入图片描述

4)、消费者83
默认集成Ribbon
在这里插入图片描述

5)、测试
启动9001,9002,83,访问http://localhost:83/consumer/payment/nacos/1

在这里插入图片描述

服务注册中心对比

》》》生态图
在这里插入图片描述

》》》Nacos和CAP
在这里插入图片描述

》》》Nacos支持AP和CP模式的切换
在这里插入图片描述

服务配置中心演示

Nacos作为服务配置中心演示

1)、基础配置

》》》3377,读取配置中心内容
在这里插入图片描述

》》》分析
在这里插入图片描述

配置中心的名称Data Id的后缀名要和bootstrap.yml的file-extension属性对应
如果Data Id的后缀名和bootstrap.yml的file-extension属性可以同时为yml,或yaml,但不可以一个是yml,一个是yaml
在这里插入图片描述
在这里插入图片描述

》》》修改发布,自动更新
在这里插入图片描述

2)、分类配置

》》》group
默认:DEFAULT_GROUP
在这里插入图片描述

》》》namespace
默认:空 , 找的是对应public,因为public命名空间ID为空
在这里插入图片描述

3)、小总结

1
2
3
4
5
6
7
8
项目配置文件 》》》 Nacos配置文件


public 》》》 Namespace ID
group 》》》 Group名称
应用名称 》》》 Data Id的前
激活环境 》》》 Data Id的后
文件扩展名 》》》 Data Id的后缀

Nacos集群,持久化

2020-05-28 15:38:27 这个折腾了好久,终于完成了。
docker启动的Nginx与docker-compose启动的nacos集群进行负载均衡配置

1)、首先你要启动三个nacos集群。
使用Docker安装Nacos集群,MySQL

2)、这时候,你可以使用docker network ls来查看哪些网络
使用下面两种方式之一来查看对应nacos容器的端口

1
2
3
4
5
# 查看网络example_default下的所有已启动容器的IP地址
docker network inspect example_default

# 查看名称为nacos1的容器IP地址
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nacos1

在这里插入图片描述

3)、关于Nginx的配置,参考Dcoker 启动Nginx
但是你不要启动,如果启动了,可以使用docker rm -f 容器名称进行删除容器

4)、修改nginx的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# upstream名称
# 不能使用下划线 _ 进行拼接
# 可以使用减号 - 进行拼接
upstream nacos-cluster{
server 172.18.0.4:8848;
server 172.18.0.5:8849;
server 172.18.0.3:8850;
}

server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nacos-cluster;
}
}

5)、启动Nginx
你可以使用下面来启迪,指定网络 example_default
这样可以保证nginx与nacos集群处于同一网段。此时就可以ping通。

1
2
3
4
5
6
7
docker run --name nginx01 -p 80:80 \
-v /app/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /app/docker/nginx/conf/default.conf:/etc/nginx/conf.d/default.conf \
-v /app/docker/nginx/html/:/usr/share/nginx/html \
-v /app/docker/nginx/log/:/var/log/nginx \
--network example_default \
-d nginx

在这里插入图片描述

6)、访问192.168.1.1/nacos即可,80端口可以省略
注意:后面要加上 /nacos

7)、测试
在这里插入图片描述

8)、坑:
如果向上面正常配置,但还是不能访问。
、可能是因为你的docker-compose启动的容器问题,可以尝试,先docker rm -f 容器名称删除启动的四个容器
、可能是你的Nginx配置错误,可以尝试先配置一个,看看能不能正常访问proxy_pass http://172.18.0.4:8848

Sentinel

spring-cloud-alibaba-sentinel
熔断与限流
2020-05-29 08:08:53

Sentinel简介

1)、官网
https://github.com/alibaba/Sentinel

2)、是什么?
一句话解释就是我们之前讲过的hystrix
在这里插入图片描述

3)、能干嘛?
在这里插入图片描述

4)、怎么玩?
、服务雪崩
、服务降级
、服务熔断
、服务限流

安装并运行Sentinel

参考Docker 安装 sentinel-dashboard

初始化演示功能

1)、搭建8401
在这里插入图片描述

2)、测试8401
多访问几次http://localhost:8401/testA http://localhost:8401/testB

查看实时监控簇点链路
注意:只有你访问之后,簇点链路的列表中才会出现对应的资源。你不访问的路径,也就不会在簇点链路中出现。
在这里插入图片描述

流控规则

1)、基本介绍
在这里插入图片描述

2)、流控模式

》》》直接(默认)
、QPS配置及说明
在这里插入图片描述
、快速点击访问http://localhost:8401/testA
结果 Blocked by Sentinel(flow limiting)
在这里插入图片描述

、线程数
此时线程数1,如果JMeter持续1线程在调用,浏览器再访问就会报默认异常。

解释:如果线程数改为2,如果JMeter持续1线程调用,浏览器再访问也正常。但是JMeter持续2线程调用,浏览器再访问就失败了。
因为JMeter线程数2,加上你浏览器的线程数1,总共3线程了,大于流控模式的2了。
在这里插入图片描述

、QPS 与 线程数 区别?
QPS是挡在外面的,线程数在挡在里面的。
QPS=3,一个医生办公室只能进3个病人。多余的人在外面等待(异常)。
线程数=1,一个医生办公室进多少人都可以,但里面只有一个医生。不能再有医生进入这个办公室(异常)。

》》》关联
、是什么?
当关联的资源达到阈值时,就限流自己
当与A关联的资源B达到阈值后,就限流自己
B惹事,A挂了

、配置A
在这里插入图片描述

、JMeter测试
在这里插入图片描述

》》》链路
省略。。。

3)、流控效果

》》》快速失败
、默认的流控处理,直接失败,抛出异常Blocked by Sentinel(flow limiting)
、源码com.alibaba.csp.sentinel.slots.block.controller.DefaultController

》》》Warm Up
、公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值
、官网,限流 冷启动https://github.com/alibaba/Sentinel/wiki/限流---冷启动
在这里插入图片描述
、默认coldFactor为3,即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值
在这里插入图片描述
、应用场景:如:秒杀系统在开启瞬间,会有很多流量上来,很可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

、案例配置
在这里插入图片描述

》》》排队等待
、匀速排队,阈值必须设置为QPS
、源码:com.ailibaba.csp.sentinel.slots.block.controller.RateLimiterController
、一间医生办公室,只能一秒处理一个病人。多余的病人在门口等待,最多病人等待2秒就受不了了,不等了(异常)。
在这里插入图片描述

降级规则

https://github.com/alibaba/Sentinel/wiki/熔断降级

1)、RT(平均响应时间)
在这里插入图片描述

2)、异常比例
在这里插入图片描述

3)、异常数
在这里插入图片描述

热点规则

官网:https://github.com/alibaba/Sentinel/wiki/热点参数限流
代码:com.alibaba.csp.sentinel.slots.block.BlockException

1)、有位置0的参数,并且QPS>1,就熔断。
在这里插入图片描述

2)、当p1=5时,QPS>200才会熔断。
在这里插入图片描述

3)、blockHandler兜底方法只针对配置的热点规则生效,对方法内的异常是不进行处理的。
在这里插入图片描述

系统规则

官网:https://github.com/alibaba/Sentinel/wiki/系统自适应限流
在这里插入图片描述

@SentinelResource

、官网:https://github.com/alibaba/Sentinel/wiki/注解支持
、官网截图
在这里插入图片描述

1)、指定流控兜底方法
如果资源名称添加的是@GetMapping中的/byResource,那么就会使用默认的兜底方法 Blocked by Sentinel (flow limiting)
如果资源名称添加的是@SentinelResource的value值byResource,那么就会使用它的blockHandler所指定的方法。
在这里插入图片描述

注意:此时关闭服务8401,会发现Sentinel的流控规则消失了。
重启之后,之前的那条流控规则也不会存在,后面我们会讲持久化。

2)、测试无兜底方法
如果不指定blockHandler兜底方法,那么控制台会报出 This application has no explicit mapping for /error, so you are seeing this as a fallback.
在这里插入图片描述

3)、自定义限流
在这里插入图片描述

服务熔断功能

1)、环境搭建 提供者9003,9004
新建提供者9003,再复制一份提供者9004,只是端口不同。下面只给出9003的截图。
在这里插入图片描述

2)、环境搭建 消费者84
在这里插入图片描述

3)、测试访问http://localhost:84/consumer/fallback/1,默认负载均衡:轮询
在这里插入图片描述

5)、不指定fallback,也不指定blockHandler
这个是上面84默认的。
在这里插入图片描述

6)、只指定fallback(异常)
注意:
、这里修改了@SentinelResource之后,devtools会不生效,需要重启项目。
、但是,我们没有配置持久化,也就是说,停止服务之后,在Sentinel配置的规则会消失,启动之后也不会再出现。
、这个是Sentinel的持久化问题,在后面我们再讨论,下面每修改一次@SentinelResource,都需要重启项目,重新配置流控规则。
在这里插入图片描述

7)、只指定blockHandler(监控)
在这里插入图片描述

8)、指定fallback(异常),指定blockHandler(监控)
在这里插入图片描述

9)、指定异常,不进行fallback处理
在这里插入图片描述

10)、OpenFeign整合Sentinel
关闭9003,9004之后,会发现服务进行降级。
在这里插入图片描述

规则持久化

1)、是什么?
一旦我们重启应用,Sentinel规则消失,生产环境需要将配置规则进行持久化。

2)、怎么玩?
将限流规则持久进Nacos保存,只要刷新8401某个rest地址,Sentinel控制台的流控规则就能看得到,只要Nacos里面的配置不删除,针对8401上的流控规则持续有效。

3)、配置,测试【重启之后,规则恢复】
在这里插入图片描述

Seata

spring-cloud-alibaba-seata
处理分布式事务

简介

0)、问题引入
分布式事务问题:一次业务操作需要垮多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题

案例:用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:
、仓储服务:对给定的商品扣除仓储数量。
、订单服务:根据采购需求创建订单。
、帐户服务:从用户帐户中扣除余额。
在这里插入图片描述

1)、是什么?
官网地址:http://seata.io/zh-cn/
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务

2)、能干嘛?
一个典型的分布式事务过程:

》》》ID + 三组件
Transaction ID(XID):全局唯一的事务id

TC - 事务协调者(Transaction Coordinator)
维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM - 事务管理器(Transaction Manager)
定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM - 资源管理器(Resource Manager)
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

》》》处理过程

  1. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
    、班主任向讲师申请问:可不可以开班?可以的话,我们就建立班级网课直播间XID
  2. XID在微服务调用链路的上下文中传播;
    、班主任把XID在微信群里面上下文传播,只要加进来,具备XID的就是这次网课的同班同学
  3. RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;
    、所有同学往直播间刷1,这时候,注册进来的学生就是讲师的管辖范围,可能会叫你回答问题。不要被逮到玩手机,可能把你踢出去。
  4. TM向TC发起针对XID的全局提交或回滚决议;
    、班主任说:所有同学进行签到,看一下人都到齐了吧,好,到齐了,告诉讲师:你可以上课了
  5. TC调度XID下管辖的全部分支事务完成提交或回滚请求。
    、在这节课的50分钟,全班同学都可以听到。如果结课了,我们再提交,那么就下课了,我们就上到这。

在这里插入图片描述

3)、去哪儿下?
当前2020-06-01 13:32:33,下载-GA版本。v1.0.0-GA
https://github.com/seata/seata/releases

4)、怎么玩?
、本地:@Transactional
、全局:@GlobalTransactional
在这里插入图片描述

Seata-Server安装

参考Docker 安装 Seata

数据库准备

1)、分布式事务业务说明
在这里插入图片描述

2)、SQL准备
》》》数据库
、seata_order:订单
、seata_storage:库存
、seata_account:账户

》》》按照上述3库分别建立对应业务表
、seata_order库下新建t_order表
、seata_storage库下新建t_storage表
、seata_account库下新建t_account表

》》》按照上述3库分别建立对应的回滚日志表
、订单-库存-账户3个库下都需要建undo_log各自独立的回滚日志表

3库6表 SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
create database if not exists seata_order character set utf8;

use seata_order;

DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) 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:已完结',
PRIMARY KEY (`int`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic;


CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;





create database if not exists seata_storage character set utf8;

use seata_storage;


DROP TABLE IF EXISTS `t_storage`;
CREATE TABLE `t_storage` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
`total` int(11) DEFAULT NULL COMMENT '总库存',
`used` int(11) DEFAULT NULL COMMENT '已用库存',
`residue` int(11) DEFAULT NULL COMMENT '剩余库存',
PRIMARY KEY (`int`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '库存' ROW_FORMAT = Dynamic;
INSERT INTO `t_storage` VALUES (1, 1, 100, 0, 100);



CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;





create database if not exists seata_account character set utf8;

use seata_account;

CREATE TABLE `t_account` (
`id` bigint(11) NOT NULL 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 NULL COMMENT '剩余可用额度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '账户表' ROW_FORMAT = Dynamic;

INSERT INTO `t_account` VALUES (1, 1, 1000, 0, 1000);


CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

3)、创建好之后,注意:account和storage里面都已经存在了一条记录。
在这里插入图片描述

微服务准备

1)、业务需求
下订单->减库存->扣余额->改(订单)状态

2)、新建订单Order-Module
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3)、新建账户,库存模块。就不截图了。

4)、声明一下

》》》我是使用Docker安装的MySQL,Nacos,Seata。
在这里插入图片描述

》》》Seata的容器的配置文件file.conf,registry.conf 与 模块下的Resource下的file.conf,registry.conf是不同的。
注意:我蓝色的三个地方,就是在这里我碰到的坑。
在这里插入图片描述

》》》还有如果你也和我一样Docker启动的Seata的话,需要配置一下Windows的路由,参考Windows访问Linux虚拟机里面的Docker容器

测试

》》》不加Seata的@GlobalTransactional注解
http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100
在这里插入图片描述
在这里插入图片描述

结果:(失败)账户内扣钱了,但是订单的状态却没有改变。

》》》加上@GlobalTransactional注解
http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100
在这里插入图片描述
在这里插入图片描述

结果:(成功)碰到了调用超时之后,全部回滚。

》》》关于@GlobalTransactional注解
在这里插入图片描述

补充

1)、再看TC/TM/RM三个组件

1
2
3
4
5
6
分布式事务的执行流程
TM开启分布式事务(TM向TC注册全局事务记录)
按业务场景,编排数据库、服务等事务内资源(RM向TC汇报资源准备状态)
TM结束分布式事务,事务一阶段结束(TM通知TC提交/回滚分布式事务)
TC汇报事务信息,决定分布式事务是提交还是回滚
TC通知所有RM提交/回滚资源,事务二阶段结束

在这里插入图片描述

2)、AT模式如何做到对业务的无侵入

》》》是什么?
在这里插入图片描述

》》》一阶段加载
在这里插入图片描述

》》》二阶段提交
在这里插入图片描述

》》》二阶段回滚
在这里插入图片描述

3)、Debug
在这里插入图片描述

4)、补充
在这里插入图片描述

5)、done…
2020-06-05 16:16:21 以此纪念