skillup

技術ブログ

アーキテクト設計全般

キャッシュの使い所とメリデメに関して(主に一覧系の処理に関して)

投稿日:

現在のプロジェクトがかなりの規模のECサイトになるため、正確性とパフォーマンスのトレードオフなどが先日議題にあがりました。

完全なトレードオフではないのかもしれませんが、比較的あちらをたてればこちらが立たず。。となりやすいかとおもいます。

そこで得た知見を自分なりにまとめてみようかと・・・

パフォーマンス問題となりますとサーバーサイド絡みの場合、ほぼDBのアクセスをどのようにして押さえるかになると思います。

サーバサイドの場合、対策としては以下の2つのように大別されるかなあと思います。

  1.  SQLのチューニングや見直し→そもそものロジックを見直し、発行回数自体を減らす、INDEXの活用を行う
  2. キャッシュの活用→staticキャッシュやインメモリDB

キャッシュのメリデメ

今回はキャッシュの使い所についての議論だったのですが、自分の場合、以下のケースでつかうことが多かったです。

  • 画面読み込み時に毎回走るDB処理でスポット的に使う一時的な変数→staticキャッシュ
  • これまた画面読み込み時に毎回走るマスタ系の処理→インメモリDB(memcachedやRedisなど)

キャッシュ(この場合インメモリのRedisなどを前提とするのですが)のメリデメとして

メリット

  • DBへのアクセスを減らせ、DBの負荷がさがる
  • アクセスが非常に高速
  • 単純な構造のデータの保存と参照につよい

デメリット

  • DBとの整合性を常に考える必要がある
  • 整合性を取るために、処理の網羅性を考えるのが面倒
  • 真の値(DB)の反映までに時間差がかかることがある
  • 揮発性のあるデータなので長期間保存しておけない
  • SQLのように複雑なデータの集計などができず、キーバリュー系の一時的なデータの保存にとどまる

のようなことが考えられると思います。

まとめると、超厳密には正しくないし、管理コストもあがるが、アクセス速度や負荷などが優先される場合(主に一時的なデータの参照)に使える手法、と言えるかと思います。

このような性質から単純なマスタの値だけでなく、参照系全般の処理に使えるかと思います。今の現場でも大量のアクセスがある一覧系の画面のAPIではDBではなくRedisを使っています。

参照系の処理の場合、

  • ユーザーのアクセスが更新系に比べると頻繁であることが多い
  • (あくまで)更新系よりは処理に厳密性を求められない

のような性質があるため、キャッシュが部分的に使えると思います。

既存の方針との比較など

高速化対策として、ちょっといままで行ってきた方針なども列挙しておこうかと思います。

個人的には一覧系で情報の参照が多い画面の場合

  1. ループ系のSQLをかく
  2. グルーピング系のSQLを書く
  3. サマリー系のテーブルを使う

といったことが多かったです。それぞれの特徴をみていきますと

ループ系のSQLをかく

一番単純で頭を使わない方法です。例えばユーザー一覧を取得する場合にループの中で1ユーザーごとにSQLを発行するような方法です。

メリット

  • 単純で何も考えなくて良い
  • 追加仕様があった際にも、ただ処理を追加するだけなので、簡単

デメリット

  • パフォーマンス的に一番厳しく、時間もかかれば、DBへの負荷も大きくなる

グルーピング系のSQLを書く

パフォーマンスに一番寄与するのはSQLそのものの発行回数を少なくすることなので、グルーピングさせて1回のSQLで出力させることができれば、単純ですがかなり効果があります。

アクセス数が爆発的でないケースではこの方法で改善することが多いのではないかと思います。直でDBをみるので、正確性もSQLが正確ならば担保ができます。ビューを使うのも実質ここにいれます。

メリット

  • 正確性をある程度保ちながら、パフォーマンスの向上が測れる
  • 直でDBをみるので真の値とのタイムラグなどがない

デメリット

  • SQLが肥大化しがちでメンテナンスが大変
  • 複雑なSQLの場合、正確な値がとれているかの確認が面倒
  • 表示項目などが多くなってくると必ずしもこの手法でとれない値もでてくる

サマリー系のテーブルを使う

グルーピング系だとSQLが肥大化したり、限界があることもあるので、サマリー系のテーブルを別途立てた方が良かったりします。

自分がやったのは勤怠報告みたいなテーブルだったんですが、日次で成績が記録されており、そこから月次のサマリーテーブルを作っていました。

メリット

  • 高速かつDBへの負荷も下がる
  • SQLが単純になる
  • 記録としても参照しやすい

デメリット

  • 真のデータ(サマリー元)とタイムラグが若干ある。
  • 真のデータ(サマリー元)との乖離に気をつける必要が常にある。(元が更新された際にサマリーテーブルに値を入れるが、このトリガーがもれることが多い)

インメモリデータベースをつかうのはこの手法にちかいかなと思います。

サマリーかつインメモリなので超高速ですが、その代わり正確性を担保するための対策というのが大変になってきます。

-アーキテクト設計全般
-

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

no image

オブジェクト指向設計 単一責任のクラスの設計

オブジェクト指向をするうえでの大事なポイントなど Contents1 単一責任のクラス設計1.1 メモ1.2 実際のコーディング上のコツ1.3 感想1.4 参考文献 単一責任のクラス設計 メモ 単一責 …

no image

テストコードの粒度に関して

テストコードを書いていることの悩みの1つにテストコードをどの粒度で書けばいいのか、ということがあります。 例えばバッチの場合、大きく分けると エントリーポイントのFeatureテスト Unitテスト( …

no image

Observeパターンについて

Contents1 Observeパターン2 他の対策2.1 プログラムで頑張って制御2.1.1 メリット2.1.2 デメリット2.2 Databaseのtirggerを使う(DB更新系のみ)2.2. …

no image

HTTPリクエストの分類について(POST、PUT、PATCT)

HTTPリクエストの分類(主に更新系のもの)について。 Contents1 POST2 PUT3 PATCH POST 更新系の代表的なHTTPリクエストですね。 通常はデータの取得=GET、更新=P …

no image

ステートパターンについて

トランザクション系のデータの場合、スタータスの遷移がキーになることが多く、仕様の把握に関してこの部分の理解が重要です。 今まで、ステータスの遷移に関してはExcelを使って表現していたことが多かったの …

アーカイブ