Каковы шансы получить дубликат при использовании SecureRandom.hex? - PullRequest
0 голосов
/ 07 ноября 2018

Я планирую использовать SecureRandom.hex для генерации ключей API для моих пользователей.

Пока здесь вывод в 3-х исполнениях:

Loading development environment (Rails 5.2.1)
2.3.5 :001 > SecureRandom.hex
 => "0369e9b7c6ffa07bd8d0a263f7b4cfa6" 
2.3.5 :002 > SecureRandom.hex
 => "1a8a168d7f70676451e3d59353e22693" 
2.3.5 :003 > SecureRandom.hex
 => "94cc188e9e5c3abfe587510fa79993ce"

Какова вероятность того, что я получу повторяющийся результат?

И будет ли созданный мною метод действительно избегать создания дублированного контента?

def generate_string
  string = SecureRandom.hex

  generate_string if Model.where(:key => string).count > 0

  string
end

unique_string = generate_string

Я использую рекурсию, что если строка уже сохранена в базе данных, она просто создаст другую.

А также, поскольку я не получаю дубликат, сколько строк я могу создать с помощью SecureRandom.hex до того, как он получит комбинации для создания?

Ответы [ 3 ]

0 голосов
/ 07 ноября 2018

В вашем примере (при использовании SecureRandom.hex с длиной по умолчанию 32) есть

16**32 = 340282366920938463463374607431768211456

возможны различные значения в шестнадцатеричном формате. Это означает, что есть шанс 1:340282366920938463463374607431768211456 создать дубликат. Этот шанс крайне низок, и имхо не имеет смысла слишком волноваться об этом.

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

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

tl; dr Вероятность дубликатов крайне мала. Только уникальный индекс для столбца key в базе данных гарантирует, что никогда не будет дубликатов (из-за условий гонки или ключей, сгенерированных в обход этого метода).

0 голосов
/ 07 ноября 2018

Длина клавиш в вашей настройке равна 32.

  • Шансы не получить дубликаты в трех исполнениях:

    ((16**32 - 1)/16**32) * ((16**32 - 2)/16**32)
    

    Таким образом, шансы получить (хотя бы пару) дубликатов где-то в трех исполнениях:

    1 - ((16**32 - 1)/16**32) * ((16**32 - 2)/16**32)
    = 8.8162076e-39
    
  • Есть:

    16**32 = 3.4028237e+38
    

    разные строки.

  • Ваш метод может избежать дубликатов, когда он работает как задумано, но он также имеет невероятно малую вероятность попасть в вечность и никогда не завершится.

0 голосов
/ 07 ноября 2018

Поскольку это базовая система счисления 16, существует 16 ** SecureRandom.hex.length возможных вариаций, что довольно много.

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

MAX_ATTEMPTS = 3 # For you to choose.

def key
  MAX_ATTEMPTS.times do
    hex = SecureRandom.hex
    return hex unless Model.where(key: hex).exists?
  end

  fail 'No attempts to generate a key left.'
end
...