3 * Database load monitoring
10 * An interface for database load monitoring
14 interface LoadMonitor
{
16 * Construct a new LoadMonitor with a given LoadBalancer parent
18 * @param LoadBalancer $parent
20 function __construct( $parent );
23 * Perform pre-connection load ratio adjustment.
25 * @param $group String: the selected query group
28 function scaleLoads( &$loads, $group = false, $wiki = false );
31 * Perform post-connection backoff.
33 * If the connection is in overload, this should return a backoff factor
34 * which will be used to control polling time. The number of threads
35 * connected is a good measure.
37 * If there is no overload, zero can be returned.
39 * A threshold thread count is given, the concrete class may compare this
40 * to the running thread count. The threshold may be false, which indicates
41 * that the sysadmin has not configured this feature.
43 * @param $conn DatabaseBase
44 * @param $threshold Float
46 function postConnectionBackoff( $conn, $threshold );
49 * Return an estimate of replication lag for each server
51 * @param $serverIndexes
56 function getLagTimes( $serverIndexes, $wiki );
59 class LoadMonitor_Null
implements LoadMonitor
{
60 function __construct( $parent ) {
63 function scaleLoads( &$loads, $group = false, $wiki = false ) {
66 function postConnectionBackoff( $conn, $threshold ) {
69 function getLagTimes( $serverIndexes, $wiki ) {
70 return array_fill_keys( $serverIndexes, 0 );
76 * Basic MySQL load monitor with no external dependencies
77 * Uses memcached to cache the replication lag for a short time
81 class LoadMonitor_MySQL
implements LoadMonitor
{
89 * @param LoadBalancer $parent
91 function __construct( $parent ) {
92 $this->parent
= $parent;
100 function scaleLoads( &$loads, $group = false, $wiki = false ) {
104 * @param $serverIndexes
108 function getLagTimes( $serverIndexes, $wiki ) {
109 wfProfileIn( __METHOD__
);
114 if ( empty( $wgMemc ) )
115 $wgMemc = wfGetMainCache();
117 $masterName = $this->parent
->getServerName( 0 );
118 $memcKey = wfMemcKey( 'lag_times', $masterName );
119 $times = $wgMemc->get( $memcKey );
121 # Randomly recache with probability rising over $expiry
122 $elapsed = time() - $times['timestamp'];
123 $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
124 if ( mt_rand( 0, $chance ) != 0 ) {
125 unset( $times['timestamp'] );
126 wfProfileOut( __METHOD__
);
129 wfIncrStats( 'lag_cache_miss_expired' );
131 wfIncrStats( 'lag_cache_miss_absent' );
134 # Cache key missing or expired
137 foreach ( $serverIndexes as $i ) {
138 if ($i == 0) { # Master
140 } elseif ( false !== ( $conn = $this->parent
->getAnyOpenConnection( $i ) ) ) {
141 $times[$i] = $conn->getLag();
142 } elseif ( false !== ( $conn = $this->parent
->openConnection( $i, $wiki ) ) ) {
143 $times[$i] = $conn->getLag();
147 # Add a timestamp key so we know when it was cached
148 $times['timestamp'] = time();
149 $wgMemc->set( $memcKey, $times, $expiry );
151 # But don't give the timestamp to the caller
152 unset($times['timestamp']);
155 wfProfileOut( __METHOD__
);
160 * @param $conn DatabaseBase
164 function postConnectionBackoff( $conn, $threshold ) {
168 $status = $conn->getMysqlStatus("Thread%");
169 if ( $status['Threads_running'] > $threshold ) {
170 return $status['Threads_connected'];