Я пишу программу clojure, которая использует STM. На данный момент я заполняю STM (используя ссылки) при запуске из базы данных, а затем асинхронно обновляю базу данных всякий раз, когда транзакция dosync завершается успешно. Я понятия не имею, делаю ли я это правильно, или есть лучшая стандартная техника для этого. Может ли кто-нибудь объяснить мне, как они превращают свойства ACI STM в ACID в своих программах Clojure?
Как мне сделать программу clojure STM постоянной?
Ответы (4)
В общем, добавление 'D' в ACID к любой программе не является тривиальным и зависит от требований программы. Прежде чем определить реализацию, необходимо определить одну важную спецификацию.
Предусмотрен ли многопоточный/многопроцессный доступ к базе данных?
Из тела вопроса ваша программа читает только при запуске и записывает после изменения в STM, где база данных будет отставать от значений в STM на некоторое небольшое время. Однако, если к базе данных обращаются другие программы, включая другие экземпляры вашей программы, вам нужно будет использовать блокировки, при которых вы блокируете доступ к базе данных непосредственно перед транзакциями и разблокируете после записи в базу данных. база данных (в качестве примечания обратите внимание, что база данных в вашем случае может быть чем угодно, включая простой файл в файловой системе). Нет никакого способа обойти это, когда у вас есть несколько операций чтения и записи, потому что оба они являются побочными эффектами, связанными с базой данных.
Если нет множественного доступа, тогда асинхронная запись подойдет, потому что код гарантированно всегда будет работать правильно, поскольку ваша программа является однопоточной, когда приходит доступ.
Если у вас есть только несколько потоков записи и нет чтения после запуска только с одним экземпляром, вам нужно только обеспечить правильный порядок записи. Вы можете сделать это с помощью агентов, где агент в основном представляет собой очередь операций записи в базу данных. Вы оборачиваете досинхронизацию вокруг эталонных транзакций и агента, обеспечивая надежность в дополнение к сохранению.
В общем, чем сложнее требования, связанные с побочными эффектами, тем больше трюков вам придется делать, чтобы обеспечить ACID. Если у вас есть дополнительные требования, возможно, придется изменить приведенные мной реализации.
ИЗМЕНИТЬ:
(def db-agent (agent dummy-value))
(defn db-write [_ data] ;; make this intelligent to handle when db is not up
(try
(write-to-db data)
(catch ... database fails, do a retry or let user know of problem))
_)
;; in the transaction code
(dosync
(alter my-ref ...)
(send-off db-agent db-write @my-ref)) ;; ensure db gets written to
Вам может быть интересно:
Модифицированное ядро Clojure Алиссы Кван, добавляющее постоянство ссылкам, см.: ANN: Надежные ссылки с гарантиями ACID – этап I, ANN: Durable Clojure — этап II — постоянные структуры данных, ANN: Durable Clojure — функции и замыкания
Библиотека Сергея Диденко, которая не дает сильной гарантии долговечности, но весьма близка к ней: Simple- Постоянство для Clojure
Другие подходы могут быть не столь прозрачны для программиста.
Модель STM очень хорошо подходит для отслеживания множественного доступа к системам по мере их изменения. Он меньше подходит для сохранения данных, когда изменения должны быть доступны после завершения жизни потоков, которые к ним обращаются.
Обычно хорошо думать о 'D' в ACID отдельно от STM.
Если вам нужна база данных, которая имеет быстрый доступ в памяти и время от времени сохраняется за кулисами, тогда используйте реальное хранилище данных, а не пытайтесь создать свое собственное, что было бы довольно большой работой.
Redis и MongoDB — два хороших варианта, но есть и много других. Вы можете найти библиотеки Clojure по адресу https://github.com/ragnard/redis-clojure и https://github.com/somnium/congomongo для Redis и Mongo соответственно.