博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微服务架构下,解决数据一致性问题的实践
阅读量:7071 次
发布时间:2019-06-28

本文共 7275 字,大约阅读时间需要 24 分钟。

随着业务的快速发展,应用单体架构暴露出代码可维护性差、容错率低、测试难度大和敏捷交付能力差等诸多问题,微服务应运而生。微服务的诞生一方面解决了上述问题,但是另一方面却引入新的问题,其中主要问题之一就是:如何保证微服务间的业务数据一致性。

本文将通过一个商品采购的业务,来看看在Dubbo的微服务架构下,如何通过Fescar来保障业务的数据一致性。本文所述的例子中,Dubbo 和 Fescar 的注册配置服务中心均使用 Nacos。Fescar 0.2.1+ 开始支持 Nacos 注册配置服务中心。

业务描述

用户采购商品的业务,包含3个微服务:

  • 库存服务: 扣减给定商品的库存数量。

  • 订单服务: 根据采购请求生成订单。

  • 账户服务: 用户账户金额扣减。

业务结构图如下:

库存服务(StorageService)

public interface StorageService {        /**          * deduct storage count          */    void deduct(String commodityCode, int count);}复制代码

订单服务(OrderService)

public interface OrderService {        /**          * create order          */    Order create(String userId, String commodityCode, int orderCount);}复制代码

账户服务(AccountService)

public interface AccountService {        /**          * debit balance of user's account          */    void debit(String userId, int money);}复制代码

说明: 以上三个微服务均是独立部署。

8个步骤实现数据一致性

Step 1:初始化 MySQL 数据库(需要InnoDB 存储引擎)

在 resources/jdbc.properties 修改StorageService、OrderService、AccountService 对应的连接信息。

jdbc.account.url=jdbc:mysql://xxxx/xxxxjdbc.account.username=xxxxjdbc.account.password=xxxxjdbc.account.driver=com.mysql.jdbc.Driver# storage db configjdbc.storage.url=jdbc:mysql://xxxx/xxxxjdbc.storage.username=xxxxjdbc.storage.password=xxxxjdbc.storage.driver=com.mysql.jdbc.Driver# order db configjdbc.order.url=jdbc:mysql://xxxx/xxxxjdbc.order.username=xxxxjdbc.order.password=xxxxjdbc.order.driver=com.mysql.jdbc.Driver复制代码

Step 2:创建 undo_log(用于Fescar AT 模式)表和相关业务表

相关建表脚本可在 resources/sql/ 下获取,在相应数据库中执行 dubbo_biz.sql 中的业务建表脚本,在每个数据库执行 undo_log.sql 建表脚本。

CREATE TABLE `undo_log` (    `id` bigint(20) NOT NULL AUTO_INCREMENT,    `branch_id` bigint(20) NOT NULL,    `xid` varchar(100) 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`),  KEY `idx_unionkey` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;复制代码
DROP TABLE IF EXISTS `storage_tbl`;CREATE TABLE `storage_tbl` (    `id` int(11) NOT NULL AUTO_INCREMENT,    `commodity_code` varchar(255) DEFAULT NULL,    `count` int(11) DEFAULT 0,    PRIMARY KEY (`id`),  UNIQUE KEY (`commodity_code`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;DROP TABLE IF EXISTS `order_tbl`;CREATE TABLE `order_tbl` (    `id` int(11) NOT NULL AUTO_INCREMENT,    `user_id` varchar(255) DEFAULT NULL,    `commodity_code` varchar(255) DEFAULT NULL,    `count` int(11) DEFAULT 0,    `money` int(11) DEFAULT 0,    PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;DROP TABLE IF EXISTS `account_tbl`;CREATE TABLE `account_tbl` (    `id` int(11) NOT NULL AUTO_INCREMENT,    `user_id` varchar(255) DEFAULT NULL,    `money` int(11) DEFAULT 0,    PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;复制代码

说明: 需要保证每个物理库都包含 undo_log 表,此处可使用一个物理库来表示上述三个微服务对应的独立逻辑库。

Step 3:引入 Fescar、Dubbo 和 Nacos 相关 POM 依赖

0.2.1
2.6.5
0.0.2
com.alibaba.fescar
fescar-spring
${fescar.version}
com.alibaba.fescar
fescar-dubbo-alibaba
${fescar.version}
dubbo
org.apache.dubbo
com.alibaba
dubbo
${dubbo.alibaba.version}
com.alibaba
dubbo-registry-nacos
${dubbo.registry.nacos.version}
复制代码

说明: 由于当前 apache-dubbo 与 dubbo-registry-nacos jar存在兼容性问题,需要排除 fescar-dubbo 中的 apache.dubbo 依赖并手动引入 alibaba-dubbo,后续 apache-dubbo(2.7.1+) 将兼容 dubbo-registry-nacos。在Fescar 中 fescar-dubbo jar 支持 apache.dubbo,fescar-dubbo-alibaba jar 支持 alibaba-dubbo。

Step 4:微服务 Provider Spring配置

分别在三个微服务Spring配置文件(dubbo-account-service.xml、 dubbo-order-service 和 dubbo-storage-service.xml )进行如下配置:

  • 配置 Fescar 代理数据源

复制代码

此处需要使用 com.alibaba.fescar.rm.datasource.DataSourceProxy 包装 Druid 数据源作为直接业务数据源,DataSourceProxy 用于业务 SQL 的拦截解析并与 TC 交互协调事务操作状态。

  • 配置 Dubbo 注册中心

复制代码
  • 配置 Fescar GlobalTransactionScanner

复制代码

此处构造方法的第一个参数为业务自定义 applicationId,若在单机部署多微服务需要保证 applicationId 唯一。

构造方法的第二个参数为 Fescar 事务服务逻辑分组,此分组通过配置中心配置项 service.vgroup_mapping.my_test_tx_group 映射到相应的 Fescar-Server 集群名称,然后再根据集群名称.grouplist 获取到可用服务列表。

Step 5:事务发起方配置

在 dubbo-business.xml 配置以下配置:

  • 配置 Dubbo 注册中心

同 Step 4

  • 配置 Fescar GlobalTransactionScanner

同 Step 4

  • 在事务发起方 service 方法上添加 @GlobalTransactional 注解

@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")复制代码

timeoutMills 为事务的总体超时时间默认60s,name 为事务方法签名的别名,默认为空。注解内参数均可省略。

Step 6:启动 Nacos-Server

  • 下载 Nacos-Server 最新 release 包并解压

  • 运行 Nacos-server

Linux/Unix/Mac

sh startup.sh -m standalone复制代码

Windows

cmd startup.cmd -m standalone复制代码

访问 Nacos 控制台:http://localhost:8848/nacos/index.html#/configurationManagement?dataId=&group=&appName=&namespace

若访问成功说明 Nacos-Server 服务运行成功(默认账号/密码: nacos/nacos)

Step 7:启动 Fescar-Server

  • 下载 Fescar-Server 最新 release 包并解压

  • 初始化 Fescar 配置

进入到 Fescar-Server 解压目录 conf 文件夹下,确认 nacos-config.txt 的配置值(一般不需要修改),确认完成后运行 nacos-config.sh 脚本初始化配置。

sh nacos-config.sh $Nacos-Server-IP复制代码

eg:

sh nacos-config.sh localhost 复制代码

脚本执行最后输出 "init nacos config finished, please start fescar-server." 说明推送配置成功。若想进一步确认可登陆Nacos 控制台 配置列表 筛选 Group=FESCAR_GROUP 的配置项。

  • 修改 Fescar-server 服务注册方式为 nacos

进入到 Fescar-Server 解压目录 conf 文件夹下 registry.conf 修改 type="nacos" 并配置 Nacos 的相关属性。

registry {    # file nacos  type = "nacos"  nacos {        serverAddr = "localhost"    namespace = "public"    cluster = "default"  }  file {        name = "file.conf"  }}复制代码

type: 可配置为 nacos 和 file,配置为 file 时无服务注册功能

nacos.serverAddr: Nacos-Sever 服务地址(不含端口号)
nacos.namespace: Nacos 注册和配置隔离 namespace
nacos.cluster: 注册服务的集群名称
file.name: type = "file" classpath 下配置文件名

  • 运行 Fescar-server

Linux/Unix/Mac

sh fescar-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA $IP(此参数可选)复制代码

Windows

cmd fescar-server.bat $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA $IP(此参数可选)复制代码

$LISTEN_PORT: Fescar-Server 服务端口

$PATH_FOR_PERSISTENT_DATA: 事务操作记录文件存储路径(已存在路径)
$IP(可选参数): 用于多 IP 环境下指定 Fescar-Server 注册服务的IP

eg: sh fescar-server.sh 8091 /home/admin/fescar/data/

运行成功后可在 Nacos 控制台看到 服务名 =serverAddr 服务注册列表:

Step 8:启动微服务并测试

  • 修改业务客户端发现注册方式为 nacos

同Step 7 中[修改 Fescar-server 服务注册方式为 nacos] 步骤 

  • 启动 DubboAccountServiceStarter

  • 启动 DubboOrderServiceStarter

  • 启动 DubboStorageServiceStarter

启动完成可在 Nacos 控制台服务列表 看到启动完成的三个 provider:

  • 启动 DubboBusinessTester 进行测试

注意: 在标注 @GlobalTransactional 注解方法内部显示的抛出异常才会进行事务的回滚。整个 Dubbo 服务调用链路只需要在事务最开始发起方的 service 方法标注注解即可。

通过以上8个步骤,我们实现了用户采购商品的业务中库存、订单和账户3个独立微服务之间的数据一致性。

大家如果觉得文章不错的话,可以点个赞和关注下,以后会有跟多的精品文章分享给大家。

作者福利:

给大家推荐一个架构技术交流群:714827309 ,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析 ,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工作 和遇到技术瓶颈的码友,在这个群里会有你需要的内容。 点击链接加入群聊【JAVA高级架构技术交流】:

转载于:https://juejin.im/post/5ca9fdd96fb9a05e6b44d7e0

你可能感兴趣的文章
文娱产业兴起 娱乐有了 文化在哪?
查看>>
Inotifywait解决监控子目录树的情况
查看>>
两棵树是否相同
查看>>
基本正则表达式和扩展正则表达式中的括号问题
查看>>
nginx+tomcat7 DOCKER镜像的dockerfile
查看>>
关于笔记本电脑网卡出问题的简单解决
查看>>
IPV4与IPV6表示方法
查看>>
桌面支持--不懂不要乱动-尤其是别人的东西
查看>>
hadoop集群上运行自定义wordcount
查看>>
Linux条件测试
查看>>
阿兰•图灵与人工智能
查看>>
操作系统简单快捷安装方式
查看>>
微软MVA征文参赛作品_微软云计算,缔造新生活
查看>>
openshift 安装
查看>>
使用图形化工具Gitbook Editor编辑gitbook电子书
查看>>
SSH免密码登录原理
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
Mbps与MB/s的区别
查看>>
eclipse 导入Maven项目的问题
查看>>