...

Linux HugePages in Web Hosting: A Performance Boost for MariaDB, Redis, and PHP-FPM

I'll show you exactly how Linux hugepages boost MariaDB, Redis, and PHP-FPM in the hosting stack, where they slow things down, and how I fine-tune them. That's how I reduce Latency, reduce TLB misses and maintain the Memory management predictable.

Key points

The following bullet points summarize the most important techniques and effects.

  • THP Mode Choose carefully: „madvise“ for general workloads, „never“ for sensitive services such as Redis.
  • Static HugePages Plan for large MariaDB buffer pools to reduce latency and TLB misses.
  • Redis Protect against latency spikes: Disable THP and limit fork costs.
  • PHP-FPM benefits indirectly from lower kernel overhead and faster backends.
  • Benchmarking and conduct monitoring before the go-live to make the effects measurable.

HugePages and THP: A Brief Explanation

I use HugePages, to enable larger memory pages and thus reduce the number of pages that need to be managed. Classic pages are 4 KB, while large pages are usually 2 MB are large. This significantly reduces TLB misses, the CPU spends less time on memory management, and services that access a lot of RAM respond more quickly. Transparent Huge Pages (THP) attempts this automatically and can work without any app modifications. Real-world reports often show operations that are 20–40 % faster when workloads and settings are well-matched.

Selecting and Testing THP Modes Correctly

I make a clear distinction between the „always“, „madvise,“ and „never,“ because they affect workloads differently. „always“ can tie up a surprising amount of RAM and generate copying overhead when services fork. „madvise“ provides control: only memory that the app explicitly marks uses large pages. „never“ offers maximum predictability, especially for fork-intensive services like Redis. If you want to dive deeper, you can find background information on the opportunities and pitfalls here: THP: A Boon or a Problem?. I test each mode under real-world load, measure latency, CPU time, and RSS, and then make a decision based on the facts.

Practical Setup on the Host

Before I migrate services, I ensure that host defaults are reproducible and that there is a secure fallback option.

Using THP in a Targeted Manner (Boot Parameters or systemd)

  • Via kernel boot: Add „transparent_hugepage=madvise“ or „transparent_hugepage=never“ to GRUB and reboot.
  • Runs via sysfs—ideal for testing or in a systemd unit:
Check # Status
cat /sys/kernel/mm/transparent_hugepage/enabled
cat /sys/kernel/mm/transparent_hugepage/defrag

# Switch to madvise (example)
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo never   > /sys/kernel/mm/transparent_hugepage/defrag

I store these commands in a small systemd unit so that the settings aren't lost when the system reboots.

Reserve Static HugePages

For HugeTLB-side reservations, I plan conservatively and with a buffer (see checklist below):

# Check size and count
grep -i huge /proc/meminfo

# Reserve 32 GB (2 MB pages -> 16384)
sysctl -w vm.nr_hugepages=16384
echo "vm.nr_hugepages=16384" > /etc/sysctl.d/90-hugepages.conf

# Optional: Mount point for hugetlbfs (useful for diagnostics)
mkdir -p /dev/hugepages
echo "hugetlbfs /dev/hugepages hugetlbfs defaults,pagesize=2M 0 0" >> /etc/fstab
mount -a

When services use HugeTLB, they generally require MEMLOCK permissions. I set limits and capabilities for this in the respective systemd unit:

[Service]
LimitMEMLOCK=infinity
CapabilityBoundingSet=CAP_IPC_LOCK
AmbientCapabilities=CAP_IPC_LOCK

Check: Do processes use large pages?

I check the actual usage for each process:

# Totals for AnonHugePages per process
grep -i 'AnonHugePages' /proc/$PID/smaps | awk '{s+=$2} END {print s " kB"}'

# System-wide metrics
grep -i huge /proc/meminfo

MariaDB: Performance Gains from Static HugePages

MariaDB relies on InnoDB—Buffer Pool and predictable RAM usage. I usually set THP to „never“ or set it to „madvise“ if I’m conducting specific tests. Reason: During forking and under write loads, 2-MB pages incur high copy-on-write costs, which slow down queries and degrade MariaDB performance. Static HugePages for a large, read-oriented buffer pool make latency more consistent and reduce administrative overhead. In addition, I adjust vm.swappiness and the I/O scheduler so that the kernel does not swap out the buffer unnecessarily.

Configuration in MariaDB, NUMA, and I/O

  • Buffer pool sized to match the load: innodb_buffer_pool_size as the main lever, innodb_buffer_pool_instances for parallelization.
  • Enable large pages (if supported by this version): innodb_use_large_pages=ON or, strictly speaking, „FORCE“ only after testing.
  • Smooth the I/O path: innodb_flush_method=O_DIRECT, a clean Write-Amp strategy, controlled checkpoints.
  • Avoiding NUMA Pitfalls: mysqld via numactl --interleave=all Start when there is a risk of node imbalance.
  • System limits: MEMLOCK as above; reserve enough HugePages in advance to prevent the startup from failing.

In practice, I increment the buffer pool in reasonable steps (e.g., 8 → 16 → 32 GB), monitor page fault rates, and compare 99p latency. Read-intensive workloads benefit the most; when there is a high write load, I evaluate CoW costs and fsync cycles particularly carefully.

Redis: Avoiding Latency Spikes

Redis is very sensitive to memory behavior and fork costs when Snapshots and AOF rewrites. When THP is enabled, the system must move 2 MB instead of 4 KB during copying—that’s a 512-fold increase, which causes latency spikes. I therefore usually set THP to „never“, which makes Redis memory usage more predictable. For large, predominantly read-heavy key-value sets, I can test „madvise,“ but only with strict benchmarks. Additionally, I set vm.overcommit_memory=1 and tune Redis defragmentation to keep fragmentation under control.

Configuration modules for low fork costs

  • THP from: Set „never“ host-wide, smooth out the fork load.
  • AOF/Snapshot: no-appendfsync-on-rewrite yes, aof-rewrite-incremental-fsync yes, schedule events during off-peak hours.
  • Defragmentation: activedefrag yes, Fine-tune the thresholds (active-defrag-threshold-lower, cycle control).
  • Overcommit: vm.overcommit_memory=1, so that forks don't get blocked.
  • Allocator: Run Redis with jemalloc to keep fragmentation low.

I measure the effects using the built-in Redis latency monitoring and correlate peaks with BGSAVE or AOF events. If the 99.9p latency drops steadily, I deploy the settings to production.

PHP-FPM: An Indirect Boost in the Web Stack

PHP-FPM itself rarely uses up huge amounts of RAM, but it benefits from having less Kernel overhead and faster backends. When MariaDB and Redis respond more quickly, TTFB and response time per request decrease. I adjust the number of FPM workers, `max_children`, and the process manager (dynamic or static) to match the load curve. This way, I take advantage of HugePages across the entire system without taking any unnecessary risks. I provide a practical introduction to the topic here: Using Server HugePages Correctly.

Practical Application: Process Variables, Opcache, and Sizing

  • I calculate pm.max_children as follows: (RAM for PHP) / (average RSS per worker), with a % reserve.
  • Keep the opcode cache stable: sufficient opcache.memory_consumption and opcache.interned_strings_buffer, to avoid having to recompile.
  • Allocator consistency: Using the same C allocator families (glibc/jemalloc) across components prevents unexpected fragmentation.
  • THP „madvise“ on the host helps manage shared libraries to some extent without driving up fork costs.

Configuration: Step-by-Step Guide and Summary Table

I start every transition with a clean Inventory: RAM, read and write rates, fork behavior, peak load. I then define goals, such as constant latency at N requests per second or less CPU time in the kernel. I configure THP based on the service and run realistic tests. Then I record the results and roll out the changes in a controlled manner. The following table summarizes field-tested starting points, which I then fine-tune:

Service THP Mode Static HugePages Note
MariaDB madvise or never Yes, compatible with the buffer pool Large reading-focused pools benefit; carefully test the writing load.
Redis never Probably not Avoid fork costs; keep defragmentation enabled.
PHP-FPM madvise Rarely necessary The benefits arise primarily indirectly through faster backends.

Hosting Environment: Choice Determines Performance

I can only achieve this on a long-term basis constant Situations where the provider sets the kernel and defaults appropriately. This includes up-to-date kernels, reasonable THP presets, sufficient RAM reserves, and support staff with tuning experience. When comparing hosting products, I look for clear statements regarding MariaDB, Redis, and PHP-FPM tuning. Anyone who wants to understand the differences between HugeTLB and THP will benefit from this concise introduction: HugeTLB vs. THP Comparison. In tests, webhoster.de has proven to be a strong contender for data-intensive projects thanks to its reliable configuration.

Containers, Cgroups, and Kubernetes

In container environments, I plan things a little differently, because many settings apply to the entire host and cannot be changed on a per-pod or per-Docker-container basis:

  • THP is a host-level decision. I install it on the node, not in the container.
  • HugeTLB requires reserved pages on the host. In orchestrations, I explicitly allocate resources (2Mi/1Gi types per node) and schedule pods to them.
  • Cgroups: I pay attention to memory.max/Swap limits, so that unexpected OOM kills don't corrupt data series.
  • Image consistency: Use the same allocator versions in all relevant containers to prevent fragmentation from drifting randomly.

I run tests at the node level using identical kernel parameters and rotate deployments on a rolling basis to avoid load dips and cold caches.

Benchmarking, Monitoring, and Capacity Planning

I don't rely on intuition; I measure hard. Before and after each change, I use identical load profiles and record latency, throughput, CPU time in user and kernel space, and RSS. I also check for peaks, not just averages, so I can detect outliers early on. When planning, I incorporate buffers to ensure that growth doesn’t immediately hit limits. This way, I keep performance consistent over weeks and allocate reserves wisely.

Measurement Parameters and Quick Test Commands

  • THP status: cat /sys/kernel/mm/transparent_hugepage/enabled, .../defrag.
  • HugeTLB: grep -i huge /proc/meminfo, cat /proc/sys/vm/nr_hugepages.
  • On the process side: /proc/$PID/smaps to AnonHugePages search.
  • Major/Minor Faults and TLB Indicators: perf stat -p $PID -e cycles,task-clock,minor-faults,major-faults,dTLB-load-misses,iTLB-load-misses.
  • Redis Latencies: Built-in latency tools, correlation with BGSAVE/AOF.
  • MariaDB: SHOW GLOBAL STATUS and performance schema for buffer hit rates and InnoDB checkpoint behavior.

Consistency in the measurement campaign is key: the same data sets, the same test windows, and the same background load. Otherwise, I’m comparing apples to oranges.

Error patterns and quick remedies

If response times increase after a THP switch, I check immediately Fork-Events and copy-on-write behavior. If „slow queries“ become frequent in MariaDB, I reduce write amplitudes, set THP to a more conservative value, and evaluate the I/O path. If Redis reports sporadic latency spikes, I set THP to „never“ and monitor snapshot timings. If the CPU load spikes, I monitor TLB misses indirectly via Perf indicators and reduce the number of static HugePages. I document every correction so that I can act more quickly if the issue recurs.

Rollback Strategy

  • Reset THP settings to the previous mode; restart only if necessary.
  • Gradually Reduce Static HugePages (vm.nr_hugepages), do not turn it off abruptly.
  • Undo service-specific flags (innodb_use_large_pages, Defrag Settings), then measure again.
  • Record the before and after values so that the next iteration will be faster.

Checklist and Size Calculation

For the calculation of static HugePages I use a simple calculation: Number = target size in bytes divided by page size (2 MB). For example, if I plan for a 32 GB InnoDB buffer pool, I need about 16,384 pages of 2 MB each. I add a 5–10 % reserve to ensure that minor fluctuations don’t cause bottlenecks. Then, at startup, I check whether the instance is actually accessing large pages. If the measurement meets expectations, I roll out the setting to additional nodes.

Note on 1-GB HugePages

With very large, stable buffer pools, 1-GB pages (HugeTLB, depending on the CPU/kernel) to alleviate additional TLB pressure. I only use it when memory requirements are constant over the long term and sufficiently large, contiguous reserves are available. The setup follows the same pattern as with 2 MB, but requires more careful planning and testing because fragmentation and startup behavior are more sensitive.

Briefly summarized

I set linux I use hugepages strategically: THP typically „madvise“ for web stacks, „never“ for Redis, and static pages for large, read-oriented MariaDB pools. This way, I reduce TLB misses, keep latencies consistent, and prevent memory surprises. PHP-FPM benefits indirectly because the database and cache respond more quickly. With thorough benchmarking and monitoring, I verify the effects and validate the changes. Combined with a provider that offers modern kernel defaults and appropriate support, the stack remains reliably fast even under load.

Current articles