緩存分層認知
| 層級 | 技術 | 範圍 | 共享性 |
| 數據對象緩存 | System.Web.Caching.Cache / Context.Cache | 進程內 | 無 (Web Garden 多進程不共享) |
| 頁面輸出緩存 | @OutputCache 指令 | 進程內 | 無 |
| 分布式緩存 | Memcached / Redis / SQL Server / 自定義 | 跨進程/跨機器 | 全共享 |
現狀痛點
- Web Garden/Web Farm:每進程獨立 Cache,資源浪費,數據不一致
- Enterprise Library Cache Block:
NullBackingStore (進程內)、SqlBackingStore (共享但性能受限)
- .NET 缺乏原生分布式緩存:微軟長期未提供內置方案
Memcached:PHP 陣營的成熟選擇
- 高性能、分布式、內存 Key-Value 存儲
- 客戶端一致性哈希路由,服務端無狀態
- .NET 客戶端庫成熟 (EnyimMemcached 等)
- 大型站點標配 (LiveJournal、Facebook、Twitter 早期架構)
自研擴展思路:EntLib + IBackingStore + Remoting/ICE
// 核心接口
public interface IBackingStore {
void Load();
void Save();
object Get(string key);
void Set(string key, object value);
// ...
}
// 基於 Remoting 的分布式實現概念
public class RemotingBackingStore : BaseBackingStore {
private ICacheService _remoteService; // 通過 Remoting/ICE 代理
public override object Get(string key) => _remoteService.Get(key);
public override void Set(string key, object value) => _remoteService.Set(key, value);
}
Discuz!NT 緩存實戰智慧
棄用 @OutputCache,採用模板預編譯 + 字符串構建
// 模板 show.html
<html><body>Hello, Your name is <% yourname %></body></html>
// 生成 show.aspx (預編譯)
templateBuilder.AppendLine("<html>");
templateBuilder.AppendLine("<body>");
templateBuilder.AppendLine("Hello, Your name is " + this.yourname); // 直接拼接
templateBuilder.AppendLine("</body>");
templateBuilder.AppendLine("</html>");
- 避開數據綁定控件性能開銷
StringBuilder 直接輸出 HTML,速度極快
分級緩存策略
- 數據層緩存:獨立緩存項 (用戶信息、版塊列表等)
- 頁面片段緩存:模板渲染結果存入 Cache
- HttpModule 早期攔截:生命周期前檢查緩存,命中直接
Response.Write(cachedHtml),執行時間 0ms
登入用戶個性化處理
- 匿名用戶:直接返回緩存頁面
- 登入用戶:緩存頁面 + **動態注入 JS** 替換用戶區塊,或 AJAX 異步獲取個性化片段
- 避免「登入用戶比匿名用戶慢」的體驗倒掛
架構建議
- **小型應用**:ASP.NET Cache + 輸出緩存足夠
- **中型/Web Farm**:引入 Memcached/Redis,Session 同步、對象緩存共享
- **大型/高併發**:多級緩存 (本地 L1 + 分布式 L2) + 緩存穿透/雪崩/擊穿防護
- **頁面緩存**:參考 DNT 模板預編譯 + HttpModule 早期輸出,極致性能
結語
「合適的才是最好的。DNT 在特定場景下的針對性優化,雖代碼不完美,但解決了實際性能問題——這才是工程的本質。」