精华内容
下载资源
问答
  • 分布式计算就是通过计算机网络将计算工作分布到多台主机上,多个主机一起协同完成工作。我试着列一下相关知识吧。网络通讯,网络是...包括:Socket多线程非阻塞IO网络框架NettyMinaZeroMQ操作系统网络部分RPC...
    分布式计算就是通过计算机网络将计算工作分布到多台主机上,多个主机一起协同完成工作。

    我试着列一下相关知识吧。
    • 网络通讯,网络是分布式的基础,对分布式的理解建立在对网络的理解上,包括:
      • OSI模型的7层
      • TCP/IP,DNS,NAT
      • HTTP,SPDY/HTTP2
      • Telnet
    • 网络编程,是通过程序在多个主机之间通信。包括:
      • Socket
      • 多线程
      • 非阻塞IO
      • 网络框架
        • Netty
        • Mina
        • ZeroMQ
    • 操作系统的网络部分
    • RPC,Socket使用不是很方便,很多分布式应用是基于RPC的,包括:
      • 同步RPC
      • 异步RPC
      • 主要的一些RPC协议
        • RMI
        • Rest API
        • Thrift
    • 集群,分布式计算离不开集群。集群就是多台主机被当作一个系统
      • 集群类型
        • 高可用,如主机备机切换,冷备,热备,双活
        • 伸缩性,如Web服务器集群,数据库服务器的Sharding
        • 并行计算,如网格,大数据
      • 集群相关技术,包括:
        • 高可用性,保证服务一直能够被访问,延长MTBF,缩短MTTR
          • 冗余的设备
          • 多副本,为了避免单点失效
        • 负载均衡,如何将大量工作负载分配到多个主机上,最大化吞吐量,最小化平均响应时间,最大化资源利用率。
        • 伸缩性(横向),能够添加计算机和设备来应对增长的计算压力
        • 分片(Sharding),把数据分成多个数据集,由多个服务器来分别处理。
          • 自动分片
        • 容错性,当硬件或软件发生故障,能够继续运转
        • 故障检测,以及故障预测
          • 心跳包
          • 告警
          • 性能预警
        • 故障转移,当出现错误,如何解决,为了高可用性和容错性
        • 分布式一致性,在分布式环境中如何维持状态的一致性,严格一致性,还是最终一致性
        • 集群状态协调,如Zookeeper,etcd等。
          • 分布式锁,在分布式环境中如何进行加锁
          • 选主,当Master宕机,如何选择出新的Master,协议如Raft
        • 一致性哈希,如何将数据分布到集群中的多个主机。
        • 分布式事务,保证在多台服务器上完成的操作符合事务的ACID属性。
    • 安全,网络通常需要保证安全。
      • 身份认证,如何验证人或机器是他们声明的身份
        • 基于用户名/口令
        • 基于数字证书
      • 私密性,如何防止窃听和嗅探
        • 对称加密
        • 非对称加密
      • 完整性,如何保证数据不被篡改
        • 安全散列
        • 消息认证码(MAC)
      • 不可否认性
        • 基于数字证书的数字签名和验签
        • 基于密钥的散列,如HMAC
    • 互联网站的基本架构
      • 页面缓存
      • 负载均衡器,如HAProxy,Nginx
      • 分布式缓存,如Memcache,Redis
      • 消息队列,如ActiveMQ,Kafka
    • 分布式框架
      • 关系型数据库(Sharding,主从同步)
      • NoSQL
        • HBase,基于HDFS和Zookeeper的NoSQL
        • Cassandra,无主集群
      • 大数据
        • HDFS,分布式文件系统
        • MapReduce,将数据处理任务拆分为多个工作,通过集群来完成。
        • Spark,提供分布式的数据集抽象
    展开全文
  • 前言:架构师还要根据业务...优秀的Java架构师掌握了哪些必备基础! Java架构师,应该算是一些Java程序员们一个职业目标吧。很多码农码了五六年代码也没能成为架构师。那成为Java架构师需要掌握哪些技术呢,...

    前言:架构师还要根据业务发展阶段,提前预见发展到下一个阶段系统架构的解决方案,并且设计当前架构时将架构的升级扩展考虑进去,做到易于升级;否则等系统瓶颈来了,出问题了再去出方案,或现有架构无法扩展直接扔掉重做。

    优秀的Java架构师掌握了哪些必备基础!

    Java架构师,应该算是一些Java程序员们的一个职业目标吧。很多码农码了五六年的代码也没能成为架构师。那成为Java架构师需要掌握哪些技术呢,总体来说呢,有两方面,一个是基础技术,另一个就是组织能力和提出解决方案能力了。小编就跟大家来简要地说说吧。

    如果你是想成为Java架构师,那么你首先要是一个Java高级工程师。也就是说,基础必须牢固,对Java编程的了解全面而且深入。

    熟练使用各种框架,并知道它们实现的原理。Jvm虚拟机原理、调优操作,懂得jvm能让你写出性能更好的代码;池技术也是要掌握的,对象池、连接池、线程池都要会;Java反射技术,写框架必备的技术;Java各种集合对象的实现原理,了解这些可以让你在解决问题时选择合适的数据结构,高效地解决问题,写出代码;nio,注意“直接内存”的特点,使用场景。
    还没完,除了上边那些,你还要熟练使用各种数据结构和算法,数组、哈希、链表、排序树等等都是;熟练使用Linux操作系统,也是必备的;熟悉各种协议,比如tcp协议,创建连接三次握手和断开连接四次握手的整个过程,不了解就没法对高并发网络应用做优化链接
    架构师还要根据业务发展阶段,提前预见发展到下一个阶段系统架构的解决方案,并且设计当前架构时将架构的升级扩展考虑进去,做到易于升级;否则等系统瓶颈来了,出问题了再去出方案,或现有架构无法扩展直接扔掉重做,或扩展麻烦问题一大堆,这会对企业造成损失。
    架构师思考的是全局的东西,是如何组织系统,以达到业务要求、性能要求。架构师要针对业务特点、系统的性能要求提出解决问题成本最低的设计方案。为了架构而架构,这是绝对不可取的。你想啊,人家一个几百人用户的系统,访问量不大,数据量也不大,你给人家上集群、分布式储存、高端服务器,肯定能到达性能要求,但是成本高啊。要知道,架构师的作用,一是满足业务需求,二是最低的硬件网络成本和技术维护成本。
    其实这些最后的统筹能力还是建立在过硬的专业基础和项目经验之上。所以小编还是建议程序员们多上手操作,多多接触项目,想要入行的小白们不妨来动力节点IT培训了解一下,这里是全程项目实训,可以在四个月内积累一到两年的项目经验,工作的时候就会顺手很多。
     

    展开全文
  • 源码精品专栏原创 | Java 2020超神之路,很肝~中文详细注释开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库中间件 Sharding-JDBC 和 MyCAT 源码解析作业调度...

    点击上方“Java基基”,选择“设为星标”

    做积极的人,而不是积极废人!

    源码精品专栏

     
    • 原创 | Java 2020 超神之路,很肝~

    • 中文详细注释的开源项目

    • RPC 框架 Dubbo 源码解析

    • 网络应用框架 Netty 源码解析

    • 消息中间件 RocketMQ 源码解析

    • 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

    • 作业调度中间件 Elastic-Job 源码解析

    • 分布式事务中间件 TCC-Transaction 源码解析

    • Eureka 和 Hystrix 源码解析

    • Java 并发源码

    来源:wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/

    • 前言
    • 可靠性
    • 代码实现
      • 组件依赖
      • 加锁代码
      • 解锁代码
    • 总结
    • 参考阅读

    本博客使用第三方开源组件Jedis实现Redis客户端,且只考虑Redis服务端单机部署的场景。

    前言

    分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。

    可靠性

    首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

    1. **互斥性。**在任意时刻,只有一个客户端能持有锁。
    2. **不会发生死锁。**即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
    3. **具有容错性。**只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
    4. **解铃还须系铃人。**加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

    代码实现

    组件依赖

    首先我们要通过Maven引入Jedis开源组件,在pom.xml文件加入下面的代码:

    <dependency>
        <groupId>redis.clientsgroupId>
        <artifactId>jedisartifactId>
        <version>2.9.0version>
    dependency>

    加锁代码

    正确姿势

    Talk is cheap, show me the code。先展示代码,再带大家慢慢解释为什么这样实现:

    public class RedisTool {

        private static final String LOCK_SUCCESS = "OK";
        private static final String SET_IF_NOT_EXIST = "NX";
        private static final String SET_WITH_EXPIRE_TIME = "PX";

        /**
         * 尝试获取分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @param expireTime 超期时间
         * @return 是否获取成功
         */

        public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

            String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;

        }

    }

    可以看到,我们加锁就一行代码:jedis.set(String key, String value, String nxxx, String expx, int time),这个set()方法一共有五个形参:

    • 第一个为key,我们使用key来当锁,因为key是唯一的。
    • 第二个为value,我们传的是requestId,很多童鞋可能不明白,有key作为锁不就够了吗,为什么还要用到value?原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()方法生成。
    • 第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;
    • 第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。
    • 第五个为time,与第四个参数相呼应,代表key的过期时间。

    总的来说,执行上面的set()方法就只会导致两种结果:1. 当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,同时value表示加锁的客户端。2. 已有锁存在,不做任何操作。

    心细的童鞋就会发现了,我们的加锁代码满足我们可靠性里描述的三个条件。首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。由于我们只考虑Redis单机部署的场景,所以容错性我们暂不考虑。

    错误示例1

    比较常见的错误示例就是使用jedis.setnx()jedis.expire()组合实现加锁,代码如下:

    public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) {

        Long result = jedis.setnx(lockKey, requestId);
        if (result == 1) {
            // 若在这里程序突然崩溃,则无法设置过期时间,将发生死锁
            jedis.expire(lockKey, expireTime);
        }

    }

    setnx()方法作用就是SET IF NOT EXIST,expire()方法就是给锁加一个过期时间。乍一看好像和前面的set()方法结果一样,然而由于这是两条Redis命令,不具有原子性,如果程序在执行完setnx()之后突然崩溃,导致锁没有设置过期时间。那么将会发生死锁。网上之所以有人这样实现,是因为低版本的jedis并不支持多参数的set()方法。

    错误示例2

    这一种错误示例就比较难以发现问题,而且实现也比较复杂。实现思路:使用jedis.setnx()命令实现加锁,其中key是锁,value是锁的过期时间。执行过程:1. 通过setnx()方法尝试加锁,如果当前锁不存在,返回加锁成功。2. 如果锁已经存在则获取锁的过期时间,和当前时间比较,如果锁已经过期,则设置新的过期时间,返回加锁成功。代码如下:

    public static boolean wrongGetLock2(Jedis jedis, String lockKey, int expireTime) {

        long expires = System.currentTimeMillis() + expireTime;
        String expiresStr = String.valueOf(expires);

        // 如果当前锁不存在,返回加锁成功
        if (jedis.setnx(lockKey, expiresStr) == 1) {
            return true;
        }

        // 如果锁存在,获取锁的过期时间
        String currentValueStr = jedis.get(lockKey);
        if (currentValueStr != null && Long.parseLong(currentValueStr)         // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间
            String oldValueStr = jedis.getSet(lockKey, expiresStr);
            if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才有权利加锁
                return true;
            }
        }

        // 其他情况,一律返回加锁失败
        return false;

    }

    那么这段代码问题在哪里?1. 由于是客户端自己生成过期时间,所以需要强制要求分布式下每个客户端的时间必须同步。2. 当锁过期的时候,如果多个客户端同时执行jedis.getSet()方法,那么虽然最终只有一个客户端可以加锁,但是这个客户端的锁的过期时间可能被其他客户端覆盖。3. 锁不具备拥有者标识,即任何客户端都可以解锁。

    解锁代码

    正确姿势

    还是先展示代码,再带大家慢慢解释为什么这样实现:

    public class RedisTool {

        private static final Long RELEASE_SUCCESS = 1L;

        /**
         * 释放分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @return 是否释放成功
         */

        public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;

        }

    }

    可以看到,我们解锁只需要两行代码就搞定了!第一行代码,我们写了一个简单的Lua脚本代码,上一次见到这个编程语言还是在《黑客与画家》里,没想到这次居然用上了。第二行代码,我们将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。eval()方法是将Lua代码交给Redis服务端执行。

    那么这段Lua代码的功能是什么呢?其实很简单,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。那么为什么要使用Lua语言来实现呢?因为要确保上述操作是原子性的。关于非原子性会带来什么问题,可以阅读【解锁代码-错误示例2】 。那么为什么执行eval()方法可以确保原子性,源于Redis的特性,下面是官网对eval命令的部分解释:

    95e246d388317198b0033635ccd61eb6.png

    简单来说,就是在eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令。

    错误示例1

    最常见的解锁代码就是直接使用jedis.del()方法删除锁,这种不先判断锁的拥有者而直接解锁的方式,会导致任何客户端都可以随时进行解锁,即使这把锁不是它的。

    public static void wrongReleaseLock1(Jedis jedis, String lockKey) {
        jedis.del(lockKey);
    }

    错误示例2

    这种解锁代码乍一看也是没问题,甚至我之前也差点这样实现,与正确姿势差不多,唯一区别的是分成两条命令去执行,代码如下:

    public static void wrongReleaseLock2(Jedis jedis, String lockKey, String requestId) {

        // 判断加锁与解锁是不是同一个客户端
        if (requestId.equals(jedis.get(lockKey))) {
            // 若在此时,这把锁突然不是这个客户端的,则会误解锁
            jedis.del(lockKey);
        }

    }

    如代码注释,问题在于如果调用jedis.del()方法的时候,这把锁已经不属于当前客户端的时候会解除他人加的锁。那么是否真的有这种场景?答案是肯定的,比如客户端A加锁,一段时间之后客户端A解锁,在执行jedis.del()之前,锁突然过期了,此时客户端B尝试加锁成功,然后客户端A再执行del()方法,则将客户端B的锁给解除了。

    总结

    本文主要介绍了如何使用Java代码正确实现Redis分布式锁,对于加锁和解锁也分别给出了两个比较经典的错误示例。其实想要通过Redis实现分布式锁并不难,只要保证能满足可靠性里的四个条件。互联网虽然给我们带来了方便,只要有问题就可以google,然而网上的答案一定是对的吗?其实不然,所以我们更应该时刻保持着质疑精神,多想多验证。

    如果你的项目中Redis是多机部署的,那么可以尝试使用Redisson实现分布式锁,这是Redis官方提供的Java组件,链接在参考阅读章节已经给出。



    欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

    9ffa125b5e5f9ae8ddc2e23b5b20769f.png

    已在知识星球更新源码解析如下:

    ef67e52ffa20b96e6a344375d0cf6ce7.png

    ed5c9cdb93c8bb1ff620612847cf7d91.png

    7711c57bc00e303498b2e7c668b0cb8f.png

    142744fc92a378c53d2105cdfe8c4407.png

    最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

    提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

    获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

    f0d116db4da37c5de573ae72205426eb.gif

    展开全文
  • 前言工欲善其事必先利其器,既然我们决定要做一个分布式事务框架,那首先需要了解一下,分布式事务是怎么回事,它跟传统本地事务有什么区别,解决方案有哪些,每种解决方案对比等等。本地事务在了解分布式事务...

    前言

    工欲善其事必先利其器,既然我们决定要做一个分布式事务框架,那首先需要了解一下,分布式事务是怎么回事,它跟传统的本地事务有什么区别,解决方案有哪些,每种解决方案的对比等等。

    本地事务

    在了解分布式事务之前,先回顾一下本地事务,顾名思义,本地事务就是在同一个JVM中,一个开启了事务的业务方法就是本地事务。

    而这一个开启了事务的业务方法里面的操作要么全部执行成功,要么全部执行失败,不允许只成功一半另外一半执行失败的事情发生。

    例如该业务方法中,有两次数据库更新操作,那么这两次数据库操作要么全部执行成功,要么全部回滚。

    使用专业术语来讲的话,就是事务的4个基本特性:Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durablity(持久性),统称ACID,这里简单的对ACID做一个概念的说明,当作是做个笔记:

    • Atomicity(原子性)
      是指事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。通俗的说,就是所有操作要么全部成功,要么全部失败回滚。
    • Consistency(一致性)
      是指事务执行前后,数据从一个状态到另一个状态必须是一致的,比如A向B转账(A、B的总金额就是一个一致性状态),不可能出现A扣了钱,B却没收到的情况发生。
    • Isolation(隔离性)
      是指当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。这里涉及到数据库的隔离级别的概念,不是我们讨论的主题,不详细展开,大家可以自行查阅相关资料。
    • Durablity(持久性)
      是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

    分布式事务

    通过以上的回顾我们知道,本地事务对于我们来说不是什么问题,因为我们可以直接使用数据库的事务支持,比如mysql、oracle这些数据库对事务都有很好的支持。

    但是,对于分布式应用来说的话,事务就没有那么简单了,因为需要开启事务的业务方法,很可能是分布在不同应用程序中,这就说明,大家不在同一个JVM中,事务空间都不一样了,那就没办法做到要么全部执行成功,要么全部执行失败了,我们可以看以下分析图:

    27f0327fd0056accc8ea017f7dba5f5b.png

    如上图所示:这是一个分布式应用,完成一个付款业务的操作需要有4个微服务参与,大家都独立运行在自己的JVM中,其中,订单系统、商品系统和会员系统是服务提供者,有自己对应的数据库。

    客户端应用在发起了付款请求时,调用了订单系统的支付业务makePayment,而makePayment方法中,又调用了远程商品系统的decrease方法和远程会员系统的payment方法,分别做减库存和扣余额的操作,那现在就有两种情况了:

    第一种情况是流程正常执行,各个业务参与者都没有异常,万事大吉。

    第二种情况是其中有一个业务参与者出现异常了,按照我们上面对本地事务的理解,它们应该要做到要么全部执行成功,要么全部执行失败了,这样才能确保数据一致性。

    但现在这个不是单体应用,而是分布式应用,原本一个本地逻辑执行单元被拆分到了多个独立的微服务中,这些微服务又分别操作不同的数据库和表,服务之间通过网络调用。

    所以这就没办法确保要么全部执行成功,要么全部执行失败了,因为我怎么知道远程的服务是否执行成功呢。

    现在问题就出现了,我们不能再用单体应用的那种事务方式,套用在分布式应用中了,必须要思考用什么样的解决方案来控制分布式应用的事务问题。这就是“分布式事务”。

    分布式事务的解决方案

    分布式事务的解决方案有很多,但可以具体归纳为两种:

    • 强一致性事务
      强一致性事务的代表就是XA事务协议了,它由Oracle Tuxedo提出,把分散到各个JVM中的事务资源,又整合为全局事务统一管理了。
    • 柔性事务
      而柔性事务并没有像强一致性事务那样整合为全局事务,但其目的都是确保分布式事务最终一致性的。柔性事务又可以细分为TCC事务和可靠消息事务,这两种分布式事务处理方式不一样,接下来我们具体分析一下这几种分布式事务解决方案的实现原理。

    XA事务协议

    XA是一个分布式事务协议,XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,MySQL5.7之后也支持XA分布式事务。

    而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。

    XA分布式事务协议的工作原理是:把各个微服务中的本地资源交给一个统一的事务管理器管理,事务管理器可以看做是事务协调者的角色(coordinator),各个本地资源管理器可以看做是事务参与者的角色(partcipant)。

    各个事务参与者之间不能直接通讯,而是通过事务协调者间接通讯,通俗来说,服务A怎么知道服务B是否执行成功?就是由事务协调者转告各个事务参与者了。

    通过以下分析图,看看XA实现分布式事务的流程:

    04a7b4fcfd710926a9eee12170313ccb.png
    1b5b9e78e90f2af2cee69f5eb42f88d9.png

    以上就是XA分布式事务执行流程,加入了全局的事务管理器作为协调者,在接收到发起带事务的业务方法后,发送prepare到各个事务参与者,各个事务参与者接收到prepare后,开启本地事务being,并执行本地业务流程,如果流程正常运行,则返回ready结果给事务协调者,告知准备就绪了,这时,如果各个事务参与者返回的结果都是ready,那么事务协调者就会再次发送一个全局事务提交global_commit的消息到各个事务参与者,最后,各个事务参与者收到global_commit后,提交本地事务commit。

    这是业务流程正常执行的情况,那如果因为流程有异常就走如下流程:事务协调者还是发送prepare到各个事务参与者,事务参与者接收到prepare后,开启本地事务begin,接着执行业务流程,此时,如果有某个事务参与者执行业务报错,返回异常abort给事务协调者,事务协调者会再次发送全局回滚global_rollback给各个事务参与者,事务参与者接受到global_rollback后,开始回滚本地事务rollback,即便是流程正常执行的也要回滚掉,这样就能确保要么一起成功,要么一起失败。

    总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。

    但是,XA也有致命的缺点,那就是性能不理想,特别是在并发量很高的情况下,会带来性能瓶颈,因为根据以上执行流程图的分析可知,在全局事务管理器向各个事务参与者发送prepare时,是需要锁住资源的,也就是此时,所有相关连的微服务都处于阻塞状态,需要等到所有事务参与者返回最终处理结构,才能释放锁,所以XA无法满足高并发场景。

    其次,XA目前在数据库的支持上不太理想,mysql5.7之前是不支持的,并且还有许多nosql也没有支持XA,而大多数新型的互联网微服务应用都会使用各种nosql数据库,所以这就导致了XA的应用场景变得非常狭隘。

    TCC事务

    TCC是Try-Confirm-Cancel的简称。其核心思想是:每个需要开启分布式事务的业务方法,都要注册一个与其对应的检测、确认和撤销的操作,如下:

    • Try阶段:主要是对业务系统做检测的操作,没有问题就调用确认操作,有问题则调用取消操作。
    • Confirm阶段:确认执行业务操作。
    • Cancel阶段:取消执行业务操作。

    具体执行流程如下:


    通过以上的流程,我们可以发现,TCC的分布式事务处理与XA的分布式事务处理流程是非常相似的, 调用try接口检查业务是否有异常的操作,类似于XA的prepare预提交,如果接口返回正常,则调用confirm确认执行业务,操作数据。


    那如果其中有一个事务参与者在调用了try接口检测后,返回了异常给事务协调者,但是之前很可能已经有其他事务参与者调用了confirm接口,执行业务流程操作了数据,那这时,事务协调者就需要调用事务参与者的cancel接口,撤销之前修改的数据,达到类似回滚的效果。


    不过XA是在跨库的DB层面,而TCC是应用层面,需要通过业务逻辑来实现分布式事务。

    TCC的实现方式优势在于:没有项目XA协议那样,把分布的资源统一管理,这就使得分布的资源不会被加锁,从而提高整体的吞吐量,所以这种分布式事务的解决方案,在性能和吞吐量要求高的应用使用的还是比较多的。

    而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作。

    此外,其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。同时,confirm和cancel接口还要考虑幂等性的问题,因为confirm和cancel有可能会被多次调用。

    可靠消息事务

    可靠消息事务全称叫做可靠消息事务最终一致性,它通常没有像前面两种分布式事务解决方案那样有回滚或撤销数据的操作,而更多的是强调事务的补偿和重试。

    这里的可靠消息指的是消息队列中间件,消息队列其中一个特点就是消息可靠性,而该解决方案最终能达到事务一致,依靠的核心就是消息队列。

    先粗略的看看它执行流程:

    6bbf7d4ba0e08ba794c7286ed7923958.png

    从以上的执行流程可以发现,各个事务参与者都是相对独立的,不管在执行业务方法的过程中是否有异常,整体的业务流程都要先跑完,这个是该解决方案的前提。

    然后在调用事务参与者的业务方法的同时,往消息队列发送事务相关的消息,这样的话,出现异常的事务参与者再从消息队列中获取消息,重新执行本地的业务,达到补偿和重试的效果,整个事务中,不管中间有哪些参与者出错,但是最终还是事务一致的。

    这种解决方案是所有解决方案中最柔性的,并且灵活度非常高,可以根据自己具体的业务场景做改变,同时,对比TCC来说,性能和吞吐量更高,并且对应用的侵入性更低。

    性能的提高体现在:没有了业务检测的环节,跟原本一样,该怎么调用远程方法就怎么调用,只是增加了一个往MQ发送消息的操作,但是该操作是异步的,而且MQ也是具备高吞吐量的特性。

    而侵入性更低体现在:MQ是中间件,只需要通过网络来调用即可,我们的业务方法并不会由于分布式事务解决方案的加入而有太多的改造,加入的代码更多是以外围扩展,或者组件的方式加入。

    可靠消息事务最终一致性的解决方案优点很明显,但缺点也不是没有的,首先该解决方案设计过于复杂,组件很多,需要考虑的情况繁杂,实现起来比较困难。

    其次,虽然它是最柔性,最灵活和性能最高的,但是事务的原子性和一致性是最弱的,因为这种解决方案是以大家都不出错为前提的,如果其中有一个出错,自己通过补偿机制重新执行本地事务,但重试的过程本身就是不确定性的。

    比如说:A转钱给B,A账户扣钱了,但是B账户加钱时出错,在该机制下,A账户不会回滚,而是让B账户重新尝试加钱,那这就产生时间上的延迟了,很可能等了很久,都没见B账户把钱加上去,或者不断重试都是失败的,最终导致整个事务不一致,需要人工处理。

    总的来说,可靠消息事务最终一致性由于它的事务原子性和一致性比较弱,所以决定了它在一些事务ACID要求非常强的应用中是不能使用的,否则会造成很多安全性的问题。

    但是对于大多数互联网应用来说,都是一个不错的解决方案。而具体使用哪一种,还是取决于项目的业务场景,然后做全面的对比、考量和取舍。

    展开全文
  • 分布式面试 - zookeeper 都有哪些使用场景? 面试题 zookeeper 都有哪些使用场景? 面试官心理分析 现在聊 topic 是分布式系统,面试官跟你聊完了 dubbo 相关一些问题之后,已经确认你对分布式服务框架/...
  • 分布式任务框架对比

    2019-07-04 15:48:01
    java有哪些定时任务的框架 单机 timer:是一个定时器类,通过该类可以为指定定时任务进行配置。TimerTask类是一个定时任务类,该类实现了Runnable接口,缺点异常未检查会中止线程 ScheduledExecutorService:相对...
  • 标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面。我也知道,不少候选人能力其实不差,但面试时没准备或不会说,这样人可能...
  • 主流RPC框架有哪些

    千次阅读 2019-09-23 17:53:58
    JavaRPC框架比较多,各特色,广泛使用的有RMI、Hessian、Dubbo等。RPC还有一个特点就是能够跨语言。 1、RMI(远程方法调用) JAVA自带远程方法调用工具,不过一定局限性,毕竟是JAVA语言最开始时...
  • 前言工欲善其事必先利其器,既然我们决定要做一个分布式事务框架,那首先需要了解一下,分布式事务是怎么回事,它跟传统本地事务有什么区别,解决方案有哪些,每种解决方案对比等等。本地事务在了解分布式事务...
  • 首先,github上的Java代码,然后打开eclipse,在左边工程栏,鼠标右键选择import,然后选择General->Existing Projects into Workspace,然后选着您下来代码路径下文件,接下来一直next就可以了。eclipse是一...
  • 因为是复刻JavaMybatis,因此框架暂命名 Rbatis。小部分功能还在进行中。 github链接https://github.com/rbatis/rbatis首先介绍下rust语言下牛逼哄哄产品有哪些?(最近风靡前端原nodejs大神实现...
  • 内容包括:Java 集合 22 题及答案解析JVM与调优 21 题及答案解析并发编程 28 题及答案解析Spring 25 题及答案解析23种设计模式解析Spring Boot25题及答案解析分布式高并发架构解析(消息队列,分库分表,事务,高...
  • 因为是复刻JavaMybatis,因此框架暂命名 Rbatis。小部分功能还在进行中。github链接https://github.com/rbatis/rbatis首先介绍下rust语言下牛逼哄哄产品有哪些?(最近风靡前端原nodejs大神实现TypeScript...
  • Java程序员除了要掌握20%以外还要掌握些什么知识才能游刃有余。下面说说我接触(使用)过、东西吧。java分布式应用丰富生态闻名,在... etc)RPC框架在SOA架构中起着重要作用,好好探究终是好处,在...
  • 分布式系统的面试连环炮 面试题 ...现在互联网公司,一般都是做分布式的系统,大家都不是做底层的分布式系统,分布式存储系统,hadoop hdfs,分布式计算系统,hadoop mapreduce,spark,分布式流式计算系
  • ✎架构师高并发高性能分布式教程(4000G)✎39阶段精品云计算大数据实战视频教程✎200本经典编程相关书籍下载✎互联网技术(框架分布式集群)干货视频大全✎程序员如何制作高质量简历【视...
  • java有哪些技术领域

    千次阅读 2018-12-07 23:10:36
    1、Java中间件,分布式系统、分布式缓存...分布式系统-dubbo-spring cloud:一定是多个节点组成系统,一般一个节点就是一台服务器,节点之间是相互连通协作,这些连通节点上部署了我们组件,共同服务于一...
  • zk都有哪些使用场景? 2、面试官心里分析 zk,zookeeper,你们现在在聊面试topic,是分布式系统,他其实已经跟你聊完了dubbo以及相关一些问题,确认,你现在分布式服务框架,rpc框架,基本都有一些认知。...
  • 有哪些成功使用案例? … 为了让你更好地了解 Netty 以及它诞生原因,先从传统网络编程说起吧! 美团面试经历(还原最真实4面) 美团一面: 1、自我介绍 2、聊项目相关 介绍项目 怎么保证redis与Mysql...
  • 开头 最近一个哥们去面试某当红...面试官不愧是大佬,一层接一层的问过来,问完**“Redis 怎样实现的分布式锁”又问“单机锁有哪些?它为什么不能在分布式环境下使用?”** 由于平时只是改改以前的框架代码,哥们当场懵
  • 3.Spring Could常见组件有哪些?可参考《Spring Cloud概述》 4.领域驱动有了解吗?什么是领域驱动模型?充血模型、贫血模型 5.JWT有了解吗,什么是JWT,可参考《前后端分离利器之JWT》 6.你怎么理解 RESTful 7...
  • Java是开源框架很多,这些框架都能解决特定问题,提高开发效率、简化我们代码复杂度,现在除了很多大家通用一些主流框架外,很多公司针对自己业务会自定义一些公司内部的框架,当然作为学习者我们首先要...
  • zookeeper 都有哪些使用场景? 面试官心理分析 现在聊 topic 是分布式系统,面试官跟你聊完了 dubbo 相关一些问题之后,已经确认你对分布式服务框架/RPC框架基本都有一些认知了。那么他可能开始要跟你聊分布式...
  • spark the best,open sourceDuckChat开源系统据说支持即时消息,它有哪些特性?您可以下载程序在本地运行。现有开源IM框架即时通讯开源项目。应该开发web爬虫选择Nutch、Crawler4j、WebMagic、scrapy、...
  • 分布式锁zookeeper面试

    2020-05-19 11:54:38
    zookeeper 都有哪些使用场景? 面试官心理分析 现在聊 topic 是分布式系统,面试官跟你聊完了 dubbo 相关一些问题之后,已经确认你对分布式服务框架/RPC框架基本都有一些认知了。那么他可能开始要跟你聊分布式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 400
精华内容 160
关键字:

java的分布式框架有哪些

java 订阅