inotifywait, 파이프 및 버퍼에 대해 알아보기

inotifywait, 파이프 및 버퍼에 대해 알아보기

디렉토리의 모든 파일 변경 사항을 모니터링하고 싶습니다 inotifywait. inotifywaitFIFO 버퍼에 기록해야 하며 그런 다음 정상적으로 읽을 수 있습니다. 상대적으로 많은 수의 이벤트를 시도하는 동안 이해하고 싶은 병목 현상이 몇 가지 발생했습니다.

변화는 항상 에 의해 발생합니다 touch {0000..9999}testfile. 병목 현상은 모든 파일 이벤트를 캡처할 수 없다는 것입니다.

출력을 파일로 리디렉션 하면 inotifywait모든 것이 예상대로 기록됩니다.

inotifywait -q -m ./쓰기 터미널은 약 5000~8000개의 파일에 대해 CREATE, OPEN, ATTRIB, CLOSE를 캡처합니다. "화면에 쓰기"가 비차단이 될 만큼 빠르지 않은 것 같나요?

cat( ) 로 파이프하면 inotifywait... | cat | ... | cat어느 시점에 그 모든 항목이 종료됩니다. 그래서 나는 파이프가 버퍼인 것 같지만 그것이 어떻게 작동하는지, 심지어 무엇을 찾아야 하는지조차 잘 이해하지 못합니다. 누군가 이것을 설명할 수 있나요?

나는 또한 여기에서 찾은 "솔루션"을 사용했습니다. pv -q -B 1g버퍼(또는 ) 로 사용됩니다 buffer.

inotifywait -q -m ./ | BUFFER | \
while read line; do
   # Do something with $line or ...
   sleep 1
done

모든 파일 이벤트가 처리되었는지 확인하는 방법은 무엇입니까? 나는 bash 부두에 관한 나의 작은 게임이 더 깊은 한계를 발견했다는 느낌을 받았고, 그것에 대해 더 많은 통찰력을 갖고 싶습니다.

답변1

출력이 inotifywait -q -m ./리디렉션되지 않고 터미널 에뮬레이터에서 실행되면 출력은 pty 장치로 이동됩니다. 장치는 pty파이프와 다소 비슷하지만 터미널과 같은 상호 작용을 촉진하는 기능이 추가된 프로세스 간 통신의 한 형태입니다.

그 pty 반대편에"관로", 터미널 에뮬레이터는 inotifywait작성된 내용을 읽고 화면에 렌더링합니다. 렌더링은 복잡하고 CPU 시간을 차지합니다.

터미널 에뮬레이터가 파이프를 채우는 것보다 느리게 파이프를 비우는 경우 inotifywait, pty관로당신은 가득 차게 될 것입니다. 파이프처럼 가득 차면 write()메모리에 다시 사용 가능한 공간이 생길 때까지 쓰기 프로세스가 차단됩니다(시스템 호출이 반환되지 않음)."관로".

내 Linux 버전에서는 한 번에 1바이트씩 쓰면 다른 쪽 끝이 차단되기 전에 아무것도 읽지 않고도 pty 장치에 19457바이트를 쓸 수 있다는 것을 발견했습니다.

$ socat -u  'exec:dd bs=1 if=/dev/zero,pty' 'exec:sleep inf,nofork' &
[1] 1247815
$ pkill -USR1 -x dd
19458+0 records in
19457+0 records out
19457 bytes (19 kB, 19 KiB) copied, 14.7165 s, 1.3 kB/s

한 번에 2바이트를 쓰면 19458바이트이고, 한 번에 256바이트를 쓰면 19712바이트입니다. 터미널을 원시 모드로 설정하거나 전송된 데이터에 개행 문자를 포함하면(CRLF로 변환되기 때문입니다) 그러면 다른 값이 됩니다.

어쨌든 버퍼 크기를 사용자 정의할 수는 없다고 생각합니다.

inotifywait사용inotify이벤트 목록을 검색하기 위한 API입니다. inotify(7)매뉴얼 페이지 에서 다음을 찾을 수 있습니다:

다음 인터페이스를 사용하여 inotify가 소비하는 커널 메모리 양을 제한할 수 있습니다.

  • /proc/sys/fs/inotify/max_queued_events

    이 파일의 값은 애플리케이션이 inotify_init(2)를 호출하여 해당 Inotify 인스턴스에 대기할 수 있는 이벤트 수의 상한을 설정할 때 사용됩니다. 이 제한을 초과하는 이벤트는 삭제되지만 IN_Q_OVERFLOW 이벤트는 항상 생성됩니다.

표준 출력이 inotifywait차단 되면 write()커널이 이 대기열에 넣는 이벤트를 처리할 수 없습니다. 대기열 자체가 가득 차면 이벤트가 삭제됩니다.

내 시스템에서는

$ sysctl fs.inotify.max_queued_events
fs.inotify.max_queued_events = 16384

이제 이렇게 하면:

inotifywait -q -m ./ | cat

이번에는 와 사이에 파이프가 있고 inotifywait터미널 에뮬레이터 cat사이에는 pty가 있습니다.cat

파이프는 각 파이프에서 ptys(Linux에서는 기본적으로 64KiB이지만 사용할 수 있음)보다 큰 버퍼를 가지며 이를 fs.pipe-max-sizesysctl 값(기본적으로 1MiB) 으로 높입니다 fcntl(fd, F_SETPIPE_SZ, newsize).

그러므로 우리는 inotifywait' 블록 write()앞에 이 두 버퍼를 채워야 합니다 . 또한 cat일부 데이터는 자체 읽기 버퍼에서 읽혀지고 기록될 때까지 기다립니다.

콘텐츠를 추가할 때마다 | cat추가 버퍼 공간(최소 64KiB 이상)을 추가합니다.

사용하면 pv -q -B 1g데이터 pv가 내부적으로 버퍼링됩니다.

이는 입력을 처리하는 데 훨씬 적은 작업을 수행해야 하기 때문에 터미널 에뮬레이터보다 더 빠르게 입력을 읽지 cat만 충분히 빠르게 읽거나 디코딩하거나 형식화할 수 없는 경우 일부 이벤트를 삭제할 수 있습니다.pvinotifywait

이벤트가 삭제될 가능성을 최소화하려면 다음을 수행할 수 있습니다.

  • 증가하다fs.inotify.max_queued_events
  • 느린 소비자에게 출력을 보내지 않거나 inotifywait이 경우 충분한 버퍼링을 추가하십시오.
  • 필터를 조정하여 inotifywait관심 있는 이벤트만 선택하세요.
  • inotifywait출력 소비자에게 낮은 우선순위가 부여되지 않도록(no niceing) 확인하십시오 .

관련 정보