[운영체제] 23. Flash-based SSD
Reference - Operating Systems: Three Easy Pieces
https://pages.cs.wisc.edu/~remzi/OSTEP/
Flash-based SSD
SSD는 디스크와 다르게 기계적인 파츠가 없다. 대신 CPU, RAM과 트랜지스터로 구성되는데, 전자회로를 통해 read and write하며 전원이 꺼지더라도 데이터를 유지할 수 있는 Non-volatile 특성을 가진다.
cell을 묶어 page로 만들고 (4kb, 16kb, or etc.) voltage 변화를 통해 데이터를 기록한다. value가 1로 초기화되고, Program operation으로 전압을 올리면 value가 0, erasure operation일 때 전압을 낮춰 value가 1로 바뀐다. read operation으로 읽을 수 있다.
NAND cells 묶음을 page라 한다. 이 page는 memory management의 paging과 다른 개념이다.
SSD의 page는 written과 read가 동시에 수행된다. 이러한 page들의 묶음을 block이라 한다.
한번 쓰여진 page에 새로쓰고 싶을 땐(update) 초기화하고 새로 써야되는데, 이때 erase는 block단위로 진행되기에 비효율적인 면이 크다. 이는 비용 절감을 위한 공정 효율성 때문으로 설계 방식이므로 바꿀 수 없다고 한다.
NAND Flash Chip의 경우 읽기 > 쓰기 > 지우기 순서로 빠르다. throughput은 그렇게 빠르진 않다. (36.4MB/s for reads)
Block size는 4MB, Die Size(=group of blocks)는 8Gb 정도가 일반적이다.
2개에서 4개의 die가 single NAND chips로 packing된다.
Performance를 증가시키기 위해 병렬성을 이용한다. SSD controller가 64-128개의 SSD를 control한다.
이때문에 performance(throughput)는 36.4MB/s * 64-128 = 2.3-4.7GB/s까지 나온다고 한다.
Capacity의 경우 density 측면에서 다른 disk보다 좋은데, 같은 cell안에 density를 n배 늘려서 Multi-level cell을 만들 수 있다. 이 경우 bit를 2^n만큼 저장가능해지며, 2023년 기준 4bit이 범용적이라고 한다. 16개의 조합이 가능하다는 뜻이다.
Disk와 Flash의 내부 구조는 완전히 다르다. 하지만 Disk가 HDD->SSD로 변화하는 동안 그대로 쓸 수 있었던 이유는 둘 다 logical block을 통해 동일한 abstraction을 제공하기 때문에 OS의 변경없이 가능했던 것이다.
SSD의 경우 전자가 수없이 이동하는 과정에서 전하가 끼게 되어 1인지 0인지 구분할 수 없게끔 왜곡된다.
이를 block의 wear out이라 하며 10K~100K의 erase가 발생할 때 훼손된다. 하지만 일반적으로 한 block에서 10K 정도의 erase가 발생하지 않기 때문에 큰 문제가 되지 않는다. 물론 이또한 문제가 있기에, 해결하는 법을 알아볼 것이다.
- SSD architecture & Flash Translation Layer
SSD 내부에 작은 CPU와 DRAM이 있고 병렬성을 위해 Flash 여러개가 들어있다.
FTL은 logical block의 read/write request를 physical page에서 low-level language (program, erase, read)명령어로 변환한다.
Direct Mapped FTL - bad approach
이해를 돕기 위해 block = 16KB, page = 4KB라고 가정하자.
첫 block에 0, 1, 2, 3을, 그 뒤 blcok은 4, 5, 6, 7, ...이렇게 Number를 setting하자.
하지만 이 경우 하나의 page를 update하려면, SSD의 erase 특성에 따라 동일한 block의 page를 모두 읽고 DRAM으로 불러온 다음 block을 초기화하고 page를 모두 다시 써야한다. 즉, overhead가 매우 커진다.
또다른 문제는 각 데이터가 locality를 가지고 있기 때문에 20퍼센트는 자주 update되고 80퍼센트는 잘 사용되지 않는데, 앞 번호를 가지는 logical block은 자주 rewrite되어 마모되게 된다. 하나의 block만 자주 사용되어 마모되면 capacity가 줄어들기에 문제가 된다. 즉, 특정 page가 빈번하게 update된다면 bad block(10K~100K write 시)이 되고, 해당 block을 쓰지 못해 capacity가 줄어들게 된다.
WAF(Write Amplification Factor) = Total write traffic by FTL / write traffic by client = 4
Log-structured FTL
오늘날 대부분의 FTL은 log structured다. 성능이 안좋은 write는 늘 새로운 공간에 연속적으로 해서 performance를 높이는 기법이다. 여기엔 두가지 중요한 컨셉이 있는데, logging과 mapping table이다.
logging은 페이지를 수정할 때 해당 페이지의 모든 block을 지우지 않고, 새로운 페이지(빈 공간)에 데이터를 append한다. 이 경우 데이터의 위치가 지정되지 않아 문제가 있는데, 이를 저장하기 위한 새로운 data structure가 필요하다. 이를 mapping table이라 한다. (page table과 유사) 이는 SSD의 DRAM에 저장되어진다.
같은 logical block에 데이터가 overwrite되면 그 전에 write된 page state를 Invalid Page로 바꾸고, 새로운 page에 data를 기록한다. 이때 생기는 Invalid page는 garbage collection으로 처리한다.
위에서 발생하는 invalid page를 언젠가 회수해야 하는데, 그 방법은 block 내 빈 공간에 valid를 복사한 뒤 invalid가 포함된 block을 reset한다. 그 과정은 아래와 같다.
이 방법은 각 block의 수명이 공평하게 배분될 확률이 높다.(better wear-leveling) WAF도 낮다. (10pages/8pages = 1.25)
이 경우 문제는 SSD의 capacity가 매우 커지면 mapping table의 size가 큰 DRAM을 넣어야 한다. (1TB -> 1GB DRAM 필요) 또한 Garbage collection은 여전히 I/O overhead가 크다.
이를 해결하기 위한 Demand-based FTLs가 있다. 이는 인기있는 entries를 DRAM에 저장하면서 모든 mapping table을 NAND flash에 저장한다. 장점은 log-structured FTLs보다 더 적은 DRAM을 요구하지만, random workload에 안좋고 miss penalty가 크다.
Wear Leveling
log-structured FTL은 free block에 write 부하를 분산시키며, garbage collection에도 도움이 된다.
하지만 만약 block2, block3는 업데이트가 잘 안되고(cold), block 0, 1, 4는 업데이트가 많이 된다고 가정하자(hot). 이경우 cold page에 비해 hot page는 빠르게 마모되어 편중될 수 있다. 이러한 현상을 막기 위해 골고루 분배하는 것이 wear leveling이다. 이를 해결하기 위해 Dynamic wear leveling이 있는데, 데이터를 append할 때 아무 block에 넣지말고, 삭제횟수가 가장 낮은 block에 넣으면 공평해질 것이다. 하지만 cold page는 해결할 수 없는데, Static wear leveling을 통해 이를 해결할 수 있다. 이 방법은 cold pages도 삭제횟수가 낮은 block에 옮겨주는 것인데, 당연히 추가적인 I/O overhead가 발생하는 문제가 있다. 그 과정에서 결국 모든 block의 수명만 줄이는 문제가 발생할 수 있기에, 알고리즘을 잘 짜야 한다.