什么是分布式锁?为什么要用分布式锁?面试必问!

Posted 爱看动漫的Java程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是分布式锁?为什么要用分布式锁?面试必问!相关的知识,希望对你有一定的参考价值。

前言

进程和线程的提出极大的提高了操作提供的性能。进程让操作系统的并发性成为了可能,而线程让进程的内部并发成为了可能。

多进程的方式也可以实现并发,为什么我们要使用多线程?

多进程方式确实可以实现并发,但使用多线程,有以下几个好处:

  • 进程间的通信比较复杂,而线程间的通信比较简单,通常情况下,我们需要使用共享资源,这些资源在线程间的通信比较容易。
  • 进程是重量级的,而线程是轻量级的,故多线程方式的系统开销更小。

由此可见多线程的学习对程序员来说是至关重要的,这也是为什么不论是大大小小的公司面试官都会问到的问题。金九银十即将来临,我特意花了时间搜集了一些相关的资料整理出了这份“Java多线程核心笔记”,我把多线程分为十一个模块进行解读。让我们来看看文档的内容

1、PTP模型

Point-to-Point,点对点通信模型。PTP是基于队列(Queue)的,一个队列可以有多个生产者,和多个消费者。消息服务器按照收到消息的先后顺序,将消息放到队列中。队列中的每一条消息,只能由一个消费者进行消费,消费之后就会从队列中移除。

需要注意的是,尽管这里使用Queue的概念,但并不是先进入队列消息,一定会被先消费。在存在多个下游Consumer情况下,一些消息中间件,例如ActiveMQ,为了提升消费能力,会将队列中的消息分发到不同Consumer并行进行处理。这意味着消息发送的时候可能是有序的,但是在消费的时候,就变成无序了。为了保证消费的有序,一些MQ提供了**"专有消费者”或者"排他消费者”**的概念,在这种情况下,队列中的消息仅允许一个消费者进行消费,如果存在多个消费者,那么从中选择一个。但是,这意味着在消息在处理中没有了并行性。如果消息量很多的情况下,将会产生消息积压。为了解决"专有消费者”的性能问题,一些消息中间件采用分区的概念来解决性能问题,我们将在后文进行介绍。

2、Pub/Sub模型

publish-and- subscribe, 即发布订阅模型。在Pub/Sub模型中,生产者将消息发布到一个主题(Topic)中,订阅了该Topic的所有下游消费者,都可以接收到这条消息。如下图:

通常情况下,一个条消息只要被消费一次就行了,那么什么情况下需要所有的消费者都对这条消息进行消费呢?最典型的情况就是需要在内存中对数据进行缓存,并需要实时进行更新。例如,笔者做过一个违禁词系统,对用户输入的评论内容进行违禁词汇检测。这个违禁词系统,部署了在N台服务器上,为了提升检测性能,每台机器都会将违禁词库全量加载到内存中,词库的更新,是通过发送MQ消息来完成的。由于采用Pub/Sub模型,每台机器的consumer,都可以接收到这条消息,直接在内存中更新敏感词库即可。

3、Partition模型

为了解决在PTP模型下,有序消息需要通过"专有消费者”消费带来的性能问题,一些消息中间件,如rocketmq,kafka采用了Partition模型,即分区模型,如下所示:

生产者发送消息到某个Topic中时,最终选择其中一个Partition进行发送。你可以将Parition模型中的分区,理解为PTP模型的队列,不同的是,PTP模型中的队列存储的是所有的消息,而每个Partition只会存储部分数据。对于消息者,此时多了一个消费者组的概念,Paritition会在同一个消费者组下的消费者中进行分配,每个消费者只消费分配给自己的Paritition。上图演示了不同的消费者可能会分配到不同数量的Paritition。Paritition模式巧妙的将PTP模型和Pub/Sub模型结合在了一起:

对于PTP模型:

一条消息只会由一个消费者进行消费,而Partition模型中每个分区最终也只会有一个消费者进行消费。对于通过"专有消费者"来保证全局消费有序的场景,在Partition模型中,只需保证创建的Topic只有一个Partition即可,这个Paritition最终也只会分配其中一个消费者。另外,在绝大部分场景下,我们没有必要保证全局有序,例如一个订单产生了3条消息,分别是订单创建,订单付款,订单完成。消费时,要按照这个顺序消费才能有意义。但是订单之间是可以并行消费的,例如将订单1产生的3条消息发送到Partiton 1,将订单2产生的3条消息发送到Partition 2,如此便达到了不同订单之间的并行消费。

对于Pub/Sub模型:

一条消息所有的下游消费者都可以进行消费。在Paritition模型中,只需要为每个消费者设置成不同的消费者组即可。然而,过多的消费者组,会给消息中间件运维带来麻烦。所以一些消息中间件,结合了Partition模型和Pub/Sub模型。例如RocketMQ,支持为消费者组设置消费模式,如果是集群模式,就按照上述描述进行消费,如果是广播模式,就按照Pub/Sub模型进行消费。当然,Partition模型也不全是优点,其最大的限制在于Partition数量是固定的(虽然可以调整),且只可以分配给其中一个消费者。当消费者的数量大于Partition数量时,这些多出来的消费者将无法消费到消息。一些消息中间件对此进行了优化,例如rocketmq,支持单个partition的并行消费。即在对单个消费者内,同时启动多个线程,来消费这个Partition中的数据,当然前提是要求消息不是有序的,对于有序的消息,只能使用一个线程按顺序消费这个Partition中的数据。

4、Transfer模型

Paritition模型中的消费者组概念很有用,同一个Topic下的消息可以由多个不同业务方进行消费,只要使用不同的消费者组即可,不同消费者组消费到的位置单独记录,互不影响。 但是,Paritition模型还是限制了消费者数量不能多于分区数。因此,又有了另外一种消费模型,笔者称之为Transfer模型,如下图所示:

生产者还是将消息发送到Topic中,针对一个Topic,可以创建多个通道,这里称之为channel。与分区不同的是,发送到Topic中的每条消息,都会转发到每个channel,因此每个channel都有这个Topic的全量数据。当然,没有必要把真的把消息体完整的拷贝一份到channel中,可以只记录一下消息元数据,表示有一条放到这个channel中了。消费者在消费消息时,必须指定从哪个channel消费。多个消费者消费同一个channel时,每条消息只会有一个消费者消费达到,这一点与PTP模型类似。事实上,我们可以认为,消费了同一个channel的消费者,就自动组成了一个消费者组。但是,与Partition模型不同的是,这里没有分区的概念,因此消费者的数量可以是任意的。事实上,GO语言编写的NSQ消息中间件,采用的就是这种模型。当然,这种模型与PTP一样,也不能保证被消息有序,除非通过类似于”专用消费者”的概念。

总结

就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!

金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。

感兴趣的朋友可以点击这里获得免费领取!

三面蚂蚁核心金融部,Java开发岗(缓存+一致性哈希+分布式)

mxTbFJ1cmN1R2dB)**

[外链图片转存中…(img-kvIbOSQY-1620814941840)]

以上是关于什么是分布式锁?为什么要用分布式锁?面试必问!的主要内容,如果未能解决你的问题,请参考以下文章

面试必问的分布式锁,你懂了吗?

面试必问的分布式锁,你懂了吗?

面试必问:一般实现分布式锁都有哪些方式?

面试只要问到分布式,必问分布式锁

面试只要问到分布式,必问分布式锁

什么是分布式锁?为什么要用分布式锁