首先需要注意的是,本文即将提到的 Druid,并非阿里巴巴的 Druid 数据库连接池,而是另一个大数据场景下的解决方案:Apache Druid。
Apache Druid 是一个用于大数据实时查询和分析的高容错、高性能开源分布式时序数据库系统,旨在快速处理大规模的数据,并能够实现快速查询和分析。尤其是当发生代码部署、机器故障以及其他产品系统遇到宕机等情况时,Druid 仍能够保持 100% 正常运行。创建 Druid 的最初意图主要是为了解决查询延迟问题,当时试图使用 Hadoop 来实现交互式查询分析,但是很难满足实时分析的需要。而 Druid 提供了以交互方式访问数据的能力,并权衡了查询的灵活性和性能而采取了特殊的存储格式。
目前 Druid 广泛应用在国内外各个公司,比如阿里,滴滴,知乎,360,eBay,Hulu 等。
本文作者 Mohan Garadi 披露了 eBay 如何使用 Druid 进行监控的技术细节。
在 eBay 中,我们将监控技术栈从传统的本地架构转换为基于 Druid 的实时监控系统。在本文中,我们将讨论如何过渡到新技术栈,以及它为我们带来了什么好处。
eBay 每天要支撑数百万用户进行电子商务交易。随着支持不同产品的各种应用所产生的数据爆炸式增长,用户数量也在大幅增长。日志是应用程序的核心,用于决定应用程序执行哪些操作。随着应用程序大小的增长,日志变得很难进行可视化。我们还有一个集中式日志存储来处理所有日志,要直接从日志中获取有用的信息非常困难,而且从日志中实时获取有用信息的想法也不可行。在 eBay 中,监控团队以不同的方式对问题进行可视化。解决问题的更好方法是:从日志中提取有用事件并通过数据管理处理这些事件。
事件的数量直接与根据当前系统的流量生成的日志数量相关。一些应用程序可能会生成数百到数千个事件,而其他应用程序可能会生成数百万个事件。我们的兴趣是基于从日志中提取的事件来监控各个应用程序的执行情况,以及在系统中出现太多错误或异常行为时提醒用户的能力。
应用程序事件包括错误状态代码、url 事务、命令执行以及在不同主机上的应用程序项目的构建 ID 等。这些事件都有不同的目的。
应用程序开发人员和网站可靠性管理(Site reliability engineering,SRE)团队都会对这些事件感兴趣,因为他们可以实时监控应用程序的性能。它们能够将系统中发生的错误数量以可视化的形式呈现,通过命令执行对这些错误进行切片和切块,并构建导致这些错误的程序,然后根据可能影响应用程序性能的错误阈值设置警报。
当应用程序开发团队必须在生产中部署应用程序的新项目时,这些信息提供了关键的洞见。他们将能够在一小部分主机上进行代码的抽样部署(sampled rollout),并可视化实时仪表盘,以确定新代码在生成错误方面的行为,然后将实时数据与历史数据进行比较,从而提供一定程度的可信度。
传统架构
传统架构是多年前设计的,当时整个站点每天生成的事件数量大约为 1000 万次。这在当时是可扩展的,并且在未来几年内也可以进行扩展。
随着时间的推移,传统架构暴露了一些缺点:
多维数据集生成是每个时间间隔的自定义编写代码。生成当前时间的数据通常需要几分钟,这对于实时监控而言是不可接受的。而且这种延迟随着数据量的增加而增加。
随着数据量的增加,自定义多维数据生成的可扩展性随时间的推移效果变得较差。
在维度基数非常高(几十万到几百万种组合)的情况下,生成速度缓慢或无法创建多维数据集。
新架构
在新的架构中,已删除 Tibco 依赖项,并将 Kafka 用做临时保存信息以供使用的层。Tranquilty 用于使用来自 Kafka 的数据并输入 Druid。
新架构的要点如下:
从时间生成到出口实现的最小端到端延迟(对于非常大的应用程序,最大不超过 10 秒)。
使用 Druid 处理多种粒度的数据,如 1 分钟、1 刻钟、1 小时等。重新索引 1 天间隔的数据。
Kubernetes 部署使我们在升级或维护时,能够在几分钟之内删除集群并重新创建集群。使用 100 个节点执行滚动更新非常容易。
Druid 可有效地处理高基数数据,只要为索引任务提供足够的可扩展性,即使是数以百万计的纬度值,也可以使用 Druid 来处理,而不会产生任何额外的延迟,索引任务可在零停机时间内实现。
(Tibco 是一种用于数据传输的企业消息总线。Tranquilty 是 Druid-io 的一部分,它带了一个将数据流发送到 Druid 的 API。)
事件处理
事件包括系统中发生的事情,这些事情从本质上来讲是零星的。一些应用程序每天会生成一些事件,而其他应用程序在一分钟内会生成数百万个事件。不同类型的事件可根据它们的用途来生成。我们在此背景下讨论监控事件。
在我们的用例中,数据具有一个固定的维度键(11 维),一个时间戳和两个要计算的度量:计数和延迟。计数是在特定时间戳收集数据时主机发生的事件数量。延迟表示所有事务的延迟总和。跨应用程序的数千个主机可能会生成数以百万计的事件,每个事件可以包含不同的纬度值集。每个应用程序的每个维度的纬度值可以从十到几千不等。
开发团队和 SRE 团队对上述事件很感兴趣,以了解特定应用程序或多个应用程序在网站上发生错误的数量,这些错误可能会造成很大影响。将每分钟几百万个事件实时收集到集中式存储并对其进行处理,会带来一系列事关准确性、速度、可靠性和弹性方面的挑战。
扩展
监控事件在整个集群中,以每秒 800 万个事件的速度生成,在高峰流量时平均为每秒 1000 万个事件,这些来自 5000 多个应用程序。监控事件需要跨多个维度进行切片和切块,例如应用程序名称、应用程序类型、操作名称、错误状态、运行应用程序的构建、主机等。所有数据都应以近实时服务级别协议进行汇总和提供。共有 11 个固定维度,所有维度的纬度值基数在 140 万到 200 万个唯一组合之间。
我们的 Druid 集群部署在多个可用区域,以实现高可用性,并保持每个数据中心的每个示例保留 2 个副本。这使得我们可以在 2 个数据中心共有 4 个副本可用。每个数据中心都有几百个中间管理器、2 个统治 + 协调(Overlord+Coordinator)节点,15 个代理节点和 80 个历史节点。
峰值数据流量如下图所示。
出口设计
数据出口的设计目标是保持数据的高可用性。Druid 代理前面的一层被设计用于查询 Druid 的数据,以确定每个数据中心的健康状况。我们希望两个数据中心的运行状况始终保持在最佳状态,且高度可用。如果任何数据中心出现任何数据丢失的情况,出口会切换到数据质量更好的集群。
我们每分钟从每个集群中获取事件计数,以确定两个集群是否具有相似的数据(偏差小于集群之间的事件计数差异的 0.5%)。如果偏差过大,我们则选择事件计数更好的集群。计算每分钟进行一次,我们继续更新集群的运行状况,以确定能够在一段时间内为数据提供服务的最佳集群。如果检测到任何数据丢失,我们还会标记集群,这样就不会有任何查询进入有问题的集群的代理节点进行查询。
我们支持早期版本的 Druid 所支持的各种粒度(1 分钟、1 刻钟、1 小时、1 天),这取决于查询数据的时间长度。这种粒度的选择是自动进行的。在需要时,由于查询的数据量很大,可以强制粒度以更长的时间段获取更细粒度的数据,但要付出响应时间的代价。
结论
对于站点监控和事件跟踪而言,带有需要实时或近实时聚合的高基数数据的用例,对于像 eBay 这样的大型生态系统做出数据驱动的决策至关重要。像 Druid 这样的分析存储可以提供洞见的能力,从监控的角度来说非常有价值,也很重要;很多团队和开发人员都依赖维护 eBay 客户系统的可用性和可靠性。
参考资料
本文中对 Druid 的所有引用都是指 Druid 开源版本,请参考以下链接:
评论