CloudNet@팀의 EKS 스터디 AEWS 3기에 작성된 자료를 토대로 작성합니다.
이번 포스팅에서는 Storage 성능 비교 및 벤치마크 주제입니다.
✅ 처리량 (Throughput )에 대한 이해
성능 지표 에 대해 다시 한번 정리
- 네트워크 환경: 초당 전송할 수 있는 패킷 수 (ex. 1Gbps 네트워크)
- 스토리지 환경: 초당 읽고 쓸 수 있는 데이터 양 (ex. 500MB/s SSD)
- 데이터베이스 환경: 초당 실행 가능한 트랜잭션 수 (ex. 1000 TPS)
- 웹 서버 환경: 초당 처리할 수 있는 HTTP 요청 수 (ex. 10,000 req/sec)
성능 비교 시 MB/s만 보며, 이 수치로 성능의 우위를 판단하는 경우가 많다.
- → 소비자들에게는 Throughput(MB/s)이 더 직관적으로 와닿음
- 그렇다면 IOPS는 왜 중요할까?
- 작은 크기의 요청(4KB, 8KB)이 많을 때 IOPS가 높은 스토리지가 유리함
- 작은 블록 크기(4KB, 8KB 등)로 처리되는 경우, IOPS가 높더라도 Throughput은 상대적으로 낮습니다.
- 예를 들어:
- 100,000 IOPS, 4KB 블록 크기 → 100,000 × 4KB = 400MB/s
- 50,000 IOPS, 64KB 블록 크기 → 50,000 × 64KB = 3,200MB/s
- 블록 크기가 커지면 동일한 쓰루풋이 높은 스토리지가 더 유리함.
📌 즉, 블록 크기가 작을수록 IOPS는 중요하고, 블록 크기가 클수록 Throughput이 중요합니다.
심지어, IOPS는 Throughput이 아닌 것으로 생각하는 경우도 흔하다. 아마도 MB/s가 가장 이해하기 쉽고 익숙하기 때문이리라.
엄밀히 말하면, 해당 제품이 제공하는 대역폭을 충분히 확인했다면 MB/s는 크게 신경 쓰지 않아도 되는 지표이다.
물론, Throughput이 MB/s이라는 사실이 틀린 것은 아니다. 쓰루풋은 우리말로 처리량이고, BPS (Bytes per Second)는 데이터 전송률을 나타내는 단위이므로, 초당 처리한 바이트의 양인 B/s, KB/s, MB/s는 쓰루풋이 맞다.
그런데, 이 쓰루풋을 MBPS (MB/sec)의 개념으로만 알고 있는 이들이 너무 많다. (스토리지 업계 종사자는 거의 대부분으로 보인다.) Throughput은 엄밀히, 각 시스템이나 장치에 따라 사용되는 용어가 따로 있다.
참고자료 : (performance.tistory.com/4 참조)
스토리지의 쓰루풋은 뭐니 뭐니 해도 IOPS이나, 많은 사람들이 스토리지의 성능 지표를 Throughput, IOPS, Latency로 말하고 있다. (물론, 제조사의 표현 방식 때문이다.) 이것이 틀린 것은 아니나, 표현의 정확성 면에서 일부 혼선과 어색함을 띄고 있다. 왜냐하면, IOPS 역시 Throughput의 하나이기 때문이다. 그러므로, MB/s의 의미로 쓰인 Throughput은 Bandwidth로 바꾸는 것이 보다 적절하다. 굳이, Throughput으로 표현하고자 한다면 Throughput (MB/s)와 같이 뒤에 단위를 써주는 것이 좋다.
혼동 없는 Throughput의 표현은 다음과 같다.
- Throughput (MB/s)
- Throughput (IO/s)
스토리지 제조사들이 성능 지표를 다르게 강조한 이유
- HDD vs SSD vs NVMe
- HDD 시대에는 Throughput(MB/s)과 Latency(ms)를 강조
- SSD 시대부터 IOPS가 중요한 지표로 등장
- NVMe가 나오면서 낮은 Latency와 높은 IOPS를 강하게 어필
- 엔터프라이즈 스토리지 vs 소비자용 SSD
- 엔터프라이즈급 스토리지는 IOPS, Latency를 강조
- 소비자용 SSD는 주로 Throughput(MB/s, GB/s)를 강조 (ex. PCIe 4.0 SSD: 7GB/s)
- 제조사별 성능 마케팅 차이
- NetApp, Dell EMC, HPE: 엔터프라이즈 환경을 고려해 IOPS + Latency 중심으로 마케팅
- Samsung, Western Digital, Seagate: 일반 소비자 시장에서는 Throughput(GB/s) 강조
- Pure Storage, Nutanix: All-Flash 스토리지에서 IOPS와 낮은 Latency 강하게 강조
- AWS, Google Cloud, Azure: 클라우드 스토리지에서는 Throughput과 IOPS를 상황별로 다르게 설명
IOPS 높은 스토리지가 유리한 사용 사례
- OLTP(Online Transaction Processing) 데이터베이스
- 은행 거래, 전자상거래, 예약 시스템과 같은 트랜잭션 중심 시스템에서는 빠른 응답 속도가 중요합니다.
- 트랜잭션은 일반적으로 작은 데이터(수 KB) 를 읽고 쓰기 때문에 높은 IOPS가 필요합니다.
- NoSQL 및 키-값 저장소 (Redis, MongoDB, Cassandra 등)
- 데이터가 자주 업데이트되고, 작은 단위의 데이터가 반복적으로 저장/조회됨.
- 빠른 랜덤 읽기/쓰기 성능이 중요하여 낮은 레이턴시와 높은 IOPS가 필요함.
- VDI(Virtual Desktop Infrastructure) 환경
- 여러 사용자가 동시에 가상 데스크톱을 실행하고 사용함.
- 운영체제와 애플리케이션의 랜덤 읽기/쓰기 요청이 많음.
- 빠른 부팅 및 애플리케이션 로딩을 위해 높은 IOPS 필요.
- 로그 데이터 저장소 및 실시간 분석
- 로그 파일이나 메트릭 데이터가 짧은 간격으로 지속적으로 기록됨.
- 실시간 분석 시스템에서는 많은 작은 파일을 읽고 쓰는 작업이 필요하여 높은 IOPS 스토리지가 유리함.
- 캐시 시스템 (Redis, Memcached 등)
- 데이터를 빠르게 저장하고 가져와야 하는 캐시 시스템에서는 짧은 레이턴시와 높은 IOPS가 중요함.
- CI/CD 빌드 서버 및 코드 리포지토리 (Git, Jenkins 등)
- 여러 개발자가 코드를 병렬로 빌드하고 테스트하는 환경에서는 작은 파일을 자주 읽고 쓰는 작업이 많음.
- 따라서 빠른 응답이 가능한 높은 IOPS 스토리지가 적합.
결론
- 작은 크기의 데이터를 자주 읽고 쓰는 워크로드에서 높은 IOPS 스토리지가 필요함.
- 반면 대용량 파일 전송(예: 영상 스트리밍, 데이터 웨어하우스) 에는 높은 스루풋 스토리지가 더 적합함.
- AWS에서는 Provisioned IOPS SSD(io1, io2) 혹은 NVMe 기반 EBS(io2 Block Express) 같은 고성능 스토리지를 사용하면 이러한 요구사항을 충족할 수 있음.
✅ Kubestr 모니터링 및 성능 측정 확인 (NVMe SSD)
1. kubestr 설치
# [운영서버 EC2] kubestr 툴 다운로드 - Link
wget https://github.com/kastenhq/kubestr/releases/download/v0.4.48/kubestr_0.4.48_Linux_amd64.tar.gz
tar xvfz kubestr_0.4.48_Linux_amd64.tar.gz && mv kubestr /usr/local/bin/ && chmod +x /usr/local/bin/kubestr
# 스토리지클래스 점검
kubestr -h
kubestr
2. kubestr 실행
# 랜덤 읽기 성능 테스트 수행 : 3분 정도 소요
# libaio 엔진과 다이렉트 I/O를 사용하여 고성능 스토리지의 랜덤 읽기 성능을 측정.
# OS 캐시를 사용하지 않고 직접 디스크 I/O 수행 (direct 플래그)
cat << EOF > fio-read.fio
[global]
ioengine=libaio
direct=1
bs=4k
runtime=120
time_based=1
iodepth=16
numjobs=4
group_reporting
size=1g
rw=randread
[read]
EOF
kubestr fio -f fio-read.fio -s local-path --size 10G # size 미 지정시 기본 100G로 노드 Disk full 발생하니 유의
3. kubestr
# 랜덤 쓰기 성능 테스트 수행 : 5분 정도 소요
# numjobs=16, iodepth=16 : 총 16×16 = 256개의 I/O 요청이 동시에 발생
cat << EOF > fio-write.fio
[global]
ioengine=libaio
numjobs=16
iodepth=16
direct=1
bs=4k
runtime=120
time_based=1
size=1g
group_reporting
rw=randrw
rwmixread=0
rwmixwrite=100
[write]
EOF
kubestr fio -f fio-write.fio -s local-path --size 20G
...
write:
IOPS=3024.619873 BW(KiB/s)=12098
iops: min=1557 max=8682 avg=3024.849365
bw(KiB/s): min=6231 max=34732 avg=12099.703125
...
✅ instance store 성능 측정 확인 (NVMe SSD)
- 인스턴스 스토어 ? AWS Instance Store는 Amazon EC2 인스턴스에 물리적으로 연결된 임시 블록 스토리지입니다. SSD 또는 HDD 형태로 제공되며, 주로 높은 IOPS(입출력 성능)가 필요한 워크로드에서 사용됩니다.
- 인스턴스 스토어의 특징 :
- 인스턴스 수명과 함께 소멸
- Instance Store는 EC2 인스턴스가 중지(Stop)되거나 종료(Terminate)될 경우 데이터가 모두 삭제됨.
- 인스턴스를 재부팅(Reboot)하는 경우에는 데이터 유지됨.
- 고성능 I/O 제공
- 로컬 디스크이기 때문에 EBS보다 지연 시간이 낮고 IOPS 성능이 뛰어남.
- 따라서 캐시, 임시 데이터 저장, 로그 저장소, 빅데이터 처리 등에 적합.
- EBS와 다름
- EBS(Elastic Block Store)는 네트워크 기반의 영구적 스토리지인 반면, Instance Store는 인스턴스에 물리적으로 연결된 비영구적 스토리지.
- EBS는 인스턴스를 중지해도 데이터가 유지되지만, Instance Store는 인스턴스를 중지하면 데이터가 삭제됨.
- 지원되는 인스턴스 타입
- 모든 EC2 인스턴스가 Instance Store를 지원하는 것은 아님.
- Instance Store를 지원하는 인스턴스 타입 예시:
- i3, i3en (High IOPS NVMe SSD)
- m5d, r5d (General Purpose SSD)
- c5d (Compute Optimized SSD)
- 인스턴스 수명과 함께 소멸
1. 인스턴스 스토어 지원 타입 확인
# 인스턴스 스토어 볼륨이 있는 c5 모든 타입의 스토리지 크기
aws ec2 describe-instance-types \
--filters "Name=instance-type,Values=c5*" "Name=instance-storage-supported,Values=true" \
--query "InstanceTypes[].[InstanceType, InstanceStorageInfo.TotalSizeInGB]" \
--output table
--------------------------
| DescribeInstanceTypes |
+---------------+--------+
| c5d.large | 50 |
| c5d.12xlarge | 1800 |
...
2. 환경 설정
#
export CLUSTER_NAME=myeks
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet3" --query "Subnets[0].[SubnetId]" --output text)
echo $PubSubnet1 $PubSubnet2 $PubSubnet3
#
SSHKEYNAME=koo-network
3. 노드그룹 생성
# 신규 노드 그룹 생성 전 정보 확인
eksctl create nodegroup --help
eksctl create nodegroup -c $CLUSTER_NAME -r ap-northeast-2 --subnet-ids "$PubSubnet1","$PubSubnet2","$PubSubnet3" --ssh-access \
-n ng2 -t c5d.large -N 1 -m 1 -M 1 --node-volume-size=30 --node-labels disk=instancestore --max-pods-per-node 100 --dry-run > myng2.yaml
cat <<EOT > nvme.yaml
preBootstrapCommands:
- |
# Install Tools
yum install nvme-cli links tree jq tcpdump sysstat -y
# Filesystem & Mount
mkfs -t xfs /dev/nvme1n1
mkdir /data
mount /dev/nvme1n1 /data
# Get disk UUID
uuid=\$(blkid -o value -s UUID mount /dev/nvme1n1 /data)
# Mount the disk during a reboot
echo /dev/nvme1n1 /data xfs defaults,noatime 0 2 >> /etc/fstab
EOT
sed -i -n -e '/volumeType/r nvme.yaml' -e '1,$p' myng2.yaml
4. 노드그룹 생성 (2)
cat << EOF > myng2.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: myeks
region: ap-northeast-2
version: "1.31"
managedNodeGroups:
- amiFamily: AmazonLinux2
desiredCapacity: 1
instanceType: c5d.large
labels:
alpha.eksctl.io/cluster-name: myeks
alpha.eksctl.io/nodegroup-name: ng2
disk: instancestore
maxPodsPerNode: 110
maxSize: 1
minSize: 1
name: ng2
ssh:
allow: true
publicKeyName: $SSHKEYNAME
subnets:
- $PubSubnet1
- $PubSubnet2
- $PubSubnet3
tags:
alpha.eksctl.io/nodegroup-name: ng2
alpha.eksctl.io/nodegroup-type: managed
volumeIOPS: 3000
volumeSize: 30
volumeThroughput: 125
volumeType: gp3
preBootstrapCommands:
- |
# Install Tools
yum install nvme-cli links tree jq tcpdump sysstat -y
# Filesystem & Mount
mkfs -t xfs /dev/nvme1n1
mkdir /data
mount /dev/nvme1n1 /data
# Get disk UUID
uuid=\$(blkid -o value -s UUID mount /dev/nvme1n1 /data)
# Mount the disk during a reboot
echo /dev/nvme1n1 /data xfs defaults,noatime 0 2 >> /etc/fstab
EOF
eksctl create nodegroup -f myng2.yaml
5. 노드 확인
# 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
kubectl get node -l disk=instancestore
6. 노드 내부의 디스크 확인
# 신규 노드 그룹 생성
eksctl create nodegroup -f myng2.yaml
# 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
kubectl get node -l disk=instancestore
# ng2 노드 그룹 *ng2-remoteAccess* 포함된 보안그룹 ID
aws ec2 describe-security-groups --filters "Name=group-name,Values=*ng2-remoteAccess*" | jq
export NG2SGID=$(aws ec2 describe-security-groups --filters "Name=group-name,Values=*ng2-remoteAccess*" --query 'SecurityGroups[*].GroupId' --output text)
aws ec2 authorize-security-group-ingress --group-id $NG2SGID --protocol '-1' --cidr $(curl -s ipinfo.io/ip)/32
aws ec2 authorize-security-group-ingress --group-id $NG2SGID --protocol '-1' --cidr 172.20.1.100/32
# 워커 노드 SSH 접속
N4=<각자 자신의 워커 노드4번 공인 IP 지정>
N4=3.37.44.222
ssh ec2-user@$N4 hostname
# 확인
ssh ec2-user@$N4 sudo nvme list
ssh ec2-user@$N4 sudo lsblk -e 7 -d
ssh ec2-user@$N4 sudo df -hT -t xfs
ssh ec2-user@$N4 sudo tree /data
ssh ec2-user@$N4 sudo cat /etc/fstab
# (옵션) max-pod 확인
kubectl describe node -l disk=instancestore | grep Allocatable: -A7
# (옵션) kubelet 데몬 파라미터 확인 : --max-pods=29 --max-pods=110
ssh ec2-user@$N4 cat /etc/eks/bootstrap.sh
ssh ec2-user@$N4 sudo ps -ef | grep kubelet
안쓸떄
6. local-path provisioner로 테스트
# 재생성
# 기존 local-path 스토리지 클래스 삭제
kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml
#
curl -sL https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml | sed 's/opt/data/g' | kubectl apply -f -
kubectl describe cm -n local-path-storage local-path-config
...
"nodePathMap":[
{
"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
"paths":["/data/local-path-provisioner"]
}
]
...
# 모니터링
watch 'kubectl get pod -owide;echo;kubectl get pv,pvc'
ssh ec2-user@$N4 iostat -xmdz 1 -p nvme1n1
# [운영서버 EC2] Read 측정
kubestr fio -f fio-read.fio -s local-path --size 10G --nodeselector disk=instancestore
...
read:
IOPS=20309.355469 BW(KiB/s)=81237
iops: min=17392 max=93872 avg=20316.857422
bw(KiB/s): min=69570 max=375488 avg=81268.023438
Disk stats (read/write):
nvme1n1: ios=2432488/9 merge=0/3 ticks=7639891/23 in_queue=7639913, util=99.950768%
- OK
'DevOps' 카테고리의 다른 글
[AWS EKS] (10) EKS 스터디 4주차 ( Control-plane ) (0) | 2025.02.26 |
---|---|
[AWS EKS] (9) EKS 스터디 3주차 ( EFS Controller/ S3 CSI driver ) (0) | 2025.02.22 |
[AWS EKS] (7) EKS 스터디 3주차 ( Storage - provsioner와 CSI driver 차이점 ) (0) | 2025.02.19 |
[AWS EKS] (6) EKS 스터디 2주차 ( DNS ) (0) | 2025.02.14 |
[AWS EKS] (5) EKS 스터디 2주차 ( iptables - CNI HOST PORT CHAIN ) (0) | 2025.02.12 |