sbe 详解_内部简单二进制编码(SBE)
sbe 詳解
SBE是用于金融行業的非??焖俚男蛄谢瘞?#xff0c;在本博客中,我將介紹一些使其快速發展的設計選擇。
序列化的全部目的是對消息進行編碼和解碼,并且有很多可用的選項,例如XML,JSON,Protobufer,Thrift,Avro等。
XML / JSON是基于文本的編碼/解碼,在大多數情況下都很好,但是當延遲很重要時,這些基于文本的編碼/解碼就會成為瓶頸。
Protobuffer / Thrift / Avro是二進制選項,使用非常廣泛。
SBE也是二進制的,是基于機械同情而構建的,以利用底層硬件(CPU緩存,預取程序,訪問模式,管線指令等)的優勢。
CPU和內存革命的小歷史。
我們的行業看到了功能強大的8位,16位,32位,64位處理器,現在普通的臺式機CPU可以執行近數十億條指令,只要程序員能夠編寫程序來生成這種類型的負載即可。 內存也變得便宜,獲得512 GB服務器非常容易。
我們必須改變編程方式以利用所有這些東西,數據結構和算法也必須改變。
讓我們潛入sbe。
全棧方法
大多數系統依賴于運行時優化,但是SBE已采用全棧方法,并且第一級優化由編譯器完成。
模式 – XML文件,用于定義消息的布局和數據類型。
編譯器 –將模式作為輸入并生成IR。 在這一層中發生了很多魔術,例如使用最終/常量,優化的代碼。
消息 –實際消息被緩沖區包裝。
全棧方法允許在各個級別進行優化。
無垃圾或少垃圾
這對于低延遲系統非常重要,如果不注意它,則應用程序將無法正確使用CPU緩存,并且可能進入GC暫停狀態。
SBE是圍繞flyweight模式構建的,它全部與重用對象有關,以減輕JVM上的內存壓力。
它具有緩沖區的概念,可以重復使用,編碼器/解碼器可以將緩沖區作為輸入并對其進行處理。 編碼器/解碼器不分配或分配很少(即在使用String的情況下)。
SBE建議使用直接/分出緩沖區使GC完全脫離圖片,這些緩沖區可以在線程級別分配,并且可以用于消息的解碼和編碼。
緩沖區使用情況的代碼段。
final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4096);final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer);tradeEncoder .tradeId(1).customerId(999).qty(100).symbol("GOOG").tradeType(TradeType.Buy);緩存預取
CPU已內置基于硬件的預取器。 緩存預取是計算機處理器使用的一種技術,可通過在實際需要之前將指令或數據從較慢內存中的原始存儲中提取到較快的本地內存中,從而提高執行性能。
從快速CPU緩存訪問數據比從主存儲器訪問數據快許多個數量級。
等待時間,您應該知道的博客文章詳細介紹了CPU高速緩存的速度。
如果算法正在流式傳輸并且所使用的基礎數據像數組一樣連續,則預取效果很好。 數組訪問非???#xff0c;因為它是連續且可預測的
SBE使用數組作為基礎存儲,并將字段打包在其中。
數據以小批量的高速緩存行(通常為8個字節)移動,因此,如果應用程序要求1個字節,它將獲得8個字節的數據。 由于數據打包在數組中,因此可以提前訪問單字節預取數組內容,這將加快處理速度。
將預取器視為數據庫表中的索引。 如果讀取基于這些索引,則應用程序將受益。
流媒體訪問
SBE支持所有原始類型,還允許定義大小可變的自定義類型,這允許編碼器和解碼器進行流傳輸和順序傳輸。 從緩存行中讀取數據具有很好的好處,并且解碼器幾乎不需要了解有關消息的元數據(即偏移量和大小)。
附帶權衡的讀取順序必須基于布局順序,尤其是在對可變類型的數據進行編碼的情況下。
例如寫正在使用以下順序
tradeEncoder .tradeId(1).customerId(999).tradeType(TradeType.Buy).qty(100).symbol("GOOG").exchange("NYSE");對于字符串屬性(符號和交換),讀取順序必須是第一個符號 ,然后是交換 ,如果應用程序交換順序,則它將讀取錯誤的字段,對于可變長度屬性,另一項讀取應僅為一次,因為它是流訪問模式。
好東西是有代價的!
不安全的API
數組綁定檢查可能會增加開銷,但是SBE使用的是不安全的API,并且沒有額外的綁定檢查開銷。
在生成的代碼上使用常量
編譯器生成代碼時,它會預先計算內容并使用常量。 一個示例是字段偏移在生成的代碼中,而不進行計算。
程式碼片段
public static int qtyId(){return 2;}public static int qtySinceVersion(){return 0;}public static int qtyEncodingOffset(){return 16;}public static int qtyEncodingLength(){return 8;}這需要權衡,這有利于性能,但不利于靈活性。 您無法更改字段順序,必須在末尾添加新字段。
關于常量的另一個好處是,它們僅在生成的代碼中存在,而在消息中卻沒有,這是非常有效的。
分支免費代碼
每個內核都有多個并行運行的端口,幾乎沒有指令像分支,mod,除法那樣阻塞。 SBE編譯器生成的代碼無需使用這些昂貴的指令,并且具有基本的指針碰撞數學功能。
沒有昂貴指令的代碼非???#xff0c;它將利用內核的所有端口。
Java序列化的樣例代碼
public void writeFloat(float v) throws IOException {if (pos + 4 <= MAX_BLOCK_SIZE) {Bits.putFloat(buf, pos, v); pos += 4; } else {dout.writeFloat(v); } }public void writeLong(long v) throws IOException {if (pos + 8 <= MAX_BLOCK_SIZE) {Bits.putLong(buf, pos, v); pos += 8; } else {dout.writeLong(v); } }public void writeDouble(double v) throws IOException {if (pos + 8 <= MAX_BLOCK_SIZE) {Bits.putDouble(buf, pos, v); pos += 8; } else {dout.writeDouble(v); } }SBE的示例代碼
public TradeEncoder customerId(final long value) {buffer.putLong(offset + 8, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this;}public TradeEncoder tradeId(final long value) {buffer.putLong(offset + 0, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this;}郵件大小上的一些數字。
類型級元帥.SerializableMarshal->大小267
類型類元帥.ExternalizableMarshal->大小75
輸入類元帥SBEMarshall->尺寸49
SBE最緊湊且速度最快,SBE的作者聲稱它比Google proto緩沖區快20到50倍。
可提供SBE代碼@ simple-binary-encoding
博客中使用的示例代碼可在@ sbeplayground獲得
翻譯自: https://www.javacodegeeks.com/2018/06/inside-simple-binary-encoding-sbe.html
sbe 詳解
總結
以上是生活随笔為你收集整理的sbe 详解_内部简单二进制编码(SBE)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos攻击防范方式(ddos攻击防范措
- 下一篇: aws lambda使用_使用AWS L