Chapter 36. Performance Tuning

IN THIS CHAPTER

Squeezing extra performance out of your hardware might sound like a pointless task given how cheap commodity upgrades are today. To a certain degree that is true—for most of us, it is cheaper to buy a new computer than to spend hours fighting to get a 5% speed boost. But what if the speed boost were 20%? How about if it were 50%?

The amount of benefit you can get by optimizing your system varies depending on what kinds of tasks you are running, but there is something for everyone. Over the next few pages we will be looking at quick ways to optimize the Apache web server, both the KDE and GNOME desktop systems, both MySQL and PostgreSQL database servers, and more.

Before we start, you need to understand that optimization is not an absolute term: If we optimize a system, we improve its performance, but it is still possible it could further be increased. We are not interested in getting 99.999% performance out of a system because optimization suffers from the law of diminishing returns—the basic changes make the biggest differences, but after that it takes increasing amounts of work to obtain decreasing speed improvements.

Hard Disk

Many Linux users love to tinker under the hood to increase the performance of their computers, and Linux gives you some great tools to do just that. Whereas mothers tell us, “Don’t fix what’s not broken,” fathers often say, “Fix it until it breaks.” In this section, you learn about many of the commands used to tune, or “tweak,” your file system.

Before you undertake any “under the hood” work with Linux, however, keep a few points in mind. First, perform a benchmark on your system before you begin. Linux does not offer a well-developed benchmarking application, but availability changes rapidly. You can search online for the most up-to-date information for benchmarking applications for Linux. If you are a system administrator, you might choose to create your own benchmarking tests. Second, tweak only one thing at a time so that you can tell what works, what does not work, and what breaks. Some of these tweaks might not work or might lock up your machine.

Always have a working boot disk handy and remember that you are personally assuming all risks for attempting any of these tweaks.

Using the BIOS and Kernel to Tune the Disk Drives

One method of tuning involves adjusting the settings in your BIOS. Because the BIOS is not Linux and every BIOS seems different, always read your motherboard manual for better possible settings and make certain that all the drives are detected correctly by the BIOS. Change only one setting at a time.

Linux does provide a limited means to interact with BIOS settings during the boot process (mostly overriding them). In this section, you will learn about those commands.

Other options are in the following list, and are more fully outlined in the BOOTPROMPT HOWTO and the kernel documentation. These commands can be used to force the IDE controllers and drives to be optimally configured. Of course, YMMV (Your Mileage May Vary) because these do not work for everyone.

  • idex=dma—. This will force DMA support to be turned on for the primary IDE bus, where x=0, or the secondary bus, where x=1.

  • idex=autotune—. This command will attempt to tune the interface for optimal performance.

  • idex=ata66—. If you have ATA66 drives and controllers, this command will enable support for it.

  • hdx=ide-scsi—. This command will enable SCSI emulation of an IDE drive. This is required for some CD-RW drives to work properly in write mode and it might provide some performance improvements for regular CD-R drives as well.

  • idebus=xx—. This can be any number from 20 to 66; autodetection is attempted, but this can set it manually if dmesg says that it isn’t autodetected correctly or if you have it set in the BIOS to a different value (overclocked). Most PCI controllers will be happy with 33.

  • pci=biosirq—. Some motherboards might cause Linux to generate an error message saying that you should use this. Look in dmesg for it; if you do not see it, you don’t need to use it.

These options can be entered into /etc/lilo.conf or /boot/grub/grub.conf in the same way as other options are appended.

The hdparm Command

The hdparm utility can be used by root to set and tune the settings for IDE hard drives. You would do this to tune the drives for optimal performance.

Once a kernel patch and associated support programs, the hdparm program is now included with Fedora Core. You should experiment only with the drives mounted read-only because some settings can damage some file systems when used improperly. The hdparm command also works with CD-ROM drives and some SCSI drives.

The general format of the command is this:

# hdparm command device

This command runs a hard disk test:

hdparm -tT /dev/hda

You will need to replace /dev/hda with the location of your hard disk. hdparm will then run two tests: cached reads and buffered disk reads. A good IDE hard disk should be getting 400–500MB/sec for the first test, and 20–30MB/sec for the second. Note your scores, and then try this command:

hdparm -m16 -d1 -u1 -c1 /dev/hda

That enables various performance-enhancing settings. Now try executing the original command again—if you see an increase, you should run this command:

hdparm -m16 -d1 -u1 -c1 -k1 /dev/hda

The extra parameter tells hdparm to write the settings to disk so that they will be used each time you boot up—ensuring optimal disk performance in the future.

The man entry for hdparm is extensive and contains useful detailed information, but because the kernel configuration selected by Fedora Core already attempts to optimize the drives, it might be that little can be gained through tweaking. Because not all hardware combinations can be anticipated by Fedora Core or by Linux and performance gains are always useful, you’re encouraged to try.

Tip

You can use the hdparm command to produce a disk transfer speed result with

# hdparm -tT device

Be aware, however, that although the resulting numbers appear quantitative, they are subject to several technical qualifications beyond the scope of what is discussed and explained in this chapter. Simply put, do not accept values generated by hdparm as absolute numbers, but only as a relative measure of performance.

Systemwide tweaks to hdparm are formally handled through the /etc/sysconfig/harddisks files, but this file’s use is poorly documented and, therefore, of little use.

Tip

You might find that your system turns off DMA for any CD-RW drives detected via a shell script command in rc.sysinit. This might not be appropriate for your hardware, so you can turn it back on simply by adding the line options ide-cd dma=1 to /etc/modules.conf.

File System Tuning

Never content to leave things alone, Linux provides several tools to adjust and customize the file system settings. The belief is that hardware manufacturers and distribution creators tend to select conservative settings that will work well all the time, leaving some of the potential of your system leashed—that’s why you have chosen Red Hat Fedora 5 Unleashed to help you.

The Linux file system designers have done an excellent job of selecting default values used for file system creation and the 2.6 version of the Linux kernel now contains new code for the IDE subsystem that significantly improves I/O (input/output) transfer speeds over older versions, obviating much of the need for special tweaking of the file system and drive parameters if you use IDE disks. Although these values work well for most users, some server applications of Linux benefit from file system tuning. As always, observe and benchmark your changes.

The mke2fs Command

mke2fs -O sparse_super will create a file system with sparse superblocks, reducing the space allocated to root for file system repair. This is not a performance enhancement per se, but it frees up additional space on a drive. This command works only on pre-2.2 kernels and is included here because a number of existing references don’t make that distinction. With kernel version 2.2, the sparse superblock option has been moved to tune2fs. This feature is turned on by default, so you will always create any new file systems with sparse superblocks.

mke2fs -b blocksize sets the block size. The block size chosen can also have an effect on the performance of the file system. A larger block size works better with large files and vice versa. There doesn’t seem to be any hard and fast rule about this, and most advice is to accept the default block size of 1024KB unless you want to spend some time running benchmarks.

The tune2fs Command

With tune2fs, you can adjust the tunable file system parameters on an ext2 or ext3 file system. A few performance-related items of note are as follows:

  • To disable file system checking, the -c 0 option sets the maximum mount count to zero.

  • The interval between forced checks can be adjusted with the -I option.

  • The -m option will set the reserved blocks percentage with a lower value, freeing more space at the expense of fsck having less space to write any recovered files.

  • Decrease the number of superblocks to save space with the -O sparse_super option. (Modern file systems use this by default.) Always run e2fsck after you change this value.

  • More space can be freed with the -r option that sets the number of reserved (for root) blocks.

Note that most of these uses of tune2fs free up space on the drive at the expense of the capability of fsck to recover data. Unless you really need the space and can deal with the consequences, just accept the defaults; large drives are now relatively inexpensive.

The e2fsck Command

This utility checks an ext2/ext3 file system. Some useful arguments taken from man e2fsck are as follows:

  • -c—. Checks for bad blocks and then marks them as bad.

  • -f—. Forces checking on a clean file system.

  • -v—. Verbose mode.

The badblocks Command

Although not a performance tuning program per se, the badblocks utility checks an (preferably) unmounted partition for bad blocks. It is not recommended that you run this command by itself, but rather allow it to be called by fsck. It should be used directly only if you specify the block size accurately—don’t guess or assume anything.

The options available for badblocks are detailed in the man page. They allow for very low-level manipulation of the file system that is useful for data recovery by file system experts or for file system hacking, but is beyond the scope of this chapter and the average user.

Disabling File Access Time

Whenever Linux reads a file, it changes the last access time—known as the atime. This is also true for your web server: If you are getting hit by 50 requests a second, your hard disk will be updating the atime 50 times a second. Do you really need to know the last time a file was accessed? If not, you can disable the atime setting for a directory by typing this:

chattr -R +A /path/to/directory

The chattr command changes file system attributes, of which “don’t update atime” is one. To set that attribute, use +A and specify -R so that it is recursively set. /path/to/directory gets changed, and so do all the files and subdirectories it contains.

Kernel

As the Linux kernel developed over time, developers sought a way to fine-tune some of the kernel parameters. Before sysctl, those parameters had to be changed in the kernel configuration and then the kernel had to be recompiled.

The sysctl command can change some parameters of a running kernel. It does this through the /proc file system, which is a “virtual window” into the running kernel. Although it might appear that a group of directories and files exist under /proc, that is only a representation of parts of the kernel. We can read values from and write values to those “files,” referred to as variables. We can display a list of the variables as shown in the following. (An annotated list is presented because roughly 250 items [or more] exist in the full list.)

# sysctl -A
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.ipfrag_time = 30

The items shown are networking parameters, and actually tweaking these values is beyond the scope of this book. If we want to change a value, however, the -w command is used:

# sysctl -w net.ipv4.tcp_retries 2=20

This increases the value of that particular kernel parameter.

Note

Fedora Core provides a graphical interface to the sysctl command in system-config-proc. It’s still a beta-quality application, and it must be launched from the command line. The interface itself is unremarkable, and it does not provide a means to manipulate all the possible values, but it does offer useful help for the kernel variables it addresses.

If you find that a particular setting is useful, you can enter it into the /etc/sysctl.conf file. The format is as follows, using the earlier example:

net.ipv4.tcp_retries 2=20

Of more interest to kernel hackers than regular users, sysctl is a potentially powerful tool that continues to be developed and documented.

Tip

The kernel does a good job of balancing performance for graphical systems, so there’s not a great deal you can do to tweak your desktop to run faster.

Both GNOME and KDE are “heavyweight” desktop systems: They are all-inclusive, all-singing, and all-dancing environments that do far more than browse your file system. The drawback to this is that their size makes them run slow on older systems. On the flip side, Fedora also comes with the Xfce desktop, which is a great deal slimmer and faster than the other two. If you find GNOME and KDE are struggling just to open a file browser, Xfce is for you.

Alternatively, if you simply cannot live without GNOME or KDE, take a look in the /usr/share/autostart directory, where you will see a list of files that are started when your graphical system boots. If you do not need any of them, simply move them out of there and into somewhere safe in case you ever need them again.

Apache

Despite being the most popular web server on the Internet, Apache is by no means the fastest. Part of the problem is that Apache has been written to follow every applicable standard to the letter, so much of its development work has been geared toward standards-compliancy rather than just serving web pages quickly. That said, with a little tweaking we can convert a $1,000 Dell server into something capable of surviving the Slashdot Effect.

Note

Slashdot.org is a popular geek news website that spawned the Slashdot Effect—the result of thousands of geeks descending on an unsuspecting website simultaneously. Our $1,000 Dell server had dual-2.8GHz Xeons with 1GB of RAM and SCSI hard disks—if you have more RAM, faster chips, and a high-end network card you can kick sand in Slashdot’s face.

The first target of your tuning should be the httpd.conf file in /etc/httpd/conf, as well as the other files in /etc/httpd/conf.d. The more modules you have loaded, the more load Apache is placing on your server—take a look through the LoadModule list and comment out (start the line with a #) the ones you do not want. Some of these modules can be uninstalled entirely through the Add or Remove Packages dialog.

As a rough guide, you will almost certainly need mod_mime and mod_dir, and probably also mod_log_config. The default Apache configuration in Fedora is quite generic, so unless you are willing to sacrifice some functionality you might also need mod_negotiation (a speed killer if there ever was one), and mod_access (a notorious problem). Both of those last two modules can and should work with little or no performance decrease, but all too often they get abused and just slow things down.

Whatever you do, when you are disabling modules you should ensure you leave either mod_deflate or mod_gzip enabled, depending on your Apache version. Your bottleneck is almost certainly going to be your bandwidth rather than your processing power, and having one of these two compressing your content will usually turn 10Kb of HTML into 3Kb for supported browsers (most of them).

Next, ensure keepalives are turned off. Yes, you read that right: Turn keepalives off. This adds some latency to people viewing your site because they cannot download multiple files through the same connection. However, it in turn reduces the number of simultaneous open connections and so allows more people to connect.

If you are serving content that does not change, you can take the extreme step of enabling MMAP support. This allows Apache to serve pages directly from RAM without bothering to check whether they have changed, which works wonders for your performance. However, the downside is that when you do change your pages you need to restart Apache. Look for the EnableMMAP directive—it is probably commented out and set to off, so you will need to remove the comment and set it to On.

Finally, you should do all you can to ensure that your content is static: Avoid PHP if you can, avoid databases if you can, and so on. If you know you are going to get hit by a rush of visitors, use plain HTML so the speed with which Apache can serve pages is limited only by your bandwidth.

Tip

Some people, when questioned about optimizing Apache, will recommend you tweak the HARD_SERVER_LIMIT in the Apache source code and recompile. Although we agree that compiling your own Apache source code is a great way to get a measurable speed boost if you know what you are doing, you should only need to change this directive only if you are hosting a huge site.

The default value, 256, is enough to handle the Slashdot Effect—and if you can handle that, you can handle most things.

MySQL

Tuning your MySQL server for increased performance is exceptionally easy to do, largely because you can see huge speed increases simply by getting your queries right. That said, there are various things you can tune in the server itself to help it cope with higher loads as long as your system has enough RAM.

The key is understanding its buffers—there are buffers and caches for all sorts of things, and finding out how full they are is crucial to maximizing performance. MySQL performs best when it has is making full use of its buffers, which in turn places a heavy demand on system RAM. Unless you have 4GB RAM or more in your machine, you do not have enough capacity to set very high values for all your buffers—you need to pick and choose.

Measuring Key Buffer Usage

When you add indexes to your data, it enables MySQL to find data faster. However, ideally you want to have these indexes stored in RAM for maximum speed, and the variable key_buffer_size defines how much RAM MySQL can allocate for index key caching. If MySQL cannot store its indexes in RAM, you will experience serious performance problems. Fortunately, most databases have relatively small key buffer requirements, but you should measure your usage to see what work needs to be done.

To do this, log in to MySQL and type SHOW STATUS LIKE '%key_read%';. That returns all the status fields that describe the hit rate of your key buffer—you should get two rows back: Key_reads and Key_read_requests, which are the number of keys being read from disk and the number of keys being read from the key buffer. From these two numbers you can calculate the percentage of requests being filled from RAM and from disk, using this simple equation:

100 – ((Key_reads / Key_read_requests) × 100)

That is, you divide Key_reads by Key_read_requests, multiply the result by 100 and then subtract the result from 100. For example, if you have Key_reads of 1000 and Key_read_requests of 100000, you divide 1000 by 100000 to get 0.01; then you multiply that by 100 to get 1.0, and subtract that from 100 to get 99. That number is the percentage of key reads being served from RAM, which means 99% of your keys are served from RAM.

Most people should be looking to get more than 95% served from RAM, although the primary exception is if you update or delete rows very often—MySQL can’t cache what keeps changing. If your site is largely read only, this should be around 98%. Lower figures mean you might need to bump up the size of your key buffer.

If you are seeing problems, the next step is to check how much of your current key buffer is being used. Use the SHOW VARIABLES command and look up the value of the key_buffer_size variable. It is probably something like 8388600, which is eight million bytes, or 8MB. Now, use the SHOW STATUS command and look up the value of Key_blocks_used.

You can now determine how much of your key buffer is being used by multiplying Key_blocks_used by 1024, dividing by key_buffer_size, and multiplying by 100. For example, if Key_blocks_used is 8000, you multiply that by 1024 to get 8192000; then you divide that by your key_buffer_size (8388600) to get 0.97656, and finally multiply that by 100 to get 97.656. Thus, almost 98% of your key buffer is being used.

Now, on to the important part: You have ascertained that you are reading lots of keys from disk, and you also now know that the reason for reading from disk is almost certainly because you do not have enough RAM allocated to the key buffer. A general rule of thumb is to allocate as much RAM to the key buffer as you can, up to a maximum of 25% of system RAM—128MB on a 512MB system is about the ideal for systems that read heavily from keys. Beyond that, you will actually see drastic performance decreases because the system has to use virtual memory for the key buffer.

Open /etc/my.cnf in your text editor, and look for the line that contains key_buffer_size. If you do not have one, you need to create a new one—it should be under the line [mysqld]. When you set the new value, do not just pick some arbitrarily high number. Try doubling what is there right now (or try 16MB if there’s no line already); then see how it goes. To set 16MB as the key buffer size, you would need a line like this:

[mysqld]
set-variable = key_buffer_size=16M
datadir=/var/lib/mysql

Restart your MySQL server with service mysqld restart, and then go back into MySQL and run SHOW VARIABLES again to see the key_buffer_size. It should be 16773120 if you have set it to 16M. Now, because MySQL just got reset, all its values for key hits and the like will also have been reset. You need to let it run for a while so that you can assess how much has changed. If you have a test system you can run, this is the time to run it.

After your database has been accessed with normal usage for a short while (if you get frequent accesses, this might be only a few minutes), recalculate how much of the key buffer is being used. If you get another high score, double the size again, restart, and retest. You should keep repeating this until you see your key buffer usage is below 50% or you find you don’t have enough RAM to increase the buffer further—remember that you should never allocate more than 25% of system RAM to the key buffer.

Using the Query Cache

Newer versions of MySQL allow you to cache the results of queries so that, if new queries come in that use exactly the same SQL, the result can be served from RAM. In some ways the query cache is quite intelligent: If, for example, part of the result changes due to another query, the cached results are thrown away and recalculated next time. However, in other ways it is very simple. For example, it uses cached results only if the new query is exactly the same as a cached query, even down to the capitalization of the SQL.

The query cache works well in most scenarios. If your site has an equal mix of reading and writing, the query cache will do its best but will not be optimal. If your site is mostly reading with few writes, more queries will be cached (and for longer), thus improving overall performance.

First, you need to find out whether you have the query cache enabled. To do this, use SHOW VARIABLES and look up the value of have_query_cache. All being well, you should get YES back, meaning that the query cache is enabled. Next, look for the value of query_cache_size and query_cache_limit—the first is how much RAM in bytes is allocated to the query cache, and the second is the maximum result size that should be cached. A good starting set of values for these two is 8388608 (8MB) and 1048576 (1MB).

Next, type SHOW STATUS LIKE 'Qcache%'; to see all the status information about the query cache. You should get output like this:

mysql> SHOW STATUS LIKE 'qcache%';
+-------------------------+--------+
| Variable_name           | Value  |
+-------------------------+--------+
| Qcache_free_blocks      | 1      |
| Qcache_free_memory      | 169544 |
| Qcache_hits             | 698    |
| Qcache_inserts          | 38     |
| Qcache_lowmem_prunes    | 20     |
| Qcache_not_cached       | 0      |
| Qcache_queries_in_cache | 18     |
| Qcache_total_blocks     | 57     |
+-------------------------+--------+
8 rows in set (0.00 sec)

From that, we can see that only 18 queries are in the cache (Qcache_queries_in_cache), we have 169544 bytes of memory free in the cache (Qcache_free_memory), 698 queries have been read from the cache (Qcache_hits), 38 queries have been inserted into the cache (Qcache_inserts), but 20 of them were removed due to lack of memory (Qcache_lowmem_prunes), giving the 18 from before. Qcache_not_cached is 0, which means 0 queries were not cached—MySQL is caching them all.

From that, we can calculate how many total queries came in—it is the sum of Qcache_hits, Qcache_inserts, and Qcache_not_cached, which is 736. We can also calculate how well the query cache is being used by dividing Qcache_hits by that number and multiplying by 100. In this case, 94.84% of all queries are being served from the query cache, which is a great number.

In our example, we can see that many queries have been trimmed because there is not enough memory in the query cache. This can be changed by editing your /etc/my.cnf file and adding a line like this one, somewhere in the [mysqld] section:

set-variable = query_cache_size=32M

An 8MB query cache should be enough for most people, but larger sites might want 16MB or even 32MB if you are storing a particularly large amount of data. Very few sites have need to go beyond a 32MB query cache, but keep an eye on the Qcache_lowmem_prunes value to ensure that you have enough RAM allocated.

Using the query cache does not incur much of a performance hit. When MySQL calculates the result of a query normally, it simply throws the result away when the connection closes. With the query cache, it skips the throwing away, and so there is no extra work being done. If your site does have many updates and deletes, be sure to check whether you get any speed boost at all from the query cache.

Miscellaneous Tweaks

If you have tuned your key buffer and optimized your query cache and yet still find your site struggling, there are a few additional small changes you can make that will add some more speed.

When reading from tables, MySQL has to open the file that stores the table data. How many files it keeps open at a time is defined by the table_cache setting, which is set to 64 by default. You can increase this setting if you have more than 64 tables, but you should be aware that Fedora does impose limits on MySQL about how many files it can have open at a time. Going beyond 256 is not recommended unless you have a particularly database-heavy site and know exactly what you are doing.

The other thing you can tweak is the size of the read buffer, which is controlled by read_buffer_size and read_buffer_rnd_size. Both of these are allocated per connection, which means you should be very careful to have large numbers. Whatever you choose, read_buffer_rnd_size should be three to four times the size of read_buffer_size, so if read_buffer_size is 1MB (suitable for very large databases), read_buffer_rnd_size should be 4MB.

Query Optimization

The biggest speed-ups can be seen by reprogramming your SQL statements so they are more efficient. If you follow these tips, your server will thank you:

  • Select as little data as possible. Rather than SELECT *, select only the fields you need.

  • If you only need a few rows, use LIMIT to select the number you need.

  • Declare fields as NOT NULL when creating tables to save space and increase speed.

  • Provide default values for fields, and use them where you can.

  • Be very careful with table joins because they are the easiest way to write inefficient queries.

  • If you must use joins, be sure you join on fields that are indexed. They should preferably be integer fields because these are faster than strings for comparisons.

  • Find and fix slow queries. Add log-long-format and log-slow-queries = /var/log/slow-queries.log to your /etc/my.cnf file, under [mysqld], and MySQL will tell you the queries that took a long time to complete.

  • Use OPTIMIZE TABLE tablename to defragment tables and refresh the indexes.

Reference

http://www.coker.com.au/bonnie++/—The home page of bonnie, a disk benchmarking tool. It also contains a link to RAID benchmarking utilities and Postal, a benchmarking utility for SMTP servers.

http://httpd.apache.org/docs-2.0/misc/perf-tuning.html—The official Apache guide to tuning your web server.

http://dev.mysql.com/doc/mysql/en/mysql-optimization.html—Learn how to optimize your MySQL server directly from the source, the MySQL manual.

There is one particular MySQL optimization book that will really help you get more from your system if you run a large site, and that is High Performance MySQL by Jeremy Zawodny and Derek Balling (O’Reilly), ISBN: 0-596-00306-4.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.198.174