Служебная фабрика - Как мы могли генерировать ключ ключа?

У меня есть служба с отслеживанием состояния с набором ключей разделов, идущих от
От -9223372036854775808 до 9223372036854775807 (UniformInt64Partition).

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

Спасибо

2 ответа

Решение

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

Предполагая, что вы храните информацию о клиенте, например, хеш для имени клиента из "Джона Смита" может сгенерировать значение хеш-функции 32, потому что любой пользователь с тем же именем, что и "Джон Смит", сгенерирует тот же хеш, если он не часто, не будет проблемой, потому что 32 не является идентификатором, и они могут повторяться, имея тот же хеш, который будет храниться в одном разделе.

Если вы действительно хотите распределить эти значения как можно более равномерно, вы можете использовать другое объединенное поле, чтобы отличать "Джона Смита" от "Джона Смита", например, дату рождения. И если оба они не родились в одну и ту же дату, вы найдете разные значения для каждый.

В вашем случае, поскольку диапазон очень большой, вы должны использовать алгоритм хеширования, чтобы хэшировать эти значения, чтобы соответствовать диапазону от -9223372036854775808 до 9223372036854775807.

Вам нужно столько ключей?

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

Если вы уже используете GUID в качестве ключа для идентификации своих данных, это не сложно сделать. Главное, чтобы знать, что GUID, хотя (практически) глобально уникальны, даже близко не распределены равномерно по диапазону. Я использую алгоритм хэширования SHA1 для хеширования GUID, потому что, несмотря на его недостатки в качестве криптографического алгоритма, он хорошо генерирует равномерно распределенные хэши, не требуя слишком большой нагрузки на сервер (с точки зрения вычислений и оперативной памяти).

Как примечание, переходя от GUID к long, вы создаете потерю данных (GUID эквивалентны 128-битному целому числу). Поскольку цель состоит в том, чтобы распределить данные по разделам, это нормально... не переживайте по мелочам. На самом деле вы можете использовать меньший диапазон, чем Int64, но если у вас уже есть GUID, то зачем беспокоиться.

См. Код, приведенный выше, для метода расширения для создания ключа раздела из GUID. Мой код реализации сворачивает его в две строки, но я разбил его ниже, чтобы я мог аннотировать его.

public static ServicePartitionKey ToPartitionKey(this Guid id)
{
    // Hash algorithms need byte arrays, so we're converting the Guid here
    byte[] guidBytes = id.ToByteArray();

    // SHA1 is light weight and good at creating distribution across the range.
    // Do not use for encryption!
    SHA1CryptoServiceProvider hasher = new SHA1CryptoServiceProvider();

    // Hash the Guid's bytes.
    byte[] hashedBytes = hasher.ComputeHash(guidBytes);

    // Now that our data is repeatibly but distributed evenly, we make it a long
    long guidAsLong = BitConverter.ToInt64(hashedBytes, 0);

    // return the partition key
    return new ServicePartitionKey(guidAsLong);
}
Другие вопросы по тегам