명명된 파이프를 사용할 때 좀비 프로세스를 피하는 방법은 무엇입니까?

명명된 파이프를 사용할 때 좀비 프로세스를 피하는 방법은 무엇입니까?

우리는 일반적으로 제어 연산자를 사용하여 백그라운드에서 FIFO 파일에 쓰기를 수행합니다 &. 아래와 같은 것.

if [ ! -p "/tmp/mysqld.init" ]; then
    mkfifo /tmp/mysqld.init
fi

echo "something" > /tmp/mysqld.init &

exec mysqld --init-file=/tmp/mysqld.init

그러나 fifo 파일을 읽으면 echo프로세스가 좀비 프로세스가 됩니다. 그것을 피하는 방법?

노트이 스크립트는 Docker 진입점 스크립트이며 적합한 좀비 처리기가 없습니다. Mysqld는 항상 pid 1을 사용합니다. 다음과 같습니다.

  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    1     0 mysql    S     383m  19%   0   0% mysqld --init-file=/tmp/mysqld.init
   40     0 root     R     1532   0%   1   0% top
    7     1 root     Z        0   0%   0   0% [entrypoint.sh]

어쩌면 tini를 ​​docker의 init 시스템으로 사용할 수도 있지만, 그것 없이 어떻게 할 수 있을까요? 이중 교잡?

답변1

Bourne Shell 또는 Bash를 사용하면 trap명명된 파이프를 닫을 수 있습니다. 예를 들어:

#!/bin/sh
set -eu
trap 'close_fifo; echo 1>&2 "!!! Unexpected signal termination."; exit 66' HUP TERM INT STOP

LOG_PATH="/tmp/acme.log"
touch "{$LOG_PATH}"

# Setup fifo and pipe input to log file with tee
FIFO=$(mktemp -u);
mkfifo $FIFO
tee -ia "{$LOG_PATH}" < $FIFO &

# Capture tee's process ID for the wait command.
TEE_PID=$!
# Redirect the rest of the stderr and stdout to our named pipe.
exec > $FIFO 2>&1

log() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*"; }

close_fifo() {
    # close the stderr and stdout file descriptors.
    exec 1>&- 2>&-

    # Wait for tee to finish since now that other end of the pipe has closed.
    [ -n $TEE_PID ] && wait $TEE_PID

    rm -f $FIFO
}

main() {
  // ---
  // Main procedure here...
}

main
close_fifo

그러면 모든 신호가 포착되고 종료 신호의 파이프가 닫힙니다. 모든 표준 출력/오류는 명명된 파이프를 사용하여 파일에 기록됩니다.

Fifo 처리 참조:https://superuser.com/a/86961/252171

답변2

문제는놀랍게도 더 복잡하다대부분의 사람들이 예상했던 것보다 더 많습니다.

간단히 말해서, init를 사용하거나 init에 대한 대체 항목을 작성하여 수집 및 다운스트림 신호 전파를 구현하거나 데이터를 mysqld에 전달하는 새로운 방법을 찾거나 이를 수락하는 방법을 찾아야 합니다(이를 위해서는 좀비 생성에 대한 이해와 제한이 필요함) 비율).

좀비 프로세스는 상위 프로세스가 종료 상태를 수집(가져오기)하지 않을 때 나타납니다. exec현재 프로세스(쉘)를 자식 프로세스로부터 상속받지 않으려는 mysqld로 교체합니다.

mysqld를 백그라운드에서 시작하고 자식을 가져오기 위해 쉘 스크립트를 그대로 놔두면 수신된 신호를 mysqld에 전파하고 응답을 기다려야 합니다. 그렇게 하지 않으면 쉘 스크립트가 종료될 때 mysql이 정상적으로 종료되지 않게 됩니다. 이런 종류의 수확과 번식이 대개의 작업입니다 init.

다음과 같이 읽기 핸들을 열면 즉시 echo를 종료할 수 있습니다.

echo "something" > /tmp/fifo &
exec 3< /tmp/fifo

...하지만 이로 인해 새로운 문제가 발생합니다. 일반적으로 echoFIFO는 닫혀 있지만 지금은 닫힐 수 없습니다. 너무 빨리 종료됩니다. 이는 mysql이 읽는 동안 차단됨을 의미합니다. 비차단 읽기를 수행하고 시간 제한 등을 구현하는 것이 가능하지만 mysql은 아마도 --init-file일반 파일처럼 동작할 것으로 예상하므로 그렇지 않을 것이라고 가정할 수 있습니다.

마지막 선택은 그것과 함께 사는 것입니다. 1개의 프로세스 또는 100개의 프로세스에 대해 이야기하고 있다면 문제가 없습니다. 그러나 프로세스 테이블은 유한하며 각 좀비 프로세스는 해당 항목 중 하나를 소비합니다. 좀비 수를 관리하지 않고 프로세스 테이블이 가득 차면 새로운 프로세스가 생성되지 않습니다.

내가 링크한 블로그 게시물에는 좋은 세부 정보가 많이 포함되어 있으며 정확한 문제를 해결하기 위해 작성자가 만든 작은 초기화 교체가 삽입되어 있습니다.

관련 정보