lua中keyvalue_40行中的持久性KeyValue Server和一个可悲的事实
lua中keyvalue
再次出現。..彼得斯撰寫了有關Unsafe用法的書面概述 ,我將簡要介紹一下Java中的低級技術如何通過啟用更高級別的抽象或允許Java性能級別來節省開發工作可能很多人都不知道。
我的主要觀點是表明,將對象轉換為字節,反之亦然是一個重要的基礎,實際上影響了任何現代Java應用程序。
硬件喜歡處理字節流,而不是處理通過指針連接的對象圖,因為“所有內存都是磁帶” (如果我沒記錯的話,M.Thompson ..)。
因此,許多基本技術很難與原始Java堆對象一起使用:
- 內存映射文件 –一種出色而簡單的技術,可安全,快速,輕松地保存應用程序數據。
- 網絡通信基于發送字節數據包
- 進程間通訊 (共享內存)
- 當今服務器的大主內存 (64GB至256GB)。 (GC問題)
- CPU高速緩存最適合在內存中以連續字節流形式存儲的數據
因此在大多數情況下使用Unsafe類有助于將Java對象圖轉換為連續的內存區域,反之亦然
- [性能增強] 對象序列化或
- 包裝器類,以簡化對連續內存區域中存儲的數據的訪問。
(本文的代碼和示例可在此處找到)
基于序列化的堆外
考慮一個零售Web應用程序,其中可能有數百萬個注冊用戶。 實際上,我們不希望在關系數據庫中表示數據,因為所有必要的操作是在用戶登錄后快速檢索與用戶相關的數據。此外,我們還想快速遍歷社交圖。
讓我們看一個簡單的用戶類,其中包含一些屬性和構成社交圖的“朋友”列表。
將其存儲在堆上的最簡單方法是簡單的大型HashMap。
或者,可以使用堆外映射來存儲大量數據。 堆外映射將其鍵和值存儲在本機堆中,因此垃圾回收不需要跟蹤此內存。 此外,可以告知本機堆自動與磁盤(內存映射文件)同步。 甚至在您的應用程序崩潰時也可以使用,因為操作系統管理回寫更改的內存區域。
有一些帶有各種功能集的開源堆外地圖實現(例如ChronicleMap ),在本示例中,我將使用一種簡單且簡單的實現,該實現具有快速迭代(可選的全掃描搜索)和易用性的特點。
序列化用于存儲對象,反序列化用于將它們再次拉到Java堆。 令人愉快的是,我已經編寫了(afaik)這個星球上最快的,完全兼容JDK的對象序列化程序 ,因此我將利用它。
完成:
- 通過內存映射文件實現持久性(映射將在創建時重新加載)。
- Java Heap仍然為空,無法使用完全GC <100ms的實時應用程序進行處理。
- 整體內存消耗明顯減少。 序列化的用戶記錄約為60個字節,因此理論上3億條記錄可容納180GB的服務器內存。 無需引發大數據標志并在AWS上運行4096個hadoop節點。
比較常規的內存中的Java HashMap和基于快速序列化的,擁有1500萬條用戶記錄的持久性堆外映射,將顯示以下結果(在3Ghz較舊的XEON 2×6上):
| 消耗的Java堆(MB) | 完整GC | 本機堆(MB) | 每秒鐘獲取/輸入操作 | 所需的VM大小(MB) | |
| 哈希圖 | 6.865,00 | 26,039 | 0 | 3.800.000,00 | 12.000,00 |
| OffheapMap(基于序列化) | 63,00 | 0,026 | 3.050 | 750.000,00 | 500,00 |
[ 測試源/博客項目 ]注意:您至少需要16GB的RAM才能執行它們。
如人們所見,無論如何,即使進行快速序列化,訪問性能也要付出沉重的代價(約5倍):與其他持久性替代方案相比,其性能仍然更好(每個“ get”操作“ put()”為1-3微秒)非常相似)。
使用JDK序列化的速度至少要慢5到10倍(下面直接比較),因此使這種方法無用。
與更高的抽象水平相比,交易性能提高了:“服務器化我”
單個服務器將無法為成千上萬的用戶提供服務,因此我們需要以某種方式在進程之間甚至跨機器共享數據,甚至更好。
使用快速實現,可以為網絡消息傳遞慷慨地使用(快速)序列化。 再說一次:如果運行速度慢5到10倍,那將是不可行的。 替代方法需要更多數量級的工作才能獲得相似的結果。
通過使用Actor實現(異步ftw!)包裝持久性堆外哈希映射,一些代碼行構成了具有基于TCP和HTTP接口的持久性KeyValue服務器(使用kontraktor actors )。 當然,如果稍后決定,仍可以在過程中使用Actor。
現在,這是一個微服務。 鑒于它沒有進行任何優化的嘗試并且是單線程的 ,因此其速度相當快[與上述XEON機器相同]:
- 每秒280_000次成功的遠程查找
- 如果失敗查找,則為800_000(找不到密鑰)
- 基于序列化的TCP接口(1個內襯)
- REST-of-us(1個班次)的嚴格Web服務。
[ 來源:KVServer,KVClient ]注意:您至少需要16GB的RAM才能執行測試。
現實世界中的實現可能希望通過將接收到的序列化對象byte []直接放入映射中而不是對其進行兩次編碼(一次編碼/解碼以通過有線傳輸,然后解碼/編碼以進行映射映射)來提高性能。
“ RestActorServer.Publish(..);” 是一個襯墊,除了原始tcp外,還可以將KVActor公開為Web服務:
使用flyweight包裝器/結構獲得類似C的性能
通過序列化,常規Java對象將轉換為字節序列。 一個可以做相反的事情:創建包裝器類,該包裝器類從基礎字節數組或本機內存地址的固定或計算位置讀取數據。 (例如,請參閱此博客文章 )。
通過移動基本指針,僅通過移動包裝器的偏移量就可以訪問不同的記錄。 復制這樣的“打包對象”歸結為內存副本。 此外,以這種方式編寫分配免費的代碼非常容易。 缺點是,與常規Java對象相比,讀/寫單個字段會降低性能。 這可以通過使用Unsafe類來彌補。
如引用的博客文章所示,“ flyweight”包裝器類可以手動實現,但是隨著代碼的增長,這種情況變得難以維護。
快速序列化提供了一個副產品“結構仿真”,支持在運行時從常規Java類創建flyweight包裝器類。 這樣可以在很大程度上避免應用程序代碼中的低級字節擺弄。
常規Java類如何映射到平面內存(fst-struct):
當然,那里有更簡單的工具來幫助減少編碼的手動編程(例如Slab ),這可能更適合許多情況并且使用較少的“魔術”。
使用不同的方法(悲傷事實傳入)可以期待什么樣的性能?
讓我們采用以下由價格更新和表示可交易工具(例如股票)的嵌入式結構組成的結構類,并使用各種方法對其進行編碼:
代碼中的“結構”
純編碼性能:
| 結構 | fast-Ser(無共享裁判) | 快速服務 | JDK Ser(未共享) | JDK系列 |
| 26.315.000,00 | 7.757.000,00 | 5.102.000,00 | 649.000,00 | 644.000,00 |
具有消息傳遞吞吐量的實際測試:
為了獲得實際應用中差異的基本估計,我進行了一個實驗,即當通過可靠的UDP消息以高速率發送和接收消息時,如何執行不同的編碼:
考試:
發送方盡可能快地對消息進行編碼,然后使用可靠的多播將其發布,訂戶接收并對其進行解碼。
| 結構 | fast-Ser(無共享裁判) | 快速服務 | JDK Ser(未共享) | JDK系列 |
| 6.644.107,00 | 4.385.118,00 | 3.615.584,00 | 81.582,00 | 79.073,00 |
(在I7 / Win8,XEON / Linux上進行的測試得分略高,結構的msg大小約為70字節,序列化約為60字節)。
與最低速度相比,最慢速度:82。測試突出顯示了微基準測試未涵蓋的問題:編碼和解碼應執行類似的操作,因為實際吞吐量由Min(編碼性能,解碼性能)確定。 出于未知的原因,JDK序列化設法以每秒500_000次的速度對測試的消息進行編碼,解碼性能僅為每秒80_000次,因此在測試中,接收器Swift下降:
”
…
*****接收速率統計:每秒80351 *********
*****接收速率統計:每秒78769 **********
SUB-ud4q已被服務1的PUB-9afs丟棄
致命的,無法跟上。 退出
“
(在此處創建背壓可能不是解決此問題的正確方法!)
結論
- 快速序列化允許在分布式應用程序中實現某種程度的抽象,如果序列化實現是
- 太慢了
–不完整。 例如無法處理任何可序列化的對象圖 –需要手動編碼/修改。 (會對演員消息類型,期貨,孢子,維護噩夢施加許多限制) - 諸如“不安全”之類的低級實用程序可啟用不同的數據表示形式,從而為特定的工作負載提供超常的吞吐量或有保證的延遲邊界(無分配主路徑)。 使用JDK的公共工具集不可能實現這些目標。
- 在分布式系統中,通信性能至關重要。 查看上面的數字,刪除不安全并不是最大的麻煩。.JSON或XML不能解決此問題。
- 盡管HotSpot VM已達到非凡的性能和可靠性水平,但JDK的某些部分卻浪費了CPU,就像沒有明天一樣。 考慮到我們生活在分布式應用程序和數據時代,應該很容易實現(而不是手動編碼)在線傳輸內容,并且應盡可能快。
附錄:有限的延遲
快速的Ping Pong RTT延遲基準測試表明Java可以輕松地與C解決方案競爭,只要主要路徑沒有分配,并且采用了上述技術即可:
[學分:圖表和使用HdrHistogram完成的測量]
這是一個“實驗”,而不是一個基準測試(因此,請不要閱讀:“ 證明:Java比C更快” ),它表明低級Java至少可以在此低級領域與C競爭。
當然,它不是完全慣用的 Java代碼,但是與JNI或純C(++)解決方案相比,它仍然更易于處理,移植和維護。 低延遲的C(++)代碼也不是慣用的!
翻譯自: https://www.javacodegeeks.com/2015/01/a-persistent-keyvalue-server-in-40-lines-and-a-sad-fact.html
lua中keyvalue
總結
以上是生活随笔為你收集整理的lua中keyvalue_40行中的持久性KeyValue Server和一个可悲的事实的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos攻击事件(ddos防御典型事件)
- 下一篇: java iterable_太糟糕了,J