MQ

96 阅读3分钟

JMS (ActiveMQ)

JMS 2.1规范

消息头

  1. JMSDestination(required): 目的地, 是一个topic/queue. 系统名_topic/queue_事件(队列)名
  2. JMSMessageID(required) 消息id, 要以ID:开头, 一般自动生成即可.
  3. JMSDeliveryMode(required) 发送模式, NON_PERSISTENT/PERSISTENT
  4. JMSTimestamp(required) 发送时间(send()时间), 需打印该时间戳
  5. JMSExpiration(optional) 过期时间, ms, 发送时间+TTL, 默认永不过期
  6. JMSPriority(optional) 0-4为普通优先级, 5-9为高优先级

消息属性

pubSession.createTextMessage().setStringProperty("username", "xx");

消息体

  1. TextMessage: String
  2. MapMessage: Map<String, Object>
  3. ByteMessage: byte[]
  4. StreamMessage: java数据流
  5. ObjectMessage: 可序列化的object

AMQP (RabbitMQ)

AMQP 0.9.1标准 消息发给交换机, 交换机使用绑定规则将消息发到队列

  1. vhost 相似业务和耦合度强的业务分配到同意vhost中, 不要在/下安排虚拟主机.
  2. 代码规范
    1. 生产者和消费者使用长链接, connection and channel are meat to be long-lived. 避免每发消息都建立连接.
    2. 多线程时每个线程独占一个channel, 可考虑使用Channel Pooling, Spring AMQP已具备此功能. (多线程共享channel可能导致帧错误进而导致连接异常, broker异常关闭)
    3. 生产者和消费者不能共用channel.
    4. Clients should try to connect all cluster node.
    5. Client要设置心跳检测, 因为consumer无法感知服务器异常. 心跳时间为10-40s(可30s)
    6. 每个jvm process中channel<100个
    7. producer确认消息已发送至mq, 对失败数据处理, 具备重发机制
    8. consumer幂等性处理
    9. 对于消费者, 不同使用者实例使用不同的使用者标签, 不然可能导致自动连接恢复和监视数据错乱. 如果不确定, 请不要声明, 使其随机生成即可.
  3. 交换机设计原则
    1. 一个应用只监听一个队列, 尽量单一化
    2. 由发送方决定交换机, 发送的内容为"我做了什么", 而不是"我要对方做什么". 因为后者与接收方业务关联, 接收方业务变化, 交换机也要随之变化, 耦合太强, 复杂度上升.
    3. 交换机不发信息给其他交换机, 否则会使业务逻辑从代码向队列平台扩散, 可能形成死循环
  4. 路由器设计规则
    1. 如无必要, 不适用routing key, 增加排查难度
    2. fanout: 没有特殊情况尽量使用该模式, 其他需求在代码中实现
    3. direct: consumer在逻辑上分开不熟(如地域原因)
    4. topic: 需要模糊匹配
  5. 命名: 小数点隔开. 队列.事件.交换机.xx.xx
  6. 持久化
    1. queue持久化(durable: true): channel.queueDeclare(QUEUE_NAME, true, false, false, null)
    2. 消息持久化(deliveryMode:2): channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
  7. consumer尽量采用事件订阅机制, 非轮训(效率低)

对比

JSM vs AMQP

-- JSM ---- AMQP --
NO跨语言和平台
peer2peer/pub-subdirect/fanout/topic/head..
多种消息类型Text/Map/Byte..byte[] 复杂消息可序列化后发送