SSD 가비지 컬렉션, TRIM이 성능 저하를 줄이는 원리

SSD 가비지 컬렉션, TRIM이 성능 저하를 줄이는 원리

텃밭에서 수확을 마친 이랑에 곧바로 새 모종을 심을 수는 없습니다. 묵은 줄기와 뿌리를 걷어 내고 흙을 갈아엎는 일이 먼저이고, 그 일을 미리 해 두었는지가 다음 파종의 속도를 정하죠.

오늘 다룰 주제는 SSD 가비지 컬렉션이 사용자가 체감하는 속도에 어떤 영향을 주는가입니다. 어떤 조건에서 SSD가 갑자기 느려지는지, 그리고 TRIM이 그 부담을 어떻게 줄여 주는지를 차례로 보겠습니다.

텃밭과 다른 점도 분명합니다. 밭은 이랑 하나를 갈아엎으면 끝이지만, SSD는 지울 블록 안에 아직 살아 있는 데이터가 섞여 있어서 그것을 먼저 다른 곳으로 옮겨야 합니다. 바로 이 이사 비용이 성능 저하의 정체입니다.

SSD 가비지 컬렉션이 성능에 영향을 주는 이유

낸드 플래시는 페이지(Page) 단위로 쓰고 블록(Block) 단위로 지우며, 이미 쓴 자리에 덮어쓸 수 없습니다. 그래서 같은 주소에 다시 쓰면 새 페이지에 쓰고 예전 페이지에는 쓸모없다는 표시만 남깁니다.

이렇게 무효 페이지가 쌓이면 가비지 컬렉션(GC, Garbage Collection)이 무효 페이지가 많은 블록을 골라 유효 페이지를 다른 블록으로 옮기고 블록 전체를 지워 빈 블록으로 되돌립니다. 이 과정의 내부 원리는 웨어 레벨링과 함께 따로 다룬 적이 있으므로, 여기서는 사용자가 체감하는 성능 쪽에 초점을 맞춥니다.

핵심은 가비지 컬렉션이 호스트의 요청과 같은 낸드 칩, 같은 채널, 같은 컨트롤러 자원을 나눠 쓴다는 점입니다. 유효 페이지를 읽고 다시 쓰는 일이 늘어나면 그만큼 사용자의 요청이 처리될 자원이 줄어듭니다.

새 SSD가 빠른 이유도 여기서 나옵니다. 처음에는 빈 블록이 넉넉해서 쓰기 요청이 곧바로 빈 페이지로 들어가고, 가비지 컬렉션이 끼어들 일이 거의 없기 때문입니다.

회수 작업이 쓰기 지연으로 이어지는 과정

가비지 컬렉션은 언제 하느냐에 따라 사용자에게 주는 영향이 크게 달라집니다. 컨트롤러가 요청이 뜸한 틈에 미리 해 두는 것이 백그라운드 방식이고, 빈 블록이 바닥나서 쓰기 요청을 받아 둔 채 급하게 하는 것이 포그라운드 방식입니다.

빈 블록이 부족해졌을 때의 흐름

  1. 호스트의 쓰기가 이어지면서 빈 블록 수가 컨트롤러가 정한 기준선 아래로 내려갑니다.
  2. 컨트롤러가 회수할 블록을 고릅니다. 보통은 무효 페이지가 많은 블록이 먼저입니다.
  3. 선택한 블록의 유효 페이지를 읽어서 다른 빈 블록에 다시 씁니다.
  4. 원래 블록을 통째로 지워 빈 블록으로 되돌립니다.
  5. 빈 블록이 확보되면 기다리던 호스트의 쓰기가 다시 진행됩니다.

호스트 입장에서는 3번과 4번에 쓰인 시간이 그대로 대기 시간으로 보입니다. 아래는 이 지연을 어림해 보는 가상 계산입니다.

가상 계산 예시, 한 블록을 회수할 때의 지연실제 제품 값이 아니라 설명을 위한 가정입니다. 블록 하나가 256페이지이고 그중 유효 페이지가 192개라고 둡니다. 페이지 하나를 옮기는 데 읽기 0.1 ms와 쓰기 0.5 ms, 합쳐서 0.6 ms가 들고 블록 소거에는 3 ms가 든다고 가정합니다.

옮기는 시간은 192 × 0.6 ms = 115.2 ms이고, 소거까지 더하면 약 118 ms입니다. 이 작업으로 확보되는 빈 페이지는 256 − 192 = 64개뿐이라, 호스트가 64페이지를 쓰는 동안 낸드는 64 + 192 = 256페이지를 쓰게 되어 쓰기 증폭이 256 ÷ 64 = 4가 됩니다.

실제 SSD는 여러 낸드 다이와 채널에 일을 나눠 병렬로 처리하므로 체감 지연은 이보다 훨씬 짧습니다. 하지만 유효 페이지가 많은 블록을 회수할수록 일이 불어나는 원리는 같습니다.

이 때문에 드라이브가 어느 정도 차고 쓰기가 계속되면 처음의 빠른 속도가 떨어져 일정한 수준으로 내려앉는 현상이 나타납니다. 이렇게 안정된 상태를 정상 상태(Steady State)라고 부르며, 데이터센터용 SSD의 성능 사양은 대개 이 상태를 기준으로 평가합니다.

다만 쓰기 속도가 떨어지면 모두 가비지 컬렉션 탓이라는 생각은 정확하지 않습니다. 일부 제품이 빠른 쓰기를 위해 둔 임시 완충 영역이 가득 차거나, 발열 때문에 속도를 낮추는 경우에도 비슷한 증상이 나타나기 때문입니다.

TRIM이 회수 부담을 덜어 주는 방식

사용자가 파일을 지우면 운영체제의 파일 시스템은 자기 목록에서만 그 파일을 뺍니다. SSD는 그 자리가 더 이상 쓰이지 않는다는 사실을 모르기 때문에, 지워진 파일의 페이지도 여전히 유효하다고 믿고 가비지 컬렉션 때 열심히 옮깁니다.

TRIM은 운영체제가 사용하지 않게 된 주소 범위를 SSD에 알려 주는 명령입니다. SATA에서는 TRIM, SCSI에서는 UNMAP, NVMe에서는 데이터 세트 관리 명령의 디얼로케이트 기능이 같은 역할을 합니다.

가상 계산 예시, TRIM이 있을 때와 없을 때실제 제품 값이 아니라 설명을 위한 가정입니다. 앞의 블록처럼 256페이지 중 192개가 유효하다고 SSD가 믿고 있는데, 사실 그중 96개는 이미 삭제된 파일의 조각이라고 둡니다.

TRIM이 없으면 192개를 모두 옮겨 쓰기 증폭이 4입니다. TRIM으로 96개가 무효 처리되면 옮길 페이지는 96개, 확보되는 빈 페이지는 160개가 되어 (96 + 160) ÷ 160 = 1.6으로 내려갑니다.

같은 블록을 지우는 일이라도 옮길 데이터가 절반으로 줄었으니, 회수에 걸리는 시간과 낸드가 닳는 정도가 함께 줄어드는 셈입니다. TRIM은 가비지 컬렉션을 없애는 것이 아니라 가비지 컬렉션의 일감을 정확하게 줄이는 정보입니다.

운영체제가 이 명령을 보내는 방식은 두 갈래입니다. 파일을 지울 때마다 즉시 보내는 방식(리눅스의 discard 마운트 옵션 등)과, 일정 주기로 모아서 보내는 방식(리눅스의 fstrim, 윈도우의 드라이브 최적화 등)이 있고, 환경에 따라 후자를 권하는 경우가 많습니다.

한 가지 오해를 짚어 두겠습니다. TRIM은 데이터를 즉시 지우는 명령이 아닙니다. 알려 주기만 하는 명령이며, 실제 소거는 나중에 가비지 컬렉션이 블록 단위로 처리합니다.

채움률과 여유 공간이 쓰기 증폭을 좌우하는 이유

SSD 가비지 컬렉션의 효율은 회수할 블록 안에 유효 페이지가 얼마나 남아 있느냐로 정해집니다. 유효 페이지의 비율을 u라고 하면, 블록 하나를 회수할 때 유효 페이지 u를 옮기고 빈 페이지 1 − u를 얻으므로 쓰기 증폭은 대략 1 ÷ (1 − u)입니다.

유효 비율에 따른 쓰기 증폭 어림값회수 대상 블록의 유효 페이지 비율을 일정하다고 본 단순 모형입니다.

  1. 유효 페이지 50%: 1 ÷ (1 − 0.5) = 2
  2. 유효 페이지 75%: 1 ÷ (1 − 0.75) = 4
  3. 유효 페이지 90%: 1 ÷ (1 − 0.9) = 10

유효 비율이 50%에서 90%로 올랐을 뿐인데 쓰기 증폭은 다섯 배로 뜁니다. 드라이브가 가득 찰수록 성능이 완만하게가 아니라 가파르게 나빠지는 까닭입니다.

이 단순 모형은 실제보다 비관적입니다. 컨트롤러는 무효 페이지가 가장 많은 블록을 골라 회수하므로 평균 채움률이 높아도 선택된 블록의 유효 비율은 더 낮을 수 있습니다.

그래서 채움률을 낮추는 쪽이 효과적입니다. 사용자에게 보이지 않게 따로 떼어 둔 오버 프로비저닝(OP, Over-Provisioning) 영역이 넉넉하면 회수할 블록을 고를 폭이 넓어지고, 파티션 일부를 할당하지 않고 남겨 두거나 TRIM으로 빈 공간을 SSD에 알려 두는 것도 비슷한 효과를 냅니다.

평균 속도보다 꼬리 지연이 중요한 환경

개인용 컴퓨터에서는 평균 속도가 중요하지만, 서버 환경에서는 가끔 터지는 느린 응답이 더 큰 문제가 됩니다. 요청 1,000개 중 가장 느린 몇 개의 응답 시간을 꼬리 지연(Tail Latency)이라고 하며, 서비스 전체 응답은 이 느린 요청에 끌려가는 경우가 많습니다.

SSD 가비지 컬렉션 중에서도 포그라운드 방식은 평소엔 수십 마이크로초에 끝나던 요청을 수십 밀리초까지 늘릴 수 있어서, 꼬리 지연의 대표적인 원인으로 꼽힙니다. 앞의 가상 계산에서 본 118 ms 같은 값이 가끔 끼어드는 것이죠.

제품 설계 쪽에서는 오버 프로비저닝을 넉넉히 두고, 회수 작업을 잘게 쪼개 조금씩 끼워 넣는 방식으로 대응합니다. 호스트 쪽에서는 수명이 비슷한 데이터를 같은 영역에 모아 쓰도록 힌트를 주는 방향이 연구되고 있고, NVMe의 존 네임스페이스(ZNS)처럼 호스트가 쓰기 위치를 직접 관리하는 규격도 이런 문제의식에서 나왔습니다.

성능 저하를 줄이는 방법 비교 표

구분백그라운드 가비지 컬렉션TRIM오버 프로비저닝
하는 일유휴 시간에 미리 빈 블록 확보삭제된 주소를 SSD에 알림사용자에게 보이지 않는 여유 블록 확보
주체SSD 컨트롤러운영체제와 파일 시스템제조사 설계 또는 사용자의 남겨 둔 공간
효과요청이 몰릴 때의 포그라운드 회수 감소옮겨야 할 유효 페이지 감소회수 블록 선택 폭 확대, 쓰기 증폭 감소
비용과 한계쉴 틈 없는 쓰기에서는 효과가 작음환경에 따라 전달되지 않을 수 있음쓸 수 있는 용량이 줄어듦
놓치기 쉬운 점쓰기가 느려지면 모두 가비지 컬렉션 탓이라는 생각과 TRIM이 데이터를 즉시 지운다는 생각에 주의합니다.

핵심 정리

SSD는 덮어쓸 수 없는 낸드 위에서 동작하므로, 빈 블록이 줄어들면 가비지 컬렉션이 유효 페이지를 옮기느라 호스트의 요청과 자원을 다투게 됩니다. SSD 가비지 컬렉션의 부담은 회수할 블록 안의 유효 비율에 따라 가파르게 커지고, 이것이 채움률이 높은 SSD가 갑자기 느려지는 이유입니다.

TRIM은 사라진 파일의 페이지를 미리 무효로 알려 이사 비용을 줄이고, 여유 공간은 회수할 블록을 고를 폭을 넓힙니다. 묵은 줄기를 미리 걷어 둔 이랑에 모종이 바로 들어가듯, 미리 정리된 빈 블록이 있어야 쓰기가 막힘없이 이어집니다. 다만 밭과 달리 SSD는 지울 자리의 살아 있는 데이터까지 옮겨야 한다는 점이 차이입니다.

면접 대비 질문

면접 대비 질문사용량이 높은 SSD에서 쓰기 성능과 지연 시간이 나빠지는 이유를 가비지 컬렉션 관점에서 설명하고, TRIM과 여유 공간이 이를 어떻게 완화하는지 말해 보세요.

[답변 포인트] 낸드가 덮어쓰기가 안 되고 블록 단위로 지워서, 빈 블록이 줄면 가비지 컬렉션이 유효 페이지를 옮기고 블록을 소거해야 한다는 점으로 시작합니다. 이 작업이 호스트 요청과 낸드와 채널 자원을 나눠 쓰기 때문에 쓰기 증폭과 지연이 늘고, 회수 대상 블록의 유효 비율이 높을수록 증폭이 1 ÷ (1 − u)처럼 가파르게 커진다는 점을 연결합니다. TRIM이 삭제된 주소를 알려 옮길 데이터를 줄이고, 오버 프로비저닝이 회수 블록 선택 폭을 넓힌다는 점, 서버에서는 포그라운드 회수가 꼬리 지연을 만든다는 점까지 덧붙이면 좋습니다.