前两篇文章介绍了分布式存储的机制,为保证数据的高性能以及可拓展,采用分片/分区机制。为保证数据的高可用性,采用复制/镜像机制存储数据。一份数据存储多份。而这两种方式在数据中,就是分片/分区机制。分库分表/读写分离。
读写分离 CQRS
读写分离是最简单数据库拓展的方式,主要应对的场景是读多写少,可以有效的把业务做相应的隔离。
读写分离的形势可能不同,一主多从(一主一从,一主两从/多从)以及可能数据备份的方式,主备等方式。图中就是一个写库,两个从库,写的时候都写主库,读的时候都写从库。
好处
1.实现起来比较容易,数据库的master-slave 配置和服务框架里的读写分离比较成熟,应用比较快
2.可以很好的把业务隔离开来,经历的公司都是所有数据表在同一个库中,当这个数据库出现问题 负载比较高时,可能会拖垮所有业务,所以需要进行数据的拆分。将一些大表,配置表进行隔离开来。
3.可以有效分担数据的读操作,大多数的业务都是读耗费性能。
坏处
1.写库存在单点故障,如果写库不可用,那么对于一些高可用的业务,比如订单 支付系统,影响比较大。
2.数据库主从同步存在一定的延时,不实时,需要强一致性的读写操作需要写到从库上。
以下是主从复制的流程图
读写分离的目的主要是提高数据库的读操作的能力
以上的方式是比较简陋的,
读写分离CQRS
CQRS(Command and Query Responsibility Segregation) 命令和查询职责分离
用户对于一个系统的动作一个是 增删改,另一个是查询,主要数据回显,或者数据分析。
命令 不会返回数据项,但是会影响数据结果,返回执行命令
- 查询 不应影响数据,但是会返回数据
- 指责明确,可以跟好的追逐系统中哪些行为或者操作修改了系统的状态变化。
分库分表 Sharding
影响数据库性能来说是两点,一个是对数据库的操作,另一个是数据库本身的容量。
前者我们可以通过减少多表join,或者合理建立索引,如果大量查询可以用es查询,比如日志,如果要做数据报表要使用hoddop处理。
但是对于数据库本身的容量是有一定的限制,比如单表5KW的级别的时候,数据查询是非常慢的。本身服务可以进行拆分成分布式的,那么数据库页可以拆分成分布式的,具体形态就是分库分表。
说到分库分表,其实比较就离不开两个事情,一个是分库分表的策略,另一个是数据中间层。
分库分表的策略,一般老说会按照时间维度,每月 每天创建一张表,或则地理位置,或者用户%操作散列哈希。库的力度其实比较大,我们可以按照业务域进行划分,比如订单域,支付域,库存域等拆分,都需要结合具体的业务进行拆分。
数据库中间层,其实这个数据中看层的目的就是为了屏蔽底层的分库分表后,一个SQL是不需要关注分库分表后的操作的。具体功能就是需要解析SQL的能力,以及多表联查 事务操作上也是有一定的难度,XA的两阶段事务提交,这个东西复杂度比较高,一般都是基础架构组进行开发的。
设计重点
一般来说,如果只是数据库层面的分库分表,其实并没有做到彻底,要做的事情是服务和数据一起拆分,一个服务一个数据库,对外只提供接口层面的访问。先做服务化的拆分在进行分片操作,分片分为垂直分片和水平分片。
比如订单系统有专门的订单数据库,支付有专门的支付库,而不是一个数据库,所有的表都存储在一个数据库中,这样非常不利于管理,而且别的系统读取你系统的数据,出现问题,你可可能要背锅。服务和数据库要一起拆分
分库分表后,如何保证全局的唯一id,一般使用雪花算法。
比如在真实开发中,如果上下业务系统需要相关数据,最好是通过通信的API的方式将数据返回,而不应该直接读取数据库。比如订单直接读取支付数据库。另一个读写分离虽然可以提高读的性能,但是当出现大量数据更新导致主从延迟,就会出现从库获取不到最新的数据,影响上下游业务系统。所以平时在高峰期不要频繁更新大量数据,刷数据。