Архитектура Swift

Преимущества

Объектное хранилище обеспечивает большую гибкость, меньшую блокировку, лучший контроль и более низкие затраты, чем традиционные системы хранения. Swift работает на языке интернета (http), поэтому легко интегрируется в web-приложения.

Открытый исходный код

Swift имеет открытый исходный код под лицензией Apache 2 как часть проекта OpenStack. Исходный код может быть проверен гораздо большим количеством разработчиков, чем в случае с проприетарным программным обеспечением. Это означает, что потенциальные ошибки, как правило, более заметны и исправляются быстрее, чем при использовании коммерческого ПО. Разработчики получают выгоду от богатого и постоянно растущего набора инструментов и библиотек Swift. Помимо основных функций по долговременному хранению и обслуживанию данных в больших масштабах, Swift имеет множество встроенных функций, которые упрощают работу разработчиков приложений и пользователей.

Масштабируемость

По мере масштабирования системы она продолает представлять единое пространство имен. Это означает, что приложению или пользователю не нужно знать, где именно расположены его данные. Это снижает нагрузку на оператора, в отличие от файловой системы, где операторам приходится управлять несколькими томами хранения. Поскольку система хранения объектов предоставляет единое пространство имен, нет необходимости вручную разбивать данные и отправлять их в разные места хранения.

Устойчивость к сбоям

SDS возлагает ответственность за систему на программное обеспечение, а не на конкретные аппаратные компоненты. Вместо того, чтобы пытаться предотвратить сбои, SDS воспринимает сбои в системе как неизбежные. Это означает, что вместо того, чтобы предсказывать сбои, система просто работает так, как будто их нет.

Маршрутизаторы в Swift могут маршрутизировать запросы к хранилищу в обход аппаратных и сетевых сбоев. При возникновении аппаратного сбоя система применяет простые правила для обслуживания запроса, собирая необходимые фрагменты данных или получая копии данных из исправных мест.

Доступность

С акцентом на доступность, а не на согласованность, Swift не имеет задержек транзакций или блокировок. Большое количество одновременных операций чтения, как и одновременная запись, выполняются асинхронно и быстро. Это означает, что Swift способен масштабироваться до чрезвычайно большого количества одновременных подключений и чрезвычайно больших наборов данных.

Мультирегиональность

Swift может распределять данные по нескольким центрам обработки данных, между которыми может наблюдаться высокая задержка. Swift делает это, позволяя операторам определять регионы и зоны внутри кластера. Регионы обычно указывают географические границы, например центры обработки данных в разных городах. Зоны - это части регионов, которые определяют точки отказа для групп машин, например стойка, в которой все узлы подключены к одному источнику питания, подключенному к одному коммутатору. Использование регионов и зон гарантирует, что Swift размещает копии в кластере таким образом, чтобы исключить сбои. Это позволяет кластеру выжить, даже если зона недоступна. Это дает дополнительные гарантии долговечности и доступности данных.

Параллелизм

Swift спроектирован для распределения запросов между несколькими серверами. Используя подход «sharednothing», Swift может использовать всю доступную мощность сервера для одновременной обработки множества запросов. Это увеличивает параллелизм системы и общую доступную пропускную способность. Это большое преимущество для тех, кому необходимо удовлетворить потребности в хранении данных для крупномасштабных веб-рабочих нагрузок.

Гибкость

Swift предлагает большую гибкость в архитектуре данных и аппаратном обеспечении, позволяя операторам адаптировать свое хранилище для удовлетворения конкретных потребностей своих пользователей. В дополнение к возможности комбинировать и сочетать стандартное оборудование, Swift имеет политику хранения, которая позволяет операторам использовать оборудование таким образом, чтобы наилучшим образом справляться с ограничениями различных ситуаций.

Свобода в выборе оборудования

Swift спроектирован с нуля для устранения сбоев, поэтому надежность отдельных компонентов менее критична. Установки Swift могут надежно работать на стандартном оборудовании и даже на обычных дисках для настольных ПК, а не на более дорогих дисках корпоративного уровня. Способность Swift использовать стандартное оборудование означает отсутствие привязки к какому-либо конкретному поставщику оборудования.

Безопасность

Объектам может быть задан срок действия, по истечении которого они станут недоступны и будут удалены. Это очень полезно для предотвращения распространения устаревших данных и соблюдения политик хранения данных. Кроме того, Swift поддерживает квотирование данных, версионность и списки доступа. Ограничения хранилища могут быть установлены для контейнеров и учетных записей. Пользователи могут записать новую версию объекта в Swift, сохранив все старые версии. Пользователи могут настроить доступ к своим данным с помощью механизма ACL, чтобы предоставить или запретить другим пользователям читать или записывать данные.

Фрагментированность

Пользователи могут загружать данные в Swift, не зная заранее, насколько велик объект. Пользователи могут прочитать или записать только один или несколько разделов объекта с помощью одного запроса.

Объемы хранения

  • 1 Йб (йотабайт) = 1000 Зб (зетабайт)
  • 1 Зб (зетабайт) = 1000 Эб (экзабайт)
  • 1 Эб (экзабайт) = 1000 Пб (петабайт)
  • 1 Пб (петабайт) = 1000 Тб (терабайт)
  • 1 Тб (терабайт) = 1000 Гб (гигабайт)

1 Эб - это примерно 537 млрд. фотографий высокого разрешения (~2 Мб). В ответ на быстрый рост данных и распространение терминов некоторые предложили просто использовать слово «хеллабайт» для обозначения «чертовски большого количества байтов».

Структура

Логическая структура представлена на рисунке.

Логическая стркутура Swift

Регионы

Swift позволяет определять физически отдельные части кластера как регионы. Регионы чаще всего определяются географическим расположением дата центров. Например, новый регион может быть определен для нескольких стоек серверов (узлов), которые расположены в удаленном месте с более высокой задержкой, вдали от других узлов кластера. В кластере должен быть минимум один регион. На практике существует множество однорегиональных кластеров, в которых все узлы принадлежат одному и тому же региону. Если кластер использует два или более региона, это многорегиональный кластер (MRC). Многорегиональные кластеры имеют определенное поведение при чтении и записи. В частности, когда MRC получает запрос на чтение, Swift будет отдавать предпочтение копиям данных, которые находятся ближе к потребителю. При этом используются алгоритмы измерения задержки. Это называется read affinity.

При операциях на соединениях с высокой задержкой может помочь включение write affinity. При привязке к записи каждый запрос на запись создает необходимое количество копий данных локально. Затем копии асинхронно передаются в другие регионы. Это позволяет ускорить операции записи за счет увеличения несогласованности между регионами до завершения асинхронной передачи.

Описание сервисов

openstack-swift-proxy

Коммуникация Swift с клиентами по протоколу HTTP и за распределение запросов на чтение и запись между узлами.

openstack-swift-account

Поддержка баз данных SQLite, содержащих информацию о контейнерах, доступных конкретной учетной записи. Для каждой учетной записи создается своя база данных, и точно так же, как и объекты, базы данных реплицируются внутри кластера.

openstack-swift-container

Поддержка баз данных, содержащих информацию об объектах, имеющихся в каждом контейнере. Для каждого контейнера создается своя база данных SQLite. Базы данных реплицируются внутри кластера.

openstack-swift-object

Отвечает за хранение, доставку и удаление объектов, сгруппированных в логические группы, называемые разделами на дисках узла. Важно, что разделы в терминологии Swift – это не разделы диска. Раздел – это директория на файловой системе, поддерживающей расширенные атрибуты файлов (обычно XFS или ext4). Объекты хранятся в поддиректориях директории-раздела. Для идентификации объекта используется MD5-хэш пути к объекту. Метаданные, такие, как, например, метка последнего доступа, хранятся в расширенных атрибутах файловой системы. Сервис позволяет хранить несколько версий одного и того же объекта, а также его срок хранения.

Теория колец

Согласованное хеширование помогает минимизировать количество объектов, которые перемещаются при добавлении или удалении емкости кластера. Вместо сопоставления каждого значения непосредственно с одним диском, диапазон значений связывается с одним диском. Это делается путем сопоставления всех возможных значений хеш-функции по кругу. Затем каждому диску присваивается точка на круге на основе хэш-значения диска. В результате все диски располагаются по кольцу в достаточно случайном порядке, как показано на рисунке.

consistent-hash-ring

Когда объект необходимо сохранить, хэш объекта определяется, а затем располагается в круге. Затем система выполнит круговой поиск по часовой стрелке, чтобы найти ближайший маркер соответствия. Это будет диск, на котором будет размещен объект. Используя подобное кольцо хеширования, вы можете добавить или удалить диск, и только несколько объектов будут перемещены, а не все объекты дщиска, как это происходит при простом хэшировании - аналоге корешков в энциклопедии. Когда в круг добавляется диск, следующий от него диск по часовой стрелке потеряет только те объекты, хеш-код которых находится в вытесненной части хеш-диапазона, захваченной новым диском. И только эти объекты будут скопированы на новый диск, остальные объекты останутся на своих местах. Когда добавляется новый диск, он сопоставляется с несколькими небольшими диапазонами хеш-функции по кольцу, и каждый из соседних дисков на кольце откажется от объектов в этих диапазонах. Перемещение меньшего количества объектов с нескольких разных дисков обеспечивает более равномерное размещение данных на всех дисках.

consistent-hash-ring-2

Swift использует модифицированное кольцо согласованного хеширования. Эти модификации создают разделенное согласованное кольцо хеширования, которое использует количество реплик, блокировку реплик и механизмы распределения данных, такие как вес диска и максимально возможное уникальное размещение, для создания отдельных колец Swift. Для кластера будет создано одно кольцо учетной записи (account), которое будет использоваться для определения места расположения данных учетной записи. Также будет создано одно кольцо контейнеров (container), которое используется для определения местоположения данных контейнера. Для каждой используемой политики хранения будет создано одно кольцо политики хранения объектов (object), которое используется для определения местоположения данных объекта.

Партиции в Swift

При использовании немодифицированного кольца согласованного хеширования существует множество небольших диапазонов хеширования, которые становятся меньше или больше при добавлении или удалении дисков. Это изменение может привести к тому, что объекты будут недоступны, поскольку они перемещаются во время изменения емкости.

Мощность раздела

Чтобы предотвратить это, Swift по-другому подходит к кольцу хеширования. Хотя кольцо по-прежнему разделено на множество небольших хэш-диапазонов, все эти диапазоны имеют одинаковый размер и их количество не изменится. Эти разделы (партиции) имеют фиксированную ширину и назначаются дискам с использованием алгоритма размещения. Каждый диск делится на разделы, каждый из которых представляет собой директорию. Рекомендуется от 100 разделов на диск. Общее количество разделов, которые могут существовать в вашем кластере, рассчитывается как два в степени мощность раздела - целого числа выбранного во время создания кластера. Для определения мощности раздела необходимо запланировать максимальное число дисков в кластере. Например, при 100 разделах на диске и общем количестве дисков 1000, общее число разделов будет 1000 × 100 = 100000. Для такого числа разделов надо определить ближайшую степень числа два, большую, чем 100 тысяч. Это будет 17, поскольку 2^17 = 131072. Соответственно, наша мощность раздела будут равна 17. Вычисляем по формуле общее количество партиций: partitions_quantity = 215 = 131072 Эти 131072 раздела затем сопоставляются со всеми доступными дисками.

Число реплик

Вторым параметром задается число реплик файла - 3. Об этом подробнее расскажем ниже.

Продолжительность блокировки

Третий параметр при создании кольца - минимальное число часов (min_part_hours), по истечении которых раздел можно перемещать. Как правило это значение равно 1 часу. Во время перемещения раздела Swift заблокирует реплики этого раздела, чтобы их нельзя было перемещать, чтобы обеспечить доступность данных. Блокировки используются как при обновлении колец, так и при оперативном перемещении данных. Точная продолжительность блокировки раздела min_part_hours задается на этапе создания кольца. Это значение зависит от многих факторов - прежде всего от пропускной способности сети, вычислительной мощности процессоров, степени загрузки СХД по времени суток и т.п.

Реплики

Чем больше у вас реплик, тем лучше вы защищены от потери данных в случае сбоя (особенно если вы распределяете реплики по центрам обработки данных и географическим регионам). Для количества реплик обычно устанавливается целое число, например 3. Однако, допустимо использовать и дробное число реплик - в этом случае определенный процент разделов будет иметь еще одну дополнительную реплику; например, количество реплик 3,3 означает, что 30% дисков будут иметь четыре реплики, место трех. Это необходимо для более плавного перехода от одного целочисленного количества реплик к другому, что позволит Swift скопировать дополнительные данные, не перегружая сеть. Кроме того, это можно использовать в тех случаях, когда необходимо разместить в СХД больше данных, чем изначально планировалось, на период времени, пока не будут приобретены и введены в эксплуатацию дополнительные серверы хранения (горизонтальное масштабирование). В этом случае, естественно, количество реплик дробно уменьшается, например с 3 до 2.7.

Репликация раздела включает в себя назначение дисков с передачей обслуживания. Это означает, что в случае сбоя диска процессы аудита и репликации заметят это и отправят данные в новые партиции. Это значительно снижает MTTR (среднее время восстановления) по сравнению со стандартным зеркалированием или RAID. Вероятность того, что все реплицированные разделы в системе будут повреждены до того, как кластер исправит это в автоматическом режиме, очень мала.

Механизмы распределения данных

Помимо использования модифицированной кольцевой структуры, в Swift есть два других механизма для равномерного распределения данных.

Вес носителя

Swift использует значение, называемое вес для каждого диска в кластере. Это определяемое пользователем значение, устанавливаемое при добавлении диска, представляет собой относительную долю диска по сравнению с другими дисками в кольце. Вес позволяет кластеру вычислить, сколько разделов следует назначить диску. Чем выше вес, тем большее количество разделов Swift должен назначить диску.

Уникальность по-возможности

Чтобы гарантировать, что кластер хранит данные равномерно в определенных пространствах (регионах, зонах, узлах и дисках), Swift размещает разделы, используя алгоритм, называемый unique-as-possible. Алгоритм определяет наименее используемый регион, затем зону, затем точку подключения сервера (IP:порт), а затем, при необходимости, наименее используемый диск. После этого Swift помещает раздел именно в эту расположение. Данный алгоритм “наименее используемого” также пытается разместить реплики разделов как можно дальше друг от друга для дополнительного обеспечения надежности хранения.

Создание колец

Создание кольца состоит из двух этапов: обновление файлов компоновщика и повторная балансировка колец. Во время создания кластера Swift использует утилиту ring-builder для создания конструктора, который является заготовкой для создания колец. Для учетных записей, контейнеров и каждой политики хранения объектов создается отдельный файл компоновщика, который содержит все три параметра кольца, которые были рассмотрены выше. Важно отметить, что информация в каждом файле компоновщика отделена от других. Так,например, можно добавить некоторые диски в кольца учетной записи и построителя контейнеров, а в объектные кольца - не добавлять. После того как файлы компоновщика созданы или обновлены, приступаем ко второму этапу - собственно, построению кольца. Утилита ring-builder запускается с ключом перебалансировки кольца, используя файл компоновщика в качестве входных данных. Соответственно, это делается для каждого из колец: аккаунта, контейнера и объекта. Как только эти новые кольца будут созданы, их необходимо скопировать на все узлы кластера, взамен старых колец.

Каждый раз, когда Swift строит кольцо, создаются и заполняются две важные внутренние структуры данных на основе информации файла компоновщика.

Список устройств

Построитель колец заполняет этот список всеми устройствами, которые были добавлены в файл построителя колец. Каждая запись о диске включает его идентификационный номер, зону, вес, IP-адрес, порт и имя устройства.

Таблица поиска устройств

Эта таблица содержит одну строку на каждую реплику и один столбец на каждую секцию в кластере. Обычно это три строки и тысячи столбцов. Построитель колец вычисляет оптимальный диск для размещения каждой реплики раздела, используя веса дисков и алгоритм максимально уникального размещения. Затем он записывает диск в таблицу, которая выглядит, как матрица:

replica 0 1 2 3 4 n
0 3 1 2 23 8 x
1 6 11 7 17 8 y
2 13 21 1 0 31 x

Эти внутренние данные запрашиваются процессом Swift, определяющим расположение данных. Процесс Swift сначала рассчитает хеш искомых данных, который сопоставляется со столбцом данной матрицы. Далее вызывающий процесс проверит каждую строку реплики в этом конкретном столбце, чтобы определить, на чем основаны данные. Затем он выполняет вторую итерацию поиска в списке устройств, чтобы получить необходимую информацию о целевом диске. Таким образом, процесс может обращаться ко всем местоположениям данных.

Опубликовано: 20.01.2024