cron 스케줄링은 실제로 어떻게 구현되고 스크립트가 제 시간에 실행되도록 보장합니까?

cron 스케줄링은 실제로 어떻게 구현되고 스크립트가 제 시간에 실행되도록 보장합니까?

크론 작업에 관해 질문하고 싶습니다. 좋아요, 스크립트를 crontab에 넣은 다음 cron 데몬이 이를 실행합니다.

이제 이것을 이해하면 cron은 매분 각 사용자의 crontab을 확인하고 구성된 스크립트를 실행합니다. 하지만 실제로는 어떻게 이루어지나요? 하위 프로세스 등을 포크합니까?

시간이 낭비되기 때문에 작업을 순차적으로 실행할 수 없습니다(예: 장기 실행 스크립트가 완료되기를 기다리는 경우). 그렇다면 이것이 실제로 어떻게 달성됩니까?

단지 도움을 주기 위해 저는 낮은 수준의 코드를 찾고 있지 않습니다. 나에게는 높은 수준의 설명(아마도 알고리즘?)이나 대부분의 배포판에서 이를 구현하는 방법이면 충분할 것입니다.

답변1

StackOverflow에서 다음과 같은 제목의 Q&A를 찾았습니다.크론은 내부적으로 어떻게 작업을 예약하나요?.

이 게시물에서 발췌한 내용과cron에 관한 Wikipedia 기사

The algorithm used by this cron is as follows:

1. On start-up, look for a file named .crontab in the home directories of 
   all account holders.

2. For each crontab file found, determine the next time in the future that
   each command is to be run.

3. Place those commands on the Franta-Maly event list with their corresponding
   time and their "five field" time specifier.

4. Enter main loop:

   1. Examine the task entry at the head of the queue, compute how far in 
      the future it is to be run.

   2. Sleep for that period of time.

   3. On awakening and after verifying the correct time, execute the task 
      at the head of the queue (in background) with the privileges of the 
      user who created it.

   4. Determine the next time in the future to run this command and place 
      it back on the event list at that time

이 슈퍼유저 Q&A의 제목은 다음과 같습니다.크로나는 어떻게 작동하나요?다른 질문 중 일부를 다룹니다. 예를 들어, cron이 동시에 예약된 작업을 처리하는 방법에 대한 질문이 있습니다. 이 스레드의 답변 중 하나는 cron 데몬이 각 작업을 처리할 때 단일 작업이 시간이 겹치는 작업을 차단하는 역할을 하지 않도록 예약된 각 작업을 분기한다는 것입니다.

답변2

나는 썼다블로그 게시물설명해보세요.
관련 텍스트를 인용하려면:

  • PriorityBlockingQueue우선 순위(스레드 안전 힙)에서 선택하여 모든 작업을 실행하는 제한된 스레드 풀을 가질 수 있습니다 job.nextExecutionTime().
  • 이는 힙의 최상위 요소가 항상 가장 빠르게 실행된다는 것을 의미합니다.
  • 표준 스레드 풀 생산자-소비자 패턴을 따릅니다.
  • 무한 루프에서 실행되고 새 작업을 소비한 후 대기열에서 스레드 풀로 제출하는 스레드가 있습니다. 우리는 그것을 부른다대기열 소비자 스레드:
void goToSleep(job, jobQueue){
    jobQueue.push(job);
    sleep(job.nextExecutionTime() - getCurrentTime());
}

void executeJob(job, jobQueue){
    threadpool.submit(job); // async call
    job = job.copy();
    job.setNextExecutionTime(getCurrentTime() + job.getExecutionInterval());
    jobQueue.add(job);
}

@Override
void run(){
    while(true)
    {
        job = jobQueue.pop()
        if(job.nextExecutionTime() > getCurrentTime()){
            // Nothing to do
            goToSleep(job, jobQueue)
        }
        else{
            executeJob(job, jobQueue)
        }
    }
}
  • 새로 추가된 작업에 대해 crontab 파일을 모니터링하고 이를 대기열에 푸시하는 스레드도 있습니다.
  • 우리는 그것을 부른다대기열 생성자 스레드:
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
    }
}
  • 그러나 여기에는 문제가 있습니다.
    • Thread1이 잠자고 있다가 한 시간 후에 깨어난다고 상상해 보십시오.
    • 동시에 매분 실행되어야 하는 새로운 작업이 도착합니다.
    • 이 새 작업은 한 시간 동안 시작되지 않습니다.
  • 이 문제를 해결하기 위해 새 작업이 대기열의 프런트엔드 작업보다 먼저 실행되어야 할 때마다 ProducerThread가 ConsumerThread를 절전 모드에서 강제로 실행하도록 할 수 있습니다.
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
        if(newJob == jobQueue.peek())
        {
            // The new job is the one that will be scheduled next.
            // So wakeup consumer thread so that it does not oversleep.
            jobQueueConsumerThread.interrupt()
        }
    }
}

관련 정보