一、内容之前的讨论
生产环境中,随着数据量的增大,数据文件以及索引文件会越来越大,对数据的增删改查操作所需要的检索量上升,最终导致数据库响应时间增加,成为产品性能瓶颈。解决方案之一当然可以砸钱买服务器分库存数据,像美团之前为了维护订单id,用户id以及商家id的查询,全量复制了好几份冗余数据分库存取。最好的解决方案就是在数据表建立之初就设想好些那些属性读多,哪些属性写多,哪些建立索引等。但不可能预见所有的情况,于是需要随着数据量的增加,逐渐进行数据优化操作,这也是本文讨论的重点。
二、表分区
将一个表的内容拆分到多个存储文件中
ALERT TABLE user PARTITION BY HASH (id) PARTITIONS 4//将user表根据id哈希分到四个区
表分区后,对外仍然是一个逻辑表,内部数据已经分流到四个分区,常用的分区方式有:Range、List、Hash、Key。
需要注意的是,分区时应该尽量结合查询规则,尽量保证查询落到一个分区中,避免全表扫描再合并查询结果,从而提升并发性能。
三、分库分表
分库和分表是两个独立的概念,分库是将一个数据库中的内容拆分到多个数据库中,通常做法是将一个DB中的表拆一半到第二个DB,因为涉及分表操作,于是常常称作分库分表。
分表是将一个表中的数据拆分到多个表中,使得每个表的数据表变小,便于索引检索,还能使行锁,表锁的范围变小,提升数据表的并发能力。
分表可以分为水平拆分和垂直拆分,顾名思义就是横着拆和竖着拆。这里不过多展开,需要注意的是将表拆分后一般要考虑的是1)查询业务逻辑修改,2)数据完整性拼接
四、读写分离
锁的存在对数据库并发能力是一个极大地限制,而读写分离就是将读操作与写操作进行分离,从而提高并发能力。而单数据库显然无法实现读写分离,因此就需要多个数据库支持。其中,一般有一个数据库(master)接受写操作,另n个数据库(slave)接受读操作。读写分离有以下两个问题需要解决:
路由操作:将请求分流到不同的库
主从复制
以MySQL为例介绍主从复制规则(去参考Redis的主从复制):
master开启BingLog,记录写操作
BingLog传输到slave,写入slave的RelayLog
slave解析ReayLog,并复现
主从复制不一致问题:
master和slave的数据不是实时一致的,所以考虑到主从复制的延迟,有以下几种主从复制方式:
异步复制:写请求写入master后立刻返回
半同步复制:写请求写入BingLog后等待至少写入一个RelayLog才返回
全同步复制:等待所有slave更新才返回
五、(题外话)海量数据存储架构设计篇
5.1 美团存储设计
早期美团为了抓住外卖的赛道,直接将数据存储在MySQL中,随着业务量的增加,发现渐渐的目前架构无法满足需求,比如用户查看历史订单刷新一下要4,5秒才出来,于是就去做订单的水平拆分,将同一张表的数据拆分到不同数据库,去承载高并发。关键问题是用什么键作为拆分键。比如用户订单表就用用户ID进行拆分,但是随之而来的问题是:商家也想查订单,随着入驻商家越来越多,商家查询越来越慢,为什么慢?是因为分片键不是商家ID而是用户ID,于是美团的做法是:冗余数据,说白了就是砸钱,将数据全部复制一份,另一份用商家ID作为分片键。
Hbas 存储历史数据,高度压缩,但是无法排序
elastic search(OLAP型)复杂聚合计算,无事务
5.2 淘宝存储设计
初期也是单表单库,但是随着业务量的增加,开始无法承载业务,于是做了一个历史数据备份,三个月的数据留在系统里,其他数据冷备份(2010年),后面数据量暴增,于是淘宝将历史数据存到HBase里,相较于美团,淘宝没有做全量复制,而是在订单表上做了一个索引表,存储指向数据分片的位置。(GLobal Index GIS,设计思想参考的是MySQL辅助索引里覆盖索引的特性)做全局二级索引,有关辅助索引和覆盖索引的介绍如下:
评论