파일 시스템은 NAND를 얼마나 배려해야 하는가: FAT에서 출발하기

오늘의 질문

앞선 글에서 SSD 펌웨어가 NAND의 제약을 호스트에게 숨긴다는 것을 봤다. 덮어쓰기가 안 되니 다른 자리에 쓰고 지도를 고치고, 무효 페이지가 쌓이면 청소한다. 호스트는 이 사정을 모른 채 그냥 쓴다.

그런데 여기서 실무적인 질문이 하나 나온다.

펌웨어가 다 알아서 해준다면 파일 시스템은 신경 쓸 게 없는 것 아닌가? 위쪽에서 어떻게 쓰든 아래쪽이 정리해줄 텐데, 왜 파일 시스템을 NAND에 맞춰 조정한다는 이야기가 나오는가?

답은 이렇다. 펌웨어는 제약을 숨길 수는 있어도 비용을 없애지는 못한다. 위에서 어떻게 쓰느냐에 따라 아래에서 치르는 비용이 몇 배씩 달라진다. 이 글은 그 연결고리를 FAT이라는 가장 단순한 파일 시스템으로 따라가 본다.

먼저 답하기

세 문장으로 줄이면 이렇다.

파일 시스템은 데이터만 쓰는 게 아니라 메타데이터를 함께 갱신하는데, 이 갱신은 작고 잦고 한곳에 몰린다. 앞 글에서 본 대로 NAND가 가장 싫어하는 패턴이다. 그래서 최적화의 방향은 셋이다 — 경계를 맞추고(정렬), 안 쓰는 영역을 알려주고(TRIM), 순서를 지켜 깨지지 않게 만든다(저널링).

여기서 메타데이터(metadata)란 파일의 내용이 아니라 파일에 관한 정보를 말한다. 이름, 크기, 어느 위치에 흩어져 있는지 같은 것들이다. 파일 하나를 만들면 내용만 저장되는 게 아니라 이 정보들도 함께 기록되어야 한다.

주제에 맞는 핵심 설명

FAT은 무엇인가

FAT(File Allocation Table)은 1977년경 등장해 MS-DOS와 초기 윈도우에서 쓰인 파일 시스템이다. 지금도 SD 카드, USB 메모리, 각종 임베디드 기기에서 널리 쓰인다. 구조가 단순해서 구현 부담이 적기 때문이다.

이름이 곧 핵심 자료구조다. FAT은 “어느 칸이 어느 파일에 속하는지”를 적어둔 표 하나를 중심으로 동작한다.

여기서 새 용어 하나가 필요하다. 클러스터(cluster)는 파일 시스템이 공간을 배분하는 최소 단위다. 섹터 여러 개를 묶은 덩어리이며, 마이크로소프트의 FAT 규격 문서를 정리한 자료들에 따르면 클러스터당 섹터 수로 허용되는 값은 1, 2, 4, 8, 16, 32, 64, 128이다. 섹터가 512 B라면 클러스터는 512 B부터 64 KiB까지가 된다.

파일이 1 바이트든 3 KB든, 클러스터가 4 KiB라면 클러스터 하나를 통째로 차지한다. 파일 시스템은 클러스터보다 작은 단위로 공간을 나눠주지 않는다.

볼륨은 어떻게 생겼고, 파일 하나를 어떻게 찾는가

위쪽은 FAT 볼륨이 예약 영역과 FAT 영역과 데이터 영역으로 나뉜 구조를 보여주고, 아래쪽은 파일을 읽을 때 디렉터리 엔트리에서 시작 클러스터 번호를 얻어 FAT 표를 따라 다음 클러스터를 계속 찾아가며 데이터 영역의 조각들을 이어붙이는 과정을 보여주는 그림

이 그림이 없으면 “FAT 표를 따라간다”는 말이 무슨 동작인지 감이 오지 않는다. 순서를 짚어보자.

볼륨은 크게 세 구역으로 나뉜다. 예약 영역에는 부트 섹터가 있고 그 안의 BPB(BIOS Parameter Block)에 클러스터 크기, FAT 개수, 각 영역의 위치 같은 설정값이 들어 있다. FAT 영역에는 표 본체가 있는데, 마이크로소프트 규격 기준으로 이 표는 보통 사본 2개가 유지된다. 데이터 영역에는 실제 파일 내용과 디렉터리 엔트리가 클러스터 단위로 늘어서 있다.

이제 REPORT.TXT를 읽어보자.

  1. 디렉터리 엔트리를 찾는다. 디렉터리 엔트리에는 이름, 속성, 크기, 그리고 첫 클러스터 번호가 들어 있다. 여기서는 5번이라고 하자.
  2. FAT 표를 따라간다. 5번 칸을 보면 다음 클러스터 번호가 적혀 있다. 9번이다. 9번 칸을 보면 12번이다. 12번 칸에는 EOC(End of Cluster chain) 표시가 있다. 여기서 사슬이 끝난다.
  3. 데이터 영역에서 조각을 읽는다. 5번, 9번, 12번 클러스터를 순서대로 읽어 이어붙이면 파일 전체가 된다.

FAT 표는 결국 연결 리스트를 배열로 구현한 것이다. 각 칸에 “다음 칸 번호”를 적어두는 방식이다. 그리고 클러스터 번호에서 실제 위치를 구하는 식도 규격에 정해져 있다. 대략 첫 데이터 섹터 + (번호 − 2) × 클러스터당 섹터 수 형태로, 번호에서 2를 빼는 이유는 0번과 1번이 예약되어 있기 때문이다.

여기서 주목할 점이 있다. 파일의 위치 정보가 한 곳에 모여 있지 않다. 디렉터리 엔트리는 첫 번호만 알려주고, 나머지 순서는 FAT 표를 한 칸씩 따라가야 한다. 그래서 파일 하나를 읽어도 FAT 영역과 데이터 영역을 번갈아 접근하게 된다.

파일을 새로 만들면 어디에 쓰기가 생기는가

새 파일을 만들 때 빈 클러스터를 찾아 데이터를 기록하고 FAT 표에 사슬을 연결한 뒤 디렉터리 엔트리를 만들어 시작 번호를 적는 다섯 단계를, 각 단계가 어느 영역에 쓰기를 발생시키는지와 함께 보여주는 그림

읽기보다 중요한 것이 쓰기다. NAND 관점의 문제가 여기서 드러나기 때문이다.

9 KB 파일 하나를 만든다고 하자. 클러스터가 4 KiB이므로 클러스터 3개가 필요하다.

  1. 빈 클러스터를 찾는다. FAT 표에서 값이 0인 칸을 찾는다. 5번, 9번, 12번을 확보했다고 하자.
  2. 데이터를 기록한다. 확보한 클러스터에 파일 내용을 쓴다. 데이터 영역 쓰기 3회.
  3. FAT 사슬을 연결한다. 5번 칸에 9를, 9번 칸에 12를, 12번 칸에 EOC를 적는다. FAT 영역 쓰기가 발생하고, 사본이 2개면 두 번 쓴다.
  4. 디렉터리 엔트리를 만든다. 부모 디렉터리에 이름, 크기, 시작 번호를 적는다. 디렉터리도 클러스터에 담긴 데이터이므로 데이터 영역 쓰기 1회.

여기서 NAND 입장의 문제가 나온다. 2번의 데이터 쓰기는 파일마다 다른 위치로 흩어진다. 그런데 3번의 FAT 갱신은 항상 같은 좁은 구역에 몰린다. 파일을 만들 때마다, 지울 때마다, 크기가 바뀔 때마다 그 구역이 다시 갱신된다.

작고 잦은 갱신이 한곳에 쏠리는 패턴. 앞 글에서 본 쓰기 증폭이 가장 나빠지는 조건이다. 게다가 FAT 칸 하나는 4 바이트인데 NAND 페이지는 KB 단위이므로, 4 바이트를 고치려고 페이지 하나를 통째로 다시 쓰게 된다.

클러스터 크기 선택도 여기 얽혀 있다. 클러스터를 작게 잡으면 같은 파일에 필요한 FAT 칸이 늘어나 갱신량이 커지고, 크게 잡으면 작은 파일이 큰 덩어리를 통째로 차지해 공간이 낭비된다(내부 단편화). 어느 쪽도 공짜가 아니다.

최적화 1: 경계를 맞춘다

위쪽은 파티션이 63섹터에서 시작해 클러스터 경계가 낸드 페이지 경계와 어긋나 클러스터 하나를 쓸 때 페이지 두 개를 건드리는 상황을 보여주고, 아래쪽은 1MiB 정렬로 두 경계가 맞아떨어져 페이지 하나만 쓰면 되는 상황을 보여주는 그림

가장 먼저 손볼 것은 정렬(alignment)이다.

정렬이란 위층의 경계와 아래층의 경계를 포개는 것을 말한다. 파일 시스템의 클러스터 경계가 NAND 페이지 경계와 어긋나 있으면, 클러스터 하나를 쓸 때 페이지 두 개를 건드리게 된다.

왜 어긋나는가. 파티션이 시작하는 위치 때문이다. 과거 PC에서는 첫 파티션이 63번 섹터에서 시작하는 것이 관행이었다. 계산해보면 이렇다.

63 × 512 B = 32,256 B = 31.5 KiB
32,256 ÷ 4,096 = 7.875   →  나누어떨어지지 않는다

31.5 KiB는 4 KiB의 배수가 아니다. 그래서 그 위에 얹힌 클러스터가 전부 3.5 KiB씩 밀린 채로 놓인다. 4 KiB 클러스터 하나가 예외 없이 페이지 두 개에 걸친다.

반면 요즘 표준인 2048번 섹터 시작은 이렇게 된다.

2048 × 512 B = 1,048,576 B = 1 MiB
1,048,576 ÷ 4,096 = 256   →  정확히 나누어떨어진다

1 MiB를 쓰는 이유는 어지간한 값으로 다 나누어떨어지기 때문이다. 4 KiB 페이지든 16 KiB 페이지든, 2 MiB 소거 블록이든 전부 1 MiB의 약수이거나 배수 관계가 성립한다. 장치마다 다른 내부 구조를 몰라도 안전한 값을 고른 셈이다. 관련 자료들에 따르면 이 1 MiB 정렬은 2009년 무렵 윈도우 7과 리눅스 커널 2.6.31 이후 주요 운영체제 설치 프로그램의 기본값이 되었다.

얼마나 차이 나는지 계산해보자.

가정 — NAND 페이지 4 KiB, 클러스터 4 KiB, 논리 섹터 512 B. 클러스터 하나를 갱신하는 상황.

항목 63섹터 시작 (어긋남) 2048섹터 시작 (1 MiB 정렬)
파티션 시작 오프셋 32,256 B (31.5 KiB) 1,048,576 B (1 MiB)
페이지 크기로 나눈 나머지 3,584 B 0
앞 8개 클러스터 중 경계를 걸치는 개수 8 / 8 0 / 8
4 KiB 갱신 시 건드리는 페이지 2개 1개
필요한 동작 두 페이지 각각 읽고-고치고-쓰기 한 페이지 쓰기
물리 쓰기량 8 KiB 4 KiB
쓰기 증폭 2.0 1.0

적용 한계 — 이 2배는 “클러스터가 페이지와 같은 크기이고 매번 경계를 걸친다”는 조건에서의 값이다. 클러스터가 페이지보다 크면 걸치는 비율이 달라지고, 장치 내부에서 여러 쓰기를 모아 처리하면 실제 영향이 줄어들 수 있다. 반대로 매핑 단위보다 작은 쓰기는 더 나빠진다. 예를 들어 매핑 단위가 4 KiB인데 512 B 하나만 쓰면 4096 ÷ 512 = 8배가 된다. 실제 수치는 장치 구성과 워크로드에 따라 달라지므로, 정렬은 확실히 손해를 막는 조치로 이해하는 편이 정확하다.

정렬은 클러스터 크기 선택과 함께 봐야 한다. 클러스터를 페이지 크기의 배수로 잡고, 파티션을 1 MiB 경계에서 시작하면 위아래 경계가 자연스럽게 포개진다. 여기에 더해 FAT 영역 자체의 시작 위치도 정렬 대상이 될 수 있다.

최적화 2: 안 쓰는 영역을 장치에 알려준다

두 번째는 TRIM이다.

문제 상황부터 보자. 파일을 지우면 무슨 일이 일어나는가. 파일 시스템은 FAT 표의 해당 칸들을 0으로 되돌리고 디렉터리 엔트리를 지움 표시한다. 데이터 영역은 건드리지 않는다. 지울 필요가 없기 때문이다.

그런데 SSD 입장에서는 이게 문제가 된다. 앞 글에서 본 대로 펌웨어는 논리 주소가 어디에 매핑되는지만 알 뿐, 그 논리 주소의 내용이 아직 의미가 있는지는 모른다. 파일 시스템이 “이제 안 쓴다”고 판단한 클러스터도, 펌웨어에게는 여전히 유효한 데이터다.

결과가 무엇인가. 가비지 컬렉션이 돌 때 이미 죽은 데이터를 살아 있는 줄 알고 새 블록으로 복사한다. 앞 글에서 계산한 유효 비율 u가 실제보다 높게 잡히고, 쓰기 증폭이 그만큼 커진다.

TRIM은 이 간극을 메우는 명령이다. 파일 시스템이 “이 논리 주소 범위는 이제 안 쓴다”고 장치에 알려주면, 펌웨어는 해당 페이지를 즉시 무효로 표시할 수 있다. ATA에서는 DATA SET MANAGEMENT 명령의 TRIM 기능으로, NVMe에서는 Dataset Management 명령의 Deallocate로 제공된다. 리눅스에서는 discard라는 이름으로 더 자주 불린다.

효과를 앞 글의 계산에 대입하면 이렇다.

상황 희생 블록의 유효 비율 u 호스트 1페이지당 물리 쓰기
TRIM 없음 — 지워진 파일도 유효로 집계 0.90 10.00
TRIM 적용 — 지워진 파일이 무효로 반영 0.50 2.00

가정과 한계 — 위 u 값은 “삭제된 데이터가 블록의 상당 부분을 차지하는 상황”을 보여주기 위한 예시이며 측정값이 아니다. 실제 개선 폭은 삭제 패턴, 오버프로비저닝 비율, 장치의 TRIM 처리 방식에 따라 달라진다. 다만 방향은 분명하다. TRIM은 GC가 옮겨야 할 유효 페이지 수를 줄인다.

실무에서 짚을 점 두 가지가 있다. 첫째, TRIM은 파일 시스템과 운영체제가 지원해야 동작한다. 지원하지 않으면 장치는 삭제 사실을 영영 알 수 없다. 둘째, TRIM 명령 자체도 비용이 있어서, 삭제할 때마다 즉시 보내는 방식과 주기적으로 모아 보내는 방식이 나뉜다. 어느 쪽이 유리한지는 워크로드에 따라 다르다.

최적화 3: 순서를 지켜 깨지지 않게 만든다

위쪽은 저널 없이 메타데이터와 데이터를 직접 갱신하다가 전원이 끊기면 어느 쪽이 반영되었는지 알 수 없는 상황을 보여주고, 아래쪽은 저널 영역에 먼저 기록하고 커밋 마크를 남긴 뒤 본 영역에 반영하고 저널을 정리하는 다섯 단계를 보여주는 그림

세 번째는 성능이 아니라 신뢰성 문제다.

앞의 파일 생성 절차를 다시 보자. 데이터를 쓰고, FAT을 고치고, 디렉터리 엔트리를 만든다. 여러 번의 쓰기가 필요하다. 그런데 이 중간에 전원이 끊기면 어떻게 되는가.

세 가지 나쁜 상태가 가능하다.

  • 데이터만 쓰이고 메타데이터가 안 쓰인 경우: 클러스터에 내용은 있는데 아무도 그걸 참조하지 않는다. 공간만 잡아먹는 유령 클러스터가 된다.
  • 메타데이터만 쓰이고 데이터가 안 쓰인 경우: 파일 목록에는 보이는데 열어보면 쓰레기 값이 나온다. 더 위험한 쪽이다.
  • 한 클러스터가 절반만 쓰인 경우: 내용이 반만 맞는 파일이 된다.

문제의 본질은 여러 번의 쓰기가 “전부 되거나 전혀 안 되거나”로 묶여 있지 않다는 데 있다.

트랜잭션과 ACID

이 문제를 다루는 개념이 데이터베이스 쪽에서 왔다. 트랜잭션(transaction)이란 여러 동작을 하나의 덩어리로 묶어, 통째로 성공하거나 통째로 없던 일이 되게 만드는 단위다. 그 성질을 네 글자로 정리한 것이 ACID다.

글자 이름 파일 시스템에서는
A 원자성 (Atomicity) 전부 되거나 전혀 안 되거나 파일 생성의 네 단계가 통째로 반영되거나 아예 안 되거나
C 일관성 (Consistency) 규칙이 깨진 상태로 남지 않음 사슬이 끊긴 FAT, 참조 없는 클러스터가 생기지 않음
I 격리성 (Isolation) 동시에 진행되는 작업끼리 간섭하지 않음 두 프로세스가 같은 디렉터리를 고쳐도 뒤엉키지 않음
D 지속성 (Durability) 완료됐다고 답한 것은 살아남음 쓰기 완료 응답 후 전원이 끊겨도 내용이 남아 있음

여기서 파일 시스템이 가장 신경 쓰는 것은 A와 D다. 특히 원자성이 없으면 위의 세 가지 나쁜 상태를 막을 방법이 없다.

저널링과 선행 기록

저널(journal)이란 본 영역을 고치기 전에 “무엇을 어떻게 고칠 것인지”를 먼저 적어두는 별도의 기록 공간이다. 회계 장부에서 분개장을 먼저 쓰고 총계정원장에 옮기는 것과 발상이 같다.

이 방식을 선행 기록(write-ahead logging, WAL)이라 부른다. 이름 그대로 “먼저 로그를 쓰고 나중에 본 영역을 고친다”는 순서를 지킨다는 뜻이다. 순서는 이렇다.

  1. 쓰기 요청이 도착한다. 무엇을 어떻게 바꿀지 계획이 정해진다.
  2. 저널 영역에 기록한다. 이 시점에 본 영역은 아직 그대로다.
  3. 커밋 마크를 남긴다. “저널 기록이 온전히 끝났다”는 표시다.
  4. 본 영역에 반영한다. 계획대로 실제 메타데이터를 고친다.
  5. 저널 영역을 정리한다. 기록을 버리고 공간을 되돌린다.

이 순서가 왜 안전한가. 어느 지점에서 끊기든 복구 판단이 가능하기 때문이다.

  • 3번 이전에 끊겼다면 커밋 마크가 없다. 계획이 완결되지 않았다는 뜻이므로 저널 내용을 버린다. 본 영역은 손대지 않았으니 이전 상태 그대로 안전하다.
  • 3번 이후, 4번 도중에 끊겼다면 커밋 마크가 있다. 무엇을 할지가 저널에 온전히 남아 있으므로 다시 읽어 마저 반영한다.

핵심은 커밋 마크 하나가 “되돌릴 것인가 밀어붙일 것인가”의 분기점 역할을 한다는 데 있다. 그리고 4번의 재실행이 안전하려면 같은 작업을 여러 번 반복해도 결과가 같아야 한다. 복구 도중에 또 끊길 수 있기 때문이다.

NAND 입장에서의 대가도 짚어야 한다. 저널링은 같은 내용을 두 번 쓴다. 저널에 한 번, 본 영역에 한 번이다. 신뢰성을 얻는 대신 쓰기량이 늘어난다. 그래서 실무에서는 무엇을 저널에 넣을지를 선택한다. 메타데이터만 저널링하고 데이터는 직접 쓰는 방식이 흔히 쓰이는데, 이러면 파일 구조는 깨지지 않지만 파일 내용은 일부 손실될 수 있다. 데이터까지 저널링하면 더 안전하지만 쓰기량이 그만큼 늘어난다.

참고로 FAT 자체에는 저널 기능이 없다. 그래서 FAT 볼륨은 갑작스러운 전원 차단에 취약하고, 잃어버린 클러스터를 찾아 정리하는 검사 도구가 별도로 필요하다. 임베디드 환경에서 FAT을 쓸 때 저널링을 얹은 변형이나 다른 파일 시스템을 검토하는 이유가 여기에 있다.

세 가지를 한자리에 놓으면

최적화 무엇을 줄이는가 어디를 손보는가 대가
정렬 경계 걸침으로 인한 읽기-수정-쓰기 파티션 시작 위치, 클러스터 크기 포맷 시점에 정해야 함
TRIM GC가 옮기는 죽은 데이터 파일 시스템·OS 지원, 발행 정책 명령 자체의 처리 비용
저널링 전원 차단 시 깨지는 상태 쓰기 순서와 저널 범위 같은 내용을 두 번 씀

앞의 둘은 쓰기량을 줄이는 방향이고, 마지막 하나는 쓰기량을 늘려서 안전을 사는 방향이다. 방향이 반대라는 점이 중요하다. 세 가지를 동시에 최대로 밀어붙일 수는 없고, 어디까지 안전을 사고 어디부터 성능을 지킬지 결정해야 한다. 그 판단 기준은 데이터가 깨졌을 때의 피해다.

자주 묻는 질문

클러스터 크기는 어떻게 정하는 게 좋은가요? 두 가지를 함께 봐야 한다. 하나는 아래쪽 경계와의 관계다. 클러스터를 NAND 페이지 크기의 배수로 잡으면 정렬이 유지되므로, 페이지가 4 KiB인 장치에서 4 KiB나 8 KiB 클러스터가 무난하다. 다른 하나는 파일 크기 분포다. 작은 파일이 대부분이면 큰 클러스터는 낭비가 크고, 큰 파일 위주면 작은 클러스터는 FAT 갱신량만 늘린다. 실무에서는 저장할 파일의 평균 크기를 먼저 확인하고, 그 다음 장치의 페이지·소거 블록 크기에 맞춰 조정하는 순서가 편하다. 다만 클러스터 크기는 포맷할 때 정해지므로 나중에 바꾸려면 다시 포맷해야 한다.

정렬이 어긋났는지 어떻게 확인하나요? 파티션의 시작 섹터 번호를 보면 된다. 512 B 섹터 기준으로 첫 파티션이 2048번 섹터에서 시작하면 1 MiB 정렬이다. 63번처럼 애매한 값이면 어긋났을 가능성이 높다. 리눅스에서는 parted의 정렬 확인 기능이나 fdisk -l의 시작 섹터 열로 볼 수 있다. 주의할 점은 오래된 디스크 복제 도구로 섹터 단위 복사를 하면 예전 오프셋이 그대로 따라온다는 것이다. HDD에서 SSD로 옮길 때 이 함정에 빠지기 쉽다.

TRIM을 켰는데도 성능이 안 나아지는 이유가 뭘까요? 몇 갈래로 나눠 볼 수 있다. 첫째, 삭제할 데이터가 애초에 적으면 TRIM이 알려줄 것도 없다. 지속적으로 쓰기만 하는 워크로드가 여기 해당한다. 둘째, TRIM 발행 정책 문제다. 주기적으로 모아 보내는 방식이라면 다음 주기 전까지는 장치가 모르는 상태로 남는다. 셋째, 병목이 다른 데 있을 수 있다. 앞 글에서 봤듯 드라이브가 거의 꽉 차 있으면 GC가 고를 블록 자체가 나쁘므로, TRIM으로 개선되는 폭이 제한된다. 이 경우는 여유 공간을 늘리는 쪽이 먼저다.

저널링을 쓰면 SSD 수명이 줄어드나요? 같은 내용을 두 번 쓰므로 쓰기량 자체는 늘어난다. 다만 저널링 대상을 메타데이터로 한정하면 늘어나는 양은 전체 쓰기의 일부에 그친다. 메타데이터는 원래 데이터보다 훨씬 작기 때문이다. 그리고 저널 영역은 순차적으로 채워지고 통째로 재사용되는 패턴이라, 앞 글의 계산에 비춰보면 GC 관점에서는 오히려 다루기 좋은 형태다. 정리하면 쓰기량 증가는 사실이지만, 그 대가로 얻는 것과 비교해 판단할 문제다. 전원이 불안정한 환경이라면 저널링 없이 얻은 수명이 큰 의미가 없다.

FAT 대신 다른 파일 시스템을 쓰면 이 문제들이 해결되나요? 일부는 그렇고 일부는 아니다. 저널링을 갖춘 파일 시스템을 쓰면 전원 차단 문제는 구조적으로 다뤄진다. 로그 구조 방식처럼 아예 덮어쓰지 않고 순차적으로만 기록하는 설계는 NAND의 성질과 잘 맞기도 한다. 하지만 정렬과 TRIM은 어떤 파일 시스템을 쓰든 여전히 확인해야 하는 항목이다. 그리고 FAT을 쓰는 이유가 대개 호환성과 구현 단순성이라면, 그 요구가 남아 있는 한 파일 시스템 교체가 답이 아닐 수 있다. 그럴 때는 이 글에서 다룬 조정으로 얻을 수 있는 만큼을 먼저 확보하는 편이 현실적이다.