数据库的种类
最为广泛的, 是关系型数据库(Relational Database), 以MySQL、Oracle、SQLServer为代表.
这类数据库把数据每个条目(row)的数据分成多个项目(Column ), 如果某个项目, 比较复杂, 从数据角度来说是个结构体, 那么就搞一个新的表(table)来存储它, 在主表中只存储一个ID来引用.
第二类是文档型数据库(Document Database), 以MongoDB为代表. 这类数据库把数据每个条目(row)称为文档(document), 每个文档用JSON或其他文档描述格式表示. 文档数据库大部分是无schema的, 也就是在插入文档时并不对文档的数据格式进行校验.
好处是使用门槛低, 升级数据格式方便. 不好之处, 质量保障体系弱化, 数据可能被弄脏而不自知.
第三类是键值存储(KV Storage), 以Cassandra, Redis为代表. 键值存储从使用的角度来说, 可以认为是数据库的特例. 数据库往往是允许设定多个索引字段的, 而键值存储明确只有唯一索引.
事务
无论是何种数据库, 都面临一个重大选择: 是否支持事务. 这是一个艰难选择. 从需求觉度来说, 事务功能非常强大, 没有道理不支持. 从实现角度来说, 食物支持带来极大的负担, 尤其是在分布式数据库的场景.
什么是事务? 简单来说, 就是把一系列数据库操作变为原子操作的能力. 展开了来说, 事务的特性我们往往简称为ACID, 详细如下:
- 原子性(Atomicity): 在整个事务中的所有操作, 要么全部完成, 要么全部不做, 没有中间操作. 事务中间若发生错误, 所有操作都要被回滚, 整个事务就像从没有被执行过一样.
- 一致性(Consistency): 系统的一致性, 就是执行的操作必须按照其指定的结果处理.
- 隔离性(Isolation): 事务与事务之间不会互相影响, 一个事务的中间状态不会被其他事务感知.
- 持久性(Durability): 一旦事务完成了, 那么事务对数据库所做的变更就完全保存在了数据库中, 即使发生了停电, 宕机, 其结果也不会发生丢失或改变.
一种常见的事务实现方式是乐观锁. 先计算出所有修改的数据, 然后最后一步统一提交修改. 提交时会进行冲突检查, 如果没有冲突则提交成功. 若有冲突则提交失败, 放弃本次修改.
主从结构
要考虑数据库的业务可用性和数据持久性, 就要考虑多副本存储数据. 可用性(Availability)关注的是业务是否正常工作, 持久性(Durability) 关注的是数据是否会被异常丢失.
数据存在多个副本, 就会有数据一致性问题. 不同的副本值不一样, 应该使用谁的.
解决这个问题的方法之一是采用主动(Master-Slave)结构. 主从结构采用的一主多从模式, 所有写操作都发往主(Master), 所有从(Slave) 都从主这边同步数据修改的操作.
分布式
多副本让数据库的可用性和持久性有了一定的保障, 但是仍然有一些问题需要解决:
- 数据规模大到一定程度后, 单个物理节点放不了那么大的数据量
- 主承受的读写压力太大了, 单台主节点承受不了这样高的IOPS(吞吐能力)
怎么解决?
分布式. 简单说, 就是把数据分片存储到多台设备上的分片服务器一起构成一个单副本的数据库. 分片的额方式常见的有两种:
- 哈希分片(Hash based sharding)
- 范围分片(Range based sharding)
在分布式存储领域, 有一个著名的(CAP)理论.
- 数据一致性(Consistency): 如果系统对一个写操作返回成功, 那么之后请求都必须读到这个新数据; 如果返回失败, 那么所有读操作都不能读到这个数据
- 服务可用性(Availability): 所有读写请求在一定时间内得到响应, 可终止、不会一直等待
- 分区容错性(Partition-tolerance): 在网络分区的情况下, 被分割的节点仍能正常对外服务
那么CAP理论说的是什么? 简单来说, 就是C、A、P三个目标不能兼得, 我们只能取其二.
假设我们不会放弃服务的可用性, 那么我们决策一个分布式存储基本上在数据一致性(C)和分区容错性(P)之间权衡.
数据一致性(C)的选择基本上是业务特性决定的, 业务要求强一致性性, 我们就不可能用最终一致性模型, 相应的, 我们只能在分区容错性(P)上取舍
此文章为3月Day5学习笔记, 内容来源于极客时间《许式伟的架构课》, 强烈推荐该课