[建築家]キャッシュ内訳 - 複製、理論、分析、問題

シーン記述

1日のアカウントマネージャーは、フィードバック朝使用するプロジェクトの製品の1月頃ライン(5W程度エンドユーザー)は、システムが非常に遅い使っていますが、数分後にして、再度問題はありません。アカウントマネージャーは、数日後とフィードバックのないこの問題、アカウントマネージャーの第五直接フィードバックシステム巨人カードの後、20分以上、すでに存在し、直接使用することはできません。このメッセージの菊タイトなR&Dマネージャー聞く:「どのようにこれは大丈夫、時々問題があるか、時には可能性をどのように最初の数週間は問題ありませんが、問題は、今日???。」
問題のトラブルシューティングを行うためにR&Dマネージャー、緊急連絡運用・保守は、データベースやアプリケーションサーバの問題で、データベースのCPUの動作および保守は、通常のアプリケーション・サーバーのリソースを待つために、スレッドの様々な演奏見つけましたが、スレッドの特に高い数。運用・保守は時間のかかる遅いSQL 35秒のリード演奏CPUデータベースを検索し、それに続く、SQLの調査の結果、この遅い今日は、10回再びがあった、と時間が非常におよそ10秒以上の間隔で、集中していることがわかりました。図5はまた、一度だけ、この遅いSQLの前に現れました。SQLのトラブルシューティングホーム「効果的なトラフィック」SQLの統計が、Redisのキャッシュを使用して、このインターフェイスのためのこの遅い開発マネージャーによります。
なぜ、このインタフェースは、なぜデータベースへの憎しみが遅いSQLクエリの多くがまだある、キャッシュされたでしょうか?この現象は、

【バッファ】高耐圧同時シナリオで、全く同時スレッドは、DB大きな圧力をもたらす、破壊バッファ、キャッシュの効果が有効になっていない、プロセスはDBからデータをフェッチするために実行させるキャッシュからデータをフェッチしない、とします上記アプリケーションDBにつながったが死んでドラッグ。

ステップで問題を再現&問題のステップを解決するために、コードを使用しました

繰り返し発生する問題

私たちは、その後、キャッシュとリターンデータに、データを取得するために、データベースから既存のキャッシュのためのデータ、キャッシュされたデータと直接フィードバック、キャッシュデータを取得するHTTPインターフェースが存在しませんシミュレートします。次のようにサンプルコードは次のとおりです。

    /** 仅仅使用缓存方式获得数据 */
    @RequestMapping("/getBookCategrouyCount/v2/useCache")
    public AjaxResponse getBookCategrouyCountUseCache(){

        /** 适用缓存获取数据方式 */
        List<BookCategrouyCount> categrouyCount = null ;
        categrouyCount = redisCache.getValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,List.class);
        if(null == categrouyCount){
            //这里假设了bookCategrouyCountServer.getCategrouyCount();会直接一个慢SQL,导致数据库CPU飙到50%
            categrouyCount = bookCategrouyCountServer.getCategrouyCount();
            redisCache.setValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,categrouyCount,5*60);
        }
        return AjaxResponse.success(categrouyCount);
    }

私たちは、データベースサーバーのCPU使用率の要求を初めて目に(35秒かかります)一度このインタフェースは、呼び出されます。
ここに画像を挿入説明
もう一度、我々は(ちょうど同時30秒以内に5つの完了し、すべての要求(6秒の要求の両方)をシミュレートするためのJMeterを使用します時間内に遅いSQLクエリ)、理想的なの期待に基づいて、我々は、CPU使用率が約50%、単に遅いSQLよりもあるはずです。(下図のように)実際のCPU使用率が90%に達し、遅いSQLデータベースより5 MySQLCPUは、マップを占領しました
遅いSQLレコードチャート
これの原因は何ですか?10はこのインタフェースを要求することながら、午前8時30分05秒午前8時30分25秒に、この20秒の間、第一のインターフェース要求は、少なくとも35秒の必要によるものであった場合、私たちが完了した後、コードを解析してみましょう、キャッシュデータに入れられます内訳をキャッシュ、死のカードサービスにつながったデータベースに、この10の要求スレッドがキャッシュからデータを取得していないすべての憎悪をリードします。
一部の学生は、同時弾力に次のコードを制御することができ、同期コードブロックを、増加し、プログラムには問題:

    /** 使用缓存方式获得数据 增加同步代码块获得数据库数据 */
    @RequestMapping("/getBookCategrouyCount/v3/useCacheSync")
    public AjaxResponse getBookCategrouyCountUseCacheSync(){
        /** 适用缓存获取数据方式 */
        List<BookCategrouyCount> categrouyCount = null ;
        categrouyCount = redisCache.getValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,List.class);
        if(null == categrouyCount){
            //规避缓存获得不到数据,一下子全部怼到数据库压力太大,增加同步控制
            synchronized (this){
                categrouyCount = bookCategrouyCountServer.getCategrouyCount();
                redisCache.setValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,categrouyCount,5*60);
            }
        }
        return AjaxResponse.success(categrouyCount);
    }

調査結果上記のコードを実行し、それを引き起こすものである鳥のような同期コードを増加させませんか?最初の元のスレッドが来ると、データベースレベルにクエリを実行し、他の9が同期しているスレッドがロックが完全に実行するための最初のスレッドを解放するまでブロックされ、他の9つのスレッドがcategrouyCount = bookCategrouyCountServer」来ます。 getCategrouyCount();「コードが、今回はまだデータベースレベルを嫌いであろう。この時間は、より良い解決策だった、同期コードブロックのもので、次のコードを与えるために、再度キャッシュからデータを取得する必要があります。

    /** 使用缓存方式获得数据 增加同步代码块获得数据库数据,规避同步并发问题 */
    @RequestMapping("/getBookCategrouyCount/v4/useCacheSyncDetail")
    public AjaxResponse getBookCategrouyCountUseCacheSyncDetail(){
        /** 适用缓存获取数据方式 */
        List<BookCategrouyCount> categrouyCount = null ;
        categrouyCount = redisCache.getValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,List.class);
        if(null == categrouyCount){
            //规避缓存获得不到数据,一下子全部怼到数据库压力太大,增加同步控制
            synchronized (this){
                //同步代码中再次获取缓存数据,可以使用同步时候第一个线程放入缓存的结果,规避大量线程怼到数据库层面
                categrouyCount = redisCache.getValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,List.class);
                if(null != categrouyCount){
                    return AjaxResponse.success(categrouyCount);
                }
                categrouyCount = bookCategrouyCountServer.getCategrouyCount();
                redisCache.setValue(CACHE_KEY_BOOK_CATEGROUY_COUNT,categrouyCount,5*60);
            }
        }
        return AjaxResponse.success(categrouyCount);
    }

最新のコード・インタフェースの結果から分かるように、遅いSQLを一度だけ実行され、効果が達成されます。
PS:非同期スレッドまたは組み合わせのようにプリロードキャッシュされたデータ:ここでは、もちろん、単にのような、より良い解決策、一例です。
これまでのところ、原則のキャッシュ内訳は、解決策は、私はGitのアドレスを参照してくださいこの記事のプロジェクトのコード例を終了します。https://github.com/yun19830206/JavaTechnicalSummary/tree/master/Technology_Experience/CacheBreakdown

思考を展開

ビジネスコードで使用されるキャッシュ上記のサンプルコードは、業界は今、業務用のコードアーキテクチャに侵入しないよりエレガントなキャッシュを持って、私はボーエン参照、「[建築家]をキャッシュ-よりエレガントなキャッシュを行う方法」
」がありますホットキーの問題」、我々は拡張子の説明を行っているのRedis:

  • Redisのホットキーとは何ですか:ホットRedisのサービスにおけるキー(アプリケーションサーバから50)10Wを来ながら、発熱キーの要求、物理的なネットワークカードがブロックされた熱キーRedisのマシンの直接的な結果は、最終的なアプリケーションDBを取ることを余儀なく途中、遅い死、ゆっくりと死のDBアプリケーション。
  • 解決策:
    4.2.1:バックアップホットキー、Redisのキーのオリジナルテイクは、複数のRedisのプログラムを取るために変換さそうということ。
    42.2:ローカルキャッシュスキーム。よりエレガントなスキーム:Jedis、増加の熱非同期統計キーストレージの変換、その後の熱キーの要求は、ローカルキャッシュに直接アクセスしてください。ビジネス側の変換がない認知、バー。(メモリキャッシングサービス付きキャッシュサーバが続く、最速、そして最後にデータベース)
公開された21元の記事 ウォン称賛17 ビュー20000 +

おすすめ

転載: blog.csdn.net/chengyun19830206/article/details/104485733