为什么要使用分布式事务和分布式锁?
我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。
事务的ACID
原子性:多条指令作为一个集体,要么都执行,要么都不执行
一致性:比如 a=100 b=100 a、b之间交易 总和一定是200
隔离性:一个事务不受其他事务的影响
持久性:事务一旦提交,它对数据库的改变时永久性的
CAP原则
在分布式系统要满足CAP原则,一个提供数据服务的存储系统无法同时满足:数据一致性、数据可用性、分区耐受性。
C数据一致性:所有应用程序都能访问到相同的数据。
A数据可用性:任何时候,任何应用程序都可以读写访问。
P分区耐受性:系统可以跨网络分区线性伸缩。(通俗来说就是数据的规模可扩展)
在大型网站中通常都是牺牲C,选择AP。为了可能减小数据不一致带来的影响,都会采取各种手段保证数据最终一致。
- 数据强一致:各个副本的数据在物理存储中总是一致的。
- 数据用户一致:数据在物理存储的各个副本可能是不一致的,但是通过纠错和校验机制,会确定一个一致的且正确的数据返回给用户。
- 数据最终一致:物理存储的数据可能不一致,终端用户访问也可能不一致,但是一段时间内数据会达成一致。
分布式事务的解决方案
基于可靠消息的最终一致性方案
- 可独立部署、独立伸缩(扩展性)
- 兼容所有实现JMS标准的MQ中间件
- 能降低业务系统与消息系统间的耦合性
- 可实现数据可靠的前提下确保一致性
业务场景:那些不要求立即返回结果的业务,完成时间上的解耦如:对应支付系统会计异步记账业务、银行通知结果信息存储与驱动订单处理TCC事务补偿型方案(两阶段提交)
* 不与具体的服务框架耦合(在RPC框架中通用)
* 位于业务服务层,而非资源层
* 可以灵活选择业务资源的锁定粒度
* 适用于强隔离性、严格一致性要求的业务场景
* 适用于执行时间较短的业务
业务场景:一个业务逻辑涉及了多个业务组件如:订单处理、资金账户处理、积分账户处理最大努力通知型方案
业务场景:适用于跨平台业务
如:支付系统的商户通知业务
分布式锁
有的时候,我们需要保证一个方法在同 一时间内只能被同一个线程执行。在单机模式下,可以通过sychronized、锁等方式来实现,在分布式环境下,有以下的解决方案:
数据库锁
1.通过一个一张表的一条记录,来判断资源的占用情况
2.使用基于数据库的排它锁 (即select * from tb_User for update)
3.使用乐观锁的方式,即CAS操作(或version字段)
基于Redis的分布式锁
redis提供了可以用来实现分布式锁的方法,比如redis的setnx方法等。(即redis事务机制可以实现乐观锁CAS)
基于Zookeeper的分布式锁(这种方式最可靠)
基于zookeeper临时有序节点可以实现的分布式锁。大致思想即为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。