forked from vitalif/vitastor
Compare commits
19 Commits
v0.6.12
...
non-odp-rd
Author | SHA1 | Date | |
---|---|---|---|
043ed854f3 | |||
73ae578981 | |||
20ee4ed758 | |||
63de79d1b2 | |||
f712967079 | |||
df0cd85352 | |||
ebaf4d7a72 | |||
d4bc10542c | |||
140309620a | |||
0a610ee943 | |||
f3ce166064 | |||
717d303370 | |||
d9857a5340 | |||
eb5d9153e8 | |||
ae6d1ed1d5 | |||
d123e58ea3 | |||
d9869d8116 | |||
4047ca606f | |||
218e294e9c |
@@ -55,11 +55,11 @@ Vitastor на данный момент находится в статусе п
|
||||
|
||||
## Планы развития
|
||||
|
||||
- Поддержка удаления снапшотов (слияния слоёв)
|
||||
- Более корректные скрипты разметки дисков и автоматического запуска OSD
|
||||
- Другие инструменты администрирования
|
||||
- Плагины для OpenNebula и других облачных систем
|
||||
- iSCSI-прокси
|
||||
- Упрощённый NFS прокси
|
||||
- Более быстрое переключение при отказах
|
||||
- Фоновая проверка целостности без контрольных сумм (сверка реплик)
|
||||
- Контрольные суммы
|
||||
|
@@ -49,11 +49,11 @@ breaking changes in the future. However, the following is implemented:
|
||||
|
||||
## Roadmap
|
||||
|
||||
- Snapshot deletion (layer merge) support
|
||||
- Better OSD creation and auto-start tools
|
||||
- Other administrative tools
|
||||
- Plugins for OpenNebula, Proxmox and other cloud systems
|
||||
- Plugins for OpenNebula and other cloud systems
|
||||
- iSCSI proxy
|
||||
- Simplified NFS proxy
|
||||
- Faster failover
|
||||
- Scrubbing without checksums (verification of replicas)
|
||||
- Checksums
|
||||
|
35
docs/params/common.yml
Normal file
35
docs/params/common.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
- name: config_path
|
||||
type: string
|
||||
default: "/etc/vitastor/vitastor.conf"
|
||||
info: |
|
||||
Path to the JSON configuration file. Configuration file is optional,
|
||||
a non-existing configuration file does not prevent Vitastor from
|
||||
running if required parameters are specified.
|
||||
info_ru: |
|
||||
Путь к файлу конфигурации в формате JSON. Файл конфигурации необязателен,
|
||||
без него Vitastor тоже будет работать, если переданы необходимые параметры.
|
||||
- name: etcd_address
|
||||
type: string or array of strings
|
||||
type_ru: строка или массив строк
|
||||
info: |
|
||||
etcd connection endpoint(s). Multiple endpoints may be delimited by "," or
|
||||
specified in a JSON array `["10.0.115.10:2379/v3","10.0.115.11:2379/v3"]`.
|
||||
Note that https is not supported for etcd connections yet.
|
||||
info_ru: |
|
||||
Адрес(а) подключения к etcd. Несколько адресов могут разделяться запятой
|
||||
или указываться в виде JSON-массива `["10.0.115.10:2379/v3","10.0.115.11:2379/v3"]`.
|
||||
- name: etcd_prefix
|
||||
type: string
|
||||
default: "/vitastor"
|
||||
info: |
|
||||
Prefix for all keys in etcd used by Vitastor. You can change prefix and, for
|
||||
example, use a single etcd cluster for multiple Vitastor clusters.
|
||||
info_ru: |
|
||||
Префикс для ключей etcd, которые использует Vitastor. Вы можете задать другой
|
||||
префикс, например, чтобы запустить несколько кластеров Vitastor с одним
|
||||
кластером etcd.
|
||||
- name: log_level
|
||||
type: int
|
||||
default: 0
|
||||
info: Log level. Raise if you want more verbose output.
|
||||
info_ru: Уровень логгирования. Повысьте, если хотите более подробный вывод.
|
200
docs/params/layout-cluster.yml
Normal file
200
docs/params/layout-cluster.yml
Normal file
@@ -0,0 +1,200 @@
|
||||
- name: block_size
|
||||
type: int
|
||||
default: 131072
|
||||
info: |
|
||||
Size of objects (data blocks) into which all physical and virtual drives are
|
||||
subdivided in Vitastor. One of current main settings in Vitastor, affects
|
||||
memory usage, write amplification and I/O load distribution effectiveness.
|
||||
|
||||
Recommended default block size is 128 KB for SSD and 4 MB for HDD. In fact,
|
||||
it's possible to use 4 MB for SSD too - it will lower memory usage, but
|
||||
may increase average WA and reduce linear performance.
|
||||
|
||||
OSDs with different block sizes (for example, SSD and SSD+HDD OSDs) can
|
||||
currently coexist in one etcd instance only within separate Vitastor
|
||||
clusters with different etcd_prefix'es.
|
||||
|
||||
Also block size can't be changed after OSD initialization without losing
|
||||
data.
|
||||
|
||||
You must always specify block_size in etcd in /vitastor/config/global if
|
||||
you change it so all clients can know about it.
|
||||
|
||||
OSD memory usage is roughly (SIZE / BLOCK * 68 bytes) which is roughly
|
||||
544 MB per 1 TB of used disk space with the default 128 KB block size.
|
||||
info_ru: |
|
||||
Размер объектов (блоков данных), на которые делятся физические и виртуальные
|
||||
диски в Vitastor. Одна из ключевых на данный момент настроек, влияет на
|
||||
потребление памяти, объём избыточной записи (write amplification) и
|
||||
эффективность распределения нагрузки по OSD.
|
||||
|
||||
Рекомендуемые по умолчанию размеры блока - 128 килобайт для SSD и 4
|
||||
мегабайта для HDD. В принципе, для SSD можно тоже использовать 4 мегабайта,
|
||||
это понизит использование памяти, но ухудшит распределение нагрузки и в
|
||||
среднем увеличит WA.
|
||||
|
||||
OSD с разными размерами блока (например, SSD и SSD+HDD OSD) на данный
|
||||
момент могут сосуществовать в рамках одного etcd только в виде двух независимых
|
||||
кластеров Vitastor с разными etcd_prefix.
|
||||
|
||||
Также размер блока нельзя менять после инициализации OSD без потери данных.
|
||||
|
||||
Если вы меняете размер блока, обязательно прописывайте его в etcd в
|
||||
/vitastor/config/global, дабы все клиенты его знали.
|
||||
|
||||
Потребление памяти OSD составляет примерно (РАЗМЕР / БЛОК * 68 байт),
|
||||
т.е. примерно 544 МБ памяти на 1 ТБ занятого места на диске при
|
||||
стандартном 128 КБ блоке.
|
||||
- name: bitmap_granularity
|
||||
type: int
|
||||
default: 4096
|
||||
info: |
|
||||
Required virtual disk write alignment ("sector size"). Must be a multiple
|
||||
of disk_alignment. It's called bitmap granularity because Vitastor tracks
|
||||
an allocation bitmap for each object containing 2 bits per each
|
||||
(bitmap_granularity) bytes.
|
||||
|
||||
This parameter can't be changed after OSD initialization without losing
|
||||
data. Also it's fixed for the whole Vitastor cluster i.e. two different
|
||||
values can't be used in a single Vitastor cluster.
|
||||
|
||||
Clients MUST be aware of this parameter value, so put it into etcd key
|
||||
/vitastor/config/global if you change it for any reason.
|
||||
info_ru: |
|
||||
Требуемое выравнивание записи на виртуальные диски (размер их "сектора").
|
||||
Должен быть кратен disk_alignment. Называется гранулярностью битовой карты
|
||||
потому, что Vitastor хранит битовую карту для каждого объекта, содержащую
|
||||
по 2 бита на каждые (bitmap_granularity) байт.
|
||||
|
||||
Данный параметр нельзя менять после инициализации OSD без потери данных.
|
||||
Также он фиксирован для всего кластера Vitastor, т.е. разные значения
|
||||
не могут сосуществовать в одном кластере.
|
||||
|
||||
Клиенты ДОЛЖНЫ знать правильное значение этого параметра, так что если вы
|
||||
его меняете, обязательно прописывайте изменённое значение в etcd в ключ
|
||||
/vitastor/config/global.
|
||||
- name: immediate_commit
|
||||
type: string
|
||||
default: false
|
||||
info: |
|
||||
Another parameter which is really important for performance.
|
||||
|
||||
Desktop SSDs are very fast (100000+ iops) for simple random writes
|
||||
without cache flush. However, they are really slow (only around 1000 iops)
|
||||
if you try to fsync() each write, that is, when you want to guarantee that
|
||||
each change gets immediately persisted to the physical media.
|
||||
|
||||
Server-grade SSDs with "Advanced/Enhanced Power Loss Protection" or with
|
||||
"Supercapacitor-based Power Loss Protection", on the other hand, are equally
|
||||
fast with and without fsync because their cache is protected from sudden
|
||||
power loss by a built-in supercapacitor-based "UPS".
|
||||
|
||||
Some software-defined storage systems always fsync each write and thus are
|
||||
really slow when used with desktop SSDs. Vitastor, however, can also
|
||||
efficiently utilize desktop SSDs by postponing fsync until the client calls
|
||||
it explicitly.
|
||||
|
||||
This is what this parameter regulates. When it's set to "all" the whole
|
||||
Vitastor cluster commits each change to disks immediately and clients just
|
||||
ignore fsyncs because they know for sure that they're unneeded. This reduces
|
||||
the amount of network roundtrips performed by clients and improves
|
||||
performance. So it's always better to use server grade SSDs with
|
||||
supercapacitors even with Vitastor, especially given that they cost only
|
||||
a bit more than desktop models.
|
||||
|
||||
There is also a common SATA SSD (and HDD too!) firmware bug (or feature)
|
||||
that makes server SSDs which have supercapacitors slow with fsync. To check
|
||||
if your SSDs are affected, compare benchmark results from `fio -name=test
|
||||
-ioengine=libaio -direct=1 -bs=4k -rw=randwrite -iodepth=1` with and without
|
||||
`-fsync=1`. Results should be the same. If fsync=1 result is worse you can
|
||||
try to work around this bug by "disabling" drive write-back cache by running
|
||||
`hdparm -W 0 /dev/sdXX` or `echo write through > /sys/block/sdXX/device/scsi_disk/*/cache_type`
|
||||
(IMPORTANT: don't mistake it with `/sys/block/sdXX/queue/write_cache` - it's
|
||||
unsafe to change by hand). The same may apply to newer HDDs with internal
|
||||
SSD cache or "media-cache" - for example, a lot of Seagate EXOS drives have
|
||||
it (they have internal SSD cache even though it's not stated in datasheets).
|
||||
|
||||
This parameter must be set both in etcd in /vitastor/config/global and in
|
||||
OSD command line or configuration. Setting it to "all" or "small" requires
|
||||
enabling disable_journal_fsync and disable_meta_fsync, setting it to "all"
|
||||
also requires enabling disable_data_fsync.
|
||||
|
||||
TLDR: For optimal performance, set immediate_commit to "all" if you only use
|
||||
SSDs with supercapacitor-based power loss protection (nonvolatile
|
||||
write-through cache) for both data and journals in the whole Vitastor
|
||||
cluster. Set it to "small" if you only use such SSDs for journals. Leave
|
||||
empty if your drives have write-back cache.
|
||||
info_ru: |
|
||||
Ещё один важный для производительности параметр.
|
||||
|
||||
Модели SSD для настольных компьютеров очень быстрые (100000+ операций в
|
||||
секунду) при простой случайной записи без сбросов кэша. Однако они очень
|
||||
медленные (всего порядка 1000 iops), если вы пытаетесь сбрасывать кэш после
|
||||
каждой записи, то есть, если вы пытаетесь гарантировать, что каждое
|
||||
изменение физически записывается в энергонезависимую память.
|
||||
|
||||
С другой стороны, серверные SSD с конденсаторами - функцией, называемой
|
||||
"Advanced/Enhanced Power Loss Protection" или просто "Supercapacitor-based
|
||||
Power Loss Protection" - одинаково быстрые и со сбросом кэша, и без
|
||||
него, потому что их кэш защищён от потери питания встроенным "источником
|
||||
бесперебойного питания" на основе суперконденсаторов и на самом деле они
|
||||
его никогда не сбрасывают.
|
||||
|
||||
Некоторые программные СХД всегда сбрасывают кэши дисков при каждой записи
|
||||
и поэтому работают очень медленно с настольными SSD. Vitastor, однако, может
|
||||
откладывать fsync до явного его вызова со стороны клиента и таким образом
|
||||
эффективно утилизировать настольные SSD.
|
||||
|
||||
Данный параметр влияет как раз на это. Когда он установлен в значение "all",
|
||||
весь кластер Vitastor мгновенно фиксирует каждое изменение на физические
|
||||
носители и клиенты могут просто игнорировать запросы fsync, т.к. они точно
|
||||
знают, что fsync-и не нужны. Это уменьшает число необходимых обращений к OSD
|
||||
по сети и улучшает производительность. Поэтому даже с Vitastor лучше всегда
|
||||
использовать только серверные модели SSD с суперконденсаторами, особенно
|
||||
учитывая то, что стоят они ненамного дороже настольных.
|
||||
|
||||
Также в прошивках SATA SSD (и даже HDD!) очень часто встречается либо баг,
|
||||
либо просто особенность логики, из-за которой серверные SSD, имеющие
|
||||
конденсаторы и защиту от потери питания, всё равно медленно работают с
|
||||
fsync. Чтобы понять, подвержены ли этой проблеме ваши SSD, сравните
|
||||
результаты тестов `fio -name=test -ioengine=libaio -direct=1 -bs=4k
|
||||
-rw=randwrite -iodepth=1` без и с опцией `-fsync=1`. Результаты должны
|
||||
быть одинаковые. Если результат с `fsync=1` хуже, вы можете попробовать
|
||||
обойти проблему, "отключив" кэш записи диска командой `hdparm -W 0 /dev/sdXX`
|
||||
либо `echo write through > /sys/block/sdXX/device/scsi_disk/*/cache_type`
|
||||
(ВАЖНО: не перепутайте с `/sys/block/sdXX/queue/write_cache` - этот параметр
|
||||
менять руками небезопасно). Такая же проблема может встречаться и в новых
|
||||
HDD-дисках с внутренним SSD или "медиа" кэшем - например, она встречается во
|
||||
многих дисках Seagate EXOS (у них есть внутренний SSD-кэш, хотя это и не
|
||||
указано в спецификациях).
|
||||
|
||||
Данный параметр нужно указывать и в etcd в /vitastor/config/global, и в
|
||||
командной строке или конфигурации OSD. Значения "all" и "small" требуют
|
||||
включения disable_journal_fsync и disable_meta_fsync, значение "all" также
|
||||
требует включения disable_data_fsync.
|
||||
|
||||
Итого, вкратце: для оптимальной производительности установите
|
||||
immediate_commit в значение "all", если вы используете в кластере только SSD
|
||||
с суперконденсаторами и для данных, и для журналов. Если вы используете
|
||||
такие SSD для всех журналов, но не для данных - можете установить параметр
|
||||
в "small". Если и какие-то из дисков журналов имеют волатильный кэш записи -
|
||||
оставьте параметр пустым.
|
||||
- name: client_dirty_limit
|
||||
type: int
|
||||
default: 33554432
|
||||
info: |
|
||||
Without immediate_commit=all this parameter sets the limit of "dirty"
|
||||
(not committed by fsync) data allowed by the client before forcing an
|
||||
additional fsync and committing the data. Also note that the client always
|
||||
holds a copy of uncommitted data in memory so this setting also affects
|
||||
RAM usage of clients.
|
||||
|
||||
This parameter doesn't affect OSDs themselves.
|
||||
info_ru: |
|
||||
При работе без immediate_commit=all - это лимит объёма "грязных" (не
|
||||
зафиксированных fsync-ом) данных, при достижении которого клиент будет
|
||||
принудительно вызывать fsync и фиксировать данные. Также стоит иметь в виду,
|
||||
что в этом случае до момента fsync клиент хранит копию незафиксированных
|
||||
данных в памяти, то есть, настройка влияет на потребление памяти клиентами.
|
||||
|
||||
Параметр не влияет на сами OSD.
|
205
docs/params/layout-osd.yml
Normal file
205
docs/params/layout-osd.yml
Normal file
@@ -0,0 +1,205 @@
|
||||
- name: data_device
|
||||
type: string
|
||||
info: |
|
||||
Path to the block device to use for data. It's highly recommendded to use
|
||||
stable paths for all device names: `/dev/disk/by-partuuid/xxx...` instead
|
||||
of just `/dev/sda` or `/dev/nvme0n1` to not mess up after server restart.
|
||||
Files can also be used instead of block devices, but this is implemented
|
||||
only for testing purposes and not for production.
|
||||
info_ru: |
|
||||
Путь к диску (блочному устройству) для хранения данных. Крайне рекомендуется
|
||||
использовать стабильные пути: `/dev/disk/by-partuuid/xxx...` вместо простых
|
||||
`/dev/sda` или `/dev/nvme0n1`, чтобы пути не могли спутаться после
|
||||
перезагрузки сервера. Также вместо блочных устройств можно указывать файлы,
|
||||
но это реализовано только для тестирования, а не для боевой среды.
|
||||
- name: meta_device
|
||||
type: string
|
||||
info: |
|
||||
Path to the block device to use for the metadata. Metadata must be on a fast
|
||||
SSD or performance will suffer. If this option is skipped, `data_device` is
|
||||
used for the metadata.
|
||||
info_ru: |
|
||||
Путь к диску метаданных. Метаданные должны располагаться на быстром
|
||||
SSD-диске, иначе производительность пострадает. Если эта опция не указана,
|
||||
для метаданных используется `data_device`.
|
||||
- name: journal_device
|
||||
type: string
|
||||
info: |
|
||||
Path to the block device to use for the journal. Journal must be on a fast
|
||||
SSD or performance will suffer. If this option is skipped, `meta_device` is
|
||||
used for the journal, and if it's also empty, journal is put on
|
||||
`data_device`. It's almost always fine to put metadata and journal on the
|
||||
same device, in this case you only need to set `meta_device`.
|
||||
info_ru: |
|
||||
Путь к диску журнала. Журнал должен располагаться на быстром SSD-диске,
|
||||
иначе производительность пострадает. Если эта опция не указана,
|
||||
для журнала используется `meta_device`, если же пуста и она, журнал
|
||||
располагается на `data_device`. Нормально располагать журнал и метаданные
|
||||
на одном устройстве, в этом случае достаточно указать только `meta_device`.
|
||||
- name: journal_offset
|
||||
type: int
|
||||
default: 0
|
||||
info: Offset on the device in bytes where the journal is stored.
|
||||
info_ru: Смещение на устройстве в байтах, по которому располагается журнал.
|
||||
- name: journal_size
|
||||
type: int
|
||||
info: |
|
||||
Journal size in bytes. Doesn't have to be large, 16-32 MB is usually fine.
|
||||
By default, the whole journal device will be used for the journal. You must
|
||||
set it to some value manually (or use make-osd.sh) if you colocate the
|
||||
journal with data or metadata.
|
||||
info_ru: |
|
||||
Размер журнала в байтах. Большим быть не обязан, 16-32 МБ обычно достаточно.
|
||||
По умолчанию для журнала используется всё устройство журнала. Если же вы
|
||||
размещаете журнал на устройстве данных или метаданных, то вы должны
|
||||
установить эту опцию в какое-то значение сами (или использовать скрипт
|
||||
make-osd.sh).
|
||||
- name: meta_offset
|
||||
type: int
|
||||
default: 0
|
||||
info: |
|
||||
Offset on the device in bytes where the metadata area is stored.
|
||||
Again, set it to something if you colocate metadata with journal or data.
|
||||
info_ru: |
|
||||
Смещение на устройстве в байтах, по которому располагаются метаданные.
|
||||
Эту опцию нужно задать, если метаданные у вас хранятся на том же
|
||||
устройстве, что данные или журнал.
|
||||
- name: data_offset
|
||||
type: int
|
||||
default: 0
|
||||
info: |
|
||||
Offset on the device in bytes where the data area is stored.
|
||||
Again, set it to something if you colocate data with journal or metadata.
|
||||
info_ru: |
|
||||
Смещение на устройстве в байтах, по которому располагаются данные.
|
||||
Эту опцию нужно задать, если данные у вас хранятся на том же
|
||||
устройстве, что метаданные или журнал.
|
||||
- name: data_size
|
||||
type: int
|
||||
info: |
|
||||
Data area size in bytes. By default, the whole data device up to the end
|
||||
will be used for the data area, but you can restrict it if you want to use
|
||||
a smaller part. Note that there is no option to set metadata area size -
|
||||
it's derived from the data area size.
|
||||
info_ru: |
|
||||
Размер области данных в байтах. По умолчанию под данные будет использована
|
||||
вся доступная область устройства данных до конца устройства, но вы можете
|
||||
использовать эту опцию, чтобы ограничить её меньшим размером. Заметьте, что
|
||||
опции размера области метаданных нет - она вычисляется из размера области
|
||||
данных автоматически.
|
||||
- name: meta_block_size
|
||||
type: int
|
||||
default: 4096
|
||||
info: |
|
||||
Physical block size of the metadata device. 4096 for most current
|
||||
HDDs and SSDs.
|
||||
info_ru: |
|
||||
Размер физического блока устройства метаданных. 4096 для большинства
|
||||
современных SSD и HDD.
|
||||
- name: journal_block_size
|
||||
type: int
|
||||
default: 4096
|
||||
info: |
|
||||
Physical block size of the journal device. Must be a multiple of
|
||||
`disk_alignment`. 4096 for most current HDDs and SSDs.
|
||||
info_ru: |
|
||||
Размер физического блока устройства журнала. Должен быть кратен
|
||||
`disk_alignment`. 4096 для большинства современных SSD и HDD.
|
||||
- name: disable_data_fsync
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Do not issue fsyncs to the data device, i.e. do not flush its cache.
|
||||
Safe ONLY if your data device has write-through cache. If you disable
|
||||
the cache yourself using `hdparm` or `scsi_disk/cache_type` then make sure
|
||||
that the cache disable command is run every time before starting Vitastor
|
||||
OSD, for example, in the systemd unit. See also `immediate_commit` option
|
||||
for the instructions to disable cache and how to benefit from it.
|
||||
info_ru: |
|
||||
Не отправлять fsync-и устройству данных, т.е. не сбрасывать его кэш.
|
||||
Безопасно, ТОЛЬКО если ваше устройство данных имеет кэш со сквозной
|
||||
записью (write-through). Если вы отключаете кэш через `hdparm` или
|
||||
`scsi_disk/cache_type`, то удостоверьтесь, что команда отключения кэша
|
||||
выполняется перед каждым запуском Vitastor OSD, например, в systemd unit-е.
|
||||
Смотрите также опцию `immediate_commit` для инструкций по отключению кэша
|
||||
и о том, как из этого извлечь выгоду.
|
||||
- name: disable_meta_fsync
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Same as disable_data_fsync, but for the metadata device. If the metadata
|
||||
device is not set or if the data device is used for the metadata the option
|
||||
is ignored and disable_data_fsync value is used instead of it.
|
||||
info_ru: |
|
||||
То же, что disable_data_fsync, но для устройства метаданных. Если устройство
|
||||
метаданных не задано или если оно равно устройству данных, значение опции
|
||||
игнорируется и вместо него используется значение опции disable_data_fsync.
|
||||
- name: disable_journal_fsync
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Same as disable_data_fsync, but for the journal device. If the journal
|
||||
device is not set or if the metadata device is used for the journal the
|
||||
option is ignored and disable_meta_fsync value is used instead of it. If
|
||||
the same device is used for data, metadata and journal the option is also
|
||||
ignored and disable_data_fsync value is used instead of it.
|
||||
info_ru: |
|
||||
То же, что disable_data_fsync, но для устройства журнала. Если устройство
|
||||
журнала не задано или если оно равно устройству метаданных, значение опции
|
||||
игнорируется и вместо него используется значение опции disable_meta_fsync.
|
||||
Если одно и то же устройство используется и под данные, и под журнал, и под
|
||||
метаданные - значение опции также игнорируется и вместо него используется
|
||||
значение опции disable_data_fsync.
|
||||
- name: disable_device_lock
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Do not lock data, metadata and journal block devices exclusively with
|
||||
flock(). Though it's not recommended, but you can use it you want to run
|
||||
multiple OSD with a single device and different offsets, without using
|
||||
partitions.
|
||||
info_ru: |
|
||||
Не блокировать устройства данных, метаданных и журнала от открытия их
|
||||
другими OSD с помощью flock(). Так делать не рекомендуется, но теоретически
|
||||
вы можете это использовать, чтобы запускать несколько OSD на одном
|
||||
устройстве с разными смещениями и без использования разделов.
|
||||
- name: disk_alignment
|
||||
type: int
|
||||
default: 4096
|
||||
info: |
|
||||
Required physical disk write alignment. Most current SSD and HDD drives
|
||||
use 4 KB physical sectors even if they report 512 byte logical sector
|
||||
size, so 4 KB is a good default setting.
|
||||
|
||||
Note, however, that physical sector size also affects WA, because with block
|
||||
devices it's impossible to write anything smaller than a block. So, when
|
||||
Vitastor has to write a single metadata entry that's only about 32 bytes in
|
||||
size, it actually has to write the whole 4 KB sector.
|
||||
|
||||
Because of this it can actually be beneficial to use SSDs which work well
|
||||
with 512 byte sectors and use 512 byte disk_alignment, journal_block_size
|
||||
and meta_block_size. But the only SSD that may fit into this category is
|
||||
Intel Optane (probably, not tested yet).
|
||||
|
||||
Clients don't need to be aware of disk_alignment, so it's not required to
|
||||
put a modified value into etcd key /vitastor/config/global.
|
||||
info_ru: |
|
||||
Требуемое выравнивание записи на физические диски. Почти все современные
|
||||
SSD и HDD диски используют 4 КБ физические секторы, даже если показывают
|
||||
логический размер сектора 512 байт, поэтому 4 КБ - хорошее значение по
|
||||
умолчанию.
|
||||
|
||||
Однако стоит понимать, что физический размер сектора тоже влияет на
|
||||
избыточную запись (WA), потому что ничего меньше блока (сектора) на блочное
|
||||
устройство записать невозможно. Таким образом, когда Vitastor-у нужно
|
||||
записать на диск всего лишь одну 32-байтную запись метаданных, фактически
|
||||
приходится перезаписывать 4 КБ сектор целиком.
|
||||
|
||||
Поэтому, на самом деле, может быть выгодно найти SSD, хорошо работающие с
|
||||
меньшими, 512-байтными, блоками и использовать 512-байтные disk_alignment,
|
||||
journal_block_size и meta_block_size. Однако единственные SSD, которые
|
||||
теоретически могут попасть в эту категорию - это Intel Optane (но и это
|
||||
пока не проверялось автором).
|
||||
|
||||
Клиентам не обязательно знать про disk_alignment, так что помещать значение
|
||||
этого параметра в etcd в /vitastor/config/global не нужно.
|
65
docs/params/monitor.yml
Normal file
65
docs/params/monitor.yml
Normal file
@@ -0,0 +1,65 @@
|
||||
- name: etcd_mon_ttl
|
||||
type: sec
|
||||
min: 10
|
||||
default: 30
|
||||
info: Monitor etcd lease refresh interval in seconds
|
||||
info_ru: Интервал обновления etcd резервации (lease) монитором
|
||||
- name: etcd_mon_timeout
|
||||
type: ms
|
||||
default: 1000
|
||||
info: etcd request timeout used by monitor
|
||||
info_ru: Таймаут выполнения запросов к etcd от монитора
|
||||
- name: etcd_mon_retries
|
||||
type: int
|
||||
default: 5
|
||||
info: Maximum number of attempts for one monitor etcd request
|
||||
info_ru: Максимальное число попыток выполнения запросов к etcd монитором
|
||||
- name: mon_change_timeout
|
||||
type: ms
|
||||
min: 100
|
||||
default: 1000
|
||||
info: Optimistic retry interval for monitor etcd modification requests
|
||||
info_ru: Время повтора при коллизиях при запросах модификации в etcd, производимых монитором
|
||||
- name: mon_stats_timeout
|
||||
type: ms
|
||||
min: 100
|
||||
default: 1000
|
||||
info: |
|
||||
Interval for monitor to wait before updating aggregated statistics in
|
||||
etcd after receiving OSD statistics updates
|
||||
info_ru: |
|
||||
Интервал, который монитор ожидает при изменении статистики по отдельным
|
||||
OSD перед обновлением агрегированной статистики в etcd
|
||||
- name: osd_out_time
|
||||
type: sec
|
||||
default: 600
|
||||
info: |
|
||||
Time after which a failed OSD is removed from the data distribution.
|
||||
I.e. time which the monitor waits before attempting to restore data
|
||||
redundancy using other OSDs.
|
||||
info_ru: |
|
||||
Время, через которое отключенный OSD исключается из распределения данных.
|
||||
То есть, время, которое монитор ожидает перед попыткой переместить данные
|
||||
на другие OSD и таким образом восстановить избыточность хранения.
|
||||
- name: placement_levels
|
||||
type: json
|
||||
default: '`{"host":100,"osd":101}`'
|
||||
info: |
|
||||
Levels for the placement tree. You can define arbitrary tree levels by
|
||||
defining them in this parameter. The configuration parameter value should
|
||||
contain a JSON object with level names as keys and integer priorities as
|
||||
values. Smaller priority means higher level in tree. For example,
|
||||
"datacenter" should have smaller priority than "osd". "host" and "osd"
|
||||
levels are always predefined and can't be removed. If one of them is not
|
||||
present in the configuration, then it is defined with the default priority
|
||||
(100 for "host", 101 for "osd").
|
||||
info_ru: |
|
||||
Определения уровней для дерева размещения OSD. Вы можете определять
|
||||
произвольные уровни, помещая их в данный параметр конфигурации. Значение
|
||||
параметра должно содержать JSON-объект, ключи которого будут являться
|
||||
названиями уровней, а значения - целочисленными приоритетами. Меньшие
|
||||
приоритеты соответствуют верхним уровням дерева. Например, уровень
|
||||
"датацентр" должен иметь меньший приоритет, чем "OSD". Уровни с названиями
|
||||
"host" и "osd" являются предопределёнными и не могут быть удалены. Если
|
||||
один из них отсутствует в конфигурации, он доопределяется с приоритетом по
|
||||
умолчанию (100 для уровня "host", 101 для "osd").
|
234
docs/params/network.yml
Normal file
234
docs/params/network.yml
Normal file
@@ -0,0 +1,234 @@
|
||||
- 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: 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, но, в
|
||||
принципе, это может применяться для клиентов со старыми версиями ядра.
|
||||
- name: use_rdma
|
||||
type: bool
|
||||
default: true
|
||||
info: |
|
||||
Try to use RDMA for communication if it's available. Disable if you don't
|
||||
want Vitastor to use RDMA. RDMA increases the performance, but TCP-only
|
||||
clients can still talk to an RDMA-enabled cluster, so you don't need to
|
||||
make sure that all clients support RDMA when enabling it.
|
||||
info_ru: |
|
||||
Пытаться использовать RDMA для связи при наличии доступных устройств.
|
||||
Отключите, если вы не хотите, чтобы Vitastor использовал RDMA.
|
||||
RDMA улучшает производительность, но
|
||||
Клиенты и клиентов and TCP-only clients in the cluster at the
|
||||
same time - TCP-only clients are still able to use an RDMA-enabled cluster.
|
||||
- name: rdma_device
|
||||
type: string
|
||||
info: |
|
||||
RDMA device name to use for Vitastor OSD communications (for example,
|
||||
"rocep5s0f0"). Please note that if your RDMA device doesn't support
|
||||
Implicit ODP (Implicit On-Demand Paging) then all Vitastor OSDs and clients
|
||||
will have to use mlockall() to lock all application memory to use RDMA.
|
||||
In case of the native Vitastor QEMU driver with RDMA, all virtual machine
|
||||
memory will be locked if your RDMA device doesn't support Implicit ODP.
|
||||
|
||||
Notably, Mellanox ConnectX-3 and older adapters don't support Implicit ODP,
|
||||
while ConnectX-4 and newer do. Run `ibv_devinfo -v` as root to list
|
||||
available RDMA devices and their features.
|
||||
info_ru: |
|
||||
Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0").
|
||||
Имейте в виду, что если ваше устройство не поддерживает Implicit ODP
|
||||
(Implicit On-Demand Paging), то все OSD и клиенты Vitastor будут вынуждены
|
||||
блокировать всю память приложения с помощью mlockall(), чтобы задействовать
|
||||
RDMA. В случае нативного QEMU-драйвера это будет означать, что при
|
||||
использовании RDMA на устройстве без поддержки Implicit ODP блокироваться
|
||||
от выгрузки будет вся память виртуальных машин.
|
||||
|
||||
В случае с адаптерами Mellanox Implicit ODP поддерживается начиная с
|
||||
ConnectX-4. ConnectX-3 и более старые адаптеры не поддерживают Implicit ODP.
|
||||
Чтобы посмотреть список своих RDMA-устройств и их возможностей, запустите
|
||||
`ibv_devinfo -v` от имени суперпользователя.
|
||||
- name: rdma_port_num
|
||||
type: int
|
||||
default: 1
|
||||
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.
|
||||
info_ru: |
|
||||
Номер порта RDMA-устройства, который следует использовать. Имеет смысл
|
||||
только для устройств, у которых более 1 порта. Чтобы узнать, сколько портов
|
||||
у вашего адаптера, посмотрите `phys_port_cnt` в выводе команды
|
||||
`ibv_devinfo -v`.
|
||||
- name: rdma_gid_index
|
||||
type: int
|
||||
default: 0
|
||||
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.
|
||||
|
||||
**IMPORTANT:** If you want to use RoCEv2 (as recommended) then the correct
|
||||
rdma_gid_index is usually 1 (IPv6) or 3 (IPv4).
|
||||
info_ru: |
|
||||
Номер глобального идентификатора адреса RDMA-устройства, который следует
|
||||
использовать. Разным gid_index могут соответствовать разные протоколы связи:
|
||||
RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со
|
||||
словом "GID" в выводе команды `ibv_devinfo -v`.
|
||||
|
||||
**ВАЖНО:** Если вы хотите использовать RoCEv2 (как мы и рекомендуем), то
|
||||
правильный rdma_gid_index, как правило, 1 (IPv6) или 3 (IPv4).
|
||||
- name: rdma_mtu
|
||||
type: int
|
||||
default: 4096
|
||||
info: |
|
||||
RDMA Path MTU to use. Must be 1024, 2048 or 4096. There is usually no
|
||||
sense to change it from the default 4096.
|
||||
info_ru: |
|
||||
Максимальная единица передачи (Path MTU) для RDMA. Должно быть равно 1024,
|
||||
2048 или 4096. Обычно нет смысла менять значение по умолчанию, равное 4096.
|
||||
- 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: 1048576
|
||||
info: Maximum size of a single RDMA send or receive operation in bytes.
|
||||
info_ru: Максимальный размер одной RDMA-операции отправки или приёма.
|
||||
- name: rdma_max_recv
|
||||
type: int
|
||||
default: 8
|
||||
info: |
|
||||
Maximum number of parallel RDMA receive operations. Note that this number
|
||||
of receive buffers `rdma_max_msg` in size are allocated for each client,
|
||||
so this setting actually affects memory usage. This is because RDMA receive
|
||||
operations are (sadly) still not zero-copy in Vitastor. It may be fixed in
|
||||
later versions.
|
||||
info_ru: |
|
||||
Максимальное число параллельных RDMA-операций получения данных. Следует
|
||||
иметь в виду, что данное число буферов размером `rdma_max_msg` выделяется
|
||||
для каждого подключённого клиентского соединения, так что данная настройка
|
||||
влияет на потребление памяти. Это так потому, что RDMA-приём данных в
|
||||
Vitastor, увы, всё равно не является zero-copy, т.е. всё равно 1 раз
|
||||
копирует данные в памяти. Данная особенность, возможно, будет исправлена в
|
||||
более новых версиях Vitastor.
|
||||
- name: peer_connect_interval
|
||||
type: sec
|
||||
min: 1
|
||||
default: 5
|
||||
info: Interval before attempting to reconnect to an unavailable OSD.
|
||||
info_ru: Время ожидания перед повторной попыткой соединиться с недоступным OSD.
|
||||
- name: peer_connect_timeout
|
||||
type: sec
|
||||
min: 1
|
||||
default: 5
|
||||
info: Timeout for OSD connection attempts.
|
||||
info_ru: Максимальное время ожидания попытки соединения с OSD.
|
||||
- name: osd_idle_timeout
|
||||
type: sec
|
||||
min: 1
|
||||
default: 5
|
||||
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
|
||||
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: up_wait_retry_interval
|
||||
type: ms
|
||||
min: 50
|
||||
default: 500
|
||||
info: |
|
||||
OSDs respond to clients with a special error code when they receive I/O
|
||||
requests for a PG that's not synchronized and started. This parameter sets
|
||||
the time for the clients to wait before re-attempting such I/O requests.
|
||||
info_ru: |
|
||||
Когда OSD получают от клиентов запросы ввода-вывода, относящиеся к не
|
||||
поднятым на данный момент на них PG, либо к PG в процессе синхронизации,
|
||||
они отвечают клиентам специальным кодом ошибки, означающим, что клиент
|
||||
должен некоторое время подождать перед повторением запроса. Именно это время
|
||||
ожидания задаёт данный параметр.
|
||||
- name: max_etcd_attempts
|
||||
type: int
|
||||
default: 5
|
||||
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
|
||||
info: |
|
||||
Timeout for etcd requests which should complete quickly, like lease refresh.
|
||||
info_ru: |
|
||||
Максимальное время выполнения запросов к etcd, которые должны завершаться
|
||||
быстро, таких, как обновление резервации (lease).
|
||||
- name: etcd_slow_timeout
|
||||
type: ms
|
||||
default: 5000
|
||||
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)
|
||||
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_timeout
|
||||
type: sec
|
||||
default: 30
|
||||
info: |
|
||||
etcd websocket ping interval required to keep the connection alive and
|
||||
detect disconnections quickly.
|
||||
info_ru: |
|
||||
Интервал проверки живости вебсокет-подключений к etcd.
|
341
docs/params/osd.yml
Normal file
341
docs/params/osd.yml
Normal file
@@ -0,0 +1,341 @@
|
||||
- name: etcd_report_interval
|
||||
type: sec
|
||||
default: 5
|
||||
info: |
|
||||
Interval at which OSDs report their state to etcd. Affects OSD lease time
|
||||
and thus the failover speed. Lease time is equal to this parameter value
|
||||
plus max_etcd_attempts * etcd_quick_timeout because it should be guaranteed
|
||||
that every OSD always refreshes its lease in time.
|
||||
info_ru: |
|
||||
Интервал, с которым OSD обновляет своё состояние в etcd. Значение параметра
|
||||
влияет на время резервации (lease) OSD и поэтому на скорость переключения
|
||||
при падении OSD. Время lease равняется значению этого параметра плюс
|
||||
max_etcd_attempts * etcd_quick_timeout.
|
||||
- name: run_primary
|
||||
type: bool
|
||||
default: true
|
||||
info: |
|
||||
Start primary OSD logic on this OSD. As of now, can be turned off only for
|
||||
debugging purposes. It's possible to implement additional feature for the
|
||||
monitor which may allow to separate primary and secondary OSDs, but it's
|
||||
unclear why anyone could need it, so it's not implemented.
|
||||
info_ru: |
|
||||
Запускать логику первичного OSD на данном OSD. На данный момент отключать
|
||||
эту опцию может иметь смысл только в целях отладки. В теории, можно
|
||||
реализовать дополнительный режим для монитора, который позволит отделять
|
||||
первичные OSD от вторичных, но пока не понятно, зачем это может кому-то
|
||||
понадобиться, поэтому это не реализовано.
|
||||
- name: osd_network
|
||||
type: string or array of strings
|
||||
type_ru: строка или массив строк
|
||||
info: |
|
||||
Network mask of the network (IPv4 or IPv6) to use for OSDs. Note that
|
||||
although it's possible to specify multiple networks here, this does not
|
||||
mean that OSDs will create multiple listening sockets - they'll only
|
||||
pick the first matching address of an UP + RUNNING interface. Separate
|
||||
networks for cluster and client connections are also not implemented, but
|
||||
they are mostly useless anyway, so it's not a big deal.
|
||||
info_ru: |
|
||||
Маска подсети (IPv4 или IPv6) для использования для соединений с OSD.
|
||||
Имейте в виду, что хотя сейчас и можно передать в этот параметр несколько
|
||||
подсетей, это не означает, что OSD будут создавать несколько слушающих
|
||||
сокетов - они лишь будут выбирать адрес первого поднятого (состояние UP +
|
||||
RUNNING), подходящий под заданную маску. Также не реализовано разделение
|
||||
кластерной и публичной сетей OSD. Правда, от него обычно всё равно довольно
|
||||
мало толку, так что особенной проблемы в этом нет.
|
||||
- name: bind_address
|
||||
type: string
|
||||
default: "0.0.0.0"
|
||||
info: |
|
||||
Instead of the network mask, you can also set OSD listen address explicitly
|
||||
using this parameter. May be useful if you want to start OSDs on interfaces
|
||||
that are not UP + RUNNING.
|
||||
info_ru: |
|
||||
Этим параметром можно явным образом задать адрес, на котором будет ожидать
|
||||
соединений OSD (вместо использования маски подсети). Может быть полезно,
|
||||
например, чтобы запускать OSD на неподнятых интерфейсах (не UP + RUNNING).
|
||||
- name: bind_port
|
||||
type: int
|
||||
info: |
|
||||
By default, OSDs pick random ports to use for incoming connections
|
||||
automatically. With this option you can set a specific port for a specific
|
||||
OSD by hand.
|
||||
info_ru: |
|
||||
По умолчанию OSD сами выбирают случайные порты для входящих подключений.
|
||||
С помощью данной опции вы можете задать порт для отдельного OSD вручную.
|
||||
- name: autosync_interval
|
||||
type: sec
|
||||
default: 5
|
||||
info: |
|
||||
Time interval at which automatic fsyncs/flushes are issued by each OSD when
|
||||
the immediate_commit mode if disabled. fsyncs are required because without
|
||||
them OSDs quickly fill their journals, become unable to clear them and
|
||||
stall. Also this option limits the amount of recent uncommitted changes
|
||||
which OSDs may lose in case of a power outage in case when clients don't
|
||||
issue fsyncs at all.
|
||||
info_ru: |
|
||||
Временной интервал отправки автоматических fsync-ов (операций очистки кэша)
|
||||
каждым OSD для случая, когда режим immediate_commit отключён. fsync-и нужны
|
||||
OSD, чтобы успевать очищать журнал - без них OSD быстро заполняют журналы и
|
||||
перестают обрабатывать операции записи. Также эта опция ограничивает объём
|
||||
недавних незафиксированных изменений, которые OSD могут терять при
|
||||
отключении питания, если клиенты вообще не отправляют fsync.
|
||||
- name: autosync_writes
|
||||
type: int
|
||||
default: 128
|
||||
info: |
|
||||
Same as autosync_interval, but sets the maximum number of uncommitted write
|
||||
operations before issuing an fsync operation internally.
|
||||
info_ru: |
|
||||
Аналогично autosync_interval, но задаёт не временной интервал, а
|
||||
максимальное количество незафиксированных операций записи перед
|
||||
принудительной отправкой fsync-а.
|
||||
- name: recovery_queue_depth
|
||||
type: int
|
||||
default: 4
|
||||
info: |
|
||||
Maximum recovery operations per one primary OSD at any given moment of time.
|
||||
Currently it's the only parameter available to tune the speed or recovery
|
||||
and rebalancing, but it's planned to implement more.
|
||||
info_ru: |
|
||||
Максимальное число операций восстановления на одном первичном OSD в любой
|
||||
момент времени. На данный момент единственный параметр, который можно менять
|
||||
для ускорения или замедления восстановления и перебалансировки данных, но
|
||||
в планах реализация других параметров.
|
||||
- name: recovery_sync_batch
|
||||
type: int
|
||||
default: 16
|
||||
info: Maximum number of recovery operations before issuing an additional fsync.
|
||||
info_ru: Максимальное число операций восстановления перед дополнительным fsync.
|
||||
- name: readonly
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Read-only mode. If this is enabled, an OSD will never issue any writes to
|
||||
the underlying device. This may be useful for recovery purposes.
|
||||
info_ru: |
|
||||
Режим "только чтение". Если включить этот режим, OSD не будет писать ничего
|
||||
на диск. Может быть полезно в целях восстановления.
|
||||
- name: no_recovery
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Disable automatic background recovery of objects. Note that it doesn't
|
||||
affect implicit recovery of objects happening during writes - a write is
|
||||
always made to a full set of at least pg_minsize OSDs.
|
||||
info_ru: |
|
||||
Отключить автоматическое фоновое восстановление объектов. Обратите внимание,
|
||||
что эта опция не отключает восстановление объектов, происходящее при
|
||||
записи - запись всегда производится в полный набор из как минимум pg_minsize
|
||||
OSD.
|
||||
- name: no_rebalance
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Disable background movement of data between different OSDs. Disabling it
|
||||
means that PGs in the `has_misplaced` state will be left in it indefinitely.
|
||||
info_ru: |
|
||||
Отключить фоновое перемещение объектов между разными OSD. Отключение
|
||||
означает, что PG, находящиеся в состоянии `has_misplaced`, будут оставлены
|
||||
в нём на неопределённый срок.
|
||||
- name: print_stats_interval
|
||||
type: sec
|
||||
default: 3
|
||||
info: |
|
||||
Time interval at which OSDs print simple human-readable operation
|
||||
statistics on stdout.
|
||||
info_ru: |
|
||||
Временной интервал, с которым OSD печатают простую человекочитаемую
|
||||
статистику выполнения операций в стандартный вывод.
|
||||
- name: slow_log_interval
|
||||
type: sec
|
||||
default: 10
|
||||
info: |
|
||||
Time interval at which OSDs dump slow or stuck operations on stdout, if
|
||||
they're any. Also it's the time after which an operation is considered
|
||||
"slow".
|
||||
info_ru: |
|
||||
Временной интервал, с которым OSD выводят в стандартный вывод список
|
||||
медленных или зависших операций, если таковые имеются. Также время, при
|
||||
превышении которого операция считается "медленной".
|
||||
- name: max_write_iodepth
|
||||
type: int
|
||||
default: 128
|
||||
info: |
|
||||
Parallel client write operation limit per one OSD. Operations that exceed
|
||||
this limit are pushed to a temporary queue instead of being executed
|
||||
immediately.
|
||||
info_ru: |
|
||||
Максимальное число одновременных клиентских операций записи на один OSD.
|
||||
Операции, превышающие этот лимит, не исполняются сразу, а сохраняются во
|
||||
временной очереди.
|
||||
- name: min_flusher_count
|
||||
type: int
|
||||
default: 1
|
||||
info: |
|
||||
Flusher is a micro-thread that moves data from the journal to the data
|
||||
area of the device. Their number is auto-tuned between minimum and maximum.
|
||||
Minimum number is set by this parameter.
|
||||
info_ru: |
|
||||
Flusher - это микро-поток (корутина), которая копирует данные из журнала в
|
||||
основную область устройства данных. Их число настраивается динамически между
|
||||
минимальным и максимальным значением. Этот параметр задаёт минимальное число.
|
||||
- name: max_flusher_count
|
||||
type: int
|
||||
default: 256
|
||||
info: |
|
||||
Maximum number of journal flushers (see above min_flusher_count).
|
||||
info_ru: |
|
||||
Максимальное число микро-потоков очистки журнала (см. выше min_flusher_count).
|
||||
- name: inmemory_metadata
|
||||
type: bool
|
||||
default: true
|
||||
info: |
|
||||
This parameter makes Vitastor always keep metadata area of the block device
|
||||
in memory. It's required for good performance because it allows to avoid
|
||||
additional read-modify-write cycles during metadata modifications. Metadata
|
||||
area size is currently roughly 224 MB per 1 TB of data. You can turn it off
|
||||
to reduce memory usage by this value, but it will hurt performance. This
|
||||
restriction is likely to be removed in the future along with the upgrade
|
||||
of the metadata storage scheme.
|
||||
info_ru: |
|
||||
Данный параметр заставляет Vitastor всегда держать область метаданных диска
|
||||
в памяти. Это нужно, чтобы избегать дополнительных операций чтения с диска
|
||||
при записи. Размер области метаданных на данный момент составляет примерно
|
||||
224 МБ на 1 ТБ данных. При включении потребление памяти снизится примерно
|
||||
на эту величину, но при этом также снизится и производительность. В будущем,
|
||||
после обновления схемы хранения метаданных, это ограничение, скорее всего,
|
||||
будет ликвидировано.
|
||||
- name: inmemory_journal
|
||||
type: bool
|
||||
default: true
|
||||
info: |
|
||||
This parameter make Vitastor always keep journal area of the block
|
||||
device in memory. Turning it off will, again, reduce memory usage, but
|
||||
hurt performance because flusher coroutines will have to read data from
|
||||
the disk back before copying it into the main area. The memory usage benefit
|
||||
is typically very small because it's sufficient to have 16-32 MB journal
|
||||
for SSD OSDs. However, in theory it's possible that you'll want to turn it
|
||||
off for hybrid (HDD+SSD) OSDs with large journals on quick devices.
|
||||
info_ru: |
|
||||
Данный параметр заставляет Vitastor всегда держать в памяти журналы OSD.
|
||||
Отключение параметра, опять же, снижает потребление памяти, но ухудшает
|
||||
производительность, так как для копирования данных из журнала в основную
|
||||
область устройства OSD будут вынуждены читать их обратно с диска. Выигрыш
|
||||
по памяти при этом обычно крайне низкий, так как для SSD OSD обычно
|
||||
достаточно 16- или 32-мегабайтного журнала. Однако в теории отключение
|
||||
параметра может оказаться полезным для гибридных OSD (HDD+SSD) с большими
|
||||
журналами, расположенными на быстром по сравнению с HDD устройстве.
|
||||
- name: journal_sector_buffer_count
|
||||
type: int
|
||||
default: 32
|
||||
info: |
|
||||
Maximum number of buffers that can be used for writing journal metadata
|
||||
blocks. The only situation when you should increase it to a larger value
|
||||
is when you enable journal_no_same_sector_overwrites. In this case set
|
||||
it to, for example, 1024.
|
||||
info_ru: |
|
||||
Максимальное число буферов, разрешённых для использования под записываемые
|
||||
в журнал блоки метаданных. Единственная ситуация, в которой этот параметр
|
||||
нужно менять - это если вы включаете journal_no_same_sector_overwrites. В
|
||||
этом случае установите данный параметр, например, в 1024.
|
||||
- name: journal_no_same_sector_overwrites
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Enable this option for SSDs like Intel D3-S4510 and D3-S4610 which REALLY
|
||||
don't like when a program overwrites the same sector multiple times in a
|
||||
row and slow down significantly (from 25000+ iops to ~3000 iops). When
|
||||
this option is set, Vitastor will always move to the next sector of the
|
||||
journal after writing it instead of possibly overwriting it the second time.
|
||||
info_ru: |
|
||||
Включайте данную опцию для SSD вроде Intel D3-S4510 и D3-S4610, которые
|
||||
ОЧЕНЬ не любят, когда ПО перезаписывает один и тот же сектор несколько раз
|
||||
подряд. Такие SSD при многократной перезаписи одного и того же сектора
|
||||
сильно замедляются - условно, с 25000 и более iops до 3000 iops. Когда
|
||||
данная опция установлена, Vitastor всегда переходит к следующему сектору
|
||||
журнала после записи вместо потенциально повторной перезаписи того же
|
||||
самого сектора.
|
||||
- name: throttle_small_writes
|
||||
type: bool
|
||||
default: false
|
||||
info: |
|
||||
Enable soft throttling of small journaled writes. Useful for hybrid OSDs
|
||||
with fast journal/metadata devices and slow data devices. The idea is that
|
||||
small writes complete very quickly because they're first written to the
|
||||
journal device, but moving them to the main device is slow. So if an OSD
|
||||
allows clients to issue a lot of small writes it will perform very good
|
||||
for several seconds and then the journal will fill up and the performance
|
||||
will drop to almost zero. Throttling is meant to prevent this problem by
|
||||
artifically slowing quick writes down based on the amount of free space in
|
||||
the journal. When throttling is used, the performance of small writes will
|
||||
decrease smoothly instead of abrupt drop at the moment when the journal
|
||||
fills up.
|
||||
info_ru: |
|
||||
Разрешить мягкое ограничение скорости журналируемой записи. Полезно для
|
||||
гибридных OSD с быстрыми устройствами метаданных и медленными устройствами
|
||||
данных. Идея заключается в том, что мелкие записи в этой ситуации могут
|
||||
завершаться очень быстро, так как они изначально записываются на быстрое
|
||||
журнальное устройство (SSD). Но перемещать их потом на основное медленное
|
||||
устройство долго. Поэтому если OSD быстро примет от клиентов очень много
|
||||
мелких операций записи, он быстро заполнит свой журнал, после чего
|
||||
производительность записи резко упадёт практически до нуля. Ограничение
|
||||
скорости записи призвано решить эту проблему с помощью искусственного
|
||||
замедления операций записи на основании объёма свободного места в журнале.
|
||||
Когда эта опция включена, производительность мелких операций записи будет
|
||||
снижаться плавно, а не резко в момент окончательного заполнения журнала.
|
||||
- name: throttle_target_iops
|
||||
type: int
|
||||
default: 100
|
||||
info: |
|
||||
Target maximum number of throttled operations per second under the condition
|
||||
of full journal. Set it to approximate random write iops of your data devices
|
||||
(HDDs).
|
||||
info_ru: |
|
||||
Расчётное максимальное число ограничиваемых операций в секунду при условии
|
||||
отсутствия свободного места в журнале. Устанавливайте приблизительно равным
|
||||
максимальной производительности случайной записи ваших устройств данных
|
||||
(HDD) в операциях в секунду.
|
||||
- name: throttle_target_mbs
|
||||
type: int
|
||||
default: 100
|
||||
info: |
|
||||
Target maximum bandwidth in MB/s of throttled operations per second under
|
||||
the condition of full journal. Set it to approximate linear write
|
||||
performance of your data devices (HDDs).
|
||||
info_ru: |
|
||||
Расчётный максимальный размер в МБ/с ограничиваемых операций в секунду при
|
||||
условии отсутствия свободного места в журнале. Устанавливайте приблизительно
|
||||
равным максимальной производительности линейной записи ваших устройств
|
||||
данных (HDD).
|
||||
- name: throttle_target_parallelism
|
||||
type: int
|
||||
default: 1
|
||||
info: |
|
||||
Target maximum parallelism of throttled operations under the condition of
|
||||
full journal. Set it to approximate internal parallelism of your data
|
||||
devices (1 for HDDs, 4-8 for SSDs).
|
||||
info_ru: |
|
||||
Расчётный максимальный параллелизм ограничиваемых операций в секунду при
|
||||
условии отсутствия свободного места в журнале. Устанавливайте приблизительно
|
||||
равным внутреннему параллелизму ваших устройств данных (1 для HDD, 4-8
|
||||
для SSD).
|
||||
- name: throttle_threshold_us
|
||||
type: us
|
||||
default: 50
|
||||
info: |
|
||||
Minimal computed delay to be applied to throttled operations. Usually
|
||||
doesn't need to be changed.
|
||||
info_ru: |
|
||||
Минимальная применимая к ограничиваемым операциям задержка. Обычно не
|
||||
требует изменений.
|
||||
- name: osd_memlock
|
||||
type: bool
|
||||
default: false
|
||||
info: >
|
||||
Lock all OSD memory to prevent it from being unloaded into swap with
|
||||
mlockall(). Requires sufficient ulimit -l (max locked memory).
|
||||
info_ru: >
|
||||
Блокировать всю память OSD с помощью mlockall, чтобы запретить её выгрузку
|
||||
в пространство подкачки. Требует достаточного значения ulimit -l (лимита
|
||||
заблокированной памяти).
|
12
mon/mon.js
12
mon/mon.js
@@ -83,13 +83,13 @@ const etcd_tree = {
|
||||
osd_idle_timeout: 5, // seconds. min: 1
|
||||
osd_ping_timeout: 5, // seconds. min: 1
|
||||
up_wait_retry_interval: 500, // ms. min: 50
|
||||
// osd
|
||||
etcd_report_interval: 5, // seconds
|
||||
max_etcd_attempts: 5,
|
||||
etcd_quick_timeout: 1000, // ms
|
||||
etcd_slow_timeout: 5000, // ms
|
||||
etcd_keepalive_timeout: 30, // seconds, default is min(30, etcd_report_interval*2)
|
||||
etcd_keepalive_timeout: 30, // seconds, default is max(30, etcd_report_interval*2)
|
||||
etcd_ws_keepalive_interval: 30, // seconds
|
||||
// osd
|
||||
etcd_report_interval: 5, // seconds
|
||||
run_primary: true,
|
||||
osd_network: null, // "192.168.7.0/24" or an array of masks
|
||||
bind_address: "0.0.0.0",
|
||||
@@ -104,6 +104,7 @@ const etcd_tree = {
|
||||
no_rebalance: false,
|
||||
print_stats_interval: 3,
|
||||
slow_log_interval: 10,
|
||||
osd_memlock: false,
|
||||
// blockstore - fixed in superblock
|
||||
block_size,
|
||||
disk_alignment,
|
||||
@@ -130,6 +131,11 @@ const etcd_tree = {
|
||||
inmemory_journal,
|
||||
journal_sector_buffer_count,
|
||||
journal_no_same_sector_overwrites,
|
||||
throttle_small_writes: false,
|
||||
throttle_target_iops: 100,
|
||||
throttle_target_mbs: 100,
|
||||
throttle_target_parallelism: 1,
|
||||
throttle_threshold_us: 50,
|
||||
}, */
|
||||
global: {},
|
||||
/* node_placement: {
|
||||
|
@@ -142,7 +142,6 @@ void blockstore_impl_t::loop()
|
||||
continue;
|
||||
}
|
||||
}
|
||||
unsigned ring_space = ringloop->space_left();
|
||||
unsigned prev_sqe_pos = ringloop->save();
|
||||
// 0 = can't submit
|
||||
// 1 = in progress
|
||||
@@ -212,7 +211,6 @@ void blockstore_impl_t::loop()
|
||||
ringloop->restore(prev_sqe_pos);
|
||||
if (PRIV(op)->wait_for == WAIT_SQE)
|
||||
{
|
||||
PRIV(op)->wait_detail = 1 + ring_space;
|
||||
// ring is full, stop submission
|
||||
break;
|
||||
}
|
||||
@@ -282,7 +280,7 @@ void blockstore_impl_t::check_wait(blockstore_op_t *op)
|
||||
{
|
||||
if (PRIV(op)->wait_for == WAIT_SQE)
|
||||
{
|
||||
if (ringloop->space_left() < PRIV(op)->wait_detail)
|
||||
if (ringloop->sqes_left() < PRIV(op)->wait_detail)
|
||||
{
|
||||
// stop submission if there's still no free space
|
||||
#ifdef BLOCKSTORE_DEBUG
|
||||
|
@@ -55,9 +55,10 @@
|
||||
#define IS_DELETE(st) (((st) & 0x0F) == BS_ST_DELETE)
|
||||
|
||||
#define BS_SUBMIT_CHECK_SQES(n) \
|
||||
if (ringloop->space_left() < (n))\
|
||||
if (ringloop->sqes_left() < (n))\
|
||||
{\
|
||||
/* Pause until there are more requests available */\
|
||||
PRIV(op)->wait_detail = (n);\
|
||||
PRIV(op)->wait_for = WAIT_SQE;\
|
||||
return 0;\
|
||||
}
|
||||
@@ -71,6 +72,7 @@
|
||||
if (!sqe)\
|
||||
{\
|
||||
/* Pause until there are more requests available */\
|
||||
PRIV(op)->wait_detail = 1;\
|
||||
PRIV(op)->wait_for = WAIT_SQE;\
|
||||
return 0;\
|
||||
}
|
||||
@@ -80,6 +82,7 @@
|
||||
if (!sqe)\
|
||||
{\
|
||||
/* Pause until there are more requests available */\
|
||||
PRIV(op)->wait_detail = 1;\
|
||||
PRIV(op)->wait_for = WAIT_SQE;\
|
||||
return 0;\
|
||||
}
|
||||
|
@@ -365,6 +365,13 @@ void cli_tool_t::run(json11::Json cfg)
|
||||
if (action_cb != NULL)
|
||||
ringloop->wait();
|
||||
}
|
||||
// Destroy the client
|
||||
delete cli;
|
||||
delete epmgr;
|
||||
delete ringloop;
|
||||
cli = NULL;
|
||||
epmgr = NULL;
|
||||
ringloop = NULL;
|
||||
}
|
||||
|
||||
int main(int narg, const char *args[])
|
||||
@@ -374,5 +381,6 @@ int main(int narg, const char *args[])
|
||||
exe_name = args[0];
|
||||
cli_tool_t *p = new cli_tool_t();
|
||||
p->run(cli_tool_t::parse_args(narg, args));
|
||||
delete p;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -108,9 +108,14 @@ resume_1:
|
||||
pool_avail = pg_free;
|
||||
}
|
||||
}
|
||||
if (pool_avail == UINT64_MAX)
|
||||
{
|
||||
pool_avail = 0;
|
||||
}
|
||||
if (pool_cfg.scheme != POOL_SCHEME_REPLICATED)
|
||||
{
|
||||
pool_avail = pool_avail * (pool_cfg.pg_size - pool_cfg.parity_chunks) / pool_stats[pool_cfg.id]["pg_real_size"].uint64_value();
|
||||
uint64_t pg_real_size = pool_stats[pool_cfg.id]["pg_real_size"].uint64_value();
|
||||
pool_avail = pg_real_size > 0 ? pool_avail * (pool_cfg.pg_size - pool_cfg.parity_chunks) / pg_real_size : 0;
|
||||
}
|
||||
pool_stats[pool_cfg.id] = json11::Json::object {
|
||||
{ "name", pool_cfg.name },
|
||||
@@ -189,11 +194,16 @@ resume_1:
|
||||
json11::Json::array list;
|
||||
for (auto & kv: pool_stats)
|
||||
{
|
||||
kv.second["total_fmt"] = format_size(kv.second["total_raw"].uint64_value() / kv.second["raw_to_usable"].number_value());
|
||||
kv.second["used_fmt"] = format_size(kv.second["used_raw"].uint64_value() / kv.second["raw_to_usable"].number_value());
|
||||
double raw_to = kv.second["raw_to_usable"].number_value();
|
||||
if (raw_to < 0.000001 && raw_to > -0.000001)
|
||||
raw_to = 1;
|
||||
kv.second["total_fmt"] = format_size(kv.second["total_raw"].uint64_value() / raw_to);
|
||||
kv.second["used_fmt"] = format_size(kv.second["used_raw"].uint64_value() / raw_to);
|
||||
kv.second["max_avail_fmt"] = format_size(kv.second["max_available"].uint64_value());
|
||||
kv.second["used_pct"] = format_q(100 - 100*kv.second["max_available"].uint64_value() *
|
||||
kv.second["raw_to_usable"].number_value() / kv.second["total_raw"].uint64_value())+"%";
|
||||
kv.second["used_pct"] = format_q(kv.second["total_raw"].uint64_value()
|
||||
? (100 - 100*kv.second["max_available"].uint64_value() *
|
||||
kv.second["raw_to_usable"].number_value() / kv.second["total_raw"].uint64_value())
|
||||
: 100)+"%";
|
||||
kv.second["eff_fmt"] = format_q(kv.second["space_efficiency"].number_value()*100)+"%";
|
||||
}
|
||||
printf("%s", print_table(to_list(), cols, parent->color).c_str());
|
||||
|
@@ -13,6 +13,7 @@
|
||||
epoll_manager_t::epoll_manager_t(ring_loop_t *ringloop)
|
||||
{
|
||||
this->ringloop = ringloop;
|
||||
this->pending = false;
|
||||
|
||||
epoll_fd = epoll_create(1);
|
||||
if (epoll_fd < 0)
|
||||
@@ -22,11 +23,19 @@ epoll_manager_t::epoll_manager_t(ring_loop_t *ringloop)
|
||||
|
||||
tfd = new timerfd_manager_t([this](int fd, bool wr, std::function<void(int, int)> handler) { set_fd_handler(fd, wr, handler); });
|
||||
|
||||
consumer.loop = [this]()
|
||||
{
|
||||
if (pending)
|
||||
handle_epoll_events();
|
||||
};
|
||||
ringloop->register_consumer(&consumer);
|
||||
|
||||
handle_epoll_events();
|
||||
}
|
||||
|
||||
epoll_manager_t::~epoll_manager_t()
|
||||
{
|
||||
ringloop->unregister_consumer(&consumer);
|
||||
if (tfd)
|
||||
{
|
||||
delete tfd;
|
||||
@@ -64,8 +73,13 @@ void epoll_manager_t::handle_epoll_events()
|
||||
io_uring_sqe *sqe = ringloop->get_sqe();
|
||||
if (!sqe)
|
||||
{
|
||||
throw std::runtime_error("can't get SQE, will fall out of sync with EPOLLET");
|
||||
// Don't handle epoll events until we manage to post the next event handler
|
||||
// otherwise we'll fall out of sync with EPOLLET
|
||||
pending = true;
|
||||
ringloop->wakeup();
|
||||
return;
|
||||
}
|
||||
pending = false;
|
||||
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
||||
my_uring_prep_poll_add(sqe, epoll_fd, POLLIN);
|
||||
data->callback = [this](ring_data_t *data)
|
||||
|
@@ -11,6 +11,8 @@
|
||||
class epoll_manager_t
|
||||
{
|
||||
int epoll_fd;
|
||||
bool pending;
|
||||
ring_consumer_t consumer;
|
||||
ring_loop_t *ringloop;
|
||||
std::map<int, std::function<void(int, int)>> epoll_handlers;
|
||||
public:
|
||||
|
@@ -1,4 +1,3 @@
|
||||
extern "C" {
|
||||
// Kill atomics in fio headers
|
||||
#define _STDATOMIC_H
|
||||
#include "fio/arch/arch.h"
|
||||
@@ -11,6 +10,7 @@ extern "C" {
|
||||
#define CONFIG_HAVE_GETTID
|
||||
#define CONFIG_SYNC_FILE_RANGE
|
||||
#define CONFIG_PWRITEV2
|
||||
extern "C" {
|
||||
#include "fio/fio.h"
|
||||
#include "fio/optgroup.h"
|
||||
}
|
||||
|
@@ -192,11 +192,16 @@ static int sec_init(struct thread_data *td)
|
||||
setsockopt(bsd->connect_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
||||
if (o->zerocopy_send)
|
||||
{
|
||||
#ifndef SO_ZEROCOPY
|
||||
perror("zerocopy send not supported on your system (socket.h misses SO_ZEROCOPY)");
|
||||
return 1;
|
||||
#else
|
||||
if (setsockopt(bsd->connect_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)) < 0)
|
||||
{
|
||||
perror("setsockopt zerocopy");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// FIXME: read config (block size) from OSD
|
||||
@@ -306,7 +311,13 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
|
||||
iov[iovcnt++] = { .iov_base = io->xfer_buf, .iov_len = io->xfer_buflen };
|
||||
wtotal += io->xfer_buflen;
|
||||
}
|
||||
if (sendv_blocking(bsd->connect_fd, iov, iovcnt, opt->zerocopy_send ? MSG_ZEROCOPY : 0) != wtotal)
|
||||
if (sendv_blocking(bsd->connect_fd, iov, iovcnt,
|
||||
#ifdef SO_ZEROCOPY
|
||||
opt->zerocopy_send ? MSG_ZEROCOPY : 0
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
) != wtotal)
|
||||
{
|
||||
perror("sendmsg");
|
||||
exit(1);
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include "msgr_rdma.h"
|
||||
#include "messenger.h"
|
||||
|
||||
@@ -54,6 +55,7 @@ msgr_rdma_connection_t::~msgr_rdma_connection_t()
|
||||
msgr_rdma_context_t *msgr_rdma_context_t::create(const char *ib_devname, uint8_t ib_port, uint8_t gid_index, uint32_t mtu, int log_level)
|
||||
{
|
||||
int res;
|
||||
bool odp = true;
|
||||
ibv_device **dev_list = NULL;
|
||||
msgr_rdma_context_t *ctx = new msgr_rdma_context_t();
|
||||
ctx->mtu = mtu;
|
||||
@@ -117,9 +119,9 @@ msgr_rdma_context_t *msgr_rdma_context_t::create(const char *ib_devname, uint8_t
|
||||
fprintf(stderr, "RDMA device %s must have local LID because it's not Ethernet, but LID is zero\n", ibv_get_device_name(ctx->dev));
|
||||
goto cleanup;
|
||||
}
|
||||
if (ibv_query_gid(ctx->context, ib_port, gid_index, &ctx->my_gid))
|
||||
if ((res = ibv_query_gid(ctx->context, ib_port, gid_index, &ctx->my_gid)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Couldn't read RDMA device %s GID index %d\n", ibv_get_device_name(ctx->dev), gid_index);
|
||||
fprintf(stderr, "Couldn't read RDMA device %s GID index %d: %s\n", ibv_get_device_name(ctx->dev), gid_index, strerror(res));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -131,9 +133,9 @@ msgr_rdma_context_t *msgr_rdma_context_t::create(const char *ib_devname, uint8_t
|
||||
}
|
||||
|
||||
{
|
||||
if (ibv_query_device_ex(ctx->context, NULL, &ctx->attrx))
|
||||
if ((res = ibv_query_device_ex(ctx->context, NULL, &ctx->attrx)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Couldn't query RDMA device for its features\n");
|
||||
fprintf(stderr, "Couldn't query RDMA device %s for its features: %s\n", ibv_get_device_name(ctx->dev), strerror(res));
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(ctx->attrx.odp_caps.general_caps & IBV_ODP_SUPPORT) ||
|
||||
@@ -141,15 +143,20 @@ msgr_rdma_context_t *msgr_rdma_context_t::create(const char *ib_devname, uint8_t
|
||||
!(ctx->attrx.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_SEND) ||
|
||||
!(ctx->attrx.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_RECV))
|
||||
{
|
||||
fprintf(stderr, "The RDMA device isn't implicit ODP (On-Demand Paging) capable or does not support RC send and receive with ODP\n");
|
||||
goto cleanup;
|
||||
fprintf(stderr, "Warning: RDMA device isn't implicit ODP (On-Demand Paging) capable, trying to lock all application memory\n");
|
||||
if (mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT) != 0)
|
||||
{
|
||||
fprintf(stderr, "mlockall() failed: %s\n", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
odp = false;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->mr = ibv_reg_mr(ctx->pd, NULL, SIZE_MAX, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_ON_DEMAND);
|
||||
ctx->mr = ibv_reg_mr(ctx->pd, NULL, SIZE_MAX, IBV_ACCESS_LOCAL_WRITE | (odp ? IBV_ACCESS_ON_DEMAND : 0));
|
||||
if (!ctx->mr)
|
||||
{
|
||||
fprintf(stderr, "Couldn't register RDMA memory region\n");
|
||||
fprintf(stderr, "Couldn't register RDMA memory region: %s\n", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@@ -111,6 +111,10 @@ void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
||||
{
|
||||
delete cl->read_op;
|
||||
}
|
||||
else
|
||||
{
|
||||
cancel_op(cl->read_op);
|
||||
}
|
||||
cl->read_op = NULL;
|
||||
}
|
||||
if (cl->osd_num)
|
||||
|
@@ -55,6 +55,15 @@ protected:
|
||||
iovec read_iov = { 0 };
|
||||
|
||||
public:
|
||||
~nbd_proxy()
|
||||
{
|
||||
if (recv_buf)
|
||||
{
|
||||
free(recv_buf);
|
||||
recv_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static json11::Json::object parse_args(int narg, const char *args[])
|
||||
{
|
||||
json11::Json::object cfg;
|
||||
@@ -322,6 +331,9 @@ public:
|
||||
delete cli;
|
||||
delete epmgr;
|
||||
delete ringloop;
|
||||
cli = NULL;
|
||||
epmgr = NULL;
|
||||
ringloop = NULL;
|
||||
}
|
||||
|
||||
void load_module()
|
||||
@@ -498,7 +510,7 @@ protected:
|
||||
goto end_unmap;
|
||||
}
|
||||
ioctl(nbd, NBD_SET_FLAGS, flags);
|
||||
if (timeout >= 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
r = ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout);
|
||||
if (r < 0)
|
||||
|
11
src/osd.cpp
11
src/osd.cpp
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -53,6 +54,16 @@ osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
|
||||
autosync_writes = max_autosync;
|
||||
}
|
||||
|
||||
if (this->config["osd_memlock"] == "true" || this->config["osd_memlock"] == "1" || this->config["osd_memlock"] == "yes")
|
||||
{
|
||||
// Lock all OSD memory if requested
|
||||
if (mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT) != 0)
|
||||
{
|
||||
fprintf(stderr, "osd_memlock is set to true, but mlockall() failed: %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
this->tfd->set_timer(print_stats_interval*1000, true, [this](int timer_id)
|
||||
{
|
||||
print_stats();
|
||||
|
@@ -112,3 +112,17 @@ void ring_loop_t::restore(unsigned sqe_tail)
|
||||
}
|
||||
ring.sq.sqe_tail = sqe_tail;
|
||||
}
|
||||
|
||||
int ring_loop_t::sqes_left()
|
||||
{
|
||||
struct io_uring_sq *sq = &ring.sq;
|
||||
unsigned int head = io_uring_smp_load_acquire(sq->khead);
|
||||
unsigned int next = sq->sqe_tail + 1;
|
||||
int left = *sq->kring_entries - (next - head);
|
||||
if (left > free_ring_data_ptr)
|
||||
{
|
||||
// return min(sqes left, ring_datas left)
|
||||
return free_ring_data_ptr;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
@@ -17,15 +17,12 @@
|
||||
|
||||
static inline void my_uring_prep_rw(int op, struct io_uring_sqe *sqe, int fd, const void *addr, unsigned len, off_t offset)
|
||||
{
|
||||
sqe->opcode = op;
|
||||
sqe->flags = 0;
|
||||
sqe->ioprio = 0;
|
||||
sqe->fd = fd;
|
||||
sqe->off = offset;
|
||||
sqe->addr = (unsigned long) addr;
|
||||
sqe->len = len;
|
||||
sqe->rw_flags = 0;
|
||||
sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
|
||||
// Prepare a read/write operation without clearing user_data
|
||||
// Very recently, 22 Dec 2021, liburing finally got this change too (8ecd3fd959634df81d66af8b3a69c16202a014e8)
|
||||
// But all versions prior to it (sadly) clear user_data
|
||||
__u64 user_data = sqe->user_data;
|
||||
io_uring_prep_rw(op, sqe, fd, addr, len, offset);
|
||||
sqe->user_data = user_data;
|
||||
}
|
||||
|
||||
static inline void my_uring_prep_readv(struct io_uring_sqe *sqe, int fd, const struct iovec *iovecs, unsigned nr_vecs, off_t offset)
|
||||
@@ -172,6 +169,7 @@ public:
|
||||
struct io_uring_cqe *cqe;
|
||||
return io_uring_wait_cqe(&ring, &cqe);
|
||||
}
|
||||
int sqes_left();
|
||||
inline unsigned space_left()
|
||||
{
|
||||
return free_ring_data_ptr;
|
||||
|
Reference in New Issue
Block a user