12.11. Configuring the Berkeley DB

You know that you need to use the /var/lib/ldap/DB_CONFIG file to configure the database backend to your LDAP directory (Berkeley DB) so that it will perform peppily and not get all bogged down. How do you know what options and values to use?

We'll start off with some reasonable values for starters, and then learn how to make some calculations to fine-tune them.

Be sure to check your slapd.conf for duplicate BDB entries and get rid of them. They can go in either file, but it's best to keep them all in DB_CONFIG. You don't want duplicates or conflicting entries.

First, make sure there is a cachesize entry in slapd.conf:

	cachesize 5000

Then, enter these options and values into /var/lib/ldap/DB_CONFIG:

	##/var/lib/ldap/DB_CONFIG
	set_cachesize 0 1048576 0
	set_lk_max_objects 1500
	set_lk_max_locks 1500
	set_lk_max_lockers 1500
	#
	#logging settings
	set_lg_regionmax 1048576
	set_lg_bsize 32768
	set_lg_max 131072
	set_lg_dir /var/log/openldap

The set_cachesize value is in bytes, and must be a power of 2, so the example is one megabyte. How do you know how much to use? Use the db4.2_stat command on Debian, and the db_stat command on Fedora to generate statistics from id2entry.bdb and dn2id.bdb, which are the two main database files:

	# db4.2_stat -d /var/lib/ldap/id2entry.bdb
	53162   Btree magic number.
	9       Btree version number.
	Flags:  little-endian
	2       Minimum keys per-page.
	16384   Underlying database page size.
	1       Number of levels in the tree.
	6       Number of unique keys in the tree.
	6       Number of data items in the tree.
	0       Number of tree internal pages.
	0       Number of bytes free in tree internal pages (0% ff).
	1       Number of tree leaf pages.
	12374   Number of bytes free in tree leaf pages (24% ff).

	0       Number of tree duplicate pages.
	0       Number of bytes free in tree duplicate pages (0% ff).
	0       Number of tree overflow pages.
	0       Number of bytes free in tree overflow pages (0% ff).
	0       Number of pages on the free list.

	# db4.2_stat -d /var/lib/ldap/dn2id.bdb
	53162   Btree magic number.
	9       Btree version number.
	Flags:  duplicates, little-endian
	2       Minimum keys per-page.
	4096    Underlying database page size.
	1       Number of levels in the tree.
	13      Number of unique keys in the tree.
	19      Number of data items in the tree.
	0       Number of tree internal pages.
	0       Number of bytes free in tree internal pages (0% ff).
	1       Number of tree leaf pages.
	3378    Number of bytes free in tree leaf pages (18% ff).

	0       Number of tree duplicate pages.
	0       Number of bytes free in tree duplicate pages (0% ff).
	0       Number of tree overflow pages.
	0       Number of bytes free in tree overflow pages (0% ff).
	0       Number of pages on the free list.

You can see that each id2entry.bdb page requires 16 KB, and dn2id.bdb needs 4 KB per page, and the number of internal pages each one is using. So, you can use this formula to calculate a bare minimum memory requirement:

	((50+1) * 4096) + ((12+1) * 16384)) = 421,888 bytes

This does not take into account other library overhead or indexing. As a shortcut, double this figure for decent performance. So, for this example, we could round it up to a whopping 1 MB of RAM.

How do you know what values to assign to set_lk_max_objects 1500, set_lk_max_locks 1500, and set_lk_max_lockers 1500? Use the db4.2_stat -c (db_stat on Fedora) command:

	# cd /var/lib/ldap
	# db4.2_stat -c
	100     Last allocated locker ID.
	2147M   Current maximum unused locker ID.
	9       Number of lock modes.
	1500    Maximum number of locks possible.
	1500    Maximum number of lockers possible.
	1500    Maximum number of lock objects possible.
	3       Number of current locks.
	11      Maximum number of locks at any one time.
	12      Number of current lockers.
	19      Maximum number of lockers at any one time.
	3       Number of current lock objects.
	8       Maximum number of lock objects at any one time.
	1170    Total number of locks requested.
	1167    Total number of locks released.
	0       Total number of lock requests failing because DB_LOCK_NOWAIT was set.
	0       Total number of locks not immediately available due to conflicts.
	0       Number of deadlocks.
	0       Lock timeout value.
	0       Number of locks that have timed out.
	0       Transaction timeout value.
	0       Number of transactions that have timed out.
	552KB   The size of the lock region..
	0 The   number of region locks granted after waiting.
	2579    The number of region locks granted without waiting.

1500 is a reasonable starting point for a smaller directory; use your db4.2_stat -c output to decide if you need to increase it. When usage hits 85 percent of your allocated values, increase them. Look at your Number of current values outputs, timeouts, and failures.

For OpenLDAP versions 2.3 and above, all you need to do after changing DB_CONFIG is restart slapd:

	# /etc/init.d/slapd restart (Debian)
	# /etc/init.d/ldap restart (Fedora)

However, this doesn't always work, so if slaptest returns errors, and is on 2.2 and older, Debian users need to use the database recovery command:

	# /etc/init.d/slapd stop
	# db4.2_recover -h /var/lib/ldap
	# /etc/init.d/slapd start

Fedora users have slightly different commands:

	# /etc/init.d/ldap stop
	# db_recover -h /var/lib/ldap
	# /etc/init.d/ldap start

Then, run this command to verify your new cache size. These examples are based on a value of 16777216 in DB_CONFIG. As usual, the Debian command is first, Fedora second:

	# db4.2_stat -h /var/lib/ldap -m | head -n 2
	20MB 1KB 604B Total cache size.
	1       Number of caches.# db_stat -h /var/lib/ldap -m | head -n 2

Now, keep an eye on the performance while slapd is running. Change to the directory your database is stored in:

	# cd /var/lib/ldap
	# db4.2_stat -m (Debian)
	# db_stat -m (Fedora)

This displays complete cache statistics.

cachesize defines the number of entries that the LDAP backend will keep in memory. For best performance, this number is equal to the number of entries in your directory, but it can be smaller. This is not the BDB cache, but OpenLDAP's own internal cache. The default is 1000.

Watch your disk I/O—iostat is a good tool for this—and keep an eye on the Requested pages found in the cache value, which you get from running db_stat-m in your database directory. You want this to be as close to 100 percent as possible, and the pages forced from the cache should be 0. If it falls under 95 percent, increase your set_cachesize value. You want requests to be answered from the memory cache as much as possible; you don't want a lot of disk thrashing.

set_cachesize has three fields: <gbytes>, <bytes>, and <ncache>. If you want to create a 2 GB cache, it looks like set_cachesize200. You may combine both gigabytes and bytes. The maximum is 4 GB. Don't make your cache larger than your total system memory. Any cache size less than 500 MB is automatically increased by 25 percent to account for buffer pool overhead.

ncache tells BDB if it should use one contiguous section of memory, or more than one. 0 or 1 means one segment; a larger number means create that number of segments. Modern Linux kernels support 1–3 GB per user process on 32-bit x86 systems, and don't forget that the kernel needs a good-sized chunk as well. This example splits a 2 GB cache across two segments:

	set_cachesize 2 0 2

On 64-bit systems, theoretically your whole memory space, except the bit reserved for the kernel, can be used by a single process.

Creating a too-big set_cachesize value can hurt overall system performance, but it won't hurt OpenLDAP, so you can set a generous value if you have abundant RAM. If you need to be frugal with your available RAM, check the See Also section for detailed references on making finer calculations.

The set_lk_max_locks, set_lk_max_lockers, and set_lk_max_objects set the maximum number of locks, lockers, and locked objects, respectively. If the values are too small, requests for locks will fail. If the values are too large, the locking sub-system will use more resources than it really needs. It's safer to have too much. Run db4.2_stat-c (db_stat -c in Fedora) in your database directory to keep tabs on this.

The locking subsystem keeps reads and writes in order. Anything that is writing to the BDB gets an exclusive lock on the object it is writing to. Reads are shared.

Configuring logging will also affect performance. This is what the examples mean: