From b6f75ebcfd466516b967c8af165cefa9246f33a4 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Mon, 4 Nov 2024 18:59:34 +0300 Subject: [PATCH] Add missing I/O path description in english --- docs/intro/architecture.en.md | 138 ++++++++++++++++++++++++++++++++-- docs/intro/architecture.ru.md | 78 ++++++++++++------- 2 files changed, 182 insertions(+), 34 deletions(-) diff --git a/docs/intro/architecture.en.md b/docs/intro/architecture.en.md index e2a4e767..236910dd 100644 --- a/docs/intro/architecture.en.md +++ b/docs/intro/architecture.en.md @@ -11,14 +11,140 @@ - [Differences from Ceph](#differences-from-ceph) - [Implementation Principles](#implementation-principles) +## Server-side components + +- **OSD** (Object Storage Daemon) is a process that directly works with the disk, stores data + and serves read/write requests. One OSD serves one disk (or one partition). OSDs talk to etcd + and to each other — they receive cluster state from etcd, and send read/write requests for + secondary copies of data to other OSDs. +- **etcd** — clustered key/value database, used as a reliable storage for configuration + and high-level cluster state. Etcd is the component that prevents splitbrain in the cluster. + Data blocks are not stored in etcd, etcd doesn't participate in data write or read path. +- **Монитор** — a separate node.js based daemon which monitors the cluster, calculates + required configuration changes and saves them to etcd, thus commanding OSDs to apply these + changes. Monitor also aggregates cluster statistics. OSD don't talk to monitor, monitor + only sends and receives data from etcd. + ## Basic concepts -- OSD (Object Storage Daemon) is a process that stores data and serves read/write requests. -- PG (Placement Group) is a "shard" of the cluster, group of data stored on one set of replicas. -- Pool is a container for data that has equal redundancy scheme and placement rules. -- Monitor is a separate daemon that watches cluster state and handles failures. -- Failure Domain is a group of OSDs that you allow to fail. It's "host" by default. -- Placement Tree groups OSDs in a hierarchy to later split them into Failure Domains. +- **Pool** is a container for data that has equal redundancy scheme and disk placement rules. +- **PG (Placement Group)** is a "shard" of the cluster, subdivision unit that has its own + set of OSDs for data storage. +- **Failure Domain** is a group of OSDs, from the simultaneous failure of which you are + protected by Vitastor. Default failure domain is "host" (server), but you choose a + larger (for example, a rack of servers) or smaller (a single drive) failure domain + for every pool. +- **Placement Tree** (similar to Ceph CRUSH Tree) groups OSDs in a hierarchy to later + split them into Failure Domains. + +## Client-side components + +- **Client library** incapsulates client I/O logic. Client library connects to etcd and to all OSDs, + receives cluster state from etcd, sends read and write requests directly to all OSDs. Due + to the symmetric distributed architecture, all data blocks (each 128 KB by default) are placed + to different OSDs, but clients always knows where each data block is stored and connects directly + to the right OSD. + +All other client-side components are based on the client library: + +- **[vitastor-cli](../usage/cli.en.md)** — command-line utility for cluster management. + Allows to view cluster state, manage pools and images, i.e. create, modify and remove + virtual disks, their snapshots and clones. +- **[QEMU driver](../usage/qemu.en.md)** — pluggable QEMU module allowing QEMU/KVM virtual + machines work with virtual Vitastor disks directly from userspace through the client library, + without the need to attach disks as kernel block devices. However, if you want to attach + disks, you can also do that with the same driver and [VDUSE](../usage/qemu.en.md#vduse). +- **[vitastor-nbd](../usage/nbd.en.md)** — utility that allows to attach Vitastor disks as + kernel block devices using NBD (Network Block Device), which works more like "BUSE" + (Block Device In Userspace). Vitastor doesn't have Linux kernel modules for the same task + (at least by now). NBD is an older, non-recommended way to attach disks — you should use + VDUSE whenever you can. +- **[CSI driver](../installation/kubernetes.en.md)** — driver for attaching Vitastor images + as Kubernetes persistent volumes. Works through VDUSE (when available) or NBD — images are + attached as kernel block devices and mounted into containers. +- **Drivers for Proxmox, OpenStack and so on** — pluggable modules for corresponding systems, + allowing to use Vitastor as storage in them. +- **[vitastor-nfs](../usage/nfs.en.md)** — NFS 3.0 server allowing export of two file system variants: + the first is a simplified pseudo-FS for file-based access to Vitastor block images (for non-QEMU + hypervisors with NFS support), the second is **VitastorFS**, full-featured clustered POSIX FS. + Both variants support parallel access from multiple vitastor-nfs servers. In fact, you are + not required to setup separate NFS servers at all and use vitastor-nfs mount command on every + client node — it starts the NFS server and mounts the FS locally. +- **[fio driver](../usage/fio.en.md)** — pluggable module for fio disk benchmarking tool for + running performance tests on your Vitastor cluster. +- **vitastor-kv** — client for a key-value DB working over shared block volumes (usual + vitastor images). VitastorFS metadata is stored in vitastor-kv. + +## Additional utilities + +- **vitastor-disk** — утилита для разметки дисков под Vitastor OSD. С её помощью можно + создавать, удалять, менять размеры или перемещать разделы OSD. + +## Overall read/write process + +- Vitastor stores virtual disks, also named "images" or "inodes". +- Each image is stored in some pool. Pool specifies storage parameters such as redundancy + scheme (replication or EC — erasure codes, i.e. error correction codes), failure domain + and restrictions on OSD selection for image data placement. See [Pool configuration](../config/pool.en.md) for details. +- Each image is split into objects/blocks of fixed size, equal to [block_size](../config/layout-cluster.en.md#block_size) + (128 KB by default), multiplied by data part count for EC or 1 for replicas. That is, + if a pool uses EC 4+2 coding scheme (4 data parts + 2 parity parts), then, with the + default block_size, images are split into 512 KB objects. +- Client read/write requests are split into parts at object boundaries. +- Each object is mapped to a PG number it belongs to, by simply taking a remainder of + division of its offset by PG count of the image's pool. +- Client reads primary OSD for all PGs from etcd. Primary OSD for each PG is assigned + by the monitor during cluster operation, along with the full PG OSD set. +- 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. +- If a primary OSD is unavailable, client retries connection attempts indefinitely + either until it becomes available or until the monitor assigns another OSD as primary + for that PG. +- Client also retries requests if the primary OSD replies with error code EPIPE, meaning + that the PG is inactive at this OSD at the moment - for example, when the primary OSD + is switched, or if the primary OSD itself loses connection to replicas during request + handling. +- Primary OSD determines where the parts of the object are stored. By default, all objects + are assumed to be stored at the target OSD set of a PG, but some of them may be present + 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 + during PG activation and stores it in memory. +- 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. +- 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 + +- If a pool uses erasure codes and some of the OSDs are unavailable, primary OSDs recover + data from the remaining parts during read. +- Each object has a version number. During write, primary OSD first determines the current + version of the object. As primary OSD usually stores the object or its part itself, most + of the time version is read from the memory of the OSD itself. However, if primary OSD + doesn't contain parts of the object, it requests the version number from a secondary OSD + which has that part. Such request still doesn't involve reading from the disk though, + 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 + it from secondary OSDs or from the local disk of the primary OSD itself. This is called + "read-modify-write" process. +- If a pool uses erasure codes, two-phase write process is used to get rid of the Write Hole + 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 + from all OSDs, new version is committed and the old one is allowed to be removed. +- 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 + 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 + 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 + 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. ## Similarities to Ceph diff --git a/docs/intro/architecture.ru.md b/docs/intro/architecture.ru.md index 78a64f7c..b7b79cae 100644 --- a/docs/intro/architecture.ru.md +++ b/docs/intro/architecture.ru.md @@ -11,6 +11,7 @@ - [Серверные компоненты](#серверные-компоненты) - [Базовые понятия](#базовые-понятия) - [Клиентские компоненты](#клиентские-компоненты) +- [Дополнительные утилиты](#дополнительные-утилиты) - [Общий процесс записи и чтения](#общий-процесс-записи-и-чтения) - [Особенности обработки запросов](#особенности-обработки-запросов) - [Схожесть с Ceph](#схожесть-с-ceph) @@ -34,8 +35,9 @@ - **Пул (Pool)** — контейнер для данных, имеющих одну и ту же схему избыточности и правила распределения по OSD. - **PG (Placement Group)** — "шард", единица деления пулов в кластере, которой назначается свой набор OSD для хранения данных (копий или частей объектов). -- **Домен отказа (Failure Domain)** — группа OSD, одновременное падение которых рассматривается - как вероятное. По умолчанию это "host" (сервер). +- **Домен отказа (Failure Domain)** — группа OSD, от одновременного падения которых должен защищать + Vitastor. По умолчанию домен отказа — "host" (сервер), но вы можете установить для пула как больший + домен отказа (например, стойку серверов), так и меньший (например, отдельный диск). - **Дерево распределения** (Placement Tree, в Ceph CRUSH Tree) — иерархическая группировка OSD в узлы, которые далее можно использовать как домены отказа. @@ -49,25 +51,39 @@ На базе клиентской библиотеки реализованы все остальные клиенты: -- **vitastor-cli** — утилита командной строки для управления кластером. В данный момент позволяет - просматривать общее состояние кластера и управлять образами — т.е. создавать, менять и удалять - виртуальные диски, их снимки и клоны. -- **Драйвер QEMU** — подключаемый модуль QEMU, позволяющий QEMU/KVM виртуальным машинам работать - с виртуальными дисками Vitastor напрямую из пространства пользователя с помощью клиентской - библиотеки, без необходимости отображения дисков в виде блочных устройств. Тот же драйвер - позволяет подключать диски в систему через [VDUSE](../usage/qemu.ru.md#vduse). -- **vitastor-nbd** — утилита, позволяющая монтировать образы Vitastor в виде блочных устройств - с помощью NBD (Network Block Device), на самом деле скорее работающего как "BUSE" - (Block Device In Userspace). Модуля ядра Linux для выполнения той же задачи в Vitastor нет - (по крайней мере, пока). -- **CSI драйвер** — драйвер для подключения Vitastor-образов в виде персистентных томов (PV) Kubernetes. - Работает через vitastor-nbd — образы отражаются в виде блочных устройств и монтируются - в контейнеры. +- **[vitastor-cli](../usage/cli.ru.md)** — утилита командной строки для управления кластером. + Позволяет просматривать общее состояние кластера, управлять пулами и образами — то есть + создавать, менять и удалять виртуальные диски, их снимки и клоны. +- **[Драйвер QEMU](../usage/qemu.ru.md)** — подключаемый модуль QEMU, позволяющий QEMU/KVM + виртуальным машинам работать с виртуальными дисками Vitastor напрямую из пространства пользователя + с помощью клиентской библиотеки, без необходимости подключения дисков в виде блочных устройств + Linux. Если, однако, вы хотите подключать диски в виде блочных устройств, то вы тоже можете + сделать это с помощью того же самого драйвера и [VDUSE](../usage/qemu.ru.md#vduse). +- **[vitastor-nbd](../usage/nbd.ru.md)** — утилита, позволяющая монтировать образы Vitastor + в виде блочных устройств с помощью NBD (Network Block Device), на самом деле скорее работающего + как "BUSE" (Block Device In Userspace). Модуля ядра Linux для выполнения той же задачи в + Vitastor нет (по крайней мере, пока). NBD — более старый и нерекомендуемый способ подключения + дисков — вам следует использовать VDUSE всегда, когда это возможно. +- **[CSI драйвер](../installation/kubernetes.ru.md)** — драйвер для подключения Vitastor-образов + в виде персистентных томов (PV) Kubernetes. Работает через VDUSE (если доступно) или через + NBD — образы отражаются в виде блочных устройств и монтируются в контейнеры. - **Драйвера Proxmox, OpenStack и т.п.** — подключаемые модули для соответствующих систем, позволяющие использовать Vitastor как хранилище в оных. -- **vitastor-nfs** — утилита, предоставляющая файловый доступ к образам в кластере Vitastor - по протоколу NFS 3.0. Предназначена для гипервизоров, не основанных на QEMU и Linux, но при - этом поддерживающих NFS. +- **[vitastor-nfs](../usage/nfs.ru.md)** — NFS 3.0 сервер, предоставляющий два варианта файловой системы: + первая — упрощённая для файлового доступа к блочным образам (для не-QEMU гипервизоров, поддерживающих NFS), + вторая — VitastorFS, полноценная кластерная POSIX ФС. Оба варианта поддерживают параллельный + доступ с нескольких vitastor-nfs серверов. На самом деле можно вообще не выделять + отдельные NFS-серверы, а вместо этого использовать команду vitastor-nfs mount, запускающую + NFS-сервер прямо на клиентской машине и монтирующую ФС локально. +- **[Драйвер fio](../usage/fio.ru.md)** — подключаемый модуль для утилиты тестирования + производительности дисков fio, позволяющий тестировать Vitastor-кластеры. +- **vitastor-kv** — клиент для key-value базы данных, работающей поверх разделяемого блочного + образа (обычного блочного образа vitastor). Метаданные VitastorFS хранятся именно в vitastor-kv. + +## Дополнительные утилиты + +- **vitastor-disk** — утилита для разметки дисков под Vitastor OSD. С её помощью можно + создавать, удалять, менять размеры или перемещать разделы OSD. ## Общий процесс записи и чтения @@ -98,16 +114,22 @@ находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех объектов рассчитывается первичным OSD при активации PG и хранится в памяти. -- Первичный OSD соединяется (если ещё не соединён) с вторичными OSD, на которых располагаются - части объекта, и отправляет им запросы чтения/записи, а также читает/пишет из/в своё локальное - хранилище, если сам входит в набор. +- Когда это возможно, первичный OSD обрабатывает запрос локально. Например, так происходит + при чтениях объектов из пулов с репликацией или при чтении из EC пула, затрагивающего + только часть, хранимую на диске самого первичного OSD. +- Когда запрос требует записи или чтения с вторичных OSD, первичный OSD использует заранее + установленные соединения с ними для выполнения этих запросов. Это происходит параллельно + локальным операциям чтения/записи с диска самого OSD. Так как соединения к вторичным OSD PG + устанавливаются при её запуске, то они уже гарантированно установлены, когда PG активна, + и если любое из этих соединений отключается, PG перезапускается, а все текущие запросы чтения + и записи в неё завершаются с ошибкой EPIPE, после чего повторяются клиентами. - После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту. ### Особенности обработки запросов - Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный OSD при чтении восстанавливает данные из оставшихся частей. -- Каждый объект имеет номер версии. При записи объекта первичный OSD сначала читает из номер +- Каждый объект имеет номер версии. При записи объекта первичный OSD сначала получает номер версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных @@ -115,20 +137,20 @@ так как метаданные объектов, включая номер версии, все OSD хранят в памяти. - Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска - самого первичного OSD. -- Также, если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется + самого первичного OSD. Это называется процессом "чтение-модификация-запись" (read-modify-write). +- Если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой. -- Если в кластере не включён режим immediate_commit, то запросы записи, отправляемые клиентами, +- Если в пуле не включён режим immediate_commit, то запросы записи, отправляемые клиентами, не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса), а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть, если соответствующий 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