web-dev-qa-db-ja.com

GET呼び出しのRESTful API結果をキャッシュする最良の方法

私は、RESTful API(Rubyで記述された)へのGETリクエストの前または最初の層としてキャッシュ層を作成する最良の方法を考えています。

すべてのリクエストをキャッシュできるわけではありません。一部のGETリクエストでも、APIはリクエストしているユーザー/アプリケーションを検証する必要があるためです。つまり、どのリクエストをキャッシュ可能にし、キャッシュされた各回答の有効期間を設定する必要があります。いくつかのケースでは、非常に短い有効期限が必要です。 15秒以下。また、有効期限にまだ達していない場合でも、キャッシュエントリがAPIアプリケーションによって期限切れになるようにする必要があります。

私はすでに考えられる多くの解決策について考えました。私の2つの最高のアイデアです。

  • aPIの最初の層(ルーティングの前でも)、自分でキャッシュロジック(すべての構成オプションを手に入れるため)、回答および有効期限をMemcachedに保存

  • webサーバープロキシ(高度な構成可能)、おそらくSquidのようなものですが、以前はこのようなケースにプロキシを使用したことがなく、それについては絶対にわかりません

また、Varnishのようなキャッシュソリューションについても考えました。「通常の」WebアプリケーションにVarnishを使用しましたが、印象的ですが、構成は特別なものです。しかし、それが最速のソリューションである場合、それを使用します。

もう1つの考えは、Solrインデックスにキャッシュすることです。Solrインデックスは、データレイヤーで既に使用しており、ほとんどの要求に対してデータベースにクエリを実行しません。

誰かがこのトピックについて読むヒントや良い情報源を持っているなら、私に知らせてください。

22
maddin2code

memcachedは素晴らしいオプションです。これは既に可能なオプションとして言及していると思います。また、Redisは、このレベルの別のオプションとして非常に称賛されているようです。

アプリケーションレベルでは、ファイル単位またはモジュール単位でファイルをキャッシュするためのよりきめ細かいアプローチの観点から、ローカルストレージは常に、ユーザーが何度も何度も要求する可能性のある一般的なオブジェクトのオプションです。オブジェクトをセッションに追加して、再利用できるようにすることと、別のHTTPレストコールを行い、適切にコーディングすること。

現在、ワニスとイカについて議論を行っていますが、どちらにも長所と短所があるようですので、どちらが良いかについてはコメントできませんが、多くの人々は、調整されたApacheサーバーを備えたワニスは動的なウェブサイトに最適だと言います。

3
jsteinmann

まず、RESTfulになるようにRESTful APIを構築します。これは、認証されたユーザーがキャッシュされたコンテンツを取得して、認証の詳細を含める必要があるURLのすべての状態を保持できることを意味します。もちろん、ここではヒット率は低くなりますが、キャッシュ可能です。

ログインしているユーザーが多い場合、一部のモデルが共有されていない場合でも多くのモデルがまだ共有されているため、フルページキャッシュの背後にある種のモデルキャッシュを持つことは非常に有益です(良いOOP =構造)。

次に、ページ全体をキャッシュするには、すべてのリクエストをWebサーバーから外し、特に次のステップ(Rubyの場合)の動的処理から遠ざけるのが最善です。通常のWebサーバーから全ページをキャッシュする最も速い方法は、常にWebサーバーの前にあるキャッシュプロキシです。

私の意見では、ワニスは手に入れるのと同じくらい良くて簡単ですが、確かにイカを好む人もいます。

5
Clarence

RESTはHTTPのものであるため、リクエストをキャッシュする最良の方法はHTTPキャッシュを使用することです。

応答でのETagの使用を検討し、「304 Not Modified」で応答するリクエストのETagを確認し、ETagが同じ場合は、Rack :: Cacheがキャッシュデータを提供するようにします。これは、キャッシュ制御の「パブリック」コンテンツに最適です。

Rack :: Cacheは、ストレージのニーズに応じてmemcacheを使用するように最適に構成されています。

Rack :: CacheがETagを使用してキャッシュされたコンテンツを検出し、新しいクライアントに返す興味深い方法について先週ブログ記事を書きました: http://blog.craz8.com/articles/2012/12/19/ rack-cache-and-etags-for-even-faster-Rails

Railsを使用していない場合でも、Rackミドルウェアツールはこのような用途に適しています。

4
Tom Fakes

Redis Cacheが最適なオプションです。 チェックしてください

オープンソースです。高度なキーと値のキャッシュとストア。

2
Jill

RESTビューでこのようにredisを正常に使用しました:

from Django.conf import settings
import hashlib
import json
from redis import StrictRedis
from Django.utils.encoding import force_bytes

def get_redis():
    #get redis connection from RQ config in settings
    rc = settings.RQ_QUEUES['default']
    cache = StrictRedis(Host=rc['Host'], port=rc['PORT'], db=rc['DB'])
    return cache



class EventList(ListAPIView):
    queryset = Event.objects.all()
    serializer_class = EventSerializer
    renderer_classes = (JSONRenderer, )


    def get(self, request, format=None):
        if IsAdminUser not in self.permission_classes:  # dont cache requests from admins


            # make a key that represents the request results you want to cache
            #  your requirements may vary
            key = get_key_from_request()

            #  I find it useful to hash the key, when query parms are added
            #  I also preface event cache key with a string, so I can clear the cache
            #   when events are changed
            key = "todaysevents" + hashlib.md5(force_bytes(key)).hexdigest()        

            # I dont want any cache issues (such as not being able to connect to redis)
            #  to affect my end users, so I protect this section
            try:
                cache = get_redis()
                data = cache.get(key)
                if not data:
                    #  not cached, so perform standard REST functions for this view
                    queryset = self.filter_queryset(self.get_queryset())
                    serializer = self.get_serializer(queryset, many=True)
                    data = serializer.data

                    #  cache the data as a string
                    cache.set(key, json.dumps(data))

                    # manage the expiration of the cache 
                    expire = 60 * 60 * 2  
                    cache.expire(key, expire)
                else:
                    # this is the place where you save all the time
                    #  just return the cached data 
                    data = json.loads(data)

                return Response(data)
            except Exception as e:
                logger.exception("Error accessing event cache\n %s" % (e))

        # for Admins or exceptions, BAU
        return super(EventList, self).get(request, format)

イベントモデルの更新で、イベントキャッシュをクリアします。これはほとんど実行されないため(管理者のみがイベントを作成し、それほど頻繁には作成しません)、常にすべてのイベントキャッシュをクリアします

class Event(models.Model):

...

    def clear_cache(self):
        try:
            cache = get_redis()
            eventkey = "todaysevents"
            for key in cache.scan_iter("%s*" % eventkey):
                cache.delete(key)
        except Exception as e:
            pass


    def save(self, *args, **kwargs):
        self.clear_cache()
        return super(Event, self).save(*args, **kwargs)
0
Comp Guy