当前位置: 首页 > 工具软件 > Chronicle > 使用案例 >

(00)Chronicle Queue 介绍

宗晟
2023-12-01

概述

Chronicle Queue 是用于高性能应用程序的持久化低延迟消息传递框架。

该项目涵盖了 Chronicle Queue 的 Java 版本。 该项目的 C++ 版本也可用,它支持 Java/C++ 互操作性以及其他语言绑定,例如 Python。 如果您有兴趣评估 C++ 版本,请联系 sales@chronicle.software

乍一看,Chronicle Queue 可以简单地看作是另一个队列实现。 但是,它有一些应该强调的主要设计选择。 使用 堆外存储,Chronicle Queue 提供了一个应用程序不受垃圾收集 (GC) 影响的环境。 在 Java 中实现高性能和内存密集型应用程序(您听说过“大数据”这个奇特的术语吗?)时,最大的问题之一就是垃圾回收。

Chronicle Queue 允许将消息添加到队列的末尾(“appended”),从队列中读取(“tailed”),并且还支持随机访问搜索。

什么是 Chronicle Queue?

您可以将 Chronicle Queue 视为类似于低延迟、无代理的持久主题,它可以包含不同类型和大小的消息。 Chronicle Queue 是一个分布式无界持久化队列:

  • 支持具有微秒延迟的异步 RMI 和发布/订阅接口。
  • 在1微秒内在 JVM 之间传递消息
  • 在 10 微秒内通过复制在不同机器上的 JVM 之间传递消息(企业功能)
  • 为单个线程到1个队列每秒数百万条消息提供稳定、软的实时延迟; 对每个事件进行总排序。为1个队列的单个线程提供稳定的软实时延迟,每秒可传输数百万条消息;对每个事件进行总排序。

当发布40字节的消息时,我们在很大程度上实现了1微秒以下的延迟。第99百分位的延迟是最差的1/100,第99.9百分位的延迟是最差的1/1000。

表 1. 在同一台机器上发送/接收的延迟。

批量大小每分钟1000万个事件每分钟6000万个事件每分钟1亿个事件
99%ile0.78 µs0.78 µs1.2 µs
99.9%ile1.2 µs1.3 µs1.5 µs

表 2. 在第二台机器上发送/接收的延迟。

批量大小每分钟1000万个事件每分钟6000万个事件每分钟1亿个事件
99%ile20 µs28 µs176 µs
99.9%ile901 µs705 µs5,370 µs

注意: 每分钟 1 亿个事件是每 660 纳秒发送一个事件; 复制并持久化。

重要: 使用大的机器集群无法实现此性能。这里只使用一个线程发布,一个线程消费。

设计动机和特点

Chronicle Queue 旨在:

  • 成为一个“记录所有内容的存储”,可以以微秒的实时延迟读取。这甚至支持最苛刻的高频交易系统。但是,它可以在任何需要记录信息的应用程序中使用。
  • 支持可靠复制,当成功复制消息时,可以通知appender(消息的编写者)或tailer(消息的读取者)。

持久化

Chronicle Queue 假设磁盘空间比内存便宜。 Chronicle Queue 充分利用您拥有的磁盘空间,因此您不受机器主内存的限制。 如果您使用硬盘,您可以以很少的成本存储许多 TB 的磁盘空间。

Chronicle Queue 需要运行的唯一额外软件是操作系统。 它没有经纪人(broker); 相反,它使用您的操作系统来完成所有工作。 如果您的应用程序死机,操作系统会继续运行几秒钟,因此不会丢失任何数据; 甚至无需复制。

由于 Chronicle Queue 将所有保存的数据存储在内存映射文件中,因此即使您有超过 100 TB 的数据,堆上开销也很小。

效率

Chronicle 投入了大量精力来实现极低的延迟。 在其他侧重于支持 Web 应用程序的产品中,低于 40 毫秒的延迟就很好,因为它们比您看到的要快; 例如,电影的帧频为 24 赫兹,即约 40 毫秒。

Chronicle Queue 的目标是在 99% 到 99.99% 的时间内实现低于 40 微秒的延迟。 使用不带复制的 Chronicle Queue,我们支持跨多个服务的端到端延迟低于 40 微秒的应用程序。 Chronicle Queue 的 99% 延迟通常完全取决于操作系统和硬盘子系统的选择。

压缩

Chronicle Wire Enterprise 版本支持Chronicle Queue 的复制。 这支持实时压缩,在写入时计算单个对象的增量。 这可以将消息的大小减少 10 倍或更好,而无需进行批处理; 也就是说,不会引入明显的延迟。

Chronicle Queue 还支持 LZW、Snappy 和 GZIP 压缩。 然而,这些格式会显着增加延迟。 这些仅在您对网络带宽有严格限制时才有用。

传递模式语义

Chronicle Queue 支持多种语义:

  • 每条消息都会在重新启动时重放。
  • 重启时只重放新消息。
  • 使用条目的索引从任何已知点重新开始。
  • 只重放您错过的消息。 这是直接使用 methodReader/methodWriter 构建器支持的。

跨机器使用高分辨率计时

在大多数系统上,System.nanoTime() 大致是自系统上次重启以来的纳秒数(尽管不同的 JVM 可能表现不同)。 这在同一台机器上的 JVM 之间是相同的,但在机器之间却大不相同。 就机器而言,绝对差异是没有意义的。 但是,该信息可用于检测异常值; 你无法确定最佳延迟是多少,但你可以确定距离最佳延迟有多远。如果您关注第 99 个百分位数的延迟,这将很有用。 我们有一个名为RunningMinimum的类,用于从不同机器获取计时,同时补偿机器之间nanoTime的漂移。 您进行测量的次数越多,这个运行最小值就越准确。

压缩日志

Chronicle Queue 按周期管理存储。 您可以添加一个StoreFileListener,它会在添加文件和不再保留文件时通知您。 您可以一次移动、压缩或删除一天的所有消息。

注意: 不幸的是,在 Windows 上,如果 IO 操作被中断,它会关闭底层的 FileChannel。

避免中断

由于性能原因,我们删除了历史记录队列代码中的中断检查。 因此,我们建议您避免将 Chronicle Queue 与生成中断的代码一起使用。 如果您无法避免产生中断,那么我们建议您为每个线程创建一个单独的 Chronicle Queue 实例。

用法

Chronicle Queue 最常用于以生产者为中心的系统,您需要在这些系统中保留大量数据数天或数年。 有关统计信息,请参阅 Chronicle-Queue 的使用

重要: Chronicle Queue 支持在任何网络文件系统上运行,无论是 NFS、AFS、基于 SAN 的存储还是其他任何系统。 原因是那些文件系统没有为内存映射文件提供所有必需的原语来让 Chronicle Queue 使用。 如果需要任何网络(例如,使多个主机可以访问数据),唯一受支持的方法是 Chronicle Queue Replication(企业功能)。

什么是以生产者为中心的系统?

大多数消息传递系统都是以消费者为中心的。 实施流量控制是为了避免消费者过载; 甚至是瞬间。 一个常见的例子是支持多个 GUI 用户的服务器。 这些用户可能在不同的机器(操作系统和硬件)、不同质量的网络(延迟和带宽)上,在不同的时间做各种其他事情。 出于这个原因,客户端消费者告诉生产者何时退出,延迟任何数据,直到消费者准备好获取更多数据是有意义的。

Chronicle Queue 是一个以生产者为中心的解决方案,它会尽一切可能永远不会对生产者施加压力,或让它放慢速度。 这使它成为一个强大的工具,在您的系统和您几乎无法控制或根本无法控制的上游生产者之间提供一个很大的缓冲区。

市场数据

市场数据发布者不会让您选择长期拒绝生产者; 如果有的话。 我们的一些用户使用 CME OPRA 的数据。 这会产生每分钟 1000 万个事件的峰值,作为 UDP 数据包发送,无需重试。 如果您错过或丢弃了一个数据包,那么它就丢失了。 您必须尽可能快地使用和记录这些数据包,并且网络适配器中的缓冲非常少。 特别是对于市场数据,实时意味着几微秒; 这并不意味着当天(白天)。

Chronicle Queue 快速高效,已被用于提高线程间数据传递的速度。 此外,它还会记录每条传递的消息,使您能够显着减少需要执行的日志记录量。

合规系统

现在越来越多的系统需要合规系统。 每个人都必须拥有它们,但没有人愿意被它们拖慢脚步。 通过使用 Chronicle Queue 在受监控系统和合规系统之间缓冲数据,您无需担心合规记录对受监控系统的影响。 同样,Chronicle Queue 可以支持每台服务器每秒数百万个事件,并访问已保留多年的数据。

对延迟敏感的微服务

Chronicle Queue 支持同一台机器上 JVM 之间 1 微秒数量级的低延迟 IPC(进程间通信); 以及在典型延迟为 10 微秒的机器之间,以实现几十万的适度吞吐量。 Chronicle Queue 支持每秒数百万个事件的吞吐量,具有稳定的微秒级延迟。

参见Chronicle Queue在微服务中的使用文章

日志替换

Chronicle Queue 可用于构建状态机。 有关这些组件状态的所有信息都可以在外部复制,无需直接访问组件或其状态。 这显着减少了对额外日志记录的需求。 但是,可以非常详细地记录您确实需要的任何日志记录。 这使得在生产环境中启用“DEBUG”日志变得切实可行。 这是因为日志记录的成本非常低; 小于 10 微秒。 可以集中复制日志以进行日志合并。 Chronicle Queue 用于存储 100+ TB 的数据,可以从任何时间点重播。

Lambda 流处理

非批处理流组件具有高性能、确定性和可重现性。 您可以重现仅在以特定顺序播放一百万个事件后才会出现的错误,并加速逼真的计时。 这使得使用流处理对于需要高质量结果的系统具有吸引力。

Chronicle Queue 版本和显着变化

从版本 4 到版本 5 的更改

Chronicle Queue v5 中,tailer 现在是只读的,在 Chronicle Queue v4 中,我们有惰性索引的概念,其中 appender 不会写入索引,而是由 tailer 完成索引,或者更准确地说, 当惰性索引打开时,索引由读取数据的第一个 tailer 完成。 因为在 v4 中,tailers 可以进行索引,所以我们不能依赖它们是只读的。 我们决定在 v5 中放弃惰性索引。 将 tailers 设置为只读不仅可以简化 Chronicle Queue,还可以让我们在代码的其他地方添加优化。

Chronicle Queue 的锁定模型在 v5 中发生了变化,在 Chronicle Queue v4 中,.cq4 文件中存在写锁(以防止并发写入队列)。 在 v5 中,这被移动到一个名为表存储 (metadata.cq4t) 的文件中。 这在内部简化了锁定代码,因为只需要检查表存储文件。

您可以使用 Chronicle Queue v5 读取使用 Chronicle Queue v4 编写的消息,但是您不应同时运行 Chronicle Queue v4 和 Chronicle Queue v5。 换句话说,避免在同时通过 Chronicle Queue v5 读取和写入的队列上运行 Chronicle Queue v4 的 appender 和 tailers。

从版本 3 到版本 4 的更改

Chronicle Queue v4 是对 Chronicle Queue 的完全重写,解决了 v3 中存在的以下问题。

  • 如果没有自描述消息,用户必须创建自己的转储消息和长期存储数据的功能。 使用 v4,您不必这样做,但如果您愿意,也可以这样做。

  • Vanilla Chronicle Queue 会为每个线程创建一个文件。 如果线程数受到控制,这很好,但是,许多应用程序很少或根本无法控制使用多少线程,这会导致可用性问题。

  • Indexed 和 Vanilla Chronicle 的配置完全在代码中,因此读者必须拥有与作者相同的配置,而且并不总是很清楚那是什么。

  • 生产者无法知道有多少数据已复制到第二台机器。 唯一的解决方法是将数据复制回生产者。

  • 在开始编写消息之前,您需要指定要保留的数据大小。

  • 在使用 Indexed Chronicle 时,您需要为 appender 进行自己的锁定。


<<<<<<<<<<<< [完] >>>>>>>>>>>>

 类似资料: