LCN框架介绍

LCN框架介绍

一、 基本概念

​ 随着互联化的蔓延,各种项目都逐渐向分布式服务做转换。如今微服务已经普遍存在,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生。 分布式事务被称为世界性的难题,目前分布式事务存在两大理论依据:CAP定律 BASE理论。

1. CAP理论

​ 这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

一致性(C)

​ 在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

可用性(A)

​ 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

分区容错性(P)

​ 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

2.BASE理论

​ BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

基本可用

​ 基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性----注意,这绝不等价于系统不可用。比如:

(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒

(2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面

软状态

​ 软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时

最终一致性

​ 最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

二、LCN简介

1、定位:LCN并不生产事务,LCN只是本地事务的协调工

 LCN框架在2017年6月份发布第一个版本,从开始的1.0,已经发展到了5.0版本。LCN名称是由早期版本的LCN框架命名,在设计框架之初的1.0 ~ 2.0的版本时框架设计的步骤是如下,各取其首字母得来的LCN命名。

  • 锁定事务单元(lock)
  • 确认事务模块状态(confirm)
  • 通知事务(notify)

 5.0以后由于框架兼容了LCN、TCC、TXC三种事务模式,为了避免区分LCN模式,特此将LCN分布式事务改名为TX-LCN分布式事务框架。
 TX-LCN定位于一款事务协调性框架,框架其本身并不操作事务,而是基于对事务的协调从而达到事务一致性的效果。

2.项目结构介绍

LCN框架介绍_第1张图片

  • txlcn-tc:TXLCN分布式事务客户端
  • txlcn-common:公共模块
  • txlcn-logger:日志模块。(默认提供日志持久化到MySQL的支持)
  • txlcn-tm:TXLCN事务管理器
  • txlcn-txmsg:事务消息扩展接口
  • txlcn-txmsg-netty:事务消息接口的Netty实现
  • txlcn-tracing:分布式事务追踪工具

3.事务控制原理

 TX-LCN由两大模块组成, TxClient、TxManager,TxClient作为模块的依赖框架,提供TX-LCN的标准支持,TxManager作为分布式事务的控制方。事务发起方或者参与反都由TxClient端来控制。

核心步骤

  • 创建事务组:是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。
  • 加入事务组:添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。
  • 通知事务组:是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。
    LCN框架介绍_第2张图片

4.LCN事务模式

  • 原理介绍:
    ​ LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代理的连接将由LCN连接池管理。
  • 特点:
    该模式对代码的嵌入性为低。
    该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。
    该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。
    该模式缺陷在于代理的连接需要随事务发起方一共释放连接,增加了连接占用的时间。

5.TCC事务模式

  • 原理介绍:
    TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。
  • 特点:
    该模式对代码的侵入性性高,要求每个业务需要写三种步骤的操作。
    该模式对有无本地事务控制都可以支持使用面广。
    数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。

6.TXC事务模式

  • 原理介绍:
    TXC模式命名来源于淘宝,实现原理是在执行SQL之前,先查询SQL的影响数据,然后保存执行的SQL信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库,目前锁实现依赖redis分布式锁控制。
  • 特点:
    该模式同样对代码的侵入性低。
    该模式仅限于对支持SQL方式的模块支持。
    该模式由于每次执行SQL之前需要先查询影响数据,因此相比LCN模式消耗资源与时间要多。
    该模式不会占用数据库的连接资源。

7.高可用配置

(1)TxManager集群说明:
​ TxManager集群比较简单,只需要控制TxManager下的db资源相同(mysql 、redis)部署多份即可,注意TxManager负载均衡5.0版本与之前版本机制不同。

(2)TX-LCN 负载均衡介绍
使用步骤:

  • 首选需要启动多个TxManager服务。
  • 在客户端配置TxManager服务地址。
  • tx-lcn.client.manager-address=127.0.0.1:8070,127.0.0.1:8072

(3)原理介绍:

  • 当有事务请求客户端时事务发起端会随机选择一个可用TxManager作为事务控制方,然后告知其参与模块都与该模块通讯。
  • 目前TX-LCN的负载机制仅提供了随机机制。

(4)关于tx-lcn.client.manager-address的注意事项:

  • 客户端在配置上tx-lcn.client.manager-address地址后,启动时必须要全部可访问客户端才能正常启动。

  • 当tx-lcn.client.manager-address中的服务存在不可用时,客户端会重试链接8次,超过次数以后将不在重试,重试链接的间隔时间为6秒,当所有的TxManager都不可访问则会导致所有的分布式事务请求都失败回滚。

  • 当增加一个新的TxManager的集群模块时不需要添加到tx-lcn.client.manager-address下,TxManager也会广播到所有的TxManager端再通知所有链接中的TxClient端新的TxManager加入。TC配置集群时,不用制定集群里的所有地址。

三、DEMO

1、准备环境

  • LCN5.0.2,JRE1.8+, Mysql5.6+, Redis3.2+
  • 下载LCN以及demo代码;

2.创建数据库以及库表

-- 创建lcn相关库表
CREATE DATABASE IF NOT EXISTS  `tx-manager` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE `tx-manager`;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `t_tx_exception`;
CREATE TABLE `t_tx_exception`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_state` tinyint(4) NULL DEFAULT NULL,
  `registrar` tinyint(4) NULL DEFAULT NULL,
  `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 待处理 1已处理',
  `remark` varchar(10240) NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;


-- 创建demo相关库表
-- 账户服务库表
CREATE TABLE `account` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_id` bigint(11) DEFAULT NULL COMMENT '用户id',
  `total` decimal(10,0) DEFAULT NULL COMMENT '总额度',
  `used` decimal(10,0) DEFAULT NULL COMMENT '已用余额',
  `residue` decimal(10,0) DEFAULT '0' COMMENT '剩余可用额度',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `seat-account`.`account` (`id`, `user_id`, `total`, `used`, `residue`) VALUES ('1', '1', '1000', '0', '100');

-- 库存服务库表
CREATE TABLE `storage` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
  `total` int(11) DEFAULT NULL COMMENT '总库存',
  `used` int(11) DEFAULT NULL COMMENT '已用库存',
  `residue` int(11) DEFAULT NULL COMMENT '剩余库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `seat-storage`.`storage` (`id`, `product_id`, `total`, `used`, `residue`) VALUES ('1', '1', '100', '0', '100');

-- 订单服务库表
CREATE TABLE `order` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(11) DEFAULT NULL COMMENT '用户id',
  `product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
  `count` int(11) DEFAULT NULL COMMENT '数量',
  `money` decimal(11,0) DEFAULT NULL COMMENT '金额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

3、demo概况

(1)demo分为四个项目,单独启动。

  • eureka:作为注册中心
  • order:订单服务,用户下单后,会创建一个订单添加在order数据库,同时会扣减库存storage,扣减账户account;
  • storage:库存服务,用户扣减库存;
  • account:账户服务,用于扣减账户余额;

注:启动以上服务之前需要先启动txlcn_tm服务

(2)配置相关

  • order,storage,account需要引入lcm相关依赖
  <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.2.RELEASE</version>
  </dependency>
  • 每个服务下的application.yml文件需要引入tc客户端地址
tx-lcn:
  client:
    manager-address: 127.0.0.1:8070
  • 在启动类上使用@EnableDistributedTransaction
@EnableDistributedTransaction
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.sugon.dao")
public class OrderServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }

}

(3)order服务关键代码如下:

    @Override
    @LcnTransaction //分布式事务注解
    public void create(Order order) {
     
        //本地方法 创建订单
        orderDao.create(order);
        //远程方法 扣减库存
        storageApi.decrease(order.getProductId(),order.getCount());
        //远程方法 扣减账户余额  可在accountServiceImpl中模拟异常
        accountApi.decrease(order.getUserId(),order.getMoney());
    }

注:其余两个服务业务组也需要加 @LcnTransaction

(4)测试

  • 正常访问:http://localhost:8080/order/create?userId=1&productId=1&count=10&money=100,各个服务正常

  • 模拟异常情况

  /**账户服务抛异常
​     * 扣减账户余额
​     * @param userId 用户id
​     * @param money 金额
​     */
​    @Override
​    public void decrease(Long userId, BigDecimal money) {
​    
  ​      LOGGER.info("------->扣减账户开始account中");
  ​      accountDao.decrease(userId,money);
  ​      LOGGER.info("------->扣减账户结束account中");
  ​      throw new RuntimeException("发生错误");
  ​      
    }

访问:http://localhost:8080/order/create?userId=1&productId=1&count=10&money=100报错,,发现事务回滚
LCN框架介绍_第3张图片

你可能感兴趣的:(java,LCN,分布式事务,TCC)