Command logging can provide complete durability, preserving a record of every transaction that is completed before the database stops. However, the amount of durability must be balanced against the performance impact and hardware requirements to achieve effective I/O.
VoltDB provides three settings you can use to optimize command logging:
The amount of disk space allocated to the command logs
The frequency between writes to the command logs
Whether logging is synchronous or asynchronous
The following sections describe these options. A fourth section discusses the impact of storage hardware on the different logging options.
The command log size specifies how much disk space is preallocated for storing the logs on disk. The logs are divided into three "segments" Once a segment is full, it is written to a snapshot (as shown in Figure 14.1, “Command Logging in Action”).
For most workloads, the default log size of one gigabyte is sufficient. However, if your workload writes large volumes of data or uses large strings for queries (so the procedure invocations include large parameter values), the log segments fill up very quickly. When this happens, VoltDB can end up snapshotting continuously, because by the time one snapshot finishes, the next log segment is full.
To avoid this situation, you can increase the total log size, to reduce the frequency of snapshots. You define the
log size in the deployment file using the
logsize attribute of the
<commandlog> tag. Specify the desired log size as an integer number of megabytes. For
<commandlog enabled="true" logsize="3072" />
When increasing the log size, be aware that the larger the log, the longer it may take to recover the database since any transactions in the log since the last snapshot must be replayed before the recovery is complete. So, while reducing the frequency of snapshots, you also may be increasing the time needed to restart.
The minimum log size is three megabytes. Note that the log size specifies the initial size. If the existing segments are filled before a snapshot can truncate the logs, the server will allocate additional segments.
The log frequency specifies how often transactions are written to the command log. In other words, the interval between writes, as shown in Figure 14.1, “Command Logging in Action”. You can specify the frequency in either or both time and number of transactions.
For example, you might specify that the command log is written every 200 milliseconds or every 500 transactions,
whichever comes first. You do this by adding the
<frequency> element as a child
<commandlog> and specifying the individual frequencies as attributes. For
<commandlog enabled="true"> <frequency time="200" transactions="500"/> </commandlog>
Time frequency is specified in milliseconds and transaction frequency is specified as the number of transactions. You can specify either or both types of frequency. If you specify both, whichever limit is reached first initiates a write.
If the command logs are being written asynchronously (which is the default), results are returned to the client applications as soon as the transactions are completed. This allows the transactions to execute uninterrupted.
However, with asynchronous logging there is always the possibility that a catastrophic event (such as a power failure) could cause the cluster to fail. In that case, any transactions completed since the last write and before the failure would be lost. The smaller the frequency, the less data that could be lost. This is how you "dial up" the amount of durability you want using the configuration options for command logging.
In some cases, no loss of data is acceptable. For those situations, it is best to use synchronous logging. When you select synchronous logging, no results are returned to the client applications until those transactions are written to the log. In other words, the results for all of the transactions since the last write are held on the server until the next write occurs.
The advantage of synchronous logging is that no transaction is "complete" and reported back to the calling application until it is guaranteed to be logged — no transactions are lost. The obvious disadvantage of synchronous logging is that the interval between writes (i.e. the frequency) while the results are held, adds to the latency of the transactions. To reduce the penalty of synchronous logging, you need to reduce the frequency.
When using synchronous logging, it is recommended that the frequency be limited to between 1 and 4 milliseconds to avoid adding undue latency to the transaction rate. A frequency of 1 or 2 milliseconds should have little or no measurable affect on overall latency. However, low frequencies can only be achieved effectively when using appropriate hardware (as discussed in the next section, Section 14.3.4, “Hardware Considerations”).
To select synchronous logging, use the
synchronous attribute of the
<commandlog> tag. For example:
<commandlog enabled="true" synchronous="true" > <frequency time="2"/> </commandlog>
Clearly, synchronous logging is preferable since it provides complete durability. However, to avoid negatively impacting database performance you must not only use very low frequencies, but you must have storage hardware that is capable of handling frequent, small writes. Attempting to use aggressively low log frequencies with storage devices that cannot keep up will also hurt transaction throughput and latency.
Standard, uncached storage devices can quickly become overwhelmed with frequent writes. So you should not use low frequencies (and therefore synchronous logging) with slower storage devices. Similarly, if the command logs are competing for the device with other disk I/O, performance will suffer. So do not write the command logs to the same device that is being used for other I/O, such as snapshots or export overflow.
On the other hand, fast, cached devices such as disks with a battery-backed cache, are capable of handling frequent writes. So it is strongly recommended that you use such devices when using synchronous logging.
To specify where the command logs and their associated snapshots are written, you use tags within the
</paths> tag set. For example, the
following example specifies that the logs are written to
/fastdisk/voltdblog and the snapshots are
<paths> <commandlog path="/faskdisk/voltdblog/" /> <commandlogsnapshot path="/opt/voltdb/cmdsnaps/" /> </paths>
Note that the default paths for the command logs and the command log snapshots are both subfolders of the voltdbroot directory. To avoid overloading a single device on production servers, it is recommended that you specify an explicit path for the command logs, at a minimum, and preferably for both logs and snapshots.
To summarize, the rules for balancing command logging with performance and throughput on production databases are:
Use asynchronous logging with slower storage devices.
Write command logs to a dedicated device. Do not write logs and snapshots to the same device.
Use low (1-2 milisecond) frequencies when performing synchronous logging.
Use moderate (100 millisecond or greater) frequencies when performing asynchronous logging.