Python 2.7은 지원이 종료되었으며 2026년 1월 31일에 지원 중단됩니다. 지원 중단 후에는 조직에서 이전에 조직 정책을 사용하여 레거시 런타임의 배포를 다시 사용 설정한 경우에도 Python 2.7 애플리케이션을 배포할 수 없습니다. 기존 Python 2.7 애플리케이션은 지원 중단 날짜 이후에도 계속 실행되고 트래픽을 수신합니다. 지원되는 최신 Python 버전으로 마이그레이션하는 것이 좋습니다.
ndb는 내부적으로 Memcache를 사용하여 쿼리 속도를 높입니다. 그러나 원하는 경우 명시적으로 Memcache 호출을 추가하여 속도 향상을 직접 제어할 수 있습니다.
데이터 캐시하기
다음 예시에서는 Python API를 사용하여 Memcache에서 값을 설정하는 여러 가지 방법을 보여줍니다.
# Add a value if it doesn't exist in the cache# with a cache expiration of 1 hour.memcache.add(key="weather_USA_98105",value="raining",time=3600)# Set several values, overwriting any existing values for these keys.memcache.set_multi({"USA_98115":"cloudy","USA_94105":"foggy","USA_94043":"sunny"},key_prefix="weather_",time=3600)# Atomically increment an integer value.memcache.set(key="counter",value=0)memcache.incr("counter")memcache.incr("counter")memcache.incr("counter")
방명록 애플리케이션은 모든 요청에서 Datastore를 쿼리합니다(ndb를 통해 수행하여 이미 어느 정도의 memcache 속도 향상을 얻음). Datastore 쿼리를 선택하기 전에 명시적으로 memcache를 사용하도록 방명록 애플리케이션을 수정할 수 있습니다.
먼저 Memcache 모듈을 가져와서 쿼리를 실행하기 전에 Memcache를 확인하는 메서드를 만듭니다.
defget_greetings(self,guestbook_name):""" get_greetings() Checks the cache to see if there are cached greetings. If not, call render_greetings and set the cache Args: guestbook_name: Guestbook entity group key (string). Returns: A string of HTML containing greetings. """greetings=memcache.get('{}:greetings'.format(guestbook_name))ifgreetingsisNone:greetings=self.render_greetings(guestbook_name)try:added=memcache.add('{}:greetings'.format(guestbook_name),greetings,10)ifnotadded:logging.error('Memcache set failed.')exceptValueError:logging.error('Memcache set failed - data larger than 1MB')returngreetings
다음으로 페이지의 HTML 생성과 쿼리를 분리합니다. 캐시에 적중하지 않는 경우 이 메서드를 호출하여 Datastore를 쿼리하고 Memcache에 저장할 HTML 문자열을 만듭니다.
defrender_greetings(self,guestbook_name):""" render_greetings() Queries the database for greetings, iterate through the results and create the HTML. Args: guestbook_name: Guestbook entity group key (string). Returns: A string of HTML containing greetings """greetings=ndb.gql('SELECT * ''FROM Greeting ''WHERE ANCESTOR IS :1 ''ORDER BY date DESC LIMIT 10',guestbook_key(guestbook_name))output=cStringIO.StringIO()forgreetingingreetings:ifgreeting.author:output.write('<b>{}</b> wrote:'.format(greeting.author))else:output.write('An anonymous person wrote:')output.write('<blockquote>{}</blockquote>'.format(cgi.escape(greeting.content)))returnoutput.getvalue()
끝으로 MainPage 핸들러를 업데이트하여 get_Contings() 메서드를 호출하고 캐시 적중 및 누락 횟수에 대한 몇 가지 통계를 표시합니다.
importcgiimportcStringIOimportloggingimporturllibfromgoogle.appengine.apiimportmemcachefromgoogle.appengine.apiimportusersfromgoogle.appengine.extimportndbimportwebapp2classGreeting(ndb.Model):"""Models an individual Guestbook entry with author, content, and date."""author=ndb.StringProperty()content=ndb.StringProperty()date=ndb.DateTimeProperty(auto_now_add=True)defguestbook_key(guestbook_name=None):"""Constructs a Datastore key for a Guestbook entity with guestbook_name"""returnndb.Key('Guestbook',guestbook_nameor'default_guestbook')classMainPage(webapp2.RequestHandler):defget(self):self.response.out.write('<html><body>')guestbook_name=self.request.get('guestbook_name')greetings=self.get_greetings(guestbook_name)stats=memcache.get_stats()self.response.write('<b>Cache Hits:{}</b><br>'.format(stats['hits']))self.response.write('<b>Cache Misses:{}</b><br><br>'.format(stats['misses']))self.response.write(greetings)self.response.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> <hr> <form>Guestbook name: <input value="{}" name="guestbook_name">
<input type="submit" value="switch"></form> </body> </html>""".format(urllib.urlencode({'guestbook_name':guestbook_name}),cgi.escape(guestbook_name)))defget_greetings(self,guestbook_name):""" get_greetings() Checks the cache to see if there are cached greetings. If not, call render_greetings and set the cache Args: guestbook_name: Guestbook entity group key (string). Returns: A string of HTML containing greetings. """greetings=memcache.get('{}:greetings'.format(guestbook_name))ifgreetingsisNone:greetings=self.render_greetings(guestbook_name)try:added=memcache.add('{}:greetings'.format(guestbook_name),greetings,10)ifnotadded:logging.error('Memcache set failed.')exceptValueError:logging.error('Memcache set failed - data larger than 1MB')returngreetingsdefrender_greetings(self,guestbook_name):""" render_greetings() Queries the database for greetings, iterate through the results and create the HTML. Args: guestbook_name: Guestbook entity group key (string). Returns: A string of HTML containing greetings """greetings=ndb.gql('SELECT * ''FROM Greeting ''WHERE ANCESTOR IS :1 ''ORDER BY date DESC LIMIT 10',guestbook_key(guestbook_name))output=cStringIO.StringIO()forgreetingingreetings:ifgreeting.author:output.write('<b>{}</b> wrote:'.format(greeting.author))else:output.write('An anonymous person wrote:')output.write('<blockquote>{}</blockquote>'.format(cgi.escape(greeting.content)))returnoutput.getvalue()classGuestbook(webapp2.RequestHandler):defpost(self):# We set the same parent key on the 'Greeting' to ensure each greeting# is in the same entity group. Queries across the single entity group# are strongly consistent. However, the write rate to a single entity# group is limited to ~1/second.guestbook_name=self.request.get('guestbook_name')greeting=Greeting(parent=guestbook_key(guestbook_name))ifusers.get_current_user():greeting.author=users.get_current_user().nickname()greeting.content=self.request.get('content')greeting.put()memcache.delete('{}:greetings'.format(guestbook_name))self.redirect('/?'+urllib.urlencode({'guestbook_name':guestbook_name}))app=webapp2.WSGIApplication([('/',MainPage),('/sign',Guestbook)],debug=True)