美文网首页web后端JavaMQ
ActiveMQ从入门到精通(一)

ActiveMQ从入门到精通(一)

作者: 张丰哲 | 来源:发表于2017-03-11 21:40 被阅读32633次

    这是关于消息中间件ActiveMQ的一个系列专题文章,将涵盖JMS、ActiveMQ的初步入门及API详细使用、两种经典的消息模式(PTP and Pub/Sub)、与Spring整合、ActiveMQ集群、监控与配置优化等。话不多说,我们来一起瞧一瞧!

    JMS

    首先来说较早以前,也就是没有JMS的那个时候,很多应用系统存在一些缺陷:

    1.通信的同步性

    client端发起调用后,必须等待server处理完成并返回结果后才能继续执行

    2.client 和 server 的生命周期耦合太高

    client进程和server服务进程都必须可用,如果server出现问题或者网络故障,那么client端会收到异常

    3.点对点通信

    client端的一次调用只能发送给某一个单独的服务对象,无法一对多

    JMS,即Java Message Service,通过面向消息中间件(MOM:Message Oriented Middleware)的方式很好的解决了上面的问题。大致的过程是这样的:发送者把消息发送给消息服务器,消息服务器将消息存放在若干队列/主题中,在合适的时候,消息服务器会将消息转发给接受者。在这个过程中,发送和接受是异步的,也就是发送无需等待,而且发送者和接受者的生命周期也没有必然关系;在pub/sub模式下,也可以完成一对多的通信,即让一个消息有多个接受者。

    JMS

    需要注意的是,JMS只是定义了Java访问消息中间件的接口,其实就是在包javax.jms中,你会发现这个包下除了异常定义,其他都是interface。我们可以扫一眼,比如Message:

    Message接口

    我想你应该发现了,JMS只给出接口,然后由具体的中间件去实现,比如ActiveMQ就是实现了JMS的一种Provider,还有阿里巴巴的RocketMQ(后续专题中在为大家介绍)。这些消息中间件都符合JMS规范。说起规范,自然要定义一些术语:

    Provider/MessageProvider:生产者

    Consumer/MessageConsumer:消费者

    PTP:Point To Point,点对点通信消息模型

    Pub/Sub:Publish/Subscribe,发布订阅消息模型

    Queue:队列,目标类型之一,和PTP结合

    Topic:主题,目标类型之一,和Pub/Sub结合

    ConnectionFactory:连接工厂,JMS用它创建连接

    Connnection:JMS Client到JMS Provider的连接

    Destination:消息目的地,由Session创建

    Session:会话,由Connection创建,实质上就是发送、接受消息的一个线程,因此生产者、消费者都是Session创建的

    初步来看,Session非常核心,因为很多东西都是它创建的,在后文中可以通过代码来进一步认识这些术语。


    ActiveMQ QuickStart

    ActiveMQ是Apache出品的,非常流行的消息中间件,可以说要掌握消息中间件,需要从ActiveMQ开始,要掌握更加强大的RocketMQ,也需要ActiveMQ的基础,因此我们来搞定它吧。官网地址:http://activemq.apache.org/,目前最新的版本是5.14.4,我这边将以最新版来讲解。这篇文章主要是ActiveMQ的初步,因此我这边暂时用windows版本,后期采用Linux。

    ActiveMQ目录结构

    bin下面存放的是ActiveMQ的启动脚本activemq.bat,注意分32、64位

    conf里面是配置文件,重点关注的是activemq.xml、jetty.xml、jetty-realm.properties。在登录ActiveMQ Web控制台需要用户名、密码信息;在JMS CLIENT和ActiveMQ进行何种协议的连接、端口是什么等这些信息都在上面的配置文件中可以体现。

    data目录下是ActiveMQ进行消息持久化存放的地方,默认采用的是kahadb,当然我们可以采用leveldb,或者采用JDBC存储到MySQL,或者干脆不使用持久化机制。

    webapps,注意ActiveMQ自带Jetty提供Web管控台

    lib中ActiveMQ为我们提供了分功能的JAR包,当然也提供了activemq-all-5.14.4.jar

    在JDK安装没有问题的情况下,直接activemq.bat启动它,并访问Web控制台!

    ActiveMQ Start

    到这里,ActiveMQ就已经启动了,So easy~ 

    访问ActiveMQ web控制台的用户名、密码在哪里配置的?URL当中的端口是在哪里配置的?

    username/pwd 4 access web  port 4 web console


    Write Code 4 ActiveMQ

    来一个HelloWorld级别的例子,来感受下ActiveMQ。具体来说,我这边会写一个生产者用于发送消息,一个消费者用于接收消息。实际上,JMS是有“套路”的,下面我将以生产者为例详细说明。

    第一步:创建ConnectionFactory连接工厂

    ConnectionFactory

    实际上,这里是存在安全隐患的,也就是任何人一旦知道MQ的地址,就可以连接访问了,我们可以在activemq.xml中配置指定的用户、密码才能访问ActiveMQ。

    关于broker_bind_url,默认就是tcp://localhost:61616,说明是采用TCP协议,61616端口。其实对于ActiveMQ不仅仅支持TCP协议,还有其他协议,开启了多个端口。

    第二步:创建Connection

    Connection

    Connection就代表了应用程序和消息服务器之间的通信链路。获得了连接工厂后,就可以创建Connection。

    事实上,ConnectionFactory存在重载方法:

    Connection createConnection(String username,String password) 

    也就是说我们也可以在这里指定用户名、密码进行验证

    第三步:创建Session

    Session

    Session,用于发送和接受消息,而且是单线程的,支持事务的。如果Session开启事务支持,那么Session将保存一组信息,要么commit到MQ,要么回滚这些消息。Session可以创建MessageProducer/MessageConsumer。

    第四步:创建Destination

    Destination

    所谓消息目标,就是消息发送和接受的地点,要么queue,要么topic。

    第五步:创建MessageProducer

    MessageProducer

    第六步:设置持久化方式

    持久化方式设置

    第七步:定义消息对象,并发送

    Message

    生产者和消费者之间传递的对象,由3个主要部分构成:

    消息头(路由)+消息属性(消息选择器,以后介绍)+消息体(JMS规范的5种类型消息)

    消息类型

    第八步:释放连接

    release resource

    必须close connection,只有这样ActiveMQ才会释放资源!

    消费者的代码和上面非常类似,只不过就是创建MessageConsumer进行receive而已,注意receive()/receive(long)/receiveNoWait(),这些说明消费者可以采用阻塞模式、非阻塞模式接受消息。

    程序运行后,我们来看一下管控台:

    ActiveMQ Web Info

    Messages Enqueued:表示生产了多少条消息,记做P

    Messages Dequeued:表示消费了多少条消息,记做C

    Number Of Consumers:表示在该队列上还有多少消费者在等待接受消息

    Number Of Pending Messages:表示还有多少条消息没有被消费,实际上是表示消息的积压程度,就是P-C


    在说说Session

    在通过Connection创建Session的时候,需要设置2个参数,一个是否支持事务,另一个是签收的模式。我们重点说一下签收模式:

    签收模式

    什么是签收?通俗点说,就是消费者接受到消息后,需要告诉消息服务器,我收到消息了。当消息服务器收到回执后,本条消息将失效。因此签收将对PTP模式产生很大影响。如果消费者收到消息后,并不签收,那么本条消息继续有效,很可能会被其他消费者消费掉!

    AUTO_ACKNOWLEDGE:表示在消费者receive消息的时候自动的签收

    CLIENT_ACKNOWLEDGE:表示消费者receive消息后必须手动的调用acknowledge()方法进行签收

    DUPS_OK_ACKNOWLEDGE:签不签收无所谓了,只要消费者能够容忍重复的消息接受,当然这样会降低Session的开销

    在实际中,我们应该采用哪种签收模式呢?CLIENT_ACKNOWLEDGE,采用手动的方式较自动的方式可能更好些,因为接收到了消息,并不意味着成功的处理了消息,假设我们采用手动签收的方式,只有在消息成功处理的前提下才进行签收,那么只要消息处理失败,那么消息还有效,仍然会继续消费,直至成功处理!


    关于消息的priority/ttl/deliveryMode

    消息有优先级及存活时间,在MessageProducer进行send的时候,存在多个重载方法,我们来看一下:

    send

    在上面的code当中,我们创建生产者的时候,指定了Destination,设置了持久化方式,实际上这些都可以不必指定的,而是到send的时候指定。而且在实际业务开发中,往往根据各种判断,来决定将这条消息发往哪个Queue,因此往往不会在MessageProducer创建的时候指定Destination。

    TTL,消息的存活时间,一句话:生产者生产了消息,如果消费者不来消费,那么这条消息保持多久的有效期

    priority,消息优先级,0-9。0-4是普通消息,5-9是加急消息,消息默认级别是4。注意,消息优先级只是一个理论上的概念,并不能绝对保证优先级高的消息一定被消费者优先消费!也就是说ActiveMQ并不能保证消费的顺序性!

    deliveryMode,如果不指定,默认是持久化的消息。如果可以容忍消息的丢失,那么采用非持久化的方式,将会改善性能、减少存储的开销。

    OK,Do you get it? Good Night~See u next time~

    相关文章

      网友评论

      • 8f74d3bcfcef:没了?
      • 12c3517e4b26:本来懵懵,现在清晰了好多。
        12c3517e4b26:@张丰哲 会的,博主写的非常好,学习了。
        张丰哲:有空常来看看~
      • 849da094cffb:文章最后,“因此往往不会在MessageProducer创建的时候指定Destination”。我看了创建生产者的源码, MessageProducer createProducer(Destination destination) throws JMSException;
        只有这一个方法创建生产者,所以创建时必须指定Destination。
        张丰哲:@大悦月 嗯嗯~
        大悦月:你可以直接传个null
      • e14f7f35b785:url怎么设置自己想要的?
      • Qionglou:讲的不错,期待后续
      • 游龙乘风:讲得很细致啊,期待后续
        张丰哲:好的,敬请期待~
      • Pecksniff1994:楼主,最近在做一个分布式的的项目,用到了dubbo 和ActiveMQ生产者生产之后消费者没来消费导致消息积压,以为是新手所以不知道要怎样配置让消费者消费,望指教.
        张丰哲:给一个思路,可以先检查下消费者配置,然后从消费者代码进行debug,调试一下,看哪里不对哈~
      • 谢高飞:你好请问怎么设置connection.start(); 超时时间了?
      • 哈我就是胡子:登陆一下,只为赞你:joy: :joy:
        张丰哲:谢谢你~
      • faccdda48833:写的挺好的,通俗易懂
        张丰哲:有空常来看看~
      • 喵爱吃的鱼:老哥,你代码里是不是忘记commit了,讲解的很细,就是最后没有在mq的页面里看到消息。:+1:
        106b1ce58ea7:@喵爱吃的鱼 并没有开启事务支持,加了commit 报错的
      • 854c26dc33c7:请问用于校验Tcp的用户名密码在哪设置啊
        张丰哲:我们可以在activemq.xml中配置指定的用户、密码才能访问ActiveMQ:smile:
      • 8b151f9278b9:不错不错。
        张丰哲:欢迎继续关注~:smile:
      • 人之初性本善_e864:楼主,想问mq里面的东西可以删除吗?
        张丰哲:你指的应该是消费消息吧,一般MQ而言,消费消息后,消息就失效了,有的会自动删除的。:smile:
      • 266c7b31c70f:特意登陆了,过来说声感谢,文章写的真不错,辞职了,在学分布式的东西了。
        张丰哲:希望文章对你有帮助,加油~:smile:
      • moxfen:感谢分享~
        张丰哲:文章会继续更新的,欢迎关注~
      • f9ee87b00b9c:写的不错 感谢分享
        张丰哲:有空常来看看,会继续更新博文。
      • fb6b1028a838:楼主用的编辑代码的工具是什么呀?求指教谢谢!
        张丰哲:@溢性循环 :blush:
        fb6b1028a838:@溢性循环 谢谢!:grin:
      • 45decfc0050b:问个问题哈,session不设置事务发送消息失败跟设置了事务失败后回滚有什么不同么?数据库里的事务可以理解,操作了多个表等进行回滚,这里的多粒度体现在哪呢?
      • Seaofdesire:通俗易懂,棒棒哒
      • 芝麻谷:写的非常通俗易懂
      • 枫叶_huazhe:你的activemq和rocketmq是不是有看白鹤翔的教程的?好奇下
      • 86c917423624:不错不错,收藏了。

        推荐下,RocketMQ 源码解析 14 篇:http://www.yunai.me/categories/RocketMQ/?jianshu&401
      • 黑白蓝调:写的很好:blush:
      • 761eebae5903:你好,有个地方不太懂。
        请问JMS的consumer是主动拉取消息还是JMS发送给consumer?
        😊😊😊
        761eebae5903:@张丰哲 好的,多谢。我找下。
        张丰哲:在本系列的第二篇博客中有这方面的阐述,你可以参考下,:smile:
      • qinkangdeid:非常感谢楼主分享 希望这一系列能够完美从始有终。拜读中...
        张丰哲:恩恩,敬请期待~
      • 波波一起飞:代码工程要是有简单截图就好了,不过也能明白

      本文标题:ActiveMQ从入门到精通(一)

      本文链接:https://www.haomeiwen.com/subject/qztzgttx.html