说明
讲师:李智慧
MySQL 复制注意事项
- 主主复制的两个数据库不能并发写入。
- 复制只是增加了数据的读并发处理能力,没有增加写并发能力和存储能力。
- 更新表结构导致巨大的同步延迟。
数据分片
当数量量太大不能放在一个数据库的时候,就需要数据分片。比如微信的用户表、Facebook用户,淘宝订单表等。
- 分片目标
- 分片特点
- 分片原理
硬编码实现数据分片
硬编码不灵活,比如服务器宕机了。
映射表外部存储
可以用多种方式映射,比如订单表里面,除了可以用userId映射,也可以用orderId映射。
不过在实践中用的并不多,因为增加了应用的复杂性。
数据分片的挑战
- 需要大量的额外代码,处理逻辑因此变得更加复杂。
- 无法执行多分片的联合查询。
- 无法使用数据库事务。
- 随着数据的增长,如何增加更多饿服务器。
分布式数据库中间件
分布式数据库中间件:Mycat
Amoeba/Cobar架构
Cobar 系统组件模型
核心模块:SQL解析模块、SQL路由模块、结构合并模块。
- SQL解析模块:解析SQL成语法树,解析出需要分片的字段。
- SQL路由模块:根据需要分片的字段,路由到SQL执行代理模块。
- 结构合并模块:查询的数据可能需要从多个数据库获取,需要把数据合并后返回给客户端。
路由配置实例
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">
<amoeba:rule xmlns:amoeba="">
...
<tableRule name="MESSAGE" schema="test" defaultPools="blogdb-1,blogdb-2">
<rule name="rule1">
<parameters>ID</parameters>
<expression><![CDATA[ abs(hash(id)) mod 2 = 0]]></expression>
<defaultPools>blogdb-1</defaultPools>
</rule>
<rule name="rule2">
<parameters>ID</parameters>
<expression><![CDATA[ abs(hash(id)) mod 2 = 0]]></expression>
<defaultPools>blogdb-2</defaultPools>
</rule>
</tableRule>
...
</amoeba:rule>
Cobar 如何做集群的伸缩
数据迁移,数据库中的数据,是一条也不能少的。
余数hash
缺陷:上图需要搬数据的范围太大,基本上所有数据库都需要搬数据。
实践中 Corba 扩容策略
Schema实际上就是数据库,扩容的时候把Schema迁移到新的数据库。
比如迁移到新MySQL的Schema有:Schema4,Schema8,Schema12.
这样子每个数据库都有3个Schema。
迁移的流程是,先把旧数据库Schema复制到新的数据库,全部复制完后,删除老数据库的Schema,路由配置实例配置修改。
数据库部署方案 - 单一服务与单一数据库
数据库部署方案 - 主从复制实现伸缩
数据库部署方案 - 两个 Web 服务及两个数据库
推荐实践顺序:先做业务分库,再做数据分片。
数据库部署方案 - 综合部署
CAP原理
一致性
一致性是说,每次读取的数据都应该是最近写入的数据或者返回一个错误(Every read receives the most recent write or an error),而不是过期数据,也就是说,数据是一致的。
可用性
可用性是说,每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过这个响应不需要保证数据是最近写入的(Every request receives a (non-error) response, without the guarantee that it contains the most recent write),也就是说系统需要一直都是可以正常使用的,不会引起调用者的异常,但是并不保证响应的数据是最新的。
分区耐受性
分区耐受性说,即使因为网络原因,部分数据库节点之间消息丢失或者延迟了,系统依然应该是可以操作的(The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes)。
CAP原理
-
当网络分区失效发生的时候,我们要么取消操作,这样数据就是一致的,但是系统却不可用;要么我们继续写入数据,但是数据的一致性就得不到保证。
-
对于一个分布式系统而言,网络失效一定会发生,也就是说,分区耐受性是必须保证的,那么在可用性和一致性上就必须二选一。
-
当网络分区失效,也就是网络不可用的时候,如果选择了一致性,系统就可能返回一个错误码或者干脆超时,及系统不可用。如果选择了可用性,那么系统总是可以返回一个数据,但是并不能保证这个数据是最新的。
所以,关于 CAP 原理,更准确的说法是,在分布式系统必须满足分区耐受性的前提下,可用性和一致性无法同时满足。
CAP 原理与数据存储冲突
最终一致性
最终一致写冲突
简单冲突处理策略:根据时间戳,最后写入覆盖。
有些应用用GPS的时钟,来保证时间戳的准确性。
客户端冲突解决
投票解决冲突 (Cassandra)
Cassandra 分布式解决方案
- 保证路由算法的一致性。需要自行选择,数据存储到哪里。
- 这些数据库也是个环状,早期的Cassandra也是用的一致性哈希算法实现服务器扩容的。
Hbase 架构
数据存储在HFile, HFile是Hadoop的数据库。HFile包装在HRegion中,HRegion包装在HRegionServer中。HRegionServer负责数据的管理,HFile负责数据存储。就是HRegion不可用,HFile的数据也是存在的。HRegion跟HFile不是强耦合的,当机器扩容的时候,HFile对应的HRegion是可以改变的。
Hadoop的HFile的数据是追加写的。不能对已经存在的数据进行修改和删除的。
当HRegionServer宕机的时候,几十分钟,存储在其中的Key就不可用了。
Zookeeper选择一个主HMaster,避免分布式系统脑裂。如果主HMaster宕机后,Zookeeper重新选择一个应用为HMaster。
HMaster决定数据最终存储在哪个HRegionServer,也就是如何路由。
HBase也是对数据分片存储。
Log Structed Merge Tree(LSM树)
B+树增加一个数据需要几十毫秒。
LSM树增加一个数据只需要几毫秒。
Hadoop的HFile的数据是追加写的。不能对已经存在的数据进行修改和删除的。
怎么做到修改数据呢?在合并的时候,重写原有数据到新的树。
越上面的数据都是旧数据,越下面的叶子节点的数据越新。
如果读旧数据,速度就有可能慢一点。
写操作只需要写内存。
机械硬盘连续写速度在70~80M/s,随机写的速度要低两个数量级,大概在1M/s左右。
ACID与BASE
数据库的事务机制 ACID
- 原子性(Atomicity):事务要么全部完成,要么全部取消。如果事务崩溃,状态回到事务之前(事务回滚)。
- 隔离性(Isolation):如果2个事务T1和T2同时运行,事务T1和T2最终的结果是相同的,不管T1和T2谁先结束,隔离性主要依靠锁实现。
- 持久性(Durability):一旦事务提交,不管发生什么(崩溃或者出错),数据要保存在数据库中。
- 一致性(Consistency):只要合法的数据(依照关系约束和函数的约束)才能写入数据库。
NoSQL是做不到ACID的,所以提出了BASE。
NoSQL的BASE
- 基本可用(Basically Available):系统在出现不可预知故障时,允许损失部分可用性,如响应时间上的损失或功能上的损失。
- 弱状态(Soft State):软状态,指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延迟。
- 最终一致性(Eventually Consistent):指系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态,因此最终一致性的本质是需要系统保证数据能够达到一致,而不需要保证系统数据的强一致性。