<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Storage on Yarang's Tech Lair</title><link>https://blog.fcoinfup.com/ko/tags/storage/</link><description>Recent content in Storage on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Mon, 04 May 2026 20:49:16 +0900</lastBuildDate><atom:link href="https://blog.fcoinfup.com/ko/tags/storage/index.xml" rel="self" type="application/rss+xml"/><item><title>하드웨어의 한계를 넘어: 마이크로벤치마킹으로 디스크 물리적 구조 파헤치기</title><link>https://blog.fcoinfup.com/ko/post/%ED%95%98%EB%93%9C%EC%9B%A8%EC%96%B4%EC%9D%98-%ED%95%9C%EA%B3%84%EB%A5%BC-%EB%84%98%EC%96%B4-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EB%B2%A4%EC%B9%98%EB%A7%88%ED%82%B9%EC%9C%BC%EB%A1%9C-%EB%94%94%EC%8A%A4%ED%81%AC-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EA%B5%AC%EC%A1%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0/</link><pubDate>Mon, 04 May 2026 20:49:16 +0900</pubDate><guid>https://blog.fcoinfup.com/ko/post/%ED%95%98%EB%93%9C%EC%9B%A8%EC%96%B4%EC%9D%98-%ED%95%9C%EA%B3%84%EB%A5%BC-%EB%84%98%EC%96%B4-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EB%B2%A4%EC%B9%98%EB%A7%88%ED%82%B9%EC%9C%BC%EB%A1%9C-%EB%94%94%EC%8A%A4%ED%81%AC-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EA%B5%AC%EC%A1%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0/</guid><description>&lt;h1 id="하드웨어의-한계를-넘어-마이크로벤치마킹으로-디스크-물리적-구조-파헤치기"&gt;하드웨어의 한계를 넘어: 마이크로벤치마킹으로 디스크 물리적 구조 파헤치기
&lt;/h1&gt;&lt;p&gt;최근 Hacker News를 통해 흥미로운 2019년도의 글이 다시 조명을 받았습니다: &amp;ldquo;Discovering hard disk physical geometry through microbenchmarking&amp;quot;입니다. 고성능 SSD가 대중화된 시대에 회전형 매체(HDD)의 물리적 구조를 파악하는 일이 왜 중요할까요?&lt;/p&gt;
&lt;p&gt;사실 이 글의 핵심은 단순한 하드디스크의 구조를 넘어, &lt;strong&gt;&amp;lsquo;관찰 가능한 성능(Observable Performance)&amp;lsquo;을 통해 하드웨어의 내부 동작을 추론하는 방법론&lt;/strong&gt;에 있습니다. 이는 최신 NVMe SSD의 ZNS(Zoned Namespace) 스토리지나 최근 논의되고 있는 LoRa 기반의 BYOMesh 같은 저전력 네트워크 장비의 성능 특성을 분석할 때도 적용 가능한 원리입니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 직접 간단한 코드를 작성하여, 하드웨어의 &amp;lsquo;숨겨진 신체 측정(Physical Geometry)&amp;lsquo;을 알아내는 마이크로벤치마킹 기법을 실습해 보겠습니다.&lt;/p&gt;
&lt;h2 id="왜-마이크로벤치마킹인가"&gt;왜 마이크로벤치마킹인가?
&lt;/h2&gt;&lt;p&gt;소프트웨어 개발자는 OS와 하드웨어 사이의 추상화 계층 덕분에 복잡한 하드웨어 세부 사항을 몰라도 개발할 수 있습니다. 하지만 고성능을 요구하는 시스템, 예를 들어 고주문량을 처리하는 전자상거래 플랫폼이나 대용량 데이터를 처리하는 분석 시스템을 개발할 때는 이야기가 달라집니다.&lt;/p&gt;
&lt;p&gt;운영체제가 제공하는 &lt;code&gt;fstat&lt;/code&gt;나 &lt;code&gt;lsblk&lt;/code&gt; 명령어만으로는 실제 섹터 배치나 캐시 메모리 크기, 회전 지연 시간 등을 정확히 알기 어렵습니다. 이때 &lt;strong&gt;직접 읽기/쓰기 작업을 수행하며 그 소요 시간을 측정하는 마이크로벤치마킹&lt;/strong&gt;이 가장 강력한 도구가 됩니다.&lt;/p&gt;
&lt;h2 id="벤치마킹의-기본-원리"&gt;벤치마킹의 기본 원리
&lt;/h2&gt;&lt;p&gt;하드디스크(HDD)의 데이터 접근 속도는 다음 세 가지 요소로 결정됩니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;탐색 시간(Seek Time):&lt;/strong&gt; 헤드가 해당 트랙으로 이동하는 시간 (물리적 이동)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;회전 지연(Rotational Latency):&lt;/strong&gt; 데이터가 있는 섹터가 헤드 아래로 회전해 올 때까지의 시간&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;전송 시간(Transfer Time):&lt;/strong&gt; 실제 데이터를 읽는 시간&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;우리는 이 중 **&amp;lsquo;탐색 시간&amp;rsquo;**에 집중할 것입니다. 헤드가 이동해야 하는 거리가 멀수록 시간이 오래 걸리므로, 인접한 섹터를 읽을 때와 멀리 떨어진 섹터를 읽을 때의 시간 차이를 측정하면 디스크의 물리적 배치(트랙과 실린더 구조)를 유추할 수 있습니다.&lt;/p&gt;
&lt;h2 id="실습-python으로-디스크-구조-탐색"&gt;실습: Python으로 디스크 구조 탐색
&lt;/h2&gt;&lt;p&gt;이제 파이썬을 사용하여 랜덤 액세스와 순차 액세스의 성능 차이를 측정해 보겠습니다. 이 코드는 디스크의 &amp;lsquo;외곽(Outer Zone)&amp;lsquo;과 &amp;lsquo;내곽(Innter Zone)&amp;rsquo; 사이의 이동 비용을 측정하는 간단한 예제입니다.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;주의:&lt;/strong&gt; 이 스크립트는 실제 디스크 장치(&lt;code&gt;/dev/sdX&lt;/code&gt; 등)에 접근하므로, &lt;strong&gt;반드시 데이터가 없는 테스트용 디스크&lt;/strong&gt;나 &lt;strong&gt;VM 환경&lt;/strong&gt;에서 진행하세요. 잘못된 장치에 접근하면 데이터가 손상될 수 있습니다.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; sys
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 테스트할 디스크 경로 (VM이나 별도 테스트 디스크로 변경 필요)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 예: Linux의 경우 &amp;#39;/dev/sdb&amp;#39;, macOS의 경우 &amp;#39;/dev/rdisk2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DISK_PATH &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/dev/sdb&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 읽기 블록 크기 (4KB)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BLOCK_SIZE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 측정 횟수&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ITERATIONS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;benchmark_random_access&lt;/span&gt;(fd, size):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;랜덤한 위치에 접근할 때의 성능 측정&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getsize(DISK_PATH) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exists(DISK_PATH) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(ITERATIONS):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 랜덤한 오프셋 계산 (블록 단위 정렬 유지)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urandom(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset_int &lt;span style="color:#f92672"&gt;=&lt;/span&gt; int&lt;span style="color:#f92672"&gt;.&lt;/span&gt;from_bytes(offset, &lt;span style="color:#e6db74"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (total_bytes &lt;span style="color:#f92672"&gt;-&lt;/span&gt; BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aligned_offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (offset_int &lt;span style="color:#f92672"&gt;//&lt;/span&gt; BLOCK_SIZE) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; BLOCK_SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lseek(fd, aligned_offset, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;SEEK_SET)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read(fd, BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (end_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# ms 변환&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;benchmark_sequential_access&lt;/span&gt;(fd):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;순차적인 위치에 접근할 때의 성능 측정&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(ITERATIONS):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read(fd, BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (end_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# ms 변환&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exists(DISK_PATH):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;DISK_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; not found. Please update DISK_PATH.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exit(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Benchmarking &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;DISK_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 파일을 열되 버퍼링을 최소화하기 위해 O_DIRECT 플래그 사용 권장 (Linux)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 여기서는 호환성을 위해 기본 모드로 진행하나 실제 하드웨어 접근 시에는 O_DIRECT가 필요함.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(DISK_PATH, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;O_RDONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;O_SYNC)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;1. Measuring Random Access (Simulating Head Seek)...&amp;#34;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 랜덤 액세스는 헤드가 계속 움직이므로 느림&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; random_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; benchmark_random_access(fd, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 1GB 가정&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; Random Access Time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;random_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;2. Measuring Sequential Access (Minimal Head Movement)...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 파일 포인터를 다시 처음으로&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lseek(fd, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;SEEK_SET)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sequential_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; benchmark_sequential_access(fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; Sequential Access Time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;sequential_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;--- Analysis ---&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Performance Gap (Seek Cost): &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;random_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; sequential_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;The gap represents the time spent moving the disk head physically.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close(fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PermissionError&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Error: Permission denied. Try running with &amp;#39;sudo&amp;#39;.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;e&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="결과-해석-및-활용"&gt;결과 해석 및 활용
&lt;/h2&gt;&lt;p&gt;위 코드를 실행하면 랜덤 액세스가 순차 액세스보다 훨씬 느린 것을 확인할 수 있습니다. 이 &amp;lsquo;차이(Gap)&amp;lsquo;가 바로 물리적 탐색(Seek)과 회전(Rotation)에 소요된 시간입니다.&lt;/p&gt;
&lt;p&gt;만약 이 측정을 디스크의 시작 부분(외곽 트랙)과 끝 부분(내곽 트랙)에서 나누어 진행한다면, 디스크의 &lt;strong&gt;Zone Bit Recording(ZBR)&lt;/strong&gt; 구조 때문에 외곽이 내곽보다 전송 속도가 빠르다는 것을 발견할 수도 있습니다. 과거에는 이를 이용해 데이터를 디스크의 앞부분에 배치하는 튜닝을 하기도 했습니다.&lt;/p&gt;
&lt;h2 id="현대적-의의-ssd와-클라우드-시대에서의-교훈"&gt;현대적 의의: SSD와 클라우드 시대에서의 교훈
&lt;/h2&gt;&lt;p&gt;비록 회전판 디스크가 예전 기술이 되어가고 있지만, **&amp;lsquo;성능 측정을 통해 시스템의 내부를 이해한다&amp;rsquo;**는 원칙은 변하지 않습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SSD의 내부 병렬성:&lt;/strong&gt; SSD는 내부적으로 여러 채널과 플레인(Plane)을 병렬로 운용합니다. 우리가 멀티스레드로 순차 읽기를 유도했을 때 성능이 급격히 상승한다면, 이는 내부 컨트롤러의 병렬 처리 능력을 추론할 수 있는 신호가 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud Storage I/O:&lt;/strong&gt; AWS나 Azure의 디스크 I/O 성능이 &amp;lsquo;Burst&amp;rsquo; 후에 &amp;lsquo;Baseline&amp;rsquo;으로 떨어지는 현상을 마이크로벤치마킹으로 포착하여 비용 효율적인 아키텍처를 설계할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;Hacker News에서 다시 주목받은 &amp;lsquo;디스크 물리적 구조 발견&amp;rsquo; 글은 우리에게 단순한 호기심을 넘어, &lt;strong&gt;시스템의 성능 병목을 진단하는 가장 기본적인 자세&lt;/strong&gt;를 일깨워 줍니다.&lt;/p&gt;
&lt;p&gt;막연한 느낌으로 &amp;ldquo;디스크가 느린가 보다&amp;quot;라고 단정 짓기보다, 직접 간단한 스크립트를 돌려보며 **&amp;ldquo;어디서 왜 느린지&amp;rdquo;**를 데이터로 증명해 보는 것. 이것이 진정한 성능 튜닝의 첫걸음입니다.&lt;/p&gt;
&lt;p&gt;오늘 포스트에서 작성해 본 벤치마킹 코드를 여러분의 개발 환경에서 한번 돌려보시기 바랍니다. 예상치 못한 하드웨어의 특성을 발견하고, 그것이 시스템 성능에 미치는 영향을 직접 관찰하는 것은 매우 흥미로운 경험이 될 것입니다.&lt;/p&gt;
&lt;h2 id="참고-자료"&gt;참고 자료
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.codesynthesis.com/~boris/blog/2019/04/17/geometry/" target="_blank" rel="noopener"
 &gt;Discovering hard disk physical geometry through microbenchmarking (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.kernel.org/doc/html/latest/block/index.html" target="_blank" rel="noopener"
 &gt;Linux Block Layer internals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>