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

时间:2014-03-26 16:12:34

标签: java google-app-engine entity deserialization objectify

事实证明,检索存储内存缓存的低级数据存储实体非常慢。由于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

第一部分显示了在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

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

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

3 个答案:

答案 0 :(得分:1)

也许我挑选你的措辞,但所有更高级别的API(JDO,JPA和Ofy)都使用低级API,因此所有实体都是LL API实体。因此,您注意到“Objectify将实体缓存为低级数据存储区实体类型”,但是并非所有更高级别的数据存储区API都这样做(假设它们已被指示使用此类缓存)?所以我认为这与你没有任何关系。

接下来,你的第三个测试比其他测试需要更长的时间似乎很自然 - 实体类型相对于简单的String甚至Map类型增加了相当大的开销。我有点惊讶,它需要更长的时间,但退后一步,你正在获取1000个实体,所以它仍然是<每个实体1毫秒。

我认为你应该再增加1个测试。有一个java API可以获取实例内存的大小(无法记住它)。确定测试中使用的实体的内存大小,然后更改字符串测试以使用相同大小的对象。这样我们就可以确定这与Entity类型本身有什么关系,或者只是第三次测试中缓存的对象大小要大的结果。


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

也许这篇文章有助于:
manual serialization / deserialization of AppEngine Datastore objects


用于获取Entity对象的memcache接口是:

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)

所以它不是一个可以集中化的,所以不是那么序列化你的方式,它可能是使用内省。这可以解释为什么'EntityPreSerializedBenchmark'比'EntityBenchmark'快得多。

答案 1 :(得分:1)

结果是appengine sdk中的一个错误。他们大概都知道这个问题和修复。

答案 2 :(得分:0)

序列化性能的这种回归在App Engine 1.9.5 SDK中得到了修复。