如何構(gòu)建一個交易系統(tǒng)(十二)

編碼解碼,不得不再次搬出這個話題园欣, 編碼解碼就是程序語言之間交流的語言!

一旦你適應(yīng)了用粗暴的思考架設(shè)了你的設(shè)計峭拘, 再從頭來會很難俊庇,一是你沒有膽量推倒重來狮暑,二是沒有時間,三是你沒有耐心辉饱; 如果搬男,反過來從最粗陋的底層開始, 倒有可能雕琢出更加精致的上層建筑彭沼!

撇開一堆高大上的RPC缔逛、分布式等等上層建筑,如何編碼解碼是個最基礎(chǔ)的環(huán)節(jié)姓惑,在自己進(jìn)程內(nèi)褐奴,怎么交流都無障礙, 就好比大家都是中國人于毙,都在說漢語敦冬,基本能夠理解你說話的意思.

但凡需要跨進(jìn)程,就需要編碼解碼你的信息唯沮, 不管是同一個還是不同語言脖旱; 這就比方你需要和一個吼達(dá)不到的人交流,你需要電話介蛉,或者書信來傳遞萌庆。 這里首要做的事情就是, 把你要表達(dá)的意思币旧,轉(zhuǎn)換成書信践险、電流信號;如果轉(zhuǎn)換的言不達(dá)意吹菱,再好的通道也是雞同鴨講巍虫。

在計算機的世界里面你將收獲一堆亂碼! 解編碼毁葱,就是程序之間通訊的一道巴別塔:

通天巴別塔

程序之間的交流和任何信息的交流過程其實都一樣垫言, 上面說對面講話如同進(jìn)程內(nèi)通訊贰剥,其實還是不太精確倾剿,任何即使面對面的對話,其實都是有解編碼過程蚌成,你腦子里面想的電信號前痘,驅(qū)動你發(fā)音系統(tǒng)產(chǎn)生氣流的震動,通過空氣傳遞到對方担忧,對方的聽覺系統(tǒng)把震動轉(zhuǎn)換成電流信號芹缔,給大腦皮層理解。

為啥她不懂你的心

概要

我們想要的解編碼協(xié)議需要滿足:

  1. 夠傻夠呆瓶盛, 字節(jié)碼打出來最欠,即使你用筆手動算也能算出來
  2. 跨語言示罗,小到內(nèi)部系統(tǒng)之間交流, 大到對外APP, 客戶端是個程序給個套路就可以解析
  3. 夠小芝硬,不能臃腫如XML 等之類蚜点,但是無需為了個把字節(jié)問題影響標(biāo)準(zhǔn) 1
  4. 夠快,夠快才能顯示我們的優(yōu)勢拌阴,同理不能為了快影響標(biāo)準(zhǔn) 1

滿足上面幾點的其實很難绍绘, 因為大部分不能滿足要求 ; 確實如此迟赃,這個猶如時間陪拘、成本、質(zhì)量鐵三角或者 CAP 一樣難以都滿足纤壁。

Quality-Cost-Time-Triangle

其實很簡單左刽, 所有的項目、工具酌媒、套路最終都是個權(quán)衡悠反,權(quán)衡和取舍!首先你不是什么消息都需要交流馍佑, 對交流的內(nèi)容和范圍做限制和取舍斋否, 可以很容易滿足上面的幾點。 大部分的IT 項目其實為了那 20% 甚至 5% 的功能拭荤,占據(jù)80%以上的代碼茵臭, 貢獻(xiàn)了絕大部分的BUG. 程序因人而生,但是公平的對待程序和自己可以省掉很多的麻煩舅世,需要和外圍通訊的消息需要滿足:

  1. 絕大部分是 primitive 類型: 這個好理解旦委, primitive 所有語言解釋套路一致,歧義少雏亚!
  2. 字段定長
    1. 如果實在需要個類似string 呢缨硝? 很簡單定長, 8/12/16/24/36/48 隨便你選罢低, 超過這個呢查辩,對不起,走其他通道网持。
  3. 少group 屬性
    1. group 也就是屬性是個列表(list)宜岛, 列表給整個消息帶來不確定性。于是少設(shè)計列表屬性功舀,能拆分就拆分萍倡, 不能拆分說明你業(yè)務(wù)模型有問題。

有人說這樣一分其實很簡單辟汰, 用個基本的分隔符列敲,就可以把消息編解碼出來阱佛, 你說對了,用個豎線( | ) 或者逗號(,)戴而,從筆者角度確實是個非常非常不錯的選擇瘫絮,緊湊、好懂填硕,非常完美的滿足上面的四點麦萤, 而且部分十分微小的消息這樣處理非常好用。

經(jīng)過如此篩選扁眯,最終可能上百個消息壮莹,最后剩下幾十個,最后帶group 的只有區(qū)區(qū)數(shù)的過來的幾個姻檀。 OK 了下面的選擇就比較寬泛 容易了命满。

FIX

最初對FIX 我是抗拒的,程序員容易犯的錯誤绣版,是對一些古老胶台、或者不時髦的東西有偏見,會一直以為最新的東西才是最NB, 最cool, 會了面子上過得去杂抽。但是這個協(xié)議是如此的簡單和健壯诈唬,已致他一直被金融界廣泛的使用,這里 有介紹缩麸,Key+Value+SOH(分隔符铸磅,字節(jié)碼 1 ) 其實就是這個協(xié)議的全部;什么狗日的 hack 幫我省那十來個字節(jié)沒有的杭朱, 比較完美符合標(biāo)準(zhǔn)阅仔; 對,其實我們在內(nèi)部也大膽的使用了FIX 作為通訊協(xié)議弧械, 如和 websocket 客戶端交流八酒, 我們也使用此風(fēng)格消息進(jìn)行交互。 看到 LOG 一竄竄漂亮的K=V 打印出來刃唐,有種賞心悅目的感覺羞迷!

SBE

SBE Simple Binary Encoding, 聽到這個詞就有種對眼的感覺, Simple 多謙虛直白的表達(dá)方式唁桩,中文的SB編碼又有點氣吞山河如虎的傲嬌闭树! 讀罷耸棒,果然簡單直接荒澡! 好帥真的一個協(xié)議。
SBE設(shè)計準(zhǔn)則, 我就不一一翻譯与殃,直接COPY Jdon 翻譯:

  1. Copy-Free:不采取中間緩沖单山,因為其在多次字節(jié)復(fù)制中有性能損耗碍现。采取直接與底層緩沖編碼與解碼,其限制是消息大小不能超過傳輸緩存的大小米奸,可以進(jìn)行碎片分段昼接。
  2. Native Type Mapping:copy-free的設(shè)計也通過將數(shù)據(jù)直接編碼為底層緩沖的原生類型中得到巨大好處,比如一個64位整數(shù)型能直接作為x86_64 MOV匯編指令被編碼進(jìn)入底層緩沖悴晰。通過這種原生的類型映射慢睡,一個字段能夠以類似高階語言如C++/Java中class類似和struct字段一樣高效率訪問。
  3. Allocation-Free:對象的分配會導(dǎo)致CPU緩存流失從而降低效率铡溪,這些被分配的對象后來得收集并刪除漂辐,對于Java是使用垃圾回收機制,導(dǎo)致stop-the-world暫停棕硫。SBE編碼采取flyweight 模式髓涯,基于底層緩沖的flyweight窗口直接對消息編碼與解碼,相應(yīng)類型的享元是基于消息頭部模板id選擇的哈扮。
  4. Streaming Access:現(xiàn)代內(nèi)存子系統(tǒng)已成為愈加復(fù)雜纬纪,該算法能夠?qū)π阅芎鸵恢滦杂泻艽髱椭瑢崿F(xiàn)最好的性能與最一致的延遲滑肉,這是以一種上升順序方式訪問內(nèi)存的方式實現(xiàn)的包各,也就是一種流。
  5. Word Aligned Access:當(dāng)word以非word大小邊界訪問時靶庙,多CPU架構(gòu)表現(xiàn)出顯著性能問題髓棋,一個word的起始地址應(yīng)該是其以字節(jié)為單位大小的倍數(shù),64位整數(shù)只能從字節(jié)地址能被8整除的地方開始惶洲,32位整數(shù)只能從被4整除的字節(jié)地址開始按声。

簡單粗暴, 是我個人對SBE 最直接的感受恬吕, 但是好用签则!

KISS

SBE 一個消息(Frame)包含哪些內(nèi)容:

SBE Frame

在HTTP中涉及久了大家基本都記得一些這樣的圖形, 基本就是個header + payload 設(shè)計手法:

WebSocket frame

當(dāng)然SBE 屬于第六層(OSI)铐料, 也就是表示層(Presentation Layer)渐裂, 最終還需要上面的應(yīng)用也就是你的業(yè)務(wù)邏輯層來處理這些數(shù)據(jù)的。

Header 保持簡單钠惩, 只保留最最基本的信息柒凉, 或者你消息路由里面需要的信息, 避免解析整個消息流篓跛。

    <composite name="messageHeader">
        <type name="blockLength" primitiveType="uint16"/>
        <type name="templateId" primitiveType="uint16"/>
        <type name="schemaId" primitiveType="uint16"/>
        <type name="version" primitiveType="uint16"/>
    </composite>

這樣的header 占據(jù)8個字節(jié)的長度膝捞, 包括信息:

  1. blockLength: payload 的長度
  2. templateId: 消息模板, 哪種類型消息愧沟, 編碼解碼需要對象的解碼編碼器蔬咬。
  3. schemaId: 屬于哪個 schema 比如和FIX 哪個兼容
  4. version: 整個是你消息的版本鲤遥, 建議不適用,如果消息變了林艘,本人更趨向創(chuàng)建個新的類盖奈,即使加上個V1..N 也可以。

對于最簡單的消息:

<sbe:message description="Internal Time Price" id="916" name="Price" semanticType="Price">
        <field id="1" name="product" presence="required" type="VARCHAR12"/>
        <field id="2" name="bid" presence="required" type="double"/>
        <field id="3" name="ask" presence="required" type="double"/>
        <field id="4" name="timestamp" presence="required" type="int64"/>
</sbe:message>

product 是一個12長度的字符串狐援, 然后是一bid 和 ask 報價钢坦, 然后是一個epoch 時間戳。
可以看到這個對象的固定長度是 : 36+8 = 44 字節(jié)啥酱, 固定長度消息场钉。 比如對于bid 字段:

offset 為 header offset 也就是8個字節(jié) + 前面的 product 12, 也就是bid 偏移是 20

編碼

buffer.putDouble(offset + 12, value, java.nio.ByteOrder.LITTLE_ENDIAN);

解碼

>buffer.getDouble(offset + 12, java.nio.ByteOrder.LITTLE_ENDIAN)

是不是好舒服懈涛, 用筆都可以算出來逛万。一個協(xié)議簡單到這個程度也令人咂舌, 好就好在這個協(xié)議沒有完備的周邊設(shè)施批钠,個人理解這個是弊端也是好處宇植!弊端不是拿過來就用, 好處是給實現(xiàn)的人留下很多的空間埋心, 而很多的協(xié)議都是全家桶指郁, 周邊都幫你實現(xiàn), 一旦出現(xiàn)亂子拷呆, 你再去扒拉闲坎,非常的艱難。

一旦你適應(yīng)了用粗暴的思考架設(shè)了你的設(shè)計茬斧, 再從頭來很難腰懂,一是你沒有膽量推倒重來,二是沒有時間项秉,三是你沒有耐心绣溜; 如果,反過來從最粗陋的底層開始娄蔼, 倒有可能雕琢出更加精致的上層建筑怖喻!

實踐

上面說的基本就是SBE 全部, 和他的一個GIT版本, 其實這個項目不能說實現(xiàn)岁诉,因為SBE 和FIX 一樣太簡單了锚沸, 這個項目僅僅是個TOOL, 生成了最基礎(chǔ)的幾個語言的 stub, 和你 application 層美好的結(jié)合還需要自己去實現(xiàn)!

萬里長征涕癣,你還在海上

首先和你底層通訊框架集合起來(RPC, MQ 等)哗蜈, 然后和你的業(yè)務(wù)bean結(jié)合起來。 現(xiàn)在的RPC, 或者M(jìn)Q 框架都有plugin 進(jìn)自己的 codec 實現(xiàn)恬叹, 好說候生, 但是和自己業(yè)務(wù)bean 結(jié)合起來就比較麻煩.

WTF同眯,給我找個轉(zhuǎn)換器來绽昼!

你不能decoder/encoder 這些 stub 類往你業(yè)務(wù)層傳啊, 這個薄的一層非常的讓人苦惱须蜗。 必須要自動代碼生成一些偽類硅确, 有這些自動生成的類有:

  1. Adapter: 反射封裝encoder/decoder get/set 之類
  2. Enum: 映射, 這個比較暴力就switch case
  3. Stub: 分兩種其實如果你需要 Lazy 模式明肮,生成一個業(yè)務(wù)bean 偽類菱农,覆蓋get方法, 對group 這里需要特別對待柿估, 如果是 Eager 模式不需要使用偽類循未,直接 adapter 中 解碼new一個然后 get/set 上去。
  4. 反射秫舌,由于SBE 是基礎(chǔ)XML的妖, 自開發(fā)一套annotation, 方便一次掃描出來!

由于以前我們一直使用kryo序列化方式足陨,效率和壓縮比還是不錯嫂粟, 但是對其他語言不兼容,換成 SBE 后對于一些小消息墨缘,由于有頭(部分頭不止8字節(jié)長度星虹,Domain 消息有29字節(jié)長度),還有對于optional 字段其實 SBE 也要占空間镊讼, 所以消息的大小沒有多大的優(yōu)勢宽涌,但是解碼編碼還是飛快不少!

特別是如果你根據(jù)消息的ID 也就是 tempalteId 做路由可以說非车澹快护糖,記得你的 templateId 固定位置, 直接截取byte 相關(guān)位置就可以路由了嚼松。


好久沒有更新嫡良,過年前(2018新年)將會有幾大篇幅,分享一些非業(yè)務(wù)東西献酗, 下一篇將講監(jiān)控寝受,有的放矢,方能胸有成竹罕偎、控制自如很澄。

關(guān)于監(jiān)控

參考

  1. SBE 協(xié)議
  2. Simple Binary Encoding, a new ultra-fast marshalling API in C++, Java and .NET
  3. 簡單二進(jìn)制編碼(SBE)
  4. OSI model
  5. GIT Simple binary encoding

GoXTX 下一代交易平臺技術(shù)供應(yīng)商
GoXTX one-stop solution for neXT generation eXchange

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子甩苛,更是在濱河造成了極大的恐慌蹂楣,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讯蒲,死亡現(xiàn)場離奇詭異痊土,居然都是意外死亡,警方通過查閱死者的電腦和手機墨林,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門赁酝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旭等,你說我怎么就攤上這事酌呆。” “怎么了搔耕?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵隙袁,是天一觀的道長。 經(jīng)常有香客問我弃榨,道長菩收,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任惭墓,我火速辦了婚禮坛梁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腊凶。我一直安慰自己划咐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布钧萍。 她就那樣靜靜地躺著褐缠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪风瘦。 梳的紋絲不亂的頭發(fā)上队魏,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音万搔,去河邊找鬼胡桨。 笑死,一個胖子當(dāng)著我的面吹牛瞬雹,可吹牛的內(nèi)容都是我干的昧谊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼酗捌,長吁一口氣:“原來是場噩夢啊……” “哼呢诬!你這毒婦竟也來了涌哲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尚镰,失蹤者是張志新(化名)和其女友劉穎阀圾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狗唉,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡初烘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了敞曹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片账月。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡综膀,死狀恐怖澳迫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剧劝,我是刑警寧澤橄登,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站讥此,受9級特大地震影響拢锹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萄喳,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一卒稳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧他巨,春花似錦充坑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至份企,卻和暖如春也榄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背司志。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工甜紫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骂远。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓囚霸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吧史。 傳聞我的和親對象是個殘疾皇子邮辽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容

  • 實時消息協(xié)議---流的分塊 版權(quán)聲明: 版權(quán)(c)2009 Adobe系統(tǒng)有限公司唠雕。全權(quán)所有。 摘要: 本備忘錄描...
    一個人zy閱讀 1,905評論 0 9
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理吨述,服務(wù)發(fā)現(xiàn)岩睁,斷路器,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 編碼問題一直困擾著開發(fā)人員揣云,尤其在 Java 中更加明顯捕儒,因為 Java 是跨平臺語言,不同平臺之間編碼之間的切換...
    x360閱讀 2,480評論 1 20
  • 簡介 用簡單的話來定義tcpdump邓夕,就是:dump the traffic on a network刘莹,根據(jù)使用者...
    保川閱讀 5,957評論 1 13
  • 文/段代洪 這座城市的東郊,新建了一處草木掩映的別墅城焚刚。讓我心動的不是別墅的華麗和幽深点弯,而是矗立在樓宇...
    段代洪的心靈驛站閱讀 397評論 2 5