Производительность
При работе с десятками тысяч документов CouchDB, как правило, работает хорошо независимо от того, как вы пишете код. Когда документов становится несколько миллионов, нужно быть гораздо внимательнее.
Дисковый ввод-вывод
Размер файла
Чем меньше размер файла, тем меньше операций ввода-вывода потребуется, тем большую часть файла CouchDB и операционная система смогут кэшировать и тем быстрее будут выполняться репликация, резервное копирование и другие операции. Поэтому внимательно изучите сохраняемые данные. Например, использовать ключи длиной в сотни символов было бы неразумно, но если применять только однобуквенные ключи, программу будет сложно поддерживать. Тщательно обдумайте, какие дублирующиеся данные следует вынести в представления.
Производительность дисков и файловой системы
Использование более быстрых дисков, массивов RAID с чередованием данных и современных файловых систем может ускорить развертывание CouchDB. Однако есть один параметр, который может повысить отзывчивость сервера CouchDB, если производительность диска становится узким местом. Из документации Erlang по модулю file:
В операционных системах с поддержкой потоков можно выполнять файловые операции в отдельных потоках, позволяя другим процессам Erlang продолжать работу параллельно с файловыми операциями. См. флаг командной строки +A в erl(1).
Если установить для этого аргумента значение больше нуля, ваша установка CouchDB может оставаться отзывчивой даже при интенсивном использовании диска. Проще всего задать этот параметр с помощью переменной окружения ERL_FLAGS. Например, чтобы предоставить Erlang четыре потока для выполнения операций ввода-вывода, добавьте следующую строку в (prefix)/etc/defaults/couchdb (или аналогичный файл):
export ERL_FLAGS="+A 4"
Ограничения системных ресурсов
По мере роста развертывания администраторам часто приходится сталкиваться с ограничениями ресурсов, установленными системой и конфигурацией приложения. Повышение этих ограничений может позволить развертыванию выйти за рамки, поддерживаемые конфигурацией по умолчанию.
Параметры конфигурации CouchDB
max_dbs_open
В вашей конфигурации (local.ini или аналогичном файле) ознакомьтесь с параметром couchdb/max_dbs_open:
[couchdb] max_dbs_open = 100
Этот параметр устанавливает верхний предел количества баз данных, которые могут быть открыты одновременно. CouchDB внутренне подсчитывает обращения к базам данных и при необходимости закрывает неиспользуемые базы. Иногда нужно одновременно держать открытыми больше баз, чем допускает значение по умолчанию, например при развертываниях, где постоянно выполняется репликация множества баз данных.
Erlang
Даже если вы увеличили максимальное количество подключений, разрешенное CouchDB, среда выполнения Erlang по умолчанию не позволит установить более 65536 подключений. Добавление следующей директивы в (prefix)/etc/vm.args (или аналогичный файл) увеличит этот предел (в данном случае до 102400):
+Q 102400
Обратите внимание, что в Windows Erlang фактически не увеличит предел файловых дескрипторов выше 8192 (то есть значения, определенного в системном заголовочном файле: FD_SETSIZE). В macOS предел может составлять всего 1024. См. этот совет о возможном обходном решении и эту ветку обсуждения с более подробным объяснением.
Максимальное количество открытых файловых дескрипторов (ulimit)
В целом современные UNIX-подобные системы могут без проблем обрабатывать очень большое количество файловых дескрипторов на процесс (например, 100000). Не бойтесь увеличивать этот предел в своей системе.
Способ увеличения этих ограничений зависит от системы инициализации и конкретной версии ОС. Во многих ОС значение по умолчанию составляет 1024 или 4096. В системах с большим количеством баз данных или представлений CouchDB может очень быстро достичь этого предела.
В Linux-системах на основе systemd (например, CentOS/RHEL 7, Ubuntu 16.04+, Debian 8 или новее), если вы запускаете CouchDB через systemd, необходимо переопределить верхний предел, отредактировав файл переопределения. Рекомендуемый способ сделать это — использовать команду systemctl edit couchdb. Добавьте в файл в открывшемся редакторе следующие строки:
[Service] LimitNOFILE=65536
…или укажите любое другое значение. Чтобы увеличить это значение выше 65536, необходимо также добавить параметр Erlang +Q в файл etc/vm.args, добавив строку:
+Q 102400
Переменная окружения ERL_MAX_PORTS, использовавшаяся ранее, игнорируется версией Erlang, поставляемой с CouchDB.
Если ваша система настроена на использование подключаемых модулей аутентификации (PAM) и CouchDB запускается не через systemd, увеличить это ограничение несложно. Например, создание файла с именем /etc/security/limits.d/100-couchdb.conf и следующим содержимым позволит CouchDB одновременно открывать до 65536 файловых дескрипторов:
#<domain> <type> <item> <value> couchdb hard nofile 65536 couchdb soft nofile 65536
Если вы используете наш скрипт sysvinit для Debian/Ubuntu (/etc/init.d/couchdb), необходимо также повысить ограничения для пользователя root:
#<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, для запуска CouchDB с повышенными ограничениями ресурсов в пользовательском скрипте обычно можно использовать команду ulimit. Типичный синтаксис: ulimit -n 65536.
Сеть
Каждый запрос и ответ сопровождаются задержками при отправке и получении. Как правило, следует отправлять запросы пакетами. В большинстве API предусмотрен механизм пакетной обработки, обычно позволяющий передавать списки документов или ключей в теле запроса. Внимательно выбирайте размер пакета. Для обработки более крупного пакета клиенту потребуется больше времени на кодирование элементов в JSON, а также на декодирование соответствующего количества ответов. Проведите тестирование со своей конфигурацией и типичными данными, чтобы определить оптимальный размер. Вероятнее всего, он составит от одной до десяти тысяч документов.
Если ваша система ввода-вывода работает быстро, можно также использовать параллельную обработку — отправлять и получать несколько запросов одновременно. Это позволяет снизить влияние задержек при формировании JSON, сетевом обмене и декодировании JSON.
Начиная с CouchDB 1.1.0 пользователи часто отмечают, что запись документов выполняется медленнее, чем в предыдущих выпусках. Главная причина в том, что в этом выпуске используется более новая версия библиотеки HTTP-сервера MochiWeb, которая по умолчанию устанавливает параметр TCP-сокета SO_NODELAY в значение false. Это означает, что небольшие объемы данных, отправляемые через TCP-сокет, например ответ на запрос записи документа (или чтение очень небольшого документа), не передаются по сети немедленно: TCP некоторое время буферизует их, рассчитывая, что через тот же сокет будет отправлено больше данных, а затем передает все данные разом для повышения производительности. Такое буферизование TCP можно отключить с помощью параметра httpd/socket_options:
[httpd]
socket_options = [{nodelay, true}] См. также
API пакетной загрузки и сохранения.
Ограничение количества подключений
Обработкой запросов CouchDB занимается MochiWeb. Максимальное количество подключений по умолчанию — 65535. Чтобы изменить это ограничение, используйте переменную конфигурации server_options. max указывает максимальное количество подключений.
[chttpd]
server_options = [{backlog, 128}, {acceptor_pool_size, 32}, {max, 262144}] CouchDB
Операция DELETE
При выполнении операции DELETE для документа база данных создает новую ревизию, содержащую поля _id и _rev, а также флаг _deleted. Эта ревизия сохраняется даже после уплотнения базы данных, чтобы удаление можно было реплицировать. Удаленные документы, как и неудаленные, могут влиять на время построения представлений, время выполнения запросов PUT и DELETE, а также на размер базы данных, поскольку увеличивают размер B+Tree. Количество удаленных документов можно узнать в database information. Если в вашем сценарии использования создается много удаленных документов (например, если вы храните временные данные — записи журналов, очереди сообщений и т. п.), можно периодически переходить на новую базу данных и удалять старую, когда срок хранения всех ее записей истечет.
Идентификатор документа
Размер файла базы данных зависит от размеров документов и представлений, а также от размера идентификаторов _id. В документе не только хранится _id, но сам идентификатор и его части дублируются в структуре бинарного дерева, которую CouchDB использует для поиска документа в файле. Например, один пользователь, заменив идентификаторы длиной 16 байт на идентификаторы длиной 4 байта, уменьшил размер базы данных с 21 ГБ до 4 ГБ при 10 миллионах документов (объем исходного текста JSON сократился с 2,5 ГБ до 2 ГБ).
Вставка документов с последовательными (и как минимум отсортированными) идентификаторами выполняется быстрее, чем с произвольными. Поэтому рассмотрите возможность самостоятельно генерировать идентификаторы, назначать их последовательно и использовать схему кодирования, требующую меньше байтов. Например, для представления 8 байт потребуется 16 шестнадцатеричных цифр, тогда как те же 8 байт можно закодировать всего 11 символами в base64url (без заполнения).
Представления
Построение представлений
Представления с сервером запросов JavaScript строятся чрезвычайно медленно, если нужно обработать значительное количество документов. Процесс построения не загрузит даже одно ядро ЦП на полную мощность, не говоря уже о подсистеме ввода-вывода. Причина — задержки при взаимодействии сервера CouchDB и отдельного сервера запросов couchjs, что наглядно показывает, насколько важно свести задержки в вашей реализации к минимуму.
Можно разрешить доступ к «устаревшим» представлениям, но на практике невозможно определить, когда они обеспечат быстрый ответ, а когда потребуется долго ждать их обновления. (Загрузка базы данных с 10 миллионами документов в CouchDB заняла около 10 минут, а построение представлений — около 4 часов.)
В кластере запросы к «устаревшим» данным обслуживаются фиксированным набором шардов, чтобы обеспечить пользователям согласованные результаты между запросами. Это сопряжено с компромиссом в отношении доступности: фиксированный набор шардов может оказаться не самым отзывчивым или доступным в кластере. Если такой уровень согласованности вам не нужен (например, если индексы относительно статичны), можно указать CouchDB использовать любую доступную реплику, задав stable=false&update=false вместо stale=ok или stable=false&update=lazy вместо stale=update_after.
Информация о представлениях не реплицируется — она создается заново в каждой базе данных, поэтому построить представления на отдельном сервере не получится.
Встроенные функции Reduce
Если вы используете очень простую функцию представления, выполняющую только суммирование или подсчет, можно вызывать их нативные реализации на Erlang, просто указав _sum или _count вместо объявления функции. Это значительно ускорит работу, поскольку сократит объем операций ввода-вывода между CouchDB и сервером запросов JavaScript. Например, как сообщалось в списке рассылки, время вывода представления, содержащего около 78 000 элементов (уже проиндексированных и закэшированных), сократилось с 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"
}
}
} См. также
Copyright © 2025 The Apache Software Foundation — Licensed under the Apache License 2.0
https://docs.couchdb.org/en/3.5.1/maintenance/performance.html