본문 바로가기
카테고리 없음

[TIL 51] 저널링에 대하여.....

by 진득한진드기 2025. 4. 8.

저널링

 

웬만한 사람들은 굳이 겪을 일은 없겠지만 극한의 격리화된 상황에서의 개발시 파일 시스템을 이용시 단지 읽고 쓰고의 방식으로 구현 해놓으면 중간에 시스템에 문제가 갈 때 데이터의 무결성을 지켜주지 못할 확률이 존재한다.

 

우리 운영체제에서도 이와 같은 상황이 존재한다.

 

내가 머리가 안좋아서 잘못된 예시 일 수도 있는데

 

예를 들면 ext4 파일 시스템을 기반으로 하는 상황에서

vi나 vim을 사용해서 특정 파일(text)를 작성한다고 했을 때, 텍스트 파일을 작성하면 해당 프로세스가 메모리 상위로 올라가게되는데 이 상황에서 작성한 텍스트들을 write 명령을 실행하면 디스크에 저장된다.

 

근데 시스템이 중간에 다운되면 write되었던 수정 데이터들은 적용이 안되고 오류가 생겨 파일이 손상 될 수 있다.

그래서 파일을 중간중간 write 될 떄 파일시스템에서 지원하는 저널 파일에 먼저 파일의 메타데이터들을 적용하여 파일이 손상되었을 때도 메타 데이터를 기반으로 수정이 가능하다.

 

이런 개념이 단지 vim 에서만 쓰이는 것이 아니라 우리가 자주 사용하는 Database에 사용된다고 알고 있다....(정확하지 않음)

 

아마 데이터베이스에 데이터가 insert나 update delete등 디스크에 데이터를 직접적으로 건들이는 명령어 사용시, 즉 트랜잭션일 보내지면 트랜잭션 log를 사용해서 나중에 시스템에 다운되거나 충돌되도 트랜잭션 로그를 보고 파일을 백업할 수 있게 한다.

 

 

사설이긴 한데 실제로 요즘 자동저장을 사용하는 굉장히 많은데 나는 자동저장을 사용하지 않는 편이다.

 

가장 중요한 이유는 나름대로 ctrl + s를 누르는 맛이 있는거지만 실제 디스크 I/O에서 wrtie는 코스트가 좀 비싼편이다.

 

그래서 예를들어 용량이 매우큰 파일을 자동저장을 사용하게 되면 디스크 I/O가 빈번하게 일어나서 컴퓨터에 조금 무리가 갈수도있다고 한다... ㅎ

 

실제로 우리 파일은 임시파일(스왑파일) 같은거를 만들어서 이를 둘다 관리하게 되는데 간단하게 흐름을 보자면 아래와 같다.

 

1. 파일 자동으로 수정됨

2. 임시 파일에 적용

3. 임시 파일에 관한 저널파일에 적용

4. 임시파일 디스크에 저장(디스크 I/O 사용)

5.  만약에 vim을 종료할 떄 가 되면 임시파일을 원본 파일과 동기화 후 임시파일을 삭제

6. 원본파일도 저널링 대상이므로 저널 파일에 적용됨.

 

이런방식으로 저장되는데 자동저장하면 특정 주기마다 이벤트를 읽어서 4번 상황이 자주 일어나는데

 

디스크I/O를 주기적으로 사용하고 이는 만약에 파일 용량이 굉장히 크면 엄청 무거운 작업이 된다.

 

간단하게 무거운 작업이다! 라고 생각하면 마음편하지만 이또한 작은 행동들의 집합으로 큰 행동으로 추상화해놓은 거기 때문에 이왕 오랜만에 글을 쓰는김에 길이가 조금 부족하니 더 들어가보자면

 

4번 상황일 때 아래와 같은 일들이 일어난다.

 

dirty page

 

먼저 dirty page를 알고가보자 dirty page는 메모리에 있는 변경된 페이지(아직 디스크에 기록되지 않은) 데이터를 의미한다.
즉, 쓰기(write)는 했지만 아직 디스크에 저장되지 않은 상태를 의미한다.

 

좀전에 디스크에 적용되는 과정은 다음과 같다.

 

설명 전에 어려울 수 있으니 설명하면 페이지 캐시는 리눅스가 I/O 성능을 높이기 위해 사용하는 파일 캐시 메모리 영역을 의미한다.

 

flush 는 dirty page를 디스크에 실제로 반영하는 작업을 의미한다.

 

1. 사용자 공간에서 write() 호출
2. 커널이 페이지 캐시에 저장한다. 
3 .해당 페이지는 dirty 상태가 됨 (dirty page)
4. flush 시점 도래 (or sync 명령, memory pressure 등)
5. 디스크에 실제 write하여 적용한다.
6. dirty flag 제거하고 clean page로 반영 (디스크와 동일한 내용의 페이지라는 뜻)

 

이런 복잡한 과정을 거치는건 

 

효율을 위해서라고 생각하면 된다. OS는 효율의 극치기 때문에.....

 

굳이 flush나 dirty page를 만들어놓은 이유도 바로바로 디스크 I/O로 write하게 되면 오버헤드가 너무 크니까 어느정도 찼을 떄 write()하기 위해서 이다.

 

이해가 안간다고 하면 flush는 dirty page나 너무 많이 쌓였거나 close()가 호출되면 disk에 적용하는 방식을 사용하는데 

이는 전에 가상 메모리를 구현했을 때 와 비슷한 것 처럼 필요해지면 그 때 주는 방식 lazy 방식을 하는 것이다.

즉 lazy-write방식을 사용한다.

 

지금 내가 기억나는 가상 메모리 플로우는 가상 메모리도 할당해놓고 그때 page fault가 나면 page handler에 의해서 필요한 만큼의 메모리를 할당해주는 lazy-allocate를 사용했었던 기억..... 이 존재는 하는데 정확한지는 한번 나중에 다시 봐야겠다.