参考课程:SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务_哔哩哔哩_bilibili
本文是黑马微服务SpringCloud课程的总结,文章总结内容包括:分布式事务Seata,Docker
分布式事务
分布式事务理论基础
我们库存失败了,但是余额却扣减了,这个时候我们的事务的状态不是一致的
我们前面的事务没有跟着回滚
——————————————————————————————————
理论基础
CAP定理
BASE理论
一致性
可用性
分区容错性
网络分区时,可用性和一致性不能同时满足
_____________________________________________
BASE理论
基本可用
软状态
最终一致性
事务协调者
初识Seata
三个重要角色
事务协调者
事务管理器
资源管理器
我们在运行我们的seata之前,还有修改我们的配置
修改配置
其实我们的配置就包含这两部分
registry 注册
config 配置
然后其实,我们只要nacos注册中心,他下面那些我们都不要了
config是我们的配置中心
dataId就是将来配置的那个文件名
为了让我们共享配置,我们选择了nacos作为我们的配置中心
springboot启动类没有被识别
然后我们在我们的nacos里面来写我们的配置
copy一下就好了
创建表
然后就是启动我们的TC服务了
可以看到我们的端口是8091
————————————————————————————————————————
如果是mysql8
mysql版本8.0以上的要换驱动
我的是数据库时区问题,在nacos的数据库url上添加&serverTimezone=Asia/Shanghai
我的是,服务根本就没有注册进去nacos2
靠,怎么搞都不成功,下载一个最新的seata看看
版本说明 · alibaba/spring-cloud-alibaba Wiki · GitHub
然后我发现关什么版本的事情,我的那个registry文件写错了,我重新copy进去就行了
ok,我的服务进来了
————————————————————————————————————————————
微服务集成SEATA
第一个依赖是springcloud的起步依赖
但它内部有个默认的seata,版本是1.3,我们要把这个内部的seata依赖给排除了
然后重新引入一个版本,指定成1.4.2
引入依赖之后,我们的微服务就有了自动装配功能了
所以seata的所有东西我们都不需要去管他,他能自动去搞
我们只需要告诉这个服务,TC地址在哪里
他们一旦去连接,后面的事情就不用我们去操作了
我们不能写死地址,要基于注册中心去得到我们的地址
type:nacos,说明我们的注册中心的类型是我们的nacos
要去nacos里面找到我们的信息
我们要正确的拿到这四个信息,我们才能确定这个服务
namespace为空的话,默认就是public
类似于刚刚的seata的registry文件的一一对应
为什么没有cluster呢?因为我们的cluster比较复杂,不能在这里配置
事务组
他的做法是配置了一个事务组
如果你希望将来不同的事务被同一个TC管理,那么就让他们是一个事务组
这个是我们的事务组和cluster的映射关系
引入seata依赖
引入依赖完成后,就到我们的配置地址了
我们的seata没有和springcloud里面的nacos做好集成关系,所以我们还要去配
我们重新启动服务,我们的RM就注册上来了
但我的三个java项目都没有注册到我们的nacos里面
我等等自己弄弄
导入我们的LoadBalancer依赖
这是我们的dependency的版本
我要修改黑马项目的版本成2022.0.0.0
spingcloud springcloud 阿里巴巴 springboot nacos,这四个东西我们的版本都要一一对应
ok刷新进来了
实践
XA模式
XA模式
强一致性
实现XA模式
首先,在配置里面开启我么的XA模式
在全局事务的入口添加GlobalTransactional注解
AT模式
不等待直接提交
AT模式的脏写问题
为了解决这个东西,我们引入了全局锁
写隔离
实现AT模式
seata是给tc服务用的
seata_demo是给我们的微服务用的
然后我们的全局锁表就有了
把我们的模式改成AT
我们用POSTMAN去做一个测试
报了500错误
我们去数据库看看数据有没有恢复
没有创建新的订单,没有扣减余额,库存没有扣减
这就说明我们的事务生效了
我们的分布式事务都回滚
看看日志
我们发现undo_log表的信息没了
TCC模式
性能模式,不需要加锁
TCC通过人工编码实现数据恢复
资源检测和预留,例如冻结我们的余额
利用TCC实现分布式事务
try和concel之间要互相进行判断,这样才能判断我们是否需要空回滚
我们必须在数据库里面去记录我们当前的状态
我们要判断到底是在try,cancel还是confirm状态???才能做空回滚
声明TCC接口
把frezz表导入进去
IMPL
然后就要开始写我们的空回滚判断
空回滚总不能返回空吧
不管有没有空回滚,我们都有一个记录进去
但是如果我们超时了的话还是会出问题的,所以我们要做一个幂等判断
而且try必须是第一次执行
我们把Controller里面的那个service改成我们的TCCService
发请求
Saga模式
seata高可用
我们要加-p参数来指定我们的启动的端口
可以看到我们这里有两个seata了
有两个集群
我们想让我们的集群变化是动态的,那么我们就要把我们的集群配置配置到我们的nacos上面
我们把配置配置到nacos之后,我们就要从nacos里面来读取我们的配置了
微服务读取我们的nacos配置
我们把配置改成HZ
然后我们跟8091断开了,到我们的8092上建立连接了
所以这样就已经实现seata服务的异地集群的一个切换
Docker
初始docker
镜像
镜像是只读的,我们不能往里面写东西
把镜像共享给别人使用
安装
如何知道当前操作系统是centos的哪个版本和内核版本?_centos查看系统内核-CSDN博客
我们要删除干净
说明我们没有安装docker
-y就是,我们安装过程中不要往下问,我们直接安装
关闭防火墙
我们自己学的时候,直接关闭防火墙就好了
# 关闭
docker命令
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
systemctl start docker # 启动docker服务
systemctl stop docker # 停止docker服务
systemctl restart docker # 重启docker服务
我们应该怎么知道我们启动了docker呢
(active)runing,说明我们启动成功
docker -v
来查看我们的版本
————————————————————————
配置镜像
镜像命令
tag
如果没有指定tag,那么默认就是最新版本的镜像
docker build
构建镜像
docker push
推送镜像到服务
docker pull
从服务拉取镜像
docker save
保存镜像为一个压缩包
docker load
加载压缩包为镜像
docker-help
我们输入
docker -help
就可以查看我们的所有命令了
例如
docker image --help
从dockerhub拉取镜像
我们来拉取nginx镜像
docker pull nginx
拉取的速度会比较慢
docker images查看镜像
我们docker images来查看我们的镜像
用 save命令来导出磁盘,再通过load加载回来
- o就是输出文件,输出到哪个文件
docker save
后面的image就是,你要输出的是哪一个镜像
文件不存在就会自动创建
我们用ll查看,我们本地出现了我们刚刚的文件
docker rmi
我们删除镜像
我们成功删掉了
docker load
docker load -i nginx.tar -q
-q,就是安静的,就是不打印日志
ok我们重新下载回来了
容器命令
docker run
docker exec
docker logs
docker ps
docker rmi
docker start
docker stop
docker pause
dokcer unpause
案例一
一般dockerhub会有我们的使用指南
我们创建一个nginx容器来试试
我们创建运行一个nginx容器
docker run
run,创建容器
name,给这个容器起名字
p,将宿主机端口与容器端口做映射
d,后台运行容器
nginx,镜像的名称
我们运行成功之后,下面生成的那一大串就是我们的容器的唯一ID
docker ps
来查看我们的容器的状态
ip addr,来查看虚拟机的ip
ip config
然后查看80端口
发现我们做了映射
docker logs xx
我们docker logs xx来查看我们的日志
发现我们发起了两次请求
我们每次输入才会看到日志,这样子很不方便
我们看看我们的帮助文档,-f,就是跟踪日志输出的意思
案例2
docker exec
进入容器内部
docker exec -it mn bash
我们进入了我们的容器的内部了,这个东西和我们的容器的ID一模一样
容器的内部会有自己的一套文件系统
pwd
ls
都可以使用
官方文档中有
看官方文档找目录
我们的静态文件的文件夹在这里
我们想修改文件内容,发现vi这个命令用不了
说明我们封装的是阉割版的系统
我们可以这样子来替换
exit
我们用exit来退出我们的容器
docker ps -a
我们默认只展示运行中的容器,我们加个-a,那么我们挂掉的容器也可以看到了
docker rm -f
我们不能删除运行中的容器,我们要让他先停下来
我们查看帮助文档,我们的-f可以做到强制删除
容器命令练习
docker run
我弄了6377端口对应容器里面的6379端口
名字,mrds
然后我们连接,发现redis确实可以连接上
然后我们进入我们的容器
然后我们用redis-cli命令来进入我们的redis里面
我们发现确实存进来了
我们之前是先bash
再进入我们的redis-cli
exec是进入容器执行命令
我们这样子可以一步到位
数据卷命令
我们要想办法解决容器与数据耦合的问题
volume是一个虚拟目录,指向宿主机文件系统中的某个目录
docker volume
create
inspect
ls
prune
rm
docker volumn--help
来查看我们的帮助文档
inspect
查看这个数据卷的详细信息
这样子就显示出了我们的这个数据卷的详细信息
我们这样子就知道了我们的数据卷挂在哪里了
prune
删除所有的没有使用的数据卷
rm
docker volumn rm xx指定删除我们的数据卷
挂载案例1
-v
通过-v参数来挂载一个数据卷到某个容器目录
我们的容器内部数据的地址
是在我们的官方文档里面写着的
我们ls查到了数据,这说明了啥
这说明了我们把容器里面的数据已经挂载到我们的虚拟机里面了
而且我们创建数据卷的时候,数据卷不存在,我们也可以自动把这个数据卷创建出来
挂载案例2
我们可以直接宿主机的文件直接覆盖我们的容器里的文件
资料里面已经准备好了我们的mysql的配置文件了
我们的mysql配置搞定了,接下来就是来运行我们的mysql容器了
这个-e,是我们的环境变量
就是我们的mysql的root的密码,这个可以让我们直接搞定我们的密码
因为命令比较长,我们建议采用换行符\的写法
这个.d结尾的,是一个目录
在这个cnf里面,它包含了这两个目录
所以放到这两个目录的一切文件最后都会被加载到一起去,作为合并配置
所以我们的配置是放在这个目录下
data存储目录
成功
我们看看我们的data目录,发现数据已经挂载过来了
然后我们测试一下我们的mysql连不连接的上
ok,我连接上了
这个的优势是,我们目录是我们自己创建的,所以我们比较清楚
自定义镜像
从基础开始,分层逐层构建
DockerFile
打开我们的资料
我们的java项目的运行,需要我们的jdk
我们把这三个东西上传上来
不管怎么样,我们的前n层都不会变,那么就把这前n层提前构建好
DockerCompose
初始化Compose
这个是我们的集群部署的手段
Overview | Docker Docs,官方网站
目前这个文件是没有权限x的
我们用chmod给它加权限
+x,就是给它执行权
部署微服务集群
我们用dockercompose部署时,所有的服务之间都可以用服务名来进行访问
这个就是指定我们的打包后的名称
我们把demo文件弄进来
docker compose--help
up启动
down停止
启动
查看日志
我们运行时,发现日志里面报错了
这是因为我们先是userservice启动,然后才是nacos启动
我们的nacos启动的太慢了
而且它失败了也不重试一下,这个是springcloud阿里巴巴的bug
我们应该先为nacos部署,然后再为其他服务部署
我们来重启一下其他服务
重启完成之后我们再查看日志
我草,部署成功了,访问到了,我草我草
docker镜像仓库
构建,启动
查看日志
然后我们在网址搜索,我们的图形化界面就出现了
前面是我们的私有仓库的地址,然后才是我们的镜像名
docker images,我们看到我们的镜像已经打包成功了
这两id一样,所以本质上是一样的,只是重命名了而已
ok,push成功了
- 拉取的话就点这个,他会把我们的拷贝命令给复制下来
删除
我们拷贝一下那个拉取命令然后执行,发现又下载回来了