Открыть сервис

Хэш-кольцо

Хэш-кольцо (англ. hash ring, также консистентное хэширование в контексте топологии) — это структура данных и алгоритм распределения нагрузки, использующийся в распределённых вычислительных системах для равномерного размещения данных или запросов на множестве узлов (серверов). Основная особенность хэш-кольца заключается в минимизации объёма перераспределения данных при добавлении или удалении узлов, что делает его ключевым компонентом многих систем хранения данных, кэширования и баз данных (например, Amazon Dynamo, Apache Cassandra, Riak).

Принцип работы

Хэш-кольцо представляет собой абстрактное пространство, представленное в виде окружности (кольца) с фиксированным диапазоном значений хэш-функции. Обычно используется диапазон от 0 до \(2^{32} - 1\) (или \(2^{64} - 1\)), что соответствует стандартным хэш-функциям, таким как MD5 или SHA-1.

Размещение узлов

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

Размещение данных

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

Пример работы

Предположим, есть три узла: A, B, C. Их хэш-значения на кольце равны 10, 50 и 90 (в условных единицах). Ключ с хэшем 30 будет назначен на узел B (следующий по часовой стрелке от 30 — это 50). Ключ с хэшем 70 — на узел C. Ключ с хэшем 95 — на узел A (поскольку кольцо замкнуто, после 90 идёт 0, а затем 10).

Преимущества перед традиционным хэшированием

Традиционное модульное хэширование (например, hash(key) % N, где N — количество узлов) страдает от серьёзного недостатка: при изменении количества узлов (добавлении или удалении) почти все ключи перераспределяются. Это приводит к высокой нагрузке на систему и потенциальной потере данных.

Хэш-кольцо решает эту проблему:

  • Минимизация перераспределения: при добавлении нового узла только часть ключей, попадающих в диапазон между новым узлом и его соседом, переназначается. В среднем, при добавлении одного узла перераспределяется только \(1/N\) часть данных (где N — общее количество узлов). При удалении узла его нагрузка равномерно распределяется между соседями.
  • Масштабируемость: система может легко расширяться или сжиматься без полной перестройки.
  • Балансировка нагрузки: с помощью виртуальных узлов (см. ниже) можно добиться равномерного распределения данных даже при неоднородной мощности серверов.

Виртуальные узлы (Virtual Nodes)

Для повышения равномерности распределения данных и снижения влияния неравномерного хэширования (когда реальные узлы могут попасть в близкие точки на кольце) используется концепция виртуальных узлов (vNodes). Каждый физический узел представляется на кольце несколькими виртуальными узлами с разными идентификаторами (например, хэш от имени узла с добавлением суффикса). Это позволяет:

  • Улучшить балансировку: нагрузка распределяется более равномерно, так как виртуальные узлы разбросаны по всему кольцу.
  • Упростить добавление/удаление узлов: при удалении физического узла его виртуальные узлы равномерно распределяются между оставшимися.
  • Адаптироваться к разной производительности: мощные узлы могут иметь больше виртуальных узлов, чем слабые.

Применение

Хэш-кольцо является фундаментальной технологией для многих распределённых систем:

Распределённые базы данных и хранилища

  • Apache Cassandra: использует хэш-кольцо для распределения данных между узлами кластера. Каждый узел отвечает за диапазон токенов. При добавлении нового узла данные перераспределяются только в пределах его диапазона.
  • Amazon DynamoDB (и его предшественник Dynamo): применяет консистентное хэширование для обеспечения высокой доступности и отказоустойчивости.
  • Riak: также основан на консистентном хэшировании.

Системы кэширования

  • Memcached: в распределённых конфигурациях может использовать хэш-кольцо для равномерного распределения ключей между серверами кэша.
  • Redis Cluster: использует хэш-слоты (16384 слота), которые распределяются между узлами. Это аналогично хэш-кольцу, но с фиксированным числом слотов.

Системы управления контентом и CDN

  • Content Delivery Networks (CDN): для распределения запросов к контенту между серверами.
  • Распределённые файловые системы: например, GlusterFS использует хэш-кольцо для определения местоположения файлов.

Балансировка нагрузки

  • Веб-серверы: для распределения входящих запросов между пулом серверов с сохранением сессий (sticky sessions).

Ограничения и недостатки

Несмотря на преимущества, хэш-кольцо имеет ряд ограничений:

  • Неравномерность распределения: даже с виртуальными узлами распределение данных может быть неидеальным, особенно при малом количестве узлов. Для больших кластеров это менее заметно.
  • Сложность репликации: для обеспечения отказоустойчивости требуется репликация данных на несколько узлов (например, на следующий по кольцу узел). Это усложняет логику записи и чтения.
  • Управление токенами: в системах с ручным управлением токенами (например, в старых версиях Cassandra) требуется тщательная настройка для избежания дисбаланса.
  • Зависимость от хэш-функции: если хэш-функция не обеспечивает равномерного распределения, это может привести к перекосам.

Реализации

  • Apache Cassandra: использует алгоритм Murmur3Partitioner (по умолчанию) или RandomPartitioner (на основе MD5). Токены распределяются по кольцу с помощью виртуальных узлов.
  • Amazon DynamoDB: использует консистентное хэширование с репликацией на N узлов (обычно 3).
  • Redis Cluster: использует фиксированное число хэш-слотов (16384), которые распределяются между узлами. Это упрощает реализацию, но не является чистым хэш-кольцом.
  • Go, Python, Java: существуют библиотеки для реализации консистентного хэширования (например, hashring в Python, consistent в Go).

История

Концепция консистентного хэширования была впервые предложена Дэвидом Кагером и его коллегами в 1997 году в работе «Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web». Изначально она использовалась для распределённого кэширования в веб-системах. Позднее, в 2007 году, компания Amazon опубликовала описание Dynamo, где консистентное хэширование стало ключевым элементом. С тех пор технология получила широкое распространение в NoSQL-базах данных и других распределённых системах.

Источники

  • Karger, D., et al. «Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web» (1997).
  • DeCandia, G., et al. «Dynamo: Amazon’s Highly Available Key-value Store» (2007).
  • Документация Apache Cassandra: «Partitioners» (The Apache Software Foundation).
  • Документация Redis Cluster: «Redis Cluster Specification» (Redis Labs).
  • Официальная документация Riak: «Riak Core — Consistent Hashing» (Basho Technologies).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →