앞서 언급했듯이 Arbiter는 Gunicorn 마스터 프로세스의 핵심입니다. Arbiter는 작업자 프로세스 시작, 모니터링 및 종료를 포함하여 작업자 프로세스를 관리하는 일을 주로 담당합니다. 동시에 Arbiter는 특정 신호가 발생할 때 앱 애플리케이션을 핫 업데이트(다시 로드)하거나 온라인으로 gunicorn을 업그레이드할 수도 있습니다. Arbiter의 핵심 코드는 하나의 파일에 들어 있으며, 코드 양은 많지 않습니다. 소스 코드는 https://github.com/benoitc/gunicorn입니다.
Arbiter에는 주로 다음과 같은 방법이 있습니다.
setup:
구성 항목을 처리하는데, 가장 중요한 것은 작업자 수와 작업자 작업 모델입니다.
init_signal:
신호 처리 기능 등록
handle_xxx :
각 신호의 특정 처리 기능
kill_worker, kill_workers:
작업자 프로세스에 신호 보내기
spawn_worker,spawn_workers:
새 작업자 프로세스를 포크합니다
murder_workers:
일정 시간 내에 응답하지 않는 작업자 프로세스 종료
manage_workers:
구성 파일의 작업자 수와 현재 활성 작업자 수를 기반으로 작업자 프로세스를 분기할지 종료할지 결정합니다.
reexec :
신호 SIGUSR2 호출 수신, 온라인 업그레이드 gunicorn
reload:
신호 SIGHUP 호출을 받은 후 작업자 프로세스는 새로운 구성에 따라 시작되고 이전 작업자 프로세스는 종료됩니다
sleep :
신호 처리가 없는 경우 선택 타임아웃을 사용하여 잠자기하고 깨울 수 있습니다.
wakeup:
파이프에 메시지를 작성하여 프로세스를 깨우고
run:
메인 루프
실제로 다른 코드(애플리케이션)에 의해 Arbiter가 호출되는 유일한 함수는 __init_ _이며 코드 한 문장에서 실행 메서드는 다음과 같습니다.
Arbiter(self).run()
위 코드의 self는 애플리케이션 인스턴스입니다. , 여기서 __init__는 setup을 호출하여 구성 항목을 설정합니다. 다음은 실행 메소드의 의사 코드입니다
def run() self.init_signal() self.LISTENERS = create_sockets(self.cfg, self.log) self.manage_workers() while True: if no signal in SIG_QUEUE self.sleep() else: handle_signal()
포크 하위 프로세스에 대해
포크 하위 프로세스에 대한 코드는spawn_worker에 있으며, 소스 코드는 다음과 같습니다.
Arbiter.spawn_worker
기본 프로세스:
(1) Worker_class 로드 및 인스턴스화(기본값은 동기 모델 SyncWorker)
(2) 상위 프로세스(마스터 프로세스)는 포크 후 반환되고 모든 후속 로직은 하위에서 실행됩니다. process
(3) Worker.init_process를 호출하여 루프, 새 채널에 들어갑니다. IELTS 훈련의 모든 작업은 이 루프에 있습니다.
(4) 루프가 끝난 후 sys.exit(0)
을 호출합니다. (5) 마지막으로 , 마지막으로 작업자 프로세스의 종료를 기록합니다.
다음은 메인 포크 프로세스를 단순화하기 위해 작은 코드를 작성한 것입니다.
1 # prefork.py 2 import sys 3 import socket 4 import select 5 import os 6 import time 7 8 def do_sub_process(): 9 pid = os.fork()10 if pid < 0:11 print 'fork error'12 sys.exit(-1)13 elif pid > 0:14 print 'fork sub process %d' % pid15 return16 17 # must be child process18 time.sleep(1)19 print 'sub process will exit', os.getpid(), os.getppid()20 sys.exit(0)21 22 def main():23 sub_num = 224 for i in range(sub_num):25 do_sub_process()26 time.sleep(10)27 print 'main process will exit', os.getpid()28 29 if __name__ == '__main__':30 main()
테스트 환경에서의 출력:
fork sub 프로세스 9601
fork 하위 프로세스 9602
하위 프로세스는 9601 9 600
하위 프로세스는 9602 9600
기본 프로세스는 9600
을 종료합니다. 라인 20은 sys.exit을 호출합니다. 보장하다 하위 프로세스가 종료됩니다. 그렇지 않으면 기본 함수의 for 루프와 후속 논리가 계속됩니다. 19행을 주석 처리하고 다시 실행하면 출력을 보면 이해할 수 있습니다.
자식 프로세스 종료에 대하여
마스터 프로세스가 작업자 프로세스를 종료하는 것은 매우 간단하며 직접 신호를 보내기만 하면 됩니다. 소스 코드는 다음과 같습니다.
1 def kill_worker(self, pid, sig): 2 """\ 3 Kill a worker 4 5 :attr pid: int, worker pid 6 :attr sig: `signal.SIG*` value 7 """ 8 try: 9 os.kill(pid, sig)10 except OSError as e:11 if e.errno == errno.ESRCH:12 try:13 worker = self.WORKERS.pop(pid)14 worker.tmp.close()15 self.cfg.worker_exit(self, worker)16 return17 except (KeyError, OSError):18 return19 raise
잠자기 및 wakeup
Arbiter sleep과 wakeup을 살펴보겠습니다. Arbiter는 처리할 신호가 없을 때 "sleep"합니다. 물론 실제로 time.sleep을 호출하지 않습니다. 그렇지 않으면 신호가 오면 즉시 처리되지 않습니다. 여기서 구현은 파이프와 선택 시간 초과를 사용하여 더 영리합니다. 코드를 보면 알 수 있습니다
def sleep(self): """\ Sleep until PIPE is readable or we timeout. A readable PIPE means a signal occurred. """ ready = select.select([self.PIPE[0]], [], [], 1.0) # self.PIPE = os.pipe() if not ready[0]: return while os.read(self.PIPE[0], 1): pass
코드의 주석은 매우 명확합니다. PIPE는 읽을 수 있고 즉시 반환되거나 대기 시간이 초과됩니다. 신호가 발생하기 때문에 파이프를 읽을 수 있습니다. 파이프 함수를 살펴보세요
os.
pipe
() os.
pipe
()
Create a pipe. Return a pair of file descriptors (r,w)
(r, w)
는 각각 읽기 및 쓰기에 사용할 수 있습니다.
그런 다음 파이프를 읽을 수 있는 경우를 살펴보겠습니다. 파이프에 기록된 내용이어야 합니다. 이것은 wakeup 함수
def wakeup(self): """ Wake up the arbiter by writing to the PIPE """ os.write(self.PIPE[1], b'.')
마지막으로 Arbiter 신호 처리를 연결합니다.
: Exit, INT: 빠른 종료 🎜🎜TERM: 우아한 종료. 시간이 초과될 때까지 작업자가 현재 요청을 완료할 때까지 기다립니다. 🎜HUP: 구성을 다시 로드하고, 새로운 구성으로 새 작업자 프로세스를 시작하고, 이전 작업자 프로세스를 정상적으로 종료합니다. Gunicorn은 애플리케이션이 사전 로드되지 않은 경우에도 새 버전을 로드합니다(--preload 옵션 사용).
TTIN: 프로세스 수를 하나씩 늘립니다.
TTOU: 프로세스 수를 하나씩 줄입니다.
USR1: 로그 파일을 다시 엽니다.
USR2: 즉시 Gunicorn을 업그레이드합니다. 이전 프로세스를 종료하려면 별도의 용어 신호를 사용해야 합니다. 이 신호는 사전 로드된 새 버전의 애플리케이션을 사용하는 데에도 사용될 수 있습니다.
Winch: Gunicorn이 데몬화되면 작업자 프로세스를 정상적으로 종료합니다.
위 내용은 Gunicorn Arbiter 소스 코드를 분석하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!