事实证明,检索存储内存缓存的低级数据存储实体非常慢。由于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中的代码已更新,已部署的示例应用程序也有最新代码,因此可以随意在此处运行此测试并查看结果。
答案 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)
所以它不是一个可以集中化的,所以不是那么序列化你的方式,它可能是使用内省。这可以解释为什么'EntityPreSerializedBenchmark'比'EntityBenchmark'快得多。
答案 1 :(得分:1)
结果是appengine sdk中的一个错误。他们大概都知道这个问题和修复。
答案 2 :(得分:0)
序列化性能的这种回归在App Engine 1.9.5 SDK中得到了修复。