应用系统中的关键服务绝大部分都会是对数据库的依赖。前端
当多个进程同时操做同一个数据,会产生资源争抢,数据一致性的问题。数据库
若是只有一个数据库服务器,数据一致性问题也就不存在了。后端
但是,随着系统访问量、数据量的不断增加,数据库出现多个服务器,又出现缓存服务,又要拆分数据库,还要分拆到不一样的子应用等等。缓存
这样一来,数据一致性问题就会变得愈来愈突出。服务器
咱们来看这样一个数据流程。并发
用户提交一个订单(2个不一样商家各一件商品)——数据源头分布式
应用服务器验证用户信息、订单信息、库存信息等等,而后将这个订单发送到订单消息队列——消息队列性能
订单处理服务器从消息队列中拿到新订单,接下来的处理,可能作的数据操做有:网站
生成一个订单/也可能会分拆为两个订单3d
更新两个商品库存数量
更新商家的销售数据
生成订单对应的支付信息
生成用户订单成功的状态信息
上面的数据处理中,涉及到的数据有:订单数据、商品数据、商家数据、支付数据、用户数据。
涉及到的应用和服务有:前端应用系统,消息队列,后端应用系统,数据库,缓存,甚至订单、商品、商家、支付、用户可能都是独立的子应用。
可能大部分系统不会像上面这么庞大。
若是先后端都是一块儿的,也就没有消息队列。
若是也没有这些子系统,数据库是集中的,那可能数据一致性问题会稍微小些。
这时候,只须要注意数据库更新的一致性就行了,比较容易想到的应对方法,就是用数据库事务来保证。
若是这些数据不仅是一份数据库,还有缓存中一份,又要考虑缓存数据的更新,因此问题仍是复杂了。
程序中处理,数据库更新后,就要立刻更新缓存数据
若是缓存更新失败或者程序出现异常,要有异常处理方法
异常处理方法能够是程序中实时的纠正或者重试
异常处理方法也能够是针对数据库的更新,二次检查缓存数据的更新
这里还只是一个数据库和一个缓存的状况,已经要作出这么多事情。
程序开发更加复杂,不能有些许的遗漏
数据验证和重试带来的性能降低
数据库事务带来的数据库瓶颈明显
二次检查再次增长复杂度和额外开销
原本一个订单处理,若是不考虑数据一致性问题,数据库写入/更新510次,缓存写入/更新510次,整个过程应该在10ms内完成。
可是加上数据库事务以后,会把这些操做中涉及到的几个表都加锁,意味着数据的读、写都串行化了,整个应用系统的并发能力急剧降低。
固然,由于这里引入缓存,对数据库的依赖会减小不少,并且还有从库能够提供读的服务,应用系统的访问并发能力不至于降低太多。
但这些代价在交易处理中是难以免的,为了解决数据一致性问题,牺牲的是订单处理的并发能力。
对于大部分商城、网站,订单并发量也不高,这类问题不太常发生,因此也就这么过去了。
可是在一些促销活动的时候,确定仍是会遇到下单等待过久的问题。
为了具有更大并发的订单处理能力,单数据库、缓存确定是行不通了。
那么要在这么多的子应用、大量的数据库、缓存服务中保持数据一致性又要怎么作呢?
每一个子应用都要支持分布式事务,共同保证数据库所有成功更新
每一个子应用各自要保证本身的数据更新一致性(异常处理、重试、二次检查等方法同上)
上面看上去只有两条,可是要作的事情和困难会比上面要多十倍,难百倍。
看到这里,是否是对于数据一致性的问题都有点绝望了。
正因如此,大部分的分布式系统,大部分应用,是没有作到数据一致性,哪怕是弱一致性。
好比:论坛里面发帖,要更新10份左右的数据,出现脏数据是常有的,这就是没有作到数据一致性。
好比:商城里面库存超卖,订单状态不一致等,也是由于没有作到数据一致性。
之因此会这样,由于投入产出严重不成比例,是很无奈的选择。
数据不一致的状况毕竟比例极低,可是投入的代价却极大。
数据不一致引起的后果,能够忍受和容忍,哪怕是发现后再修正。
下面有几个方法能够考虑:
一个每秒钟上百万请求的应用系统能不能分拆为1000个每秒钟1000请求的独立集群呢?
一个上百万的商家、商品、订单库,能不能分拆为1000个只有1000个商家、商品、订单的子库呢?
上面的订单、库存、商家、支付、用户几个数据,核心数据只有订单,其余的几个数据彻底能够从订单数据推导出来,减小订单处理中的一致性要求。
减小业务耦合,集中资源重点投入。