1. 개요
얼마 전 파일 디스크립터에 대해 설명한 적이 있다.
오늘은 관련 명령어인 lsof를 간단히 소개하고자 한다. lsof는 list open files라는 뜻으로, 흔히 [엘에스오브]라고 발음하는 것 같다. 외국에서는 어떻게 발음하는지 아시는 분 있으면 제보 좀…
리눅스/유닉스 계열에서는 일반 파일뿐 아니라 디렉터리, 라이브러리, 파이프, 소켓까지 “열린 파일”로 취급된다. 그래서 lsof는 단순히 어떤 파일을 누가 쓰는지 확인하는 용도뿐 아니라, 특정 포트를 점유한 프로세스나 파일 디스크립터 사용량을 확인할 때도 유용하다.
2. 설치
우선 yum을 이용하여 설치해 보도록 하자.
# yum install lsof Loaded plugins: fastestmirror Determining fastest mirrors * base: ftp.daumkakao.com * extras: ftp.daumkakao.com * updates: ftp.daumkakao.com base | 3.7 kB 00:00 extras | 3.4 kB 00:00 extras/primary_db | 37 kB 00:00 updates | 3.4 kB 00:00 updates/primary_db | 2.6 MB 00:00 Setting up Install Process Resolving Dependencies --> Running transaction check ---> Package lsof.x86_64 0:4.82-5.el6 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================================================================== Package Arch Version Repository Size ================================================================================================================================== Installing: lsof x86_64 4.82-5.el6 base 324 k Transaction Summary ================================================================================================================================== Install 1 Package(s) Total download size: 324 k Installed size: 900 k Is this ok [y/N]: y Downloading Packages: lsof-4.82-5.el6.x86_64.rpm | 324 kB 00:00 Running rpm_check_debug Running Transaction Test Transaction Test Succeeded Running Transaction Installing : lsof-4.82-5.el6.x86_64 1/1 Verifying : lsof-4.82-5.el6.x86_64 1/1 Installed: lsof.x86_64 0:4.82-5.el6 Complete!
배포판에 따라 패키지 관리자는 다를 수 있다. 예를 들어 Debian/Ubuntu 계열에서는 보통 apt로 설치한다.
# apt install lsof
3. 실행
그럼 설치된 lsof를 실행해 보자.
# lsof COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME init 1 root cwd DIR 253,1 4096 2 / init 1 root rtd DIR 253,1 4096 2 / init 1 root txt REG 253,1 150352 917532 /sbin/init init 1 root mem REG 253,1 65928 393290 /lib64/libnss_files-2.12.so init 1 root mem REG 253,1 1921176 393227 /lib64/libc-2.12.so init 1 root DEL REG 253,1 393560 /lib64/libgcc_s-4.4.7-20120601.so.1;5761fb6c init 1 root mem REG 253,1 43880 393562 /lib64/librt-2.12.so init 1 root mem REG 253,1 142640 393251 /lib64/libpthread-2.12.so init 1 root mem REG 253,1 265728 393311 /lib64/libdbus-1.so.3.4.0 init 1 root mem REG 253,1 39896 393431 /lib64/libnih-dbus.so.1.0.0 init 1 root mem REG 253,1 101920 393433 /lib64/libnih.so.1.0.0 init 1 root mem REG 253,1 154624 393306 /lib64/ld-2.12.so init 1 root 0u CHR 1,3 0t0 3643 /dev/null init 1 root 1u CHR 1,3 0t0 3643 /dev/null init 1 root 2u CHR 1,3 0t0 3643 /dev/null init 1 root 3r FIFO 0,8 0t0 6488 pipe init 1 root 4w FIFO 0,8 0t0 6488 pipe init 1 root 5r DIR 0,10 0 1 inotify init 1 root 6r DIR 0,10 0 1 inotify init 1 root 7u unix 0xffff880037999680 0t0 6489 @/com/ubuntu/upstart init 1 root 8u unix 0xffff880037fe0380 0t0 424583 socket init 1 root 9u unix 0xffff88007c86a980 0t0 7715 socket
옵션 없이 실행하면 시스템에서 열려 있는 파일 목록이 많이 출력된다. 권한이 부족하면 일부 항목이 보이지 않을 수 있으므로, 운영 상황을 확인할 때는 필요에 따라 root 권한으로 실행한다.
4. 해독
4-1. 주요 컬럼
- COMMAND: 파일을 열고 있는 명령 또는 프로세스 이름
- PID: 프로세스 ID
- USER: 프로세스를 실행한 사용자
- FD: 파일 디스크립터 정보
- TYPE: 파일의 종류
- DEVICE, SIZE/OFF, NODE, NAME: 장치 번호, 크기/오프셋, inode, 파일 또는 소켓 이름
4-2. FD의 의미는 다음과 같다
- cwd: 현재 디렉터리
- rtd: 루트 디렉터리
- txt: 실행 중인 프로그램의 텍스트 파일
- mem: 메모리 매핑된 파일
- mmap: 메모리 매핑된 장치
- NUMBER: 파일 디스크립터 번호. 숫자 뒤의
r은 read,w는 write,u는 read/write를 의미한다.
4-3. TYPE의 의미는 다음과 같다
- REG: 일반 파일
- DIR: 디렉터리
- FIFO: 선입선출 파이프
- CHR: 캐릭터 특수 파일
- IPv4, IPv6: 네트워크 소켓
- unix: 유닉스 도메인 소켓
5. 명령어
특정 프로세스가 사용 중인 파일 디스크립터 수를 간단히 세고 싶다면 다음처럼 확인할 수 있다.
$ lsof -p 프로세스ID | wc -l
- 해당 프로세스가 사용하고 있는 열린 파일 목록의 줄 수를 센다.
- 헤더 한 줄도 포함되므로, 정확히 FD 개수만 계산하려면 그 점을 감안해야 한다.
- 이 값은 일반적으로
ulimit -a에서 확인할 수 있는 open files 제한값의 영향을 받는다. - 프로세스가 제한값에 근접할 정도로 파일 디스크립터를 많이 사용하면 새 파일이나 소켓을 열지 못해 장애나 성능 저하의 원인이 될 수 있다.
현재 셸에 적용된 open files 제한은 다음과 같이 확인할 수 있다.
$ ulimit -n
6. 실전
6-1. 특정 파일을 사용하는 프로세스 찾기
이번에는 특정 파일을 찾아보자. /usr/sbin/apache2를 찾는 예이다.
# lsof /usr/sbin/apache2 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME apache2 9651 root txt REG 253,1 474776 921962 /usr/sbin/../lib/apache2/mpm-worker/apache2 apache2 14428 www-data txt REG 253,1 474776 921962 /usr/sbin/../lib/apache2/mpm-worker/apache2 apache2 14429 www-data txt REG 253,1 474776 921962 /usr/sbin/../lib/apache2/mpm-worker/apache2 apache2 14430 www-data txt REG 253,1 474776 921962 /usr/sbin/../lib/apache2/mpm-worker/apache2
6-2. 특정 디렉터리 하위 파일 찾기
이번에는 특정 디렉터리 하위 파일을 찾는 것이다.
# lsof +D /usr/sbin COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME rsyslogd 414 syslog txt REG 253,1 384440 654108 /usr/sbin/rsyslogd sshd 612 root txt REG 253,1 517112 659298 /usr/sbin/sshd vsftpd 634 root txt REG 253,1 159880 653691 /usr/sbin/vsftpd acpid 836 root txt REG 253,1 43792 666185 /usr/sbin/acpid atd 837 daemon txt REG 253,1 23152 665363 /usr/sbin/atd cron 838 root txt REG 253,1 44320 657705 /usr/sbin/cron ntpd 1148 ntp txt REG 253,1 671176 658483 /usr/sbin/ntpd sshd 16409 root txt REG 253,1 517112 659298 /usr/sbin/sshd sshd 17254 root txt REG 253,1 517112 659298 /usr/sbin/sshd sshd 17255 sshd txt REG 253,1 517112 659298 /usr/sbin/sshd
+D는 하위 디렉터리까지 훑기 때문에 대상 경로가 크면 시간이 오래 걸릴 수 있다. 범위를 좁힐 수 있다면 특정 파일이나 더 작은 디렉터리를 지정하는 편이 좋다.
6-3. 특정 프로세스 이름으로 찾기
이번에는 특정 프로세스명으로 검색해 보자.
# lsof -c apache2 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME apache2 9651 root cwd DIR 253,1 4096 2 / apache2 9651 root rtd DIR 253,1 4096 2 / apache2 9651 root txt REG 253,1 474776 921962 /usr/lib/apache2/mpm-worker/apache2 apache2 9651 root mem REG 253,1 105288 391710 /lib/x86_64-linux-gnu/libresolv-2.15.so apache2 9651 root mem REG 253,1 31104 391718 /lib/x86_64-linux-gnu/libnss_dns-2.15.so apache2 9651 root mem REG 253,1 52120 391721 /lib/x86_64-linux-gnu/libnss_files-2.15.so apache2 9651 root mem REG 253,1 47680 391720 /lib/x86_64-linux-gnu/libnss_nis-2.15.so apache2 9651 root mem REG 253,1 97248 391707 /lib/x86_64-linux-gnu/libnsl-2.15.so apache2 9651 root mem REG 253,1 35680 391722 /lib/x86_64-linux-gnu/libnss_compat-2.15.so
이 옵션은 아래와 같이 중복 사용이 가능하다.
# lsof -c apache2 -c ssh (생략) sshd 612 root mem REG 253,1 149280 391714 /lib/x86_64-linux-gnu/ld-2.15.so sshd 612 root 0u CHR 1,3 0t0 4856 /dev/null sshd 612 root 1u CHR 1,3 0t0 4856 /dev/null sshd 612 root 2u CHR 1,3 0t0 4856 /dev/null sshd 612 root 3u IPv6 7783 0t0 TCP *:ssh (LISTEN) sshd 612 root 4u IPv4 7788 0t0 TCP *:ssh (LISTEN) sshd 612 root 6r FIFO 0,8 0t0 98449668 pipe apache2 9651 root cwd DIR 253,1 4096 2 / apache2 9651 root rtd DIR 253,1 4096 2 / apache2 9651 root txt REG 253,1 474776 921962 /usr/lib/apache2/mpm-worker/apache2 apache2 9651 root mem REG 253,1 105288 391710 /lib/x86_64-linux-gnu/libresolv-2.15.so apache2 9651 root mem REG 253,1 31104 391718 /lib/x86_64-linux-gnu/libnss_dns-2.15.so apache2 9651 root mem REG 253,1 52120 391721 /lib/x86_64-linux-gnu/libnss_files-2.15.so apache2 9651 root mem REG 253,1 47680 391720 /lib/x86_64-linux-gnu/libnss_nis-2.15.so apache2 9651 root mem REG 253,1 97248 391707 /lib/x86_64-linux-gnu/libnsl-2.15.so (생략)
6-4. 특정 사용자로 찾기
특정 사용자로도 검색할 수 있다.
# lsof -u www-data COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME apache2 14428 www-data cwd DIR 253,1 4096 2 / apache2 14428 www-data rtd DIR 253,1 4096 2 / apache2 14428 www-data txt REG 253,1 474776 921962 /usr/lib/apache2/mpm-worker/apache2 apache2 14428 www-data mem REG 253,1 105288 391710 /lib/x86_64-linux-gnu/libresolv-2.15.so apache2 14428 www-data mem REG 253,1 31104 391718 /lib/x86_64-linux-gnu/libnss_dns-2.15.so apache2 14428 www-data mem REG 253,1 52120 391721 /lib/x86_64-linux-gnu/libnss_files-2.15.so apache2 14428 www-data mem REG 253,1 47680 391720 /lib/x86_64-linux-gnu/libnss_nis-2.15.so apache2 14428 www-data mem REG 253,1 97248 391707 /lib/x86_64-linux-gnu/libnsl-2.15.so apache2 14428 www-data mem REG 253,1 35680 391722 /lib/x86_64-linux-gnu/libnss_compat-2.15.so apache2 14428 www-data mem REG 253,1 22528 921141 /usr/lib/apache2/modules/mod_status.so apache2 14428 www-data mem REG 253,1 14336 921077 /usr/lib/apache2/modules/mod_setenvif.so apache2 14428 www-data mem REG 253,1 14344 921122 /usr/lib/apache2/modules/mod_reqtimeout.so apache2 14428 www-data mem REG 253,1 34824 921123 /usr/lib/apache2/modules/mod_negotiation.so apache2 14428 www-data mem REG 253,1 18432 921940 /usr/lib/apache2/modules/mod_mime.so apache2 14428 www-data mem REG 253,1 10240 921140 /usr/lib/apache2/modules/mod_env.so apache2 14428 www-data mem REG 253,1 10240 921121 /usr/lib/apache2/modules/mod_dir.so
참고로 lsof -u ^www-data로 실행하면 www-data 사용자만 제외하고 결과를 보여준다. 즉 exclude 조건이다.
6-5. PID로 찾기
이번에는 PID로 검색해 보자.
# lsof -p 9651 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME apache2 9651 root cwd DIR 253,1 4096 2 / apache2 9651 root rtd DIR 253,1 4096 2 / apache2 9651 root txt REG 253,1 474776 921962 /usr/lib/apache2/mpm-worker/apache2 apache2 9651 root mem REG 253,1 105288 391710 /lib/x86_64-linux-gnu/libresolv-2.15.so apache2 9651 root mem REG 253,1 31104 391718 /lib/x86_64-linux-gnu/libnss_dns-2.15.so apache2 9651 root mem REG 253,1 52120 391721 /lib/x86_64-linux-gnu/libnss_files-2.15.so apache2 9651 root mem REG 253,1 47680 391720 /lib/x86_64-linux-gnu/libnss_nis-2.15.so apache2 9651 root mem REG 253,1 97248 391707 /lib/x86_64-linux-gnu/libnsl-2.15.so apache2 9651 root mem REG 253,1 35680 391722 /lib/x86_64-linux-gnu/libnss_compat-2.15.so apache2 9651 root mem REG 253,1 22528 921141 /usr/lib/apache2/modules/mod_status.so apache2 9651 root mem REG 253,1 14336 921077 /usr/lib/apache2/modules/mod_setenvif.so apache2 9651 root mem REG 253,1 14344 921122 /usr/lib/apache2/modules/mod_reqtimeout.so apache2 9651 root mem REG 253,1 34824 921123 /usr/lib/apache2/modules/mod_negotiation.so apache2 9651 root mem REG 253,1 18432 921940 /usr/lib/apache2/modules/mod_mime.so apache2 9651 root mem REG 253,1 10240 921140 /usr/lib/apache2/modules/mod_env.so apache2 9651 root mem REG 253,1 10240 921121 /usr/lib/apache2/modules/mod_dir.so apache2 9651 root mem REG 253,1 92720 391908 /lib/x86_64-linux-gnu/libz.so.1.2.3.4
6-6. 특정 포트를 열고 있는 프로세스 찾기
마지막으로 특정 포트를 열고 있는 프로세스를 찾아보자.
# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME apache2 9651 root 3u IPv4 55344500 0t0 TCP *:http (LISTEN) apache2 14429 www-data 3u IPv4 55344500 0t0 TCP *:http (LISTEN) apache2 14430 www-data 3u IPv4 55344500 0t0 TCP *:http (LISTEN)
LISTEN 상태의 TCP 포트만 보고 싶다면 다음처럼 조건을 조금 더 좁힐 수 있다.
# lsof -iTCP -sTCP:LISTEN