aboutsummaryrefslogtreecommitdiffstats
path: root/includes/libs/objectcache
diff options
context:
space:
mode:
authorTimo Tijhof <krinkle@fastmail.com>2023-03-23 12:52:09 -0700
committerTimo Tijhof <krinkle@fastmail.com>2023-04-29 01:23:56 +0100
commitf83f75d3e64e9352c36d10b6280ca0d0b52b38d2 (patch)
tree7d92d18b982d83abde0850c98a8cc5704b7ec1d4 /includes/libs/objectcache
parent39fb10aa719f0614713fc5495e95f7151478586b (diff)
downloadmediawikicore-f83f75d3e64e9352c36d10b6280ca0d0b52b38d2.tar.gz
mediawikicore-f83f75d3e64e9352c36d10b6280ca0d0b52b38d2.zip
objectcache: Remove WANObjectCache's internal cool-off bounce feature
Bug: T203786 Bug: T302623 Bug: T321634 Change-Id: Ie3a2215d3325fe7290658e1013adaac4f4565884
Diffstat (limited to 'includes/libs/objectcache')
-rw-r--r--includes/libs/objectcache/wancache/WANObjectCache.php83
1 files changed, 2 insertions, 81 deletions
diff --git a/includes/libs/objectcache/wancache/WANObjectCache.php b/includes/libs/objectcache/wancache/WANObjectCache.php
index f0d77019f6d6..876d6a9ee46e 100644
--- a/includes/libs/objectcache/wancache/WANObjectCache.php
+++ b/includes/libs/objectcache/wancache/WANObjectCache.php
@@ -224,8 +224,6 @@ class WANObjectCache implements
/** Seconds to keep lock keys around */
private const LOCK_TTL = 10;
- /** Seconds to no-op key set() calls to avoid large blob I/O stampedes */
- private const COOLOFF_TTL = 2;
/** Seconds to ramp up the chance of regeneration due to expected time-till-refresh */
private const RAMPUP_TTL = 30;
@@ -302,8 +300,6 @@ class WANObjectCache implements
private const TYPE_MUTEX = 'm';
/** Single character component for interium value keys */
private const TYPE_INTERIM = 'i';
- /** Single character component for cool-off bounce keys */
- private const TYPE_COOLOFF = 'c';
/** Value prefix of purge values */
private const PURGE_VAL_PREFIX = 'PURGED';
@@ -1776,10 +1772,9 @@ class WANObjectCache implements
// Callback yielded a cacheable value
( $value !== false && $ttl >= 0 ) &&
// Current thread was not raced out of a regeneration lock or key is tombstoned
- ( !$useRegenerationLock || $hasLock || $isKeyTombstoned ) &&
- // Key does not appear to be undergoing a set() stampede
- $this->checkAndSetCooloff( $key, $kClass, $value, $elapsed, $hasLock )
+ ( !$useRegenerationLock || $hasLock || $isKeyTombstoned )
) {
+ $this->stats->timing( "wanobjectcache.$kClass.regen_set_delay", 1e3 * $elapsed );
// If the key is write-holed then use the (volatile) interim key as an alternative
if ( $isKeyTombstoned ) {
$this->setInterimValue(
@@ -1932,80 +1927,6 @@ class WANObjectCache implements
}
/**
- * Check whether to skip set() on account of concurrent I/O spike rate-limiting
- *
- * This mitigates problems caused by popular keys suddenly becoming unavailable due to
- * unexpected evictions or cache server outages. These cases are not handled by the usual
- * preemptive refresh logic.
- *
- * With a typical scale-out infrastructure, CPU and query load from getWithSetCallback()
- * invocations is distributed among appservers and replica DBs, but cache operations for
- * a given key route to a single cache server (e.g. striped consistent hashing). A set()
- * stampede to a key can saturate the network link to its cache server. The intensity of
- * the problem is proportionate to the value size and access rate. The duration of the
- * problem is proportionate to value regeneration time.
- *
- * @param string $key Cache key made with makeKey()/makeGlobalKey()
- * @param string $kClass Key collection name
- * @param mixed $value The regenerated value
- * @param float|null $elapsed Seconds spent fetching, validating, and regenerating the value
- * @param bool $hasLock Whether this thread has an exclusive regeneration lock
- * @return bool Whether it is OK to proceed with a key set operation
- */
- private function checkAndSetCooloff( $key, $kClass, $value, $elapsed, $hasLock ) {
- if ( is_scalar( $value ) ) {
- // Roughly estimate the size of the value once serialized
- $hypotheticalSize = strlen( (string)$value );
- } else {
- // Treat the value is a generic sizable object
- $hypotheticalSize = $this->keyHighByteSize;
- }
-
- if ( !$hasLock ) {
- // Suppose that this cache key is very popular (KEY_HIGH_QPS reads/second).
- // After eviction, there will be cache misses until it gets regenerated and saved.
- // If the time window when the key is missing lasts less than one second, then the
- // number of misses will not reach KEY_HIGH_QPS. This window largely corresponds to
- // the key regeneration time. Estimate the count/rate of cache misses, e.g.:
- // - 100 QPS, 20ms regeneration => ~2 misses (< 1s)
- // - 100 QPS, 100ms regeneration => ~10 misses (< 1s)
- // - 100 QPS, 3000ms regeneration => ~300 misses (100/s for 3s)
- $missesPerSecForHighQPS = ( min( $elapsed, 1 ) * $this->keyHighQps );
-
- // Determine whether there is enough I/O stampede risk to justify throttling set().
- // Estimate unthrottled set() overhead, as bps, from miss count/rate and value size,
- // comparing it to the per-key uplink bps limit (KEY_HIGH_UPLINK_BPS), e.g.:
- // - 2 misses (< 1s), 10KB value, 1250000 bps limit => 160000 bits (low risk)
- // - 2 misses (< 1s), 100KB value, 1250000 bps limit => 1600000 bits (high risk)
- // - 10 misses (< 1s), 10KB value, 1250000 bps limit => 800000 bits (low risk)
- // - 10 misses (< 1s), 100KB value, 1250000 bps limit => 8000000 bits (high risk)
- // - 300 misses (100/s), 1KB value, 1250000 bps limit => 800000 bps (low risk)
- // - 300 misses (100/s), 10KB value, 1250000 bps limit => 8000000 bps (high risk)
- // - 300 misses (100/s), 100KB value, 1250000 bps limit => 80000000 bps (high risk)
- if ( ( $missesPerSecForHighQPS * $hypotheticalSize ) >= $this->keyHighUplinkBps ) {
- $cooloffSisterKey = $this->makeSisterKey( $key, self::TYPE_COOLOFF );
- $watchPoint = $this->cache->watchErrors();
- if (
- !$this->cache->add( $cooloffSisterKey, 1, self::COOLOFF_TTL ) &&
- // Don't treat failures due to I/O errors as the key being in cool-off
- $this->cache->getLastError( $watchPoint ) === self::ERR_NONE
- ) {
- $this->logger->debug( "checkAndSetCooloff($key): bounced; {$elapsed}s" );
- $this->stats->increment( "wanobjectcache.$kClass.cooloff_bounce" );
-
- return false;
- }
- }
- }
-
- // Corresponding metrics for cache writes that actually get sent over the write
- $this->stats->timing( "wanobjectcache.$kClass.regen_set_delay", 1e3 * $elapsed );
- $this->stats->updateCount( "wanobjectcache.$kClass.regen_set_bytes", $hypotheticalSize );
-
- return true;
- }
-
- /**
* @param string $key Cache key made with makeKey()/makeGlobalKey()
* @param float $minAsOf Minimum acceptable value "as of" UNIX timestamp
* @param float $now Fetch time to determine "age" metadata