单节点Chroma:性能与限制

Chroma的单节点版本旨在易于部署和维护,同时仍提供满足广泛生产应用需求的强大性能。

为了帮助您了解单节点Chroma何时适合您的使用场景,我们进行了一系列压力测试和性能实验,以探究系统的功能并发现其限制和边缘情况。我们分析了这些边界在不同硬件配置下的表现,以确定何种部署适合不同的工作负载。

本文档描述了这些发现,以及一些充分利用Chroma部署的一般原则。

结果总结#

大致来说,以下是您可以在不同EC2实例类型上从Chroma获得的性能,使用非常典型的工作负载:

  • 1024维嵌入
  • 小文档(100-200字)
  • 每条记录三个元数据字段
实例类型系统内存最大集合大小(近似)平均延迟(插入)99.9%延迟(插入)平均延迟(查询)99.9%延迟(查询)每月成本
t3.small2250,00055ms250ms22ms72ms$15.936
t3.medium4700,00037ms120ms14ms41ms$31.072
t3.large81,700,00030ms100ms13ms35ms$61.344
t3.xlarge163,600,00030ms100ms13ms30ms$121.888
t3.2xlarge327,500,00030ms100ms13ms30ms$242.976
r7i.2xlarge6415,000,00013ms50ms7ms13ms$386.944


不建议在系统内存小于2GB的系统上部署Chroma。

请注意,此表中的延迟数据适用于小集合。随着集合的增长,延迟会增加:请参见下文的延迟与集合大小以获取完整分析。

内存与集合大小#

Chroma使用hnswlib的一个分支来高效地索引和搜索嵌入向量。HNSW算法要求嵌入索引驻留在系统内存中以进行查询或更新。

因此,可用系统内存的数量定义了Chroma集合(或多个集合,如果它们同时使用)大小的上限。如果集合增长超过可用内存,插入和查询延迟会迅速飙升,因为操作系统开始将内存交换到磁盘。索引的内存布局不利于交换,系统很快变得不可用。

因此,用户应始终计划提供足够的RAM来容纳预期的嵌入总数。

为了分析需要多少RAM,我们在不同大小的EC2实例上启动了Chroma实例,然后插入嵌入,直到每个系统变得无响应。正如预期的那样,这个失败点与RAM和嵌入数量线性相关。

对于1024维嵌入,每个嵌入有三个元数据记录和一个小文档,这相当于N = R * 0.245,其中N是最大集合大小(以百万计),R是所需的系统内存量(以GB计)。请记住,除了Chroma所需的内存外,您还需要为系统的其他需求至少保留一GB内存。

这种模式在约700万嵌入之前都成立,这是我们测试的极限。此时Chroma仍然快速且稳定,我们没有发现Chroma数据库大小的严格上限。

磁盘空间与集合大小#

Chroma将每个集合持久化到磁盘。所需的空间是保存HNSW嵌入索引所需的空间与存储文档和嵌入元数据的sqlite数据库所需空间的组合。

持久化HNSW索引的计算与计算RAM大小类似。作为经验法则,只需确保系统的存储至少与其RAM一样大,再加上几GB以考虑操作系统和其它应用程序的开销。 sqlite数据库所需的空间大小变化很大,完全取决于是否在Chroma中保存文档和元数据,以及如果保存,它们的大小如何。全面探索所有可能的排列组合超出了我们能够进行的实验范围。

然而,作为一个单一数据点,一个包含约4万份每份1000字的文档和约60万个元数据条目的集合的sqlite数据库大约为1.7GB。

元数据数据库的大小没有严格的限制:sqlite本身支持达到TB级别的数据库,并且能够有效地分页到磁盘。

在大多数实际使用场景中,HNSW索引在RAM中的大小和性能很可能成为Chroma集合大小的限制因素,远在元数据数据库成为限制因素之前。

延迟与集合大小#

随着集合变大和索引规模增长,插入和查询的完成时间都会变长。增加的速率起初相当平缓,然后大致呈线性增长,拐点和斜率取决于可用CPU的数量和速度。

查询延迟#

query-latency

插入延迟#

insert-latency

并发性#

尽管HNSW算法的某些方面是多线程的,但在任何时候只有一个线程可以读取或写入给定的索引。在大多数情况下,单节点Chroma本质上是一个单线程系统。如果在一个操作仍在进行时执行另一个操作,它会阻塞直到第一个操作完成。

这意味着在并发负载下,每个请求的平均延迟会增加。

在写入时,随着批量大小的增加,延迟的增加更为明显,因为系统更加饱和。我们已经通过实验验证了这一点:随着并发写入者数量的增加,平均延迟线性增加。

concurrent-writes

concurrent-queries

尽管延迟受到影响,Chroma在高并发负载下仍然保持稳定。过多的并发用户最终可能会增加延迟到系统无法接受的程度,但这通常只发生在较大的批量大小下。如上图所示,系统在每秒几十到几百个操作的情况下仍然可用。

请参阅下面的插入吞吐量部分,讨论在并发性受控的情况下(例如在插入批量数据时),如何优化用户数量以实现最大吞吐量。

CPU速度、核心数量与类型#

作为一个CPU密集型应用,CPU速度和类型对平均延迟的影响并不令人惊讶。

数据表明,尽管Chroma并未完全并行化,但它仍然可以利用多个CPU核心来提高吞吐量。

cpu-mean-query-latency

插入吞吐量#

一个经常相关的问题是:给定要插入的批量数据,插入的速度有多快,以及快速插入大量数据的最佳方式是什么?

首先要考虑的重要因素是并发插入请求的数量。

如上文并发性部分所述,实际插入吞吐量并不会从并发性中受益。然而,存在一定量的网络和HTTP开销,这些开销可以并行化。因此,为了在保持尽可能低的延迟的同时使Chroma饱和,我们建议使用2个并发客户端进程或线程尽可能快地插入。

第二个要考虑的因素是每个请求的批量大小。性能与批量大小大致呈线性关系,处理HTTP请求本身有一个固定的开销。

实验证实了这一点:总体吞吐量(跨批量大小和请求数量的嵌入总数)在批量大小为100-500之间保持相当平稳:

concurrent-inserts

鉴于较小的批量具有更低、更一致的延迟,并且不太可能导致超时错误,我们建议选择此曲线中较小一侧的批量:任何介于50到250之间的批量都是一个合理的选择。

结论#

用户在使用适当硬件部署的情况下,应能放心地依赖Chroma处理接近数千万嵌入向量的用例。其读写的平均和上限延迟使其成为适用于除最大规模AI应用之外的良好平台,能够支持潜在的数千名同时在线用户(具体取决于应用的后端访问模式)。

然而,作为一个单节点解决方案,它并非无限扩展。若您发现需求超出了本分析所列参数,我们非常希望听取您的反馈。请填写此表单,我们将把您加入专门支持生产用户的Slack工作区。我们乐于协助您思考系统设计,无论Chroma是否适合其中,或您是否适合我们即将推出的分布式云服务。