2P by neo 27일전 | favorite | 댓글 1개

파이프가 "멈추는" 이유: 버퍼링

  • 문제 설명: 로그 파일에서 특정 출력을 찾기 위해 tail -f /some/log/file | grep thing1 | grep thing2 명령어를 실행할 때, 로그 라인이 느리게 추가되면 출력이 나타나지 않는 문제 발생. 이는 파이프가 멈추는 것처럼 보이지만 실제로는 프로그램이 데이터를 파이프에 쓰지 않기 때문임.

버퍼링의 원인

  • 버퍼링의 이유: 프로그램이 데이터를 파이프나 파일에 쓰기 전에 버퍼링을 하는 것이 일반적임. 이는 성능 향상을 위해 모든 출력을 즉시 쓰는 대신, 일정량의 데이터를 모아서 한 번에 쓰기 때문임.
  • 예시: grep thing1은 8KB의 데이터를 모을 때까지 매칭된 데이터를 저장하고, 이로 인해 출력이 나타나지 않을 수 있음.

터미널에 쓸 때는 버퍼링하지 않음

  • 터미널과 파이프의 차이: grep은 출력이 터미널로 향할 때는 라인 버퍼링을 사용하지만, 파이프로 향할 때는 블록 버퍼링을 사용함. 이는 isatty 함수를 통해 결정됨.

버퍼링하는 명령어와 하지 않는 명령어

  • 버퍼링하지 않는 명령어: tail, cat, tee 등은 버퍼링하지 않음.
  • 버퍼링하는 명령어: grep, sed, awk, tcpdump, jq, tr, cut 등은 버퍼링하며, 일부는 특정 플래그로 버퍼링을 비활성화할 수 있음.

프로그래밍 언어의 기본 출력 버퍼링

  • 버퍼링하는 언어: C, Python, Ruby, Perl 등은 기본적으로 출력 버퍼링을 하며, 특정 방법으로 비활성화 가능함.

Ctrl-C를 눌렀을 때 버퍼 내용 손실

  • 문제 설명: Ctrl-C를 누르면 버퍼에 있는 내용이 손실됨. 이는 SIGINT 신호가 먼저 전달되기 때문임.
  • 해결책: tcpdump의 PID를 찾아 kill -TERM $PID를 실행하면 버퍼를 플러시할 수 있음.

파일로 리다이렉션할 때도 버퍼링

  • 파일 리다이렉션: 파일로 리다이렉션할 때도 버퍼링이 발생하지만, Ctrl-C로 인한 버퍼 손실 문제는 발생하지 않음.

버퍼링을 피하는 여러 방법

  • 해결책 1: 빠르게 종료되는 프로그램 실행.
  • 해결책 2: grep--line-buffered 플래그 사용.
  • 해결책 3: awk 사용.
  • 해결책 4: stdbuf 사용.
  • 해결책 5: unbuffer 사용.

버퍼링을 비활성화하는 환경 변수

  • 아이디어: PYTHON_UNBUFFERED와 같은 표준 환경 변수가 있으면 좋겠다는 의견. NO_BUFFER와 같은 변수를 제안함.

생략된 내용

  • 생략된 주제: 라인 버퍼링과 완전한 비버퍼링의 차이, stderr와 stdout의 버퍼링 차이, 운영 체제의 TTY 드라이버 버퍼링 등.
Hacker News 의견
  • 버퍼링된 접근은 일정 바이트 수나 시간이 지나면 플러시해야 함. 하드웨어 인터페이스에서 유사한 문제를 해결하는 일반적인 방법임

    • 사용자 공간에서 버퍼링하는 라이브러리는 데이터를 처음 버퍼링할 때 적절한 타이머를 설정해야 함
    • 타임아웃 파라미터는 인수로 전달하거나, 인간의 시간 척도보다 약간 낮거나, 대역폭/임계값에 비례하거나, 플러싱 오버헤드에 비례하는 것이 좋음
    • 쓰기와 읽기 모두에 적용되며, 데이터 채널에 따라 다를 수 있음
  • 시스템 전체 CPU가 유휴 상태가 되면 모든 버퍼를 플러시하고 싶음

    • 버퍼링은 일반적으로 CPU 절약 기법임
    • CPU가 유휴 상태가 되면 모든 프로세스에 "버퍼를 플러시하라"는 신호를 보내야 함
  • NIX 시스템을 20년 이상 다뤘지만, 버퍼링 문제를 항상 잊어버림

  • Unix를 35년 이상 사용했지만 버퍼링 작동 방식을 완전히 이해하지 못했음. 이 설명이 유익했음

  • "비버퍼링"과 "라인 버퍼링"을 혼동하고 있음

    • 비버퍼링은 성능을 저하시킬 수 있으며, 여러 소스가 동일한 파이프에 쓰는 경우 잘못된 출력을 생성할 수 있음
    • 라인 버퍼링은 터미널의 기본값이며, 파이프에 적합함
  • 버퍼는 화면에 출력을 인쇄하는 것보다 버퍼에 쓰는 것이 상대적으로 매우 느리기 때문에 존재함

    • UART 작업 시 자주 발생하는 문제이며, 다양한 해결책이 있음
    • 특수 문자 사용, 길이 기반 접근, 시간 기반 접근 등 다양한 방법이 있음
  • Ctrl-C를 누르면 버퍼 내용이 손실될 수 있음

    • 대부분의 프로그램은 SIGINT에서 버퍼를 플러시할 것이라고 생각함
  • Unix에서 버퍼링 문제를 겪었으며, 모든 'awk' 구현이 동일하게 작동하지 않음

  • 얼어붙은 파이프 농담을 놓친 기분임