【问题标题】:What is the pattern for Google Cloud Functions to implement mutexGoogle Cloud Functions 实现互斥锁的模式是什么
【发布时间】:2019-04-14 18:35:21
【问题描述】:

我正在使用 https 触发的 Google Cloud Functions 来处理客户端请求以执行数据库写入。数据的结构方式使得大多数并行写入不会导致损坏。

在少数情况下,我需要防止同一项目同时发生多个写入操作。在功能级别上锁定对某些资源的访问的常见模式是什么。我正在寻找一些“类似互斥锁”的功能。

我在考虑一些外部服务,可以授予或拒绝对资源的访问以请求函数实例,但连接开销会很大 - 每次握手等等。

根据要求添加了一个示例。在这种特定情况下,重组数据以跟踪更新并不是一个合适的解决方案。

import * as admin from "firebase-admin";

function updateUserState(userId: string) {
    // Query current state
    admin
        .database()
        .ref()
        .child(`/users/${userId}/state`)
        .once("value")
        .then(snapshot => {
            return snapshot.val() || 0;
        })
        .then(currentState => 
            // Perform some operation
            modifyStateAsync(currentState)
        )
        .then(newState => {
            admin
                .database()
                .ref()
                .child(`/users/${userId}/state`)
                .set(newState);
        });
}

【问题讨论】:

  • 这听起来像XY problem。如果您显示重现实际问题的最少代码,则更有可能有人可以帮助您解决具体问题。
  • 应要求添加了更具体的示例。
  • 如果要基于现有值写入新值,请使用transaction。除此之外:最后两个 then() 子句不返回任何值,因此如果您在 Cloud Functions 中运行此代码,它无法知道您何时完成对数据库的写入。

标签: google-cloud-platform google-cloud-functions


【解决方案1】:

这不是您希望在 Cloud Functions 中实现的模式。限制 Cloud Functions 的并行性会限制其可扩展性,这与 Cloud Functions 的工作方式背道而驰。要详细了解 Cloud Functions 如何扩展,请watch this video

如果您的数据库需要对并发访问进行一些保护,您应该使用数据库自​​己的事务功能。几乎每个提供数据并发访问的数据库也提供了一些执行原子事务的能力。使用这些事务,让无服务器容器以它认为合适的方式向上和向下扩展。

【讨论】:

  • 我很欣赏重复常见的真理,但请阅读问题。我在第一句话中强调这是一个例外,而不是使用函数/ lambdas 的方式。 Cloud Datastore 或实时数据库不提供执行真实事务的选项,除了操作由读取和写入组成。
  • 实时数据库和 Cloud Firestore 确实提供了适用于 Cloud Functions 的事务。 Cloud Functions 如何扩展的规则也不例外。听起来您的问题实际上可能是关于这些交易,而不是关于 CF。
  • Realtime Database Admin SDK 不提供事务,而且整个操作由读写组成,在此期间底层数据不应该改变。这就是为什么即使使用不同的数据库,它也不是带有事务的任务。
  • 使用外部服务“锁定整个数据库”是一个非常糟糕的主意,并且会对您的应用程序的扩展程度产生影响。
  • 那些不是数据库级别的事务,而是客户端和服务器之间的几次往返(对于客户端,它需要读取权限)。该应用程序存储了许多资源类型,其中 95% 的模型运行良好。我不想“锁定整个数据库”。想象一个代表几个人的日常日历的集合。可以在不同的日子或个人并行操作(读取->处理->写入),但不能在同一天从2个功能并行操作(读取->处理->写入)。如果其他人正在编写相同的资源,我想快速失败一个函数。
【解决方案2】:

在 Google Cloud 中,有一种优雅的方式可以在云函数中为 critical section 提供全局分布的 mutex

gcslock

这是一个用 Go 语言编写的库,因此可用于用 Go 编写的 Cloud Functions,它利用 Google Cloud Storage 服务的原子性保证。由于 S3 服务中缺乏此类保证,因此这种方法在 AWS 中显然不可用。

该工具并非适用于所有用例。获取和释放锁是 10ms 量级的操作,这对于高速处理用例来说可能太多了。

对于时间要求不高的典型批处理过程,该工具提供了非常有趣的选项,可确保您的云函数不会在同一目标资源上同时运行。只需在 GCS 中创建具有唯一名称的锁定文件,该名称对于您想要放入关键部分的操作并在完成后释放它(或依靠 GCS 对象生命周期管理来清理锁定)。

更多注意事项及优缺点请查看原工具GitHub项目。

在 Python 中显然也有一个 implementation

这是一个很好的article,它特别总结了 GCP 上分布式锁定的用例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    相关资源
    最近更新 更多