单库单表
业务开始阶段,一个数据库,加上几个业务表,就够用。代码也写在一起,一个service就搞定了。
单库分表
但某个表到达千万级别甚至上亿级别,日增长在2%左右,这个时候,可以预见这个表将来会变得异样庞大。这个时候需要分表。操作上可以用分区函数,把一个表分到多个分区文件上。也可以真实地拆为多个实体表,不过这就意味着业务代码需要做相应的改动,或者需要引入中间件来获取所有的数据。
分表以后,只解决了单表的压力,整个数据库的压力实际上还是没有解决。
分库
这个时候,我们需要分库,把表拆分到多个数据库中去。
垂直拆分
垂直分库
个人见过的方式,将业务相关的代码拆成一个单独的service,与之对应的表也迁移到新的数据库。
垂直分表
按列拆分,把频繁更新的保存到一个表,剩余的放在另外一个表。反第三范式。不过数仓反的还少么?不必教条。
水平拆分
和分表类型,通过函数将表的数据拆分到多个库中去,这些库里面的表结构都是一致的。可以通过Hash,按照日期,ID范围来拆分。
分库分表之后
跨库的join关联性查询很差。解决方案可能是通过数仓简历自身产品的数据集市Data Mart。
关系型数据库
ACID
关系型数据库的ACID模型,原子性,一致性,隔离性,持久性。 原子性,即所有提交要么全部提交,要么全部回滚,不存在部分提交的情况。整个事务不可再分割。 一致性,即操作前后系统都处于一致的状态,不会出现某条数据违背约定的情况。 隔离性,即多个事务互相隔离,一个事务不影响另一个事务。 持久性,即数据保存下来,即使服务器重启数据都依旧存在。
隔离级别
一般隔离级别有四种,在四种基础上,会有其他的衍生隔离级别。Read Uncommitted, Read Committed, Repeatable Read, Seriablize.
一致性
关系型数据库的一致性和分布式数据库的一致性意义不一样。分布式数据库的更加注重节点。
强一致性
强制一致性,即任何一次读取任一节点都可以读到最新的改动。
弱一致性
数据更新后,允许后续的访问能够访问到部分或者全部访问不到。
最终一致性
不保证任一时刻任一节点上的数据是一致的,但随着时间的迁移,不同节点上的数据总是趋向同一方向变化。
分布式数据库
CAP原理
- Consistency 一致性 要求所有节点的数据更新是一致的
- Availablity 可用性 好的响应性能
- Partition tolerance 分区容错性 可靠性,某个节点坏掉后依旧可以使用
你只能够牺牲其中一个来保证其他两个,不能够同时拥有CAP。
BASE理论
基于CAP的AP,要求基本可用,软状态,最终一致性。
柔性事务
在CAP和BASE理论下,出现的柔性事务,相对于关系型数据库的刚性事务。一般通过日志记录+正向/反向补偿,消息,或者无锁设计(版本控制)。
分布式事务的解决方案
两阶段提交
一个全局事务管理器调节多个节点的事务管理器。分为prepare和commit/rollback阶段。
但是有弊端,比如同步阻塞,需要等待所有节点都准备好;单点阻塞,如果一个节点不available,就造成所有的阻塞了;可能会导致部分节点上面的数据不一致。
TCC
Try-Confirm-Cancel,是对两阶段提交的补充方案。主要是引入超时来解决同步阻塞,以及补偿机制。
本地消息表
通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。
MQ事务
系统A往MQ、Kafka里面丢消息,系统B去消费消息。系统B接收到消息以后返回ACK。如果成功,系统B记录改动。否则,系统B向系统A发出回滚请求。
总结
能不分表分库就不要分表分库,像我遇到的产品最多也就是主从同步,不是个个都能够做成天猫,京东。
MQ事务不就是以前J2EE里面就有的东西么?多个Service之间异步通信,靠MQ就可以实现了。现在只是把MQ应用到多个数据库节点中去。
如何保证多个节点中的自增ID唯一呢?保留最后1、2位,结尾为01的就是node1生成的id,上限支持99个节点。结尾为00一般用来给数据修复用。
此外,还有最近几年新起的NewSQL,能够既提高性能,又支持关系模型。What’s really new in NewSQL?