X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FLoadBalancer.php;h=4ebe26c708a3e76ab3163f85ba2774b03ce380d6;hb=fa5dec53ce155e2b1b7eb3f816e7e395703467c3;hp=d77cf3f66a797d1a1cea9c107858b2d15d0f7b4d;hpb=c6f0a73ae04aecd3bb22d12ad34e55ca93f01745;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/LoadBalancer.php b/includes/LoadBalancer.php index d77cf3f66a..4ebe26c708 100644 --- a/includes/LoadBalancer.php +++ b/includes/LoadBalancer.php @@ -1,35 +1,13 @@ mServers = array(); - $this->mConnections = array(); - $this->mFailFunction = false; - $this->mReadIndex = -1; - $this->mForce = -1; - $this->mLastIndex = -1; - $this->mErrorConnection = false; - $this->mAllowLag = false; - } - - function newFromParams( $servers, $failFunction = false, $waitTimeout = 10 ) - { - $lb = new LoadBalancer; - $lb->initialise( $servers, $failFunction, $waitTimeout ); - return $lb; - } + /** + * Scale polling time so that under overload conditions, the database server + * receives a SHOW STATUS query at an average interval of this many microseconds + */ + const AVG_STATUS_POLL = 2000; - function initialise( $servers, $failFunction = false, $waitTimeout = 10 ) + function __construct( $servers, $failFunction = false, $waitTimeout = 10, $waitForMasterNow = false ) { $this->mServers = $servers; $this->mFailFunction = $failFunction; @@ -65,12 +30,14 @@ class LoadBalancer { $this->mWriteIndex = -1; $this->mForce = -1; $this->mConnections = array(); - $this->mLastIndex = 1; + $this->mLastIndex = -1; $this->mLoads = array(); $this->mWaitForFile = false; $this->mWaitForPos = false; $this->mWaitTimeout = $waitTimeout; $this->mLaggedSlaveMode = false; + $this->mErrorConnection = false; + $this->mAllowLag = false; foreach( $servers as $i => $server ) { $this->mLoads[$i] = $server['load']; @@ -83,6 +50,14 @@ class LoadBalancer { } } } + if ( $waitForMasterNow ) { + $this->loadMasterPos(); + } + } + + static function newFromParams( $servers, $failFunction = false, $waitTimeout = 10 ) + { + return new LoadBalancer( $servers, $failFunction, $waitTimeout ); } /** @@ -120,7 +95,9 @@ class LoadBalancer { # Unset excessively lagged servers $lags = $this->getLagTimes(); foreach ( $lags as $i => $lag ) { - if ( isset( $this->mServers[$i]['max lag'] ) && $lag > $this->mServers[$i]['max lag'] ) { + if ( $i != 0 && isset( $this->mServers[$i]['max lag'] ) && + ( $lag === false || $lag > $this->mServers[$i]['max lag'] ) ) + { unset( $loads[$i] ); } } @@ -164,6 +141,9 @@ class LoadBalancer { $i = false; if ( $this->mForce >= 0 ) { $i = $this->mForce; + } elseif ( count( $this->mServers ) == 1 ) { + # Skip the load balancing if there's only one server + $i = 0; } else { if ( $this->mReadIndex >= 0 ) { $i = $this->mReadIndex; @@ -180,7 +160,7 @@ class LoadBalancer { $i = $this->getRandomNonLagged( $loads ); if ( $i === false && count( $loads ) != 0 ) { # All slaves lagged. Switch to read-only mode - $wgReadOnly = wfMsgNoDB( 'readonly_lag' ); + $wgReadOnly = wfMsgNoDBForContent( 'readonly_lag' ); $i = $this->pickRandom( $loads ); } } @@ -194,20 +174,23 @@ class LoadBalancer { unset( $loads[$i] ); $sleepTime = 0; } else { - $status = $this->mConnections[$i]->getStatus("Thread%"); - if ( isset( $this->mServers[$i]['max threads'] ) && - $status['Threads_running'] > $this->mServers[$i]['max threads'] ) - { + if ( isset( $this->mServers[$i]['max threads'] ) ) { + $status = $this->mConnections[$i]->getStatus("Thread%"); + if ( $status['Threads_running'] > $this->mServers[$i]['max threads'] ) { # Too much load, back off and wait for a while. # The sleep time is scaled by the number of threads connected, # to produce a roughly constant global poll rate. - $sleepTime = AVG_STATUS_POLL * $status['Threads_connected']; + $sleepTime = self::AVG_STATUS_POLL * $status['Threads_connected']; # If we reach the timeout and exit the loop, don't use it $i = false; - } else { + } else { $done = true; $sleepTime = 0; + } + } else { + $done = true; + $sleepTime = 0; } } } else { @@ -436,15 +419,12 @@ class LoadBalancer { */ function reallyOpenConnection( &$server ) { if( !is_array( $server ) ) { - wfDebugDieBacktrace( 'You must update your load-balancing configuration. See DefaultSettings.php entry for $wgDBservers.' ); + throw new MWException( 'You must update your load-balancing configuration. See DefaultSettings.php entry for $wgDBservers.' ); } extract( $server ); # Get class for this database type $class = 'Database' . ucfirst( $type ); - if ( !class_exists( $class ) ) { - require_once( "$class.php" ); - } # Create object $db = new $class( $host, $user, $password, $dbname, 1, $flags ); @@ -469,7 +449,7 @@ class LoadBalancer { $conn->reportConnectionError( $this->mLastError ); } else { // If all servers were busy, mLastError will contain something sensible - wfEmergencyAbort( $conn, $this->mLastError ); + throw new DBConnectionError( $conn, $this->mLastError ); } } else { if ( $this->mFailFunction ) { @@ -477,7 +457,8 @@ class LoadBalancer { } else { $conn->failFunction( false ); } - $conn->reportConnectionError( "{$this->mLastError} ({$conn->mServer})" ); + $server = $conn->getProperty( 'mServer' ); + $conn->reportConnectionError( "{$this->mLastError} ({$server})" ); } $reporting = false; } @@ -523,8 +504,7 @@ class LoadBalancer { * Save master pos to the session and to memcached, if the session exists */ function saveMasterPos() { - global $wgSessionStarted; - if ( $wgSessionStarted && count( $this->mServers ) > 1 ) { + if ( session_id() != '' && count( $this->mServers ) > 1 ) { # If this entire request was served from a slave without opening a connection to the # master (however unlikely that may be), then we can fetch the position from the slave. if ( empty( $this->mConnections[0] ) ) { @@ -624,21 +604,24 @@ class LoadBalancer { * Results are cached for a short time in memcached */ function getLagTimes() { - global $wgDBname; - + wfProfileIn( __METHOD__ ); $expiry = 5; $requestRate = 10; global $wgMemc; - $times = $wgMemc->get( "$wgDBname:lag_times" ); + $times = $wgMemc->get( wfMemcKey( 'lag_times' ) ); if ( $times ) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max( 0, ( $expiry - $elapsed ) * $requestRate ); if ( mt_rand( 0, $chance ) != 0 ) { unset( $times['timestamp'] ); + wfProfileOut( __METHOD__ ); return $times; } + wfIncrStats( 'lag_cache_miss_expired' ); + } else { + wfIncrStats( 'lag_cache_miss_absent' ); } # Cache key missing or expired @@ -654,10 +637,11 @@ class LoadBalancer { # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); - $wgMemc->set( "$wgDBname:lag_times", $times, $expiry ); + $wgMemc->set( wfMemcKey( 'lag_times' ), $times, $expiry ); # But don't give the timestamp to the caller unset($times['timestamp']); + wfProfileOut( __METHOD__ ); return $times; } }