使用Azure SQL数据库的分布式锁管理器

使用Azure SQL数据库的分布式锁管理器,azure,redis,locking,apache-zookeeper,Azure,Redis,Locking,Apache Zookeeper,我们有使用Azure SQL数据库的Web API。数据库模型有客户和经理。客户可以添加约会。我们不允许两个或更多客户为同一位经理重复预约。因为我们在分布式环境中工作(web服务器的多个实例可以同时将记录插入数据库),所以可能会保存无效的约会。例如,客户1希望在10:00到10:30之间预约。客户2想要在10:15到10:45之间预约。如果两个约会同时发生,那么Web API中的验证代码将不会捕获错误。这就是为什么我们需要分布式锁管理器。我们从Redis和Zookeeper那里了解到了红锁。我的

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


如果我们使用红锁,那么我们将使用Azure Redis缓存,因为我们已经使用Azure云托管我们的Web API。我们计划使用ManagerId+Date标识共享资源(我们要锁定的资源)。这将导致在某个日期为经理锁定,所以在其他日期为同一经理设置其他锁定是可能的。我们计划使用一个Azure Redis缓存实例,这足够安全吗?

Q1:红锁或Zookeeper是我们用例的好选择,还是有更好的解决方案

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

a) 它的保证是在使用DB操作之前设置的特定时间量(TTL)。如果出于某种原因(请与DevOps联系,了解令人难以置信的原因,并进行检查),DB操作所需的时间超过TTL,则您失去了锁定有效性的保证(请参阅中的锁定有效性时间)。您可以使用较大的TTL(分钟),也可以尝试使用另一个线程来扩展其有效性,该线程将监视DB操作时间,但这会变得非常复杂。另一方面,在zookeeper(ZK)的帮助下,你的锁就在那里,直到你把它取下或者这个过程结束;当DB操作挂起时,可能会导致锁也挂起,但DevOps工具很容易发现此类问题,这将终止挂起过程,进而释放ZK锁(还可以选择使用监控流程,该流程可以更快、更具体地针对您的业务进行监控)

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

c) 红锁是基于时间的测量,这是难以置信的棘手;至少检查包含“自鸣得意”的段落(也包括结论段落),然后再次思考TTL值应该有多大,以确保基于红锁(时间)的锁定

由于这些原因,我认为RedLock是一个危险的解决方案,而动物园管理员是一个很好的解决方案。其他更好的分布式锁定解决方案适合您的情况我不知道,但其他分布式锁定解决方案确实存在,例如,只需检查

Q2:我们计划使用一个Azure Redis缓存实例,这足够安全吗

对于您的用例来说,这可能是安全的,因为TTL似乎是可预测的(如果我们真的相信时间测量-请参阅下面的警告),但只有在从机接管发生故障的主机可能会延迟的情况下(如果可能,不确定,您应该检查Redis配置功能)。如果在锁与从属锁同步之前松开了主进程,那么另一个进程可能只会获取相同的锁。Redlock建议使用延迟重启(检查性能、崩溃恢复和fsync in),时间至少为1 TTL。如果出于Q1:a+c的原因,您的TTL非常长,那么您的系统可能无法锁定一段不可接受的长时间(因为您仅有的1台Redis主机必须以延迟方式由从机替换)


PS:我再次强调阅读Martin Kleppmann的文章,你会发现数据库操作延迟的难以置信的原因(在到达存储服务之前搜索),以及锁定时不及时中继的难以置信的原因(还有一个反对使用Redlock的有趣论点)

我无法通过锁定整件事来解决这个问题。这是先到先得的方案,对吗?在保留约会之前,请检查约会时段是否仍然可用。如果没有-返回HTTP 409或其他内容-并通知用户找到另一个插槽-否则从您的WebAPI返回200。我们使用实体框架ORM,因此有可能在一个实例检查无约会插槽并确定其为空闲插槽时,在将新约会插入数据库之前,web服务的另一个实例还确定约会槽是免费的,并且还插入约会=我们得到了约会重叠,所以我们正在尝试解决这个问题确保我明白你的意思-但是仍然有一些方法可以解决这个问题,而不必锁定。例如:使用WebAPI将消息放在队列中,只需使用一个worker来提取消息、检查重叠并存储在数据库中。解决并发问题的一种方法是消除并发。我是从Mark Seamann在Pluralsight上的功能性建筑课程中学到的:嘿@JochenvanWylick,我是Vukasins的同事之一。您对消息队列的看法是,它可以消除并发性,但这带来了两个问题:无法扩展工作人员角色;其次,如果约会成功创建,则需要立即通知用户,这意味着我们必须创建更复杂的