您的位置:首页 > 其它

JMS消息选择器

2016-05-29 12:10 162 查看
  消息选择器:对于消息消费者而言,可能希望接收通道中特定规则的消息,这个时候就需要使用消息选择器.

Java代码  


MessageConsumer consumer = session.createConsumer(replyTo,"JMSCorrelationID='" + cid + "'");  

    消息选择器需要在创建consumer时指定,且整个session生命周期中不能被改变;如果需要改变消费者的选择器,只能把当前consumer.close(),然后重新创建consumer实例.

    对于JMS Provider而言,也会持有每个活跃的consumer以及其选择器信息.其中对于Topic而言,如果JMS Provider接收到消息后,会检测+计算每个conmser的选择器,provider对过滤结果为true的consumer创建此消息的副本,并择机发送消息给此consumer.对于Queue则稍有不同,对于每条消息首先加入队列,那么在此消息被发送时才会计算选择器,并将此消息发送给选择器计算结果为true的某个消费者.

    QueueReceiver,TopicSubscriber都可以在创建时指定消息选择器,一旦使用了消息选择器,此消费者只能接收到符合"选择器"要求的消息;消息选择器是一个符合SQL-92语法的表达式,其实它可以认为是sql语言中where之后的字句部分,例如"JMSCorrelationID= 'zhangsan' and amount between (10,20)";其中表达式中的比较标识符可以来自JMS消息的消息头或者属性.但是不能使用消息体中的内容.

    其中JMS消息头为:JMSDeliveryMode,JMSPriority,JMSMessageID,JMSTimestamp,JMSCorrelationID,JMSType.

    任何通过类似于message.setStringProperty("name","zhangsan")设置的消息属性,也可以在消息选择器中使用.

 

    如果使用了消息选择器,当全局中所有的消费者都没有将某条消息覆盖,那么此消息就是"僵尸消息",它将不能被任何消费者使用,将永久驻留在JMS Provider中;如果这种"遗漏"的消息非常庞大,当然会带来致命的风险.例如下述2个消费者的选择器:"age > 25" "age < 25".如果此通道中只有这2中选择器的消费者,那么会导致"age = 25"的消息无法被传送.解决这个问题的方式有:

    1) 创建一个额外的补充消费者,这个消费者不设置任何选择器

    2) 为持久化的消息设定timeToLive属性,可以控制消息消亡的时间,以避免此类型消息的沉积.因为消息的沉积,必将带来队列深度问题.

 

    其实换个角度考虑,使用消息选择器能解决的问题,仍然可以通过"多目的地"的方式解决,比如将"age > 25"的消息发送到queue1,将"age <25"的发送到queue2."多目的地"通道是一种良好的设计,它更细颗粒度的控制了消息的分类,但是它要求Client端需要更多的关注消息的属性和通道的关系.通常情况下,我们根据消息的类型不同,来使用"多目的地"方式,然后在"同一类"消息中使用"选择器",比如:我们有一个订单系统用来发送订单内容,订单类型有"虚拟商品订单"/"图书商品订单"/"电器商品订单",那么在这个维度上,我可以为每种不同类型的订单消息,创建一个"目的地",那么非常方便不同的业务应用来获取它们感兴趣的订单类型;同时每个订单,都有不同的订单状态(待付款,已付款,退款),那么对于这种维度,我们可以使用消息选择器,比如"财务退款中心"的系统对"退款"状态的订单感兴趣.

 



    通过上述图示,我们可以简单的理解"多目的地(multi destination)" 和消息选择器的使用场景.

    还有一个很重要的因素影响着这两种方式的选择:消息"滞留"的速率..我们通过上述讲解,已经知道了消息选择器的表达式,是在JMS Server端计算的对于queue而言,每次消息的发送,都意味着需要对message属性内容进行一次拆解和表达式的计算(需要声明:消息的内容在存储上并非严格结构化和可索引化的),当消息的发送密度相当高时,这种计算开支也是不容忽略的,这种计算潜在了放缓了消息的消费速度,而且当一个通道中,多个选择器类型的消息消费速度相差较大时(从消息到达消费者,然后消息确认信号返回.比如"退款"类型的消息比较耗时,但是"取消订单"执行较快),这种隐式的消息沉淀,也会加剧队列深度,从而拖累整个通道的消息消费速率.

    "多目的地"意味我们需要创建更多的通道(Topic,或者queue),在一定的程度上,我们能够通过这种方式来规避一些"单通道队列深度"问题;但是通道个数越多,其实对JMS Provider的性能考验也是很深刻的.一个通道在消息的分发机制中,将需要一个独立的线程来负责,此线程维护着内存消息队列和消费者列表;那么当活跃的通道越多,那么server的资源压力就会严峻.很多时候,我们需要在"通道个数" "通道中消息密度"之间做个平衡.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: