Мне нужно придумать собственный механизм рекурсивной блокировки объектов \ шаблон для распределенной системы в C #. По сути, у меня есть многоузловая система. Каждый узел имеет эксклюзивные разрешения на запись для n-го числа состояний. Такое же состояние также доступно в форме только для чтения, по крайней мере, на одном другом узле. Некоторые записи / обновления должны быть атомарными во всех узлах, в то время как другие обновления в конечном итоге станут согласованными в процессе фоновой репликации, очередях и т. Д.
Для атомарных обновлений я ищу шаблон или образцы, которые позволят мне пометить объект как заблокированный для записи, который я затем смогу распространять, фиксировать, выполнять откат и т. Д. Так как система имеет высокий уровень параллелизма, я Я предполагаю, что мне нужно будет иметь возможность наращивать блокировки, которые будут либо превышены по времени, либо будут развернуты после снятия блокировок.
Части транзакций или сообщений не являются предметом этого вопроса, но я предоставил их для некоторого дополнительного контекста. С учетом сказанного, не стесняйтесь сформулировать, какие сообщения, по вашему мнению, будут необходимы, если хотите.
Вот расплывчатый образец того, что я представлял, хотя я открыт для любых новых идей, кроме реализации целых новых продуктов
thing.AquireLock(LockLevel.Write);
//Do work
thing.ReleaseLock();
Я думал об использовании методов расширения, которые могут выглядеть примерно так
public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{
//TODO: Add aquisition wait, retry, recursion count, timeout support, etc...
//TODO: Disallow read lock requests if the 'thing' is already write locked
//TODO: Throw exception when aquisition fails
instance.Lock = lockLevel;
}
public static void ReleaseLock(this IThing instance)
{
instance.Lock = TupleLockLevel.None;
}
Чтобы уточнить пару деталей ...
- Все коммуникации осуществляются по протоколу TCP / IP с использованием протокола двоичного запроса / ответа.
- Нет промежуточных технологий, таких как очереди или базы данных
- Центрального главного узла нет. В этом случае механизм блокировки определяется инициатором блокировки и партнером, который выполнит запрос с некоторой формой тайм-аута для управления его поведением.
У кого-нибудь есть предложения?
Ответы:
Спасибо за разъяснения.
В этом случае я бы порекомендовал использовать модель публикации / подписки. Протокол распределенной блокировки Google Chubby (реализация Paxos )
Я никогда не использовал Paxos (или Chubby), но , как представляется , реализация с открытым исходным кодом здесь .
Если это не сработает, вы можете реализовать свою собственную версию Paxos, используя, например, одного из обычных подозреваемых с точки зрения библиотек сообщений: библиотеки с нулевой очередью сообщений , RabbitMQ или ActiveMQ .
Предыдущий ответ:
Большинство предложений по SO ( [A] , [B] ) касаются использования очереди сообщений для обеспечения блокировки между компьютерами.
Ваш
AcquireLock
метод помещает что-то, идентифицирующее объект блокировки, в очередь, проверяя предыдущие случаи блокировок до успеха. ВашReleaseLock
метод удалит объект блокировки из очереди.Пользователь SO Атлантис предлагает, в этой должности , должности Джефф Ключа для некоторых деталей.
источник
Мне кажется, у вас есть несколько смешанных технологий:
коммуникация (на которую вы в основном полагаетесь как на 100% надежную ... которая может быть фатальной)
блокировка / взаимное исключение
таймауты (с какой целью)?
Слово предупреждения: таймауты в распределенных системах могут быть чреваты опасностью и сложностью. Если они используются, их следует устанавливать и использовать очень осторожно, потому что неразборчивое использование тайм-аутов не решает проблему, оно просто откладывает катастрофу. (Если вы хотите увидеть, как следует использовать таймауты , прочитайте и поймите документацию по протоколу связи HDLC. Это хороший пример подходящего и умного использования в сочетании с умной системой кодирования битов, позволяющей обнаруживать такие вещи, как линия IDLE) ,
Некоторое время я работал в многопроцессорных распределенных системах, подключенных по каналам связи (не TCP, что-то еще). Одна из вещей, которые я узнал, заключалась в том, что в качестве грубого обобщения есть несколько опасных мест для мультипрограммирования:
зависимость от очередей обычно заканчивается слезами (если очередь заполняется, вы попадаете в беду. ЕСЛИ вы можете рассчитать размер очереди, который никогда не заполнится, и в этом случае вы, вероятно, могли бы использовать решение без очереди)
опора на блокировку - это болезненно, попробуйте и подумайте, есть ли другой способ (если вам нужно использовать блокировку, посмотрите литературу, многопроцессорная распределенная блокировка была предметом многих научных работ последних 2-3 десятилетий)
Если вам нужно использовать блокировку, то:
Я ПРИЗНАЮ, что вы будете использовать тайм-ауты только в качестве средства восстановления последней инстанции - т.е. для обнаружения сбоя базовой коммуникационной системы. Далее я предполагаю, что ваша система связи TCP / IP имеет высокую пропускную способность и может рассматриваться как низкая задержка (в идеале ноль, но этого никогда не происходит).
Я хотел бы предложить, чтобы каждый узел имел список подключений других узлов, к которым он может подключиться. (Узлам было бы все равно, откуда происходит соединение.) Заполнение таблиц, к каким узлам может подключиться узел, оставляется как отдельная вещь для сортировки, вы не сказали, будет ли это статически установлено или нет. Также удобно игнорировать такие вещи, как распределение номеров IP-портов, где соединения будут приходить на узел - могут быть веские причины для приема запросов только на один порт или на несколько портов. Это должно быть тщательно продумано. Факторы будут включать неявную организацию очередей, порядок, использование ресурсов, тип операционной системы и возможности.
Как только узлы узнают, к кому они подключаются, они могут отправить этому узлу запрос на блокировку и должны получить ответ от ответа на блокировку от этого удаленного узла. Вы можете упаковать эти две операции в оболочку, чтобы она выглядела атомарно. Результатом этого является то, что узлы, желающие получить блокировку, сделают вызов примерно таким:
вызовы get_lock и release_lock должны быть примерно такими (в принципе):
Вы должны быть очень осторожны с распределенной системой блокировки, чтобы единицы работы, выполняемые при удержании блокировки, были небольшими и быстрыми, потому что у вас будет много удаленных узлов, которые потенциально могут быть заблокированы в ожидании получения блокировки. По сути, это многопроцессорная / коммуникационная система «останови и жди», которая является надежной, но не имеет максимально возможной производительности.
Предложение состоит в том, чтобы использовать совершенно другой подход. Можете ли вы использовать удаленный вызов процедуры, когда каждый вызов RPC содержит пакет информации, который может быть обработан получателем и который устраняет необходимость в блокировках?
Перечитывая вопрос, похоже, что вы на самом деле не хотите интересоваться коммуникационной стороной, вы просто хотите решить проблему блокировки.
Поэтому мой ответ может показаться немного не по теме, однако я считаю, что вы не сможете решить проблему с блокировкой, если не будете правильно понимать ее детали. Аналогия: строительство дома на плохом фундаменте приводит к его падению ... В конце концов.
источник
Ваш вопрос может быть легко реализован с использованием распределенного кэша, такого как NCache. Вам нужен механизм пессимистической блокировки, где вы можете получить блокировку, используя объект. Затем выполните свои задачи и операции и снимите блокировку для других приложений для последующего использования.
Посмотрите на следующий код;
Здесь вы должны получить блокировку для определенного ключа, а затем выполнить задачи (начиная с одной или нескольких операций) и, наконец, снять блокировку, когда закончите.
Взято по ссылке: http://blogs.alachisoft.com/ncache/distributed-locking/
источник