Skip to content

Commit e4237b5

Browse files
committed
分布式
1 parent 0b104ab commit e4237b5

File tree

5 files changed

+96
-11
lines changed

5 files changed

+96
-11
lines changed

MD/分布式-一致性hash.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
# 一致 Hash 算法
2-
来源:https://github.com/crossoverJie/JCSprout/blob/master/MD/Consistent-Hash.md
3-
42
分布式缓存中,如何将数据均匀的分散到各个节点中,并且尽量的在加减节点时能使受影响的数据最少。
53

64
## Hash 取模
@@ -60,4 +58,6 @@
6058

6159
这样只需要在原有的基础上多一步由虚拟节点映射到实际节点的步骤即可让少量节点也能满足均匀性。
6260

61+
https://github.com/crossoverJie/JCSprout/blob/master/MD/Consistent-Hash.md
62+
6363
欢迎光临[91Code](http://www.91code.info/?utm_source=github&utm_medium=github),发现更多技术资源~

MD/分布式-事务.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
### 两阶段提交方案/XA方案
2+
所谓的 XA 方案,即:两阶段提交,有一个**事务管理器**的概念,负责协调多个数据库(资源管理器)的事务,事务管理器先问问各个数据库你准备好了吗?如果每个数据库都回复 ok,那么就正式提交事务,在各个数据库上执行操作;如果任何其中一个数据库回答不 ok,那么就回滚事务。
3+
4+
这种分布式事务方案,比较适合单块应用里,跨多个库的分布式事务,而且因为严重依赖于数据库层面来搞定复杂的事务,效率很低,绝对不适合高并发的场景。如果要玩儿,那么基于 `Spring + JTA` 就可以搞定,自己随便搜个 demo 看看就知道了。
5+
6+
这个方案,我们很少用,一般来说**某个系统内部如果出现跨多个库**的这么一个操作,是**不合规**的。我可以给大家介绍一下, 现在微服务,一个大的系统分成几十个甚至几百个服务。一般来说,我们的规定和规范,是要求**每个服务只能操作自己对应的一个数据库**
7+
8+
如果你要操作别的服务对应的库,不允许直连别的服务的库,违反微服务架构的规范,你随便交叉胡乱访问,几百个服务的话,全体乱套,这样的一套服务是没法管理的,没法治理的,可能会出现数据被别人改错,自己的库被别人写挂等情况。
9+
10+
如果你要操作别人的服务的库,你必须是通过**调用别的服务的接口**来实现,绝对不允许交叉访问别人的数据库。
11+
12+
![distributed-transacion-XA](/images/distributed-transaction-XA.png)
13+
14+
### TCC 方案
15+
TCC 的全称是:Try、Confirm、Cancel。
16+
17+
- Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行**锁定或者预留**
18+
- Confirm 阶段:这个阶段说的是在各个服务中**执行实际的操作**
19+
- Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要**进行补偿**,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚)
20+
21+
这种方案说实话几乎很少人使用,我们用的也比较少,但是也有使用的场景。因为这个**事务回滚**实际上是**严重依赖于你自己写代码来回滚和补偿**了,会造成补偿代码巨大,非常之恶心。
22+
23+
比如说我们,一般来说跟****相关的,跟钱打交道的,**支付****交易**相关的场景,我们会用 TCC,严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性,保证在资金上不会出现问题。
24+
25+
而且最好是你的各个业务执行的时间都比较短。
26+
27+
但是说实话,一般尽量别这么搞,自己手写回滚逻辑,或者是补偿逻辑,实在太恶心了,那个业务代码很难维护。
28+
29+
![distributed-transacion-TCC](/images/distributed-transaction-TCC.png)
30+
31+
### 本地消息表
32+
本地消息表其实是国外的 ebay 搞出来的这么一套思想。
33+
34+
这个大概意思是这样的:
35+
36+
1. A 系统在自己本地一个事务里操作同时,插入一条数据到消息表;
37+
2. 接着 A 系统将这个消息发送到 MQ 中去;
38+
3. B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样**保证不会重复处理消息**
39+
4. B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态;
40+
5. 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理;
41+
6. 这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。
42+
43+
这个方案说实话最大的问题就在于**严重依赖于数据库的消息表来管理事务**啥的,会导致如果是高并发场景咋办呢?咋扩展呢?所以一般确实很少用。
44+
45+
![distributed-transaction-local-message-table](/images/distributed-transaction-local-message-table.png)
46+
47+
### 可靠消息最终一致性方案
48+
这个的意思,就是干脆不要用本地的消息表了,直接基于 MQ 来实现事务。比如阿里的 RocketMQ 就支持消息事务。
49+
50+
大概的意思就是:
51+
52+
1. A 系统先发送一个 prepared 消息到 mq,如果这个 prepared 消息发送失败那么就直接取消操作别执行了;
53+
2. 如果这个消息发送成功过了,那么接着执行本地事务,如果成功就告诉 mq 发送确认消息,如果失败就告诉 mq 回滚消息;
54+
3. 如果发送了确认消息,那么此时 B 系统会接收到确认消息,然后执行本地的事务;
55+
4. mq 会自动**定时轮询**所有 prepared 消息回调你的接口,问你,这个消息是不是本地事务处理失败了,所有没发送确认的消息,是继续重试还是回滚?一般来说这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,而确认消息却发送失败了。
56+
5. 这个方案里,要是系统 B 的事务失败了咋办?重试咯,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚,比如 B 系统本地回滚后,想办法通知系统 A 也回滚;或者是发送报警由人工来手工回滚和补偿。
57+
6. 这个还是比较合适的,目前国内互联网公司大都是这么玩儿的,要不你举用 RocketMQ 支持的,要不你就自己基于类似 ActiveMQ?RabbitMQ?自己封装一套类似的逻辑出来,总之思路就是这样子的。
58+
59+
![distributed-transaction-reliable-message](/images/distributed-transaction-reliable-message.png)
60+
61+
### 最大努力通知方案
62+
这个方案的大致意思就是:
63+
64+
1. 系统 A 本地事务执行完之后,发送个消息到 MQ;
65+
2. 这里会有个专门消费 MQ 的**最大努力通知服务**,这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以,接着调用系统 B 的接口;
66+
3. 要是系统 B 执行成功就 ok 了;要是系统 B 执行失败了,那么最大努力通知服务就定时尝试重新调用系统 B,反复 N 次,最后还是不行就放弃。
67+
68+
### 你们公司是如何处理分布式事务的?
69+
如果你真的被问到,可以这么说,我们某某特别严格的场景,用的是 TCC 来保证强一致性;然后其他的一些场景基于阿里的 RocketMQ 来实现分布式事务。
70+
71+
你找一个严格资金要求绝对不能错的场景,你可以说你是用的 TCC 方案;如果是一般的分布式事务场景,订单插入之后要调用库存服务更新库存,库存数据没有资金那么的敏感,可以用可靠消息最终一致性方案。
72+
73+
友情提示一下,RocketMQ 3.2.6 之前的版本,是可以按照上面的思路来的,但是之后接口做了一些改变,我这里不再赘述了。
74+
75+
当然如果你愿意,你可以参考可靠消息最终一致性方案来自己实现一套分布式事务,比如基于 RocketMQ 来玩儿。
76+
77+
https://github.com/doocs/advanced-java/blob/master/docs/distributed-system/distributed-transaction.md

MD/分布式-消息队列.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
来源: https://github.com/doocs/advanced-java#%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97 https://dbaplus.cn/news-73-1123-1.html
2-
31
## 优点
42
1. 减少请求响应时间。比如注册功能需要调用第三方接口来发短信,如果等待第三方响应可能会需要很多时间
53
2. 服务之间解耦。主服务只关心核心的流程,其他不重要的、耗费时间流程是否如何处理完成不需要知道,只通知即可
@@ -60,4 +58,6 @@ Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker
6058

6159
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/kafka集群.png)
6260

61+
https://github.com/doocs/advanced-java#%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97 https://dbaplus.cn/news-73-1123-1.html
62+
6363
欢迎光临[91Code](http://www.91code.info/?utm_source=github&utm_medium=github),发现更多技术资源~

MD/分布式-锁.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
## 为什么用
2-
在分布式环境中,需要一种跨JVM的互斥机制来控制共享资源的访问。例如,为避免用户操作重复导致交易执行多次,使用分布式锁可以将第一次以外的请求在所有服务节点上立马取消掉。如果使用事务在数据库层面进行限制也能实现的但会增大数据库的压力。
2+
在分布式环境中,需要一种跨JVM的互斥机制来控制共享资源的访问。
3+
4+
例如,为避免用户操作重复导致交易执行多次,使用分布式锁可以将第一次以外的请求在所有服务节点上立马取消掉。如果使用事务在数据库层面进行限制也能实现的但会增大数据库的压力。
5+
6+
例如,在分布式任务系统中为避免统一任务重复执行,某个节点执行任务之后可以使用分布式锁避免其他节点在同一时刻得到任务
37

48
## 实现方式
5-
来源: https://blog.csdn.net/xlgen157387/article/details/79036337 https://www.hollischuang.com/archives/1716 https://www.jianshu.com/p/c2b4aa7a12f1
69
### 数据库
710
在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。
811

@@ -36,9 +39,10 @@ delete from method_lock where method_name ='methodName';
3639

3740
缺点:
3841

39-
1. 没有锁失效自动删除机制,因为有可能出现成功插入数据后,服务器宕机了,对应的数据没有被删除,当服务恢复后一直获取不到锁,所以,需要在表中新增一列,用于记录失效时间,并且需要有定时任务清除这些失效的数据
42+
1. 没有锁失效自动删除机制,因为有可能出现成功插入数据后,服务器宕机了,对应的数据没有被删除,当服务恢复后一直获取不到锁,所以,需要在表中新增一列,用于记录失效时间,并且需要有定时任务清除这些失效的数据
4043
2. 吞吐量很低
4144
3. 单点故障问题
45+
4. 轮询获取锁状态方式太过低效
4246

4347
### 基于Redis
4448
NX是Redis提供的一个原子操作,如果指定key存在,那么NX失败,如果不存在会进行set操作并返回成功。我们可以利用这个来实现一个分布式的锁,主要思路就是,set成功表示获取锁,set失败表示获取失败,失败后需要重试。再加上EX参数可以让该key在超时之后自动删除。
@@ -68,17 +72,21 @@ public void lock(String key, String request, int timeout) throws InterruptedExce
6872

6973
1. 单点故障问题
7074
2. 锁超时问题:如果A拿到锁之后设置了超时时长,但是业务还未执行完成且锁已经被释放,此时其他进程就会拿到锁从而执行相同的业务
75+
3. 轮询获取锁状态方式太过低效
7176

7277
### 基于ZooKeeper
73-
当客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁只需要判断有序节点中序号最小的一个。当释放锁的时候,将这个瞬时节点删除
78+
1. 当客户端对某个方法加锁时,在Zookeeper上的与该方法对应的指定节点的目录下,生成一个临时有序节点
79+
2. 判断该节点是否是当前目录下最小的节点,如果是则获取成功;如果不是,则获取失败,并获取上一个临时有序节点,对该节点进行监听,当节点删除时通知唯一的客户端
7480

7581
优点:
7682

7783
1. 解决锁超时问题。因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,同时可以对这个节点进行Watch,如果节点删除会通知其他节点抢占锁
84+
2. 能通过watch机制高效通知其他节点获取锁,避免惊群效应
85+
3. 有锁失效自动删除机制,保证不会阻塞所有流程
7886

7987
缺点:
8088

8189
1. 性能不如Redis
82-
2. 强依赖zk,如果原来系统不用zk那就很麻烦了
90+
2. 强依赖zk,如果原来系统不用zk那就需要维护一套zk
8391

8492
欢迎光临[91Code](http://www.91code.info/?utm_source=github&utm_medium=github),发现更多技术资源~

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
本项目是本人于2018年参加BATJ等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。
22

3-
PS:除开知识点,一定要准备好以下套路:
3+
除开知识点,一定要准备好以下套路:
44
1. **个人介绍**,需要准备1分钟和5分钟两个版本,包括学习经历、工作经历、项目经历、个人优势、一句话总结。一定要自己背得滚瓜烂熟,张口就来
55
2. **抽象概念回答方式**,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化、应用方面系统性地回答
66
3. **项目所占的比重是非常大的**,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳
@@ -25,7 +25,7 @@ PS:除开知识点,一定要准备好以下套路:
2525
### 分布式
2626
* [CAP理论](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-CAP理论.md)
2727
* [](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-锁.md)
28-
* [事务](https://mp.weixin.qq.com/s/gg4q_53eiHCI3OUWzN7eWg)
28+
* [事务](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-事务.md)
2929
* [消息队列](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-消息队列.md)
3030
* [ID生成方式](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-ID生成方式.md)
3131
* [一致性hash](https://github.com/xbox1994/2018-Java-Interview/blob/master/MD/分布式-一致性hash.md)

0 commit comments

Comments
 (0)