Druid技术笔记整理第4篇,关于Druid Coordinator
Coordinator 主要完成如下功能:
1. loading new segments
2. dropping outdated segments
3. managing segment replication
4. balancing segment load
Coordinator Node主要负责Druid集群中Segment的管理与发布,包括加载新Segment、丢弃不符合规则的Segment、管理Segment副本以及Segment负载均衡等。如果集群中存在多个Coordinator Node,则通过选举算法产生Leader,其他Follower作为备份。
Coordinator会定期(默认一分钟)同步Zookeeper中整个集群的数据拓扑图、元信息库中所有有效的Segment信息以及规则库,从而决定下一步应该做什么。对于有效且未分配的Segment,Coordinator Node首先按照Historical Node的容量进行倒序排序,即最少容量拥有最高优先级,新的Segment会优先分配到高优先级的Historical Node上。由3.3.4.1节可知,Coordinator Node不会直接与Historical Node打交道,而是在Zookeeper中Historical Node对应的load queue目录下创建待加载Segment的临时信息,等待Historical Node去加载该Segment。
Coordinator在每次启动后都会对比Zookeeper中保存的当前数据拓扑图以及元信息库中保存的数据信息,所有在集群中已被加载的、却在元信息库中标记为失效或者不存在的Segment会被Coordinator Node记录在remove list中,其中也包括我们在3.3.3节中所述的同一Segment对应的新旧version,旧version的Segments同样也会被放入到remove list中,最终被逻辑丢弃。
对于离线的Historical Node,Coordinator Node会默认该Historical Node上所有的Segment已失效,从而通知集群内的其他Historical Node去加载该Segment。但是,在生产环境中,我们会遇到机器临时下线,Historical Node在很短时间内恢复服务的情况,那么如此“简单粗暴”的策略势必会加重整个集群内的网络负载。对于这种场景,Coordinator会为集群内所有已丢弃的Segment保存一个生存时间(lifetime),这个生存时间表示Coordinator Node在该Segment被标记为丢弃后,允许不被重新分配最长等待时间,如果该Historical Node在该时间内重新上线,则Segment会被重新置为有效,如果超过该时间则会按照加载规则重新分配到其他Historical Node上。
考虑一种最极端的情况,如果集群内所有的Coordinator Node都停止服务,整个集群对外依然有效,不过新Segment不会被加载,过期的Segment也不会被丢弃,即整个集群内的数据拓扑会一直保持不变,直到新的Coordinator Node服务上线。
监控Historical节点组,以确保数据可用、可复制,并且在一般的“最佳”配置。它们通过从MySQL读取数据段的元数据信息,来决定哪些数据段应该在集群中被加载,使用Zookeeper来确定哪个Historical节点存在,并且创建Zookeeper条目告诉Historical节点加载和删除新数据段。
Druid的Coordinator主要负责数据的管理和在Historical Node上的分布。Coordinator告诉Historical Node加载新数据、卸载过期数据、复制数据、和为了负载均衡移动数据。Druid为了维持稳定的视图,使用一个多版本的并发控制交换协议来管理不可变的segment。如果任何不可变的segment包含的数据已经被新的segment完全淘汰了,则过期的segment会从集群中卸载掉。Coordinator会经历一个leader选举的过程,来决定由一个独立的节点来执行协调功能,其余的Coordinator则作为冗余备份节点。
Coordinator会周期性的执行,以确定集群的当前状态。它通过在运行的时候对比集群的预期状态和集群的实际状态来做决定。和所有的Druid节点一样,Coordinator维持一个和Zookeeper的连接来获取当前集群的信息。同时Coordinator也维持一个与MySQL数据库的连接,mysql包含有更多的操作参数和配置信息。其中一个存在于MySQL的关键信息就是Historical Node可以提供服务的所有segment的一个清单,这个表可以由任何可以创建segment的服务进行更新,例如Realtime Node。MySQL数据库中还包含一个Rule表来控制集群中segment的是如何创建、销毁和复制。
一、Rules
Rules管理历史segment是如何在集群中加载和卸载的。Rules指示segment应该如何分配到不同的Historical Nodetier中,每一个tier中应该保存多少份segment的副本。Rules还可能指示segment何时应该从集群中完全地卸载。Rules通常设定为一段时间,例如,一个用户可能使用Rules来将最近一个月的有价值的segment载入到一个“热点数据”的集群中,最近一年的有价值的数据载入到一个“冷数据”的集群中,而将更早时间前的数据都卸载掉。
Coordinator从MySQL数据库中的rule表加载一组rules。Rules可能被指定到一个特定的数据源,或者配置一组默认的rules。Coordinator会循环所有可用segment并会匹配第一条适用于它的rule。
二、负载均衡
在典型的生产环境中,查询通常命中数打甚至上百个segment,由于每个Historical Node的资源是有限的,segment必须被分布到整个集群中,以确保集群的负载不会过于不平衡。要确定最佳的负载分布,需要对查询模式和速度有一定的了解。通常,查询会覆盖一个独立数据源中最近的一段邻近时间的一批segment。平均来说,查询更小的segment则更快。
这些查询模式提出以更高的比率对历史segment进行复制,把大的segment以时间相近的形式分散到多个不同的Historical Node中,并且使存在于不同数据源的segment集中在一起。为了使集群中segment达到最佳的分布和均衡,我们根据segment的数据源、新旧程度、和大小,开发了一个基于成本的优化程序。该算法的具体细节超出了本文的范畴。
三、 副本
Coordinator可能会告诉不同的Historical Node加载同一个segment的副本。和HDFS的副本block类似策略,每个segment会存在多个Historical Node中。每一个Historical Node tier中副本的数量是完全可配置。设置一个高级别容错性的集群可以设置一个比较高数量的副本数。segment的副本被视为和原始segment一样的,并使用相同的负载均衡算法。通过复制segment,单一Historical Node故障对于整个Druid集群来说是透明的,不会有任何影响。我们使用这个特性来进行软件升级。我们可以无缝地将一个Historical Node下线,更新它,再启动回来,然后将这个过程在集群中所有Historical Node上重复。在过去的两年中,我们的Druid集群从来没有因为软件升级而出现过停机。
四、可用性
Druid的Coordinator有Zookeeper和MySQL这两个额外的依赖,Coordinator依赖Zookeeper来确定集群中有哪些Historical Node。如果Zookeeper变为不可用,Coordinator将不可以再进行segment的分配、均衡和卸载指令的发送。不过,这些都不会影响数据的可用性。
对于MySQL和Zookeeper响应失效的设计原则是一致的:如果Coordinator一个额外的依赖响应失败了,集群会维持现状。Druid使用MySQL来存储操作管理信息和关于segment如何存在于集群中的segment元数据。如果MySQL下线了,这些信息就在Coordinator中变得不可用,不过这不代表数据不可用。如果Coordinator不可以和MySQL进行通信,他们会停止分配新的segment和卸载过期的segment。在MySQL故障期间Broker节点、Historical Node、Realtime Node都是仍然可以查询的。