DEV Community

Cover image for Complete Guide to Setting Up NX + Next.js + Expo Project: Modern Monorepo Architecture. Part 2 (Tailwind configuration)
Devops Makeit-run
Devops Makeit-run

Posted on • Edited on • Originally published at make-it.run

Complete Guide to Setting Up NX + Next.js + Expo Project: Modern Monorepo Architecture. Part 2 (Tailwind configuration)

Optimizing MySQL Performance on Hetzner Cloud vs AWS: A Deep Dive into Storage Choices\n\nMySQL performance in production is often constrained by disk I/O characteristics, particularly with small random reads/writes and latency. When choosing cloud infrastructure to host MySQL, understanding the underlying storage capabilities is vital to ensure throughput and responsiveness align with workload demands.\n\nThis guide unpacks the key differences between Hetzner Cloud and AWS storage options, focusing on how local NVMe SSDs and network-attached volumes impact MySQL workloads. You’ll learn to evaluate performance tradeoffs, select appropriate storage, and tune deployments for optimal MySQL I/O efficiency.\n\n## What You'll Master\n\n Differences between Hetzner Cloud Volumes and local NVMe SSDs\n Comparing Hetzner NVMe SSDs with AWS EBS gp3 and io2 volumes\n Choosing and configuring storage to maximize MySQL IOPS and throughput\n\n\n## Why This Matters\n\nMySQL, especially for OLTP-heavy workloads, depends critically on fast, low-latency random I/O. Suboptimal storage can bottleneck transactions, slowing query response and concurrency. Hetzner Cloud offers economical options but has significant differences in storage architecture compared to AWS:\n\n- Hetzner Cloud Volumes are network-attached block storage with triple replication but limited IOPS (~5,000 max) and practical random write throughput often below 500 IOPS.\n\n- Local NVMe SSDs on Hetzner deliver much higher raw I/O performance (30k+ IOPS), saturating PCIe lanes for parallel I/O.\n\n- AWS offers flexible EBS volumes, from gp3 baseline to high-performance io2 Block Express with tens of thousands of IOPS and guaranteed sub-millisecond latency — configurable with cost tradeoffs.\n\nUnderstanding these tradeoffs directly impacts how well MySQL runs in each environment and what configurations will drive predictable performance.\n\n\nWhen benchmarking MySQL I/O, always test with production-like workloads and data sizes. Synthetic IOPS alone don't fully represent transactional bottlenecks or latency impacts.\n\n\n## Prerequisites and Setup\n\nBefore diving into performance tuning and benchmarking MySQL, ensure you have:\n\n- Access to a Hetzner Cloud account with instance types supporting local NVMe SSDs and Cloud Volumes.\n- Access to AWS with permissions to provision EBS volumes (gp3 and io2) and EC2 instances with instance-store or EBS-backed storage.\n- Basic Linux command-line familiarity, MySQL 8.x installed, and a benchmarking tool like fio or sysbench for I/O tests.\n- MySQL configured with appropriate tuning for I/O performance (e.g., InnoDB parameters, buffer pool size).\n\n\n


bash\n# Example: Installing fio for benchmarking on Linux\nsudo apt update && sudo apt install -y fio\n\n# Verify MySQL version\nmysql --version\n\n# Sample MySQL tuning for InnoDB on 8GB RAM (adjust per host)\n# Edit /etc/mysql/my.cnf or /etc/mysql/mysql.conf.d/mysqld.cnf\n# Add or modify:\n# innodb_buffer_pool_size=4G\n# innodb_log_file_size=512M\n# innodb_flush_method=O_DIRECT\n# innodb_flush_log_at_trx_commit=1\n\nsudo systemctl restart mysql\n

\n\n\n## Implementation Steps\n\n### 1. Understand Storage Types and Their IOPS Characteristics\n\n- Hetzner Cloud Volumes \n Network-attached, with triple replication across servers, optimized for data availability over raw speed. Official specs cap sustained IOPS at 5,000 and throughput at 200 MB/s, but practical random write tests show ~300 IOPS on 4K write workloads.\n\n- Hetzner Local NVMe SSDs \n Directly attached via PCIe (~32 Gbps), designed for parallelism and high throughput. Benchmarks report 30,000+ 4K IOPS and ~1,100 MB/s sequential throughput.\n\n- AWS gp3 Volumes \n Default baseline 3,000 IOPS and 125 MB/s throughput, provisionable up to 16,000 IOPS and 1,000 MB/s with added cost.\n\n- AWS io2/io2 Block Express Volumes \n High-end with tens of thousands of IOPS, consistent sub-millisecond latencies, and scaling up to hundreds of thousands of IOPS for mission-critical workloads.\n\n### 2. Benchmark Storage Performance Using fio\n\nRun a controlled fio job with 4K random writes to quantify IOPS and throughput per storage type.\n\n\n


\n</CodeBlock>\n\nRun this command on both a Hetzner Cloud Volume and a local NVMe disk:\n\n<Terminal>\n

```bash\nsudo fio fio-4k-randwrite.fio --filename=/dev/sdX\n```

\n</Terminal>\n\n**Expected Results:**\n\n| Storage Type                | Approx. IOPS | Throughput (MB/s) |\n|-----------------------------|--------------|-------------------|\n| Hetzner Cloud Volume         | ~300-400     | ~1.3              |\n| Hetzner Local NVMe (PCIe)   | ~30,000      | ~1100+            |\n| AWS gp3 Volume (default)    | 3,000        | 125               |\n| AWS io2 Block Express       | 50,000+      | 1000+             |\n\n### 3. Configure MySQL on Hetzner for Optimal Storage Use\n\nPrefer local NVMe SSDs over Cloud Volumes for high IOPS workloads:\n\n- Deploy Hetzner VM or dedicated server with NVMe SSDs.\n- Mount NVMe devices with `noatime` and `discard` options to reduce overhead.\n- Tune InnoDB parameters as per available memory and storage latency.\n- For Cloud Volumes, limit workload or use caching layers (e.g., ProxySQL, buffer pools) to mitigate I/O constraints.\n\n### 4. On AWS, Select Storage According to Performance Needs and Cost\n\n- For moderate workloads, gp3 volumes offer reasonable performance and cost.\n- For heavy OLTP, provision io2 Block Express volumes or consider instance-store SSDs on suitable EC2 instances.\n- Utilize Amazon RDS or Aurora for managed MySQL with autoscaling, optimized storage, and IO offload.\n\n### 5. Monitor and Adjust Based on Workload Characteristics\n\nUse `iostat`, `vmstat`, and MySQL performance schema to monitor I/O wait, throughput, and latency live:\n\n<Terminal>\n

```bash\niostat -x 1\nvmstat 1\nmysql -e \"SELECT * FROM performance_schema.file_summary_by_instance WHERE FILE_NAME LIKE '/dev/%';\"\n```

\n</Terminal>\n\nAdjust buffer pool size and commit frequency to balance durability and throughput.\n\n## Advanced Tips or Optimization\n\n- Hetzner Cloud Volumes carry network and replication overhead causing unpredictable latency spikes. Consider using NVMe SSDs with RAID configurations for fault tolerance without network latency.\n\n- AWS io2 Block Express volumes guarantee latency SLAs (~sub-millisecond), crucial for ultra-low-latency MySQL use cases.\n\n- Using local instance-store SSDs in AWS compromises durability unless combined with replication or backups but offers the lowest latency.\n\n- Always complement storage benchmarking with realistic MySQL load testing, such as sysbench OLTP benchmarks.\n\n<TopTip>\nAvoid simple IOPS numbers as the sole metric; latency distribution and tail latency most impact transactional database performance.\n</TopTip>\n\n## Conclusion\n\nThis guide detailed the critical impact of storage choice on MySQL's I/O performance, comparing Hetzner Cloud Volumes, local NVMe SSDs, and AWS EBS variants. Hetzner’s local NVMe is a strong, cost-efficient contender for moderate to high I/O workloads, whereas AWS’s provisioned IOPS and managed services provide scalable, ultra-low-latency solutions for mission-critical deployments.\n\nTo get the most from your MySQL deployments:\n\n- Prefer local NVMe SSDs for high-performance needs on Hetzner.\n- Benchmark with your production workload to inform decisions.\n- Leverage AWS’s managed offerings if simplified scaling and top-tier performance justify extra costs.\n\nApply these insights to design MySQL infrastructure tuned to your workload and budget.\n\n<GitHub\n  link=\"https://github.com/letsbeam/downpat-mysql-storage-optimization\"\n  name=\"downpat-mysql-storage-optimization\"\n  owner=\"letsbeam\"\n  language=\"bash\"\n/>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)