Compare commits

..

2 Commits

Author SHA1 Message Date
Vitaliy Filippov 4f7c8752e0 WIP Architecture in english
Test / test_dd (push) Successful in 12s Details
Test / test_root_node (push) Successful in 7s Details
Test / test_rebalance_verify_ec (push) Successful in 1m54s Details
Test / test_rebalance_verify_ec_imm (push) Successful in 1m56s Details
Test / test_write_no_same (push) Successful in 8s Details
Test / test_switch_primary (push) Successful in 33s Details
Test / test_write (push) Successful in 31s Details
Test / test_write_xor (push) Successful in 36s Details
Test / test_heal_pg_size_2 (push) Successful in 2m16s Details
Test / test_heal_ec (push) Successful in 2m15s Details
Test / test_heal_antietcd (push) Successful in 2m16s Details
Test / test_heal_csum_32k_dmj (push) Failing after 2m28s Details
Test / test_heal_csum_32k_dj (push) Successful in 2m16s Details
Test / test_heal_csum_32k (push) Successful in 2m17s Details
Test / test_heal_csum_4k_dmj (push) Successful in 2m17s Details
Test / test_snapshot_pool2 (push) Successful in 13s Details
Test / test_osd_tags (push) Successful in 8s Details
Test / test_enospc (push) Successful in 10s Details
Test / test_heal_csum_4k_dj (push) Successful in 2m15s Details
Test / test_enospc_xor (push) Successful in 11s Details
Test / test_enospc_imm (push) Successful in 9s Details
Test / test_enospc_imm_xor (push) Successful in 12s Details
Test / test_scrub (push) Successful in 13s Details
Test / test_scrub_zero_osd_2 (push) Successful in 12s Details
Test / test_scrub_xor (push) Successful in 13s Details
Test / test_scrub_pg_size_3 (push) Successful in 14s Details
Test / test_scrub_pg_size_6_pg_minsize_4_osd_count_6_ec (push) Successful in 16s Details
Test / test_scrub_ec (push) Successful in 15s Details
Test / test_nfs (push) Successful in 13s Details
Test / test_heal_csum_4k (push) Successful in 2m19s Details
2024-11-06 00:42:27 +03:00
Vitaliy Filippov 9def199981 Auto-reduce new_data_len in resize
Test / test_dd (push) Successful in 11s Details
Test / test_root_node (push) Successful in 8s Details
Test / test_rebalance_verify_ec (push) Successful in 1m45s Details
Test / test_rebalance_verify_ec_imm (push) Successful in 1m46s Details
Test / test_write_no_same (push) Successful in 8s Details
Test / test_switch_primary (push) Successful in 33s Details
Test / test_write (push) Successful in 32s Details
Test / test_write_xor (push) Successful in 33s Details
Test / test_heal_pg_size_2 (push) Successful in 2m14s Details
Test / test_heal_ec (push) Successful in 2m17s Details
Test / test_heal_antietcd (push) Successful in 2m15s Details
Test / test_heal_csum_32k_dmj (push) Successful in 2m16s Details
Test / test_heal_csum_32k_dj (push) Successful in 2m17s Details
Test / test_heal_csum_32k (push) Successful in 2m17s Details
Test / test_heal_csum_4k_dmj (push) Successful in 2m17s Details
Test / test_heal_csum_4k_dj (push) Successful in 2m16s Details
Test / test_osd_tags (push) Successful in 8s Details
Test / test_snapshot_pool2 (push) Successful in 16s Details
Test / test_enospc (push) Successful in 11s Details
Test / test_enospc_xor (push) Successful in 12s Details
Test / test_enospc_imm (push) Successful in 9s Details
Test / test_enospc_imm_xor (push) Successful in 14s Details
Test / test_scrub_zero_osd_2 (push) Successful in 12s Details
Test / test_scrub (push) Successful in 14s Details
Test / test_scrub_xor (push) Successful in 14s Details
Test / test_scrub_pg_size_3 (push) Successful in 14s Details
Test / test_scrub_pg_size_6_pg_minsize_4_osd_count_6_ec (push) Successful in 16s Details
Test / test_scrub_ec (push) Successful in 13s Details
Test / test_nfs (push) Successful in 13s Details
Test / test_heal_csum_4k (push) Successful in 2m18s Details
2024-11-05 02:57:11 +03:00
3 changed files with 89 additions and 71 deletions

View File

@ -80,67 +80,71 @@ All other client-side components are based on the client library:
- **vitastor-disk** — утилита для разметки дисков под Vitastor OSD. С её помощью можно - **vitastor-disk** — утилита для разметки дисков под Vitastor OSD. С её помощью можно
создавать, удалять, менять размеры или перемещать разделы OSD. создавать, удалять, менять размеры или перемещать разделы OSD.
## Общий процесс записи и чтения ## Overall read/write process
- В Vitastor хранятся виртуальные диски, также называемые "образы" или "иноды". - Vitastor stores virtual disks, also named "images" or "inodes".
- Каждый образ хранится в определённом пуле. Пул определяет параметры хранения образов в нём, - Each image is stored in some pool. Pool specifies storage parameters such as redundancy
такие, как схему избыточности (репликация или EC — коды коррекции ошибок), домен отказа scheme (replication or EC — erasure codes, i.e. error correction codes), failure domain
и ограничения по выбору OSD для размещения данных образов. См. [Конфигурация пулов](../config/pool.ru.md). and restrictions on OSD selection for image data placement. See [Pool configuration](../config/pool.en.md) for details.
- Каждый образ разбивается на объекты фиксированного размера, равного [block_size](../config/layout-cluster.ru.md#block_size) - Each image is split into objects/blocks of fixed size, equal to [block_size](../config/layout-cluster.en.md#block_size)
(по умолчанию 128 КБ), умноженному на число частей данных для EC или на 1 для реплик. (128 KB by default), multiplied by data part count for EC or 1 for replicas. That is,
То есть, например, если в пуле используется схема кодирования 4+2 (4 части данных + 2 чётности), if a pool uses EC 4+2 coding scheme (4 data parts + 2 parity parts), then, with the
то при стандартном block_size образы разбиваются на части по 512 КБ. default block_size, images are split into 512 KB objects.
- Клиентские запросы чтения/записи разделяются на части, соответствующие этим объектам. - Client read/write requests are split into parts at object boundaries.
- Для каждого объекта определяется номер PG, которой он принадлежит, путём простого взятия - Each object is mapped to a PG number it belongs to, by simply taking a remainder of
остатка от деления ID образа и смещения на число PG в пуле, которому принадлежит образ. division of its offset by PG count of the image's pool.
- Клиент читает информацию о первичном OSD всех PG из etcd. Первичный OSD каждой PG назначается - Client reads primary OSD for all PGs from etcd. Primary OSD for each PG is assigned
монитором в процессе работы кластера, вместе с текущим целевым набором OSD этой PG. by the monitor during cluster operation, along with the full PG OSD set.
- Клиент соединяется (если ещё не соединён) с первичными OSD всех PG, объекты которых участвуют - If not already connected, client connects to primary OSDs of all PGs involved in a
в запросе и одновременно отправляет им запросы чтения/записи частей. read/write request and sends parts of the request to them.
- Если какие-то из первичных OSD недоступны, клиент повторяет попытки соединения бесконечно до - If a primary OSD is unavailable, client retries connection attempts indefinitely
тех пор, пока они не станут доступны или пока PG не будут назначены другие первичные OSD. either until it becomes available or until the monitor assigns another OSD as primary
- Клиент также повторяет запросы, если первичные OSD отвечают кодом ошибки EPIPE, означающим, for that PG.
что запрос не может быть обработан в данный момент. Это происходит, если PG либо не активна - Client also retries requests if the primary OSD replies with error code EPIPE, meaning
вообще, либо не активна на данном OSD в данный момент (например, если в этот момент меняется that the PG is inactive at this OSD at the moment - for example, when the primary OSD
её первичный OSD) или если в процессе обработки запроса сам первичный OSD теряет подключение is switched, or if the primary OSD itself loses connection to replicas during request
к репликам. handling.
- Первичный OSD определяет, на каких OSD находятся части объекта. По умолчанию все объекты - Primary OSD determines where the parts of the object are stored. By default, all objects
считаются находящимися на текущем целевом наборе OSD соответствующей PG, но какие-то могут are assumed to be stored at the target OSD set of a PG, but some of them may be present
находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс at a different OSD set if they are degraded or moved, or if the data rebalancing process
ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех is active. OSDs doesn't do any network requests, if calculates locations of all objects
объектов рассчитывается первичным OSD при активации PG и хранится в памяти. during PG activation and stores it in memory.
- Первичный OSD соединяется (если ещё не соединён) с вторичными OSD, на которых располагаются - Primary OSD handles the request locally when it can - for example, when it's a read
части объекта, и отправляет им запросы чтения/записи, а также читает/пишет из/в своё локальное from a replicated pool or when it's a read from a EC pool involving only one data part
хранилище, если сам входит в набор. stored on the OSD's local disk.
- После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту. - When a request requires reads or writes to additional OSDs, primary OSD uses already
established connections to secondary OSDs of the PG to execute these requests. This happens
in parallel to local disk operations. All such connections are guaranteed to be already
established when the PG is active, and if any of them is dropped, PG is restarted and
all current read/write operations to it fail with EPIPE error and are retried by clients.
- After completing all secondary read/write requests, primary OSD sends the response to
the client.
### Особенности обработки запросов ### Nuances of request handling
- Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный - If a pool uses erasure codes and some of the OSDs are unavailable, primary OSDs recover
OSD при чтении восстанавливает данные из оставшихся частей. data from the remaining parts during read.
- Каждый объект имеет номер версии. При записи объекта первичный OSD сначала читает из номер - Each object has a version number. During write, primary OSD first determines the current
версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер version of the object. As primary OSD usually stores the object or its part itself, most
версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта of the time version is read from the memory of the OSD itself. However, if primary OSD
не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных doesn't contain parts of the object, it requests the version number from a secondary OSD
OSD, на которых копия объекта есть. Обращения к диску при этом всё равно не происходит, which has that part. Such request still doesn't involve reading from the disk though,
так как метаданные объектов, включая номер версии, все OSD хранят в памяти. because object metadata, including version number, is always stored in OSD memory.
- Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления - If a pool uses erasure codes, partial writes of an object require reading other parts of
чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска it from secondary OSDs or from the local disk of the primary OSD itself. This is called
самого первичного OSD. "read-modify-write" process.
- Также, если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется - If a pool uses erasure codes, two-phase write process is used to get rid of the Write Hole
двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей problem: first a new version of object parts is written to all secondary OSDs without
объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения removing the previous version, and then, after receiving successful write confirmations
успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой. from all OSDs, new version is committed and the old one is allowed to be removed.
- Если в кластере не включён режим immediate_commit, то запросы записи, отправляемые клиентами, - In a pool doesn't use immediate_commit mode, then write requests sent by clients aren't
не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты treated as committed to physical media instantly. Clients have to send separate type of
должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса), requests (SYNC) to commit changes, and before it isn't sent, new versions of data are
а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть, allowed to be lost if some OSDs die. Thus, when immediate_commit is disabled, clients
если соответствующий OSD упадёт. Поэтому, когда режим immediate_commit отключён, все store copies of all write requests in memory and repeat them from there when the
запросы записи клиенты копируют в памяти и при потере соединения и повторном соединении connection to primary OSD is lost. This in-memory copy is removed after a successful
с OSD повторяют из памяти. Скопированные в память данные удаляются при успешном fsync, SYNC, and to prevent excessive memory usage, clients also do an automatic SYNC
а чтобы хранение этих данных не приводило к чрезмерному потреблению памяти, клиенты every [client_dirty_limit](../config/network.en.md#client_dirty_limit) written bytes.
автоматически выполняют fsync каждые [client_dirty_limit](../config/network.ru.md#client_dirty_limit)
записанных байт.
## Similarities to Ceph ## Similarities to Ceph

View File

@ -114,16 +114,22 @@
находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс
ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех
объектов рассчитывается первичным OSD при активации PG и хранится в памяти. объектов рассчитывается первичным OSD при активации PG и хранится в памяти.
- Первичный OSD соединяется (если ещё не соединён) с вторичными OSD, на которых располагаются - Когда это возможно, первичный OSD обрабатывает запрос локально. Например, так происходит
части объекта, и отправляет им запросы чтения/записи, а также читает/пишет из/в своё локальное при чтениях объектов из пулов с репликацией или при чтении из EC пула, затрагивающего
хранилище, если сам входит в набор. только часть, хранимую на диске самого первичного OSD.
- Когда запрос требует записи или чтения с вторичных OSD, первичный OSD использует заранее
установленные соединения с ними для выполнения этих запросов. Это происходит параллельно
локальным операциям чтения/записи с диска самого OSD. Так как соединения к вторичным OSD PG
устанавливаются при её запуске, то они уже гарантированно установлены, когда PG активна,
и если любое из этих соединений отключается, PG перезапускается, а все текущие запросы чтения
и записи в неё завершаются с ошибкой EPIPE, после чего повторяются клиентами.
- После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту. - После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту.
### Особенности обработки запросов ### Особенности обработки запросов
- Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный - Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный
OSD при чтении восстанавливает данные из оставшихся частей. OSD при чтении восстанавливает данные из оставшихся частей.
- Каждый объект имеет номер версии. При записи объекта первичный OSD сначала читает из номер - Каждый объект имеет номер версии. При записи объекта первичный OSD сначала получает номер
версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер
версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта
не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных
@ -131,20 +137,20 @@
так как метаданные объектов, включая номер версии, все OSD хранят в памяти. так как метаданные объектов, включая номер версии, все OSD хранят в памяти.
- Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления - Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления
чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска
самого первичного OSD. самого первичного OSD. Это называется процессом "чтение-модификация-запись" (read-modify-write).
- Также, если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется - Если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется
двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей
объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения
успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой. успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой.
- Если в кластере не включён режим immediate_commit, то запросы записи, отправляемые клиентами, - Если в пуле не включён режим immediate_commit, то запросы записи, отправляемые клиентами,
не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты
должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса), должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса),
а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть, а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть,
если соответствующий OSD упадёт. Поэтому, когда режим immediate_commit отключён, все если соответствующий OSD упадёт. Поэтому, когда режим immediate_commit отключён, все
запросы записи клиенты копируют в памяти и при потере соединения и повторном соединении запросы записи клиенты копируют в памяти и при потере соединения и повторном соединении
с OSD повторяют из памяти. Скопированные в память данные удаляются при успешном fsync, с OSD повторяют из памяти. Скопированные в память данные удаляются при успешном SYNC,
а чтобы хранение этих данных не приводило к чрезмерному потреблению памяти, клиенты а чтобы хранение этих данных не приводило к чрезмерному потреблению памяти, клиенты
автоматически выполняют fsync каждые [client_dirty_limit](../config/network.ru.md#client_dirty_limit) автоматически выполняют SYNC каждые [client_dirty_limit](../config/network.ru.md#client_dirty_limit)
записанных байт. записанных байт.
## Схожесть с Ceph ## Схожесть с Ceph

View File

@ -123,6 +123,14 @@ int disk_tool_t::resize_parse_params()
? parse_size(options["new_journal_offset"]) : dsk.journal_offset; ? parse_size(options["new_journal_offset"]) : dsk.journal_offset;
new_journal_len = options.find("new_journal_len") != options.end() new_journal_len = options.find("new_journal_len") != options.end()
? parse_size(options["new_journal_len"]) : dsk.journal_len; ? parse_size(options["new_journal_len"]) : dsk.journal_len;
if (new_data_len+new_data_offset > dsk.data_device_size)
new_data_len = dsk.data_device_size-new_data_offset;
if (new_meta_device == dsk.data_device && new_data_offset < new_meta_offset &&
new_data_len+new_data_offset > new_meta_offset)
new_data_len = new_meta_offset-new_data_offset;
if (new_journal_device == dsk.data_device && new_data_offset < new_journal_offset &&
new_data_len+new_data_offset > new_journal_offset)
new_data_len = new_journal_offset-new_data_offset;
if (new_meta_device == dsk.meta_device && if (new_meta_device == dsk.meta_device &&
new_journal_device == dsk.journal_device && new_journal_device == dsk.journal_device &&
new_data_offset == dsk.data_offset && new_data_offset == dsk.data_offset &&
@ -220,10 +228,10 @@ int disk_tool_t::resize_remap_blocks()
} }
for (uint64_t i = 0; i < free_last; i++) for (uint64_t i = 0; i < free_last; i++)
{ {
if (data_alloc->get(total_blocks-i)) if (data_alloc->get(total_blocks-i-1))
data_remap[total_blocks-i] = 0; data_remap[total_blocks-i-1] = 0;
else else
data_alloc->set(total_blocks-i, true); data_alloc->set(total_blocks-i-1, true);
} }
for (auto & p: data_remap) for (auto & p: data_remap)
{ {
@ -482,7 +490,7 @@ int disk_tool_t::resize_rewrite_meta()
block_num = remap_it->second; block_num = remap_it->second;
if (block_num < free_first || block_num >= total_blocks-free_last) if (block_num < free_first || block_num >= total_blocks-free_last)
{ {
fprintf(stderr, "BUG: remapped block not in range\n"); fprintf(stderr, "BUG: remapped block %lu not in range %lu..%lu\n", block_num, free_first, total_blocks-free_last);
exit(1); exit(1);
} }
block_num += data_idx_diff; block_num += data_idx_diff;