5.2. 性能

对于多达数万个文档,无论您如何编写代码,CouchDB通常都能很好地执行。一旦你开始查阅数以百万计的文档,你就需要更加小心。

5.2.1. 磁盘I/O

5.2.1.1. 文件大小

你的文件越小,就越少 I/O 如果有操作,CouchDB和操作系统可以缓存的文件越多,复制、备份等就越快。因此,您应该仔细检查您存储的数据。例如,使用几百个字符长的键是很愚蠢的,但是如果只使用单个字符键,则很难维护程序。通过将数据放入视图中,仔细考虑复制的数据。

5.2.1.2. 磁盘和文件系统性能

使用更快的磁盘、分条RAID阵列和现代文件系统都可以加快CouchDB的部署。但是,当磁盘性能成为瓶颈时,有一个选项可以提高CouchDB服务器的响应能力。从文件模块的Erlang文档中:

在具有线程支持的操作系统上,可以让文件操作在自己的线程中执行,从而允许其他Erlang进程继续与文件操作并行执行。见 command line flag +A in erl(1) .

将此参数设置为大于零的数字可以使CouchDB安装保持响应,即使在磁盘使用率很高的时期也是如此。设置此选项的最简单方法是通过 ERL_FLAGS 环境变量。例如,要为Erlang提供四个执行I/O操作的线程,请将以下内容添加到 (prefix)/etc/defaults/couchdb (或等效物):

export ERL_FLAGS="+A 4"

5.2.2. 系统资源限制

随着部署规模的扩大,管理员遇到的问题之一是系统和应用程序配置施加的资源限制。提高这些限制可以使您的部署扩展到超出默认配置支持的范围。

5.2.2.1. CouchDB配置选项

5.2.2.1.1. max_dbs_open

在你 configuration (本地.ini或类似)熟悉 couchdb/max_dbs_open

[couchdb]
max_dbs_open = 100

此选项对一次可以打开的数据库数量设置了上限。CouchDB reference对内部数据库访问进行计数,并在必要时关闭空闲数据库。有时需要同时打开多个默认值,例如在许多数据库将连续复制的部署中。

5.2.2.2. Erlang

即使您增加了CouchDB允许的最大连接数,默认情况下Erlang运行时系统也不允许超过65536个连接。将以下指令添加到 (prefix)/etc/vm.args (或等效值)将增加此限制(在本例中为102400):

+Q 102400

注意,在Windows上,Erlang实际上不会将文件描述符限制增加到8192以上(即系统头定义的值 FD_SETSIZE ). 在macOS上,这个限制可能低到1024。看到了吗 this tip for a possible workaroundthis thread for a deeper explanation .

5.2.2.3. 最大打开文件描述符(ulimit)

一般来说,现代类UNIX系统可以在每个进程中处理大量的文件句柄(例如100000个),而不会出现问题。不要害怕增加系统的这个限制。

增加这些限制的方法各不相同,这取决于您的init系统和特定的操作系统版本。许多操作系统的默认值是1024或4096。在具有多个数据库或多个视图的系统上,CouchDB可以非常迅速地达到这个限制。

对于基于systemd的Linuxes(例如CentOS/RHEL 7、Ubuntu 16.04+、Debian 8或更新版本),假设您从systemd启动CouchDB,则必须通过编辑override文件覆盖上限。最佳做法是通过 systemctl edit couchdb 命令。在编辑器中将这些行添加到文件中:

[Service]
LimitNOFILE=65536

…或任何你喜欢的价值。要将该值增加到65536以上,还必须添加Erlang +Q 参数 etc/vm.args 通过添加以下行:

+Q 102400

老年人 ERL_MAX_PORTS CouchDB提供的Erlang版本忽略了环境变量。

如果您的系统设置为使用可插拔身份验证模块 (PAM) ,你就是 not 从systemd启动CouchDB,增加这个限制很简单。例如,创建名为 /etc/security/limits.d/100-couchdb.conf 以下内容将确保CouchDB一次可以打开65536个文件描述符:

#<domain>    <type>    <item>    <value>
couchdb      hard      nofile    65536
couchdb      soft      nofile    65536

如果您使用的是Debian/Ubuntu sysvinit脚本 (/etc/init.d/couchdb ),您还需要提高对根用户的限制:

#<domain>    <type>    <item>    <value>
root         hard      nofile    65536
root         soft      nofile    65536

您可能还需要编辑 /etc/pam.d/common-session/etc/pam.d/common-session-noninteractive 要添加行的文件:

session required pam_limits.so

如果它还不存在。

如果您的系统不使用PAM,则 ulimit 命令通常可在自定义脚本中使用,以在增加资源限制的情况下启动CouchDB。典型的语法应该是 ulimit -n 65536 .

5.2.3. 网络

生成和接收每个请求/响应都会有延迟开销。一般来说,你应该分批处理你的请求。大多数api都有一些机制来执行批处理,通常是通过在请求主体中提供文档或键的列表。注意你挑选的批量大小。较大的批处理需要您的客户机花费更多的时间将项目编码为JSON,并花费更多的时间解码该数量的响应。使用您自己的配置和典型数据进行一些基准测试,以找到最佳位置。它可能在一千到一万个文档之间。

如果您有一个快速的I/O系统,那么您也可以使用并发—同时有多个请求/响应。这减少了在组装JSON、进行网络连接和解码JSON时的延迟。

从couchdb1.1.0开始,用户报告的文档写入性能通常低于旧版本。主要原因是此版本附带了HTTP服务器库MochiWeb的较新版本,该库默认设置TCP套接字选项 SO_NODELAY 错了。这意味着发送到TCP套接字的小数据,如对文档写入请求(或读取非常小的文档)的答复不会立即发送到网络—TCP将缓冲它一段时间,希望它能被要求通过同一个套接字发送更多数据,然后一次发送所有数据以提高性能。这种TCP缓冲行为可以通过 httpd/socket_options

[httpd]
socket_options = [{nodelay, true}]

参见

散装 loadstore 应用程序编程接口。

5.2.3.1. 连接限制

MochiWeb 处理CouchDB请求。默认最大连接数为2048。若要更改此限制,请使用 server_options 配置变量。 max 指示最大连接数。

[chttpd]
server_options = [{backlog, 128}, {acceptor_pool_size, 16}, {max, 4096}]

5.2.4. 库奇德

5.2.4.1. 删除操作

当你 DELETE 数据库将创建一个包含 _id_rev 字段以及 _deleted 旗子。即使在 database compaction 以便可以复制删除。删除的文档和未删除的文档一样,会影响视图生成时间, PUTDELETE 请求时间,以及数据库的大小,因为它们增加了B+树的大小。您可以在中查看已删除文档的数量 :get:`database information </{{db}}>` . 如果您的用例创建了大量已删除的文档(例如,如果您存储的是短期数据,如日志条目、消息队列等),您可能希望定期切换到新数据库并删除旧数据库(一旦其中的条目都已过期)。

5.2.4.2. 文件ID

数据库文件大小来自于文档和视图大小,但也取决于 _id 尺寸。不仅是 _id 存在于文档中,但它及其部分在CouchDB用于导航文件以查找文档的二叉树结构中是重复的。一个真实的例子是,一个用户从16字节ID切换到4字节ID,使数据库从21GB变为4GB,其中包含1000万个文档(从2.5GB到2GB时是原始JSON文本)。

使用顺序(至少是排序的)id插入比随机id更快。因此,您应该考虑自己生成id,按顺序分配它们,并使用消耗更少字节的编码方案。例如,用16个十六进制数字来表示的东西可以用4个62进制数字(10个数字,26个小写,26个大写)来完成。

5.2.5. 意见

5.2.5.1. 视图生成

当需要处理大量文档时,JavaScript查询服务器的视图生成速度非常慢。生成过程甚至不会使单个CPU饱和,更不用说I/O了。原因是CouchDB服务器和独立服务器之间的延迟 couchjs 查询服务器,极大地说明了消除实现延迟的重要性。

您可以让视图访问“过时”,但确定何时会发生这种情况并给出快速响应和更新视图的时间是不实际的,这需要很长时间。(一个1000万个文档数据库需要大约10分钟才能加载到CouchDB中,但是大约需要4个小时来生成视图)。

在集群中,“过时”请求由一组固定的碎片提供服务,以便在请求之间向用户呈现一致的结果。这是一个可用性权衡的问题——固定的碎片集可能不是集群中响应最快/可用的。如果您不需要这种一致性(例如,您的索引是相对静态的),您可以通过指定 stable=false&update=false 而不是 stale=okstable=false&update=lazy 而不是 stale=update_after .

视图信息不会被复制-它是在每个数据库上重建的,因此您不能在单独的服务器上生成视图。

5.2.5.2. 内置Reduce函数

如果您使用的是一个非常简单的视图函数,它只执行求和或计数的减少,那么您可以通过简单的编写来调用它们的本机Erlang实现 _sum_count 代替函数声明。这将极大地加快速度,因为它减少了CouchDB和 JavaScript query server . 例如,作为 mentioned on the mailing list ,输出包含约78000个项目的(已编制索引和缓存)视图的时间从60秒减少到4秒。

之前:

{
    "_id": "_design/foo",
    "views": {
        "bar": {
            "map": "function (doc) { emit(doc.author, 1); }",
            "reduce": "function (keys, values, rereduce) { return sum(values); }"
        }
    }
}

后:

{
    "_id": "_design/foo",
    "views": {
        "bar": {
            "map": "function (doc) { emit(doc.author, 1); }",
            "reduce": "_sum"
        }
    }
}