LoadMonitor.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /**
  3. * An interface for database load monitoring
  4. */
  5. interface LoadMonitor {
  6. /**
  7. * Construct a new LoadMonitor with a given LoadBalancer parent
  8. */
  9. function __construct( $parent );
  10. /**
  11. * Perform pre-connection load ratio adjustment.
  12. * @param array $loads
  13. * @param string $group The selected query group
  14. * @param string $wiki
  15. */
  16. function scaleLoads( &$loads, $group = false, $wiki = false );
  17. /**
  18. * Perform post-connection backoff.
  19. *
  20. * If the connection is in overload, this should return a backoff factor
  21. * which will be used to control polling time. The number of threads
  22. * connected is a good measure.
  23. *
  24. * If there is no overload, zero can be returned.
  25. *
  26. * A threshold thread count is given, the concrete class may compare this
  27. * to the running thread count. The threshold may be false, which indicates
  28. * that the sysadmin has not configured this feature.
  29. *
  30. * @param Database $conn
  31. * @param float $threshold
  32. */
  33. function postConnectionBackoff( $conn, $threshold );
  34. /**
  35. * Return an estimate of replication lag for each server
  36. */
  37. function getLagTimes( $serverIndexes, $wiki );
  38. }
  39. /**
  40. * Basic MySQL load monitor with no external dependencies
  41. * Uses memcached to cache the replication lag for a short time
  42. */
  43. class LoadMonitor_MySQL implements LoadMonitor {
  44. var $parent; // LoadBalancer
  45. function __construct( $parent ) {
  46. $this->parent = $parent;
  47. }
  48. function scaleLoads( &$loads, $group = false, $wiki = false ) {
  49. }
  50. function getLagTimes( $serverIndexes, $wiki ) {
  51. wfProfileIn( __METHOD__ );
  52. $expiry = 5;
  53. $requestRate = 10;
  54. global $wgMemc;
  55. if ( empty( $wgMemc ) )
  56. $wgMemc = wfGetMainCache();
  57. $masterName = $this->parent->getServerName( 0 );
  58. $memcKey = wfMemcKey( 'lag_times', $masterName );
  59. $times = $wgMemc->get( $memcKey );
  60. if ( $times ) {
  61. # Randomly recache with probability rising over $expiry
  62. $elapsed = time() - $times['timestamp'];
  63. $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
  64. if ( mt_rand( 0, $chance ) != 0 ) {
  65. unset( $times['timestamp'] );
  66. wfProfileOut( __METHOD__ );
  67. return $times;
  68. }
  69. wfIncrStats( 'lag_cache_miss_expired' );
  70. } else {
  71. wfIncrStats( 'lag_cache_miss_absent' );
  72. }
  73. # Cache key missing or expired
  74. $times = array();
  75. foreach ( $serverIndexes as $i ) {
  76. if ($i == 0) { # Master
  77. $times[$i] = 0;
  78. } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
  79. $times[$i] = $conn->getLag();
  80. } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
  81. $times[$i] = $conn->getLag();
  82. }
  83. }
  84. # Add a timestamp key so we know when it was cached
  85. $times['timestamp'] = time();
  86. $wgMemc->set( $memcKey, $times, $expiry );
  87. # But don't give the timestamp to the caller
  88. unset($times['timestamp']);
  89. $lagTimes = $times;
  90. wfProfileOut( __METHOD__ );
  91. return $lagTimes;
  92. }
  93. function postConnectionBackoff( $conn, $threshold ) {
  94. if ( !$threshold ) {
  95. return 0;
  96. }
  97. $status = $conn->getStatus("Thread%");
  98. if ( $status['Threads_running'] > $threshold ) {
  99. return $status['Threads_connected'];
  100. } else {
  101. return 0;
  102. }
  103. }
  104. }