架构设计
Druid具有多进程,分布式架构,旨在实现云友好且易于操作。每种Druid进程类型都可以独立配置和扩展,从而为您的集群提供最大的灵活性。这种设计还提供了增强的容错能力:一个组件的故障不会立即影响其他组件。
进程和服务器
Druid有几种过程类型,下面简要描述:
- Coordinator进程管理群集上的数据可用性。
- Overlord进程控制数据提取工作负载的分配。
- broker程序处理来自外部客户端的查询。
- router进程是可选进程,可以将请求路由到代理,协调器和霸主。
- Historical过程存储可查询的数据。
- MiddleManager进程负责摄取数据。
Druid进程可以按照您喜欢的任何方式进行部署,但是为了易于部署,我们建议将其组织为三种服务器类型:Master服务器,Query服务器和Data服务器。
- Master:运行协调器和霸主流程,管理数据可用性和接收。
- Query:运行代理和可选的路由器进程,处理来自外部客户端的查询。
- Data:运行Historical和MiddleManager进程,执行提取工作负载并存储所有可查询的数据。
有关进程和服务器组织的更多详细信息,请参阅Druid进程和服务器。
外部依赖
除了内置的进程类型外,Druid还具有三个外部依赖项。这些旨在能够利用现有的现有基础结构。
深度储存
每个Druid服务器均可访问共享文件存储。在集群部署中,这通常将是分布式对象存储(例如S3或HDFS)或网络安装的文件系统。在单服务器部署中,这通常是本地磁盘。德鲁伊使用深度存储来存储已摄取到系统中的所有数据。
Druid仅将深度存储用作数据的备份,并作为在Druid进程之间在后台传输数据的方式。为了响应查询,历史进程不会从深度存储中读取数据,而是会在提供任何查询之前从其本地磁盘读取预提取的段。这意味着Druid不需要在查询期间访问深层存储,从而帮助它提供了最佳的查询延迟。这也意味着在深度存储和历史进程中,必须有足够的磁盘空间用于计划加载的数据。
深度存储是Druid的弹性,容错设计的重要组成部分。即使每台数据服务器都丢失并重新配置,Druid也可以从深度存储中引导。
有关更多详细信息,请参阅深度存储页面。
元数据存储
元数据存储区包含各种共享的系统元数据,例如段可用性信息和任务信息。在集群部署中,这通常将是传统的RDBMS,例如PostgreSQL或MySQL。在单服务器部署中,它通常将是本地存储的Apache Derby数据库。
有关更多详细信息,请参见“ 元数据存储”页面。
动物园管理员
用于内部服务发现,协调和领导者选举。
有关更多详细信息,请参见ZooKeeper页面。
架构图
下图显示了使用建议的Master / Query / Data服务器组织的查询和数据在整个体系结构中的流动方式:
储物设计
数据源和细分
德鲁伊数据存储在“数据源”中,类似于传统RDBMS中的表。每个数据源都按时间分区,并且可以选择按其他属性进一步分区。每个时间范围都称为“块”(例如,如果您的数据源按天划分,则为一天)。在一个块中,数据被划分为一个或多个 “段”。每个段都是单个文件,通常包含多达几百万行的数据。由于细分是按时间块组织的,因此将细分视为生活在时间线上的以下内容有时会有所帮助:
数据源可能具有从几个段到数十万甚至数百万个段的任何位置。每个段都开始于在MiddleManager上创建的生命,并且那时是可变的且未提交的。段构建过程包括以下步骤,旨在生成紧凑且支持快速查询的数据文件:
- 转换为列格式
- 使用位图索引编制索引
- 使用各种算法进行压缩
- 字符串列的ID存储最小化的字典编码
- 位图索引的位图压缩
- 所有列的类型感知压缩
分段会定期提交和发布。此时,它们被写入深度存储,变得不可变,并从MiddleManagers迁移到Historical进程。有关该段的条目也将写入到元数据存储中。该条目是有关段的元数据的自描述位,包括诸如段的模式,其大小及其在深度存储上的位置之类的信息。这些条目是协调器用来了解集群上应该有哪些数据的内容。
有关段文件格式的详细信息,请参阅段文件。
有关在Druid中对数据建模的详细信息,请参见模式设计。
索引和切换
索引是创建新段的机制,移交是它们被发布并开始由历史过程提供服务的机制。该机制在索引端的工作方式如下:
- 一个索引任务开始运行,并建立一个新的细分市场。在开始构建段之前,必须确定该段的标识符。对于要追加的任务(例如Kafka任务或追加模式中的索引任务),可以通过在霸主上调用“分配” API来完成,以潜在地将新分区添加到现有的段集中。对于要覆盖的任务(例如Hadoop任务或不在附加模式下的索引任务),这可以通过锁定间隔并创建新的版本号和新的段集来完成。
- 如果索引任务是实时任务(例如Kafka任务),则此时可以立即查询该段。它可用,但尚未发布。
- 索引任务完成对段的数据读取后,将其推入深度存储,然后通过将记录写入元数据存储来发布它。
- 如果索引任务是实时任务,则此时它等待“历史”进程加载该段。如果索引任务不是实时任务,它将立即退出。
并在协调员/历史方面这样:
- 协调器定期(默认情况下,每1分钟)轮询元数据存储区以查找新发布的段。
- 当协调器找到已发布和使用但不可用的段时,它会选择一个“历史记录”进程来加载该段并指示“历史记录”这样做。
- 历史记录会加载细分并开始投放。
- 此时,如果索引任务正在等待切换,它将退出。
段标识符
段均具有包含以下部分的四部分标识符:
- 数据源名称。
- 时间间隔(对于包含分段的时间块;这对应
segmentGranularity
于摄取时指定的时间间隔)。 - 版本号(通常为ISO8601时间戳,与首次启动段集的时间相对应)。
- 分区号(整数,在数据源+间隔+版本内是唯一的;可能不一定是连续的)。
例如,这是datasource clarity-cloud0
,time chunk 2018-05-21T16:00:00.000Z/2018-05-21T17:00:00.000Z
,version 2018-05-21T15:56:09.909Z
和分区号1中的段的标识符:
clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z_1
复制
分区号为0(块中的第一个分区)的段省略了分区号,如以下示例所示,它是与前一个分区在同一时间块中的段,但分区号为0而不是1:
clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z
复制
段版本控制
您可能想知道上一节中描述的“版本号”是什么。或者,您可能不是,在这种情况下对您有好处,您可以跳过本节!
它在那里支持批处理模式覆盖。在德鲁伊中,如果您要做的只是追加数据,那么每个时间块只有一个版本。但是,当您覆盖数据时,在幕后发生的事情是使用相同的数据源,相同的时间间隔,但版本号更高的方式创建了一组新的段。这向Druid系统的其余部分发出信号,表明应从群集中删除较旧的版本,而应使用新版本替换它。
对于用户而言,切换似乎是瞬间发生的,因为Druid通过首先加载新数据(但不允许对其进行查询)来处理此问题,然后在所有新数据加载完毕后,立即切换所有新查询以使用这些新查询。新细分。然后,它在几分钟后删除了旧段。
段生命周期
每个部分的生命周期都涉及以下三个主要领域:
- 元数据存储区:一旦构建完段,就将段元数据(小的JSON有效负载,通常不超过几个KB)存储在 元数据存储区中。将段的记录插入元数据存储的操作称为发布。这些元数据记录具有一个名为的布尔标志
used
,该标志控制该段是否可查询。由实时任务创建的细分将在发布之前可用,因为它们仅在细分完成时才发布,并且不接受任何其他数据行。 - 深度存储:分段数据构建完成后,会将分段数据文件推送到深度存储。这在将元数据发布到元数据存储之前立即发生。
- 查询的可用性:段可用于在某些Druid数据服务器上进行查询,例如实时任务或历史进程。
您可以使用Druid SQL sys.segments
表检查当前活动段的状态 。它包括以下标志:
is_published
:如果段元数据已发布到存储的元数据中,used
则为true,并且为true。is_available
:如果该段当前可用于实时任务或历史流程查询,则为True。is_realtime
:如果细分仅在实时任务上可用,则为true 。对于使用实时提取的数据源,通常会先开始true
,然后false
随着段的发布和移交而变成。is_overshadowed
:如果该段已发布(used
设置为true)并且被其他一些已发布的段完全遮盖,则为true。通常,这是一个过渡状态,处于此状态的段很快就会将其used
标志自动设置为false。
查询处理
查询首先进入Broker,Broker将在其中识别哪些段具有与该查询有关的数据。段列表始终按时间修剪,也可以根据其他属性来修剪,这取决于数据源的分区方式。然后,代理将确定哪些历史记录和 MiddleManager正在为这些段提供服务,并将重写的子查询发送给每个流程。Historical / MiddleManager进程将接受查询,对其进行处理并返回结果。经纪人接收结果并将它们合并在一起以得到最终答案,并将其返回给原始呼叫者。
代理修剪是Druid限制每个查询必须扫描的数据量的一种重要方法,但这不是唯一的方法。对于比Broker可以使用的过滤器更细粒度的过滤器,每个段内的索引结构允许Druid在查看任何数据行之前找出哪些行(如果有)与过滤器集匹配。一旦Druid知道哪些行与特定查询匹配,它就只会访问该查询所需的特定列。在这些列中,Druid可以在行与行之间跳过,从而避免读取与查询过滤器不匹配的数据。
因此,Druid使用三种不同的技术来最大化查询性能:
- 修剪为每个查询访问的细分。
- 在每个段中,使用索引来标识必须访问的行。
- 在每个段中,仅读取与特定查询相关的特定行和列。
其他参考:https://cloud.tencent.com/developer/article/1500155