운영계 세팅 회고 ep1 - RAID란?
목차
English version: Production Server Setup Notes, Ep. 1 - What Is RAID?
발견
새 운영 서버를 넘겨받아 세팅을 시작했다.
무엇을 깔기 전에 디스크 구성부터 확인했는데, lsblk에 이런 줄이 나왔다.
nvme0n1 931.5G disk isw_raid_member
├─md126 1.7T raid0
│ ├─md126p3 1.7T part LVM2_member
│ │ ├─rl-root 70G lvm xfs /
│ │ └─rl-home 1.6T lvm xfs /home
nvme1n1 931.5G disk isw_raid_member
├─md126 1.7T raid0
sda 7T disk
└─sda1 7T part xfs /data/ssd
sdb 7.3T disk
└─sdb1 7.3T part xfs /data/hdd
OS가 올라간 NVMe 두 장이 raid0으로 묶여 있었다.
둘 중 한 장만 고장 나도 OS가 통째로 사라지는 구성이다.
서버를 넘겨준 쪽에 왜 RAID 0으로 묶었는지 물어봤더니, 그렇게 돼 있는 줄 몰랐다는 답이 돌아왔다. (ㅡ..ㅡ)
그래서 OS 디스크를 RAID 1로 다시 구성해 달라고 요청했다.
아래는 그 판단의 바탕이 된 RAID의 개념을 정리한 것이다.
RAID란
RAID(Redundant Array of Independent Disks)는 디스크 여러 장을 운영체제에는 디스크 하나처럼 보이게 묶는 방식이다.
묶는 목적은 둘 중 하나다.
더 크고 빠른 디스크를 만들거나, 디스크가 고장 나도 데이터를 잃지 않게 하거나.
묶는 방법은 세 가지 재료를 어떻게 섞느냐로 정해진다.
| 재료 | 하는 일 | 얻는 것 | 잃는 것 |
|---|---|---|---|
| striping | 데이터를 조각내 여러 디스크에 번갈아 쓴다 | 속도, 용량 합산 | 한 장이 고장 나면 전체를 잃는다 |
| mirroring | 같은 데이터를 두 장에 똑같이 쓴다 | 한 장 고장을 버틴다 | 용량이 절반이 된다 |
| parity | 데이터로 계산한 복구용 값을 따로 저장한다 | 적은 용량으로 고장을 버틴다 | 쓸 때마다 계산해야 한다 |
이 조합에 붙인 번호가 RAID 레벨이다.
RAID 레벨
아래 그림은 레벨마다 데이터가 디스크에 어떻게 놓이는지, 그리고 두 번째 디스크가 고장 났을 때 무엇이 남는지를 그린 것이다.
A1, A2…는 파일 하나를 나눈 조각이고, p가 붙은 칸은 parity다.
parity는 같은 줄의 데이터 조각들을 XOR로 계산한 값으로, 조각 하나가 사라져도 남은 조각과 parity를 다시 XOR하면 사라진 조각을 되살릴 수 있다.
RAID 0
striping만 쓴다.
파일을 조각내 두 디스크에 번갈아 쓰므로, 두 장의 용량을 다 쓰고 읽기와 쓰기도 나눠서 빨라진다.
대신 여분(redundancy)이 0이다.
그래서 이름이 0이다.
파일 조각이 두 디스크에 흩어져 있으니 한 장이 죽으면 남은 장의 조각만으로는 어떤 파일도 되살리지 못한다.
디스크가 두 장이면 둘 중 하나라도 죽을 확률은 한 장일 때의 약 두 배가 된다.
잃어도 되는 임시 공간이나 캐시에 쓴다.
RAID 1
mirroring이다.
두 장에 똑같이 쓰므로 한 장이 죽어도 다른 장이 그대로 원본이다.
용량은 디스크 한 장 몫만 쓸 수 있다.
고장 난 디스크를 갈아 끼우면 살아 있는 쪽을 그대로 복사해 다시 맞춘다.
구조가 단순해서 OS 디스크처럼 작고 멈추면 안 되는 곳에 많이 쓴다.
RAID 5
striping에 parity를 하나 더한다.
세 장이면 두 장 몫에 데이터를, 한 장 몫에 parity를 쓴다.
parity는 한 디스크에 몰리지 않고 줄마다 자리를 바꿔 놓인다.
한 장이 죽으면 남은 데이터와 parity로 죽은 장의 내용을 계산해 낸다.
용량 대비 효율이 좋지만, 한 장이 죽은 뒤 새 디스크를 채우는 동안(리빌드)에는 더 버틸 여유가 없다.
이 시간에 한 장이 더 죽으면 전부 잃는다.
디스크가 클수록 리빌드가 길어지므로, 큰 HDD를 여러 장 묶을 때는 RAID 6을 권한다.
RAID 6
RAID 5에 parity를 하나 더 둔다.
두 장까지 동시에 버티고, 네 장 이상이 필요하다.
쓰기마다 parity 두 개를 계산하므로 RAID 5보다 쓰기가 느리다.
RAID 10
RAID 1 쌍을 만든 뒤 그 쌍들을 striping한다.
네 장이면 두 장씩 mirror pair가 둘이다.
쌍마다 한 장씩은 죽어도 버티지만, 같은 쌍의 두 장이 함께 죽으면 잃는다.
용량은 절반이지만 parity 계산이 없어 쓰기가 빠르고, 그래서 쓰기가 많은 DB에 많이 쓴다.
레벨 비교
같은 크기 디스크 n장, 한 장 용량 C 기준이다.
| 레벨 | 최소 장수 | 쓸 수 있는 용량 | 버티는 고장 | 주로 쓰는 곳 |
|---|---|---|---|---|
| RAID 0 | 2 | n × C | 0장 | 임시 공간, 캐시 |
| RAID 1 | 2 | C | n−1장 | OS 디스크 |
| RAID 5 | 3 | (n−1) × C | 1장 | 읽기가 많은 데이터 |
| RAID 6 | 4 | (n−2) × C | 2장 | 큰 디스크 여러 장 |
| RAID 10 | 4 | n/2 × C | 쌍마다 1장 | 쓰기가 많은 DB |
RAID가 막는 것은 디스크 고장뿐이다.
실수로 지운 데이터나 랜섬웨어가 암호화한 데이터는 모든 디스크에 똑같이 기록되므로, 이런 사고는 별도의 백업으로 막아야 한다.
RAID를 묶는 주체
같은 RAID라도 누가 묶느냐에 따라 세 가지로 나뉜다.
이 서버에는 하드웨어 RAID(데이터용 SSD)와 펌웨어 RAID(OS용 NVMe)가 섞여 있었다.
| 방식 | 묶는 주체 | 이 서버에서 |
|---|---|---|
| 하드웨어 RAID | 전용 컨트롤러 카드 | SSD 세 장을 MegaRAID SAS-3 3108 컨트롤러가 RAID 5로 묶어, OS에는 7T 디스크 sda 한 장으로 보인다 |
| 펌웨어 RAID | 메인보드 칩셋이 정한 형식 + OS 드라이버 | NVMe 두 장이 isw_raid_member로 보인다. Intel 칩셋 형식(IMSM)의 RAID 정보를 리눅스의 mdadm이 읽어 md126으로 조립한다 |
| 소프트웨어 RAID | OS(mdadm, LVM, ZFS) | 없음 |
mdadm은 리눅스 소프트웨어 RAID, 곧 커널의 md(Multiple Devices) 장치를 만들고 관리하는 도구다. Intel 칩셋 RAID가 쓰는 IMSM 형식도 읽을 수 있어서 펌웨어 RAID를 리눅스에서 조립할 때도 쓴다.
LVM(Logical Volume Manager)은 물리 디스크로 가상의 블록 장치를 만드는 리눅스 도구로, 디스크 여러 장을 하나로 모은 뒤 필요한 크기로 나눠 쓸 수 있게 해 준다.
ZFS는 파일 시스템과 볼륨 관리자를 하나로 합친 것으로, 디스크를 직접 묶고(RAIDZ 등) 블록마다 체크섬을 두어 읽을 때 손상을 찾아내며, 중복이 있으면 스스로 고친다.
차이는 고장이 났을 때 드러난다.
하드웨어 RAID에서 OS는 묶인 디스크 한 장만 보기 때문에, 안쪽 디스크가 하나 죽어도 OS 입장에서는 멀쩡하다.
그래서 컨트롤러 전용 도구(storcli)나 서버 관리 보드의 경보로 따로 지켜봐야 한다.
펌웨어·소프트웨어 RAID는 OS에서 cat /proc/mdstat로 바로 볼 수 있다.
두 장 다 정상이면 [UU], 한 장이 빠지면 [U_]로 나온다.
정리
RAID 레벨은 속도, 용량, 고장을 버티는 정도 가운데 무엇을 얻고 무엇을 내줄지 고르는 일이다.
RAID 0은 속도와 용량을 얻는 대신 고장을 하나도 버티지 못하고, RAID 1은 용량 절반을 내주는 대신 한 장 고장을 버틴다.
RAID 5·6은 parity로 용량을 아끼면서 고장을 버티고, RAID 10은 용량을 내주는 대신 쓰기 속도와 안정성을 함께 얻는다.
OS 디스크는 용량이나 속도보다 멈추지 않는 것이 중요하다.
그래서 OS 디스크에는 RAID 0이 아니라 RAID 1을 써야 했다.
참고
- mdadm(8) 매뉴얼 https://man7.org/linux/man-pages/man8/mdadm.8.html
- Linux 커널 문서, RAID arrays (md) https://docs.kernel.org/admin-guide/md.html
- lvm(8) 매뉴얼 https://man7.org/linux/man-pages/man8/lvm.8.html
- LVM2 프로젝트 https://sourceware.org/lvm2/
- OpenZFS 문서, Basic Concepts https://openzfs.github.io/openzfs-docs/Basic%20Concepts/index.html
- OpenZFS 문서, Checksums and Their Use in ZFS https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Data%20Storage/Checksums.html