高性能ASP.NET站點構建之細節決定成敗

前言:曾經就由於一個小小的疏忽,從而致使了服務器崩潰了,後來才發現:原來就是由於一個循環而致使的,因此,對「注意細節「這一說法是深有感觸。javascript

本篇的議題以下:java

問題的描述數據庫

細節的重要性緩存

問題的描述服務器

首先,描述一下故事的背景:(但願你們耐心的故事讀完)ide

在網站中,網頁中的分頁控件每次顯示10條數據,每次點擊下一頁,就再次去取下一個10條數據。至於分頁的方法怎樣作,方法有不少,相信這點你們都知道。網站

過程是這樣的:在用戶請求數據的時候(考慮到了用戶的操做和網站的訪問量)我會第一次取出500條數據,而後把數據放在緩存中,也就是說,我取出了50頁的數據,放在緩存中,這樣若是,之後用戶請求第一頁到第49頁的時候,就直接從緩存中拿數據。this

以下圖:spa

緩存流程圖
 

第一個數據塊:xml

採用鍵值對的形式:字典保存

若是用戶請求到了49頁之後,那麼就再次從數據庫中取出下一個數據塊(包含501到1000數據),而後,如今內存中就有了1000條數據。

至於緩存多久,數據什麼失效,失效後怎麼作,這裏暫不談論。(網站在這種緩存策略下運行的很好)。 

代碼以下:

   
   
   
   
  1. List<Product> products=GetDataFromCacheOrDatabase(condition,pageIndex,count….); 
  1.  

代碼的意思很清楚,從緩存中拿數據,若是緩存中沒有對應的數據,那麼就先從數據庫中拿500條數據,而後放在緩存中,最後返回10條數據。

後來,由於某些功能的須要,須要返回當前頁的前6頁數據和後6頁的數據,例如:若是當前頁是第12頁,那麼就要返回12頁以前6頁Product(也就是第6,7,8,9,10,11頁的數據),和第12頁後的頁的Product(第13,14,15,16,17,18頁的數據)。 

以下:

 

 

固然,若是當前頁是第5頁,那麼就把以前全部5頁的數據都返回,另外再加上第5頁以後的6頁數據。

這裏就可能涉及到跨塊獲取數據,如:

若是當前頁是第48頁的時候,那麼返回前6頁數據是沒有什麼問題的,那麼後6頁的數據就不足了,由於49,40也得數據能夠從緩存的數據塊中取到,至於51,52,53,54頁的數據,就須要再次從數據庫中讀取,而後再次緩存(若是事先沒有被緩存)。

最後在緩存中的數據以下:

而後調用方法:(僞碼)

List<Product> products=GetDataFromCacheOrDatabase(condition,42, 126….);  

上面傳入的是從第42頁開始的數據,也就是第48頁的前6頁和後6頁的數據。

這個方法的內部實現是這樣的:

1.    首先從第一個數據塊中取出42頁到50頁的數據

取出數據後保存在一個List<Product> firstProductList;

2.    從第二個數據塊中取出從51頁到54頁(若是第二個數據塊在緩存不存在,就去數據庫中取501-1000條,而後再放在緩存的第二個數據塊中)。

保存在第二個List<Product> secondProductList

3. 而後把兩個list合併,返回結果。例如

secondProductList.Foreach(u=>firstProductList.Add(u)); 

基本的實現就是這樣,看起來還行,也比較的合理,可是就是由於這個操做,從而致使服務器內存溢出。

你們想一想看是什麼緣由。

細節的重要性

其實緩存的數據不是不少,是不足以讓服務器內存溢出的,可是服務器仍是出現了out of memory的異常。以前一直跑的很好,就是改了代碼以後纔出現問題的。

其實這就是因爲一個最基本的錯誤產生的:引用類型。

下面就來分析下:

首先是從第一個數據塊中取出數據,而後用

List<Product> firstProductList 引用指向取出的數據

而後從第二個數據塊中取出數據,用

List<Product> secondProductList指向數據的引用

以下圖

 

在第三步中採用

  
  
  
  
  1. secondProductList.Foreach(u=>firstProductList.Add(u)); 
  1.  

把secondProductList中的數據加入到firstProductList中,就由於是引用類型,其實實際操做的結果是:不斷的在改變第一個數據塊中的數據,使得第一個數據塊中的數據逐漸的變多。

如今當前頁是48頁,採用上面的操做,導致第一個數據塊中的數據增長了60條,

若是用戶再次翻頁,到了49頁,那麼第一個數據塊中的數據又增多了60條

依此類推,最後致使了服務器內存的不足,導致服務器崩潰了。本來的「功臣」----緩存卻成爲了罪魁禍首。

其實這個問題的解決,只要改變一點點的代碼就好了: 

List<Product> firstProductList;  

List<Product> secondProductList; 

而後

List<Product> resultProductList=new List<Product>();而後分別把firstProductList,secondProductList遍歷,加入到resultProductList就好了。

就這麼簡單。

一個小的細節,致使了大的問題。

相關文章
相關標籤/搜索