很清晰的一节课:https://www.bilibili.com/video/BV1S142197x7?p=68&vd_source=a51416fdc1c05fee728077538bb353b8
微服务架构背景
架构演进阶段:
前后端不分离——>前后端分离单体架构——>前后端分离微服务架构
单体架构
将所有业务的所有功能集中在一个项目中开发,打成一个包部署。单体架构适合开发功能相对简单,规模较小的项目。
微服务架构
微服务架构,是服务化思想指导下的一套最佳实践架构方案。服务化,就是把单体架构中的功能模块拆分为多个独立项目。
一个微服务用一个数据库,单独打包部署。
SpringCloud架构
springcloud里面包括了各种微服务的组件用于解决微服务各种问题,可以说springcloud是一个生态,里面的组件只是各个厂商开发的比较好用的微服务组件,并不一定是spring厂商开发的。
微服务项目结构
https://www.bilibili.com/video/BV1S142197x7?p=42&vd_source=a51416fdc1c05fee728077538bb353b8
目前微服务的项目结构主要有两种:独立Project和Maven聚合。
独立Project
每个微服务一个project项目,把他们放在一个普通文件夹中就行。
Maven聚合
使用Maven聚合的方式,但是和传统的方式区别是:
①传统是只有一个模块有启动类,相互模块之间有依赖有调用。
②这种是每个模块都有自己的启动类,模块之间没有依赖调用,只有继承父模块。
服务远程调用问题
把系统拆成一个个微服务其中一个问题就是,跨数据库的业务操作,你不能直接访问其他微服务的数据库,那怎么办呢?
解决的思路是“如果你A微服务需要B微服务的数据,那就在B微服务写一个接口,然后A发起网络请求”。
注册中心
但是如果只是直接调用这种简单粗暴的方式明显还会有一些问题:
①如果微服务很多的话不方便统一管理,比如哪几个微服务的端口变了等。
②如果某个微服务宕机了,无法实时检测到。
基于上面的问题就有了注册中心,我每次需要访问其他微服务接口的时候问注册中心待访问微服务的端口就行。
注册中心原理
注册中心组件
目前开源的注册中心框架有很多,国内比较常见的有:
Eureka: Netflix公司出品,目前被集成在SpringCloud当中,一般用于Java应用
Nacos: Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用
Consul: HashiCorp公司出品,目前集成在SPringCloud中,不限制微服务语言
我们使用Nacos
部署Nacos
教程:https://blog.csdn.net/weixin_44485316/article/details/131344689
教程:https://blog.csdn.net/studio_1/article/details/132160081
# 拉取镜像
docker pull nacos/nacos-server
# 查看镜像
docker images
# 将镜像打包存储到一个位置
docker save d3063c1db2bb -o D:\file\nacos.tar
# 拷贝到linux服务器将tar包
# 到linux服务器加载镜像
docker load < nacos.tar
# 查看导入结果,
docker images。
# 加载成功后REPOSITORY和TAG显示none,需要我们修改标签
docker tag d3063c1db2bb nacos/nacos-server:版本号
# 创建映射文件
mkdir -p /home/nacos/data/conf
mkdir -p /home/nacos/data/logs
mkdir -p /home/nacos/data/data
# 启动镜像,创建一个临时容器
docker run --name nacos -d -p 8848:8848 -e MODE=standalone nacos/nacos-server
# 复制配置文件到本地
docker cp nacos:/home/nacos/logs/ /home/nacos/data
docker cp nacos:/home/nacos/conf/ /home/nacos/data
docker cp nacos:/home/nacos/data/ /home/nacos/data
# 删除临时容器
docker rm -f nacos
# 修改 Nacos 配置文件 application.properties(修改自己的mysql地址、账号、密码等信息)
vi /home/nacos/data/conf/application.properties
# 启动容器
docker run -d \
--name nacos \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
-e MODE=standalone \
-v /home/nacos/data/logs/:/home/nacos/logs \
-v /home/nacos/data/conf/:/home/nacos/conf \
-v /home/nacos/data/data/:/home/nacos/data \
--restart=always \
nacos/nacos-server
访问:http://10.1.40.87:8848/nacos
配置登录鉴权
# 在application.properties文件中添加如下配置即可,设置秘钥,开启鉴权保存即可(热部署),账号密码默认nacos(怎么自定义没找到)
nacos.core.auth.plugin.nacos.token.secret.key=${NACOS_AUTH_TOKEN:SecretKey01234567890123456789012345345678999987654901234567890123456789}
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=nacos
nacos.core.auth.server.identity.value=nacos
服务注册、服务发现和负载均衡
服务注册
spring:
application:
name: 微服务名
cloud:
nacos:
discovery:
server-addr: nacos注册中心
username: nacos
password: nacos
远程服务调用开源技术
远程服务调用开源技术有openFeign、Dubbo
OpenFeign
分布式事务问题
由于将单体应用拆分成了微服务的形式,调用其他微服务的方式由原来的依赖直接调用变成了调用web api的形式,这样就会破坏事务的四大特性(原子性、一致性、隔离性、持久性),进而无法进行事务的回滚操作。
Seata解决
Seata是2019年1月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。致力于提供高性能和简单易用的分布式事务服务,为用户打造一站式的分布式解决方案。
Seata解决思路
Seata事务管理中有三个重要的角色:
TC(Transaction Coordinator)-事务协调者∶维护全局和分支事务的状态,协调全局事务提交或回滚。
**TM(Transaction Manager)-事务管理器:**定义全局事务的范围、开始全局事务、提交或回滚全局事务。
**RM(Resource Manager)-资源管理器:**管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态
Seata-server部署
如何部署seata呢,我们同样把它作为一个微服务启动起来即可,不过这里使用的是docker,并没有和其他微服务一样统一放在一个父模块下面,这么做是为了让团队工作快一点不然还要每个人在本地启动起来seata。
映射配置文件
docker pull seataio/seata-server
# 启动容器
docker run -d --name seata -p 8091:8091 -p 7091:7091 seataio/seata-server
# 从容器中拷贝配置文件到宿主机(linux)目录/home/seata(这个目录需要先手动创建)
cd /home
mkdir seata
# 复制文件
docker cp seata-server:/seata-server/resources /home/seata/
# 停止并删除容器
docker stop seata
docker rm seata
修改配置文件apllication.yml
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${log.home:${user.home}/logs/seata}
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos, consul, apollo, zk, etcd3(设置配置文件的形式)
type: file
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa(设置注册中心的形式)
type: nacos
nacos:
application: seata-server
server-addr: 10.1.40.87:8848
group: "DEFAULT_GROUP"
# 命名空间去nacos看自己的命名空间名
namespace: "public"
username: "nacos"
password: "nacos"
#context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
store:
# support: file 、 db 、 redis 、 raft
mode: db
session:
mode: db
lock:
mode: db
file:
dir: sessionStore
max-branch-session-size: 16384
max-global-session-size: 512
file-write-buffer-cache-size: 16384
session-reload-read-size: 100
flush-disk-mode: async
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.1.40.87:3306/seata?rewriteBatchedStatements=true&serverTimezone=UTC
user: root
password: 1903@heBut.
min-conn: 5
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 100
max-wait: 5000
# server:
# service-port: 8091 #If not configured, the default is '${server.port} + 1000'
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/version.json
docker启动命令
docker run --name seata \
-p 8099:8099 \
-p 7091:7091 \
-e SEATA_IP=10.1.40.87 \
-v /home/seata/seata-server/resources:/seata-server/resources \
--privileged=true \
-d \
seataio/seata-server
Seata-client配置
引入依赖
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
配置文件apllication.yml
seata:
registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
type: nacos # 注册中心类型 nacos
nacos:
server-addr: 10.1.40.87:8848 # nacos地址
namespace: "" # namespace,默认为空
group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
application: seata-server # seata服务名称
username: nacos
password: nacos
tx-service-group: hmall # 事务组名称
service:
vgroup-mapping: # 事务组与tc集群的映射关系
hmall: "default"
分布式事务模式
Seata支持四种不同的分布式事务解决方案:
- XA
- TCC
- AT
- SAGA
这里我们以XA
模式和AT
模式来给大家讲解其实现原理。
XA模式
(1)工作流程
RM
一阶段的工作:
- 注册分支事务到
TC
- 执行分支业务sql但不提交
- 报告执行状态到
TC
TC
二阶段的工作:
TC
检测各分支事务执行状态- 如果都成功,通知所有RM提交事务
- 如果有失败,通知所有RM回滚事务
RM
二阶段的工作:
- 接收
TC
指令,提交或回滚事务
(2)XA
模式的优点是什么?
- 事务的强一致性,满足ACID原则
- 常用数据库都支持,实现简单,并且没有代码侵入
XA
模式的缺点是什么?
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务
(3)实现方法
首先,我们要在配置文件中指定要采用的分布式事务模式。我们可以在Nacos中的共享shared-seata.yaml配置文件中设置:
seata:
data-source-proxy-mode: XA
其次,我们要利用@GlobalTransactional
标记分布式事务的入口方法:
AT模式
AT
模式同样是分阶段提交的事务模型,不过缺弥补了XA
模型中资源锁定周期过长的缺陷。
(1)工作流程
阶段一RM
的工作:
- 注册分支事务
- 记录undo-log(数据快照)
- 执行业务sql并提交
- 报告事务状态
阶段二提交时RM
的工作:
- 删除undo-log即可
阶段二回滚时RM
的工作:
- 根据undo-log恢复数据到更新前
(2)实现方法
seata:
data-source-proxy-mode: AT
XA和AT区别
简述AT
模式与XA
模式最大的区别是什么?
XA
模式一阶段不提交事务,锁定资源;AT
模式一阶段直接提交,不锁定资源。XA
模式依赖数据库机制实现回滚;AT
模式利用数据快照实现数据回滚。XA
模式强一致;AT
模式最终一致
可见,AT模式使用起来更加简单,无业务侵入,性能更好。因此企业90%的分布式事务都可以用AT模式来解决。
网关路由
最后就剩下一个问题了,就是说如果后端有一堆服务的话,前端岂不是要每个业务都要通过访问不同的端口来访问到对应的微服务吗,所以出现了网关的概念,前端同样只要访问一个端口就行,也就是网关的端口,然后网关会负责把这些请求发送到不同的微服务的。
微服务身份验证方式
https://www.apiseven.com/blog/understanding-microservices-authentication-services