Подтвердить что ты не робот

Лучший способ кэширования результатов API RESTful вызовов GET

Я думаю о наилучшем способе создания уровня кэша спереди или в качестве первого уровня для запросов GET для моего RESTful API (написанного на Ruby).

Не каждый запрос может быть кэширован, потому что даже для некоторых запросов GET API должен проверять запрашивающего пользователя/приложение. Это означает, что мне нужно настроить, какой запрос кэшируется, и как долго каждый кешированный ответ действителен. Для нескольких случаев мне нужно очень короткое время истечения, например. 15 с и ниже. И я должен иметь возможность истекать через кэширование приложений API, даже если дата истечения еще не достигнута.

Я уже думал о многих возможных решениях, моих двух лучших идеях:

  • первый уровень API (даже до маршрутизации), логика кэша сама (для всех параметров конфигурации в моей руке), ответы и дата истечения срока хранения, хранящиеся в Memcached

  • прокси-сервер webserver (с высокой степенью конфигурирования), возможно, что-то вроде Squid, но я никогда не использовал прокси-сервер для такого случая раньше, и я абсолютно не уверен в этом

Я также подумал о решении для кеша, таком как Varnish, я использовал Larnish для "обычных" веб-приложений, и это впечатляюще, но конфигурация является особенной. Но я бы использовал его, если бы это было самое быстрое решение.

Другая мысль заключалась в том, чтобы кэшировать индекс Solr, который я уже использую в слое данных, чтобы не запрашивать базу данных для большинства запросов.

Если у кого-то есть подсказка или хорошие источники, чтобы прочитать об этой теме, сообщите мне.

4b9b3361

Ответ 1

memcached - отличный вариант, и я вижу, что вы упомянули об этом уже как возможный вариант. Кроме того, Redis, похоже, похвалили, как еще один вариант на этом уровне.

На уровне приложений с точки зрения более гранулярного подхода к кешу в файле по файлу и/или модулю локальное хранилище всегда является опцией для обычных объектов, которые пользователь может запрашивать снова и снова, даже так же просто, как просто отбрасывая объекты ответа в сеанс, чтобы их можно было повторно использовать, а также сделать другой HTTP-вызов и кодирование соответствующим образом.

Теперь люди идут вперед и назад, обсуждая вопрос о лаке против кальмара, и оба, похоже, имеют свои плюсы и минусы, поэтому я не могу комментировать, какой из них лучше, но многие говорят, что лак с настроенным сервером Apache отлично подходит для динамических веб-сайтов.

Ответ 2

Во-первых, создайте свой RESTful API для RESTful. Это означает, что пользователи, прошедшие проверку подлинности, также могут получать кешированный контент, чтобы сохранить все состояние в URL-адресе, в котором он должен содержать данные авторизации. Конечно, уровень атаки здесь будет ниже, но он доступен для кеширования.

С большим количеством зарегистрированных пользователей будет очень полезно иметь некоторый тип кэша модели за полноэкранным кешем, так как многие модели по-прежнему доступны, даже если некоторые из них (в хорошей структуре ООП).

Затем для полноэкранного кеша вам лучше всего отложить все запросы от веб-сервера и особенно от динамической обработки на следующем шаге (в вашем случае Ruby). Самый быстрый способ кэшировать полные страницы с обычного веб-сервера - это всегда кеширующий прокси перед веб-серверами.

Лак на мой взгляд так же хорош и прост, как и он, но некоторые предпочитают Squid действительно.

Ответ 3

Поскольку REST - это HTTP-приложение, возможно, лучший способ кэширования запросов - использовать кеширование HTTP.

Посмотрите на использование ETags в своих ответах, проверив ETag в запросах на ответ с помощью "304 Not Modified" и имея Rack:: Cache для обслуживания кэшированных данных, если ETags одинаковы. Это отлично работает для "публичного" контента, контролирующего кеш.

Rack:: Кэш лучше всего настроен для использования memcache для хранения данных.

На прошлой неделе я написал сообщение в блоге об интересном способе, которым Rack:: Cache использует ETags для обнаружения и возврата кэшированного контента новым клиентам: http://blog.craz8.com/articles/2012/12/19/rack-cache-and-etags-for-even-faster-rails

Даже если вы не используете Rails, инструменты промежуточного программного обеспечения для стойки вполне подходят для этого.

Ответ 4

Redis Cache - лучший вариант. здесь.

Это с открытым исходным кодом. Расширенный кеш-ключ и хранилище.

Ответ 5

Я использовал redis успешно таким образом в представлении REST:

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)