【java】消息队列

来源:互联网 发布:铁路 知乎 编辑:程序博客网 时间:2024/05/20 11:24
    在上一篇博客中,介绍了事件在项目中的应用,在自定义事件中,往往会将事件和消息队列一同使用,本篇博客就来了解消息队列。
    一.为什么使用消息队列
    当我在项目中看到了消息队列的使用,我并不明白为什么要使用它。也许如果你知道了下面对消息队列的概述,也知道答案。因为我对消息队列的接触等于0,所以就先查了查,简单地说:
    在高并发环境下,由于来不及同步处理,请求往往会发生堵塞(主要原因),比如说,大量的insert,update之类的请求同时到达mysql,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。
    二.消息队列概述
    消息队列(Message Queue):把消息按照产生的次序加入队列,而由另外的处理程序/模块将其从队列中取出,并加以处理;从而形成了一个基本的消息队列。
    使用消息队列可以很好地将任务以异步的方式进行处理,或者进行数据传送和存储等。例如,当你频繁地向数据库中插入数据、频繁地向搜索引擎提交数据,就可采取消息队列来异步插入。另外,还可以将较慢/较复杂的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理。  
    目前在生产环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。
    三.消息队列应用场景
    消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。
    【异步消息】
    场景说明:在用户注册后,会发生一系列的动作,如给用户发送短信、邮件、给用户的账户增加积分等等。传统的做法有串行和并行两种。
    (1)串行方式:每一个动作都是在上一个动作完成的基础上发生的,等到所有的动作完成后,才返回给客户端。可想,时间长,性能低,在高并发的情况下,很容易造成阻塞。
    (2)并行方式:动作与动作发生不再是一个接一个,而是同时进行,最后返回给客户端。这样,时间上减少了,性能也有了一定的提高。
    下面是两种方式的示意图:
    以上两种方式面对高并发的情况下,显然都是不行的。如何解决这个问题?
    引入消息队列,将不是必须的业务逻辑,异步处理。改造后的示意图:
    按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。发送短信,获得积分写入消息队列后,直接返回,因写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。 
    【应用解耦】
    场景说明:用户注册后,会员系统需要调用积分系统。传统的做法是会员系统调用积分系统的接口。如下图:
    传统模式的缺点:
    (1)如果积分系统无法访问,那么用户注册失败,从而导致无法注册。
    (2)会员系统与积分系统耦合。
    如何解决上面的问题?引入消息队列,示意图如下:
    会员系统:用户注册后,会员系统完成持久化处理,将消息写入消息队列,返回用户注册成功。
    积分系统:订阅注册的消息,采用拉/推的方式,积分系统根据注册结果,进行积分操作。
    假如:在用户注册时积分系统不能正常使用。也不影响用户注册,因为注册后,会员系统写入消息队列就不再关心其他的后续操作了。实现会员系统与积分系统的应用解耦。
    四.JMS消息服务
    JMS在J2EE十三个规范中有过接触。之前学习的时候,并没有很看重这个规范,到现在,才发现原来它属于个重头戏啊。
    JMS(Java Message Service,Java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
    【消息模型】
    在JMS标准中,有两种消息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。
    1. 点对点
    P2P模式包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
    特点:
    (1)每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
    (2)发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
    (3)接收者在成功接收消息之后需向队列应答成功
    如果希望发送的每个消息都会被成功处理的话,便可采用P2P模式。
    2. 发布订阅
    包含三个角色主题(Topic),发布者(Publisher),订阅者(Subscriber) 。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
    特点:
    (1)每个消息可以有多个消费者
    (2)发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。
    (3)为了消费消息,订阅者必须保持运行的状态。
    如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。
    【消息消费】
    在JMS中,消息的产生和消费都是异步的。对于消费来说,JMS的消息者可以通过两种方式来消费消息。 
    (1)同步 
    订阅者或接收者通过receive方法来接收消息,receive方法在接收到消息之前(或超时之前)将一直阻塞;
    (2)异步 
    订阅者或接收者可以注册为一个消息监听器。当消息到达之后,系统自动调用监听器的onMessage方法。
   五.常用消息队列
    下面就详细介绍两个在项目中见到的详细队列:ActiveMQ/Kafka
    【ActiveMQ】
    ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
     ActiveMQ特性如下: 
    ⒈ 多种语言和协议编写客户端。语言: Java,C,C++,C#,Ruby,Perl,Python,PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
 
    ⒉ 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
 
    ⒊ 对spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
 
    ⒋ 通过了常见J2EE服务器(如 Geronimo,JBoss 4,GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
 
    ⒌ 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
 
    ⒍ 支持通过JDBC和journal提供高速的消息持久化
 
    ⒎ 从设计上保证了高性能的集群,客户端-服务器,点对点
 
    ⒏ 支持Ajax
 
    ⒐ 支持与Axis的整合
 
    ⒑ 可以很容易得调用内嵌JMS provider,进行测试
    【kafka】
    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。
 
    Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性
    1.通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。(文件追加的方式写入数据,过期的数据定期删除)
    2.高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息。
    3.支持通过Kafka服务器和消费机集群来分区消息。
    4.支持Hadoop并行数据加载。 

    Kafka相关概念 
    1.Broker
        Kafka集群包含一个或多个服务器,这种服务器被称为broker[5]
    2.Topic
        每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
    3.Partition
        Parition是物理上的概念,每个Topic包含一个或多个Partition.
    4.Producer
        负责发布消息到Kafka broker
    5.Consumer
        消息消费者,向Kafka broker读取消息的客户端。
    6.Consumer Group
        每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。
    【总结】
    通过一次特别不情愿地接受别人负责过的代码,一次没有写过事件的茫然,让我在完成代码的接触上,又get到了如此丰富的知识。
    很满足,此次电商项目的背后,真的隐藏着很多宝藏,还会继续挖掘下去。
0 1
原创粉丝点击