2014-03-26 4 views
5

Es stellt sich heraus, dass das Abrufen von Datenspeichereinheiten auf niedriger Ebene, in denen Memcache gespeichert ist, äußerst langsam ist. Da Objekte als Entity-Typ des Datenspeichers der unteren Ebene objektiviert werden, führt dies zu einer schlechten Leistung beim Abrufen vieler Entitäten aus Memcache mithilfe von "objectify".Langsame Deserialisierung beim Abrufen von Datenobjekten auf niedriger Ebene Entitätsobjekte aus Memcache

Die eigentliche Frage ist, warum es langsam ist, den Entity-Typ aus Memcache zu deserialisieren? Ich habe ein Beispielprojekt zusammengestellt, um die Unterschiede beim Abrufen von Entitäten aus Memcache gegenüber einfachen Strings oder einer einfachen Map zu demonstrieren.

Hier ist der Code:

https://github.com/aleemstreak/perftest oder die entsprechende Datei: https://github.com/aleemstreak/perftest/blob/master/src/com/rewardly/perftest/PerftestServlet.java

Auch ich entfaltet es, so dass Sie, wie groß ein Unterschied sehen kann dies in der Produktion ist: aleemsandbox.appspot.com/perftest. Es ist ein naives Profiler, aber es zeigt eine enorme Ungleichheit in der Leistung. Aktualisieren Sie die Seite einige Male, um den Unterschied zu sehen. Hier einige Beispiel-Ausgabe:

Storing String Data Test 
------------------------- 
generateData: 0ms 
storeData: 10ms 
fetchData: 9ms 


Storing Map Data Test 
------------------------- 
generateData: 0ms 
storeData: 21ms 
fetchData: 92ms 


Storing Entity Data Test 
------------------------- 
generateData: 69ms 
storeData: 24ms 
fetchData: 792ms 

Der erste Abschnitt zeigt die Zeit, die 1000 Strings in memcache zu speichern nimmt und dann holen rechts zurück. Das nächste Beispiel macht dasselbe für 1000 Map-Objekte und schließlich speichert das letzte Beispiel 1000 Low-Level-Entity-Typen. Sie können die enorme Zeit erhöhen, um Entity-Typen abzurufen.

Irgendwelche Ideen, warum Entitäten langsam aus Memcache deserialisieren könnten?

UPDATE 1

einen Vorschlag in einer der Antworten Folgen, ich protokolliert auch die kumulative Größe der Objekte, um sie in memcache und die Ergebnisse kein Ausdruck gespeichert werden. Ich habe auch einen anderen Testfall hinzugefügt - anstatt eine Entity direkt zu speichern, serialisiere ich die Entity zuerst auf ein Byte [] und speichere sie dann in Memcache. Hier sind die Ergebnisse:

StringBenchmark 
---------------- 
Average Fetch Time: 40.16ms 
Fetch Size: 24.41KB 


MapBenchmark 
---------------- 
Average Fetch Time: 27.36ms 
Fetch Size: 102.54KB 


EntityBenchmark 
---------------- 
Average Fetch Time: 1029.88ms 
Fetch Size: 463.87KB 


EntityPreSerializedBenchmark 
---------------- 
Average Fetch Time: 218.82ms 
Fetch Size: 490.23KB 

Was hier interessant ist, sind die letzten beiden Ergebnisse. Obwohl sie ungefähr die gleiche Größe haben, dauert es etwa 1/5, um das Byte [] manuell abzurufen und zu deserialisieren.

Der Code im Github Repo wurde aktualisiert und die bereitgestellte Beispiel-App enthält auch den neuesten Code. Sie können diesen Test also dort ausführen und die Ergebnisse sehen.

+0

Eine Sache, die ich vergessen habe zu erwähnen, ist, dass dieser Code auch mit appstats profiliert wird und alle Abrufe von Memcache <10ms sind. Das bedeutet, dass die restliche Zeit damit verbracht wird, die Objekte zu deserialisieren. – aloo

+0

Können Sie für EntityPreSerializedBenchmark auch angeben, wie lange die Serialisierung dauert und wie viel Zeit noch benötigt wird? – Nick

+0

Entschuldigung durch Abrufzeit meinst du die Abrufzeit zu aktuellem Memcache wie von Appstats aufgelistet? – aloo

Antwort

1

Vielleicht bin ich nick-Picking Ihre Formulierung, aber alle der höheren Ebene API (JDO, JPA und Ofy) verwenden die Low-Level-API, so dass alle Entitäten sind wirklich LL API-Entitäten. Sie stellen also fest, dass "Objectify Caches Entitäten als Entity-Typ des Datenspeichers niedriger Ebene" verwendet, aber würden nicht alle Datenspeicher-APIs der höheren Ebene dasselbe tun (vorausgesetzt, sie wurden angewiesen, ein solches Caching zu verwenden)? Also ich denke nicht, dass das irgendwas mit oy zu tun hat.

Weiter geht es natürlich, dass Ihr 3. Test dauert viel länger als die anderen - der Entity-Typ fügt erhebliche Overhead relativ zu den einfachen String und sogar Map-Typen. Ich bin ein wenig überrascht, dass es so viel länger dauert, aber einen Schritt zurück, Sie holen 1000 Einheiten, so dass immer noch < 1 ms pro Einheit ist.

Ich denke, Sie sollten einen weiteren Test hinzufügen. Es gibt eine Java-API, um die Größe im Speicher einer Instanz zu erhalten (ich kann mich nicht daran erinnern). Ermitteln Sie die Speichergröße der Entitäten, die Sie in Ihrem Test verwenden, und ändern Sie dann den Stringtest, um ein Objekt der gleichen Größe zu verwenden.Auf diese Weise können wir isolieren, ob dies etwas mit dem Entity-Typ selbst zu tun hat, oder ist nur ein Ergebnis der beträchtlich größeren Größe der Objekte, die im dritten Test zwischengespeichert werden.


Update als Reaktion auf neue Testergebnisse ... Interessant. Das scheint deine Theorie zu bestätigen, dass die Serialisierung durch den Memcache-Code die Verlangsamung verursacht. Das ist allerdings merkwürdig - würde Memcache das Objekt nicht einfach serialisieren, ähnlich wie das, was Sie tun?

Vielleicht diesen Beitrag hilft:
manual serialization/deserialization of AppEngine Datastore objects


Die memcache Schnittstelle, die Sie zum Abrufen von Entity-Objekte verwenden ist:

java.lang.Object get(java.lang.Object key) 

https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/memcache/MemcacheService#get(java.lang.Object)

So ist es kein seralizable nehmen , also lieber serialisieren als du es bist, wird es wahrscheinlich benutzen Introspektion. Das würde erklären, warum "EntityPreSerializedBenchmark" viel schneller ist als "EntityBenchmark".

+0

Eigentlich was ich meinte war, dass Ofy die Low-Level-Entity-Klasse in MEMCACHE speichert, wenn es Caching aktiviert hat. Ich glaube nicht, dass JDO/JPA automatisch in Memcache zwischenspeichern kann, also denke ich nicht, dass es ein Problem für diese Frameworks ist. – aloo

+0

Trotzdem - das Problem bleibt bestehen. Ich habe meine Frage aktualisiert, um Ihre Rückmeldung zu berücksichtigen, und habe versucht, die Entity-Objekte in Byte [] zu serialisieren, bevor Sie sie in Memcache setzen. Sie werden in Entity-Objekte aus Byte [] nach dem Holen deserialisiert Benchmark-Zeit (Ich aktualisierte den Benchmark-Code und implementierte ihn für ppl, um damit zu spielen) – aloo

+0

Update Q, um auf neue Informationen zu antworten – Tom

1

Es erweist sich als ein Fehler in der Appengine SDK. Sie sind sich des Problems bewusst und beheben es vermutlich.

0

Diese Regression in Serialisierungsleistung wurde in App Engine 1.9.5 SDK behoben.

Verwandte Themen