数据分区(数据密集型应用系统设计第六章)
我们必须摆脱串行的限制. 明确状态定义, 提供优先级与属性描述, 我们必须首先定义清楚关系, 然后才是执行步骤
------Grace Murray Hopper, 管理方法以及未来的计算机
面对海量数据或非常高的压力查询, 复制技术还不够, 我们还需要将数据拆分成为分区或分片
分区的定义: 每一条数据(或者每条记录, 每行或每个文档) 只属于某个特定分区
采用数据分区的目的是提高可扩展性, 不同的分区可以放在一个无共享集群的不同节点上, 对 单个分区进行查询时, 每个节点对自己所在分区可以独立执行查询操作, 因此添加更多的节点可以提高查询吞吐量
数据分区与数据复制
分区通常与复制结合使用, 即每个分区在多个节点都存有副本 , 以提高容错性
例如: 每个分区都有自己的主副本, 从副本被分配在其他一些节点, 一个节点可能既是某些分区的主副本, 也是其他分区的从副本
分区的主要目标将数据和查询负载均匀分布在所有节点上, 如果分区不均匀,则会出现某些分区节点比其他分区承担更多的数据量和查询负载, 称之为倾斜, 导致所有负载可能会集中在一个分区节点上, 称为系统热点
为了避免热点, 当读取特定数据时, 需要知道数据保存在哪个节点上
基于关键字区分分区
为每个分区分配一段连续的关键字或者关键字区间范围
关键字的区间段不一定非要均匀分布, 因为数据本身就可能不均匀(比如电商网站按订单日期每个月进行分区, 那么 11 月的分区会比其他分区大很多), 为了更均匀的分布数据, 分区边界理应适配数据本身的分布特征
优点是可以轻松支持区间查询,然而缺点是会导致热点, 比如双十一, 11 月分区可能会存在写入负载高的情况, 而其他分区始终空闲
基于关键字哈希分区
对于数据倾斜与热点问题, 许多分布式系统采用了基于关键字哈希函数的方式来分区
这种方法可以很好的将关键字均匀地分布到多个分区中, 但是丧失了区间查询特性
负载倾斜与热点
就算基于哈希的分区方法可以减轻热点, 但是无法做到完全避免
例如微博上一些名人有数百万粉丝, 当发布一些热点事件可能会引发一场访问风暴, 出现大量的对相同关键字的读写操作, 此时, 哈希起不到任何帮助作用, 因为两个相同 ID 的哈希值仍然相同
目前大多数系统无法自动消除这种高度倾斜的负载, 只能通过应用层来减轻
分区与二级索引
刚才讨论的分区方案都依赖键值的数据模型, 但二级索引并不能标识唯一的值, 例如查找所有颜色为红色的汽车等
二级索引是关系数据库必备的特性, 一些文档数据库也非常普遍, 这也是全文搜索引擎 ElasticSearch 存在的根本
基于文档分区的二级索引
假设一个二手车的网站, 每个列表都有一个唯一的文档 ID, 用此 ID 对数据库进行分区, 0~499 属于分区 0, 500~999 属于分区 1
现在用户需要搜索汽车, 可按汽车颜色和厂商进行过滤, 所以需要在颜色和制造商上设定二级索引, 例如, 每当一一辆红色汽车添加到数据库中, 自动在索引"color:red" 添加这个文档的 ID
但读取时需要注意, 除非对文档 ID 做了特殊处理, 如果想要搜索红色汽车, 就需要将查询发送到所有分区, 然后合并所有返回结果
这种查询分区数据库的方法有时也称为 分散/聚集
基于词条的二级索引分区
我们可以对所有的数据构建全局索引, 而不是在每个分区上 维护自己的本地索引, 而且, 为了避免瓶颈, 不能将全局索引存储在一个节点上, 否则就破坏了设计分区均衡的目标, 所以全局索引页必须进行分区, 且可以与数据关键字采用不同的分区策略
例如 从a到 r 开始的颜色放在分区 0 中, s 到 z 的颜色放到分区 1
我们将这种索引方案称为词条分区, term 指的是文档中出现所有单词的集合
这种全局词条分区相比于文档分区索引主要的优点是:
读取更为高效, 他不需要对所有的分区都执行一遍查询, 相反, 客户端只需要向包含词条的那一个分区发出读请求
缺点是: 写入速度较慢且非常复杂, 因为单个文档更新时, 会涉及到多个二级索引, 而二级索引的分区又可能在多个节点上, 由此势必引入写入放大. 理想情况下, 索引应该保持最新, 即写入数据要立即反映在最新的索引上, 但是词条分区需要跨多个相关分区的分布式事务的支持, 写入速度会受到极大的影响, 所以现有的数据库都不支持同步更新二级索引