在聊分布式项目前,我们需要知道一个概念,分布式的意义在于从容应对高并发和单点故障,所以分布式项目一般会和微服务一起使用。简而言之,分布式就是解决单点故障,分散服务器压力;而微服务就是分散功能,将复杂的项目根据业务进行抽取,独立成一个单独的服务,不会由于单个服务的宕机,影响到其他功能。
分布式项目中需要考虑的问题
分布式事务
1.1 事务
1.1.1 事务的概念
事务可以看做是一组操作,要么都成功,要么都要失败。举个简单的例子,张三向王五转账1000元,那么需要保证张三的账户执行-1000,王五的账户+1000,两个操作都必须成功。
1.1.2 事务的特性
原子性 :原子是最小单位,事务的原子性决定了事务不可以被分隔。Mysql中,是通过innodb引擎的undolog日志保证原子性。undolog日志是记录旧数据的,当其中一个操作出现问题,会按照日志记录将数据进行回滚。
隔离性 :两个事务之间应该相互隔离,互不影响。
一致性 :事务执行后,需要满足一些我们预定的规则。例如账户余额不能小于0,在转账情况下总额不变等。
持久性 :事务执行后,可以将数据持久化同步到磁盘,永不丢失。Mysql中,是通过innodb的redolog日志实现,记录新数据,当操作进行完成都没有出现问题,那么会将日志中的数据同步到数据库,完成持久化。
1.1.3 事务的传播机制
1.1.4 mysql中脏读、不可重复读、幻读问题
脏读 :在读取数据是,读取到了其他事务未提交的数据。
不可重复读 : 在同一事务中以相同的条件进行读取数据,数据不一致的情况,针对于其他事务在做修改操作。
幻读 : 在同一事务中以相同的条件进行读取数据,数据不一致的情况,针对于其他事务在做新增或者删除操作。
1.1.5 mysql的事务隔离级
读未提交 : 会出现脏读、幻读、不可重复读问题
读已提交 : 会出现不可重复读、幻读问题
可重复读 : 可以解决以上三个问题,其中幻读是通过间隙锁完成
串行化 : 可以解决以上三个问题
1.2 分布式事务
1.2.1 分布式事务概念
一个请求,涉及到多个数据源或者跨进程的操作,所涉及到的事务就是分布式事务。
1.2.2 分布式微服务项目中,如何减少分布式事务
分布式事务其实一个很复杂很棘手的问题,所以在设计微服务框架时,尽量将相同业务划分到同一个服务中,避免服务之间的调用,这样既可以节约内存,也可以减少处理分布式事务。
1.3 cap理论和Base理论
cap理论 :
c : 一致性。关注数据的一致性,站在用户的角度,肯定是希望强一致,但是在实际开发中,我们会根据业务的性质,具体考虑是强一致还是最终一致。
a : 可用性。在合理的时间内,将数据返回给用户。这里合理的时间,是根据项目实际情况而定,在多少时间内处理完成可以接受的意思。
p :分区容错性。在分布式微服务项目中,必然存在服务调用,就会涉及到网络问题,那么网络调用延迟等问题,就是这里的分区容错。
很多小伙伴认为,在分布式微服务中,cap理论只能三选二,其实并不然,基于分布式微服务的情况下,分区容错必须得到保证,否则就不是一个分布式项目了,所有只能是ca二选一。
1.4 分布式事务处理方案
1.4.1 2pc两段式提交
2pc两段式提交分为准备阶段和提交阶段 准备阶段 : 事务参与者会向TM(事务管理器)之间会进行通讯,各个事务都准备完成,才会进入提交阶段。
提交阶段 : 事务管理器会通知事务参与者,提交自己的事务,如果在准备阶段有事务参与者返回false,则发出回滚的指令。
问题:
在第一阶段,如果参与者迟迟没有回复状态,会造成阻塞。
在第二阶段,如果出现宕机情况,无法判断那些事务参与者收到了消息。
1.4.2 tcc
选择ap实现。保证弱一致性。
提供三个接口,tyr(预留资源),confirm(扣减资源),cancle(回滚)。
问题 : 实现复杂,需要和业务代码冗余,不方便后期维护。
1.4.3 最大努力通知
一般情况下,只有边缘非核心业务会选择,例如:积分成功这些通知类,尽最大努力通知n次,还是无法同步,就放弃。
1.4.4 可靠消息最终一致性
方案一 :本地消息表。将事务做持久化,定时任务扫描信息表,服务队列监听消息即可。
方案二 :rocketmq 。
1.生产者发送一个half消息到一个特定 队列 查看队列是否正常 并返回结果给生产者
2.此时生产者接收到half消息成功发送的结果 提交本地事务
3.将本地事务提交结果发送给消费者监听的队列,如果是成功的给消费者消费 如果是失败的 回滚
4.发送消息的时候如果没有返回结果 此时需要生产者提供一个可以查询本地事务提交结果的接口 供队列查询
1.4.5 seata方案
1.向tc事务协调器注册一个全局事务 生一个全局事务的XID
2.开始执行每个分支事务,但是此时携带了全局事务的xid,每一个分支事务都需要根据这个XID向TC注册分支事务
3.执行每个分支的业务代码,并且写入undolog,然后提交本地事务,并将本地事务的提交状态告知TC
4.全局事务管理器TM,向TC发送全局事务提交的请求,此时从TC获取所有分支事务的状态
5.如果所有分支事务状态提交都是成功的,删除分支事务的undolog即可
6.如果有一个分支事务失败,每个事务分支执行undolog进行回滚
分布式锁
2.1 lock锁和Synchronized关键字
1.synchronized是java中的关键字,我们无需去关注锁的释放,不会出现死锁(jdk会自己处理),而Lock是一个接口,是我们自己创建的,可能会出现死锁,需要在finally中释放锁;
2.Lock可以让等待的线程中断处理,Synchronized不行,我们无法控制;
3.synchronized是非公平锁,Lock可以手动设置(默认是非公平);
4.Lock的实现类ReentrantReadWriteLock,可以获取读锁和写锁;
5.Lock只能在用在代码块,Synchronized可以锁代码块、对象实例和类;
6.Lock可以分组唤醒线程,Synchronized要么唤醒一个线程,要么全部唤醒。
2.2 分布式锁的实现
关于后面的知识,下次再聊。。现在有点困了。