我们有使用 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 云来托管我们的 Web API。我们计划使用 ManagerId + Date 来标识共享资源(我们要锁定的资源)。这将导致经理在某个日期被锁定,因此可能在其他日期对同一经理有其他锁定。我们计划使用一个 Azure Redis 缓存实例,这足够安全吗?
最佳答案
问题1:Redlock 或 Zookeeper 是否适合我们的用例,或者有更好的解决方案吗?
我认为 Redlock 不是您用例的最佳选择,因为:
a) 它的保证是在使用数据库操作之前设置的特定时间量 (TTL)。如果由于某种原因(与 DevOps 讨论令人难以置信的问题并检查 How to do distributed locking ),数据库操作花费的时间超过 TTL,您将失去锁有效性的保证(请参阅 official documentation 中的锁有效性时间) 。您可以使用较大的 TTL(分钟),或者您可以尝试使用另一个监视数据库操作时间的线程来扩展其有效性 - 但这会变得非常复杂。另一方面,对于 Zookeeper (ZK),你的锁会一直存在,直到你将其移除或进程终止为止;这可能是当你的数据库操作挂起时导致锁也挂起的情况,但这些问题很容易被 DevOps 工具发现,这将终止挂起进程,从而释放 ZK 锁(也可以选择有一个监控流程,可以更快、更针对您的业务方式执行此操作)。
b) 在尝试锁定时,进程必须“战斗”以赢得锁定; “战斗”假设他们等待然后重试获取锁。这些可能会导致重试计数溢出,从而导致无法获取锁。在我看来,这似乎是一个不太重要的问题,但使用 ZK,解决方案要好得多:没有“战斗”,但所有进程都会排队等待轮到获得锁(检查 ZK lock recipe )。
c) Redlock 基于时间测量,这非常棘手;至少检查 How to do distributed locking 中包含“自鸣得意”的段落(结论段落也是如此)然后再次考虑 TTL 值应该有多大才能确定基于 RedLock(时间)的锁定。
出于这些原因,我认为 RedLock 是一个有风险的解决方案,而 Zookeeper 是适合您的用例的良好解决方案。其他更好的分布式锁定解决方案适合您的情况我不知道,但其他分布式锁定解决方案确实存在,例如只需检查 Apache ZooKeeper vs. etcd3 .
问题2:我们计划使用一个Azure Redis缓存实例,这足够安全吗?
这对于您的用例来说可能是安全的,因为 TTL 似乎是可预测的(如果我们真的相信时间测量 - 请参阅下面的警告),但仅如果从机接管故障的主机可以被延迟(不确定是否可能,您应该检查Redis配置功能)。如果您在锁同步到从属设备之前松开主设备,则另一个进程可能会获取相同的锁。 Redlock 建议使用延迟重启(检查 official documentation 中的性能、崩溃恢复和 fsync),周期至少为 1 TTL。如果出于 Q1:a+c 的原因,您的 TTL 非常长,那么您的系统将无法锁定一段可能 Not Acceptable 较长时间(因为您拥有的唯一 1 个 Redis 主服务器必须在 < em>延迟时尚)。
PS:我再次强调阅读 Martin Kleppmann 的 opinion on Redlock您会发现数据库操作延迟的令人难以置信的原因(在到达存储服务之前搜索),以及在锁定时不中继时间测量的令人难以置信的原因(以及反对使用的有趣论据)雷德洛克)
关于azure - 具有 Azure SQL 数据库的分布式锁管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36549656/