Wir bauen gerade einen kleinen und einfachen zentralen HTTP-Service auf, der "externe Identitäten" (wie eine Facebook-ID) einer "internen (uu) ID" zuordnet, die in all unseren Services einzigartig ist und die Analyse unterstützt.Welche Antwortzeiten können von GAE/NDB erwartet werden?
Der erste Prototyp in "unserem Stapel" (Kolben + Postgresql) wurde innerhalb eines Tages erstellt. Da wir jedoch möchten, dass der Service (fast) nie fehlschlägt und automatisch skaliert, haben wir uns für Google App Engine entschieden.
Nach einer Woche & & versucht Lesen dieser Frage Benchmarking ergibt:
Welche Reaktionszeiten gelten als "normal" auf App Engine (mit NDB)?
Wir bekommen Reaktionszeiten, die konsequent über 500 ms im Durchschnitt und deutlich über 1 s im 90percentile sind.
Ich habe unten eine abgespeckte Version unseres Codes beigefügt, in der Hoffnung, dass jemand auf den offensichtlichen Fehler hinweisen kann. Wir mögen das Autoscaling und den verteilten Speicher wirklich, aber wir können uns nicht vorstellen, dass 500ms wirklich die erwartete Leistung in unserem Fall ist. Der sql-basierte Prototyp reagierte viel schneller (konsistent), gehostet auf einem einzelnen Heroku-Dyno mit dem kostenlosen, cache-losen Postgresql (sogar mit einem ORM).
Wir haben sowohl synchrone als auch asynchrone Varianten des folgenden Codes ausprobiert und das Profil von appstats betrachtet. Es sind immer RPC-Aufrufe (Memcache und Datenspeicher), die sehr lange dauern (50ms-100ms), verschlimmert durch die Tatsache, dass es immer mehrere Aufrufe gibt (zB. Mc.get() + ds.get() + ds.set () auf einem schreiben). Wir haben auch versucht, so viel wie möglich auf die Aufgabenwarteschlange zu verschieben, ohne merkliche Gewinne.
import json
import uuid
from google.appengine.ext import ndb
import webapp2
from webapp2_extras.routes import RedirectRoute
def _parse_request(request):
if request.content_type == 'application/json':
try:
body_json = json.loads(request.body)
provider_name = body_json.get('provider_name', None)
provider_user_id = body_json.get('provider_user_id', None)
except ValueError:
return webapp2.abort(400, detail='invalid json')
else:
provider_name = request.params.get('provider_name', None)
provider_user_id = request.params.get('provider_user_id', None)
return provider_name, provider_user_id
class Provider(ndb.Model):
name = ndb.StringProperty(required=True)
class Identity(ndb.Model):
user = ndb.KeyProperty(kind='GlobalUser')
class GlobalUser(ndb.Model):
uuid = ndb.StringProperty(required=True)
@property
def identities(self):
return Identity.query(Identity.user==self.key).fetch()
class ResolveHandler(webapp2.RequestHandler):
@ndb.toplevel
def post(self):
provider_name, provider_user_id = _parse_request(self.request)
if not provider_name or not provider_user_id:
return self.abort(400, detail='missing provider_name and/or provider_user_id')
identity = ndb.Key(Provider, provider_name, Identity, provider_user_id).get()
if identity:
user_uuid = identity.user.id()
else:
user_uuid = uuid.uuid4().hex
GlobalUser(
id=user_uuid,
uuid=user_uuid
).put_async()
Identity(
parent=ndb.Key(Provider, provider_name),
id=provider_user_id,
user=ndb.Key(GlobalUser, user_uuid)
).put_async()
return webapp2.Response(
status='200 OK',
content_type='application/json',
body = json.dumps({
'provider_name' : provider_name,
'provider_user_id' : provider_user_id,
'uuid' : user_uuid
})
)
app = webapp2.WSGIApplication([
RedirectRoute('/v1/resolve', ResolveHandler, 'resolve', strict_slash=True)
], debug=False)
Der Vollständigkeit halber die (fast Standard) app.yaml
application: GAE_APP_IDENTIFIER
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: .*
script: main.app
libraries:
- name: webapp2
version: 2.5.2
- name: webob
version: 1.2.3
inbound_services:
- warmup
Yepp, Sie haben recht über die Leistung von dev_appserver (sqlite auf ssd ...), so testen wir auf Produktion (bezahlte Konto sogar). Bei den Iterationen halten wir die Tests in der Regel für ca. 5 Minuten. Wir versuchen auch sicherzustellen, dass jeder Lauf eine vergleichbare Anzahl an Treffern/Fehlschlägen aufweist (durch Leeren des Datenspeichers/Memcache zwischen Läufen oder durch Herumspielen mit dem Bereich, in dem sich "provider_user_id" befindet). – selkie
Ein Hinweis: Wenn Sie einen großen Benchmark betreiben, müssen Sie Ihren Traffic schrittweise erhöhen (sagen wir 5-10 Minuten) und ihn dann für eine Weile (weitere 5-10 Minuten) unterstützen, um realistische Effekte zu messen. App Engine startet die erforderlichen Instanzen nicht sofort, wenn die Auslastung von 0 auf 100 wechselt. Es gibt einen "Gouverneur" bei diesem Prozess, um Instabilitäten zu vermeiden. –
Ich habe gerade gelesen über HRDs "ein Schreiben pro Sekunde pro Entitätsgruppe" Verhalten. Würde er im obigen Code nicht unsere Probleme erklären? Es gibt nur eine Handvoll Anbieter (hauptsächlich Facebook), und _Identity_ hat _Provider_ als Eltern, was sie zu einer _entity group_ macht? – selkie