从Memcache中获取低级别数据存储区实体对象时,反向串行化缓慢

alo*_*loo 5 java google-app-engine entity objectify deserialization

事实证明,检索存储内存缓存的低级数据存储实体非常缓慢.由于objectify将实体缓存为低级数据存储区实体类型,因此当使用objectify从memcache中获取许多实体时,这会导致性能不佳.

真正的问题是为什么从memcache反序列化实体类型的速度慢?我整理了一个示例项目来演示从memcache与普通字符串或简单Map中检索实体的差异.

这是代码:

https://github.com/aleemstreak/perftest或相关文件:https://github.com/aleemstreak/perftest/blob/master/src/com/rewardly/perftest/PerftestServlet.java

此外,我部署了它,因此您可以看到它在生产中有多大差异:aleemsandbox.appspot.com/perftest.它是一个天真的探测器,但它确实表现出巨大的性能差异.刷新页面几次以查看差异.这是一些示例输出:

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
Run Code Online (Sandbox Code Playgroud)

第一部分显示了在memcache中存储1000个字符串然后立即获取它所需的时间.下一个示例对1000个Map对象执行相同操作,最后一个示例存储并检索1000个低级实体类型.您可以看到检索实体类型的时间增加.

任何想法为什么实体可能很慢从memcache反序列化?

更新1

根据其中一个答案中的建议,我还记录了存储在memcache中的对象的累积大小,结果没有打印出来.我还添加了另一个测试用例 - 而不是直接存储实体,而是首先将Entity序列化为byte [],然后将其存储在memcache中.结果如下:

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
Run Code Online (Sandbox Code Playgroud)

这里有趣的是最后两个结果.尽管它们的大小大致相同,但手动获取和反序列化byte []需要大约1/5的时间.

github repo中的代码已更新,部署的示例应用程序也有最新代码,因此可以随意在此处运行此测试并查看结果.

Tom*_*Tom 1

也许我在挑剔你的措辞,但所有更高级别的 API(JDO、JPA 和 Ofy)都使用低级别 API,因此所有实体实际上都是 LL API 实体。因此,您注意到“Objectify 将实体缓存为低级数据存储实体类型”,但所有高级数据存储 API 是否都会执行相同的操作(假设它们已被指示使用此类缓存)?所以我认为这与ofy没有任何关系。

继续,您的第三个测试比其他测试花费的时间似乎很自然 - 实体类型相对于简单的字符串甚至映射类型增加了相当大的开销。我有点惊讶它需要这么长的时间,但退一步来说,您正在获取 1000 个实体,因此每个实体仍然 < 1 毫秒。

我认为你应该再添加 1 个测试。有一个java API可以获取实例的内存大小(一时记不住)。确定您在测试中使用的实体的内存大小,然后更改字符串测试以使用相同大小的对象。这样我们就可以隔离这是否与实体类型本身有关,或者只是第三次测试中缓存的对象大小相当大的结果。


更新以响应新的测试结果......有趣。这似乎确实证实了您的理论,即内存缓存代码完成的序列化导致了速度减慢。但这很奇怪 - memcache 不会以与您正在做的非常相似的方式简单地序列化对象吗?

也许这篇文章有帮助:
AppEngine Datastore 对象的手动序列化/反序列化


您用于获取实体对象的 memcache 接口是:

java.lang.Object get(java.lang.Object key)
Run Code Online (Sandbox Code Playgroud)

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

所以它没有采用可序列化,所以它可能使用内省,而不是像你这样序列化。这可以解释为什么“EntityPreSerializedBenchmark”比“EntityBenchmark”快得多。