Лучший способ кэшировать результаты RESTful API вызовов GET
Я думаю о лучшем способе создания слоя кэша спереди или в качестве первого слоя для запросов GET к моему RESTful API (написанному на Ruby).
Не каждый запрос может быть кэширован, потому что даже для некоторых запросов GET API должен проверить запрашивающего пользователя / приложение. Это означает, что мне нужно настроить, какой запрос кэшируется и как долго каждый кэшированный ответ действителен. Для нескольких случаев мне нужно очень короткое время истечения, например, 15s и ниже. И я должен быть в состоянии дать записи кэша истекают приложением API, даже если срок действия еще не достигнут.
Я уже думал о многих возможных решениях, мои две лучшие идеи:
первый уровень API (даже до маршрутизации), логика кэша сама по себе (чтобы иметь все параметры конфигурации в моей руке), ответы и срок действия, хранящиеся в Memcached
прокси-сервер веб-сервера (высокий настраиваемый), возможно, что - то вроде Squid, но я никогда не использовал прокси для такого случая раньше, и я абсолютно не уверен в этом
Я также думал о решении кэша, таком как лак, я использовал лак для "обычных" веб-приложений, и это впечатляет, но конфигурация особенная. Но я бы использовал его, если это самое быстрое решение.
другой мыслью было кэшировать к индексу Solr, который я уже использую в слое данных, чтобы не запрашивать базу данных для большинства запросов.
Если кто-то имеет подсказка или хорошие источники, чтобы прочитать об этой теме, дайте мне знать.
5 ответов
memcached-отличный вариант, и я вижу, что вы уже упоминали об этом как о возможном варианте. Также Redis, похоже, очень хвалят как еще один вариант на этом уровне.
на уровне приложения, с точки зрения более детального подхода к кэшированию в файле по файлу и / или модулю, локальное хранилище всегда является опцией для общих объектов, которые пользователь может запрашивать снова и снова, даже просто как просто падение объектов ответа в сеанс, чтобы можно было повторно использовать против создания другого http rest вызов и кодирование соответствующим образом.
теперь люди идут туда и обратно, обсуждая лак против squid, и у обоих, похоже, есть свои плюсы и минусы, поэтому я не могу комментировать, какой из них лучше, но многие люди говорят, что лак с настроенным сервером apache отлично подходит для динамических веб-сайтов.
во-первых, создайте свой RESTful API, чтобы быть RESTful. Это означает, что аутентифицированные пользователи также могут получить кэшированное содержимое, чтобы сохранить все состояние в URL-адресе, который должен содержать данные аутентификации. Конечно, скорость попадания здесь будет ниже,но она достижима.
с большим количеством зарегистрированных пользователей будет очень полезно иметь какой-то кэш модели за полным кэшем страницы, поскольку многие модели по-прежнему являются общими, даже если некоторые из них (в хорошей структуре ООП).
тогда для a полный кэш страниц вам лучше всего держать все запросы вне веб-сервера и особенно вдали от динамической обработки на следующем шаге (в вашем случае Ruby). Самый быстрый способ кэширования полных страниц с обычного веб-сервера - это всегда кэширующий прокси перед веб-серверами.
лак, на мой взгляд, так же хорошо и легко, как и получается, но некоторые предпочитают кальмаров.
поскольку REST-это HTTP-вещь, возможно, лучший способ кэширования запросов-использовать HTTP-кэширование.
посмотрите на использование ETags в ваших ответах, проверяя ETag в запросах на ответ с "304 не изменено" и имея Rack::Cache для обслуживания кэшированных данных, если ETags одинаковы. Это отлично подходит для "публичного" контента cache-control.
Rack:: Cache лучше всего настроить для использования memcache для его потребностей хранения.
Я написал пост в блоге на прошлой неделе о интересный способ, которым Rack:: Cache использует ETags для обнаружения и возврата кэшированного содержимого новым клиентам: http://blog.craz8.com/articles/2012/12/19/rack-cache-and-etags-for-even-faster-rails
даже если вы не используете Rails, инструменты промежуточного программного обеспечения стойки довольно хороши для этого материала.
Redis Cache-лучший вариант. регистрация здесь.
Это с открытым исходным кодом. Расширенный кэш и хранилище значений ключей.
Я успешно использовал 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)