首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

.NET 應用緩存設計全攻略:策略、實現與 CommunityServer 實戰類解析

     編輯:ASP.NET 基礎

一、緩存適用場景判斷

並非所有數據都適合緩存。決策矩陣如下:

特徵適合緩存不適合緩存
讀寫比高讀低寫(如配置、字典、靜態資訊)高寫頻繁(如論壇回覆、即時庫存)
數據穩定性週期性變更(如每日更新的報表)實時性強(如股價、聊天消息)
計算成本複雜聚合、跨服務調用簡單主鍵查詢

二、緩存設計四步法

  1. 確定結構:Key 命名規範(如 Module:Entity:Id)、值類型(POCO、DataTable、JSON 字符串)。
  2. 確定數據源:哪些查詢、服務調用結果入緩存。
  3. 過期與清理策略:
    • 絕對過期:DateTime.Now.AddMinutes(30)
    • 滑動過期:TimeSpan.FromMinutes(10)(訪問即續期)
    • 依賴項:CacheDependency 綁定文件/ SQL 表/ 其他 Key
    • 主動清理:按前綴/正則批量移除
  4. 加載方式:同步阻塞 vs 異步預熱(啟動任務/後台職程)。

三、CommunityServer 風格緩存封裝類深度解析

using 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

六、遷移指引:從 HttpRuntime.Cache 到 IDistributedCache

// 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 級項目穩定運行,可作為遷移至分佈式緩存前的最佳過渡方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved