Непоследовательное выполнение в расписании задач - PullRequest
0 голосов
/ 13 февраля 2019

Я пишу компонент планирования задач, так что задача таймера должна выполняться только один раз в кластере с дублированным планировщиком (т. Е. На сервере приложений), и в настоящее время для надежности используется распределенная блокировка.

Распределенная блокировка реализована с помощью записи Redis.Когда задача отправляется в планировщик A, планировщик B будет использовать SETNX (атомарный) и записывать запись задачи на сервере Redis.Если другой планировщик отправляет точно такую ​​же задачу (например, по электронной почте пользователю), SETNX не будет выполнен, и тогда планирование будет отменено в планировщике B.

Моя проблема возникает в особом случаеэто описано следующим образом:

   scheduler A              Redis         scheduler B        scheduler C
             |      lock      |               |                   
             |--------------->|      lock     |                   
             |     success    |<--------------|                   
             |<---------------|      fail     |                   
task alpha   o                |-------------->|                   
  submit     |                |               x schedule          
 success     |                |                 canceled          0 a new scheduler
             |                |                                   | is scaled in cluster
             |                |         fetch existing tasks      |
             |                |<----------------------------------|
             |                |        report submitted tasks     |
             |                |---------------------------------->| now scheduler C
             |                |                                   | knows task alpha.
             |                |                                   |
task alpha   o      lock      |                lock               o task alpha
  starts     |--------------->|<----------------------------------|   starts
 execute     |      fail      |              success              |  execute
             |<---------------|---------------------------------->| 
 schedule    x                |                                   | keep executing
 canceled                     |                                   |
                              |                                   |
                              |                                   |
                              x Redis fail                        |
                                                                  |
                                              unlock              v execution success
                               <----------------------------------| delete task record
                                                                  |
                        Redis 0                                   |
                    recovered |                                   |
                              |              0 scheduler B
                   the record |     fetch    | recovered
                of task alpha |<-------------|
                 still exists |    report    |
                              |------------->| task alpha needs
                              |     lock     o execution because
                              |<-------------| time has arrived!
                              |    success   |
                              |------------->|
                              |              |
                              |    unlock    v execution success (inconsistent execution)
                              |<-------------|
                                             |
                                             |

На этом рисунке планировщик C выполнил task alpha. Однако из-за сбоя разблокировки запись задачи не удаляется из Redis.После этого, когда планировщик B будет восстановлен, задание будет выполнено снова, что вызывает несоответствие .

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

Длинное описание, но короткие вопросы:

  • Как можно решить проблему несоответствия?
  • Есть ли какой-либо другой лучший планировщик для сценария, описанного выше?
...