【问题标题】:Distributed Lock Manager with Azure SQL database带有 Azure SQL 数据库的分布式锁管理器
【发布时间】:2018-11-28 18:08:54
【问题描述】:

我们有使用 Azure SQL 数据库的 Web API。数据库模型有客户和经理。客户可以添加约会。我们不能允许同一经理的 2 个或更多客户的重叠约会。因为我们在分布式环境中工作(多个Web服务器实例可以同时将记录插入数据库),所以有可能会保存无效的约会。例如,客户 1 想要 10:00 - 10:30 之间的约会。客户 2 想要 10:15 - 10:45 之间的约会。如果两个约会同时发生,那么 Web API 中的验证代码将不会捕获错误。这就是为什么我们需要像分布式锁管理器这样的东西。我们从 Redis 和 Zookeeper 中了解了 Redlock。我的问题是:Redlock 或 Zookeeper 是我们用例的好选择还是有更好的解决方案?

如果我们使用 Redlock,我们会使用 Azure Redis 缓存,因为我们已经使用 Azure Cloud 来托管我们的 Web API。我们计划使用 ManagerId + Date 来识别共享资源(我们要锁定的资源)。这将导致 Manager 在某个日期被锁定,因此可能会在其他日期为同一 Manager 获得其他锁定。我们计划使用一个 Azure Redis 缓存实例,这样够安全吗?

【问题讨论】:

  • 我不会通过锁定整个事情来解决这个问题。这是一个先到先得的场景,对吧?在保留约会之前,请检查约会空档是否仍然可用。如果不是 - 返回 HTTP 409 或其他内容 - 并通知用户找到另一个插槽 - 否则从您的 WebAPI 返回 200。
  • 我们正在使用实体框架 ORM,因此有可能当一个实例检查预约空闲槽并确定它是空闲时,在它将新预约插入数据库之前,另一个 Web 服务实例也确定该预约插槽是空闲的并且还插入约会 = 我们得到约会重叠,所以我们正在尝试解决这个问题
  • 当然我明白你的意思 - 但仍然有办法解决这个问题而无需锁定。例如:使用 WebAPI 将消息放在队列中,并仅使用 1 个工作人员来获取消息,检查重叠并存储在数据库中。解决并发问题的一种方法是消除并发。我是从 Mark Seamann 在 Pluralsight 上的功能架构课程中得到的:pluralsight.com/courses/functional-architecture-fsharp
  • 嘿@JochenvanWylick,我是 Vukasins 的同事之一。您对消息队列的权利可以消除并发性,但这带来了两个问题:您无法扩展工作角色,其次,如果成功创建约会,则需要立即通知用户,这意味着我们有为 UI 创建更复杂的通知系统
  • 是的,确实,这两点都是正确的。这是一个权衡 - 但肯定是可能的。这就是为什么我强烈建议关于复数的课程。一个著名的例子是亚马逊库存系统。如果您同时向 2 位用户展示“还剩 1 件商品” - 并且其中一位购买得更快,那么第二位购买者可能会收到错误消息。但是亚马逊并不会在有人看到该商品时立即停止购买——如果他们的销售量超过库存(这种情况只会发生几次),他们会进行补偿。

标签: azure redis locking apache-zookeeper


【解决方案1】:

Q1:对于我们的用例来说,Redlock 或 Zookeeper 是不错的选择还是有更好的解决方案?

我认为 Redlock 不是您用例的最佳选择,因为:

a) 它的保证是在使用 DB 操作之前设置的特定时间量 (TTL)。如果出于某种原因(与 DevOps 讨论令人难以置信的问题并检查 How to do distributed locking),DB 操作花费的时间比 TTL 长,您就失去了锁有效性的保证(请参阅 official documentation 中的 锁有效性时间) .您可以使用较大的 TTL(分钟),或者您可以尝试使用另一个监视数据库操作时间的线程来扩展其有效性 - 但这变得非常复杂。另一方面,对于 zookeeper (ZK),您的锁一直存在,直到您将其移除或进程终止;这可能是您的数据库操作挂起的情况,这会导致锁也挂起,但这些问题很容易被 DevOps 工具发现,这将杀死挂起的过程,进而释放 ZK 锁(还有选项有一个监控过程,它也可以更快、更具体地为您的业务方式执行此操作)。

b) 在尝试锁定进程时,必须“战斗”以赢得锁定; “战斗”假设他们等待然后重试获得锁。这些可能会导致 retry-count 溢出,从而导致无法获得锁。在我看来,这似乎是一个不太重要的问题,但使用 ZK 的解决方案要好得多:没有“战斗”,但所有进程都会排成一列等待轮到自己获得锁(检查 ZK lock recipe)。

c) Redlock 是基于时间度量的,这非常棘手;至少检查How to do distributed locking 中包含“自鸣得意”的段落(结论 段落),然后再考虑一下 TTL 值应该有多大,以便确定基于 RedLock(时间)的锁定。

出于这些原因,我认为 RedLock 是一个有风险的解决方案,而 Zookeeper 是适合您的用例的一个很好的解决方案。我不知道其他更适合您的情况的分布式锁定解决方案,但确实存在其他分布式锁定解决方案,例如只需检查Apache ZooKeeper vs. etcd3

Q2:我们计划使用一个 Azure Redis Cache 实例,这样够安全吗?

这对您的用例来说可能是安全的,因为 TTL 似乎是可预测的(如果我们真的相信时间测量 - 请参阅下面的警告)但 只有如果从属设备接管失败的主设备可以延迟(不确定是否可能,您应该检查 Redis 配置功能)。如果您在锁与从属同步之前松开主控,那么另一个进程可能会获得相同的锁。 Redlock 建议使用时间至少为 1 TTL 的 延迟重启(检查official documentation 中的性能、崩溃恢复和 fsync)。如果出于 Q1:a+c 的原因,您的 TTL 非常长,而您的系统可能无法锁定很长一段时间(因为您拥有的唯一 1 个 Redis 主服务器必须在 延迟时尚)。

PS:我再次强调阅读 Martin Kleppmann 的 opinion on Redlock,您会发现令人难以置信的延迟数据库操作的原因(搜索在到达存储服务之前)以及令人难以置信的原因锁定时不按时间测量(也是反对使用 Redlock 的一个有趣论点)

【讨论】:

    猜你喜欢
    • 2014-05-27
    • 2022-07-14
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    相关资源
    最近更新 更多