系统设计基础组件 - 数据库伸缩
数据库类型
关系型数据库 SQL
以MySQL,Oracle和Postgrad为代表的关系型数据库在关系型数据存储领域已经是称霸多年,也是主流的业务系统中的首选数据库选型。
非关系型数据库 No-SQL
随着行业的发展,大家逐渐意识到类似“用户行为”这样细粒度的数据在数字化商业领域的价值,从而带来了数据的大爆发,整个行业也一夜之间进入大数据时代。
大数据时代数据存储的需求趋向于易伸缩、性能好的数据库存储解决方案,传统的SQL数据库就显得笨重和吃力了(当然后来SQL数据库也开始支持No-SQL的一些特性)。
我们都知道新技术的演进背后往往都是在做一些trade-off,那么No-SQL到底放弃了哪些SQL特性来达成了易伸缩和高性能的特性呢?主要是两点:
- ACID 事务相关的特性
- 强Schema特性
No-SQL数据库类型
数据结构数据库(Data structure Database)
- Redis
列数据库(Column Database)
- Cassandra
- HBase
- ClickHouse
文档型数据库(Doucument Database)
- MongoDB
- SimpleDB
- CouchDB
搜索数据库(Search Database)
- Elasticsearch
图数据库(Graph Database)
- neo4j
SQL 与 NO-SQL 该如何选择
选择关系型数据库的理由:
- 业务必须需要ACID这样的事务特性保证
- 业务的数据是结构化的并且schema是不变的
选择非关系型数据库的理由:
- 数据规模大,大到已经突破了传统关系型数据库的限制
- 需要快速横向扩展(scale out)并支持快速发展的业务
新型数据库 NewSQL
首先newSQL是属于SQL类的关系型数据库,支持ACID的事务特性,但是试图去解决传统SQL数据库的大规模数据的伸缩性问题。wikipedia - NewSQL
关系型数据库伸缩设计
在我们拥抱NewSQL数据库这种新技术之前,先看看在原有的关系型数据库上我们都有哪些手段做数据伸缩性的调整。
在伸缩的维度上分为纵向伸缩(scale up)和横向伸缩(scale out)。
Scale up
纵向伸缩,顾名思义就是通过提升单节点的硬件配置来达到提升算力的目的。
当然纵向伸缩的策略是有其优劣的:
优势:
- 调整效果即时可见。
- 不需要其他研发成本的投入,或者是成本可忽略。
劣势:
- 硬件提升受工艺限制影响,总会有上限。
- 硬件的提升意味着需要更多的财务支持。
一个项目、公司的IT投入一定还是有预算的,所以Scale up的策略也一定是在一定范围内的调整,追求算力和财务支出的动态平衡。
在实际的项目中,Scale up的策略往往是用在应对临时的或者是短期的算力需求提升的场景,解决临时的燃眉之急。
如果是业务扩大,流量中长期稳健增长,就需要结合业务的综合发展重新制定IT预算,调整算力组合。
Scale out
横向伸缩,就是通过添加相对廉价计算节点的方式来达到提升算力的目的。
同样这种伸缩策略也是有其优劣的:
优势:
- 可伸缩空间大,相对于纵向伸缩会更晚遇到伸缩瓶颈。
- 相对于纵向伸缩的策略,在性价比会更有优势。
劣势:
- 有可能需要对现有系统做对应的技术改造,增加研发成本。
- 使现有的系统复杂性提升,对应的研发、测试和运维技术水平也有待升级。
使用重复(Replication)作为Scale out的解决方案
这里的重复指的是读节点的重复,相信你也猜到了,这个方案就是大家常说的“master-slave”方案(也称一主多从方案)。
这个方案使用的场景是:数据库读压力远远大于写压力的场景。
具体的做法是将数据库的写操作通过业务代码封装的方式路由到Master节点,而将读操作路由到各个slave读节点上,由mysql负责做master与slave节点之间的replication的数据同步。MySQL - Using Replication for Scale-Out
该方案的优点:
相关技术成熟,改造和培训应用成本较低。
数据库的master-slave方案以及框架的读写分离方案都是经过一定时间和一定规模检验的成熟方案,落地应用会相对较快。有效分担了读操作的负载
读操作毕竟是消耗CPU的大头。
缺点:
- 写节点存在单点故障风险
- 主从不能保证数据的强一致性
所以问题来了,如果是在master-slave下需要强一致性的功能怎么办?
如果这样的例子不多,临时的解决方案就是对于需要强一致性的功能,读写操作都放在master节点上。
以上的Replication 本质上是通过重复数据副本的方式(空间换时间)来达到提升特定性能。
然而常见的数据库性能问题是数据规模的大小,在遇到这样的瓶颈问题时Replication的方式就不能解决了。
我们需要考虑用其他思路来试试,比如说用下面“切分”的方式。
partitioning
既然是拆分,那么需要面对的问题就是
- 怎么拆?
- 按什么原则拆?
- 拆到什么粒度合适?
……
partitioning 类型
从表的维度来看
水平拆分(Horiziontal partitioning)
按照一定的规则以表的“行”为维度进行拆分,拆分后的表拥有相同的Schema。垂直拆分(Vertical partitioning)
按照表的字段进行拆分,一般来说常见的拆分方式是按字段变化频率高低进行表字段进行归集。
例如,对于商品表来说商品的价格就是相对变化频率高的字段,所以如果决定水平拆分商品表,将价格字段拆分出来会是合理的一个选择。
从拆分的执行者来看
MySQL partition解决方案
MySQL 5.1 及之后的版本开始支持partition的解决方案(目前的版本只是支持水平拆分) MySQL Partitioning。
虽然在存储引擎层面将数据分成了不同的文件,但是在SQL使用者的视角还是视为一个统一的数据表。
这个特性对于维护复杂、短时间不好修改的系统来说会是个好消息,意味着可以在不改变应用系统SQL语句的前提下进行表的拆分。开发者根据特定规则实现的partion方案
有开发者根据业务的特点制定partition 规则拆分表数据。
常说的sharding是什么
sharding就是水平拆分的方案。
水平拆分需要注意的事项
在动手拆分表数据之前,确定服务和数据库是否已经拆分合理
拆分之后需要注意之后的分片平衡问题
拆分的规则是静态的,但是数据是动态的。所以后续不可避免的就是需要进行平衡分片的操作,避免出现热点分区的出现。避免出现拆分后的分区事务问题
如果实在避免不了事务问题,就需要考虑是否有必要在业务层引入2PC(两阶段提交)和或在数据层引入Paxos一致性算法。
水平拆分的常见策略
按照某个合适分类业务的字段拆分
按照某个字段的范围拆分
按照某个字段的Hash算法拆分
No-SQL数据库
//TODO
No-SQL建模
//TODO
No-SQL如何选型
//TODO
No-SQL性能优化
//TODO