7.producer

来源:互联网 发布:网页电子书制作软件 编辑:程序博客网 时间:2024/05/16 07:57
  1. 消息生产者,消息的种类:
    1. 普通消息

      import com.alibaba.rocketmq.client.exception.MQClientException;import com.alibaba.rocketmq.client.producer.DefaultMQProducer;import com.alibaba.rocketmq.client.producer.SendResult;import com.alibaba.rocketmq.common.message.Message;public class ProducerTest {//nameserver地址private String namesrvAddr = "127.0.0.1:9876";//producer实例private DefaultMQProducer producer;public ProducerTest(String group) throws MQClientException {//初始化producer并启动producer = new DefaultMQProducer(group);        producer.setNamesrvAddr(namesrvAddr);        producer.start();}/** * 发送普通消息 * @param topic * @param msg */public void send(String topic, Object msg) {byte[] bytes = null;//convert msg to byteSendResult sendResult = null;try {sendResult = producer.send(new Message(topic, bytes));//发送消息成功,但是需要检测状态switch(sendResult.getSendStatus()) {case SEND_OK:break;case FLUSH_DISK_TIMEOUT://刷盘超时,服务器宕机消息可能丢失break;case FLUSH_SLAVE_TIMEOUT://同步到slave超时,Master宕机消息可能丢失break;case SLAVE_NOT_AVAILABLE://slave此时不可用break;}} catch (Exception e) {e.printStackTrace();//发送异常,记录发送的结果,业务方需要判断是否重新发送该消息System.out.println(sendResult);}}}


    2. 延时消息

      msg.setDelayTimeLevel();


    3. 顺序消息

      /** * 发送有序消息 * * @param msg 消息数据 * @param selector   队列选择器,发送时会回调 * @param order      回调队列选择器时,此参数会传入队列选择方法,提供配需规则 * @return 发送结果 */public Result<SendResult> send(Message msg, MessageQueueSelector selector, Object arg) class IDHashMessageQueueSelector implements MessageQueueSelector{    public MessageQueue select(List<MessageQueue> mqs, Message msg,            Object arg) {        int id = Integer.parseInt(arg.toString());        int size = mqs.size();        int index = id%size;        return mqs.get(index);    }}


  2. 普通消息
    1. 默认发送超时时间为3秒
    2. 默认发送的数据传输方式为同步,即等待数据的返回
    3. 默认消息发送失败重试次数为3次
    4. 在3+1秒内,重试3次,如果还不成功将会抛出异常,但是因为一次发送的超时时间为3秒,如果超时可能只能重试2次
    5. 发送的流程如下:

      rocketmq会存储一个topic+brokername+queueid的列表,举个具体的例子,如下:

      那么这个列表是topic-a+broker-a+queue-0,topic-a+broker-a+queue-1,topic-a+broker-b+queue-0,topic-a+broker-b+queue-1
      发送时会轮询这个列表(即使并发请求),选择一个broker进行发送。
      如果第一次发送失败,会按顺序选择选择下一个非失败的broker,例如:
      第一次发送选择的是:topic-a+broker-a+queue-0,如果失败了,那么第二次发送选的将是:topic-a+broker-b+queue-0
    6. 上面的列表默认每30秒更新一次
    7. 高可用:
      1. 各个producer直接无通信
      2. producer发送失败会按顺序选择下一个broker进行重试
      3. 最终还是存在发送失败的情况,需要调用者处理
  3. 延时消息
    1. 延时消息需要延时消费,比如通信软件中的通知,离线状态是不能收到的,上线后发送通知。
    2. 延时消息的实现:

    3. 高可用
      1. ScheduleMessageService读取消息后,再次保存,出错则保留当前offset,等待下一次任务执行
      2. offset会每隔10s定时持久化到硬盘
      3. broker重启会从持久化的数据中加载offset
      4. slave同样会和master一样,构建延时队列,并定时解析到commitLog中
      5. messageDelayLevel 定时消息级别,默认为1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h分别对应1~18级
  4. 顺序消息
    1. 这里的顺序,主要是指局部顺序,即生产者通过将某一类消息发送至同一个队列来实现
      例如:某个微信用户发了一条消息(A),然后撤回(B)
      如何保持顺序:
      1. 对于业务端来说,这两个消息需要顺序发送,即A的消息发送成功,才能发送B
      2. 对于生产者来说,只要是单线程的,将A,B发往同一个队列即可保证顺序
      3. 如何将不同的消息发往同一个队列呢?通过id取模定位:
        此时需要这两个消息有共同的元素,比如uid,在发送消息时可以通过uid%queueNum来获取发往那个queue,即同一个uid的消息都发往同一个queue

    2. 普通顺序消息
      1. 正常情况下,保证消息的顺序性
      2. 异常情况下,例如broker宕机或重启,那么由于队列总数发生变化,id取模定位后队列发生变化(定时从nameserver更新topic路由),会产生短暂的消息顺序不一致,如下图:

        假设broker-c宕机,那么queue-2不可用,那么100的会发往queue-0,由于queue-1此时也有100的消息,故不能做到顺序消费。
        另外,101会发往queue-1,而此时broker-c如果起来了,也不能做到顺序消费。
    3. 严格顺序消息
      1. 无论正常异常情况,都需要保证消息的顺序性
      2. 对于rocketmq来说,严格顺序消息是如何实现的呢,如下图:

        这里,跟普通顺序消息唯一不一样的地方就是多了一个topic的kv配置,即topic的路由信息是死的,即使某个broker挂了,路由信息也不变
        这样就能保证发往其他的queue的消息顺序不变,但是发往挂了的broker的消息会失败,此时需要客户端来处理。
  5. nameserver挂了的影响
    1. 由于producer会从nameserver列表中顺序选一个进行连接,并定时查询topic的路由信息,如果正在连接的nameserver挂了,会选择下一个nameserver进行连接
      所以nameserver挂了并不会影响producer
  6. 关于消息重复
    1. 由于发送消息时会发送失败,失败的情况有多种:
      1. 网络异常
      2. 消息数据问题
      3. broker挂了
      4. 超时
      5. 数据写入问题等等
    2. 由于各种复杂的情况会导致消息发送失败,此时需要业务端根据自身需要再次发送该消息
    3. 所以有可能会存在同一条消息被发送了两次,但是消息的msgid是不同的


0 0