且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Cloud Firestore文档锁定

更新时间:2023-02-14 09:55:30

悲观与乐观

Cloud Firestore中没有本地独占锁定.由于该系统旨在在大型分布式系统(例如1000个手机用户或Kubernetes集群)中运行,因此它基于乐观锁定模式.

Pessimistic vs Optimistic

There is no native exclusive locking in Cloud Firestore. As the system is designed to run in large distributed systems (e.g, 1000's of mobile phone users or a Kubernetes cluster), it is based around optimistic locking patterns.

这意味着当您执行读写事务时,如果在提交该事务之前已写入您阅读的文档,则该事务将失败,因此客户端可以回滚.

This means that when you do a read-write transaction, if the document you read is written to before you can commit the transaction, the transaction will fail so the client can rollback.

我将假设您是从移动SDK入手的,并将在下一节中介绍服务器客户端.

I'm going to assume you're coming in from a mobile SDK to start with, and will address server clients in the next section.

您可以使用单独的文档在此之上构建排他锁.例如,假设您要对集合critical_data中的文档实施排他锁定.

You can build an exclusive lock on top of this by using a separate document. For example, say you want to implement exclusive locking on documents in collection critical_data.

为此,我们将使用名为mutex_critical_data的单独集合,其中的文档是与集合critical_data中具有相同ID的文档互斥的.

For this, we're going to use a separate collection called mutex_critical_data, with the documents inside being mutexes for documents with the same id in collection critical_data.

在访问critical_data中名为doc_id的文档之前,您需要执行写事务以为您设置互斥锁字段owner.我假设您使用的是Firebase身份验证,所以您==用户的身份验证ID auth_id.但是,这可以是唯一标识用户或进程的任何ID.

Before you can access a document called doc_id in critical_data you'll want to perform a write transaction to set the mutex field owner to you. I'll assume you're using Firebase Auth so you == the user's auth id auth_id. This can be any id that uniquely identifies the user or process though.

完成文档后,删除互斥文档,以便其他人可以使用它.

Once you are finished with the document, delete the mutex document so others can use it.

为确保它是排他性的,并且其他人无法窃取它,您需要在安全规则定义中添加一些检查.

To ensure it's exclusive and other people cannot steal it, you'll want to add some checks in your security rules definition.

// In the match section that sets the document id to 'doc_id'
function mutex_exists ()
{
    return exists(/databases/$(database)/documents/mutex_critical_data/$(doc_id));
}

function mutex_owner ()
{
    return get(/databases/$(database)/documents/mutex_critical_data/$(doc_id)).data;
}

function user_owns_mutex () {
    return mutex_owner().owner == request.auth.uid;
}

allow write: if not(mutex_exists()) || user_owns_mutex;

您还可以使用规则来强制执行互斥锁,即通过也拥有互斥锁来对资源进行写操作.

You can also use rules to enforce the mutex as well, by predicating writing to the resource by also owning the mutex.

请记住,安全规则是针对Mobile/Web SDK访问的,而不是用于服务器客户端的.由于服务器客户端被认为是受信任的环境,而不是由规则强制执行排他性逻辑,因此您将需要在互斥锁上的读写事务中进行检查.

Keep in mind that security rules are for Mobile/Web SDK access and aren't used for server clients. As server clients are considered a trusted environment, rather than having the exclusivity logic enforced by rules, you'll want to do the check in the read-write transaction on the mutex.

如果要构建此文件,最后一点是,我强烈建议您研究排他租约而不是排他锁.

Last point if you build this, is I'd highly recommend looking into exclusive leases rather than exclusive locks.

租约就像锁一样,但是如果租约者在设定的时间之前不(或不允许)续约,则租约会自动过期.这意味着,如果客户端不回来(例如,客户端崩溃),那么其他人最终将能够获得租赁,而无需管理员采取任何行动.

A lease is like a lock, but it automatically expires if the leasee doesn't (or isn't allowed) to renew the lease before a set time. This means if the client doesn't come back (e.g, client crashes), someone else will eventually be able to obtain the lease without administrator action.

概念相同,但是您不仅可以设置所有者,还可以在字段中设置租约时间.如果租约的租期大于x的旧租约,其中x是租约的时间长度,则认为所有者不再持有该租约.在租约到期之前,您可以选择设置新的租约时间来允许所有者更新租约.

The concept is the same, but rather than setting just the owner, you also set the lease time in a field. If the lease is greater than x old, where x is the time length of the lease, it is consider to no longer be held by the owner. Before the lease expires, you can optionally allow the owner to renew the lease by setting a new lease time.