* 파일(file)에 대한 토막글 (토막글인데 쓰다보니 길어졌다. TL;DR을 참고) 기업체 특강을 가보면 의외로 file의 개념을 절반만 알고 있는 programmer나 system engineer들이 꽤 있었다. 대부분 파일이라고 하면 그냥 TXT나 PDF 같은 데이터가 저장된 파일만 생각하는 경우가 많은데, 그런 경우는 추상적인 개념을 눈에 보이는 부분만 이해한 경우다. 그래서 file에 대해 간단한 상식 글을 가볍게 써볼까 했는데..... 1시간 가까이 쓰게 됐다. 이런... * 이 글을 쓰게된 이유 기업체 특강에서는 다수를 상대로 강의하다보니 모르는 용어나 개념이 나와도 모두들 질문하지 않는 암묵적인 불문율이 있다.(shy programmer) 그래서 강의도중에 아는지 모르는지 아리송할 때가 많다. 원래는 다들 알고 있을거라고 판단해서 file과 memory 개념을 말할 때 용어나 개념은 생략하고 설명을 했었다. 그러다가 최근 몇 년부터 출강하러가면 강의 전후로 시험문제를 출제해달라는 요청이 있어서, 시험 문제에 file/memory에 대해 묻는 문제를 출제 했었다. 그런데 인사팀의 피드백에 의해 file과 memory의 관계에 대해 잘 몰라서 틀리는 분들이 의외로 많았다는 것을 알게되었다. 점수를 주려고 교과서적인 개념을 묻는 문제를 출제했는데 오히려 대부분 틀리는 경우가 많았다는 아이러니가... (오픈북, 인터넷 사용가능인데 의외로 많이 틀린다) 그래서 한 번은 파일에 대해 제대로 글을 써둘까 했었다. 그리고 글을 쓰겠다고 마음 먹은지 한 3년 만에 쓰게 된다. 절대 게을러서 그런게 아니라 그냥 바빠서다. -_-; (사실은 페북에다가 대충 쓰고나서 나중에 블로그에 정리해서 올려놓고, 강의할 때 읽어보라고 하면 편할 것 같아서...) * POSIX (파직스라고 읽는다. 절대로 포식스라고 읽는거 아니다. 번역서에 죄다 포식스라고 적는데 틀린 발음이다) 먼저 file에 대한 이야기 하기 전에 여기서 다루는 개념들은 POSIX 시스템을 기반으로 하는 것들이다. 물론 특수한 목적의 OS(Operating system)를 빼고, 범용 OS 대부분이 POSIX 기반 운영체제이므로 대학의 운영체제론에서 배우는 개념의 구현(implementation)이 바로 POSIX 운영체제라고 간주해도 된다. 사실 OS를 제대로 이해하려면 modern OS의 근간이 되었던 POSIX system에 대해 이해하는 것은 필수코스이기 때문이다. 그리고 특수한 운영체제라고 하더라고 POSIX의 기본 개념을 차용하고 슬림화해서 만드는 경우가 많으므로 POSIX 개념을 알아두는 것은 운영체제 전반을 이해하는데 있어서 굉장히 중요하다. 나는 학교다닐때 운좋게 운영체제론과 UNIX, Linux를 같이 배워서 빠르게 이해할 수 있었던 부분들이 많았다. * 파일(file)이란? 먼저 우리가 탐색기나 파일관리자에서 볼 수 있는 txt, pdf 같은 데이터를 저장하는 파일들은 정식 명칭으로는 regular file이라고 부른다. 그러면 regular file이 아닌 것도 있다고 생각할 수 있을 것이다. 가장 쉽게 볼 수 있는 non-regular file로는 디렉터리(directory)가 있다. 디렉터리는 파일 목록을 담고있는 파일이다. 더 쉽게 추상적으로 설명하면 파일목록을 담고 있는 HTML 파일이라고 간주하면 이해가 쉽다.(당연히 디렉터리는 HTML 파일로 구현된 것은 아니다. 하지만 개념을 이해할 때는 그냥 파일 목록을 담고 있는 hyper text라서 다른 파일로 점프 시켜주는 거라고 생각하면 이해가 빠르다.) 이 외에 특수하게 pipe라든지 socket, 혹은 device들도 전부 file의 종류다. 그러면 왜 file로 만들었을까? 그건 interface의 통일성 때문이다. OS론과 그 외 프로그래밍언어를 공부해보면 interface와 abstraction에 대한 직관을 얻을 수 있을 것이다. * 경로(path) 위에서는 파일의 종류 중에 디렉터리를 이야기 했는데, 이 파일들이 유저의 눈에 보일려면 탐색기나 파일관리자에서 파일이 들어있는 디렉터리로 이동해야 한다. 즉 파일의 정확한 위치 정보는 directory + file name이 되겠다. 이것을 경로(path)라고 부른다. path를 좀더 고상하게 표현하면 file을 외부에서 액세스할 수 있는 접점(interface)이라고 할 수 있다. 이렇게 path가 존재하는 경우를 named file, path가 존재하지 않는 경우를 anonymous file이라고 부른다. 그럼 path가 존재하지 않는 anonymous 파일이 있을까? 외부 탐색기에서 안보이면 anonymous로 생각하면 된다. 가장 쉽게 찾으려면 last | sort 같은 명령을 치면 중간에 보이는 "|" 문자의 구현체가 바로 anonymous pipe라고 불리는 파일이다. last 명령의 실행 결과가 sort로 전달될 때 anonymous pipe 파일을 통해 전달되는데 그 과정에서 anonymous pipe의 path는 존재하지 않는다. 그럼 anonymous pipe말고 path가 있는 named pipe도 존재할까? 당연히 있다. named pipe로 last | sort와 같은 결과를 만들려면 mkfifo /tmp/myfifo; last > /tmp/myfifo &; sort /tmp/myfifo 으로 명령하면 된다. 이렇게하면 named pipe로 /tmp/myfifo를 만들어서 통신할 수 있다. 명령어 실행 후 ls -l /tmp/myfifo 해보면 file attribute에 pipe를 뜻하는 'p'가 표시되는 것을 볼 수 있다. 이것보다 더 직관적으로 last > last.txt; sort last.txt 로 실행해서 last.txt라는 regular file을 생성해서 넘겨줘도 된다.(하지만 뭔가 수준 낮아보이는 것은 기분탓일 수도 있다) 여기서 직관이 있는 사람들은 anonymous는 임시적인 lifetime을 가지는 객체구나~하면서 무릎을 칠 수 있을 것이다. 반대로 named는 persistency를 가지겠구나~하면서 무을 연타할 수 있을 것이다. * anonymous vs named. 그리고 직관이 뛰어난 사람은 이것을 memory의 개념까지 확장할 수 있다. 원래 학교에서 배운 주기억 장치(main memory)는 RAM을 의미한다. 그리고 disk에 존재하는 file을 읽거나 쓰려면 memory에 올라와야 한다는 것을 배웠을 것이다. (locality, memory hierarchy, memory mapped I/O 등등 배울 때 다 배운 내용들이다.) 그러면 process가 실행되어 디스크에 path가 존재하는 file을 읽으면? 바로 named memory가 되는 것이다. 반대로 malloc같은 기능으로 heap memory를 가져오면 이것은 anonymous memory가 된다. 이젠 굳이 설명하지 않아도 왜 그런지 알 것이다. 즉 시스템에서 사용하는 모든 데이터는 외부 액세스의 특징으로 구분지으면 anonymous, named로 분류될 수 있는 것이다. 그래서 /proc/meminfo를 봤을 때 anonymous가 늘어나는 것은 heap memory나 stack같은 것들이 증가했다는 것을 알 수 있게 해주는 것이다. 그러면 간단 퀴즈를 풀어보자. shared memory는 anonymous일까? 아니면 named일까? (찍어도 확률은 1/2이다) 또한 virtual memory로 개념을 확장하면 page in/page out, swap in/swap out까지도 영향을 받는다. (예를 들어 page out은 되지만 swap out은 안되는 경우는?) 덤으로 dirty page의 개념도 named와 연관시켜서 알아두면 큰 그림을 보는데 도움이 될 수 있다. (DB로 따지면 update SQL구문이나 random walking이 왜 더 큰 비용을 발생시키는지도 이해할 수 있게 된다.) 또 network으로 개념을 확장하면 socket 중에 named는 뭐가 있을지도 생각해보면 이해가 빨라진다. ----------------------------------------------------------------- * data, meta data 앞에서는 주로 path의 유무(有無)에 대해서 이야기 했는데 이번에는 조금 다른 이야기를 해보겠다. 예를 들어 디지털 카메라를 이용해서 "우주소녀"가 노래부르는 것을 녹화했다고 가정하자.(우주소녀 팬이라서 예시를 그렇게 들었다고 생각한다면... 맞았다. 팬이다.) 녹화된 영상의 파일명을 "우주소녀.mp4"로 저장했는데, 이 파일을 "BTS.mp4"로 변경했다. 그렇다면 파일명을 우주소녀.mp4에서 BTS.mp4로 바꾸면 영상의 내용이 BTS로 바뀔까? 만일 바뀐다고 대답했다면 심각한 인지오류가 존재하는 것이므로 가까운 병원부터 가봐야 한다. 그러면 파일의 내용은 안바뀌는데 file name은 바뀌었다? 그러면 file name은 어디에 저장되는 것일까라는 의문이 생길 것이다. 안생긴다면 유투브에 가서 BTS영상이나 보자. 여기서 직관이 있는 사람들은 이마를 탁 치면서 data외에 file name을 저장하는 공간이 어딘가 존재하겠구나~라고 생각할 것이다. 실험을 위해 "touch 우주소녀.txt" 라고 명령을 내려 파일을 생성해보자. "stat 우주소녀.txt"로 확인 해보면 access time (atime), modify file(mtime), change time(ctime)이 보이는데 처음에는 다 동일한 값이다. 그러나 우주소녀.txt를 방탄소년단.txt로 이름을 변경하면 ctime만 바뀐다. 그러나 우주소녀.txt에 내용을 추가한 뒤에 보면 mtime, ctime이 모두 바뀐다. 즉 mtime은 data의 변경 시간을 보여주는 것이고, ctime은 meta data가 변경되었다는 것을 보여주는 것이다. 그런데 내용을 변경하면 왜 mtime, ctime이 다 변경될까? 이해를 했다면 즉시 답이 나올 것이다. 참고로 이 부분이 좀 더 궁금해지면 i-node와 hard link에 대해서 공부해보면 POSIX 시스템의 구조에 대해 좀 더 깊이 알 수 있다. * data, meta data : process 그럼 이번에는 process로 무대를 넓혀보자. 예를 들어 chrome web browser 아이콘을 클릭하면 매번 크롬 브라우저가 실행될 것이다. chrome 실행했는데 firefox가 실행되지는 않을거다. 즉 chrome 실행 파일을 가리키는 path의 파일을 실행하면 항상 동일한 binary file과 부가적인 파일들을 로딩한다는 것이다.(물론 재실행일 때는 disk로부터 읽기는 생략되고 사본인 memory로부터 가져온다.) 하지만 pid(Process ID)라든지 user id, 실행권한 같은 정보들은 매번 바뀐다. 그럼 pid같은 정보는 어디에 저장되는 것일까? 즉 process도 meta영역이 따로 있다는 것이다. 결론적으로 모든 data는 그 데이터를 관리하기 위해 meta data가 어딘가에는 존재해야 한다. 이 둘은 별개로 취급된다. (이 관계를 잘 이해하면 zombie process가 왜 defunct process(현존하지 않는 프로세스)라고 불리는지도 이해할 수 있다.) 덧붙여서 깨진 파일을 복구하면 왜 파일명이 제대로 안나오고 무슨 일련번호 붙여서 나오는지도 이해할 수 있을 것이다. 그러면 돌발 퀴즈를 하나 해보자. 10테라 바이트의 정보를 저장할 때 파일 1개로 저장하는 것이 효율적일까? 아니면 1TB짜리 10개로 저장하는게 효율적일까? 그것도 아니면 10MB짜리 1백만개로 저장하는 것이 효율적일까? * 잡담 POSIX 시스템을 이해하려면 file이라는 추상적 개념을 이해하는게 중요한데, file에 대해 이해가 깊지 못해서 짠밥에서 우러나오는 통밥스킬(i.e. perception)이 생기지 않는 경우를 많이 봐왔다. 추상적 개념을 제대로 이해하면 하나를 보면 최소한 둘이상을 직관으로 깨닫게 되므로 새로운 인터페이스나 기술이 나온다고 하더라도 통밥스킬에 의해 자연스럽게 이해하거나 빠르게 습득 할 수 있게 된다. 이는 마치 고전을 많이 읽어서 직관이 생긴 사람들은 다른 인문 서적이나 과학 서적을 볼 때 책이 담고 있는 메시지를 빠르게 간파할 수 있는 것과 비슷하다. 뛰어난 프로그래머나 엔지니어가 되려면 직관이 필요한데, 직관을 키우는데는 알고리즘으로 논리력을 키우는 것도 중요하지만, 그 알고리즘과 데이터구조가 왜 나왔는지 인과관계를 이해해야 한다. 수십년동안 대가들은 컴퓨터가 좀 더 빠르게 작동하도록 노력해왔는데, 그 노력의 정점에는 운영체제가 있다. 따라서 운영체제를 어떻게 구현했는지 이해하는 것은 매우 중요하다. 그래서 운영체제 친화적인 프로그래밍 기술은 아무나 할 수 있는게 아니다. (웃픈 건 인터넷에 나와있는 잘못된 기법을 사용해서 순정 상태보다 더 느리게 만드는 경우도 있는데, 이게 다 운영체제의 이해부족이다.) 만일 1천대의 서버를 운영하는 회사에서 운영체제, 네트워크를 제대로 이해해서 5%만이라도 최적화된 서비스를 만들면 회사는 대략 50대를 감축할 수 있다. 반대로 논리력은 있지만 직관이 없어서 겨우 20% 더 느린 시스템을 만들면 회사는 수백대의 서버를 더 확보해야 한다. 이것은 cost 상승을 가져오고, 경쟁사에 의해 망할 수도 있는 결과를 가져온다. * TL;DR file은 추상적인 interface이다. path의 유무에 따라 anonymous, named가 있다. memory도 path를 가진 backed file의 유무에 따라 anonymouse, named(filebacked)로 나뉠 수 있다. file은 data, meta data가 따로 관리된다. 이걸 잘 이해하면 character 능력치 중에 perception skill이 +1 된다. 이 문서는 구양진경처럼 베이스 내공을 1칸 정도는 올려줄 것이다.