首页
4K壁纸
直播
统计分析
友情链接
搜索
1
#1031 – TABLE STORAGE ENGINE FOR ” DOESN’T HAVE THIS OPTION解决方法
1,224 阅读
2
让浏览器不显示 https 页面中 http 请求警报 http-equiv=”Content-Security-Policy” content=”upgrade-insecure-requests”
941 阅读
3
报错代码:ERROR 1227 (42000)-解决办法
730 阅读
4
微信个人商户号养号建议
580 阅读
5
解决移动端position:fixed随软键盘移动的问题
550 阅读
Php
Mysql
Linux
Reids
Java
Python
常用笔记
学习
乱七八糟
Search
标签搜索
php
千卡云支付
Mysql
Linux
redis
千卡云
千卡易支付
function
Nginx
shell
JS
JSON
跨域
支付宝
CentOS
Apache
支付
composer
Array
database
蓝科迪梦
累计撰写
98
篇文章
累计收到
0
条评论
首页
栏目
Php
Mysql
Linux
Reids
Java
Python
常用笔记
学习
乱七八糟
页面
4K壁纸
直播
统计分析
友情链接
搜索到
1
篇与
的结果
2025-10-15
PHP开发中的缓存穿透、击穿与雪崩防护解决方案
PHP开发中的复杂问题及解决方案:缓存穿透、击穿与雪崩防护在高并发的PHP应用中,缓存系统的三个经典问题——缓存穿透、缓存击穿和缓存雪崩——是影响系统稳定性的关键因素。这些问题可能导致数据库压力骤增,甚至系统崩溃。三大缓存问题解析1. 缓存穿透查询不存在的数据,请求直接打到数据库,缓存形同虚设。2. 缓存击穿热点数据过期瞬间,大量请求同时查询数据库。3. 缓存雪崩大量缓存同时过期,数据库面临瞬时高压。解决方案方案一:布隆过滤器防止缓存穿透<?php /** * 布隆过滤器实现 */ class BloomFilter { private array $bitArray; private int $size; private array $hashFunctions; public function __construct(int $size = 1000000) { $this->size = $size; $this->bitArray = array_fill(0, $size, 0); $this->hashFunctions = [ [$this, 'hash1'], [$this, 'hash2'], [$this, 'hash3'] ]; } /** * 添加元素到布隆过滤器 */ public function add(string $item): void { foreach ($this->hashFunctions as $hashFunc) { $index = $hashFunc($item) % $this->size; $this->bitArray[$index] = 1; } } /** * 检查元素是否存在 */ public function mightContain(string $item): bool { foreach ($this->hashFunctions as $hashFunc) { $index = $hashFunc($item) % $this->size; if ($this->bitArray[$index] === 0) { return false; } } return true; } private function hash1(string $item): int { return crc32($item); } private function hash2(string $item): int { return abs(crc32(strrev($item))); } private function hash3(string $item): int { return abs(crc32($item . strrev($item))); } } /** * 防止缓存穿透的服务层 */ class CachePenetrationProtection { private \Redis $redis; private BloomFilter $bloomFilter; public function __construct(\Redis $redis) { $this->redis = $redis; $this->bloomFilter = new BloomFilter(); $this->initializeBloomFilter(); } /** * 初始化布隆过滤器(从持久化存储加载) */ private function initializeBloomFilter(): void { $existingKeys = $this->redis->smembers('valid_keys'); foreach ($existingKeys as $key) { $this->bloomFilter->add($key); } } /** * 安全获取数据 */ public function getDataSafely(string $key) { // 布隆过滤器快速检查 if (!$this->bloomFilter->mightContain($key)) { // 肯定不存在,直接返回空值并缓存 $this->cacheEmptyResult($key); return null; } // 缓存中查找 $cachedData = $this->redis->get($key); if ($cachedData !== false) { return $cachedData === 'NULL_VALUE' ? null : json_decode($cachedData, true); } // 数据库查询 $data = $this->queryFromDatabase($key); if ($data === null) { // 确认不存在的数据,缓存空值并添加到布隆过滤器 $this->cacheEmptyResult($key); } else { // 存在的数据,正常缓存 $this->redis->setex($key, 3600, json_encode($data)); $this->bloomFilter->add($key); $this->redis->sadd('valid_keys', $key); } return $data; } private function cacheEmptyResult(string $key): void { $this->redis->setex($key, 300, 'NULL_VALUE'); // 空值缓存时间较短 } private function queryFromDatabase(string $key) { // 实际的数据库查询逻辑 return null; } }方案二:互斥锁防止缓存击穿<?php /** * 缓存击穿防护机制 */ class CacheBreakdownProtection { private \Redis $redis; public function __construct(\Redis $redis) { $this->redis = $redis; } /** * 获取热点数据(防击穿版本) */ public function getHotData(string $key, callable $databaseQuery, int $expireTime = 3600) { // 尝试从缓存获取 $cachedData = $this->redis->get($key); if ($cachedData !== false) { return $cachedData === 'NULL_VALUE' ? null : json_decode($cachedData, true); } // 缓存未命中,尝试获取分布式锁 $lockKey = "lock:{$key}"; $lockValue = uniqid(php_uname('n'), true); // 获取锁(使用Lua脚本保证原子性) $acquired = $this->acquireLock($lockKey, $lockValue, 10); if ($acquired) { try { // 再次检查缓存(双重检查) $cachedData = $this->redis->get($key); if ($cachedData !== false) { return $cachedData === 'NULL_VALUE' ? null : json_decode($cachedData, true); } // 查询数据库 $data = $databaseQuery(); // 缓存结果 if ($data === null) { $this->redis->setex($key, 300, 'NULL_VALUE'); } else { $this->redis->setex($key, $expireTime, json_encode($data)); } return $data; } finally { // 释放锁 $this->releaseLock($lockKey, $lockValue); } } else { // 未获得锁,短暂等待后重试 usleep(50000); // 等待50毫秒 return $this->getHotData($key, $databaseQuery, $expireTime); } } /** * 获取分布式锁 */ private function acquireLock(string $key, string $value, int $expire): bool { $script = ' return redis.call("SET", KEYS[1], ARGV[1], "NX", "EX", ARGV[2]) '; return $this->redis->eval($script, [$key, $value, $expire], 1) === "OK"; } /** * 释放分布式锁 */ private function releaseLock(string $key, string $value): bool { $script = ' if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end '; return $this->redis->eval($script, [$key, $value], 1) > 0; } }方案三:多级缓存与过期时间随机化<?php /** * 多级缓存管理器 */ class MultiLevelCacheManager { private \Redis $redis; private array $localCache; private int $localCacheSize; public function __construct(\Redis $redis, int $localCacheSize = 1000) { $this->redis = $redis; $this->localCache = []; $this->localCacheSize = $localCacheSize; } /** * 获取数据(多级缓存) */ public function getData(string $key, callable $databaseQuery, int $baseExpire = 3600) { // 一级缓存(本地缓存) if (isset($this->localCache[$key])) { $cacheEntry = $this->localCache[$key]; if (time() < $cacheEntry['expire']) { return $cacheEntry['data']; } else { unset($this->localCache[$key]); } } // 二级缓存(Redis) $cachedData = $this->redis->get($key); if ($cachedData !== false) { $data = $cachedData === 'NULL_VALUE' ? null : json_decode($cachedData, true); // 回填到本地缓存 $this->setLocalCache($key, $data, 300); // 本地缓存5分钟 return $data; } // 缓存未命中,查询数据库 $data = $databaseQuery(); // 缓存数据(使用随机过期时间防止雪崩) $this->cacheData($key, $data, $baseExpire); return $data; } /** * 缓存数据(防雪崩) */ private function cacheData(string $key, $data, int $baseExpire): void { // 添加随机过期时间(±10%波动) $randomExpire = $baseExpire + rand(-$baseExpire * 0.1, $baseExpire * 0.1); $randomExpire = max($randomExpire, 60); // 最少60秒 if ($data === null) { $this->redis->setex($key, min($randomExpire, 300), 'NULL_VALUE'); } else { $this->redis->setex($key, $randomExpire, json_encode($data)); } // 回填本地缓存 $this->setLocalCache($key, $data, min(300, $randomExpire * 0.1)); } /** * 设置本地缓存 */ private function setLocalCache(string $key, $data, int $expire): void { // LRU淘汰策略 if (count($this->localCache) >= $this->localCacheSize) { reset($this->localCache); $oldestKey = key($this->localCache); unset($this->localCache[$oldestKey]); } $this->localCache[$key] = [ 'data' => $data, 'expire' => time() + $expire ]; } /** * 预热缓存 */ public function warmUpCache(array $keys, callable $batchQuery): void { $uncachedKeys = []; // 检查哪些key未缓存 foreach ($keys as $key) { if ($this->redis->exists($key) === 0) { $uncachedKeys[] = $key; } } if (empty($uncachedKeys)) { return; } // 批量查询数据 $dataMap = $batchQuery($uncachedKeys); // 批量缓存 foreach ($dataMap as $key => $data) { $this->cacheData($key, $data, 3600); } } }最佳实践建议1. 缓存策略配置// 缓存配置优化 $cacheConfig = [ 'default_expire' => 3600, 'null_value_expire' => 300, 'hot_data_expire' => 7200, 'cold_data_expire' => 1800 ];2. 监控和告警<?php /** * 缓存监控工具 */ class CacheMonitor { public static function recordCacheHit(string $key): void { Metrics::increment('cache.hits'); } public static function recordCacheMiss(string $key): void { Metrics::increment('cache.misses'); } public static function recordCachePenetrationAttempt(string $key): void { Metrics::increment('cache.penetration_attempts'); Log::warning("Cache penetration attempt for key: {$key}"); } }3. 应急处理机制<?php /** * 缓存降级处理 */ class CacheDegradationHandler { private bool $cacheEnabled = true; private int $degradationThreshold = 100; // 每秒请求数阈值 public function shouldUseCache(): bool { if (!$this->cacheEnabled) { return false; } // 根据系统负载决定是否使用缓存 $currentLoad = $this->getCurrentSystemLoad(); return $currentLoad < $this->degradationThreshold; } private function getCurrentSystemLoad(): int { // 获取当前系统负载 return Metrics::getRate('requests.per_second'); } public function disableCacheTemporarily(int $seconds = 30): void { $this->cacheEnabled = false; Timer::setTimeout(function() { $this->cacheEnabled = true; }, $seconds * 1000); } }总结缓存系统防护的关键策略:分层防护:布隆过滤器+互斥锁+多级缓存相结合随机化策略:过期时间随机化避免集中失效监控预警:实时监控缓存命中率和异常行为应急机制:缓存降级和熔断保护系统稳定性预热策略:热点数据提前加载到缓存中通过这套完整的防护体系,可以有效应对缓存穿透、击穿和雪崩问题,保障系统的高可用性和稳定性。
2025年10月15日
0 阅读
0 评论
0 点赞