使用LMAX Disruptor构建快速、线程安全的热点跟踪库

本文介绍了如何使用LMAX Disruptor来构建一个快速、线程安全和内存高效的热点跟踪库。通过解决并发、内存限制和性能问题,实现了在高基数数据流中高效跟踪热点的目标。
摘要由CSDN通过智能技术生成

LMAX Disruptor 是 Java 中最好的库之一,用于构建具有无锁队列的有界队列。Hubspot 撰写了有关 LMAX Disruptor 如何帮助构建快速、线程安全的跟踪库的文章:

HubSpot 的用例是单个进程中的多个线程需要协调以在高基数数据流中查找最频繁的项目。在这篇博文中,我们以一种快速、线程安全和内存高效的方式描述了我们的设计。

HubSpot 后端的 Web 服务都运行大量线程,用于同时处理多个 HTTP 请求。我们处理的大部分工作负载都是 I/O 绑定的,因此通常需要使用大量线程运行我们的 Web 服务才能获得充分的 CPU 利用率。

多年来,我们的 Web 服务经常遇到的一个问题是接收大量并发请求,每个请求都要求我们从后备数据库中获取同一行。这种访问模式会降低我们 API 的性能,因为所有这些请求都转到后备数据库的同一个节点,可能会使其过载。

我们将此场景称为热点,它会使我们的用户体验缓慢且不可靠。

发生这种情况时,为了缓解问题,我们需要能够跟踪哪些行被频繁访问。

换句话说,我们需要知道哪些数据行是“热的”。

我们将首先介绍热点跟踪系统的简单、幼稚设计。我们将讨论为什么这种方法不起作用,然后我们将迭代设计并进行改进,直到我们的设计达到快速、线程安全和内存高效的地方。如果您从事并发编程,尤其是在 Java 中,希望这能激发您的想象力并为您提供可以在未来应用的想法。

原始方式

假设我们有一个 Web 服务,调用者发出 HTTP 请求以获取一些资源,并且每个资源都由一个字符串唯一标识。为了处理请求资源 XYZ 的 HTTP 请求,我们做两件事:

  1. 记录在我们的热点跟踪器中请求资源 XYZ 的事实。这将帮助我们检测资源 XYZ 是否很热。
  2. 从数据库中获取资源 XYZ 的数据(例如,SELECT * from table where id = XYZ)并将该数据返回给调用者。

对于第 1 步,我们的 Web 服务的每个实例都将拥有一个 HotspotTracker 对象。这个单例 HotspotTracker 将在进程中的所有 HTTP 请求线程之间共享。一个简单的实现可能看起来像这样:

为简洁起见,此处未显示,但后台线程将每分钟运行一次并执行以下操作:

  1. 报告前一分钟计数最高的十个ID(即报告最热的ID)
  2. 清除 countsById map

这种每分钟一次的热 ID 报告可以记录下来供工程师稍后查看,或者它也可以暴露给应用程序的其他部分,因此我们可以对热 ID 应用特殊处理( 如这里 )。

如果你熟悉 Java 中的并发编程,你就会知道上面的设计是行不通的,因为 HashMap 不是线程安全的。并发运行的 HTTP 请求需要安全地共享这个 HotSpotTracker,所以我们需要使用线程安全的数据结构。更正确的实现可能如下所示:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值