桂人网

找回密码
免费注册

QQ登录

只需一步,快速开始

资迅
资迅
生活
生活
服务
服务
工具
工具
搜索
桂人网 门户 查看主题

聊一聊:面试官:基于数据库实现的分布式锁真的无用吗?

发布者: 无爱一身 | 发布时间: 2019-9-12 12:17| 查看数: 4| 评论数: 0 |帖子模式 |只看大图 |关灯


在单机时代,虽然不需要分布式锁,但也面临过类似的问题,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制,即当某个线程获取到这个资源后,就立即对这个资源进行加锁,当使用完资源之后,再解锁,其它线程就可以接着使用了。例如,在JAVA中,甚至专门提供了一些处理锁机制的一些API(synchronize/Lock等)。分布式数据库相关问题,可以到网站详细了解,更为仔细。  

  但是到了分布式系统的时代,这种线程之间的锁机制,就没作用了,系统可能会有多份并且部署在不同的机器上,这些资源已经不是在线程之间共享了,而是属于进程之间共享的资源。

  因此,为了解决这个问题,我们就必须引入分布式锁。分布式锁是指在分布式的部署环境下,通过锁机制来让多客户端互斥的对共享资源进行访问。

  目前比较常见的分布式锁实现方案有以下几种:

  基于数据库,如MySQL基于缓存,如Redis基于Zookeeper、etcd等

  我们在讨论使用分布式锁的时候往往首先排除掉基于数据库的方案,本能的会觉得这个方案不够“高级”。从性能的角度考虑,基于数据库的方案性能确实不够优异,整体性能对比:缓存 > Zookeeper、etcd > 数据库。也有人提出基于数据库的方案问题很多,不太可靠。笔者认为采用哪种方案是要基于使用场景来看的,选择哪种方案,合适最重要。

  我这里引用一下之前文章中的一个应用场景——分配任务场景。在这个场景中,由于是公司的业务后台系统,主要是用于审核人员的审核工作,并发量并不是很高,而且任务的分配规则设计成了通过审核人员每次主动的请求拉取,然后服务端从任务池中随机的选取任务进行分配。这个场景看到这里你会觉得比较单一,但是实际的分配过程中,由于涉及到了按用户聚类的问题,所以要比我描述的复杂,但是这里为了说明问题,大家可以把问题简单化理解。那么在使用过程中,主要是为了避免同一个任务同时被两个审核人员获取到的问题。在这个场景下使用基于数据库的方案就比较合理。

  再补充一下,比如某一个服务它下游依赖数据库来做一些数据的读写操作,模型如下图所示:

  一般服务也是多实例部署,如果多个实例需要操作同一份数据的时候(比如前面所说的同一个任务同时被两个审核人员获取到的问题),自然而然的引入了分布式锁。不过此时,我们并没有采用数据库的方案,而是引入了Redis,模型如下图所示:

  引入Redis之后,正向的收益我就不赘述了,反向的收益是增加了系统的复杂度,对于整个服务而言,还需要多考虑1和2失效的情况。1失效是指服务模块与Redis的交互出现了异常,这种异常不单是指无法通信的异常,也有可能是服务模块发送请求只Redis的过程中或者Redis响应服务模块的过程中出现的异常,整体服务需要考虑这种情况:是重试、丢弃还是采取其他措施;2失效是指Redis本身出现了异常。数据链路一旦变长,系统复杂度一旦变大,在出现问题的时候会阻碍故障排查以及服务恢复,从而使得服务的整体可用性下调。

  反观,如果采用数据库的方案,那么就可以省去了这部分的复杂度,如果数据库的方案能满足当下场景以及可视范围内的未来扩展,为什么还要平白地增加系统复杂度呢?大家要根据具体业务场景选择合适的技术方案

最新评论

关闭

最新推荐上一条 /1 下一条

发布主题 上个主题 下个主题 快速回复 返回列表 联系我们 官方QQ群