Introduction to the problem: Why optimize server performance?
When you’re new to Linux servers, you’ll soon realize that keeping the system running smoothly and quickly is extremely important. This is especially true as the number of users or data begins to grow. A slow server not only degrades the user experience but also causes many serious problems: loss of customers, service interruptions, and even financial damage. Therefore, optimizing performance is not just a skill; it’s also the responsibility of every system administrator.
Are you new to IT and find the concept of “server performance” complex? Don’t worry! This article will help you understand every aspect and provide detailed practical steps that you can apply immediately.
Core Concepts: What is Performance and Bottlenecks
Before we dive into optimization, we need to understand what “performance” truly means in the context of a Linux server. Server performance is evaluated through many factors, but the most basic are:
- Throughput: The ability to process how many requests or how much data within a given period (e.g., number of transactions per second).
- Latency: The time required to respond to a request (e.g., website loading time).
- Resource Utilization: The level of usage of hardware resources such as CPU, RAM, Disk I/O, and Network.
When server performance declines, it’s often due to one or more overloaded resources, creating what we call a “bottleneck.” Our task is to identify these bottlenecks and fix them. For example, if the CPU is consistently running at 100% while there’s plenty of free RAM, then the CPU is the bottleneck.
Detailed Practice: Steps to Optimize Linux Server Performance
1. Monitoring and Analysis: Know Thy Enemy (and Thyself)
The first and most important step to optimize any system is to monitor it. You cannot improve what you do not measure. Linux provides many powerful tools for resource monitoring.
Overview of Resource Monitoring
Commands like top and htop (a more popular and feature-rich tool than top) give you an overview of CPU, RAM, swap, and running processes.
htop
To view only RAM and swap usage:
free -h
Check disk space:
df -h
Disk I/O Monitoring
iostat helps effectively check disk I/O performance:
iostat -x 1 10
This command will display detailed I/O reports every second, repeated 10 times. Pay attention to important columns such as %util (device utilization), r/s, w/s (reads/writes per second), rkB/s, wkB/s (amount of data read/written per second). In particular, the await column (average wait time for I/O operations) is very noteworthy.
iotop is also very useful for seeing which process is causing the most I/O, similar to top for CPU/RAM:
iotop
Network Monitoring
ss (a modern replacement for netstat) helps you view active network connections:
ss -tulpn
This command displays listening TCP, UDP sockets and established sockets along with their process names.
Checking Logs (System Logs)
Never ignore log files! They are a treasure trove of information that helps you understand what’s happening on the server. When I was a new sysadmin, I once spent an entire afternoon debugging a slow server just because I didn’t thoroughly read the logs. It turned out that a failing service was continuously trying to restart, consuming CPU and Disk I/O resources. If I had bothered to check the logs sooner, I would have saved a lot of time!
Important logs to check:
/var/log/syslogor/var/log/messages(general system logs)- Logs for specific applications (Apache, Nginx, database, your application…)
- Use
journalctlfor systemd-based systems:
journalctl -xe
This command will display the most recent logs, helping you quickly detect errors or warnings.
2. CPU Optimization
If top or htop shows your CPU is frequently at a high level, here are some optimization methods:
- Identify CPU-intensive processes: Use
top/htop, sort by the%CPUcolumn to find the process consuming the most CPU. Then, you need to investigate whether that process is operating correctly or has an error. - Adjust process priority: If there are processes that are not critical but still need to run, you can lower their priority using
niceandrenice. This helps them yield CPU to more important processes.
# Run a command with lower priority (e.g., my_command will receive fewer CPU resources)
nice -n 10 my_command
# Change the priority of a running process (PID is the process ID)
renice +10 -p <PID>
A higher nice value (e.g., +19) means lower priority. Conversely, a lower value (e.g., -20) means higher priority.
3. RAM and Swap Optimization
RAM is an extremely crucial resource for server speed. If RAM is insufficient, the system will have to use swap (a portion of the disk used as virtual RAM). This is hundreds of times slower than real RAM.
Controlling Swappiness
swappiness is a kernel parameter that controls how aggressively the system uses swap space. By default on Ubuntu, this value is often 60, meaning the kernel will start using swap when 40% of RAM is free. In a production environment, we generally want the server to prioritize keeping data in RAM. Restricting swapping too early is crucial.
# Check current swappiness value
sysctl vm.swappiness
# Set a lower swappiness value (e.g., 10) to use less swap
sudo sysctl vm.swappiness=10
# To make this change permanent, add to /etc/sysctl.conf
sudo echo "vm.swappiness=10" >> /etc/sysctl.conf
The appropriate swappiness value will depend on your application. For high-performance applications that rarely use swap, a value of 10 or even 1 is ideal. Conversely, if the server has limited RAM and you want to avoid system crashes due to out-of-memory (OOM killer), you can keep the default value or increase it slightly.
Reducing File System Cache
The Linux kernel often uses a portion of RAM to cache file systems such as page cache, inode cache, and dentry cache to speed up read/write operations. This is generally good, but sometimes these caches can consume too much RAM, leading to memory shortages for applications that truly need it. The vm.vfs_cache_pressure parameter controls how aggressively the kernel reclaims these caches. The default value is 100.
# Check current value
sysctl vm.vfs_cache_pressure
# Decrease this value (e.g., 50) so the kernel reclaims caches less aggressively, keeping them in RAM longer
sudo sysctl vm.vfs_cache_pressure=50
# To make the change permanent
sudo echo "vm.vfs_cache_pressure=50" >> /etc/sysctl.conf
Adjusting vm.vfs_cache_pressure requires careful consideration. If reduced too low, the file system might become slower. This is an advanced optimization and is usually only performed when you have a clear understanding of your application and have explored other options.
4. Disk I/O Optimization
Disk I/O (Input/Output) is one of the most common bottlenecks, especially for database applications or large file processing.
Mount Options
When mounting filesystems, you can add options to improve performance:
noatime: By default, Linux updates the access time (atime) every time a file is read. This causes a significant amount of unnecessary Disk I/O write operations. Thenoatimeoption disables this update, helping to reduce disk load.
To add noatime, edit the /etc/fstab file. Find the mount line of the partition you want to optimize and add noatime to the options list.
For example, from:
UUID=... / ext4 defaults 0 1
To:
UUID=... / ext4 defaults,noatime 0 1
After editing, you need to remount the partition (or restart the server):
sudo mount -o remount /
Be careful when editing /etc/fstab, a small error can prevent the system from booting.
I/O Scheduler
The I/O scheduler determines the order in which read/write requests are sent to the physical disk. Common schedulers are noop, deadline, and cfq.
noop: This is the simplest scheduler, often suitable for SSDs or virtualized environments. Here, I/O coordination is already handled at the hardware or hypervisor layer.deadline: Prioritizes read requests and sets deadlines for them, ensuring no request waits too long. Often good for database applications.cfq(Completely Fair Queuing): Attempts to distribute I/O bandwidth fairly among processes. Often good for desktops or general-purpose servers with traditional HDDs.
With modern SSDs, noop or deadline often yield better performance.
# Check the current scheduler for sda disk
cat /sys/block/sda/queue/scheduler
# Set the scheduler to noop
sudo echo noop > /sys/block/sda/queue/scheduler
To make this change permanent, you need to edit the GRUB configuration file or use udev rules.
5. Network Optimization
Although some advanced network configurations have been covered in other articles, you can still apply some basic optimizations to the Linux kernel’s TCP/IP stack to improve overall network performance.
TCP/IP Tuning
Edit the /etc/sysctl.conf file to add or modify the following kernel parameters:
# Increase the maximum number of connections that can be kept in TIME_WAIT state
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 500000
# Increase the queue for incoming connections that have not yet been accepted
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# Increase network buffer limits (receive buffer and send buffer)
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 4194304
# Enable Fast Open (reduces TCP connection setup latency)
net.ipv4.tcp_fastopen = 3
After editing, apply the changes:
sudo sysctl -p
These parameters help the server better handle incoming and outgoing connections, reducing the likelihood of network congestion due to a lack of socket resources, especially under high load.
Increasing File Descriptors Limit (ulimit)
Every network connection or open file uses a file descriptor. Applications like web servers or databases may need to open thousands, even tens of thousands, of file descriptors simultaneously. If this limit is too low, the application will encounter errors and cannot operate effectively.
Check the current limit for your shell process:
ulimit -n
To increase this limit for the entire system, you need to edit the /etc/security/limits.conf file:
# Add these two lines to the end of the file to set soft and hard limits
* soft nofile 65535
* hard nofile 65535
And ensure that the PAM module is enabled in /etc/pam.d/common-session or /etc/pam.d/login (usually enabled by default):
session required pam_limits.so
After making changes, you need to log out and log back in or restart the server for the changes to take effect.
Conclusion
Optimizing Linux server performance is a continuous process that requires monitoring, analysis, and adjustment. There is no one-size-fits-all formula, as each application and environment has unique requirements. The important thing is to understand how your server is operating, which resources are bottlenecks, and then apply appropriate optimization measures.
Remember, optimization doesn’t stop at initial configuration. You need to constantly monitor the system, read logs, and be ready to adjust as the workload changes. With the knowledge and tools in this article, I believe you have enough preparation to begin your journey of making your server faster and more powerful.

