系列文章:
一 概述
上一篇文章数据架构:概念与冷热分离中介绍了数据架构的概念和意义。并抛出了数据冷热分离的问题。事实上,这并不是新的概念,各公司在很早之前就已经开始了落地实践。微软云有冷热blob存储,阿里云有ots,都是为了在云服务层面提供冷热存储的解决方案。尽管有这些工具,如果很好地实现冷热分离,仍然是值得仔细思考和玩味的。
二 冷热分离核心问题与案例
2.1 关键问题
回归话题,无论我们怎样选择冷热存储方案,首先,都还是需要一种存储介质。哪怕是云上的存储方案。冷热分离的具体实现,也会与存储介质的选择直接相关。举个栗子,数据从热存储到冷存储的迁移,最简单的来看,需要实现2个步骤:1、数据写入冷存储;2、热存储数据删除;而删除动作就与数据库的选择有很大关系。
2.1.1 大数据删除
大量的数据插入和数据删除,尤其是在有索引的大表上,这样的操作会很大程度地影响数据库读写性能;而且删除后,未必会立即释放旧数据所占的空间,在某些db下,甚至可能需要做一次数据整理才能真正释放。这会导致一个很严重的问题,如果不做整理操作,那么相当于这些旧数据物理上还占据着空间,最终必然也会导致磁盘空间不足。
2.1.2 查询包含热数据也有冷数据
这点可以理解为中间层路由的实现。什么时候查询热数据,什么时候查询冷数据,需要有一个规则层来控制。理想的情况,冷热数据都是分别查询,而且冷数据查询的频率(在整体查询中的比例)低一个或多个数量级,这样的分离说明是比较合理的。
2.2 几个案例
接下来,我们通过可以搜索到的几个文章中的案例,来了解不同存储方案下的冷热分离实现,并试图分析其中合理和不合理的地方。
2.2.1 mysql
2.2.1.1 案例概述
案例中是采用数据分库的方式实现。也就是说,建立了生产库 和 历史库两个数据库,生产库存放热数据,历史库放冷数据。文中描述的架构如下图所示:
2.2.1.2 数据迁移
通常,迁移我们会采用定时任务的方式实现。也就是说,对于冷热数据的分割,会倾向于使用“天”的粒度。当然,根据实际的业务需求也可以进一步细分。
为了不影响常规业务,就需要在业务低谷时期执行这些非核心业务动作,所以会在每天凌晨执行迁移动作,在新的业务请求高峰到来之前完成迁移,降低影响。在任务的具体实现上,还需要特别注意,某些任务可能会依赖数据迁移的完成,这样就意味着存在任务之间的依赖关系,以及失败重试等等。并且为了确保数据的完整性和一致性,最好对迁移数据进行一致性校验,避免数据丢失和错误数据的产生。
2.2.1.3 多数据源的查询
这里的多数据源,就是指既有热数据,也有冷数据的查询。当然前面我们有过描述,理想情况下不应该有这样的情况存在,但在真实业务中很可能是不可避免的。这就要求:1)系统提供跨热、冷数据库的查询支持;2)冷数据查询性能明显低于热数据库的情况下,尽可能减小查询耗时。如果可能,最好能实现降低长尾耗时查询的比例。为了达到这个效果,就需要结合缓存策略或在功能上限制查询模式和查询范围,并在具体业务中做好引导和取舍。
2.2.2 Elasticsearch
2.2.2.1 节点异构
与mysql的冷热部署类似,这里的es也采用双集群模式,但强调出了节点异构。(其实这是必要环节和前提,简单来说,热库侧重实时业务读写能力,要求保障性能,空间足以存储热数据即可;而冷库则需要保障数据存储量级和一致,能够接受牺牲一定程度的读写性能,因为要存储大量历史数据,所以相比热裤,空间需要大很多。)
“部分是高性能的节点用于存储热点数据,部分是性能相对差些的大容量节点用于存储冷数据,却可以一方面保证热数据的性能,另一方面保证冷数据的存储,降低存储成本,这也是Elasticsearch冷热分离架构的基本思想”。
2.2.2.2 节点指定冷热属性
在elasticsearch.yml文件中增加配置的方式,为节点打上标签。
node.attr.{attribute}: {value}
其中attribute为用户自定义的任意标签名,value为该节点对应的该标签的值,例如对于冷热分离,可以使用如下设置
node.attr.temperature: hot //热节点 node.attr.temperature: warm //冷节点
2.2.2.3 冷热索引设置
冷热数据做了分离,前面也提到二者适用于不同场景,那么在数据的索引上,也可以针对使用场景进行曲分设计,不必保持一致。
注意冷热数据与数据库主从的区别,冷热数据库会要求表/集合的结构一致,但索引可以有所区别。
2.2.2.4 索引生命周期
Elasticsearch从6.6版本开始提供索引生命周期管理功能,索引生命周期管理可以通过API或者kibana界面配置。这一特性使得我们可以使用索引生命周期管理结合冷热分离架构实现索引数据的动态管理。
这里引述Elasticsearch冷热分离原理和实践中的描述:
索引的生命周期被分为:Hot phrase
,Warm phase
, Cold phase
,Delete phrase
四个阶段
- Hot phrase: 该阶段可以根据索引的文档数,大小,时长决定是否调用rollover API来滚动索引,详情可以参考[indices-rollover-index],因与本文关系不大不再详细赘述。
- Warm phrase: 当一个索引在Hot phrase被roll over后便会进入Warm phrase,进入该阶段的索引会被设置为read-only, 用户可以为这个索引设置要使用的attribute, 如对于冷热分离策略,这里可以选择temperature: warm属性。另外还可以对索引进行forceMerge, shrink等操作,这两个操作具体可以参考官方文档。
- Cold phrase: 可以设置当索引rollover一段时间后进入cold阶段,这个阶段也可以设置一个属性。从冷热分离架构可以看出冷热属性是具备扩展性的,不仅可以指定hot, warm, 也可以扩展增加hot, warm, cold, freeze等多个冷热属性。如果想使用三层的冷热分离的话这里可以指定为temperature: cold, 此处还支持对索引的freeze操作,详情参考官方文档。
- Delete phrase: 可以设置索引rollover一段时间后进入delete阶段,进入该阶段的索引会自动被删除。
总结
本篇分析了几个冷热分离的实现案例,并整理了一些问题和解决方案。通过mysql 和 Es的两种冷热分离实现,阐述了不同存储方案上冷热分离实现上的共同点和差别。回归本源,设计最终还是依赖于具体业务需求。后续还需要在实践中,通过足够的业务场景和数据量级支撑,来继续验证方案的可行性和潜在问题,不断进行完善升级。