Pull to refresh

Comments 14

Хабраюзер Suor когда-то анонсировал свою разработку — django-cacheops. В качестве хранилища используется только redis. Если этот факт не смущает, то, думаю, пост можно считать закрытым :-)
Не очень понимаю, как это закрывает пост. К этому приложению применимы все те же две претензии:
  • Недостаточный контроль за инвалидацией: можно инвалидировать объект, можно инвалидировать все объекты модели, больше ничего.
  • Ограничения, возможно, потребующие дополнительного кода (раздел Caveats)


Плюс, инвалидация только через удаление записи в кэше, что не всегда является лучшим решением (о чем я пишу в посте).

Приложение хорошее, да, не хуже тех, что перечислены в посте, но у меня не было цели сделать обзор всех готовых решений. Так что может рано пока закрывать? :-)
Недостаточный контроль за инвалидацией: можно инвалидировать объект, можно инвалидировать все объекты модели, больше ничего.

Все объекты кверисета. Со всеми его фильтрами. Что ещё нужно-то? :-)

Плюс, инвалидация только через удаление записи в кэше, что не всегда является лучшим решением (о чем я пишу в посте).

По-моему, Вы как раз и пишете, что обновлять данные в кеше не стоит, т.к. операция неатомарная. И таки да, это правильно.
Думаю, что пример с непосредственным вызовом операций типа incr и decr настолько частный случай (явное управление кешем с явно заданным бэкендом) не может рассматриваться как общий случай, который готовые решения покрывают. Я бы не стал эту претензию предъявлять ни к одному из generic-приложений. Случай не тот.

Что ещё нужно-то? :-)

Я приводил пример в посте. Часто, если в обработчике сигнала created == True, можно не инвалидировать часть ключей. Например, условно, топ100 статей за все время, свежесозданная статья туда не попадет. Есть и еще ряд проверок, которые могут оказаться очень полезными, чтобы не делать сложные выборки.

И я не утверждаю, что это нужно всегда. Но что это есть, знать стоит, и учитывать при выборе подхода к кэшированию тоже стоит.

По-моему, Вы как раз и пишете, что обновлять данные в кеше не стоит, т.к. операция неатомарная.

Немного не о том. Я про то, что часто лучше заменить cache.delete(key) на cache.set(key, instance), если instance передается в сигнал.

В целом, спор кажется бесперспективным. Я же не говорю: не используйте готовое, пишите все сами, только хардкор и т. д. У готовых решений есть некоторые ограничения. Если они критичны (или есть какие-то другие причины), то можно рассмотреть возможность реализации кэша самостоятельно. Если не критичны, конечно, используйте готовое. Только и всего.
Насчёт только удаления — есть недокументированная возможность:

CACHEOPS = {
    'auth.user': ('get', 60*15, {'cache_on_save': True}),
    'people.userprofile': ('get', 60*15, {'cache_on_save': 'user'}),
}


При сохранении юзера он будет закеширован по id, при сохранении профиля по user_id.

А так, в целом, конечно, никакое универсальное решение не универсально настолько, чтобы удовлетворить всех.
Еще один из вариантов — varnish. А тут можно посмотреть пример того как подружить его с Django.
У johny-cache на самом деле недостатков намного больше чем достоинств. И основной из них — то, что тормозная десериализация queryset'ов зачастую дает отрицательный выигрыш по сравнению с запросом в СУБД. Та же проблема у cache-machine.

Вообще, как подсказывает мой небольшой опыт, большая часть задач решается либо кешированием на уровне вьюх/шаблонов, либо точечным кешированием в считаных местах.

А за django-cached-modelform отдельное человеческое спасибо. Приятно, когда можно воспользоваться чьим-то готовым велосипедом ;)
У Johnny Cache есть очень серьезная проблема — он кеширует radnom запросы. Приходится или дописывать какую-то динамическую фигню в запросы или лезть править его внутренности.
Не используйте random запросы. Не только из-за того, что у Johnny Cache с этим серьезная проблема.
Не используйте random запросы

Не совсем понимаю суть совета. А каким тогда образом получать случайный товар для магазина, случайный совет пользователю?
Не совсем про кверисеты, но как кеширование для меня работает: github.com/smn/django-dirtyfields
Началось все тут: stackoverflow.com/questions/110803/dirty-fields-in-django
Автор сам Armin Ronacher :)

class Cacheable(object):
    def cleanup(self):
        cache.delete(':'.join([self.__class__.__name__, self.id]))

class AwesomeUser(models.Model, DirtyFieldsMixin, Cacheable):
    name = models.CharField()
    surname = models.CharField()
    awesomeness = models.BigIntegerField()

    def do_stuff(self):
        # Does some awesome stuff
        return 

    def save(self, *args, **kwargs):
        # Processing
        self.do_stuff()

        # Gets modified fields
        is_dirty = set(self.get_dirty_fields().keys()) \
                    & set(['awesomeness', 'name'])

        super(AwesomeUser, self).save(*args, **kwargs)
        
        # If got dirty
        if is_dirty:
            self.cleanup()
            # do other stuff


Можно просто if self.is_dirty() — так можно узнать были ли вообще какие-либо изменения. В моем примере проверяется определенные поля.
DirtyFields — вообще обалденная штука. Можно не сохранять модель, если нет на то причины или делать проверку до сохранения.
Как именовать ключи?
Инвалидация
как известно, в CS есть только две трудные вещи. :)

вероятно, здесь стоит упомянуть ещё одну стратегию — generational cache strategy (прочитать можно, например, тут www.regexprn.com/2011/06/web-application-caching-strategies_05.html), которая позволяет обходиться без явной инвалидации, благодаря использованию динамических ключей.
Так инвалидация будет удобней, но станет более «жадной», о чем и сам автор пишет.

For example if you update a post in a particular category, this strategy will expire all the keys for all the categories.


Чаще всего это нежелательно. Хотя, можно группировать ключи более «гранулярно». Впервые я услышал о подобном подходе к организации ключей в этой прекрасной презентации.
Sign up to leave a comment.

Articles