作为一名程序员,你是不是经常在很多场景,例如看博客、聊天吹水等等时候听到这样一个词"系统数据一致性",是不是有时候感觉到了迷糊,不知道这个"系统数据一致性"到底是在说什么?其实,你可能只是不明白这个词,但是你肯定在实际工作中发现、解决过这样的问题。
单体架构下系统数据一致性问题
在传统的系统应用中,一般都是使用单体架构来构建系统的。即所有的功能模块都放在一起实现,打成一个WAR包部署在Tomcat中,数据一般存放在关系型数据库中,如MySQL数据库。
前面我说过即使这种单体架构的系统也是数据一致性的问题的,举一个电商下单的例子,用户提交完订单,系统,系统在订单表order表中写入订单金额、用户等相关数据,在订单明细order_item表中写入商品价格、购买的数量等数据,最后更新商品的库存sku信息。用户下单成功之后,系统操作了order、order_item、sku这三个数据表,对于这三个表的操作无论成功与失败,都应该是原子的,操作成功则都要成功,失败则都要一起失败。不然就会出现脏数据,数据一致性被破坏。
1、 如果操作order和order_item表成功,操作sku表失败,则会导致本应该扣减的库存没有扣减,则商品有可能出现超卖。
2、如果操作order和order_item表失败,操作sku表成功,则会导致本不应该扣减的库存扣减了,则商品有可能出现少卖。
3、如果操作order和sku表成功,order_item操作失败,则这个订单数据丢失,订单后续的操作肯定也是操作不了了。
上面只是简单的举了三种可能出现的情况,也可能会有其他的情况发生。那我们怎么避免这些情况的发生呢?其实这种问题稍微有的开发经验的同学都会想到解决方案,那就是使用数据库的事务,事务的原子性保证上述的步骤成功则一起成功,失败则一起失败。
BEGIN;
INSERT INTO order;
INSERT INTO order_item;
UPDATE sku;
COMMIT; # ROLLBACK
在单体架构的系统下解决内部模块的数据一致性的问题,用数据库的ACID特性就能保证。
单体架构的优点就是相对分布式来说开发简单,功能可以集中管理,模块之间通信没有损耗。但随着业务越来越复杂、需求越来越庞大,人们对系统响应时间、吞吐量和出现故障的时候的系统可用性的要求也越来越高!传统的单体架构系统在这种情况下暴露的缺点也越来越多,人们开始寻求转变。既然部署在一个服务器上的单体架构系统搞不定,那就多部署几台,即用多台单机节点组成集群,再用负载均衡向外提供服务。
但是这样做还是解决不了单体架构存在的一些问题:
- 只能使用同种语言开发,不能针对不同业务场景利用不同语言的优势开发对应的模块。
- 系统模块耦合性太强,系统中某一个模块出现问题,例如高并发、大数据场景或者出现bug,整个系统都会受到牵连。
- 某个模块发布,整个系统都要停机发布,系统所有模块都不能对外提供服务,这样无法快速响应市场需求。
- 集群负担大,如果想要集群,只能对整个系统进行集群,即使只有一个模块有压力。
集群(Cluster): 系统单机部署对外服务能力出现瓶颈,则将系统进行多机部署