终于跑通分布式事务框架tcc-transaction的示例项目
1、背景
前段时间在看项目代码的时候,发现有些接口的流程比较长,在各个服务里面都有通过数据库事务保证数据的一致性,但是在上游的controller层并没有对一致性做保证。
网上查了下,还没找到基于Go开源的比较成熟的分布式事务框架。
于是,准备看看之前隔壁部门大佬写的tcc-transaction,这是一个基于tcc思想实现的分布式事务框架。
tcc分别代码Try,Confirm和Cancel。
Try: 尝试执行业务
- 完成所有业务检查(一致性)
- 预留必须业务资源(准隔离性)
Confirm: 确认执行业务
- 真正执行业务
- 不作任何业务检查
- 只使用Try阶段预留的业务资源
- Confirm操作满足幂等性
Cancel: 取消执行业务
- 释放Try阶段预留的业务资源
- Cancel操作满足幂等性
要了解其实现原理,第一步就是跑通项目自带的示例,即tcc-transaction-tutorial-sample部分的代码。
今天主要介绍在跑通tcc-transaction-tutorial-sample过程中遇到的各种坑。
2、依赖环境
- Java
- Maven
- Git
- MySQL
- Redis
- Zookeeper
- Intellij IDEA
源码地址:https://github.com/changmingxie/tcc-transaction
我自己Fork了一份(配置改动已提交):https://github.com/DMinerJackie/tcc-transaction
3、踩坑历程
踩坑准备
第一步:克隆代码
使用"git clone https://github.com/DMinerJackie/tcc-transaction"命令下载代码
第二步:导入代码并执行数据库脚本
代码导入Intellij IDEA。
执行tcc-transaction-http-sample/src/main/dbscripts 下的数据库脚本。
第三步:修改配置文件
主要修改的是数据库配置参数。拿tcc-transaction-dubbo-sample举例,需要修改的文件有
tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-capital/src/main/resources/tccjdbc.properties
tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-redpacket/src/main/resources/tccjdbc.properties
tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-order/src/main/resources/tccjdbc.properties
三个文件修改后对应配置如下
# 根据具体的MySQL版本使用驱动名称
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
# 换成你连接数据库的地址
tcc.jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
# 换成你需要配置数据库的用户名
jdbc.username=root
# 换成你需要配置数据库的密码
jdbc.password=rootroot c3p0.initialPoolSize=
c3p0.minPoolSize=
c3p0.maxPoolSize=
c3p0.acquireIncrement=
c3p0.maxIdleTime=
c3p0.checkoutTimeout=
同时修改tcc-transaction-sample-capital、tcc-transaction-sample-redpacket和tcc-transaction-sample-order三个项目中jdbc.proerties文件的数据库连接,修改后配置如下
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC_CAP?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
tcc.jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
jdbc.username=root
jdbc.password=rootroot c3p0.initialPoolSize=10
c3p0.minPoolSize=10
c3p0.maxPoolSize=30
c3p0.acquireIncrement=3
c3p0.maxIdleTime=1800
c3p0.checkoutTimeout=30000
第四步:启动项目
结合项目的README.md文件以及网上的文章了解到如果要跑通示例项目,需要分别启动三个项目。
tcc-transaction提供了两个版本:
- 基于dubbo通讯的示例版本
- 基于http通讯的示例版本
这两个版本对于的三个项目分别是
- tcc-transaction-dubbo-capital(账户资产服务)、 tcc-transaction-dubbo-redpacket(红包服务)、 tcc-transaction-dubbo-order(交易订单服务)
- tcc-transaction-http-capital(账户资产服务)、 tcc-transaction-http-redpacket(红包服务)、 tcc-transaction-http-order(交易订单服务)
其实这两个版本我都跑过,最终成功跑通的只有基于dubbo通讯的示例版本(http版本在最后confirm的时候最是失败,导致最终订单状态为unkown)。
以基于dubbo通讯的示例为例
tcc-transaction-dubbo-capital的启动配置如下
tcc-transaction-dubbo-redpacket的启动配置如下
tcc-transaction-dubbo-order的启动配置如下
坑1:连接不上zk
启动tcc-transaction-dubbo-capital项目,报错信息如下
[sample-dubbo-capital]2019-08-31 17:48:05,312 INFO [org.apache.zookeeper.ZooKeeper] Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=30000 watcher=org.I0Itec.zkclient.ZkClient@32c7bb63
[sample-dubbo-capital]2019-08-31 17:48:05,334 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:05,344 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081)
[sample-dubbo-capital]2019-08-31 17:48:06,456 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:06,459 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081)
[sample-dubbo-capital]2019-08-31 17:48:07,566 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:07,567 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
从报错信息,一眼就看出是连不上zk即zookeeper。
这个很好理解,因为本地没有安装zk,于是安装并通过"./zkServer.sh start"启动zk
坑2:redis连不上
启动tcc-transaction-dubbo-order报错部分信息如下:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.order.service.PlaceOrderServiceImpl org.mengyun.tcctransaction.sample.dubbo.order.web.controller.OrderController.placeOrderService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'placeOrderServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.order.service.PaymentServiceImpl org.mengyun.tcctransaction.sample.dubbo.order.service.PlaceOrderServiceImpl.paymentService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.capital.api.CapitalTradeOrderService org.mengyun.tcctransaction.sample.dubbo.order.service.PaymentServiceImpl.capitalTradeOrderService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'captialTradeOrderService': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compensableTransactionAspect' defined in class path resource [tcc-transaction.xml]: Cannot resolve reference to bean 'transactionConfigurator' while setting bean property 'transactionConfigurator'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionConfigurator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.mengyun.tcctransaction.TransactionRepository org.mengyun.tcctransaction.spring.support.SpringTransactionConfigurator.transactionRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionRepository' defined in file [/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-order/target/tcc-transaction-dubbo-order-1.2.6/WEB-INF/classes/config/spring/local/appcontext-service-tcc.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'jedisPool' threw exception; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:526)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:295)
... 60 more
这个和上面的原因类似,本地没有安装redis,导致无法拿到redis连接。
于是安装redis,并使用"redis-server"启动redis。
坑3:Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection
三个项目都启动后,可以看到一个商品链接列表页,但是在点击链接后无法跳转,并且报错如下
Type Exception Report
Message Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
Description The server encountered an unexpected condition that prevented it from fulfilling the request.
Exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
### The error may exist in URL [jar:file:/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order/target/tcc-transaction-http-order-1.2.6/WEB-INF/lib/tcc-transaction-sample-order-1.2.6.jar!/config/sqlmap/main/sample-product.xml]
### The error may involve org.mengyun.tcctransaction.sample.order.infrastructure.dao.ProductDao.findByShopId
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:965)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106) Root Cause
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
### The error may exist in URL [jar:file:/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order/target/tcc-transaction-http-order-1.2.6/WEB-INF/lib/tcc-transaction-sample-order-1.2.6.jar!/config/sqlmap/main/sample-product.xml]
根据错误信息,排查是MySQL版本和数据库驱动版本不匹配。
本地的MySQL版本是"8.0.11 MySQL Community Server - GPL",但是tcc-transaction中对应的驱动版本是
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.33</version>
</dependency>
改为
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
同时针对高版本,需要在连接的jdbc-url后面加上useSSL=false
坑4:Loading class `com.mysql.jdbc.Driver'. This is deprecated
启动tcc-transaction-dubbo-redpacket时,在日志中看到一个警告"Loading class `com.mysql.jdbc.Driver'. This is deprecated"。
通过搜索,发现是因为数据库驱动com.mysql.jdbc.Driver'已经被弃用了,需要使用com.mysql.cj.jdbc.Driver,于是修改jdbc.proerties的配置(具体配置见上面),启动正常。
踩完上面的坑后,启动三个项目,完整走完流程,实现了一个基于分布式事务的商品购买行为,具体过程如下图所示
4、 总结
运行示例项目的过程不算太顺利,主要有一下几个原因吧
- 本地环境配置和项目提供的不一致,导致走了很多弯路,比如MySQL的版本。
- 缺少详细的跑示例项目的文档说明。
- 网上提供的资料比较粗略,也比较陈旧,文中能跑起来的步骤说明已经不适用现在的代码了。
所以,在踩完这么多坑总结下,避免后面的人走同样的弯路。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
终于跑通分布式事务框架tcc-transaction的示例项目的更多相关文章
- tcc分布式事务框架解析
前言碎语 楼主之前推荐过2pc的分布式事务框架LCN.今天来详细聊聊TCC事务协议. 2pc实现:https://github.com/codingapi/tx-lcn tcc实现:https://g ...
- 【原创】分布式事务之TCC事务模型
引言 在上篇文章<老生常谈--利用消息队列处理分布式事务>一文中留了一个坑,今天来填坑.如下图所示 如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务B要 ...
- TX-LCN 分布式事务框架
第十章 TX-LCN 分布式事务框架 (Spring Cloud 高级) 一. 什么是分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位 于不同的分布式系统的不同 ...
- 快速了解阿里微服务热门开源分布式事务框架——Seata
一.Seata 概述 Seata 是 Simple Extensible Autonomous Transaction Architecture 的简写,由 feascar 改名而来. Seata 是 ...
- 分布式事务之TCC事务模型
一.引言 在上篇文章<老生常谈--利用消息队列处理分布式事务>一文中留了一个坑,今天来填坑.如下图所示 如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务 ...
- 基于Dubbo的分布式事务框架(LCN)
原文地址:http://原文地址:https://github.com/1991wangliang/transaction 基于Dubbo的分布式事务框架(LCN) 该框架依赖Redis/dubbo/ ...
- 分布式事务框架Seata及EasyTransaction架构的比对思考
本文将会对比Seata与EasyTransaction两个分布式事务的一些高层设计,相信大家会有收获. Seata的概述 Seata(曾用名Fescar,开源版本GTS)是阿里的开源分布式事务框架,其 ...
- 关于如何实现一个Saga分布式事务框架的思考
关于Saga模式的介绍,已经有一篇文章介绍的很清楚了,链接在这里:分布式事务:Saga模式. 关于TCC模式的介绍,也已经有一篇文章介绍的很清楚了,链接在这里:关于如何实现一个TCC分布式事务框架的一 ...
- 开源的分布式事务框架 springcloud Alibaba Seata 的搭建使用 一次把坑踩完。。。
seata的使用 1. Seata 概述 Seata 是 Simple Extensible Autonomous Transaction Architecture 的简写,由 feascar 改名而 ...
随机推荐
- 如何使用 nvm-windows 管理 nodejs 版本
写在前边的话: (1). 路径一定不要包含空格,如 Program Files 这样,所以有把程序安装到 D:\Program Files 文件下的同学请注意了:(2). 为了避免 nvm 无法切换源 ...
- Codeforces1144B(B题)Parity Alternated Deletions
B. Parity Alternated Deletions Polycarp has an array aa consisting of nn integers. He wants to play ...
- Linux中bash shell环境变量
别名 别名是命令的快捷方式.为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用.语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令.重要的 ...
- 1.4.2python网站地图爬虫(每天一更)
# -*- coding: utf-8 -*- ''' Created on 2019年5月6日 @author: 薛卫卫 ''' import urllib.request import re de ...
- 提交bug的标准及书写规范
Bug有效性 1.交付过程中测试者需按照专家设定好的模块,对Bug进行归类提交: 2.Bug的类型默认为UI问题.功能问题.崩溃问题,提交Bug时不能弄错: 3.需求是否明确.前提条件是否满足.输入数 ...
- 『开发技术』Windows极简安装使用face_recognition
face_recognition是一个强大.简单.易上手的人脸识别开源项目,并且配备了完整的开发文档和应用案例,特别是兼容树莓派系统.此项目是世界上最简洁的人脸识别库,你可以使用Python和命令行工 ...
- Jenkins 持续集成持续发布使用搭建基础
一.环境搭建基础 1.持续集成.持续交付.持续部署概念 ①.集成: 是指软件多人研发的部分软件代码整合交付,以便尽早发现个人开发部分的问题:持续集成:强调开发人员提交了新代码之后,立刻进行构建(单元) ...
- 0R电阻在PCB布线中对布线畅通的一个小妙用
在PCB布线中,我们都会尽量节约板子空间,将元器件排布的紧密一些,难免会遇到布线不通的时候. 博主下面就来说一个关于0R电阻在PCB布线使之畅通的一个小妙用. 使用0R电阻前 假设我们这个TXD的线周 ...
- eclipse导入码云-GIT项目
1.首先找到项目源码地址我随便找到一个git地址 :https://gitee.com/mingSoft/MCMS 2.打开eclipse空白处右键导入项目搜索git. 3.将第一步复制的git地址复 ...
- JavaWeb配置详解(结合框架SpringMVC)
详解 先说一说常识性的东西,我们的JavaWeb程序运行一开始走的是web.xml文件,这是我们的核心文件,可以说没有web.xml文件我们就无法运行项目,这个文件长什么样子,读者自己新建一个web项 ...