Создание отказоустойчивого генератора серийных номеров с помощью файлов журнала - PullRequest
1 голос
/ 31 июля 2011

У меня есть система, которая в основном является генератором серийных номеров.

Существует два основных требования к конструкции генератора серийных номеров (с точки зрения отказоустойчивости):

  1. Все выданные серийные номера должны быть уникальными (без дубликатов)
  2. В случае сбоя генератора серийного номера требуется способ перезапустить примерно с того места, где он остановился (пропуская несколько серийных номеров привосстановление после сбоя - это нормально, если необходимо, чтобы убедиться, что требование № 1 выполнено)

Можно предположить, что серийные номера выдаются последовательно (1, 2, 3, 4 и т. д.)

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

Вот вызов:

Итак, чтопреимущества и недостатки следующих подходов к ведению журналов:

  1. иметь один файл журнала, который добавляется и ограничивается определенным размером
  2. имеет два файла журнала, ни один из которых не являетсяприлагается.Первый файл журнала всегда содержит последний выпущенный серийный номер, а второй файл содержит второй самый последний выпущенный серийный номер.Файлы журналов записываются в виде наглядности (т.е. все четные серийные номера попадают в файл журнала «A», а нечетные серийные номера помещаются в файл журнала «B»).Конечный результат заключается в том, что у вас всегда есть последние два выпущенных серийных номера (и не более), использование дискового пространства незначительно, и если произошел сбой генератора серийного номера при регистрации самого последнего серийного номера, то 'последний файл может быть поврежден.Поскольку у нас также есть второй самый последний серийный номер в другом файле журнала, мы можем обнаружить сбой и перезапустить генератор серийного номера с этого «второго самого последнего» серийного номера, + 2

InСценарий сбоя, при котором генератор серийного номера не может определить, какой из «самых последних» или «2-х самых последних» файлов журнала является поврежденным, должно быть безопасно всегда перезапустить сбойный генератор из неповрежденный серийный номер + 2.

Вариант 1 немного проще реализовать, но вариант 2 использует меньше дискового пространства и кажется более интеллектуальным.

Я что-то упускаю с точки зрения разработкисистема, которая может надежно восстановиться после сбоя с помощью достаточного количества файлов журнала?

Ответы [ 2 ]

1 голос
/ 31 июля 2011

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

Вдобавок ко всему, некоторые из них могут быть следующими: Недостаток места на диске, плохое кодирование с несвободными ресурсами, проблемы с многопоточностью и т. Д.

Если ваша цель просто убедиться, что сгенерированный серийный номер сохранен и уникален, то я бы, вероятно, предложил использовать что-то вроде сервера sql в сочетании со столбцом типа NEWSEQUENTIALID (). Здесь есть определенные преимущества из-за проблемного пространства, которое SQL Server уже решил. Количество транзакций в секунду, которые вы можете поддерживать, зависит от оборудования и от того, как вы его используете.

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

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


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

1 голос
/ 31 июля 2011

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

Скажем, его 1000.

Тогда вы сохраните самую большую последовательность в файле.

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

В случае сбоя необходимо ОСТАНОВИТЬ и прервать генератор последовательности.

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

Итак, вот процедура.

function int getNextSequence() {
    currentSeq = currentSeq + 1; 
    if (currentSeq >= maxSeq) {
        maxSeq = maxSeq + 1000;
        write(maxSeq, "newSeq");
        rename("newSeq", "curSeq");
    }
    return currentSeq;
}

function restartSequence() {
    maxSeq = read("curSeq");

    currentSeq = maxSeq - 1; // This will immediately create a disk update on first use.
 }

Может быть одиношибка здесь, не проверено.

Дополнения:

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

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

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

Но вы пишете значения и хэши.

Причина, по которой вы делаете это, проста.

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

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

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

...