深度剖析一站式分布式事务方案Seata
更多干货
-
分布式实战(干货)
-
spring cloud 实战(干货)
-
mybatis 实战(干货)
-
spring boot 实战(干货)
-
React 入门实战(干货)
-
构建中小型互联网企业架构(干货)
-
python 学习持续更新
-
ElasticSearch 笔记
-
kafka storm 实战 (干货)
-
scala 学习持续更新
-
RPC
-
深度学习
-
GO 语言 持续更新
-
Android 学习
-
nginx 相关文章
-
vue学习
转载: http://blog.itpub.net/31555607/viewspace-2640669/
1.关于Seata
再前不久,我写了一篇关于分布式事务中间件Fescar的解析,没过几天Fescar团队对其进行了品牌升级,取名为Seata(Simpe Extensible Autonomous Transcaction Architecture),而以前的Fescar的英文全称为Fast & EaSy Commit And Rollback。可以看见Fescar从名字上来看更加局限于Commit和Rollback,而新的品牌名字Seata旨在打造一套一站式分布式事务解决方案。更换名字之后,我对其未来的发展更有信心。
这里先大概回忆一下Seata的整个过程模型:
-
TM:事务的发起者。用来告诉TC,全局事务的开始,提交,回滚。
-
RM:具体的事务资源,每一个RM都会作为一个分支事务注册在TC。
-
TC:事务的协调者。也可以看做是Fescar-servr,用于接收我们的事务的注册,提交和回滚。
在之前的文章中对整个角色有个大体的介绍,在这篇文章中我将重点介绍其中的核心角色TC,也就是事务协调器。
2.Transcation Coordinator
为什么之前一直强调TC是核心呢?那因为TC这个角色就好像上帝一样,管控着云云众生的RM和TM。如果TC一旦不好使,那么RM和TM一旦出现小问题,那必定会乱的一塌糊涂。所以要想了解Seata,那么必须要了解他的TC。
那么一个优秀的事务协调者应该具备哪些能力呢?我觉得应该有以下几个:
-
正确的协调:能正确的协调RM和TM接下来应该做什么,做错了应该怎么办,做对了应该怎么办。
-
高可用: 事务协调器在分布式事务中很重要,如果不能保证高可用,那么他也没有存在的必要了。
-
高性能:事务协调器的性能一定要高,如果事务协调器性能有瓶颈那么他所管理的RM和TM那么会经常遇到超时,从而引起回滚频繁。
-
高扩展性:这个特点是属于代码层面的,如果是一个优秀的框架,那么需要给使用方很多自定义扩展,比如服务注册/发现,读取配置等等。
下面我也将逐步阐述Seata是如何做到上面四点。
2.1 Seata-Server的设计
Seata-Server整体的模块图如上所示:
-
Coordinator Core: 在最下面的模块是事务协调器核心代码,主要用来处理事务协调的逻辑,如是否commit,rollback等协调活动。
-
Store:存储模块,用来将我们的数据持久化,防止重启或者宕机数据丢失。
-
Discover: 服务注册/发现模块,用于将Server地址暴露给我们Client。
-
Config: 用来存储和查找我们服务端的配置。
-
Lock: 锁模块,用于给Seata提供全局锁的功能。
-
Rpc:用于和其他端通信。
-
HA-Cluster:高可用集群,目前还没开源。为Seata提供可靠的高可用功能。
2.2 Discover
首先来讲讲比较基础的Discover模块,又称服务注册/发现模块。我们将Seata-Sever启动之后,需要将自己的地址暴露给其他使用者,那么就需要我们这个模块帮忙。
这个模块有个核心接口RegistryService,如上图所示:
-
register:服务端使用,进行服务注册。
-
unregister:服务端使用,一般在JVM关闭钩子,ShutdownHook中调用。
-
subscribe:客户端使用,注册监听事件,用来监听地址的变化。
-
unsubscribe:客户端使用,取消注册监听事件。
-
looup:客户端使用,根据key查找服务地址列表。
-
close:都可以使用,用于关闭Register资源。
如果需要添加自己定义的服务注册/发现,那么实现这个接口即可。截止目前在社区的不断开发推动下,已经有四种服务注册/发现,分别是redis,zk,nacos,eruka。下面简单介绍下Nacos的实现:
2.2.1 register接口:
step1:校验地址是否合法
step2:获取Nacos的Name实例,然后将地址注册到当前Cluster名称上面。
unregister接口类似,这里不做详解。
2.2.2 lookup接口:
step1:获取当前clusterName名字
step2:判断当前cluster是否已经获取过了,如果获取过就从map中取。
step3:从Nacos拿到地址数据,将其转换成我们所需要的。
step4:将我们事件变动的Listener注册到Nacos
2.2.3 subscribe接口
这个接口比较简单,具体分两步:
step1:将clstuer和listener添加进map中。
step2:向Nacos注册。
2.3 Config
配置模块也是一个比较基础,比较简单的模块。我们需要配置一些常用的参数比如:Netty的select线程数量,work线程数量,session允许最大为多少等等,当然这些参数再Seata中都有自己的默认设置。
同样的在Seata中也提供了一个接口Configuration,用来自定义我们需要的获取配置的地方:
-
getInt/Long/Boolean/Config():通过dataId来获取对应的值。
-
putConfig:用于添加配置。
-
removeConfig:删除一个配置。
-
add/remove/get ConfigListener:添加/删除/获取 配置监听器,一般用来监听配置的变更。
目前为止有四种方式获取Config:File(文件获取),Nacos,Apollo,ZK。再Seata中首先需要配置registry.conf,来配置conf的类型。实现conf比较简单这里就不深入分析。
2.4 Store
存储层的实现对于Seata是否高性能,是否可靠非常关键。
如果存储层没有实现好,那么如果发生宕机,在TC中正在进行分布式事务处理的数据将会被丢失,既然使用了分布式事务,那么其肯定不能容忍丢失。如果存储层实现好了,但是其性能有很大问题,RM可能会发生频繁回滚那么其完全无法应对高并发的场景。
在Seata中默认提供了文件方式的存储,下面我们定义我们存储的数据为Session,而我们的TM创造的全局事务数据叫GloabSession,RM创造的分支事务叫BranchSession,一个GloabSession可以拥有多个BranchSession。我们的目的就是要将这么多Session存储下来。
在FileTransactionStoreManager#writeSession代码中:
上面的代码主要分为下面几步:
-
step1:生成一个TransactionWriteFuture。
-
step2:将这个futureRequest丢进一个LinkedBlockingQueue中。为什么需要将所有数据都丢进队列中呢?当然这里其实也可以用锁来实现,再另外一个阿里开源的RocketMQ中,使用的锁。不论是队列还是锁他们的目的是为了保证单线程写,这又是为什么呢?有人会解释说,需要保证顺序写,这样速度就很快,这个理解是错误的,我们的FileChannel其实是线程安全的,已经能保证顺序写了。保证单线程写其实是为了让我们这个写逻辑都是单线程的,因为可能有些文件写满或者记录写数据位置等等逻辑,当然这些逻辑都可以主动加锁去做,但是为了实现简单方便,直接再整个写逻辑加锁是最为合适的。
-
step3:调用future.get,等待我们该条数据写逻辑完成通知。
我们将数据提交到队列之后,我们接下来需要对其进行消费,代码如下:
这里将一个WriteDataFileRunnable()提交进我们的线程池,这个Runnable的run()方法如下:
分为下面几步:
step1: 判断是否停止,如果stopping为true则返回null。
step2:从我们的队列中获取数据。
step3:判断future是否已经超时了,如果超时,则设置结果为false,此时我们生产者get()方法会接触阻塞。
step4:将我们的数据写进文件,此时数据还在pageCahce层并没有刷新到磁盘,如果写成功然后根据条件判断是否进行刷盘操作。
step5:当写入数量到达一定的时候,或者写入时间到达一定的时候,需要将我们当前的文件保存为历史文件,删除以前的历史文件,然后创建新的文件。这一步是为了防止我们文件无限增长,大量无效数据浪费磁盘资源。
在我们的writeDataFile中有如下代码:
step1:首先获取我们的ByteBuffer,如果超出最大循环BufferSize就直接创建一个新的,否则就使用我们缓存的Buffer。这一步可以很大的减少GC。
step2:然后将数据添加进入ByteBuffer。
step3:最后将ByteBuffer写入我们的fileChannel,这里会重试三次。此时的数据还在pageCache层,受两方面的影响,OS有自己的刷新策略,但是这个业务程序不能控制,为了防止宕机等事件出现造成大量数据丢失,所以就需要业务自己控制flush。下面是flush的代码:
这里flush的条件写入一定数量或者写的时间超过一定时间,这样也会有个小问题如果是停电,那么pageCache中有可能还有数据并没有被刷盘,会导致少量的数据丢失。目前还不支持同步模式,也就是每条数据都需要做刷盘操作,这样可以保证每条消息都落盘,但是性能也会受到极大的影响,当然后续会不断的演进支持。
我们的store核心流程主要是上面几个方法,当然还有一些比如,session重建等,这些比较简单,读者可以自行阅读。
2.5 Lock
大家知道数据库实现隔离级别主要是通过锁来实现的,同样的再分布式事务框架Seata中要实现隔离级别也需要通过锁。一般在数据库中数据库的隔离级别一共有四种:读未提交,读已提交,可重复读,串行化。在Seata中可以保证写的隔离级别是已提交,而读的隔离级别一般是未提交,但是提供了达到读已提交隔离的手段。
Lock模块也就是Seata实现隔离级别的核心模块。在Lock模块中提供了一个接口用于管理我们的锁:
其中有三个方法:
-
acquireLock:用于对我们的BranchSession加锁,这里虽然是传的分支事务Session,实际上是对分支事务的资源加锁,成功返回true。
-
isLockable:根据事务ID,资源Id,锁住的Key来查询是否已经加锁。
-
cleanAllLocks:清除所有的锁。
对于锁我们可以在本地实现,也可以通过redis或者mysql来帮助我们实现。官方默认提供了本地全局锁的实现:
在本地锁的实现中有两个常量需要关注: -
BUCKET_PER_TABLE:用来定义每个table有多少个bucket,目的是为了后续对同一个表加锁的时候减少竞争。
-
LOCK_MAP:这个map从定义上来看非常复杂,里里外外套了很多层Map,这里用个表格具体说明一下:
层数 | key | value |
---|---|---|
1-LOCK_MAP | resourceId(jdbcUrl) | dbLockMap |
2- dbLockMap | tableName (表名) | tableLockMap |
3- tableLockMap | PK.hashcode%Bucket (主键值的hashcode%bucket) | bucketLockMap |
4- bucketLockMap | PK | trascationId |
可以看见实际上的加锁在bucketLockMap这个map中,这里具体的加锁方法比较简单就不作详细阐述,主要是逐步的找到bucketLockMap,然后将当前trascationId塞进去,如果这个主键当前有TranscationId,那么比较是否是自己,如果不是则加锁失败。
2.6 Rpc
保证Seata高性能的关键之一也是使用了Netty作为RPC框架,采用默认配置的线程模型如下图所示:
如果采用默认的基本配置那么会有一个Acceptor线程用于处理客户端的链接,会有cpu*2数量的NIO-Thread,再这个线程中不会做业务太重的事情,只会做一些速度比较快的事情,比如编解码,心跳事件,和TM注册。一些比较费时间的业务操作将会交给业务线程池,默认情况下业务线程池配置为最小线程为100,最大为500。
这里需要提一下的是Seata的心跳机制,这里是使用Netty的IdleStateHandler完成的,如下:
在Sever端对于写没有设置最大空闲时间,对于读设置了最大空闲时间,默认为15s,如果超过15s则会将链接断开,关闭资源。
step1:判断是否是读空闲的检测事件。
step2:如果是则断开链接,关闭资源。
2.7 HA-Cluster
目前官方没有公布HA-Cluster,但是通过一些其他中间件和官方的一些透露,可以将HA-Cluster用如下方式设计:
具体的流程如下:
step1:客户端发布信息的时候根据transcationId保证同一个transcation是在同一个master上,通过多个Master水平扩展,提供并发处理性能。
step2:在server端中一个master有多个slave,master中的数据近实时同步到slave上,保证当master宕机的时候,还能有其他slave顶上来可以用。
当然上述一切都是猜测,具体的设计实现还得等0.5版本之后。目前有一个Go版本的Seata-Server也捐赠给了Seata(还在流程中),其通过raft实现副本一致性,其他细节不是太清楚。
2.8 Metrics
这个模块也是一个没有具体公布实现的模块,当然有可能会提供插件口,让其他第三方metric接入进来,最近Apache skywalking 正在和Seata小组商讨如何接入进来。
3.Coordinator Core
上面我们讲了很多Server基础模块,想必大家对Seata的实现已经有个大概,接下来我会讲解事务协调器具体逻辑是如何实现的,让大家更加了解Seata的实现内幕。
3.1 启动流程
启动方法在Server类有个main方法,定义了我们启动流程:
step1:创建一个RpcServer,再这个里面包含了我们网络的操作,用Netty实现了服务端。
step2:解析端口号和文件地址。
step3:初始化SessionHoler,其中最重要的重要就是重我们dataDir这个文件夹中恢复我们的数据,重建我们的Session。
step4:创建一个CoorDinator,这个也是我们事务协调器的逻辑核心代码,然后将其初始化,其内部初始化的逻辑会创建四个定时任务:
-
retryRollbacking:重试rollback定时任务,用于将那些失败的rollback进行重试的,每隔5ms执行一次。
-
retryCommitting:重试commit定时任务,用于将那些失败的commit进行重试的,每隔5ms执行一次。
-
asyncCommitting:异步commit定时任务,用于执行异步的commit,每隔10ms一次。
-
timeoutCheck:超时定时任务检测,用于检测超时的任务,然后执行超时的逻辑,每隔2ms执行一次。
step5: 初始化UUIDGenerator这个也是我们生成各种ID(transcationId,branchId)的基本类。
step6:将本地IP和监听端口设置到XID中,初始化rpcServer等待客户端的连接。
启动流程比较简单,下面我会介绍分布式事务框架中的常见的一些业务逻辑Seata是如何处理的。
3.2 Begin-开启全局事务
一次分布式事务的起始点一定是开启全局事务,首先我们看看全局事务Seata是如何实现的:
step1: 根据应用ID,事务分组,名字,超时时间创建一个GloabSession,这个再前面也提到过他和branchSession分别是什么。
step2:对其添加一个RootSessionManager用于监听一些事件,这里要说一下目前在Seata里面有四种类型的Listener(这里要说明的是所有的sessionManager都实现了SessionLifecycleListener):
-
ROOT_SESSION_MANAGER:最全,最大的,拥有所有的Session。
-
ASYNC_COMMITTING_SESSION_MANAGER:用于管理需要做异步commit的Session。
-
RETRY_COMMITTING_SESSION_MANAGER:用于管理重试commit的Session。
-
RETRY_ROLLBACKING_SESSION_MANAGER:用于管理重试回滚的Session。
由于这里是开启事务,其他SessionManager不需要关注,我们只添加RootSessionManager即可。
step3:开启Globalsession
这一步会把状态变为Begin,记录开始时间,并且调用RootSessionManager的onBegin监听方法,将Session保存到map并写入到我们的文件。
step4:最后返回XID,这个XID是由ip+port+transactionId组成的,非常重要,当TM申请到之后需要将这个ID传到RM中,RM通过XID来决定到底应该访问哪一台Server。
3.3 BranchRegister-分支事务注册
当我们全局事务在TM开启之后,我们RM的分支事务也需要注册到我们的全局事务之上,这里看看是如何处理的:
step1:通过transactionId获取并校验全局事务是否是开启状态。
step2:创建一个新的分支事务,也就是我们的BranchSession。
step3:对分支事务进行加全局锁,这里的逻辑就是使用的我们锁模块的逻辑。
step4:添加branchSession,主要是将其添加到globalSession对象中,并写入到我们的文件中。
step5:返回branchId,这个ID也很重要,我们后续需要用它来回滚我们的事务,或者对我们分支事务状态更新。
分支事务注册之后,还需要汇报分支事务的后续状态到底是成功还是失败,在Server目前只是简单的做一下保存记录,汇报的目的是,就算这个分支事务失败,如果TM还是执意要提交全局事务,那么再遍历提交分支事务的时候,这个失败的分支事务就不需要提交。
3.4 GlobalCommit - 全局提交
当我们分支事务执行完成之后,就轮到我们的TM-事务管理器来决定是提交还是回滚,如果是提交,那么就会走到下面的逻辑:
step1:首先找到我们的globalSession。如果他为Null证明已经被commit过了,那么直接幂等操作,返回成功。
step2:关闭我们的GloabSession防止再次有新的branch进来。
step3:如果status是等于Begin,那么久证明还没有提交过,改变其状态为Committing也就是正在提交。
step4:判断是否是可以异步提交,目前只有AT模式可以异步提交,因为是通过Undolog的方式去做的。MT和TCC都需要走同步提交的代码。
step5:如果是异步提交,直接将其放进我们ASYNC_COMMITTING_SESSION_MANAGER,让其再后台线程异步去做我们的step6,如果是同步的那么直接执行我们的step6。
step6:遍历我们的BranchSession进行提交,如果某个分支事务失败,根据不同的条件来判断是否进行重试,异步不需要重试,因为其本身都在manager中,只要没有成功就不会被删除会一直重试,如果是同步提交的会放进异步重试队列进行重试。
3.5 GlobalRollback - 全局回滚
如果我们的TM决定全局回滚,那么会走到下面的逻辑:
这个逻辑和提交流程基本一致,可以看作是他的反向,这里就不展开讲了。
4.总结
最后在总结一下开始我们提出了分布式事务的关键4点,Seata到底是怎么解决的:
-
正确的协调:通过后台定时任务各种正确的重试,并且未来会推出监控平台有可能可以手动回滚。
-
高可用: 通过HA-Cluster保证高可用。
-
高性能:文件顺序写,RPC通过netty实现,Seata未来可以水平扩展,提高处理性能。
-
高扩展性:提供给用户可以自由实现的地方,比如配置,服务发现和注册,全局锁等等。
最后希望大家能从这篇文章能了解Seata-Server的核心设计原理,当然你也可以想象如果你自己去实现一个分布式事务的Server应该怎样去设计?
seata github地址:https://github.com/seata/seata。
- 点赞 1
- 收藏
- 分享
![](http://img.e-com-net.com/image/info8/d7974a5d6c664a37aee121b5539c61f8.jpg)
深度剖析一站式分布式事务方案Seata-Client
阅读数 70
1.背景在之前的文章中已经介绍过Seata的总体介绍,如何使用以及Seata-Server的原理分析,有兴趣的可以阅读下面的文章:深度剖析一站式分布式事务方案Seata-Server解密分布式事务框架...博文来自: weixin_33950035的博客
深度剖析一站式分布式事务方案 Seata-Server
阅读数 12
本文作者李钊,公众号「咖啡拿铁」作者,分布式事务 Seata 社区 Contributor。1.关于Seata在前不久,我写了一篇关于分布式事务中间件 Fescar 的解析,没过几天 Fescar 团...博文来自: weixin_34392435的博客
深度剖析一站式分布式事务方案Seata(Fescar)-Server
阅读数 92
1.关于Seata再前不久,我写了一篇关于分布式事务中间件Fescar的解析,没过几天Fescar团队对其进行了品牌升级,取名为Seata(Simpe Extensible Autonomous Tr...博文来自: weixin_33811961的博客
【Spring Cloud Alibaba】【Hoxton】Seata从入门到实战
阅读数 995
1 简介官网地址:https://seata.io/zh-cn/1.1 SeataSeata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 A...博文来自: qq_34125999的博客
![](http://img.e-com-net.com/image/info8/d7974a5d6c664a37aee121b5539c61f8.jpg)
【JSON解析】浅谈JSONObject的使用
阅读数 1万+
简介在程序开发过程中,在参数传递,函数返回值等方面,越来越多的使用JSON。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,同时也易于机器解析和生成、易于理...博文来自: 一枕江风
《MySQL 性能优化》之理解 MySQL 体系结构
阅读数 9237
本文介绍 MySQL 的体系结构,包括物理结构、逻辑结构以及插件式存储引擎。博文来自: Tony.Dong的专栏
程序员请照顾好自己,周末病魔差点一套带走我。
阅读数 3万+
程序员在一个周末的时间,得了重病,差点当场去世,还好及时挽救回来了。...博文来自: 敖丙
卸载 x 雷某度!GitHub 标星 1.5w+,从此我只用这款全能高速下载工具!
阅读数 12万+
作者 | Rocky0429来源 | Python空间大家好,我是 Rocky0429,一个喜欢在网上收集各种资源的蒟蒻…网上资源眼花缭乱,下载的方式也同样千奇百怪,比如 BT 下载,磁力链接,网...博文来自: Rocky0429
只因接了一个电话,程序员被骗 30 万!
阅读数 1万+
今天想给大家说一个刚刚发生在我身边的一起真实的诈骗经历,我的朋友因此被骗走30万。注:为了保护当事人隐私,部分情节进行了修改。1平安夜突来的电话开始以为就像普通的诈骗一样,想办法让你把钱......博文来自: 纯洁的微笑
![](http://img.e-com-net.com/image/info8/d7974a5d6c664a37aee121b5539c61f8.jpg)
我一个37岁的程序员朋友
阅读数 2万+
周末了,人一旦没有点事情干,心里就瞎想,而且跟几个老男人坐在一起,更容易瞎想,我自己现在也是 30 岁了,也是无时无刻在担心自己的职业生涯,担心丢掉工作没有收入,担心身体机能下降,担心突......博文来自: 嵌入式Linux
python自动下载图片
阅读数 7万+
近日闲来无事,总有一种无形的力量萦绕在朕身边,让朕精神涣散,昏昏欲睡。可是,像朕这么有职业操守的社畜怎么能在上班期间睡瞌睡呢,我不禁陷入了沉思。。。。突然旁边的IOS同事问:‘嘿,兄弟,我发现一个网站...博文来自: vio小黑
一名大专同学的四个问题
阅读数 4万+
【前言】 收到一封来信,赶上各种事情拖了几日,利用今天要放下工作的时机,做个回复。 2020年到了,就以这一封信,作为开年标志吧。【正文】 您好,我是一名现在有很多困惑的大二学生。有一些问题想要...博文来自: 迂者-贺利坚的专栏
复习一周,京东+百度一面,不小心都拿了Offer
阅读数 12万+
京东和百度一面都问了啥,面试官百般刁难,可惜我全会。博文来自: 敖丙
Java 14 都快来了,为什么还有这么多人固守Java 8?
阅读数 3万+
从Java 9开始,Java版本的发布就让人眼花缭乱了。每隔6个月,都会冒出一个新版本出来,Java 10 , Java 11, Java 12, Java 13, 到2020年3月份,......博文来自: 码农翻身
达摩院十大科技趋势发布:2020 非同小可!
阅读数 3万+
【CSDN编者按】1月2日,阿里巴巴发布《达摩院2020十大科技趋势》,十大科技趋势分别是:人工智能从感知智能向认知智能演进;计算存储一体化突破AI算力瓶颈;工业互联网的超融合;机器间大规模协作成为可...博文来自: CSDN资讯
轻松搭建基于 SpringBoot + Vue 的 Web 商城应用
阅读数 4万+
首先介绍下在本文出现的几个比较重要的概念:函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算...博文来自: 阿里云云栖号
Python+OpenCV实时图像处理
阅读数 5万+
目录1、导入库文件2、设计GUI3、调用摄像头4、实时图像处理4.1、阈值二值化4.2、边缘检测4.3、轮廓检测4.4、高斯滤波4.5、色彩转换4.6、调节对比度5、退出系统初学OpenCV图像处理的...博文来自: 不脱发的程序猿
2020年一线城市程序员工资大调查
阅读数 5万+
人才需求一线城市共发布岗位38115个,招聘120827人。其中beijing 22805guangzhou 25081shanghai 39614shenzhen 3...博文来自: juwikuang的专栏
为什么猝死的都是程序员,基本上不见产品经理猝死呢?
阅读数 5万+
相信大家时不时听到程序员猝死的消息,但是基本上听不到产品经理猝死的消息,这是为什么呢?我们先百度搜一下:程序员猝死,出现将近700多万条搜索结果:搜索一下:产品经理猝死,只有400万条的搜索结果,从搜...博文来自: 曹银飞的专栏
害怕面试被问HashMap?这一篇就搞定了!
阅读数 3万+
声明:本文以jdk1.8为主!搞定HashMap作为一个Java从业者,面试的时候肯定会被问到过HashMap,因为对于HashMap来说,可以说是Java集合中的精髓了,如果你觉得自己对它掌握的还不...博文来自: 编码之外的技术博客
毕业5年,我问遍了身边的大佬,总结了他们的学习方法
阅读数 9万+
我问了身边10个大佬,总结了他们的学习方法,原来成功都是有迹可循的。博文来自: 敖丙
推荐10个堪称神器的学习网站
阅读数 21万+
每天都会收到很多读者的私信,问我:“二哥,有什么推荐的学习网站吗?最近很浮躁,手头的一些网站都看烦了,想看看二哥这里有什么新鲜货。”今天一早做了个恶梦,梦到被老板辞退了。虽然说在我们公司,只有我辞退老...博文来自: 沉默王二
这些软件太强了,Windows必装!尤其程序员!
阅读数 21万+
Windows可谓是大多数人的生产力工具,集娱乐办公于一体,虽然在程序员这个群体中都说苹果是信仰,但是大部分不都是从Windows过来的,而且现在依然有很多的程序员用Windows。所以,今天我就把我...博文来自: 编码之外的技术博客
阿里面试,面试官没想到一个ArrayList,我都能跟他扯半小时
阅读数 4万+
我是真的没想到,面试官会这样问我ArrayList。博文来自: 敖丙
曾经优秀的人,怎么就突然不优秀了。
阅读数 4万+
职场上有很多辛酸事,很多合伙人出局的故事,很多技术骨干被裁员的故事。说来模板都类似,曾经是名校毕业,曾经是优秀员工,曾经被领导表扬,曾经业绩突出,然而突然有一天,因为种种原因,被裁员了,......博文来自: caoz的梦呓
大学四年因为知道了这32个网站,我成了别人眼中的大神!
阅读数 28万+
依稀记得,毕业那天,我们导员发给我毕业证的时候对我说“你可是咱们系的风云人物啊”,哎呀,别提当时多开心啦????,嗯,我们导员是所有导员中最帅的一个,真的????不过,导员说的是实话,很多人都叫我大神...博文来自: 编码之外的技术博客
良心推荐,我珍藏的一些Chrome插件
阅读数 5万+
上次搬家的时候,发了一个朋友圈,附带的照片中不小心暴露了自己的 Chrome 浏览器插件之多,于是就有小伙伴评论说分享一下我觉得还不错的浏览器插件。我下面就把我日常工作和学习中经常用到的一些 Chr...博文来自: 不忘初心
看完这篇HTTP,跟面试官扯皮就没问题了
阅读数 6万+
我是一名程序员,我的主要编程语言是 Java,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟、醍醐灌顶的感觉。最初在有网...博文来自: c旋儿的博客
史上最全的IDEA快捷键总结
阅读数 8万+
现在Idea成了主流开发工具,这篇博客对其使用的快捷键做了总结,希望对大家的开发工作有所帮助。...博文来自: 扬帆向海的博客
阿里程序员写了一个新手都写不出的低级bug,被骂惨了。
阅读数 11万+
这种新手都不会范的错,居然被一个工作好几年的小伙子写出来,差点被当场开除了。...博文来自: 敖丙
谁是华为扫地僧?
阅读数 2万+
是的,华为也有扫地僧!2020年2月11-12日,“养在深闺人不知”的华为2012实验室扫地僧们,将在华为开发者大会2020(Cloud)上,和大家见面。到时,你可以和扫地僧们,吃一个洋......博文来自: CSDN资讯
Idea 中最常用的10款插件(提高开发效率),一定要学会使用!
阅读数 3万+
学习使用一些插件,可以提高开发效率。对于我们开发人员很有帮助。这篇博客介绍了开发中使用的插件。...博文来自: 扬帆向海的博客
AI 没让人类失业,搞 AI 的人先失业了
阅读数 6万+
最近和几个 AI 领域的大佬闲聊根据他们讲的消息和段子改编出下面这个故事如有雷同都是巧合1. 老王创业失败,被限制高消费“这里写我跑路的消息实在太夸张了。”王葱葱哼笑一下,把消息分享给群里。阿杰也看了...博文来自: CSDN 官方博客
2020年,冯唐49岁:我给20、30岁IT职场年轻人的建议
阅读数 8万+
点击“技术领导力”关注∆每天早上8:30推送作者|Mr.K 编辑| Emma来源|技术领导力(ID:jishulingdaoli)前天的推文《冯唐:职场人35岁以后,方法论比经验重要》,收到了不少读者...博文来自: 技术领导力
作为一名大学生,如何在B站上快乐的学习?
阅读数 5万+
B站是个宝,谁用谁知道????作为一名大学生,你必须掌握的一项能力就是自学能力,很多看起来很牛X的人,你可以了解下,人家私底下一定是花大量的时间自学的,你可能会说,我也想学习啊,可是嘞,该学习啥嘞,不...博文来自: 编码之外的技术博客
木兰编程语言,当事人最新回复来了
阅读数 9846
同行12年,不知Python是木兰,当事人回应来了博文来自: dotNet全栈开发
那些年,我们信了课本里的那些鬼话
阅读数 1万+
教材永远都是有错误的,从小学到大学,我们不断的学习了很多错误知识。斑羚飞渡在我们学习的很多小学课文里,有很多是错误文章,或者说是假课文。像《斑羚飞渡》:随着镰刀头羊的那声吼叫,整个斑羚群迅速分成两拨,...博文来自: hebtu666
一个程序在计算机中是如何运行的?超级干货!!!
阅读数 7万+
强烈声明:本文很干,请自备茶水!????开门见山,咱不说废话!你有没有想过,你写的程序,是如何在计算机中运行的吗?比如我们搞Java的,肯定写过这段代码public class HelloWorld ...博文来自: 编码之外的技术博客
在中国程序员是青春饭吗?
阅读数 2万+
今年,我也32了 ,为了不给大家误导,咨询了猎头、圈内好友,以及年过35岁的几位老程序员……舍了老脸去揭人家伤疤……希望能给大家以帮助,记得帮我点赞哦。目录:你以为的人生 一次又一次的伤害 猎头界的真...博文来自: 启舰
原创
610
粉丝
2418
获赞
713
评论
182
访问
138万+
等级:
周排名:
722
积分:
1万+
总排名:
803
![](http://img.e-com-net.com/image/info8/d7974a5d6c664a37aee121b5539c61f8.jpg)
分类专栏
【架构】90篇
【分布式】24篇
【构建高可用架构】339篇
【大数据】156篇
【前端 react】51篇
【更多】17篇
【项目相关】39篇
【python】56篇
【springboot】39篇
【spring cloud】28篇
【dubbo】10篇
【转载】55篇
【版本控制】17篇
【监控】20篇
【kafka】21篇
【消息中间件】20篇
【linux】15篇
【ElatisSearch】130篇
【RPC】16篇
【GO】20篇
【nginx】36篇
zookeeper4篇
maven3篇
网络1篇
mybatis4篇
jpa4篇
工具5篇
环境搭建3篇
算法2篇
mongodb2篇
mysql8篇
strom1篇
hive1篇
spark6篇
auth1篇
java虚拟机4篇
redis10篇
jenkins5篇
ELK4篇
docker7篇
scala31篇
多语言39篇
分享
kylin5篇
sqoop1篇
hadoop3篇
tools1篇
c++1篇
代码质量2篇
android12篇
vue4篇
java工具类7篇
sm架构
展开
最新文章
- DevOps架构下如何进行微服务性能测试?
- Skywalking收集与发送链路数据部分源码解析
- k8s之安装环境知识点四 -存储卷
- k8s之安装环境知识点三-资源
- k8s之安装环境知识点二-控制器
归档
- 2020年3月1篇
- 2020年1月1篇
- 2019年12月9篇
- 2019年11月4篇
- 2019年9月1篇
- 2019年8月6篇
- 2019年7月6篇
- 2019年6月1篇
- 2019年5月4篇
- 2019年4月15篇
- 2019年1月1篇
- 2018年12月5篇
- 2018年11月5篇
- 2018年10月9篇
- 2018年9月2篇
- 2018年8月9篇
- 2018年7月70篇
- 2018年6月64篇
- 2018年5月87篇
- 2018年4月111篇
- 2018年3月156篇
- 2018年2月44篇
- 2018年1月50篇
- 2017年12月25篇
- 2017年11月39篇
- 2017年9月1篇
- 2017年6月3篇
- 2017年3月11篇
展开
热门文章
- ZUUL-API网关
阅读数 52097
- redis缓存与数据库一致性问题解决
阅读数 43424
- Spring Boot 集成Dubbo
阅读数 28315
- 分布式 实战(干货)
阅读数 23561
- spring boot 整合 spring security 登录认证
阅读数 20217
最新评论
- 分布式事务四_基于可靠消息的最终一...
u011923482:RocketMQ可以支持,事务消息
- springboot思维导图
qq_40445661:[reply]weixin_44955939[/reply]你好 楼主思维导图有分享吗
- redis缓存与数据库一致性问题解决
qq_40213580:[reply]qq_31426247[/reply]增加缓存失败重试机制
- redis缓存与数据库一致性问题解决
baronZhuZhu:写了半天,也没见写清除怎么解决的
- redis缓存与数据库一致性问题解决
h2604396739:[reply]chengguotao[/reply]先清缓存后写库,再次之前拿到一个读写库的互斥锁就能解决数据不一致了。至于击穿问题:也是互斥锁,拿不到读写库的锁就等待+重试。