技术干货

更多场景、更多选择,Milvus 新消息队列 NATS 了解一下

2023-09-13
叶桢

叶桢

更多场景、更多选择,Milvus 新消息队列 NATS 了解一下

在 Milvus 的云原生架构中,消息队列(Log Broker)可谓任重道远,它不仅要具备流式数据持久性、支持 TT 同步、事件通知等能力,还要确保工作节点从系统崩溃中恢复时增量数据的完整性。

在 Milvus 的架构中,一切围绕消息队列构建,遵循日志结构化存储的原则,消息队列在 Milvus 中的作用可以类比于传统数据库的 WAL(Redo Log)的角色。在 Milvus 2.3 之前,Milvus 官方支持 RocksMQ(Standalone 模式限定,Milvus 官方基于 RockDB 实现的 MQ 系统),以及 Pulsar、Kafka 等传统 MQ。

在 Milvus Standalone 模式下,相比于 Pulsar 和 Kafka,RocksMQ 是最简单的 MQ 部署方案。但由于 RocksMQ 基于 RocksDB,在大消息体以及海量消息的场景下性能表现一般。同时 RocksMQ 需要 rocksdb,频繁的调用 CGO,带来额外的性能负担。在 Milvus 2.3中,Milvus Standalone 最新引入了新的基于 NATS 的单机 MQ 实现,给用户提供在不同的使用场景下更多的 MQ 选择。

本文将介绍新 MQ 的使用方式以及与其他 MQ 的对比。

01.什么是 NATS

NATS 是 GO 实现的分布式系统连接技术,支持 Request-Reply、Publish-Subscribe 等跨系统沟通模式,通过底层的 JetStream 支持数据的持久化,以及内置的 RAFT 来提供分布式能力。想要系统的了解 NATS,可以查看官方网站:https://nats.io/

NATS 支持的 Feature 非常多,在 Milvus 2.3 standalone 模式下,Milvus 利用单机版的 NATS+JetStream+PubSub 模式提供 MQ 能力。同时,Nats-server 被 Embedding 进了 Milvus 的程序中,不需要额外的 NATS 部署即可实现 NATSMQ。

02.如何启用 NATS

在 Milvus 2.3中,新引入了mq.type作为 MQ 类型的控制选项,为了保持向上兼容,NATS 不会进入默认的 MQ 选择优先级中,需要使用mq.type=natsmq强制指定。在 Milvus 实例启动后,如果看到以下的日志,则说明 Milvus使用了 NATS 作为 MQ。

[INFO] [dependency/factory.go:83] ["try to init mq"] [standalone=true] [mqType=natsmq]

03.NATS 配置项详解

当前配置项支持下述的定制化配置能力:

natsmq:
  server: # server side configuration for natsmq.
    port: 4222 # 4222 by default, Port for nats server listening.
    storeDir: /var/lib/milvus/nats # /var/lib/milvus/nats by default, directory to use for JetStream storage of nats.
    maxFileStore: 17179869184 # (B) 16GB by default, Maximum size of the 'file' storage.
    maxPayload: 8388608 # (B) 8MB by default, Maximum number of bytes in a message payload.
    maxPending: 67108864 # (B) 64MB by default, Maximum number of bytes buffered for a connection Applies to client connections.
    initializeTimeout: 4000 # (ms) 4s by default, waiting for initialization of natsmq finished.
    monitor:
      trace: false # false by default, If true enable protocol trace log messages.
      debug: false # false by default, If true enable debug log messages.
      logTime: true # true by default, If set to false, log without timestamps.
      logFile: /tmp/milvus/logs/nats.log # /tmp/milvus/logs/nats.log by default, Log file path relative to .. of milvus binary if use relative path.
      logSizeLimit: 536870912 # (B) 512MB by default, Size in bytes after the log file rolls over to a new one.
    retention:
      maxAge: 4320 # (min) 3 days by default, Maximum age of any message in the P-channel.
      maxBytes: # (B) None by default, How many bytes the single P-channel may contain. Removing oldest messages if the P-channel exceeds this size.
      maxMsgs: # None by default, How many message the single P-channel may contain. Removing oldest messages if the P-channel exceeds this limit.
  • server.port:由于 Nats 为 C-S 模式程序,当前不支持使用类似于 unix socket 等不占用端口的套接字方案,当前在 Milvus 中需要指定server.port作为 NATS Server 的端口,如果出现端口冲突,则 Milvus 不能正常启动。填写server.port=-1,可以随机选择端口。
  • storeDir:用于指定底层的 JetStream 持久化机制的存储目录,建议将该目录挂载在高性能的 SSD 上来提升 Milvus 的读写吞吐。如果出现 Milvus 无法启动的情况,请检查该目录是否存在或者目录的使用权限。
  • maxFileStore:用于限制 JetStream 的存储量上限,如果超出该上限将会出现禁止写入的情况。
  • maxPayload:单个消息的硬大小限制,Milvus 最大的消息chunk支持到5MB,因此该配置应该要保持在5MB以上并留有一定的余量,否则可能出现 Milvus 拒绝写入的情况。
  • initializeTimeout:用于控制 Milvus 启动时,Nats Server 的启动超时配置。如果出现以下日志,可以适当调高该配置。
[WARN] [nmq/nmq_server.go:77] ["nmq is not ready within timeout"]
  • monitor:用于配置 NATS 的独立日志,建议在日常运行环境中启用 trace 日志。
  • retention:用于控制 NATS 消息的保持机制,由于当前 Milvus 的消息保持机制与消息消费机制尚未实现同步。因此请务必保持该配置有充足的余量,让 Milvus 可以在消息被消息队列清退前消费完毕,否则 Milvus 可能会出现数据丢失的情况。

以上的绝大部分配置都与 NATS 官方配置对齐,如果需要了解更多的配置,或者希望 Milvus 引入更多的定制化配置,可以查看 NATS 的官方文档 https://docs.nats.io/running-a-nats-service/config

04.RocksMQ 迁移至 NATS

可以采用 Milvus 的通用 MQ 迁移方案。

  • 停止 Milvus 一切的写入操作。
  • 调用 FlushALL 操作,等待 FlushALL 完毕后,关闭Milvus 进程。
  • 修改配置项 mq.type=natsmq,以及 natsmq下相关需要修改的配置项(如果出现端口冲突或者目录权限等问题)
  • 启动 2.3 版本的 Milvus 进程:
    • 日志应当出现mqType=natsmq日志。
    • natsm.server.storeDir配置的目录下应当出现 jetstream 文件夹。
  • 可选:备份并清理原rocksmq.path存储目录下的文件数据。

05.NATS 和 RocksMQ 对比

Pub/Sub 性能对比

测试平台与方案

  • M1 Pro Chip / Memory: 16GB
  • 启动 MQ,同时对一个 Topic 进行订阅和发布随机内容数据包,循环 N 次发布操作后,直到订阅得到最后一次发布结果时,测试结束。

测试结果

  • NATS 为纯 GO 的实现,而 RocksMQ 使用 CGO 与 rocksdb 的 lib 交互。因此 NATS 的绝大部分内存由 GO 的 GC 接管,而 RocksMQ 依赖 lib 自身的内存管理。NATS 的内存开销会更高。
  • 在数据包较小(小于 64kb)的场景下,RocksMQ 不论在内存、CPU 还是在响应速度都具备较大优势。(1kb message rocksmq 有1x 以上性能优势)
  • 在数据包较大的场景下(大于 64kb),NATS 在内存充足以及理想的 GC 场景下,在响应速度方面有较大的优势(5MB message NATS 有 1x 以上性能优势)
  • 存储方面,RocksMQ 当前有 Zstd 压缩加持,消耗的磁盘空间更少(NATS 未开压缩)

Milvus 集成测试

  • 在 1 亿级别的向量对比测试中:NATS 可以支持更低的检索延迟。

  • 在数据量较少的场景下:NATS 与 RocksMQ 的差距不大。

以上就是关于 Milvus 新消息队列 NATS 的全部内容,如果大家有任何疑问都可以跟我们沟通,下一篇我们会继续讲解 Milvus 2.3 的新功能——MMap,敬请期待。