Coder Social home page Coder Social logo

codingapi / tx-lcn Goto Github PK

View Code? Open in Web Editor NEW
4.2K 282.0 1.5K 14.21 MB

LCN distributed transaction framework, compatible with dubbo, spring cloud and Motan framework, supports various relational databases

Home Page: https://www.codingapi.com

License: Apache License 2.0

Java 99.83% HTML 0.12% Dockerfile 0.05%
tx-lcn motan spring-cloud dubbo transaction jta

tx-lcn's Introduction

Distributed Transaction Framework - LCN (6.0.0)

License Maven Central codecov Build Status

文档

见5.x版本文档见 https://www.codingapi.com/docs/txlcn-preface/

参与方式

代码提交步骤

  • fork该项目地址,并更新代码
  • 认领任务或发布问题
  • 维护代码编写测试
  • 发起合并请求,关联issues
  • 代码审核通过合并到仓库中

代码结构

  • example: 示例与测试相关的代码
  • starter-txlcn-protocol: txlcn-protocol模块的starter
  • starter-txlcn-tc: txlcn-tc模块的starter
  • txlcn-p6spy: p6spy-解析sql与jdbc的event定义
  • txlcn-protocol: 通讯协议制度
  • txlcn-tc: TC事务客户端模块
  • txlcn-tm: TM事务控制端

从0到1实现分布式事务 公开课

第一节课

分布式事务从0到1-认识分布式事务
原文 B站

第二节课

分布式事务从0到1-了解TX-LCN原理
原文 B站-原理一 B站-原理二

B站地址
https://space.bilibili.com/386239614
公众号(通过公众号加群):
CODINGAPI分享者

项目运行步骤

依赖的环境:
mysql redis

数据库脚步:
sql

启动步骤:
1、配置TM的参数信息,然后启动TM。
2、配置example-tc example-tc-2信息,启动他们。
3、测试example-tc,接口地址为 http://localhost:8090/save?name=123

tx-lcn's People

Contributors

544845389 avatar 600849155 avatar 645775992 avatar ahao888 avatar bigblacksheep avatar boylong12 avatar caisirius avatar foxdd avatar hackcater avatar hundredbai avatar johnnywjh avatar meetzy avatar pangdonghao avatar silent-night-no-trace avatar ujued avatar xlorne avatar yu199195 avatar zfvipgit avatar zhoumengyks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tx-lcn's Issues

无spring下是否可以使用

请问如何在不使用spring的情况下使用tx-lcn,有参考demo吗,tx-manager是否支持使用别的注册中心,比如consul/zookeeper?

微服务多节点部署时,一致性无法保证!

----------案例---------- 场景: 一个微服务A , 部署了两个节点 A1 和 A2 ,当我的事务组发起方是 B 时,在同一业务中,多次调用到A服务的数据。 问题: 多次调用A时,发现,有可能到A1 有可能到A2,同一分布式事务中,如果通过A1插入了数据(假提交),又调用A2来获取---会获取不到

我建议的解决方案: 因为单节点时,在LCN中,还保持着同一个datasource连接,就和本地一样,可以保证一致性;只是如果多节点,在不同的应用上,就不可能是同一连接了。 所以,如果一个分布式事务业务流程在一个线程中,能保证多次调用一直是 A1 或 A2 就没问题。 (要能保证同一线程中,调用的节点不要乱跑就很好了)

客户端数据没有进行回滚

参考spring cloud的demo做了一下测试,服务端异常后,客户端没有进行回滚。。。
服务端和客户端的service代码都比较简单。

  • 服务端的service:
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Server addOne(Server entity) {
        Server one = null;
        if (entity.getStatus() == 0) {
            one = dao.addOne(entity);
        } else {
            // throw new RuntimeException("status should be 0");
            entity.setVersion("12345678901234567890");  // 字段超长
            one = dao.addOne(entity);
        }
        return one;
    }
  • 客户端的service:
    @Override
    @TxTransaction
    @Transactional(rollbackFor = Exception.class)
    public Client addOne(Client entity) {
        Client one = dao.addOne(entity);
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", one.getName() + "-server");
        map.put("version", one.getVersion());
        map.put("status", one.getStatus().toString());
        // 这里调用服务
        serverConsumer.addOne(map);
        return one;
    }
  • 客户端的Feign:
// LcnTxConfiguration的内容和demo一样,除了名字
@FeignClient(name = "sample-cloud-server", configuration = LcnTxConfiguration.class, fallback = ServerConsumerFallback.class)
public interface ServerConsumer {
    @PostMapping("/server")
    String addOne(Map<String, String> map);
}

主要不同的地方在于:

  • 服务端和客户端都有一个全局异常处理 (后来注释掉之后进入了fallback,但客户端数据仍未回滚):
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public CommonInfo<String> jsonErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append("request.exception").append(" ").append(req.getRequestURL().toString());
        return CommonInfo.fail(new String(sb), e.getMessage());
    }
}
  • 数据源是采用Processor处理的:
@Component
public class LcnTxDataSourceProxyProcessor implements BeanPostProcessor {
    final private static Logger logger = LoggerFactory.getLogger(LcnTxDataSourceProxyProcessor.class);
    final private static String DATA_SOURCE = "dataSource";
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (DATA_SOURCE.equals(beanName)) {
            // 这里在启动时候已经打印了
            logger.info("Use lcn data source proxy override data source");
            LCNTransactionDataSource dataSourceProxy = new LCNTransactionDataSource();
            dataSourceProxy.setDataSource((DataSource) bean);
            dataSourceProxy.setMaxCount(10);
            return dataSourceProxy;
        } else {
            return bean;
        }
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  • 拦截器的切入点用的通配符:
@Aspect
@Component
public class LcnTxTransactionInterceptor implements Ordered {
    @Autowired
    private TxManagerInterceptor txManagerInterceptor;
    @Override
    public int getOrder() {  return 1;  }
    // 这里service前用了 *
    @Around("execution(* com.xxx.boot.*.service.impl.*Impl.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        return txManagerInterceptor.around(point);
    }
}

请问问题有可能出现在哪里呢?

关于spring cloud的回滚原理

spring cloud的服务是http的方式调用的,本地应该没法控制被调用方的连接池的。
架设有这么一个情景:
那么如果A服务器调用B服务器的服务,B服务成功,再调用C服务器的服务,C服务失败。
那么A服务器是因为TX改写连接池代理,可以实现回滚。但是B服务如何回滚呢?

补偿机制的一点疑问

1.补偿决策,2.补偿结果通知
这两种补偿模式有什么区别?
对应的接收接口需要怎么处理?
能说明下吗?谢谢

每一个项目启动需要配置dubbo的provider端口,这个是否可以去掉

从目前看在在线模块中,模块地址需要一个端口号,其他并没有发现配置dubbo provider的端口号有其他用途,如果没有其他用途,建议去掉该端口号的配置,使用一个随机的端口号,作为模块地址的端口号,这样是否可以,如果可以,这样在consumer端,就不用配置provider了

[4.0.3.M2] [SpringCloud] 补偿调用时,提交或回滚逻辑判断有问题

比如 A 发起事务,先调用 A > B1.fun1,再调用 A > B2.fun1,其中B1和B2是相同模块不同实例,fun1是同一个方法,如果在最后事务通知阶段,B1或者B2出现通知失败会导致产生如下的补偿信息:

{
  "address": "192.168.1.161:60010",
  "className": "com.xxx.xxx.user.service.demo.DemoService",
  "currentTime": 1516777802788,
  "data": "C5IBK2NvbS55b3VuYS55eHoudXNlci5zZXJ2aWNlLmRlbW8uRGVtb1NlcnZpY2UMEgZ0eFRlc3QbehBqYXZhLmxhbmcuT2JqZWN0GAAQARwjeg9qYXZhLmxhbmcuQ2xhc3MYABABJCpAcHVibGljIHZvaWQgY29tLnlvdW5hLnl4ei51c2VyLnNlcnZpY2UuZGVtby5EZW1vU2VydmljZS50eFRlc3QoKQ==",
  "groupId": "zqIGXYkf",
  "methodStr": "public void com.xxx.xxx.user.service.demo.DemoService.txTest()",
  "model": "A",
  "startError": 0,
  "state": 0,
  "time": 5117,
  "txGroup": {
    "groupId": "zqIGXYkf",
    "hasOver": 1,
    "isCommit": 0,
    "list": [
      {
        "address": "192.168.1.161:49296",
        "isCommit": 0,
        "isGroup": 0,
        "kid": "dux2oC5M",
        "methodStr": "public com.xxx.xxx.common.domain.demo.Demo com.xxx.xxx.edge.service.demo.DemoService.save(com.youna.yxz.common.domain.demo.Demo)",
        "model": "B",
        "modelIpAddress": "192.168.1.161:62003",
        "modelName": "/192.168.1.161:9183",
        "notify": 0,
        "uniqueKey": "8fa2f86e1f37be77c669d6383f0a488b"
      },
      {
        "address": "192.168.1.161:49296",
        "isCommit": 0,
        "isGroup": 0,
        "kid": "yRgeaVSg",
        "methodStr": "public com.xxx.xxx.common.domain.demo.Demo com.xxx.xxx.edge.service.demo.DemoService.save(com.youna.yxz.common.domain.demo.Demo)",
        "model": "B",
        "modelIpAddress": "192.168.1.161:62000",
        "modelName": "/192.168.1.161:8114",
        "notify": 1,
        "uniqueKey": "3eab2f2d491f0f4f3e05fa03270114be"
      }
    ],
    "nowTime": 0,
    "rollback": 0,
    "startTime": 1516777797675,
    "state": 1
  },
  "uniqueKey": "70000381435434571fa98e58c5e694f4"
}

注意里面的list列表为上述的B模块,如果存在这种多个B模块相同方法,则最后出现的那个B模块实例对象的 notify 如果为 1,则在调用补偿时,全部B模块都会被rollback,反之都会被commit。

推测,我没看TxManager的源码,这个bug估计是TxManager补偿时,是通过一个map来遍历的补偿信息,key可能为model + methodStr,之前B模块不同实例的key估计是被后出现的覆盖了。

如果txmanager设置了security,客户端报权限问题

看了源码,最终调用HttpUtils里的方法,并未对Auth做处理。一般的服务布署后都要设置权限访问的。建议加上这一方面的处理。

当前解决方法:根据源码,提供自己实现TxManagerHttpRequestService接口,并注册至Spring容器

dubbo TransactionFilter

4.10版本
dubbo 服务 TransactionFilter TxTransactionLocal.current();为null 无法创建groupId
好奇怪

4.0.3.M2发起方如过本地事物commit异常,会导致补偿信息不被记录

比如,LCNStartConnection的transaction方法中如果出现SQLException,会进入catch块(176行);
将waitTask的state设置为connectionError;
然后在TxStartTransactionServerImpl的execute方法中会执行128行,发送补偿信息给txManager;

但txManager中接收信息的CompensateServiceImpl中68行判断为空直接return,即没有在redis中找到信息对应的groupId,导致代码没有继续往下执行,补偿信息就没有被记录到redis中。

txmanage挂掉之后,业务无法正常流转了

项目启动阶段,如果txmanage没有启动则服务无法注册到注册中心(dubbo);
项目运行阶段,如果txmanage宕机,则业务中断;
建议:如果txmanage异常,是否可以执行本地事务?

对于事务补偿机制中的疑问

  • 看你的文档中,你不是使用2PC,3PC等来保证事务的一致性,那么你是不是还是需要至少进行两次网络往返?

  • 有一个问题就是,在Spring Cloud中,有一个业务B,需要调用B1,B2和B3等三个业务,B1,B2和B3都已经成功的执行了事务之后,通知到TxManager,然后TxManager进行通知TxClient进行数据库提交。在此时,B1和B2能够成功的通知到了,但是B3此时出现了网络震荡,始终无法到达,** 阻塞 ** 在网络途中,那么根据你的超时机制,B1和B2被自动回滚了。那么这样的话,B3还未到超时时间,你的B3被自动提交了。是不是意味着出现了数据不一样的情况了?

我认为,不应该存在这种超时的机制,并且B3如果宕机了,再次重启,你是如何保障该业务数据重新提交到数据库呢?

这是我的联系方式
可以向我发邮件进行沟通
期待您的回复. 😄

dubbo 框架下多RegisterConfig时报错

image

image

@Autowired(required=false)
    private RegistryConfig registryConfig;


private int getPort(){
    	
        if(registryConfig!=null && registryConfig.getPort()!=null){
            return registryConfig.getPort();
        }
        if(providerConfig.getPort()!=null){
            return providerConfig.getPort();
        }
        return 2181;
    }

4.0.3.M3 优雅停机问题

txClient客户端,多处线程池ExecutorService和Netty连接,在程序停机时未做destroy处理,导致Spring Boot优雅停机被阻塞,需要做资源释放的位置如下:
SocketManager > [ChannelHandlerContext ctx] close() 和 channel().eventLoop().shutdownGracefully()
SocketManager > [Executor threadPool] shutdown()
SocketManager > [ScheduledExecutorService executorService] shutdown()
NettyServiceImpl > [EventLoopGroup workerGroup] shutdownGracefully()
NettyControlServiceImpl > [Executor threadPool] shutdown()

最新4.1.0 Demo搭建疑问

不知是否支持一下版本
<spring-cloud.version>Finchley.M8</spring-cloud.version>
<spring-boot.version>2.0.1.RELEASE</spring-boot.version>
我按照提供的Demo来做,应用不能正常启动:
Initialization of bean failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'transactionAspect': Unsatisfied dependency expressed through field 'txManagerInterceptor';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'txManagerInterceptor':
Unsatisfied dependency expressed through field 'aspectBeforeService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'aspectBeforeServiceImpl': Unsatisfied dependency expressed through field 'transactionServerFactoryService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'transactionServerFactoryServiceImpl':
Unsatisfied dependency expressed through field 'txStartTransactionServer';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'txStartTransactionServer': Unsatisfied dependency expressed through field 'txManagerService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'MQTxManagerServiceImpl': Unsatisfied dependency expressed through field 'modelNameService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'modelNameServiceImpl': Unsatisfied dependency expressed through field 'serverListener';
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverListener':
Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [com.codingapi.tx.springcloud.listener.ServerListener] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2]

Hystrix timeoutInMilliseconds失效

我的配置

feign.hystrix.enabled: true
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds: 5000
hystrix.command.default.execution.isolation.strategy: SEMAPHORE
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000

引入tx-lcn后超时配置失效(变回默认的1000),移除后恢复正常。。。

tx-lcn: 4.1.0
springboot: 1.5.10
springcloud: Edgware.SR2

springcloud demo启动不成功

wiki中的4.0.0在maven库中没有。。
用4.0.1和4.0.2 均发现空指针异常。断点追踪到时txserver为空。
default
如果用4.0.3则在编译时就出错了
2

客户端业务执行失败,记录的事务补偿信息发送给服务器端,但是本地未做记录

通过查看源码发现,TxStartTransactionServerImpl里面执行txManagerService.sendCompensateMsg(groupId, time, info,executeConnectionError);时候,本地不做任何记录(saveLocal()里面只做了日志输出),只是将补偿信息发送到服务器端,之后服务器会进行轮询(异常会重复3次)补偿操作;这里面有个问题,如果客户端在发送消息时服务器(txmanager)异常或者txclient网络有问题,会导致补偿失败!

建议(可能待完善):在saveLocal记录补偿信息(放到redis都行),之后客户端(txclient)启动检查是否有未执行的补偿信息,有则发送到服务端进行处理;

txManager后台手动补偿的时候抛ServiceException异常

txManager后台手动补偿的时候抛异常:
TxRunningTransactionServerImpl.execute(final ProceedingJoinPoint point, final TxTransactionInfo info)方法抛出throw new ServiceException("update TxGroup error, groupId:" + txGroupId);
Caused by: com.lorne.core.framework.exception.ServiceException: update TxGroup error, groupId:fvo9ksEH

请问如何控制事物手动回滚?

类似于 Spring的 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 因为不一定是异常才需要回滚,我没有在文档上看到手动回滚的东西 谢谢

LcnRibbonConfiguration 问题

问题描述

加了 transaction-springcloud之后,eureka上服务的ip和端口变了,restTempLate 调用的还是老的ip和端口

解决办法

去除TransactionConfiguration类上的
@RibbonClients(defaultConfiguration=LcnRibbonConfiguration.class) 注解
去除
LcnRibbonConfiguration 的@componentscan 注解

关于tx.properties配置

您好。我在查看Demo的时候按照您的Demo进行配置在application.properties中配置了tm.manager...
是否这个配置心事不是必须的?而resources目录下的tx.properties才是正确的配置方式?

Consider defining a bean of type 'com.codingapi.tx.datasource.ILCNTransactionControl' in your configuration.

版本: 4.0.3.M2
造成原因: 只要在入口方法加入@import({xx.class}) 就会报错
报错内容:


APPLICATION FAILED TO START


Description:

Field transactionControl in com.codingapi.tx.aop.service.impl.TxRunningTransactionServerImpl required a bean of type 'com.codingapi.tx.datasource.ILCNTransactionControl' that could not be found.

Action:

Consider defining a bean of type 'com.codingapi.tx.datasource.ILCNTransactionControl' in your configuration.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.