Aaron Schulz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/310757

Change subject: [WIP] Implement scaleLoads() in LoadMonitorMySQL
......................................................................

[WIP] Implement scaleLoads() in LoadMonitorMySQL

Also let LoadMonitor support options for flexibility

Change-Id: I53b89b0c25bdcc30deec3f8b502fb14479c53ae8
---
M includes/libs/rdbms/loadmonitor/ILoadMonitor.php
M includes/libs/rdbms/loadmonitor/LoadMonitor.php
M includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
M includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
4 files changed, 94 insertions(+), 26 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/57/310757/1

diff --git a/includes/libs/rdbms/loadmonitor/ILoadMonitor.php 
b/includes/libs/rdbms/loadmonitor/ILoadMonitor.php
index e355c03..72a8785 100644
--- a/includes/libs/rdbms/loadmonitor/ILoadMonitor.php
+++ b/includes/libs/rdbms/loadmonitor/ILoadMonitor.php
@@ -34,16 +34,19 @@
         * @param ILoadBalancer $lb LoadBalancer this instance serves
         * @param BagOStuff $sCache Local server memory cache
         * @param BagOStuff $cCache Local cluster memory cache
+        * @param array $options Options map
         */
-       public function __construct( ILoadBalancer $lb, BagOStuff $sCache, 
BagOStuff $cCache );
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache, array 
$options = []
+       );
 
        /**
         * Perform pre-connection load ratio adjustment.
-        * @param int[] &$loads
+        * @param int[] &$weightByServer Map of (server index => integer weight)
         * @param string|bool $group The selected query group. Default: false
         * @param string|bool $domain Default: false
         */
-       public function scaleLoads( &$loads, $group = false, $domain = false );
+       public function scaleLoads( array &$weightByServer, $group = false, 
$domain = false );
 
        /**
         * Get an estimate of replication lag (in seconds) for each server
@@ -55,7 +58,7 @@
         *
         * @return array Map of (server index => float|int|bool)
         */
-       public function getLagTimes( $serverIndexes, $domain );
+       public function getLagTimes( array $serverIndexes, $domain );
 
        /**
         * Clear any process and persistent cache of lag times
diff --git a/includes/libs/rdbms/loadmonitor/LoadMonitor.php 
b/includes/libs/rdbms/loadmonitor/LoadMonitor.php
index 1da8f4e..9ec5665 100644
--- a/includes/libs/rdbms/loadmonitor/LoadMonitor.php
+++ b/includes/libs/rdbms/loadmonitor/LoadMonitor.php
@@ -37,7 +37,9 @@
        /** @var LoggerInterface */
        protected $replLogger;
 
-       public function __construct( ILoadBalancer $lb, BagOStuff $srvCache, 
BagOStuff $cache ) {
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $srvCache, BagOStuff $cache, array 
$options = []
+       ) {
                $this->parent = $lb;
                $this->srvCache = $srvCache;
                $this->mainCache = $cache;
@@ -48,16 +50,35 @@
                $this->replLogger = $logger;
        }
 
-       public function scaleLoads( &$loads, $group = false, $domain = false ) {
+       public function scaleLoads( array &$weightByServer, $group = false, 
$domain = false ) {
+               $states = $this->getServerStates( $weightByServer, $domain );
+               $factorsByServer = $states['weightScales'];
+               foreach ( $weightByServer as $i => $weight ) {
+                       if ( $weight >= 1 ) { // sanity
+                               // Scale from 10% to 100% of nominal weight
+                               $coefficient = max( $factorsByServer[$i], .10 );
+
+                               $weightByServer[$i] = (int)max( $weight * 
$coefficient, 1 );
+                       }
+               }
        }
 
-       public function getLagTimes( $serverIndexes, $domain ) {
+       public function getLagTimes( array $serverIndexes, $domain ) {
+               $states = $this->getServerStates( $serverIndexes, $domain );
+
+               return $states['lagTimes'];
+       }
+
+       protected function getServerStates( array $serverIndexes, $domain ) {
                if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 
0 ) {
                        # Single server only, just return zero without caching
-                       return [ 0 => 0 ];
+                       return [
+                               'lagTimes' => [ $this->parent->getWriterIndex() 
=> 0 ],
+                               'weightScales' => [ 
$this->parent->getWriterIndex() => 1 ]
+                       ];
                }
 
-               $key = $this->getLagTimeCacheKey();
+               $key = $this->getCacheKey();
                # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
                $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
                # Keep keys around longer as fallbacks
@@ -67,7 +88,7 @@
                $value = $this->srvCache->get( $key );
                if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl 
) ) {
                        $this->replLogger->debug( __METHOD__ . ": got lag times 
($key) from local cache" );
-                       return $value['lagTimes']; // cache hit
+                       return $value; // cache hit
                }
                $staleValue = $value ?: false;
 
@@ -77,7 +98,7 @@
                        $this->srvCache->set( $key, $value, $staleTTL );
                        $this->replLogger->debug( __METHOD__ . ": got lag times 
($key) from main cache" );
 
-                       return $value['lagTimes']; // cache hit
+                       return $value; // cache hit
                }
                $staleValue = $value ?: $staleValue;
 
@@ -91,13 +112,15 @@
                        } );
                } elseif ( $staleValue ) {
                        # Could not acquire lock but an old cache exists, so 
use it
-                       return $staleValue['lagTimes'];
+                       return $staleValue;
                }
 
                $lagTimes = [];
+               $weightScales = [];
                foreach ( $serverIndexes as $i ) {
                        if ( $i == $this->parent->getWriterIndex() ) {
                                $lagTimes[$i] = 0; // master always has no lag
+                               $weightScales[$i] = 1.0; // nominal weight
                                continue;
                        }
 
@@ -109,17 +132,22 @@
                                $close = true; // new connection
                        }
 
+                       $lastWeight = isset( $staleValue['weightScales'][$i] )
+                               ? $staleValue['weightScales'][$i]
+                               : 1.0;
+                       $weightScales[$i] = $this->getWeightScale( $i, $conn ?: 
null, $lastWeight );
+
                        if ( !$conn ) {
                                $lagTimes[$i] = false;
                                $host = $this->parent->getServerName( $i );
-                               $this->replLogger->error( __METHOD__ . ": host 
$host (#$i) is unreachable" );
+                               $this->replLogger->error( __METHOD__ . ": host 
$host is unreachable" );
                                continue;
                        }
 
                        $lagTimes[$i] = $conn->getLag();
                        if ( $lagTimes[$i] === false ) {
                                $host = $this->parent->getServerName( $i );
-                               $this->replLogger->error( __METHOD__ . ": host 
$host (#$i) is not replicating?" );
+                               $this->replLogger->error( __METHOD__ . ": host 
$host is not replicating?" );
                        }
 
                        if ( $close ) {
@@ -132,26 +160,39 @@
                }
 
                # Add a timestamp key so we know when it was cached
-               $value = [ 'lagTimes' => $lagTimes, 'timestamp' => microtime( 
true ) ];
+               $value = [
+                       'lagTimes' => $lagTimes,
+                       'weightScales' => $weightScales,
+                       'timestamp' => microtime( true )
+               ];
                $this->mainCache->set( $key, $value, $staleTTL );
                $this->srvCache->set( $key, $value, $staleTTL );
                $this->replLogger->info( __METHOD__ . ": re-calculated lag 
times ($key)" );
 
-               return $value['lagTimes'];
+               return $value;
+       }
+
+       /**
+        * @param integer $index Server index
+        * @param IDatabase|null $conn Connection handle or null on connection 
failure
+        * @param float $lastWeight
+        * @return float
+        */
+       protected function getWeightScale( $index, IDatabase $conn = null, 
$lastWeight ) {
+               return $conn ? ( .1 + .9 * $lastWeight ) : .9 * $lastWeight;
        }
 
        public function clearCaches() {
-               $key = $this->getLagTimeCacheKey();
+               $key = $this->getCacheKey();
                $this->srvCache->delete( $key );
                $this->mainCache->delete( $key );
        }
 
-       private function getLagTimeCacheKey() {
-               $writerIndex = $this->parent->getWriterIndex();
+       private function getCacheKey() {
                // Lag is per-server, not per-DB, so key on the master DB name
                return $this->srvCache->makeGlobalKey(
                        'lag-times',
-                       $this->parent->getServerName( $writerIndex )
+                       $this->parent->getServerName( 
$this->parent->getWriterIndex() )
                );
        }
 }
diff --git a/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php 
b/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
index 7286417..0b06162 100644
--- a/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
+++ b/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
@@ -26,8 +26,30 @@
  * @ingroup Database
  */
 class LoadMonitorMySQL extends LoadMonitor {
-       public function scaleLoads( &$loads, $group = false, $domain = false ) {
-               // @TODO: maybe use Threads_running/Threads_created ratio to 
guess load
-               // and Queries/Uptime to guess if a server is warming up the 
buffer pool
+       protected function getWeightScale( $index, IDatabase $conn = null, 
$lastWeight ) {
+               if ( !$conn ) {
+                       return .9 * $lastWeight;
+               }
+
+               $weight = 1.0;
+               $res = $conn->query( 'SHOW STATUS', false );
+               $s = $res ? $conn->fetchObject( $res ) : false;
+               if ( $s === false ) {
+                       $host = $this->parent->getServerName( $index );
+                       $this->replLogger->error( __METHOD__ . ": host $host is 
not queryable" );
+               } else {
+                       // 
http://dev.mysql.com/doc/refman/5.7/en/server-status-variables.html
+                       if ( $s->Innodb_buffer_pool_pages_total > 0 ) {
+                               $weight *= $s->Innodb_buffer_pool_pages_data / 
$s->Innodb_buffer_pool_pages_total;
+                       } elseif ( $s->Qcache_free_blocks > 0 ) {
+                               $weight *= 1 - $s->Qcache_free_blocks / 
$s->Qcache_total_blocks;
+                       }
+
+                       if ( $s->Threads_created > 0 ) {
+                               $weight *= min( 1, $s->Threads_created / 
$s->Threads_running );
+                       }
+               }
+
+               return $weight;
        }
 }
diff --git a/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php 
b/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
index 07b59b1..bbc83a0 100644
--- a/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
+++ b/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
@@ -21,18 +21,20 @@
 use Psr\Log\LoggerInterface;
 
 class LoadMonitorNull implements ILoadMonitor {
-       public function __construct( ILoadBalancer $lb, BagOStuff $sCache, 
BagOStuff $cCache ) {
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache, array 
$options = []
+       ) {
 
        }
 
        public function setLogger( LoggerInterface $logger ) {
        }
 
-       public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+       public function scaleLoads( array &$weightByServer, $group = false, 
$wiki = false ) {
 
        }
 
-       public function getLagTimes( $serverIndexes, $wiki ) {
+       public function getLagTimes( array $serverIndexes, $wiki ) {
                return array_fill_keys( $serverIndexes, 0 );
        }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/310757
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I53b89b0c25bdcc30deec3f8b502fb14479c53ae8
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <asch...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to