1

Python を使用して Google-App-Engine に Web サイトをデプロイしました。

GAE は「キープアライブ」を保証しないため、ステートレス サーバーを実装しました。

  1. 内部変数が変更されるたびに、それらはすぐに GQL データベースに保存されます。

  2. プロセスが開始されるたびに、すべての内部変数が GQL データベースからロードされます。

めったに例外をスローしないシナリオがあり、それを追跡できませんでした。

  • クライアントが同期 AJAX POST 要求を送信します。

  • サーバーはセッションを作成し、応答で一意のセッション ID を送信します。

  • クライアントは、セッション ID を引数として同期 AJAX GET 要求を送信します。

  • サーバーは応答でテキスト メッセージを送信します。

クライアントのリクエストは同期的であるため、シーケンス全体も同期的です。

私のサーバー内の関連するマッピングは次のとおりです。

from webapp2 import WSGIApplication
from Handler import MyRequestHandler

app = WSGIApplication([
    ('/request1'    ,MyRequestHandler), # post request
    ('/request2(.*)',MyRequestHandler), # get request
])

私のサーバー内の関連するリクエスト処理は次のとおりです。

from webapp2 import RequestHandler
from Server  import MyServer

myServer = MyServer()

class MyRequestHandler(RequestHandler):
    def post(self):
        try:
            if self.request.path.startswith('/request1'):
                sessionId = myServer.GetNewSessionId()
                self.SendContent('text/plain',sessionId)
        except Exception,error:
            self.SendError(error)
    def get(self,sessionId):
        try:
            if self.request.path.startswith('/request2'):
                textMessage = myServer.GetMsg(sessionId)
                self.SendContent('text/plain',textMessage)
        except Exception,error:
            self.SendError(error)
    def SendContent(self,contentType,contentData):
        self.response.set_status(200)
        self.response.headers['content-type'] = contentType
        self.response.headers['cache-control'] = 'no-cache'
        self.response.write(contentData)
    def SendError(self,error):
        self.response.set_status(500)
        self.response.write(error.message)

私のサーバーの内部実装は次のとおりです。

class MyServer():
    def __init__(self):
        self.sessions = SessionsTable.ReadSessions()
    def GetNewSessionId(self):
        while True:
            sessionId = ... # a 16-digit random number
            if SessionsTable.ReserveSession(sessionId):
                self.sessions[sessionId] = ... # a text message
                SessionsTable.WriteSession(self.sessions,sessionId)
                return sessionId
    def GetMsg(self,sessionId):
        return self.sessions[sessionId]

最後に、サーバー内のデータベースのメンテナンスは次のとおりです。

from google.appengine.ext import db

class SessionsTable(db.Model):
    message = db.TextProperty()
    @staticmethod
    def ReadSessions():
        sessions = {}
        for session in SessionsTable.all():
            sessions[session.key().name()] = session.message
        return sessions
    @staticmethod
    @db.transactional
    def ReserveSession(sessionId):
        if not SessionsTable.get_by_key_name(sessionId):
            SessionsTable(key_name=sessionId,message='').put()
            return True
        return False
    @staticmethod
    def WriteSession(sessions,sessionId):
        SessionsTable(key_name=sessionId,message=sessions[sessionId]).put()
    @staticmethod
    def EraseSession(sessionId):
        SessionsTable.get_by_key_name(sessionId).delete()

例外自体はsessions、キーを使用したディクショナリへの不正なアクセスを示していsessionIdます。私の観察によると、この質問の冒頭で説明したクライアント/サーバー シーケンスが、サーバーが比較的長い期間 (数日程度) 「スリープ状態」になった後に開始された場合にのみ発生します。私にはわかりませんが、この問題の原因を突き止める手掛かりが得られるかもしれません。

私の質問:

  1. 私のデザインに目に見える問題はありますか?

  2. GAEで同様の問題を経験した人はいますか?

  3. この問題を理解するのに役立つ明らかな解決策やデバッグ方法を誰かが見ていますか?

ありがとう

4

1 に答える 1

3

すべてのリクエストが同じインスタンスによって処理されると誤って想定しています。これはまったく当てはまりません。GAE は、ほとんどのホスティング環境と同様に、どのサーバー プロセスが要求を処理するかについて保証しません。

実装では、モジュール レベルの変数 を使用していますmyServer。これは、独自のインスタンス変数を持つクラス インスタンスです。ただし、各サーバー プロセスには myServer の独自のインスタンスがあり、それらはプロセス間で共有されません。そのため、1 つの要求で作成された辞書エントリが 2 番目に存在するとは限りません。

インスタンス間でこのデータを永続化する方法を検討する必要があります。実際、それがそもそもデータストアの目的です。オーバーヘッドが気になる場合は、memcache を使用して調査する必要があります。

于 2014-01-22T14:26:59.133 に答える