- name: osd_network
  type: string or array of strings
  type_ru: строка или массив строк
  info: |
    Network mask of public OSD network(s) (IPv4 or IPv6). Each OSD listens to all
    addresses of UP + RUNNING interfaces matching one of these networks, on the
    same port. Port is auto-selected except if [bind_port](osd.en.md#bind_port) is
    explicitly specified. Bind address(es) may also be overridden manually by
    specifying [bind_address](osd.en.md#bind_address). If OSD networks are not specified
    at all, OSD just listens to a wildcard address (0.0.0.0).
  info_ru: |
    Маски подсетей (IPv4 или IPv6) публичной сети или сетей OSD. Каждый OSD слушает
    один и тот же порт на всех адресах поднятых (UP + RUNNING) сетевых интерфейсов,
    соответствующих одной из указанных сетей. Порт выбирается автоматически, если
    только [bind_port](osd.ru.md#bind_port) не задан явно. Адреса для подключений можно
    также переопределить явно, задав [bind_address](osd.ru.md#bind_address). Если сети OSD
    не заданы вообще, OSD слушает все адреса (0.0.0.0).
- name: osd_cluster_network
  type: string or array of strings
  type_ru: строка или массив строк
  info: |
    Network mask of separate network(s) (IPv4 or IPv6) to use for OSD
    cluster connections. I.e. OSDs will always attempt to use these networks
    to connect to other OSDs, while clients will attempt to use networks from
    [osd_network](#osd_network).
  info_ru: |
    Маски подсетей (IPv4 или IPv6) отдельной кластерной сети или сетей OSD.
    То есть, OSD будут всегда стараться использовать эти сети для соединений
    с другими OSD, а клиенты будут стараться использовать сети из [osd_network](#osd_network).
- name: use_rdma
  type: bool
  default: true
  info: |
    Try to use RDMA through libibverbs for communication if it's available.
    Disable if you don't want Vitastor to use RDMA. TCP-only clients can also
    talk to an RDMA-enabled cluster, so disabling RDMA may be needed if clients
    have RDMA devices, but they are not connected to the cluster.

    `use_rdma` works with RoCEv1/RoCEv2 networks, but not with iWARP and,
    maybe, with some Infiniband configurations which require RDMA-CM.
    Consider `use_rdmacm` for such networks.
  info_ru: |
    Попробовать использовать RDMA через libibverbs для связи при наличии
    доступных устройств. Отключите, если вы не хотите, чтобы Vitastor
    использовал RDMA. TCP-клиенты также могут работать с RDMA-кластером,
    так что отключать RDMA может быть нужно, только если у клиентов есть
    RDMA-устройства, но они не имеют соединения с кластером Vitastor.

    `use_rdma` работает с RoCEv1/RoCEv2 сетями, но не работает с iWARP и
    может не работать с частью конфигураций Infiniband, требующих RDMA-CM.
    Рассмотрите включение `use_rdmacm` для таких сетей.
- name: use_rdmacm
  type: bool
  default: false
  info: |
    Use an alternative implementation of RDMA through RDMA-CM (Connection
    Manager). Works with all RDMA networks: Infiniband, iWARP and
    RoCEv1/RoCEv2, and even allows to disable TCP and run only with RDMA.
    OSDs always use random port numbers for RDMA-CM listeners, different
    from their TCP ports. `use_rdma` is automatically disabled when
    `use_rdmacm` is enabled.
  info_ru: |
    Использовать альтернативную реализацию RDMA на основе RDMA-CM (Connection
    Manager). Работает со всеми типами RDMA-сетей: Infiniband, iWARP и
    RoCEv1/RoCEv2, и даже позволяет полностью отключить TCP и работать
    только на RDMA. OSD используют случайные номера портов для ожидания
    соединений через RDMA-CM, отличающиеся от их TCP-портов. Также при
    включении `use_rdmacm` автоматически отключается опция `use_rdma`.
- name: disable_tcp
  type: bool
  default: true
  info: |
    Fully disable TCP and only use RDMA-CM for OSD communication.
  info_ru: |
    Полностью отключить TCP и использовать только RDMA-CM для соединений с OSD.
- name: rdma_device
  type: string
  info: |
    RDMA device name to use for Vitastor OSD communications (for example,
    "rocep5s0f0"). If not specified, Vitastor will try to find an RoCE
    device matching [osd_network](osd.en.md#osd_network), preferring RoCEv2,
    or choose the first available RDMA device if no RoCE devices are
    found or if `osd_network` is not specified. Auto-selection is also
    unsupported with old libibverbs < v32, like in Debian 10 Buster or
    CentOS 7.

    Run `ibv_devinfo -v` as root to list available RDMA devices and their
    features.

    Remember that you also have to configure your network switches if you use
    RoCE/RoCEv2, otherwise you may experience unstable performance. Refer to
    the manual of your network vendor for details about setting up the switch
    for RoCEv2 correctly. Usually it means setting up Lossless Ethernet with
    PFC (Priority Flow Control) and ECN (Explicit Congestion Notification).

    Vitastor supports all adapters, even ones without ODP (On-Demand Paging)
    support, like Mellanox ConnectX-3 and non-Mellanox cards. ODP is only present
    in Mellanox ConnectX >= 4 adapters and allows to skip memory registration
    for RDMA and thus, in theory, avoid memory copying.

    Versions up to Vitastor 1.2.0 required ODP, then it was disabled by default,
    but it was still supported up to 3.0.3. Now ODP support is removed because it
    actually only hurts performance: an example 3-node cluster with 8 NVMe in each
    node and 2*25 GBit/s ConnectX-6 RDMA network pushed 3950000 read iops without
    ODP, but only 239000 iops with ODP.

    This happens because Mellanox ODP implementation seems to be based on
    message retransmissions when the adapter doesn't know about the buffer yet -
    it likely uses standard "RNR retransmissions" (RNR = receiver not ready)
    which is generally slow in RDMA/RoCE networks. Here's a presentation about
    it from ISPASS-2021 conference: https://tkygtr6.github.io/pub/ISPASS21_slides.pdf
  info_ru: |
    Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0").
    Если не указано, Vitastor попробует найти RoCE-устройство, соответствующее
    [osd_network](osd.en.md#osd_network), предпочитая RoCEv2, или выбрать первое
    попавшееся RDMA-устройство, если RoCE-устройств нет или если сеть `osd_network`
    не задана. Также автовыбор не поддерживается со старыми версиями библиотеки
    libibverbs < v32, например в Debian 10 Buster или CentOS 7.

    Запустите `ibv_devinfo -v` от имени суперпользователя, чтобы посмотреть
    список доступных RDMA-устройств, их параметры и возможности.

    Обратите внимание, что если вы используете RoCE/RoCEv2, вам также необходимо
    правильно настроить для него коммутаторы, иначе вы можете столкнуться с
    нестабильной производительностью. Подробную информацию о настройке
    коммутатора для RoCEv2 ищите в документации производителя. Обычно это
    подразумевает настройку сети без потерь на основе PFC (Priority Flow
    Control) и ECN (Explicit Congestion Notification).

    Vitastor поддерживает все модели адаптеров, включая те, у которых нет
    поддержки ODP (On-Demand Paging), например, ConnectX-3 и карты производства
    не Mellanox. Функция ODP доступна только на адаптерах Mellanox ConnectX-4 и
    более новых и позволяет не регистрировать память для её использования RDMA-картой,
    благодаря чему в теории можно избежать лишних копирований памяти.

    Версии Vitastor до 1.2.0 включительно требовали ODP, потом функция был отключена
    по умолчанию, но поддерживалась вплоть до версии 3.0.3. Сейчас поддержка ODP
    полностью удалена, так как на самом деле она только портит производительность:
    например, на 3-узловом кластере с 8 NVMe в каждом узле и сетью 2*25 Гбит/с на
    чтение с RDMA без ODP удаётся снять 3950000 iops, а с ODP - всего 239000 iops.

    Это происходит из-за того, что реализация ODP у Mellanox неоптимальная и
    основана на повторной передаче сообщений, когда карте не известен буфер -
    вероятно, на стандартных "RNR retransmission" (RNR = receiver not ready).
    А данные повторные передачи в RDMA/RoCE - всегда очень медленная штука.
    Презентация на эту тему с конференции ISPASS-2021: https://tkygtr6.github.io/pub/ISPASS21_slides.pdf
- name: rdma_port_num
  type: int
  info: |
    RDMA device port number to use. Only for devices that have more than 1 port.
    See `phys_port_cnt` in `ibv_devinfo -v` output to determine how many ports
    your device has.

    Not relevant for RDMA-CM (use_rdmacm).
  info_ru: |
    Номер порта RDMA-устройства, который следует использовать. Имеет смысл
    только для устройств, у которых более 1 порта. Чтобы узнать, сколько портов
    у вашего адаптера, посмотрите `phys_port_cnt` в выводе команды
    `ibv_devinfo -v`.

    Опция неприменима к RDMA-CM (use_rdmacm).
- name: rdma_gid_index
  type: int
  info: |
    Global address identifier index of the RDMA device to use. Different GID
    indexes may correspond to different protocols like RoCEv1, RoCEv2 and iWARP.
    Search for "GID" in `ibv_devinfo -v` output to determine which GID index
    you need.

    If not specified, Vitastor will try to auto-select a RoCEv2 IPv4 GID, then
    RoCEv2 IPv6 GID, then RoCEv1 IPv4 GID, then RoCEv1 IPv6 GID, then IB GID.
    GID auto-selection is unsupported with libibverbs < v32.

    A correct rdma_gid_index for RoCEv2 is usually 1 (IPv6) or 3 (IPv4).

    Not relevant for RDMA-CM (use_rdmacm).
  info_ru: |
    Номер глобального идентификатора адреса RDMA-устройства, который следует
    использовать. Разным gid_index могут соответствовать разные протоколы связи:
    RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со
    словом "GID" в выводе команды `ibv_devinfo -v`.

    Если не указан, Vitastor попробует автоматически выбрать сначала GID,
    соответствующий RoCEv2 IPv4, потом RoCEv2 IPv6, потом RoCEv1 IPv4, потом
    RoCEv1 IPv6, потом IB. Авто-выбор GID не поддерживается со старыми версиями
    libibverbs < v32.

    Правильный rdma_gid_index для RoCEv2, как правило, 1 (IPv6) или 3 (IPv4).

    Опция неприменима к RDMA-CM (use_rdmacm).
- name: rdma_mtu
  type: int
  info: |
    RDMA Path MTU to use. Must be 1024, 2048 or 4096. Default is to use the
    RDMA device's MTU.
  info_ru: |
    Максимальная единица передачи (Path MTU) для RDMA. Должно быть равно 1024,
    2048 или 4096. По умолчанию используется значение MTU RDMA-устройства.
- name: rdma_max_sge
  type: int
  default: 128
  info: |
    Maximum number of scatter/gather entries to use for RDMA. OSDs negotiate
    the actual value when establishing connection anyway, so it's usually not
    required to change this parameter.
  info_ru: |
    Максимальное число записей разделения/сборки (scatter/gather) для RDMA.
    OSD в любом случае согласовывают реальное значение при установке соединения,
    так что менять этот параметр обычно не нужно.
- name: rdma_max_msg
  type: int
  default: 132096
  info: Maximum size of a single RDMA send or receive operation in bytes.
  info_ru: Максимальный размер одной RDMA-операции отправки или приёма.
- name: rdma_max_recv
  type: int
  default: 16
  info: |
    Maximum number of RDMA receive buffers per connection (RDMA requires
    preallocated buffers to receive data). Each buffer is `rdma_max_msg` bytes
    in size. So this setting directly affects memory usage: a single Vitastor
    RDMA client uses `rdma_max_recv * rdma_max_msg * OSD_COUNT` bytes of memory.
    Default is roughly 2 MB * number of OSDs.
  info_ru: |
    Максимальное число буферов для RDMA-приёма данных на одно соединение
    (RDMA требует заранее выделенных буферов для приёма данных). Каждый буфер
    имеет размер `rdma_max_msg` байт. Таким образом, настройка прямо влияет на
    потребление памяти - один Vitastor-клиент с RDMA использует
    `rdma_max_recv * rdma_max_msg * ЧИСЛО_OSD` байт памяти, по умолчанию -
    примерно 2 МБ * число OSD.
- name: rdma_max_send
  type: int
  default: 8
  info: |
    Maximum number of outstanding RDMA send operations per connection. Should be
    less than `rdma_max_recv` so the receiving side doesn't run out of buffers.
    Doesn't affect memory usage - additional memory isn't allocated for send
    operations.
  info_ru: |
    Максимальное число RDMA-операций отправки, отправляемых в очередь одного
    соединения. Желательно, чтобы оно было меньше `rdma_max_recv`, чтобы
    у принимающей стороны в процессе работы не заканчивались буферы на приём.
    Не влияет на потребление памяти - дополнительная память на операции отправки
    не выделяется.
- name: peer_connect_interval
  type: sec
  min: 1
  default: 5
  online: true
  info: Interval before attempting to reconnect to an unavailable OSD.
  info_ru: Время ожидания перед повторной попыткой соединиться с недоступным OSD.
- name: peer_connect_timeout
  type: sec
  min: 1
  default: 5
  online: true
  info: Timeout for OSD connection attempts.
  info_ru: Максимальное время ожидания попытки соединения с OSD.
- name: osd_idle_timeout
  type: sec
  min: 1
  default: 5
  online: true
  info: |
    OSD connection inactivity time after which clients and other OSDs send
    keepalive requests to check state of the connection.
  info_ru: |
    Время неактивности соединения с OSD, после которого клиенты или другие OSD
    посылают запрос проверки состояния соединения.
- name: osd_ping_timeout
  type: sec
  min: 1
  default: 5
  online: true
  info: |
    Maximum time to wait for OSD keepalive responses. If an OSD doesn't respond
    within this time, the connection to it is dropped and a reconnection attempt
    is scheduled.
  info_ru: |
    Максимальное время ожидания ответа на запрос проверки состояния соединения.
    Если OSD не отвечает за это время, соединение отключается и производится
    повторная попытка соединения.
- name: max_etcd_attempts
  type: int
  default: 5
  online: true
  info: |
    Maximum number of attempts for etcd requests which can't be retried
    indefinitely.
  info_ru: |
    Максимальное число попыток выполнения запросов к etcd для тех запросов,
    которые нельзя повторять бесконечно.
- name: etcd_quick_timeout
  type: ms
  default: 1000
  online: true
  info: |
    Timeout for etcd requests which should complete quickly, like lease refresh.
  info_ru: |
    Максимальное время выполнения запросов к etcd, которые должны завершаться
    быстро, таких, как обновление резервации (lease).
- name: etcd_slow_timeout
  type: ms
  default: 5000
  online: true
  info: Timeout for etcd requests which are allowed to wait for some time.
  info_ru: |
    Максимальное время выполнения запросов к etcd, для которых не обязательно
    гарантировать быстрое выполнение.
- name: etcd_keepalive_timeout
  type: sec
  default: max(30, etcd_report_interval*2)
  online: true
  info: |
    Timeout for etcd connection HTTP Keep-Alive. Should be higher than
    etcd_report_interval to guarantee that keepalive actually works.
  info_ru: |
    Таймаут для HTTP Keep-Alive в соединениях к etcd. Должен быть больше, чем
    etcd_report_interval, чтобы keepalive гарантированно работал.
- name: etcd_ws_keepalive_interval
  type: sec
  default: 5
  online: true
  info: |
    etcd websocket ping interval required to keep the connection alive and
    detect disconnections quickly.
  info_ru: |
    Интервал проверки живости вебсокет-подключений к etcd.
- name: etcd_min_reload_interval
  type: ms
  default: 1000
  online: true
  info: |
    Minimum interval for full etcd state reload. Introduced to prevent
    excessive load on etcd during outages when etcd can't keep up with event
    streams and cancels them.
  info_ru: |
    Минимальный интервал полной перезагрузки состояния из etcd. Добавлено для
    предотвращения избыточной нагрузки на etcd во время отказов, когда etcd не
    успевает рассылать потоки событий и отменяет их.
- name: tcp_header_buffer_size
  type: int
  default: 65536
  info: |
    Size of the buffer used to read data using an additional copy. Vitastor
    packet headers are 128 bytes, payload is always at least 4 KB, so it is
    usually beneficial to try to read multiple packets at once even though
    it requires to copy the data an additional time. The rest of each packet
    is received without an additional copy. You can try to play with this
    parameter and see how it affects random iops and linear bandwidth if you
    want.
  info_ru: |
    Размер буфера для чтения данных с дополнительным копированием. Пакеты
    Vitastor содержат 128-байтные заголовки, за которыми следуют данные размером
    от 4 КБ и для мелких операций ввода-вывода обычно выгодно за 1 вызов читать
    сразу несколько пакетов, даже не смотря на то, что это требует лишний раз
    скопировать данные. Часть каждого пакета за пределами значения данного
    параметра читается без дополнительного копирования. Вы можете попробовать
    поменять этот параметр и посмотреть, как он влияет на производительность
    случайного и линейного доступа.
- name: min_zerocopy_send_size
  type: int
  default: 32768
  info: |
    OSDs and clients will attempt to use io_uring-based zero-copy TCP send
    for buffers larger than this number of bytes. Zero-copy send with io_uring is
    supported since Linux kernel version 6.1. Support is auto-detected and disabled
    automatically when not available. It can also be disabled explicitly by setting
    this parameter to a negative value.

    ⚠️ Warning! Zero-copy send performance may vary greatly from CPU to CPU and from
    one kernel version to another. Generally, it tends to only make benefit with larger
    messages. With smaller messages (say, 4 KB), it may actually be slower. 32 KB is
    enough for almost all CPUs, but even smaller values are optimal for some of them.
    For example, 4 KB is OK for EPYC Milan/Genoa and 12 KB is OK for Xeon Ice Lake
    (but verify it yourself please).

    Verification instructions:
    1. Add `iommu=pt` into your Linux kernel command line and reboot.
    2. Upgrade your kernel. For example, it's very important to use 6.11+ with recent AMD EPYCs.
    3. Run some tests with the [send-zerocopy liburing example](https://github.com/axboe/liburing/blob/master/examples/send-zerocopy.c)
       to find the minimal message size for which zero-copy is optimal.
       Use `./send-zerocopy tcp -4 -R` at the server side and
       `time ./send-zerocopy tcp -4 -b 0 -s BUFFER_SIZE -D SERVER_IP` at the client side with
       `-z 0` (no zero-copy) and `-z 1` (zero-copy), and compare MB/s and used CPU time
       (user+system).
  info_ru: |
    OSD и клиенты будут пробовать использовать TCP-отправку без копирования (zero-copy) на
    основе io_uring для буферов, больших, чем это число байт. Отправка без копирования
    поддерживается в io_uring, начиная с версии ядра Linux 6.1. Наличие поддержки
    проверяется автоматически и zero-copy отключается, когда поддержки нет. Также
    её можно отключить явно, установив данный параметр в отрицательное значение.

    ⚠️ Внимание! Производительность данной функции может сильно отличаться на разных
    процессорах и на разных версиях ядра Linux. В целом, zero-copy обычно быстрее с
    большими сообщениями, а с мелкими (например, 4 КБ) zero-copy может быть даже
    медленнее. 32 КБ достаточно почти для всех процессоров, но для каких-то можно
    использовать даже меньшие значения. Например, для EPYC Milan/Genoa подходит 4 КБ,
    а для Xeon Ice Lake - 12 КБ (но, пожалуйста, перепроверьте это сами).

    Инструкция по проверке:
    1. Добавьте `iommu=pt` в командную строку загрузки вашего ядра Linux и перезагрузитесь.
    2. Обновите ядро. Например, для AMD EPYC очень важно использовать версию 6.11+.
    3. Позапускайте тесты с помощью [send-zerocopy из примеров liburing](https://github.com/axboe/liburing/blob/master/examples/send-zerocopy.c),
       чтобы найти минимальный размер сообщения, для которого zero-copy отправка оптимальна.
       Запускайте `./send-zerocopy tcp -4 -R` на стороне сервера и
       `time ./send-zerocopy tcp -4 -b 0 -s РАЗМЕР_БУФЕРА -D АДРЕС_СЕРВЕРА` на стороне клиента
       с опцией `-z 0` (обычная отправка) и `-z 1` (отправка без копирования), и сравнивайте
       скорость в МБ/с и занятое процессорное время (user+system).
- name: use_sync_send_recv
  type: bool
  default: false
  info: |
    If true, synchronous send/recv syscalls are used instead of io_uring for
    socket communication. Useless for OSDs because they require io_uring anyway,
    but may be required for clients with old kernel versions.
  info_ru: |
    Если установлено в истину, то вместо io_uring для передачи данных по сети
    будут использоваться обычные синхронные системные вызовы send/recv. Для OSD
    это бессмысленно, так как OSD в любом случае нуждается в io_uring, но, в
    принципе, это может применяться для клиентов со старыми версиями ядра.
