高性能ASP.NETサイト構築の詳細が成否を決める


前言:小さな不注意でサーバーがクラッシュしたことがありますが、ループが原因だったことに気づき、「細部に注意」という言い方に感銘を受けました.
本編の議題は以下の通りです.
問題の説明
細部の重要性
問題の説明
まず、物語の背景を説明します:(辛抱強い物語を読んでほしい)
ウェブサイトでは、ページ内のページングコントロールが10個のデータを表示するたびに、次のページをクリックするたびに、再び次の10個のデータを取りに行きます.ページ分けの仕方については、いろいろな方法がありますが、それはみんな知っていると思います.
プロセスは、ユーザーがデータを要求するとき(ユーザーの操作とウェブサイトのアクセス量を考慮して)私は初めて500個のデータを取り出して、それからデータをキャッシュに入れます.つまり、私は50ページのデータを取り出して、キャッシュに入れます.そうすれば、後のユーザーが最初のページから49ページを要求するとき、直接キャッシュからデータを取ります.
次の図を示します.
 
最初のブロック:
キー値ペアの形式:辞書保存
ユーザーが49ページまで要求した場合、次のデータブロック(501~1000データを含む)をデータベースから再び取り出し、メモリに1000個のデータが格納されます.
キャッシュがどのくらい有効になったか、データが無効になった後にどうするかについては、ここでは議論しません.(ウェブサイトはこのようなキャッシュポリシーの下でよく動作しています). 
コードは次のとおりです.
    
    
    
    
  1. List<Product> products=GetDataFromCacheOrDatabase(condition,pageIndex,count….); 
  •  

  • コードの意味ははっきりしていて、キャッシュからデータを取って、キャッシュに対応するデータがなければ、まずデータベースから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 firstProductListに保存する.
    2.第2のデータ・ブロックから51ページから54ページを取り出す(第2のデータ・ブロックがキャッシュに存在しない場合は、データベースから501〜1000個を取り、キャッシュされた第2のデータ・ブロックに入れる).
    2番目のList secondProductListに保存
    3.次に2つのリストをマージし、結果を返します.たとえば

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


    基本的な実装は、まあまあのように見え、合理的ですが、この操作によりサーバメモリがオーバーフローします.
    何が原因なのか考えてみましょう.
    細部の重要性
    キャッシュされたデータはそれほど多くなく、サーバのメモリをオーバーフローさせるには十分ではありませんが、サーバにはout of memoryの異常が発生しています.以前はよく走っていましたが、コードを変更してから問題が発生しました.
    これは、最も基本的なエラーによるものです.参照タイプです.
    次に分析します.
    まず最初のブロックからデータを取り出し、
    List firstProductListは取り出したデータを参照する
    そして2番目のブロックからデータを取り出し、
    List secondProductListデータへの参照
    以下の図
     
    ステップ3で採用
       
       
       
       
    1. secondProductList.Foreach(u=>firstProductList.Add(u)); 
  •  

  • secondProductListのデータをfirstProductListに組み込むと、参照タイプであるため、実際の動作の結果、最初のデータブロックのデータが絶えず変化し、最初のデータブロックのデータが徐々に多くなる.
    現在のページは48ページで、上記の操作により、最初のデータブロックのデータが60個増加し、
    ユーザが再びページをめくって49ページになると,最初のデータブロックのデータは60個増加する.
    このようにして、最後にサーバのメモリが不足し、サーバがクラッシュしました.本来の「功労者」であるキャッシュが元凶となった.
    実はこの問題の解決は、わずかなコードを変えればいいのです.

    List<Product> firstProductList;  

    List<Product> secondProductList; 


    そして
    List resultProductList=new List();そしてfirstProductList,secondProductListをそれぞれ巡回しresultProductListに加えればよい.
    簡単です.
    小さな細部が、大きな問題を引き起こした.