Sidekiq 문제 해결

Tier: Free, Premium, Ultimate Offering: Self-Managed

Sidekiq는 GitLab이 비동기로 작업을 실행하기 위해 사용하는 백그라운드 작업 프로세서입니다. 문제가 발생하면 문제 해결이 어려울 수 있습니다. 또한 프로덕션 시스템의 작업 대기열이 채워지는 경우에는 고압일 가능성이 높습니다. 사용자는 새 브랜치가 표시되지 않거나 병합 요청이 업데이트되지 않는 것을 알게 됩니다. 다음은 병목 현상을 진단하는 데 도움이 되는 몇 가지 문제 해결 단계입니다.

GitLab 관리자/사용자는 GitLab 지원팀과 함께 이러한 디버그 단계를 수행하여 백트레이스를 분석해야 합니다. 이는 때로는 GitLab에서 버그나 개선이 필요한 사항을 드러낼 수 있습니다.

백트레이스 중 어디에서든 데이터베이스, Redis에서 대기 중이거나 뮤텍스를 획들기 위해 대기하고 있는 쓰레드가 의심스러운 경우를 주의해야 합니다. 이 가능성이 있을 수도 있지만, 나머지 쓰레드와 다른 하나를 찾으세요. 이 다른 쓰레드는 모든 사용 가능한 CPU를 사용하거나 루비 전역 인터프리터 락을 가지고 있을 수 있어서 다른 쓰레드가 계속할 수 없게 만들 수 있습니다.

Sidekiq 작업에 전달되는 인수 로깅

일부 특정 작업을 제외한 모든 작업의 숫자 인수를 기본적으로 GitLab에 의해 기록합니다. (예: 비밀번호 초기화 토큰).

예제 로그 출력:

{"severity":"INFO","time":"2020-06-08T14:37:37.892Z","class":"AdminEmailsWorker","args":["[FILTERED]","[FILTERED]","[FILTERED]"],"retry":3,"queue":"admin_emails","backtrace":true,"jid":"9e35e2674ac7b12d123e13cc","created_at":"2020-06-08T14:37:37.373Z","meta.user":"root","meta.caller_id":"Admin::EmailsController#create","correlation_id":"37D3lArJmT1","uber-trace-id":"2d942cc98cc1b561:6dc94409cfdd4d77:9fbe19bdee865293:1","enqueued_at":"2020-06-08T14:37:37.410Z","pid":65011,"message":"AdminEmailsWorker JID-9e35e2674ac7b12d123e13cc: done: 0.48085 sec","job_status":"done","scheduling_latency_s":0.001012,"redis_calls":9,"redis_duration_s":0.004608,"redis_read_bytes":696,"redis_write_bytes":6141,"duration_s":0.48085,"cpu_s":0.308849,"completed_at":"2020-06-08T14:37:37.892Z","db_duration_s":0.010742}
{"severity":"INFO","time":"2020-06-08T14:37:37.894Z","class":"ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper","wrapped":"ActionMailer::MailDeliveryJob","queue":"mailers","args":["[FILTERED]"],"retry":3,"backtrace":true,"jid":"e47a4f6793d475378432e3c8","created_at":"2020-06-08T14:37:37.884Z","meta.user":"root","meta.caller_id":"AdminEmailsWorker","correlation_id":"37D3lArJmT1","uber-trace-id":"2d942cc98cc1b561:29344de0f966446d:5c3b0e0e1bef987b:1","enqueued_at":"2020-06-08T14:37:37.885Z","pid":65011,"message":"ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper JID-e47a4f6793d475378432e3c8: start","job_status":"start","scheduling_latency_s":0.009473}
{"severity":"INFO","time":"2020-06-08T14:39:50.648Z","class":"NewIssueWorker","args":["455","1"],"retry":3,"queue":"new_issue","backtrace":true,"jid":"a24af71f96fd129ec47f5d1e","created_at":"2020-06-08T14:39:50.643Z","meta.user":"root","meta.project":"h5bp/html5-boilerplate","meta.root_namespace":"h5bp","meta.caller_id":"Projects::IssuesController#create","correlation_id":"f9UCZHqhuP7","uber-trace-id":"28f65730f99f55a3:a5d2b62dec38dffc:48ddd092707fa1b7:1","enqueued_at":"2020-06-08T14:39:50.646Z","pid":65011,"message":"NewIssueWorker JID-a24af71f96fd129ec47f5d1e: start","job_status":"start","scheduling_latency_s":0.001144}

Sidekiq JSON 로깅을 사용할 때, 인수 로그는 최대 10 킬로바이트의 텍스트 크기로 제한되며, 이 제한 이후의 인수는 폐기되고 문자열 "..."을 포함하는 단일 인수로 대체됩니다.

SIDEKIQ_LOG_ARGUMENTS 환경 변수0 (false)로 설정하여 인수 로깅을 비활성화할 수 있습니다.

예제:

gitlab_rails['env'] = {"SIDEKIQ_LOG_ARGUMENTS" => "0"}

Sidekiq 대기열 대기 또는 느린 성능 조사

느린 Sidekiq 성능의 증상은 병합 요청 상태 업데이트에 문제가 있거나 CI 파이프라인이 실행되기 전에 지연된 것입니다.

잠재적인 원인으로는:

  • GitLab 인스턴스가 더 많은 Sidekiq 워커가 필요할 수 있습니다. 기본적으로 단일 노드 Linux 패키지 설치는 하나의 워커를 실행하며, Sidekiq 작업을 최대 하나의 CPU 코어에서 실행합니다. 여러 Sidekiq 워커 실행에 대해 더 읽어보기.

  • 인스턴스가 더 많은 Sidekiq 워커가 구성된 경우에도 추가 워커의 대부분이 대기 중인 작업을 실행하도록 구성되지 않았습니다. 이는 인스턴스가 바쁜 경우 작업 부하가 월 또는 년간 변경되었거나, GitLab 제품 변경의 결과로 발생할 수 있습니다.

다음의 Ruby 스크립트를 사용하여 Sidekiq 워커의 상태에 관한 데이터를 수집합니다.

  1. 스크립트 생성:

    cat > /var/opt/gitlab/sidekiqcheck.rb <<EOF
    require 'sidekiq/monitor'
    Sidekiq::Monitor::Status.new.display('overview')
    Sidekiq::Monitor::Status.new.display('processes'); nil
    Sidekiq::Monitor::Status.new.display('queues'); nil
    puts "----------- workers ----------- "
    workers = Sidekiq::Workers.new
    workers.each do |_process_id, _thread_id, work|
      pp work
    end
    puts "----------- Queued Jobs ----------- "
    Sidekiq::Queue.all.each do |queue|
      queue.each do |job|
        pp job
      end
    end ;nil
    puts "----------- done! ----------- "
    EOF
    
  2. 실행하고 출력 캡처:

    sudo gitlab-rails runner /var/opt/gitlab/sidekiqcheck.rb > /tmp/sidekiqcheck_$(date '+%Y%m%d-%H:%M').out
    

    성능 문제가 때로는 발생하는 경우:

    • 이것을 지속적으로 5분마다 크론 작업에서 실행합니다. 충분한 공간을 가진 위치에 파일을 작성하십시오: 파일당 최소 500KB 이상의 공간을 확보하십시오.

      cat > /etc/cron.d/sidekiqcheck <<EOF
      */5 * * * *  root  /opt/gitlab/bin/gitlab-rails runner /var/opt/gitlab/sidekiqcheck.rb > /tmp/sidekiqcheck_$(date '+\%Y\%m\%d-\%H:\%M').out 2>&1
      EOF
      
    • 무엇이 잘못되었는지 확인하기 위해 데이터를 참조하십시오.

  3. 출력을 분석합니다. 아래 명령들은 출력 파일 디렉토리를 가정합니다.

    1. grep 'Busy: ' *은 실행 중인 작업의 수를 보여줍니다. grep 'Enqueued: ' *는 해당 시간에 대기 중인 작업을 보여줍니다.

    2. Sidekiq가 부하 중인 샘플에서 워커 전체에서 바쁜 쓰레드의 수를 살펴보세요:

      ls | while read f ; do if grep -q 'Enqueued: 0' $f; then :
        else echo $f; egrep 'Busy:|Enqueued:|---- Processes' $f
        grep 'Threads:' $f ; fi
      done | more
      

      예시 출력:

      sidekiqcheck_20221024-14:00.out
             Busy: 47
         Enqueued: 363
      ---- Processes (13) ----
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 23 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (0 busy)
        Threads: 30 (24 busy)
        Threads: 30 (23 busy)
      
      • 이 출력 파일에서 47개의 쓰레드가 바쁘며, 363개의 작업 대기열이 있었습니다.
      • 13 개의 워커 프로세스 중 2개만 바쁜 상태였습니다.
      • 다른 워커가 너무 특정하게 구성되었음을 나타냅니다.
      • sidekiq_queues 구성과 상관관계를 찾으려면 전체 출력을 살펴보세요.
      • 한 가지 워커로 오버로드된 환경은 다음과 같을 수 있습니다.

        sidekiqcheck_20221024-14:00.out
               Busy: 25
           Enqueued: 363
        ---- Processes (1) ----
          Threads: 25 (25 busy)
        
    3. 파일 내의 ---- Queues (xxx) ---- 섹션을 살펴보아 그 시간에 대기 중인 작업을 결정합니다.

    4. 파일에는 작업 부하가 발생한 지점의 낮은 수준의 세부 정보도 포함되어 있습니다. 이는 작업 부하가 어디에서 주로 발생하는지 확인하는 데 유용할 수 있습니다.

      • ----------- workers ----------- 섹션은 요약에서 Busy 수량을 구성하는 작업에 대한 세부 정보를 제공합니다.
      • ----------- Queued Jobs ----------- 섹션은 Enqueued 상태의 작업에 대한 세부 정보를 제공합니다.

쓰레드 덤프

TTIN 신호를 Sidekiq 프로세스 ID에 보내 스레드 백트레이스를 로그 파일에 출력합니다.

kill -TTIN <sidekiq_pid>

백트레이스 출력을 확인하려면 /var/log/gitlab/sidekiq/current 또는 $GITLAB_HOME/log/sidekiq.log를 확인하세요. 백트레이스는 일반적으로 여러 WARN 수준 메시지로 시작하는 긴 메시지입니다. 다음은 단일 스레드의 백트레이스의 예시입니다:

2016-04-13T06:21:20.022Z 31517 TID-orn4urby0 WARN: ActiveRecord::RecordNotFound: Couldn't find Note with 'id'=3375386
2016-04-13T06:21:20.022Z 31517 TID-orn4urby0 WARN: /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/activerecord-4.2.5.2/lib/active_record/core.rb:155:in `find'
/opt/gitlab/embedded/service/gitlab-rails/app/workers/new_note_worker.rb:7:in `perform'
/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/processor.rb:150:in `execute_job'
/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/processor.rb:132:in `block (2 levels) in process'
/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/middleware/chain.rb:127:in `block in invoke'
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/sidekiq_middleware/memory_killer.rb:17:in `call'
/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/middleware/chain.rb:129:in `block in invoke'
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/sidekiq_middleware/arguments_logger.rb:6:in `call'
...

일부 경우에는 Sidekiq가 멈추어 TTIN 신호에 응답하지 못할 수 있습니다. 그럴 경우 다른 문제 해결 방법으로 넘어가세요.

rbspy를 사용한 루비 프로파일링

rbspy는 CPU 사용량의 flamegraph 스타일 다이어그램을 만들 수 있는 사용하기 쉽고 오버헤드가 적은 루비 프로파일러입니다.

GitLab의 변경 사항은 필요하지 않으며 의존성도 없습니다. 설치하려면:

  1. rbspy 릴리스 페이지에서 바이너리를 다운로드합니다.
  2. 바이너리를 실행 가능하게 만듭니다.

한 분 동안 Sidekiq worker를 프로파일링하려면 다음을 실행합니다:

sudo ./rbspy record --pid <sidekiq_pid> --duration 60 --file /tmp/sidekiq_profile.svg

예시 rbspy flamegraph

rbspy로 생성된 flamegraph 예시에서 대부분의 Sidekiq 프로세스 시간이 Rugged의 네이티브 C 함수 중 하나인 rev_parse에서 소요되고 있습니다. 스택에서 rev_parseExpirePipelineCacheWorker에 의해 호출되는 것을 볼 수 있습니다.

rbspy컨테이너화된 환경에서 별도의 권한을 필요로 합니다. 최소한SYS_PTRACE 기능이 필요하며, 그렇지 않으면 permission denied 오류로 종료됩니다.

::: TabTitle 쿠버네티스

securityContext:
  capabilities:
    add:
      - SYS_PTRACE
도커
docker run --cap-add SYS_PTRACE [...]
도커 Compose
services:
  ruby_container_name:
    ...
    cap_add:
      - SYS_PTRACE

perf를 사용한 프로세스 프로파일링

리눅스에는 특정 프로세스가 많은 CPU를 사용하는 경우 유용한 프로세스 프로파일링 도구인 perf가 있습니다. 높은 CPU 사용량이 있고 Sidekiq가 TTIN 신호에 응답하지 않는 경우 다음 단계로 넘어가세요.

만약 시스템에 perf가 설치되지 않았다면 apt-get 또는 yum을 통해 설치하세요:

# Debian
sudo apt-get install linux-tools

# Ubuntu (추가 커널 패키지가 필요할 수 있습니다)
sudo apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`

# Red Hat/CentOS
sudo yum install perf

Sidekiq PID에 대해 perf를 실행하세요:

sudo perf record -p <sidekiq_pid>

30-60초 이내로 실행한 후에 Ctrl-C를 누르세요. 그런 다음 perf 보고서를 확인하세요:

$ sudo perf report

# 샘플 출력
Samples: 348K of event 'cycles', Event count (approx.): 280908431073
 97.69%            ruby  nokogiri.so         [.] xmlXPathNodeSetMergeAndClear
  0.18%            ruby  libruby.so.2.1.0    [.] objspace_malloc_increase
  0.12%            ruby  libc-2.12.so        [.] _int_malloc
  0.10%            ruby  libc-2.12.so        [.] _int_free

위는 perf 보고서의 샘플 출력입니다. 거의 97%의 CPU가 Nokogiri 및 xmlXPathNodeSetMergeAndClear 안에서 사용되고 있는 것을 보여줍니다. 이러한 명백한 상황에 대해서는 GitLab의 어떤 작업이 Nokogiri 및 XPath를 사용하는 지 조사해야 합니다. 이것은 해당하는 루비 코드를 확인하기 위해 TTIN 또는 gdb 출력과 결합할 수 있습니다.

GNU 프로젝트 디버거(gdb)

gdb는 Sidekiq를 디버깅하는 데 유용한 또 다른 도구일 수 있습니다. 각 스레드를 조사하고 문제의 원인을 찾는 더 상호작용적인 방법을 제공합니다.

gdb로 프로세스에 연결하면 해당 프로세스의 표준 작동이 중단됩니다(Sidekiq는 gdb가 연결된 동안 작업을 처리하지 않습니다).

먼저 Sidekiq PID에 연결하여 시작하세요:

gdb -p <sidekiq_pid>

그런 다음 모든 스레드에 대한 정보를 수집하세요:

info threads

# 예시 출력
30 Thread 0x7fe5fbd63700 (LWP 26060) 0x0000003f7cadf113 in poll () from /lib64/libc.so.6
29 Thread 0x7fe5f2b3b700 (LWP 26533) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
28 Thread 0x7fe5f2a3a700 (LWP 26534) 0x0000003f7ce0ba5e in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
27 Thread 0x7fe5f2939700 (LWP 26535) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
26 Thread 0x7fe5f2838700 (LWP 26537) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
25 Thread 0x7fe5f2737700 (LWP 26538) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
24 Thread 0x7fe5f2535700 (LWP 26540) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
23 Thread 0x7fe5f2434700 (LWP 26541) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
22 Thread 0x7fe5f2232700 (LWP 26543) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
21 Thread 0x7fe5f2131700 (LWP 26544) 0x00007fe5f7b570f0 in xmlXPathNodeSetMergeAndClear ()
from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
...

위와 같이 의심스러운 스레드를 볼 수 있으면 더 많은 정보를 얻을 수 있을 것입니다:

thread 21
bt

# 예시 출력
#0  0x00007ff0d6afe111 in xmlXPathNodeSetMergeAndClear () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#1  0x00007ff0d6b0b836 in xmlXPathNodeCollectAndTest () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#2  0x00007ff0d6b09037 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#3  0x00007ff0d6b09017 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#4  0x00007ff0d6b092e0 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#5  0x00007ff0d6b0bc37 in xmlXPathRunEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#6  0x00007ff0d6b0be5f in xmlXPathEvalExpression () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
#7  0x00007ff0d6a97dc3 in evaluate (argc=2, argv=0x1022d058, self=<value optimized out>) at xml_xpath_context.c:221
#8  0x00007ff0daeab0ea in vm_call_cfunc_with_frame (th=0x1022a4f0, reg_cfp=0x1032b810, ci=<value optimized out>) at vm_insnhelper.c:1510

모든 스레드에서 한꺼번에 백트레이스를 출력하려면:

set pagination off
thread apply all bt

gdb 디버깅이 끝나면 프로세스에서 분리하고 종료해야 합니다:

detach
exit

Sidekiq kill signals

TTIN 시그널은 로깅을 위해 백트레이스를 출력하는 시그널로 설명되었지만 Sidekiq는 다른 시그널에도 응답합니다. 예를 들어 TSTP와 TERM을 사용하여 Sidekiq를 정상적으로 종료할 수 있습니다. 자세한 내용은 Sidekiq Signals 문서를 참조하십시오.

블로킹 쿼리 확인

때로는 Sidekiq이 작업을 처리하는 속도가 너무 빨라 데이터베이스 contention을 일으킬 수 있습니다. 위의 백트레이스에서 많은 스레드가 데이터베이스 어댑터에 갇혀있음을 보여줄 때 블로킹 쿼리를 확인하십시오.

PostgreSQL 위키에는 블로킹 쿼리를 확인할 수 있는 쿼리에 대한 세부 정보가 있습니다. 쿼리는 PostgreSQL 버전에 따라 다릅니다. 쿼리 세부 정보는 Lock Monitoring를 참조하십시오.

Sidekiq 대기열 관리

Sidekiq API를 사용하여 Sidekiq에서 여러 문제 해결 단계를 수행할 수 있습니다.

이러한 명령은 관리 목적으로 사용되며 현재 설치의 규모로 인해 관리 인터페이스가 적합하지 않을 때에만 사용해야 합니다.

모든 이러한 명령은 gitlab-rails console을 사용하여 실행해야 합니다.

대기열 크기 보기

Sidekiq::Queue.new("pipeline_processing:build_queue").size

모든 대기 중인 작업 열거

queue = Sidekiq::Queue.new("chaos:chaos_sleep")
queue.each do |job|
  # job.klass # => 'MyWorker'
  # job.args # => [1, 2, 3]
  # job.jid # => jid
  # job.queue # => chaos:chaos_sleep
  # job["retry"] # => 3
  # job.item # => {
  #   "class"=>"Chaos::SleepWorker",
  #   "args"=>[1000],
  #   "retry"=>3,
  #   "queue"=>"chaos:chaos_sleep",
  #   "backtrace"=>true,
  #   "queue_namespace"=>"chaos",
  #   "jid"=>"39bc482b823cceaf07213523",
  #   "created_at"=>1566317076.266069,
  #   "correlation_id"=>"c323b832-a857-4858-b695-672de6f0e1af",
  #   "enqueued_at"=>1566317076.26761},
  # }

  # job.delete if job.jid == 'abcdef1234567890'
end

현재 실행 중인 작업 열거

workers = Sidekiq::Workers.new
workers.each do |process_id, thread_id, work|
  # process_id는 Sidekiq 프로세스마다 고유한 식별자입니다
  # thread_id는 스레드마다 고유한 식별자입니다
  # work는 다음과 같이 보입니다:
  # {"queue"=>"chaos:chaos_sleep",
  #  "payload"=>
  #  { "class"=>"Chaos::SleepWorker",
  #    "args"=>[1000],
  #    "retry"=>3,
  #    "queue"=>"chaos:chaos_sleep",
  #    "backtrace"=>true,
  #    "queue_namespace"=>"chaos",
  #    "jid"=>"b2a31e3eac7b1a99ff235869",
  #    "created_at"=>1566316974.9215662,
  #    "correlation_id"=>"e484fb26-7576-45f9-bf21-b99389e1c53c",
  #    "enqueued_at"=>1566316974.9229589},
  #  "run_at"=>1566316974}],
end

특정 매개변수에 대한 Sidekiq 작업 제거 (파괴적인)

조건에 따라 작업을 중지시키는 일반적인 방법은 다음 명령입니다. 이는 대기 중이지만 시작되지 않은 작업을 제거합니다. 실행 중인 작업은 종료할 수 없습니다.

queue = Sidekiq::Queue.new('<queue name>')
queue.each { |job| job.delete if <condition>}

취소되는 작업에 대한 섹션을 참조하십시오.

위의 방법에서 <queue-name>은 삭제하려는 작업이 포함된 대기열의 이름이고 <condition>은 어떤 작업을 삭제할지 결정합니다.

일반적으로 <condition>은 작업 아규먼트를 참조하며 이는 해당 작업 유형에 따라 다릅니다. 특정 대기열의 아규먼트를 찾으려면 일반적으로 /app/workers/<queue-name>_worker.rb에 위치한 관련 워커 파일의 perform 함수를 확인할 수 있습니다.

예를 들어 repository_import는 작업 아규먼트로 project_id를 갖고 있으며, update_merge_requestsproject_id, user_id, oldrev, newrev, ref를 갖고 있습니다.

아규먼트는 job.args가 Sidekiq 작업에 제공된 모든 아규먼트의 목록이므로 순서 ID로 참조해야 합니다.

다음은 일부 예시입니다:

queue = Sidekiq::Queue.new('update_merge_requests')
# 이 예제에서는 ID가 125이고 ref가 `ref/heads/my_branch`인 어떤 update_merge_requests 작업을 삭제하려고 합니다
queue.each { |job| job.delete if job.args[0] == 125 and job.args[4] == 'ref/heads/my_branch' }
# `RepositoryImportWorker.new.perform_async(100)`와 같은 작업을 취소하는 경우
id_list = [100]

queue = Sidekiq::Queue.new('repository_import')
queue.each do |job|
  job.delete if id_list.include?(job.args[0])
end

특정 작업 ID 삭제 (파괴적인)

queue = Sidekiq::Queue.new('repository_import')
queue.each do |job|
  job.delete if job.jid == 'my-job-id'
end

실행 중인 작업 취소 (파괴적인)

이는 매우 위험한 작업으로 최후의 수단으로 사용해야 합니다. 작업이 실행 중인 경우 데이터 손상이 발생할 수 있으며 적절한 롤백이 구현되지 않을 수 있습니다.

Gitlab::SidekiqDaemon::Monitor.cancel_job('job-id')

이 작업을 수행하려면 SIDEKIQ_MONITOR_WORKER=1 환경 변수로 Sidekiq를 실행해야 합니다.

인터럽트를 수행하기 위해 우리는 Thread.raise를 사용하는데, 이는 Why Ruby’s Timeout is dangerous (and Thread.raise is terrifying)에 언급된 것처럼 여러 단점이 있습니다:

여기서 함의가 흥미롭고 무서운 것을 알 수 있습니다. 이것은 예외가 발생할 수 있다는 것을 의미합니다:

  • 네트워크 요청 중 (주변 코드가 Timeout::Error를 catch하는 것이 준비가 되어 있다면 괜찮음)
  • 네트워크 요청의 정리 중
  • rescue 블록 중
  • 이후에 데이터베이스에 저장하기 위한 객체를 만드는 중
  • 코드 중 어디서든, 이전에 예외를 발생시킬 수 있지 않을지라도

누구도 정말로 모든 줄에서 예외에 대비하는 코드를 작성하지 않습니다. 그것은 심지어 불가능합니다. 그래서 Thread.raise는 사실상 거의 모든 것으로 이어질 수 있는 코드에 대한 의도치 않은 공격과 같습니다. 아마도 모든 상태를 수정하지 않는 순수 함수형 코드라면 문제가 없을 것입니다. 하지만 이것은 루비이기 때문에 그럴 가능성이 적습니다 :)

크론 작업 수동으로 트리거하기

/admin/background_jobs를 방문하여 인스턴스에서 예약/실행/보류 중인 작업을 살펴볼 수 있습니다.

UI에서 “즉시 대기열에 넣기” 버튼을 선택하여 크론 작업을 트리거할 수 있습니다. 프로그래밍 방식으로 크론 작업을 트리거하려면 먼저 Rails 콘솔을 엽니다.

테스트하려는 크론 작업을 찾으려면:

job = Sidekiq::Cron::Job.find('job-name')

# 작업 상태 가져오기:
job.status

# 지금 바로 작업 대기열에 넣기!
job.enque!

예를 들어, 저장소 미러를 업데이트하는 update_all_mirrors_worker 크론 작업을 트리거하려면:

irb(main):001:0> job = Sidekiq::Cron::Job.find('update_all_mirrors_worker')
=>
#<Sidekiq::Cron::Job:0x00007f147f84a1d0
...
irb(main):002:0> job.status
=> "enabled"
irb(main):003:0> job.enque!
=> 257

사용 가능한 작업 목록은 workers 디렉토리에서 찾을 수 있습니다.

Sidekiq 작업에 대한 자세한 정보는 Sidekiq-cron 문서를 참조하십시오.

크론 작업 비활성화

관리자 영역의 모니터링 섹션을 방문하여 Sidekiq 크론 작업을 비활성화할 수 있습니다. 또한 명령줄 및 Rails Runner를 사용하여 동일한 작업을 수행할 수도 있습니다.

모든 크론 작업을 비활성화하려면:

sudo gitlab-rails runner 'Sidekiq::Cron::Job.all.map(&:disable!)'

모든 크론 작업을 활성화하려면:

sudo gitlab-rails runner 'Sidekiq::Cron::Job.all.map(&:enable!)'

한 번에 일부 작업만 활성화하려는 경우 이름 일치를 사용할 수 있습니다. 예를 들어, 이름에 geo가 포함된 작업만 활성화하려면:

sudo gitlab-rails runner 'Sidekiq::Cron::Job.all.select{ |j| j.name.match("geo") }.map(&:disable!)'

Sidekiq 작업 중복성 Idempotency 키 지우기

가끔 기대했던 작업(예: 크론 작업)이 전혀 실행되지 않은 것처럼 보입니다. 로그를 확인할 때 “job_status”: “deduplicated”로 표시된 작업이 실행되지 않은 경우가 있을 수 있습니다.

이는 작업이 실패하고 idempotency 키가 제대로 지워지지 않은 경우 발생할 수 있습니다. 예를 들어, Sidekiq를 중지하면 25초 후에 남아있는 작업이 모두 제거됩니다.

기본적으로 키는 6시간 후에 만료되지만, 즉시 idempotency 키를 지우려면 다음 단계를 따르십시오(제공된 예제는 Geo::VerificationBatchWorker에 대한 것입니다):

  1. Sidekiq 로그에서 작업의 worker 클래스 및 args를 찾습니다:

    { ... "class":"Geo::VerificationBatchWorker","args":["container_repository"] ... }
    
  2. Rails 콘솔 세션을 시작합니다.
  3. 다음 스니펫을 실행합니다:

    worker_class = Geo::VerificationBatchWorker
    args = ["container_repository"]
    dj = Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob.new({ 'class' => worker_class.name, 'args' => args }, worker_class.queue)
    dj.send(:idempotency_key)
    dj.delete!
    

Sidekiq BRPOP 호출에 의한 Redis CPU 포화

Sidekiq BROP 호출은 Redis의 CPU 사용량 증가를 유발할 수 있습니다. Redis의 CPU 사용량을 개선하려면 SIDEKIQ_SEMI_RELIABLE_FETCH_TIMEOUT 환경 변수를 늘리십시오.

오류: OpenSSL::Cipher::CipherError

다음과 같은 오류 메시지를 받는 경우:

"OpenSSL::Cipher::CipherError","exception.message":"","exception.backtrace":["encryptor (3.0.0) lib/encryptor.rb:98:in `final'","encryptor (3.0.0) lib/encryptor.rb:98:in `crypt'","encryptor (3.0.0) lib/encryptor.rb:49:in `decrypt'"

이 오류는 프로세스가 GitLab 데이터베이스에 저장된 암호화된 데이터를 해독할 수 없는 것을 의미합니다. 이는 /etc/gitlab/gitlab-secrets.json 파일에 문제가 있음을 나타내므로 기본 GitLab 노드에서 파일을 Sidekiq 노드로 복사했는지 확인하십시오.

관련 주제