【问题标题】:How should I make a clojure STM program persistent?我应该如何使 clojure STM 程序持久化?
【发布时间】:2010-12-23 22:06:33
【问题描述】:

我正在编写一个使用 STM 的 clojure 程序。目前我正在从数据库启动时填充 STM(使用 refs),然后在 dosync 事务成功时异步更新数据库。我不知道我是否以正确的方式执行此操作,或者是否有更好的标准技术来执行此操作。谁能向我解释一下他们是如何在 Clojure 程序中将 STM 的 ACI 属性转换为 ACID 的?

【问题讨论】:

    标签: clojure stm


    【解决方案1】:

    一般来说,将 ACID 中的“D”添加到任何程序都不是一件容易的事,并且取决于程序的要求。在确定实现之前,需要确定一个重要的规范。

    数据库是否存在多线程/多进程访问?

    从问题主体来看,您的程序似乎只在启动时读取并在 STM 更改后写入,其中数据库会滞后 STM 中的值一小段时间。但是,如果数据库被其他程序访问,包括您程序的其他实例,那么您将需要使用锁,在事务之前锁定对数据库的访问,并在写入数据后解锁数据库(作为旁注,请注意,您的数据库可以是任何东西,包括文件系统中的简单文件)。当您有多次读取和写入时,没有办法解决这个问题,因为它们都是涉及数据库的副作用。

    如果没有多重访问,那么异步编写就可以了,因为您的程序在访问时是单线程的,因此可以保证代码始终按顺序工作。

    如果你只有多个写线程,并且只有一个实例启动后没有读,那么你只需要确保正确的写顺序。您可以使用代理来执行此操作,其中代理基本上是对数据库的写入操作队列。您将 dosync 包装在参考事务和代理周围,除了持久性之外,还为您提供持久性。

    一般来说,涉及副作用的要求越复杂,确保 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
    

    【讨论】:

    • 啊,终于有人尝试回答实际问题了,谢谢 :) 没有多进程访问数据库(H2 或 Oracle)。访问数据库的唯一进程是 Clojure 程序本身。
    • 你的程序是多线程读还是多线程写?如果是多线程读取,是不是在启动之后?
    • 启动后,多线程是从持久化存储中读取,还是从内存引用中读取?
    • 好的,那么我建议使用代理就足够了,我将编辑帖子以反映一些代码。
    • 谢谢,用代理保存的有用方法,我猜要确保写入是连续的?
    【解决方案2】:

    您可能对以下内容感兴趣:

    1. Alyssa Kwan 修改后的 Clojure 核心,为 refs 添加了持久性,请参阅: ANN: Durable refs with ACID guarantees - Phase IANN: Durable Clojure - Phase II - Persistent Data StructuresANN: Durable Clojure - Functions and Closures

    2. Sergey Didenko 的库,它没有提供强大的耐用性保证,但非常接近: Simple-Persistence-for-Clojure

    其他方法对程序员来说可能不是那么透明。

    【讨论】:

    • FleetDB 链接转到关于葡萄酒的博客。
    【解决方案3】:

    STM 模型非常适合在系统变化时跟踪对系统的多次访问。它不太适合数据持久性,其中更改需要在访问它们的线程的生命周期之外访问。

    通常最好将 ACID 中的“D”与 STM 分开考虑

    【讨论】:

      【解决方案4】:

      如果您想要一个具有快速内存访问且不时在后台持续存在的数据库,请使用真正的数据存储,而不是尝试构建自己的数据存储,这将是一项艰巨的工作。

      RedisMongoDB 是两个不错的选择,但还有很多其他选择。您可以在 https://github.com/ragnard/redis-clojurehttps://github.com/somnium/congomongo 找到分别用于 Redis 和 Mongo 的 Clojure 库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 2011-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-28
        • 1970-01-01
        相关资源
        最近更新 更多