0%

“反范式”数据库设计之数据冗余架构设计与细节

一、解决什么问题?

(1)数据量大
(2)需要水平切分
(3)一个schema上有多个字段的查询需求

举例:订单业务
Order(oid, info_detail)
T(buyer_id, seller_id, oid)
数据量大了怎么办?一个表一个库是存不下的,这个时候往往需要进行水平切分。订单表很容易进行水平切分,根据订单id进行表切分,查询的时候可以根据订单id直接定位到它水平切分到哪个库或者哪个表里面。但是关系表怎么切分呢?有买家id、卖家id,如果通过买家id来水平切分,保证同一个买家id的数据在一个库里或一个表里,根据买家id可以定位到这个买家有多少个订单id,这里如果要用卖家id来查询的话,就需要遍历多个库了;反之如果用卖家id来进行分库分表,同一个卖家的订单关系在一个库或一个表里,此时如果用买家id来查询订单,也需要遍历多个库或多个表。所以不管用买家id还是卖家id来进行水平切分,都有另外一种业务是无法满足的,如果要满足就需要扫描多库,在库的数量非常多数据量非常大的时候,扫描多库的性能是非常非常的低。

二、如何解决?

如果用大学数据库学的范式来解决,几乎是无解的,所以在互联网的某些场景之下,只有逆范式或反范式来设计表结构,进行数据冗余才可以满足在多个业务场景下多个查询条件下的水平切分的需求。

冗余表
Order(oid, info_detail)
T1(buyer_id, seller_id, oid)
T2(seller_id, buyer_id, oid)

三、如何冗余?

(1)服务同步冗余
在进行表数据插入时,同时插入到T1,T2两张表中
优点:1.不复杂; 2.不一致性概率低
缺点:1.因为要插入两张表数据,处理业务时间增加; 2.仍然可能出现不一致

(2)服务异步冗余
增加一个消息队列,当插入T1表后,向消息队列中发送一个消息,然后由另外一个服务将数据插入到T2表中
优点:访问一次数据库,与不冗余数据时时间相同
缺点:1.复杂度增加,增加一个MQ; 2.消息发送成功不等于T2插入成功,此时查询T2会查询不到数据,但这个时间比较短,业务上往往是可以接受的; 3.不在一个分布式事务里,会出现数据不一致性

(3)线下异步冗余
添加一个bin log,然后调用服务进行T2表的数据插入
优点:两次写操作解耦
缺点:1.有延时,可能在T2中查询不到数据; 2.会出现数据不一致性问题

四、“原子性事务”,正向表和反向表谁先操作?

如果原子性被破坏,不一致出现,谁先做对业务的影响较小,就谁先执行

五、如何保证一致性?

在大数据、高并发、延迟敏感的业务中,并不能实时保证一致性,而是尽可能的发现数据不一致性,然后保证最终一致性。

六、如何保证一致性?

(1)全量数据扫描
写一个离线程序,定时每天检查一次T1和T2表中数据是否一致,不一致的话进行补偿,使数据一致
优点:解耦
缺点:每天都需要大量检测,已经检测过的数据会重复检测,需要耗费的时间长,会导致数据不一致性的时间长

(2)增量日志扫
服务插入T1或T2表后向T1日志或T2日志中写一条日志数据,然后写一个离线的程序,对日志进行检测,发现不一致则进行补偿,使数据一致
优点:1.不会重复检测数据; 2.检测周期缩短; 3.线上影响比较低
缺点:时效性还是不高

(3)实时消息对检测
增加一个消息队列,插入T1成功后就向消息队列中发送一条消息,插入T2d成功后,就向消息队列中发送一条消息,根据经验,5秒内能收到2条消息,如果未收到消息,则检测数据库数据是否一致
缺点:复杂度高

-------------本文结束感谢您的阅读-------------