{"id":46,"date":"2020-05-17T19:59:02","date_gmt":"2020-05-17T19:59:02","guid":{"rendered":"https:\/\/www.scalebench.com\/?p=46"},"modified":"2026-08-14T20:07:24","modified_gmt":"2026-08-14T20:07:24","slug":"aws-ebs-vs-aws-instance-store-local-disk-storage","status":"publish","type":"post","link":"https:\/\/www.scalebench.com\/blog\/?p=46","title":{"rendered":"AWS EBS vs. AWS instance store (local disk) storage"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">AWS is well known for it\u2019s EBS (elastic block storage) offering, which effectively separates (both physically and functionally) the storage component of a VM from the processing component. This means that it\u2019s trivial to mix and match front end processing systems, allowing a user to upgrade\/downgrade\/pause an instance seamlessly with storage waiting to be re-attached. This storage can be found on separate instances using the AWS custom built&nbsp;<a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/instance-types.html#ec2-nitro-instances\" target=\"_blank\" rel=\"noreferrer noopener\">nitro system<\/a>. Multiple copies of data for a given EC2 instance are read\/written to within the same availability zone. Based on&nbsp;<a href=\"https:\/\/aws.amazon.com\/ebs\/features\/#Amazon_EBS_Availability_and_Durability\" target=\"_blank\" rel=\"noreferrer noopener\">their details page<\/a>&nbsp;we are going to assume it\u2019s a one (or more) disk master copy read\/write, and there are other disk (set) copies on other servers that are written to asynchronously, and not used for reading (that would be the safest way to do it and avoid getting into the weeds of architecting a synchronous cluster based storage system).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So what is the other option? The old fashioned way of having one or more disks physically attached to your server. AWS does have this, they call it \u2018instance store\u2019, and you\u2019ll see on the&nbsp;<a href=\"\/https:\/\/aws.amazon.com\/ec2\/instance-types\/\" target=\"_blank\" rel=\"noreferrer noopener\">instances types<\/a>&nbsp;page, any listing with NVMe SSD, supports local disk. However, beware, for the AWS version of local disk is&nbsp;<a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/InstanceStorage.html\" target=\"_blank\" rel=\"noreferrer noopener\">\u2018ephemeral\u2019<\/a>, which means if the instance is either stopped, or terminated, you lose the data (rebooting is okay). This is likely due to their overall architecture philosophy where once an instance is stopped, the front end processing VM (included any attached disks) is thrown back into the pool for other users. The big advantage local storage has, is the close proximity and thus low latency of interactions, and so they certainly should perform better.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Why don\u2019t they offer a class of servers with local storage AND durable local storage? We\u2019ll just chalk it up to business reasons.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">so let\u2019s compare the following options and see how they perform, <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">EBS SSD general iops (about 3k for a 1TB volume)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">EBS SSD provisioned iops (about 50k for a 1TB volume)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NVMe SSD local disk (one disk raid 0)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NVMe SSD local disk (two disks striped raid 1)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">* you would generally never run a local disk as raid 0 (otherwise you\u2019d risk losing your data on failure), but it\u2019s useful to how a single disk performs for the active workload and how multiple disks can improve performance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Specs are the following,<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>M5.8xlarge \/ M5d.8xlarge<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>32 cores \/ 3201.76 mhz \/ Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz<\/li>\n\n\n\n<li>L1d: 32 L1i: 32 L2: 1024 L3: 33792<\/li>\n\n\n\n<li>RAM: 123.16 GB \/ swap: 0.00 GB \/ hugepages: 0.00 GB \/ hp size: 2.00 MB<\/li>\n\n\n\n<li>(m5d.8xlarge local disk) 2 X 558.80 GB, ext4<\/li>\n\n\n\n<li>(m5.8xlarge EBS) 1023.00 GB, ext4<\/li>\n\n\n\n<li>Amazon Linux AMI 2018.03 35.164.220.8<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Testing Parameters<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We use the Scalebench platform to leverage Sysbench benchmarking tool.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\n<ul class=\"wp-block-list\">\n<li>Sysbench benchmark suite<\/li>\n\n\n\n<li>3 X 60 second runs (yes, pretty short runs. more on this below)<\/li>\n\n\n\n<li>disk \u2013 seqrd, seqwr, rndrd, rndwr (default settings)<\/li>\n\n\n\n<li>total file size of 500GB\u00a0 ( >> 128GB memory)<\/li>\n\n\n\n<li>16KB requests<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Results<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We do 4 separate tests read\/write in sequential\/random fashion. Before we start to analyze the results, there are a few AWS specific limits to keep in mind, which are detailed&nbsp;<a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/ebs-optimized.html\" target=\"_blank\" rel=\"noreferrer noopener\">here&nbsp;<\/a>and&nbsp;<a href=\"https:\/\/aws.amazon.com\/ebs\/features\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>. Essentially AWS has both I\/O and throughput limits for EBS and specifics depend on the volume type.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\n<ul class=\"wp-block-list\">\n<li>EBS 3k \u2013 3,000 iops\u00a0 | 250MB\/sec throughput<\/li>\n\n\n\n<li>EBS 3k \u2013 50,000 iops\u00a0 | ~800MB\/sec throughput<\/li>\n\n\n\n<li>EBS per instance (m5.8xlarge\/ m5d.8xlarge) \u2013 30,000 iops | ~850MB\/sec*<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">* and so the instance type can limit the iops and throughput regardless of the EBS storage settings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Random Writes<\/strong>\u00a0\u2013 Because it\u2019s a random access pattern, each piece of data will likely reside on a different block, and thus generally an I\/O per request. So iops becomes the limiting factor. The graph shows this to be quite true for EBS general iops which tops out at about 3,000 iops for 2+ threads. the EBS provisioned iops improves with more threads, however tops out at 32+ threads and begins to degrade due to thread contention. Also the max iops reached was ~ 23k iops, somewhat lower than the instance max of 30k iops. The local disk results both reach max capacity much more quickly at 4+ threads as there is no imposed limit, and due to low latency of local disk. The single disk vs. raid 1 (two copies), have the same results, as raid1 has to write a copy of the data to each disk.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"500\" src=\"https:\/\/www.scalebench.com\/wp-content\/uploads\/2026\/08\/2-1.jpg\" alt=\"\" class=\"wp-image-47\" srcset=\"https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-1.jpg 700w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-1-300x214.jpg 300w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-1-624x446.jpg 624w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Random Reads<\/strong>\u00a0\u2013 Again, for the same I\/O per request reason, the limiting factor is likely to be iops for EBS, and we see that the general characteristics are similar to the Random Reads graph. EBS 3K is limited quickly at 2+ threads and maxes at ~ 4k (there may be some bundling in the physical writes), EBS 50k increases capacity to max out at 16+ threads and hits a max of 40k iops (limit should be 30k max of the instance). Again bundling of physical writes by about the same factor. The local disk runs<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"500\" src=\"https:\/\/www.scalebench.com\/wp-content\/uploads\/2026\/08\/2-2.jpg\" alt=\"\" class=\"wp-image-48\" srcset=\"https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-2.jpg 700w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-2-300x214.jpg 300w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-2-624x446.jpg 624w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Sequential Writes<\/strong>\u00a0\u2013 Sequential access is fundamentally different,\u00a0 requests can be made to the same block on disk and so subsequent requests are cached for reads to the same block. Additionally, the process then moves on to query adjacent blocks which are likely also cached in a read-ahead, journal file system. So many sequential requests can result in one block request. Instead of sequential access hitting the iops ceiling, it hits the thoughput ceiling. We can see that EBS 3k run is steady at ~16K iops for all threads, and you\u2019ll find that 16,000 iops * 16k per request\u00a0 ~ 250MB\/sec, the throughput ceiling for EBS 3K. For the local cases, throughput is also a limiting factor, although it\u2019s the throughput of the disk(s) themselves with no artificial limit and so the results are flat for all thread runs. Raid1 and single disk results are the same as raid1 needs to write to both disks.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"500\" src=\"https:\/\/www.scalebench.com\/wp-content\/uploads\/2026\/08\/2-3.jpg\" alt=\"\" class=\"wp-image-49\" srcset=\"https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-3.jpg 700w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-3-300x214.jpg 300w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-3-624x446.jpg 624w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Sequential Reads<\/strong>\u00a0\u2013 uh-oh a big red line through it. That can\u2019t be good. When doing these benchmarks, we did very short runs (60 secs). Why so short? In the interest of cost savings, even with 60 seconds per run, a disk test 3 times per combo for 1-128 threads for the 4 access options takes about 6 hours per instance. With the other 3 cases, there were minimal effects, but in the case of sequential reads, there were cached reads that skewed the results the first 5-10 seconds. Below is the results with first 10 seconds cut.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"500\" src=\"https:\/\/www.scalebench.com\/wp-content\/uploads\/2026\/08\/2-4.jpg\" alt=\"\" class=\"wp-image-50\" srcset=\"https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-4.jpg 700w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-4-300x214.jpg 300w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-4-624x446.jpg 624w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now we have proper data, and you can see, EBS 3k again tops out quickly at ~16,000 iops \/ 250 MB\/sec. EBS 50k doesn\u2019t reach it\u2019s max until 64+ threads, topping out at 50k iops but really, 50k iops * 16kb = 800 MB\/sec, which is probably the true limiting factor in this case. Both local disk cases start out vastly better due to low latency and the raid 1 performs 2x+ better than the single disk for lower thread values, as there are 2 disks to serve reads. As threads increase, thread contention brings the results closer together.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"499\" src=\"https:\/\/www.scalebench.com\/wp-content\/uploads\/2026\/08\/2-5.jpg\" alt=\"\" class=\"wp-image-51\" srcset=\"https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-5.jpg 700w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-5-300x214.jpg 300w, https:\/\/www.scalebench.com\/blog\/wp-content\/uploads\/2026\/08\/2-5-624x445.jpg 624w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Takeaways<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>the local disk options are vastly better at random access than EBS, due to low latency and iops being a limiting factor. Although most applications try to avoid random reading, it\u2019s hard to avoid completely and so good performance in this area is a big plus. Sequential reads are also vastly better than EBS, mainly due to rate limiting of EBS, specifically the throughput. Generally you are going to get full, unrestricted access to a local disk with much lower latency than network storage (EBS).<\/li>\n\n\n\n<li>Raid1 is (not surprisingly) up to 2x better for reads than the single disk. Writes are the same due to needing to write to both disks. However on larger system, you can have 4+ disks and do raid10 (mirrored striping) which would give improvements to writes as well.<\/li>\n\n\n\n<li>Unfortunately as mentioned at the start, local disk options are ephemeral and will lose your data on a terminate\/stop of the instance. Even so, it might be worth considering a high availability architecture to allow using it.<\/li>\n\n\n\n<li>EBS 50K is certainly more performant than 3K, although you generally need to get past 4+ threads to see a real difference (e.g. a database). Single threaded processes are not going to be much faster (e.g. a file copy, zip, etc..). EBS 50k was limited by the instance max iops (30k), so generally be aware the instance size also can be a limiting factor on EBS performance.<\/li>\n\n\n\n<li>It\u2019s possible to raid EBS as well, but keep in mind it\u2019s networked storage and so that will likely be a real bottleneck on any performance gains. Worth a separate test to compare.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>AWS is well known for it\u2019s EBS (elastic block storage) offering, which effectively separates (both physically and functionally) the storage component of a VM from the processing component. This means that it\u2019s trivial to mix and match front end processing systems, allowing a user to upgrade\/downgrade\/pause an instance seamlessly with storage waiting to be re-attached. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=46"}],"version-history":[{"count":2,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":53,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions\/53"}],"wp:attachment":[{"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.scalebench.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}