Оптимизировали генерацию и хранение уникальных маркировочных кодов

6 июня 2025

Задача

У клиента возникли проблемы с безопасным хранением кодов в базе данных — при проверке выяснилось, что коды хранятся в открытом виде и при утечке могут быть использованы злоумышленниками.
Нам нужно было решить три задачи:

  1. Сделать хранение кодов в базе более безопасным.
  2. Улучшить архитектуру и использовать более надёжные библиотеки.
  3. Избежать бесконечной работы программы из-за рекурсии.

Решение

Обеспечили безопасное хранение кодов

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

Что мы сделали:

  • Добавили новые поля в таблицы для хранения хешей.
  • Написали отдельный сервис, который создаёт хеш и записывает его во временную таблицу при генерации.
  • Перешли на более надёжный способ генерации кодов — RandomNumberGenerator, что улучшило уникальность кодов.
  • В настройках добавили ограничения на количество повторов, чтобы не возникала бесконечная генерация.
  • Перед началом генерации кодов программа теперь рассчитывает, сколько уникальных кодов можно получить при заданных параметрах. Если нужное количество невозможно, генерация не начинается.
  • Изменили запросы для удаления дубликатов: теперь они работают по хешу, а не по коду.
  • Подготовили инструкцию для клиента по переходу на работу с хешами вместо обычных кодов.

Добавили хеши для уже существующих кодов

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

В базе уже было ~ 65 миллионов кодов. Чтобы быстро посчитать для них хеши, мы использовали SQL-запросы прямо в MySQL:

UPDATE fmccodes
SET CodeHash = SHA2(CONCAT(Code, 'key'), 256)
WHERE Prefix IN ('XX', 'YY', 'ZVC');

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

Оптимизировали процесс генерации и хранения кодов

Как работала генерация кодов до оптимизации? На основе настроек создавался массив параметров, где указывалось, сколько кодов нужно сгенерировать за один раз и сколько потоков использовать. Коды генерировались по заданным правилам: длина, допустимые символы, спецсимволы и т. д.

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

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

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

Мы проанализировали процесс генерации и нашли самые «тормозящие» операции:

  • Коды долго записывались в основную таблицу из-за большого объёма данных и индексов;
  • Также долго удалялись дубликаты в основной и временной таблицах;
  • При удалении старых кодов место на диске не освобождалось.

Как мы ускорили процесс:

  • Ввели отдельные таблицы для каждого префикса — как бы разбили основную таблицу на части.
  • Убрали лишние индексы, которые тормозили запись.
  • Сделали поле CodeHash основным ключом во временной таблице. Это значит, что дубликаты в неё просто не добавлялись.
  • Использовали вставку INSERT IGNORE — если код уже есть, он не добавляется, а программа просто генерирует ещё.
  • Отказались от удаления дублей — теперь мы просто дозаписываем недостающие коды.

После оптимизации генерация 10 миллионов кодов заняла всего 18 минут на обычном ПК вместо 8 часов — то есть время сократилось в 20 раз.

Увеличение скорости генерации кодов

Результат

Мы предоставили клиенту исходный код консольной программы на языке C#, которая генерирует уникальные коды и записывает их в базу данных. Перед запуском сотрудник настраивает параметры генерации в XML-файле, а после завершения работы коды появляются в базе в хешированом виде, а в файле — в открытом.

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

Пример работы программы:

Пример генерации кодов

Что дальше

Чтобы сделать процесс генерации кодов ещё удобнее и безопаснее, мы наметили следующие шаги:

  • Создать веб-интерфейс, через который можно будет запускать генерацию кодов, следить за процессом и скачивать готовые файлы с кодами.
  • Развернуть приложение на сервере или в Docker-контейнере.
  • Описать и задокументировать архитектуру базы данных.
  • Внедрить очереди задач для более стабильной и масштабируемой генерации.
  • Изменить консольную программу, чтобы она принимала параметры прямо при запуске, а не из XML-файла.
Вертикальная линия Обсудить проект
Давайте добьемся успеха вместе

Контактные данные




Нажимая кнопку «Отправить», я даю свое согласие на обработку моих персональных данных в соответствии с Федеральным законом от 27.07.2006 года №152-ФЗ «О персональных данных», на условиях и для целей, определенных в политике конфиденциальности

Vertical Line
Choose languageRU

© 2009—2025 Mygento. Все права защищены. Политика конфиденциальности

Menu Menu Menu

Аккредитованная
ИТ-компания