Memcache является высокопроизводительным распределенным кэшем в оперативной памяти, который позволяет строить динамичные web-приложения и снижать нагрузку на хранилище. В общем случае Memcache используется для кэширования результатов запросов из хранилища или сгенерированного вашим приложением кода HTML.
Алгоритм использования сервиса Memcache простой:
Код, показывающий, как происходит типичный запрос к кэшу:
def get_data():
data = memcache.get("key")
if data is not None:
return data
else:
data = self.query_for_data()
memcache.add("key", data, 60)
return data
Приложение 'Гостевая книга', рассмотренное в Руководстве для начинающих получает данные из хранилища при каждом запросе пользователя. Мы можем изменить его таким образом, чтобы оно выполняло опрос кэша перед выполнением любого запроса к хранилищу.
Сначала мы должны импортировать модуль memcache и создать новый метод, который будет выполнять запрос к кэшу до обращения к хранилищу.
from google.appengine.api import memcache
def get_greetings(self):
"""get_greetings()
Проверка кэша на предмет наличия объекта greetings
Если он не обнаружен, то вызывается метод render_greetings и возвращаемый результат помещается в кэш
Возвращает:
Строку с HTML кодом, содержащую сообщения.
"""
greetings = memcache.get("greetings")
if greetings is not None:
return greetings
else:
greetings = self.render_greetings()
if not memcache.add("greetings", greetings, 10):
logging.error("Memcache set failed.")
return greetings
Теперь необходимо разделить моменты, когда происходит запрос данных и создание отображения страницы. Когда в кэше не будет содержаться требуемых данных, мы вызовем этот метод и произведем запрос к хранилищу для получения сообщений, которые требуется отобразить пользователю.
def render_greetings(self):
"""render_greetings()
Выполняет запрос пользовательских сообщений, добавляет их к переменной
results и создает на базе этого HTML.
Возвращает:
Строку с HTML кодом, содержащую сообщения
"""
results = db.GqlQuery("SELECT * "
"FROM Greeting "
"ORDER BY date DESC").fetch(10)
output = StringIO.StringIO()
for result in results:
if result.author:
output.write("<b>%s</b> wrote:" % result.author.nickname())
else:
output.write("An anonymous person wrote:")
output.write("<blockquote>%s</blockquote>" %
cgi.escape(result.content))
return output.getvalue()
В завершении необходимо будет обновить обработчик MainPage для вызова нового метода get_greetings() и отображения статистики по результатам работы с кэшем: сколько раз мы получили кэшированные данные.
import cgi
import datetime
import wsgiref.handlers
import logging
import StringIO
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.api import memcache
logging.getLogger().setLevel(logging.DEBUG)
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write("<html><body>")
greetings = self.get_greetings()
stats = memcache.get_stats()
self.response.out.write("<b>Cache Hits:%s</b><br>" % stats['hits'])
self.response.out.write("<b>Cache Misses:%s</b><br><br>" %
stats['misses'])
self.response.out.write(greetings)
self.response.out.write("""
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
</body>
</html>""")
def get_greetings(self):
"""
get_greetings()
Проверка кэша на предмет наличия объекта greetings
Если он не обнаружен, то вызывается метод render_greetings и возвращаемый результат помещается в кэш
Возвращает:
Строку с HTML кодом, содержащую сообщения.
"""
greetings = memcache.get("greetings")
if greetings is not None:
return greetings
else:
greetings = self.render_greetings()
if not memcache.add("greetings", greetings, 10):
logging.error("Memcache set failed.")
return greetings
def render_greetings(self):
"""
render_greetings()
Выполняет запрос пользовательских сообщений, добавляет их к переменной
results и создает на базе этого HTML.
Возвращает:
Строку с HTML кодом, содержащую сообщения
"""
results = db.GqlQuery("SELECT * "
"FROM Greeting "
"ORDER BY date DESC").fetch(10)
output = StringIO.StringIO()
for result in results:
if result.author:
output.write("<b>%s</b> wrote:" % result.author.nickname())
else:
output.write("An anonymous person wrote:")
output.write("<blockquote>%s</blockquote>" %
cgi.escape(result.content))
return output.getvalue()
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/')
application = webapp.WSGIApplication([
('/', MainPage),
('/sign', Guestbook)
], debug=True)
def main():
wsgiref.handlers.CGIHandler().run(application)
if __name__ == '__main__':
main()