将数据压缩到数据结构中
這個故事是關(guān)于我們最近在Plumbr進(jìn)行的容量優(yōu)化任務(wù)。 一切始于將無害的要求添加到現(xiàn)有組合中。
如您所知,Plumbr監(jiān)視解決方案作為連接到服務(wù)器的Java代理分發(fā)。 只需少量添加即可跟蹤一段時間內(nèi)所有已連接的代理,以便可以實(shí)時回答以下問題:
- 我們有多久沒有收到這個特定JVM的消息了?
- 另一個JVM的最后一次已知停機(jī)時間是什么?
當(dāng)每個代理每秒發(fā)送一次心跳時,我們在服務(wù)器端需要做的就是跟蹤所有心跳。 由于每個心跳都附加有唯一的時間戳記,因此天真的解決方案就像將Set或Map中的所有心跳都扔掉一樣容易。 那么-簡單,完成,接下來,請?
但是,一些快速的數(shù)學(xué)運(yùn)算表明,最初的想法可能行不通。 考慮到:
- 時間戳記的類型很長 ,需要8個字節(jié)才能容納它自己
- 一年中有365 x 24 x 60 x 60 = 31,536,000秒
我們可以快速進(jìn)行數(shù)學(xué)計(jì)算,發(fā)現(xiàn)單個JVM僅使用一年的原始數(shù)據(jù)就需要240MB 。 僅原始數(shù)據(jù)的大小就已經(jīng)足夠嚇人了,但是當(dāng)打包到HashSet時,結(jié)構(gòu)的保留大小 激增至約2GB ,而所有開銷java.util.Collection API實(shí)現(xiàn)都隱藏在它們的腹部 。
幼稚的解決方案已經(jīng)無法解決,我們需要一個替代方案。 最初我們不必走得很遠(yuǎn),因?yàn)樵谕籮ava.util包中,一個等待被發(fā)現(xiàn)的意外之舉叫java.util.BitSet 。 根據(jù)該類的javadoc:
BitSet類實(shí)現(xiàn)一個按需增長的位向量。 位集合的每個分量都有一個布爾值。 BitSet的位由非負(fù)整數(shù)索引。 可以檢查,設(shè)置或清除各個索引位。
那么,如果我們將從代理獲取的心跳存儲為由心跳時間戳記索引的布爾值,該怎么辦? Java中的時間戳表示為當(dāng)前時間與1970年1月1日UTC午夜之間的毫秒差。 知道這一點(diǎn)后,我們可以將UTC表示為2015年9月1日12:00 UTC,即數(shù)字1441108800。那么,如果當(dāng)我們看到一個Agent在時間戳1441108800處向我們發(fā)送心跳信號時,我們會將帶有索引1441108800的位設(shè)置為true ,否則被保留為默認(rèn)false ?
解決方案的問題隱藏在一個事實(shí)中,即BitSet中的位是用整數(shù)而不是long索引的。 要繼續(xù)執(zhí)行此解決方案,我們將需要一種將整數(shù)映射到long而不丟失任何信息的方法。 如果似乎不可能,那么讓我們回顧一下這樣一個事實(shí),即需要一秒而不是一毫秒的精度。 知道了這一點(diǎn),我們可以將索引縮小1,000倍,并以秒而不是毫秒的精度標(biāo)記時間。
但是僅使用整數(shù)就可以表示多少秒? 顯然,Integer.MAX_VALUE足夠大,可以表示從1970年1月1日到19.01.2038的每一秒。 除了制造2038年的問題外,它還應(yīng)該足夠好,對嗎?
不幸的是,正如我們的餐巾紙計(jì)算所顯示的那樣,一年的數(shù)據(jù)價值仍需要約800MB的堆空間。 這是從原始HashSet的2GB向正確方向邁出的一小步,但對于實(shí)際使用而言仍然太多了。
為了克服該問題,可能需要重新閱讀/重新考慮“足以代表1970年1月1日的每一秒”的部分。 (不幸的)先生。 直到1995年,高斯林才發(fā)明Java虛擬機(jī)。18年后,Plumbr看到了曙光。 因此,我們直到1970年才需要回顧歷史,并且每個整數(shù)都有一堆零。 可以從01.01.2013開始,而不是從01.01.1970開始,并使用一個索引0對應(yīng)于01.01.2013 00:00(UTC)。
重做我們的餐巾紙數(shù)學(xué),并在實(shí)踐中檢查結(jié)果使我們成為贏家。 現(xiàn)在一年的數(shù)據(jù)量只能存儲在20MB中 。 與原始2GB相比,我們將所需容量減少了100倍 。 由于現(xiàn)有的基礎(chǔ)架構(gòu)已經(jīng)可以解決這個問題,因此已經(jīng)處于舒適區(qū)域,因此我們沒有在優(yōu)化路徑上走得更遠(yuǎn)。
故事的道德啟示? 當(dāng)您有需求時,請找出對應(yīng)用程序性能的影響。 我的意思是性能的各個方面,因?yàn)椴粌H有延遲和吞吐量,還應(yīng)該忘記容量。 并且–了解您的域名。 沒有它,您將無法做出決策,如果僅僅配備了有關(guān)數(shù)據(jù)結(jié)構(gòu)的智能書籍,這些決策就顯得不安全且危險。
翻譯自: https://www.javacodegeeks.com/2015/09/squeezing-data-into-the-data-structure.html
總結(jié)
以上是生活随笔為你收集整理的将数据压缩到数据结构中的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样选一个好车牌如何在电脑上选车牌号
- 下一篇: 端到端测试_端到端测试的滥用–测试技术2