跳至内容
GitHub 仓库 论坛 RSS 新闻提要

LavinMQ:理解代码以获得最佳性能

Beta Ziliani

使用 Crystal 构建 LavinMQ 是一个主动的选择,因为保持对代码库的控制是重中之重。十年的学习经验优先考虑快速更新和轻松的错误修复。同时,选择 Crystal 为我们提供了提升应用程序性能的机会。

LavinMQ 由 84codes 的经验丰富的开发人员构建,他们是最大的云消息传递平台之一 CloudAMQP 的创始人。LavinMQ 通过优先确保稳定通信和可靠消息传递在服务内和服务之间,旨在快速有效地处理数据,同时允许解耦的系统组件独立运行并根据需要进行扩展。

LavinMQ 可以处理发布者、队列和消费者之间的众多连接,这通常是物联网架构中的一个要求。它是一个开源的消息代理,经过预优化,与其他代理相比速度极快,可以轻松处理每秒 100 万条消息。

LavinMQ 包含了人们最需要的功能,并且仅占用了少量内存,支持

  • 流式传输
  • 灵活路由
  • AMQP 0.9.1 协议
  • 确认和确认
  • 流队列
  • 无限队列长度(取决于磁盘空间)
  • 复制

我们强调了从技术角度突出的特点。它如何实现每秒处理超过一百万条消息,并且内存占用量很低?其中一半是由于,我们引用

消息写入磁盘的速度非常快,并且缓存由操作系统本身管理。这在保持 RAM 占用量低的同时提高了性能。

但是,正如他们在 博客 中提到的,另一半是由于它使用 Crystal 开发的。这在几个方面很有趣。

  1. Crystal 由于其 LLVM 后端而得到高效编译。这使得可以进行积极的优化,例如内联方法和消除间接调用。

  2. Crystal 帮助开发人员将他们的数据分配到堆或栈上。堆分配很昂贵,因此在程序的热路径上将数据分配到栈上会带来重要的性能提升。Crystal 使得轻松选择数据应该存储在何处。

  3. Crystal 的 stdlib 和编译器是用 Crystal 本身编写的。Crystal 的一个黄金特点是其可读性,这使得能够阅读程序将要运行的代码,而无需诉诸其他,通常是更低级的语言。

后一点是本文的重点。事实上,标准库的文档指向代码,这使得调用特定方法的性能影响变得明确。例如,请查看 Digest.file 的文档。点击 查看源代码,我们就会进入该方法的代码。

能够阅读、理解甚至为语言及其 stdlib 做出贡献的重要性在 84codes 对 Crystal 的 一个 多个 PR 中得到了体现。细节并不重要,但如果你好奇,他们注意到在上面提到的 io 对象中存在缓冲区重复。以下摘录显示了贡献的主要部分;带有一个添加行的差异,并解释了为什么在 io 对象中删除缓冲区是合理的。

diff --git a/src/digest/digest.cr b/src/digest/digest.cr
index e6a401e90545..bc38599da7f8 100644
--- a/src/digest/digest.cr
+++ b/src/digest/digest.cr
@@ -213,6 +213,7 @@ abstract class Digest
   # Reads the file's content and updates the digest with it.
   def file(file_name : Path | String) : self
     File.open(file_name) do |io|
+      # `#update` works with big buffers so there's no need for additional read buffering in the file
+      io.read_buffering = false
       self << io
     end
   end

只有一行代码,但它会对应用程序产生显著的影响。应用程序和代码所依赖的库使用相同的语言,这对于理解代码的行为及其性能影响是一个巨大的优势。

在结束之前,我们想指出,84codes 不仅负责对标准库进行大量改进:84codes 也是支持 Crystal 开发的主要赞助商。为了进一步突破语言的极限,在撰写本文时,他们正在支持一项大型努力,以改进 Crystal 程序的 并行执行。也许下一版本的 LavinMQ 将借助 Crystal 团队的力量进一步突破极限!

Photo of Carl Hörberg

Carl Hörberg,84codes 首席执行官

Crystal 以独特的方式平衡了可读性和性能。此外,我们能够通过理解运行我们的应用程序的底层代码来提升应用程序的性能。