[英]Slow deserialization when fetching low level datastore Entity objects from Memcache
事實證明,檢索存儲內存緩存的低級數據存儲實體非常緩慢。 由於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中的代碼已更新,部署的示例應用程序也有最新代碼,因此可以隨意在此處運行此測試並查看結果。
也許我挑選你的措辭,但所有更高級別的API(JDO,JPA和Ofy)都使用低級API,因此所有實體都是LL API實體。 因此,您注意到“Objectify將實體緩存為低級數據存儲區實體類型”,但是並非所有更高級別的數據存儲區API都這樣做(假設它們已被指示使用此類緩存)? 所以我不認為這與你有任何關系。
繼續前進,你的第三次測試比其他測試需要更長的時間似乎很自然 - 實體類型相對於簡單的String甚至Map類型增加了相當大的開銷。 我有點驚訝,它需要更長的時間,但退后一步,你獲取1000個實體,所以每個實體仍然<1毫秒。
我想你應該再增加一個測試。 有一個java API可以獲取實例內存的大小(無法記住它)。 確定測試中使用的實體的內存大小,然后更改字符串測試以使用相同大小的對象。 這樣我們可以隔離這是否與Entity類型本身有關,或者僅僅是第三次測試中緩存的對象大小相當大的結果。
更新以響應新的測試結果......有趣。 這似乎證實了你的理論,即由memcache代碼完成的序列化導致了減速。 這很奇怪 - 但是memcache不會簡單地以與你正在做的非常類似的方式序列化對象嗎?
也許這篇文章有助於:
AppEngine數據存儲對象的手動序列化/反序列化
用於獲取Entity對象的memcache接口是:
java.lang.Object get(java.lang.Object key)
因此,它不是采用可預測的方式,而是按照自己的方式序列化,它可能是使用內省。 這可以解釋為什么'EntityPreSerializedBenchmark'比'EntityBenchmark'快得多。
結果是appengine sdk中的一個bug。 他們知道這個問題並且大概是在修理。
序列化性能的這種回歸在App Engine 1.9.5 SDK中得到了修復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.