`
deepinmind
  • 浏览: 451315 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41606
社区版块
存档分类
最新评论

你可能并不需要消息队列

MQ 
阅读更多
我是一个极简主义者,我不喜欢过早或者没必要地让软件复杂化。而往软件系统中添加组件就是严重增加复杂性的一种做法。我们来拿消息队列举个例子。

消息队列是一个能让你获得容错性,分布式,解耦等架构能力的系统。纸上谈兵的话,它看起来还不错。

或许消息列队在你的应用中有不少适用的场景。你可以看下这篇关于消息队列优点的文章,看看到底有哪些合适的场景。但可不要因为说"能解耦那太好了”就轻易使用它。我们来看一个例子——你希望你的邮件发送和订单处理互相解耦。因此你发送一个消息到消息队列里,然后邮件处理系统取出这个消息并发送邮件。那你在一个独立的单classpath的应用中怎么实现呢?让你的订单处理服务依赖于一个邮件服务,然后调用sendEmail()方法,而不是sendToMQ()方法。如果你使用了消息队列,你需要定义一个两个系统都能识别的消息格式 ;如果你不使用消息队列,那么你得定义一个方法签名。它们有什么本质的区别吗?其实没有。

不过你可能还有别的消费者想要对某个指定的消息进行额外的处理?这的确是可能发生的,而并不只是针对我们这里说到的这个项目而已。尽管确有可能,但相比添加另一个方法调用而言,它可能并不值当。耦合?是的。不过这个耦合并没有什么不方便的。

那我应该如何处理峰值流量?你可以通过消息队列将请求放到一个持久化队列中,然后再一并处理它们。这是一个非常有用的特性,不过它也受限于几个 因素——你的请求是在UI后台处理,还是需要即时响应?serlvet容器的线程池某种程度上可以当作是一个队列,用户最终会拿到响应,但是得需要等待(如果线程的超时时间过短的话,请求可能会丢失)。你可以使用一个内存队列来存储那些较重的请求(得在UI后台进行处理)。不过注意了,你的队列并不是默认高可用的。比如说,如果一个消息队列节点挂掉了,你的消息就丢失了。因此,不去使用应用节点内的内存队列,而是去使用一个消息队列,这可能并没有什么优势。

消息队列使得我们可以进行异步处理——这的确是个有用的特性。你不希望在用户等待的时候做一些很重的操作。不过你也可以使用一个内存队列,或者简单地启动一个新的线程(比如Spring的@Async注解)。这样又有另一个问题——如果消息丢失的话是否有问题?如果你应用处理请求的节点挂了,你可以进行恢复吗?你会发现这事会经常发生,如果不保证所有消息都处理到的话,很难保证功能的正确性。因此,仅将较重的调用进行异步处理是比较可取的。

把消息放到队列以便让另一个组件来进行处理,对于这个场景,如果消息丢失是无法接受的 ,这也有一个很简单的解决方案——数据库。你可以把一条processed=false的数据存储到数据库中。然后再运行一个调度作业,将所有未处理的记录挑选出来,异步地进行处理。当处理完成的时候,将标记设为true。我经常用这个方法,包括在一些大型的线上系统中,它也工作得挺好的。

这样你还能不断地对你的应用节点进行扩展,只要它们的内存中没有任何的持久化状态的话。不管你是否使用了消息队列都可以(临时的内存处理队列并不属于持久化状态)。

为什么我要给经常用到的消息队列提供一些备选方案?因为如果你由于不恰当的原因选择了它,那么消息队列可能会成为一个负担。它们并非如想像中那样容易使用。首先,它有一个学习曲线。一般来说,你集成的组件切分得越多,就越容易出现问题。其次,还有一个设置及配置的成本。比如说,当消息队列需要在一个集群中运行的话,比如说多个数据中心,那么这就变得复杂了。高可用性并不是上来就有的——默认它是不会打开的。还有就是你的应用节点如何连接到消息队列?通过一个刷新的连接池,或者使用短生命周期的DNS记录,还是通过一个负载均衡器?你的队列可能还有许多配置项,大小是多少,行为是怎样的(消费者需不需要确认接受,要不要通知处理失败,多个消费者能够取到同一个消息吗,消息有没有TTL,等等)同时还有网络及消息传递的开销,尤其是现在大家都喜欢用XML或者JSON来传输消息。如果你过度地使用了消息队列,那么它会增加你系统的延时。最后一点,但并不是最次要的——如果出现问题的话,使用消息队列会让问题跟踪变得异常困难。你没法在IDE中看到所谓的调用层次,因为一旦你发送消息到队列里了,你就得自己去查找它在哪里处理的了。这可不是听起来那么简单的。你看到了吧,它会给你增加许多的复杂性,以及许多需要注意的东西。


通常而言,在某些上下文中,消息队列还是非常有用的。当它们的确适合的话,我也会在项目中使用它们——比方说,我们不想丢失消息,但又希望能快速地进行处理。我也见过它在一些不太常见的场景中使用的情况,比如说只有一个应用节点来进行消费,不管是哪个节点投递过来的消息。你还可以看下stackoverflow上的这个问题。还有一些使用场景就是,或许你的确需要进行多语言间的通信,又或者你的数据流已经过于复杂了,不使用新的消息消费者而是增加新方法调用的话代价会很大。

我想说的是那句老掉牙的真理“杀鸡焉用牛刀”。如果你不是很确定已经没有别的更容易管理和维护的方法,一定要使用消息队列的话,最好不要使用它。不要因为”万一它有用呢“而去用它——只有你确实觉得需要的话再去使用。因为很有可能,就像这里说到的这个项目一样,消息队列其实是没有必要的。


原创文章转载请注明出处:http://it.deepinmind.com


英文原文链接
2
0
分享到:
评论
3 楼 xugangqiang 2014-07-08  
KISS - keep it simple & stupid
2 楼 lvwenwen 2014-07-08  
有列子更好
1 楼 liubey 2014-07-08  
不错不错

相关推荐

    C++ 跨平台 异步消息队列

    这些同步机制确保了在多个线程同时访问消息队列时,能正确地进行读写操作,防止数据不一致和竞争状态。 "SyncQueue.h"可能是异步消息队列的头文件,定义了队列的数据结构以及相关的接口。队列通常采用先进先出...

    C# winform可忽略消息的自定义消息队列

    标题中的“C# Winform可忽略消息的自定义消息队列”指的是创建一个特定的机制,允许在WinForm应用中,对控件事件产生的消息进行管理和筛选,确保只有最终需要的消息才会被执行,从而提高程序的响应速度和流畅性。...

    基于网络编程中的消息队列

    消息队列是网络编程中的一种进程间通信(IPC,...在实际的网络编程应用中,消息队列可以用于协调多线程、多进程间的任务,实现异步处理,或者提供一种可靠的通信机制,特别是在需要消息顺序保证或消息持久化的场景下。

    消息队列——message

    在Linux系统中,消息队列是一种可靠的存储数据的方式,它允许进程将数据结构作为消息发送,并在合适的时候由其他进程接收。这种通信方式比传统的管道、共享内存或者信号量更灵活,因为它提供了数据的结构化存储和...

    queue_C语言消息队列_

    3. **消息获取**(出队):接收进程从队列头部取出消息,检查队列是否为空,不为空则删除队头消息并更新队头指针。 4. **错误处理**:处理可能出现的内存溢出、空队列等情况。 在实时消息共享和传输中,消息队列...

    用消息队列实现的简单聊天程序

    客户端发送的消息会被放入消息队列,服务器端从队列中取出并处理这些消息,然后可能向客户端发送响应。 5. **异步通信**:使用消息队列,客户端可以立即返回,无需等待服务器响应,提高了用户体验。服务器也可以...

    消息队列的简单示范

    这些代码可能分为生产者和消费者两部分,生产者向消息队列写入消息,而消费者读取并处理这些消息。通过这些实例,你可以学习如何使用C语言或其他编程语言与这些消息队列接口交互。 学习消息队列的关键在于理解它的...

    消息队列 入门实例

    消费者则需要监听对应的队列,接收到消息后解码并展示给用户。为了保证实时性,我们可以使用发布/订阅模型,让消费者订阅特定的聊天主题,这样当有新消息时,所有订阅该主题的用户都能立即收到通知。 通过这个聊天...

    xxjyjy5.rar_LINUX消息队列_linux 消息队列_linux 消息_linux 消息队列_消息队列

    3. 同步问题:如果多个进程同时尝试访问一个消息队列,可能需要额外的同步机制,如互斥锁。 综上所述,Linux消息队列是进程间通信的一种强大工具,尤其适用于需要有序通信和数据持久化的场景。在实际应用中,开发者...

    易语言消息队列

    你需要指定消息队列的大小,以及是否允许消息在队列满时被丢弃。 3. 发送消息: 使用`PostMessage`或`SendMessage`函数将消息放入消息队列。`PostMessage`是非阻塞的,即发送消息后立即返回,不等待接收方处理;而...

    消息队列,消息队列的使用场景,C,C++

    - 创建消息队列:使用`xQueueCreate()`函数创建一个消息队列,并指定队列长度和每个消息的大小。 - 发送消息:使用`xQueueSend()`或`xQueueSendToFront()`将消息添加到队列,如果队列已满,可以设置超时时间或选择...

    PB消息队列聊天源码

    4. 一致性与可靠性:为了保证消息不丢失,消息队列通常会实现事务机制、确认机制或者消息重试策略。例如,使用“发布/订阅”模型时,消息可能会被持久化存储,直到所有订阅者都确认收到。 5. 安全性:在实际应用中...

    消息队列.zip

    "apache-activemq-5.15.8-bin.zip"则是ActiveMQ的具体版本,包含可执行文件和配置文件,用户可以下载后部署并配置自己的消息队列服务。 "JMS.txt"文件很可能包含了Java Message Service的详细信息。JMS是Java平台上...

    消息队列,消息队列的使用场景,C,C++源码.zip

    3. **负载均衡**:多个消费者可以从消息队列中取出任务并并行处理,提高处理能力,特别是在高峰期。 4. **容错机制**:如果消息队列支持持久化,即使某个服务出现故障,待其恢复后仍能处理之前未完成的消息。 5. *...

    FreeRTOS PPT_消息队列

    消息队列就是通过RTOS 内核提供的服务,任务或中断服务子程序可以将一个消息(注意,FreeRTOS 消息队列传递的是实际数据,并不是数据地址,RTX,uCOS-II 和 uCOS-III 是传递的地址)放入到队列。

    windows消息队列应用

    在实现局域网内的消息传递时,我们可以创建自定义的消息类型,并使用网络通信技术,如TCP/IP或UDP,将这些消息发送到其他机器上,接收端再将接收到的消息插入到自己的消息队列中。 三、局域网消息传递 1. **消息...

    Java消息队列的简单实现代码

    同时,由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。 在实际应用中,消息队列的使用场景非常广泛,例如在用户注册时,服务端收到用户的注册...

    windows消息队列基本操作实例

    Windows消息队列(Message Queuing,简称MSMQ)是微软提供的一种异步通信技术,它允许应用程序在不直接连接的情况下交换消息。这种技术特别适用于网络环境不稳定或应用程序间需要进行延迟处理的情况。在这个实例中,...

    Linux消息队列分析及应用

    若不存在,则创建一个新的消息队列并返回其标识符。这一操作主要由sys_msgget执行。 2. **msgsnd**:用于向消息队列发送消息。消息发送者通过此函数将消息插入队列,具体执行由sys_msgsnd完成。 3. **msgrcv**:从...

Global site tag (gtag.js) - Google Analytics