Diagram illustrating key MySQL 8.x features enhancing InnoDB Cluster reliability.

MySQL 8.x Features That Improve InnoDB Cluster Reliability

,

The InnoDB buffer pool is the core of MySQL performance. It is where data and indexes are cached, where changes are prepared before flushing, and where most queries spend their time. Understanding how it works is essential for reliable tuning.

This article explains buffer pool internals, how pages flow through it, and step-by-step ways to size and tune it on a typical RHEL/Rocky Linux system.

1. What the InnoDB buffer pool actually does

InnoDB stores data and indexes in fixed-size pages (usually 16 KB). The buffer pool is an in-memory cache of these pages plus some metadata. Every read or write goes through the buffer pool:

┌──────────────────────────────────────────────┐
│                InnoDB Buffer Pool           │
├──────────────────────────────────────────────┤
│  Cached data pages (reads & writes)        │
│  Cached index pages                         │
│  Change buffer (secondary index changes)    │
│  Adaptive hash index (optional)             │
└──────────────────────────────────────────────┘

Key roles:

  • Read cache: Avoids disk I/O by serving pages from memory.
  • Write buffer: Modifies pages in memory and writes them to disk later.
  • Concurrency control: Coordinates access with latches and locks.

2. How pages flow through the buffer pool

InnoDB uses a variation of LRU (least recently used) with a split list: a “young” sublist and an “old” sublist. This helps avoid large scans evicting the working set.

┌──────────────────────────────────────────────┐
│                LRU List (simplified)        │
├───────────────┬─────────────────────────────┤
│ Young sublist │          Old sublist        │
│ (hot pages)   │      (recently read pages)  │
└───────────────┴─────────────────────────────┘

High-level flow:

  1. Query needs a page.
  2. If in buffer pool, it is a cache hit and the page is moved towards the young end.
  3. If not, InnoDB loads it from disk into the old sublist.
  4. Pages in the old sublist that are not re-used soon are candidates for eviction.

Dirty pages (modified but not yet flushed) are tracked separately on a flush list. They must be written to disk before eviction.

3. Sizing the buffer pool step by step

The single most important setting is innodb_buffer_pool_size. Oversizing it will cause swapping and kill performance; undersizing it will cause constant disk I/O.

3.1 Gather memory information

On RHEL/Rocky:

free -m

# Or for more detail
cat /proc/meminfo | egrep "MemTotal|MemFree|Buffers|Cached"

Also consider what else runs on the host: OS, MySQL overhead, other services.

3.2 Derive an initial value

  • Dedicated MySQL server: start with 60–70% of RAM.
  • Shared server: be more conservative (30–40% or less).

Example: 64 GB RAM, dedicated MySQL:

  • Target buffer pool ≈ 0.65 × 64 GB ≈ 42 GB.

In /etc/my.cnf:

[mysqld]
innodb_buffer_pool_size = 42G

Restart MySQL after changing this setting (unless you plan to use dynamic resizing; see below).

3.3 Split into multiple instances

For large buffer pools, multiple instances can reduce latch contention:

[mysqld]
innodb_buffer_pool_size      = 42G
innodb_buffer_pool_instances = 8

Practical guidance:

  • Below ~4 GB, multiple instances rarely help.
  • Above ~8–10 GB, use 4–8 instances, adjusting based on workload.

4. Monitoring buffer pool efficiency

4.1 Check cache hit ratio

Use SHOW GLOBAL STATUS to derive a rough hit ratio:

mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"

Key counters:

  • Innodb_buffer_pool_read_requests: logical reads from buffer pool.
  • Innodb_buffer_pool_reads: reads that had to go to disk.

Approximate hit ratio:

hit_ratio = 1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)

As a rule of thumb, aim for > 99% for OLTP workloads. If it is much lower and the server still has free RAM, consider increasing the buffer pool (carefully, and only if the OS will not swap).

4.2 Inspect buffer pool statistics

Use InnoDB engine status:

mysql -e "SHOW ENGINE INNODB STATUS\G" | egrep "BUFFER POOL AND MEMORY|Buffer pool size|Database pages|Free buffers|Modified db pages" -A5

Look at:

  • Buffer pool size: total pages.
  • Database pages: used pages.
  • Free buffers: how much headroom is left.
  • Modified db pages: how many are dirty.

5. Dynamic buffer pool resizing

Modern MySQL allows changing innodb_buffer_pool_size online. This is useful but must be done gradually to avoid memory pressure.

5.1 Increase size online

Example: increase from 32G to 40G:

mysql -e "SET GLOBAL innodb_buffer_pool_size = 40 * 1024 * 1024 * 1024;"

Best practices:

  • Increase in small steps (e.g. 10–20%).
  • After each step, monitor free -m and swap usage.
  • Update /etc/my.cnf to make the change persistent.

5.2 Decrease size online

Decreasing forces InnoDB to evict pages. This can be disruptive if you shrink too fast. Decrease in small increments and monitor performance and I/O.

6. Controlling I/O pressure from the buffer pool

The buffer pool interacts closely with background flushing. If dirty pages accumulate faster than they are flushed, checkpoints lag and sudden spikes of I/O can appear.

6.1 Key parameters

  • innodb_io_capacity: InnoDB's view of the IOPS your storage can sustain.
  • innodb_io_capacity_max: upper bound InnoDB can use during bursts.
  • innodb_flush_neighbors: how aggressively adjacent pages are flushed.

Example baseline for decent SSD storage:

[mysqld]
innodb_io_capacity      = 2000
innodb_io_capacity_max  = 4000
innodb_flush_neighbors  = 0

Adjust these based on actual storage benchmarks and monitoring. Too low, and dirty pages accumulate; too high, and you may saturate disks.

7. Avoiding common buffer pool pitfalls

7.1 Oversizing and swap

Never size the buffer pool so large that the OS starts swapping. Swap activity destroys latency-sensitive workloads.

Monitor:

vmstat 5

# Check swap usage
free -m

If you see non-zero swap usage increasing over time, reconsider buffer pool size and other memory consumers.

7.2 Large scans polluting the cache

Long-running full scans can push out hot pages. InnoDB's split LRU mitigates this, but bad query patterns still hurt.

Best practices:

  • Index critical queries to avoid full table scans.
  • Run heavy reporting on replicas or off-peak where possible.
  • Use EXPLAIN to identify queries that scan large ranges.

7.3 Ignoring buffer pool warmup

After a restart, the buffer pool is cold and performance often degrades until it is warmed up. Use buffer pool dump and load to preserve hot pages across restarts.

[mysqld]
innodb_buffer_pool_dump_at_shutdown = 1
innodb_buffer_pool_load_at_startup  = 1

On clean shutdown, InnoDB records the most frequently used pages. On startup, it reloads them, reducing the warmup period.

8. Step-by-step tuning process

When tuning an existing system, follow a structured approach:

  1. Measure current state
    • Record buffer pool size, instances, hit ratio, dirty pages, and I/O stats.
    • Capture workload characteristics (QPS, peak times).
  2. Check memory headroom
    • Use free -m and vmstat to confirm no swapping.
    • Estimate how much RAM you can safely allocate to InnoDB.
  3. Adjust buffer pool size
    • Increase or decrease in small steps.
    • Update /etc/my.cnf and plan restarts during maintenance windows.
  4. Tune I/O capacity
    • Measure disk performance with tools like fio (outside MySQL).
    • Set innodb_io_capacity and innodb_io_capacity_max accordingly.
  5. Stabilise and observe
    • Monitor over several days, including peak periods.
    • Revisit application queries and indexing once the buffer pool is stable.

This article offers general technical guidance. Validate all configurations in a safe environment before applying them to production.

With a clear view of how the InnoDB buffer pool works, you can make deliberate, low-risk tuning changes instead of guessing. Start by sizing it conservatively, monitor behaviour under real load, and iterate. Combined with good indexing and query design, a well-tuned buffer pool is one of the most effective levers for sustained MySQL performance.

Smart reads for curious minds

We don’t spam! Read more in our privacy policy