Хэш-кольцо
Хэш-кольцо (англ. 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 →