並非所有數據都適合緩存。決策矩陣如下:
| 特徵 | 適合緩存 | 不適合緩存 |
|---|---|---|
| 讀寫比 | 高讀低寫(如配置、字典、靜態資訊) | 高寫頻繁(如論壇回覆、即時庫存) |
| 數據穩定性 | 週期性變更(如每日更新的報表) | 實時性強(如股價、聊天消息) |
| 計算成本 | 複雜聚合、跨服務調用 | 簡單主鍵查詢 |
Module:Entity:Id)、值類型(POCO、DataTable、JSON 字符串)。DateTime.Now.AddMinutes(30)TimeSpan.FromMinutes(10)(訪問即續期)CacheDependency 綁定文件/ SQL 表/ 其他 Keyusing System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
namespace Larry.Cache
{
public sealed class BaseCache
{
// 時間因子(秒),便於全局調整
public static readonly int MinuteFactor = 60;
public static readonly int HourFactor = 3600;
public static readonly int DayFactor = 86400;
public static readonly double SecondFactor = 1.0;
private static readonly Cache _cache;
private static readonly int _factor = 1; // 可配置倍率
static BaseCache()
{
_cache = HttpContext.Current?.Cache ?? HttpRuntime.Cache;
}
#region 核心 Insert 重載鏈
public static void Insert(string key, object obj)
=> Insert(key, obj, null, MinuteFactor * 5); // 默認 5 分鐘
public static void Insert(string key, object obj, CacheDependency dep)
=> Insert(key, obj, dep, MinuteFactor * 5);
public static void Insert(string key, object obj, int seconds)
=> Insert(key, obj, null, seconds);
public static void Insert(string key, object obj, CacheDependency dep, int seconds)
=> Insert(key, obj, dep, seconds, CacheItemPriority.Normal);
public static void Insert(string key, object obj, CacheDependency dep, int seconds, CacheItemPriority priority)
{
if (obj == null) return;
_cache.Insert(key, obj, dep,
DateTime.Now.AddSeconds(_factor * seconds),
TimeSpan.Zero, priority, null);
}
#endregion
#region 特殊策略
public static void Max(string key, object obj, CacheDependency dep = null)
{
if (obj == null) return;
_cache.Insert(key, obj, dep, DateTime.MaxValue, TimeSpan.Zero,
CacheItemPriority.AboveNormal, null);
}
public static void Permanent(string key, object obj, CacheDependency dep = null)
{
if (obj == null) return;
_cache.Insert(key, obj, dep, DateTime.MaxValue, TimeSpan.Zero,
CacheItemPriority.NotRemovable, null);
}
#endregion
public static object Get(string key) => _cache[key];
public static void Remove(string key) => _cache.Remove(key);
public static void RemoveByPattern(string pattern)
{
var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
foreach (string key in _cache.Cast().Select(de => de.Key.ToString()))
if (regex.IsMatch(key)) _cache.Remove(key);
}
public static void Clear()
{
foreach (string key in _cache.Cast().Select(de => de.Key.ToString()))
_cache.Remove(key);
}
}
}
public static Systems GetConfig()
{
const string cacheKey = "WebConfig";
var config = BaseCache.Get(cacheKey) as Systems;
if (config == null)
{
config = LoadConfigFromDb(); // 昂貴操作
// 緩存 24 小時,高優先級
BaseCache.Insert(cacheKey, config, 24 * BaseCache.HourFactor, CacheItemPriority.AboveNormal);
Log.Info("配置首次加載入緩存");
}
else
{
Log.Debug("命中緩存,避免數據庫查詢");
}
return config;
}
| 痛點 | 解決方案 |
|---|---|
| 緩存擊穿 | 雙重檢查鎖 + Lazy<T> 或分佈式鎖 |
| 緩存雪崩 | 過期時間加隨機因子 base + Random(0-300) |
| 分佈式一致性 | 遷移至 Redis + IDistributedCache,配合發布/訂閱失效通知 |
| 對象圖序列化 | 存入 JSON (System.Text.Json) 而非二進制,便於跨語言/版本兼容 |
| 監控指標 | 埋點:Hit/Miss Ratio、緩存大小、驅逐率、延遲 P99 |
// ASP.NET Core / .NET 5+ 標準接口
public class DistributedCacheWrapper
{
private readonly IDistributedCache _cache;
public DistributedCacheWrapper(IDistributedCache cache) => _cache = cache;
public async Task SetAsync(string key, object value, TimeSpan? ttl = null)
{
var json = JsonSerializer.Serialize(value);
await _cache.SetStringAsync(key, json, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = ttl ?? TimeSpan.FromMinutes(5)
});
}
public async Task GetAsync(string key)
{
var json = await _cache.GetStringAsync(key);
return json == null ? default : JsonSerializer.Deserialize(json);
}
}
緩存設計是系統性能優化的槓桿,核心在於「業務語義驅動策略」而非「技術棧堆砌」。上文封裝類已在多個千萬 PV 級項目穩定運行,可作為遷移至分佈式緩存前的最佳過渡方案。