Kafka-реализация отложенной очереди с использованием потребителя высокого уровня

хотите реализовать отложенного потребителя с помощью API потребителя высокого уровня

основные идеи:

  • создавать сообщения по ключу (каждый msg содержит метку времени создания) это гарантирует, что каждый раздел упорядочил сообщения по времени создания.
  • "авто".совершать.enable=false (будет явно фиксироваться после каждого процесса сообщения)
  • употребляет
  • проверьте метку времени сообщения и проверьте, достаточно ли времени прошло
  • сообщение процесса (эта операция никогда не будет терпеть неудачу)
  • зафиксировать 1 смещение

    while (it.hasNext()) {
      val msg = it.next().message()
      //checks timestamp in msg to see delay period exceeded
      while (!delayedPeriodPassed(msg)) { 
         waitSomeTime() //Thread.sleep or something....
      }
      //certain that the msg was delayed and can now be handled
      Try { process(msg) } //the msg process will never fail the consumer
      consumer.commitOffsets //commit each msg
    }
    

некоторые проблемы с этой реализацией:

  1. фиксация каждого смещения может замедлить ZK
  2. может потребителя.commitOffsets создает исключение? если да, я буду использовать одно и то же сообщение дважды (может решить с идемпотентными сообщениями)
  3. проблема долгое время ожидания без фиксации смещения, например период задержки составляет 24 часа, будет получать следующий от итератора, спать в течение 24 часов, обрабатывать и фиксировать (тайм-аут сеанса ZK ?)
  4. как сеанс ZK может поддерживать жизнь без фиксации новых смещений ? (установка зоопарка улья.сеанс.тайм-аут.ms может разрешать в Мертвом потребителе, не признавая его)
  5. любые другие проблемы im отсутствует?

спасибо!

4 ответов


один из способов сделать это - использовать другую тему, где вы нажимаете все сообщения, которые должны быть задержаны. Если все отложенные сообщения должны быть обработаны после той же задержки времени, это будет довольно прямо вперед:

while(it.hasNext()) {
    val message = it.next().message()

    if(shouldBeDelayed(message)) {
        val delay = 24 hours
        val delayTo = getCurrentTime() + delay
        putMessageOnDelayedQueue(message, delay, delayTo)
    }
    else {
       process(message)
    }

    consumer.commitOffset()
}

все регулярные сообщения теперь будут обработаны как можно скорее, в то время как те, которые нуждаются в задержке, помещаются на другую тему.

хорошо то, что мы знаем, что сообщение во главе отложенной темы-это то, что должен быть обработан первым, так как его значение delayTo будет наименьшим. Поэтому мы можем настроить другого потребителя, который читает сообщение head, проверяет, находится ли отметка времени в прошлом, и если да, обрабатывает сообщение и фиксирует смещение. Если нет, он не фиксирует смещение и вместо этого просто спит до этого времени:

while(it.hasNext()) {
    val delayedMessage = it.peek().message()
    if(delayedMessage.delayTo < getCurrentTime()) {
        val readMessage = it.next().message
        process(readMessage.originalMessage)
        consumer.commitOffset()
    } else {
        delayProcessingUntil(delayedMessage.delayTo)
    }
}

если есть разные времена задержки, вы можете разделить тему на задержку (например, 24 часа, 12 часов, 6 часов). Если время задержки более динамично это становится немного сложнее. Вы могли бы решить его, введя две темы задержки. Прочитайте все сообщения от темы задержки A и обрабатывать все сообщения, чьи delayTo значение в прошлом. Среди других вы просто найдете тот, который с ближайшим delayTo и затем поставить их на тему B. Спите, пока ближайший не будет обработан, и делайте все наоборот, т. е. обрабатывайте сообщения из темы B и поместите один раз, который еще не должен быть обработан по теме A.

чтобы ответить на ваши конкретные вопросы (некоторые из них были рассмотрены в комментарии на ваш вопрос)

  1. фиксация каждого смещения может замедлить ZK

вы можете рассмотреть возможность переключения на сохранение смещения в Кафке (функция доступна с 0.8.2, проверьте offsets.storage свойство в конфигурации потребителя)

  1. может потребителя.commitOffsets создает исключение? если да я буду потреблять одно и то же сообщение дважды (может решить с идемпотентными сообщениями)

Я считаю, что это возможно, если он не может связаться с хранилищем смещения, например. Использование идемпотентных сообщений решает эту проблему, как вы говорите.

  1. проблема долгое время ожидания без фиксации смещения, например, период задержки составляет 24 часа, будет получать следующий от итератора, спать в течение 24 часов, обрабатывать и фиксировать (тайм-аут сеанса ZK ?)

это не будет проблемой с вышеуказанным изложенным решением, если обработка самого сообщения не займет больше времени ожидания сеанса.

  1. как сеанс ZK может поддерживать жизнь без фиксации новых смещений ? (установка зоопарка улья.сеанс.тайм-аут.ms может разрешать в Мертвом потребителе, не признавая его)

опять же с вышеизложенным вам не нужно устанавливать длительный тайм-аут сеанса.

  1. любые другие проблемы im отсутствует?

там всегда есть ;)


Я бы предложил другой путь в ваши дела.

нет смысла рассматривать время ожидания в основном потоке потребителя. Это будет анти-шаблон в том, как используются очереди. Концептуально, вам нужно обработать сообщения как можно быстрее и сохранить очередь с низким коэффициентом загрузки.

вместо этого я бы использовал планировщик, который будет планировать задания для каждого сообщения, которое вам нужно отложить. Таким образом, вы можете обработать очередь и создать асинхронные задания, которые будут запускаться в заранее определенные моменты времени.

падение использования этого метода заключается в том, что он чувствителен к состоянию JVM, который держит запланированные задания в памяти. Если эта JVM терпит неудачу, вы теряете запланированные задания, и вы не знаете, была ли задача выполнена или не была выполнена.

есть реализации планировщика, хотя это может быть настроено для запуска в кластерной среде, тем самым сохраняя вас в безопасности от сбоев JVM.

взгляните на эту структуру планирования java:http://www.quartz-scheduler.org/


используйте Tibco EMS или другие очереди JMS. У них есть задержка повтора . Кафка не может быть правильным выбором дизайна для того, что вы делаете


Keyed-list по расписанию или его альтернатива redis могут быть лучшими подходами.