存儲設計方案
① 客廳的儲物櫃怎麼設計比較合適不規則排列比較好看嗎
客廳的儲物櫃怎麼設計比較合適?
不規則排列比較好看。客廳作為家庭交流休息的重要場所,當你在客廳里安頓下來休息時,面對擁擠的儲物架和物品,很難放鬆下來。因此我們需要尋找最佳客廳存儲設計方案,為您的空間帶來秩序和平靜。充分利用飄窗利用飄窗經常被浪費的空間,配備巧妙的內置座椅,內置抽屜將創造額外的存儲空間,並且比掀蓋更實用。將不規則的末端部分用作內置邊桌,並納弊在頂部添加墊子以提高舒適度。結合開放式和封閉式存儲。
利用每一個牆面空間,這是充分利用客廳中每個角落和縫隙的好方法,並使用牆板打造引人注目的裝飾效果,在牆裙高度劃分面板將為存儲和展示藝術品提供一個小壁架,而小的存儲櫃可用於存放書籍、配件和小擺設。建立自己的媒體存儲,選擇多功能電視和媒體存儲方案,一次就可以存儲所有必需品。現成的模塊化儲物空間看起來像是定製的內置件,但有頂部和底部部分以及一系列寬度和高度,因此您可以根據自己的空念啟間大小進行安排。
選擇帶有「秘密」存儲空間的邊桌,在沙發的不遠的距離內找到一個放置遙控器、杯墊或任何其他必需品的空間,但又不想弄亂你的桌面。這些整潔的嵌仔茄如套邊桌可以單獨使用,或者當嵌套在一起時,最小的桌子就成了零碎物品的方便藏身處。
② 存儲解決方案的內容描述
存儲整合將迅速增長的數據分配至常用平台,從而簡化管理。戴爾提供的存儲整合解決方案可幫助簡化操作、提高利用率並促進經濟實惠地擴展。
1、存儲區域網路 (SAN)>
存儲區域網路(SAN)是共享存儲設備(例如磁碟存儲陣列和磁帶自動化系統)網路。 藉助SAN體系結構,連接區域網(LAN)或廣域網(WAN)的多台伺服器均可獲得存儲資源, 因為存儲數據不是直接駐留在任何網路伺服器上、處理能力針對企業應用程序進行了優化並且伺服器上的存儲容量被配置在最需要的位置。與諸如直接連接存儲(DAS)等其他選項相比,SAN存儲還可減少管理時間和數據備份需求。最後,SAN存儲可以簡化數據分層、形成更好的資源利用率並且通常可以隨著存儲需求的增長而輕松擴展。
SAN通常使用以下協議進行部署:
光纖通道(FC)SAN - 具備光纖通道連接性的磁碟存儲陣列,連接光纖通道主機匯流排適配器(HBA)和交換機
互聯網SCSI(iSCSI) SAN - 具備IP連接性的磁碟存儲陣列,使用iSCSI標准協議連接網路介面卡(NIC)和乙太網交換機
2、統一存儲>
3、文件整合/網路連接存儲(NAS) >
基於網路的文件級存儲
網路連接存儲(NAS)是專業存儲伺服器,其配備私有IP地址,可提供給連接區域網(LAN)或廣域網(WAN)的多台客戶機和伺服器。預安裝的網路通信協議將予以啟用,以便異構環境中具有不同操作系統的客戶機和操作系統可以讀寫NAS伺服器上的數據。組織可向文件/列印NAS伺服器中添加磁碟存儲陣列、磁帶機或磁帶自動化系統 ,來幫助簡化管理和備份操作、提高存儲資源的利用率,並作為集中化平台來進行經濟高效的擴展。NAS網關可連接存儲區域網路(SAN)中的磁碟存儲陣列或磁帶自動化系統。
③ 如何做好倉庫存儲的方案設計
存儲業的重點在於倉庫的管理,合理的倉庫管理可以有效地縮短存取貨物的時間,降低存儲管理的成本。
由於貨物要在倉庫的不同區域和單位移動,企業在倉庫管理上需要作出合適的方案來布置倉庫,從而使倉庫貨物的搬運量達到最小。通常倉庫寄存的貨物有專門的存放點,每一個存放單位都是隔開的,便於貨物的區分。所以一般情況下,貨物的搬運都發生在出入口和貨物區,並不存在各個貨物單位之間的搬運工作。由此對於倉庫倉儲的設計會有兩種方案可以借鑒。
第一種情況是在各種物品所需貨區面積相同時,我們只需要把搬運次數最多的貨物單位區布置在靠近出入口的地方,得到最小的總負荷數。
第二種情況是各種物品所需貨區面積不同下,我們需要先將貨物的搬運次數和所需貨區數量之比計算出來,從中取比值最大者做為靠近出入口的貨物放置點,並且依次往下排列。
以上兩種情況倉庫貨區布置方法,都是以總負荷數最小為目標,設計簡單而又科學。但是在實際的貨物存儲中,還要需要更多不同的倉庫布置方案來解決每一貨物存放的位置和途徑。
就比如引入新技術可以讓貨物存放的位置更加准確,只要有計算機倉庫管理系統,就可以讓揀運人員快速知道貨物的存放位置,並且為貨物的出行路線提供最佳的方案給揀運人員做選擇,加速了整個貨物存取的工作效率和正確性,也節約了工作人員在確認貨物區域上的時間。
④ Redis百億級Key存儲設計方案
該應用場景為DMP緩存存儲需求,DMP需要管理非常多的第三方id數據,其中包括各媒體cookie與自身cookie(以下統稱supperid)的mapping關系,還包括了supperid的人口標簽、移動端id(主要是idfa和imei)的人口標簽,以及一些黑名單id、ip等數據。
在hdfs的幫助下離線存儲千億記錄並不困難,然而DMP還需要提供毫秒級的實時查詢。由於cookie這種id本身具有不穩定性,所以很多的真實用戶的瀏覽行為會導致大量的新cookie生成,只有及時同步mapping的數據才能命中DMP的人口標簽,無法通過預熱來獲取較高的命中,這就跟緩存存儲帶來了極大的挑戰。
經過實際測試,對於上述數據,常規存儲超過五十億的kv記錄就需要1T多的內存,如果需要做高可用多副本那帶來的消耗是巨大的,另外kv的長短不齊也會帶來很多內存碎片,這就需要超大規模的存儲方案來解決上述問題。
人⼝標簽主要是cookie、imei、idfa以及其對應的gender(性別)、age(年齡段)、geo(地域)等;mapping關系主要是媒體cookie對supperid的映射。以下是數據存儲⽰示例:
媒體編號-媒體cookie=>supperid
supperid => { age=>年齡段編碼,gender=>性別編碼,geo=>地理位置編碼 }
imei or idfa => { age=>年齡段編碼,gender=>性別編碼,geo=>地理位置編碼 }
顯然PC數據需要存儲兩種key=>value還有key=>hashmap,⽽而Device數據需要存儲⼀一種
key=>hashmap即可。
存儲吃緊的一個重要原因在於每天會有很多新數據入庫,所以及時清理數據尤為重要。主要方法就是發現和保留熱數據淘汰冷數據。
網民的量級遠遠達不到幾十億的規模,id有一定的生命周期,會不斷的變化。所以很大程度上我們存儲的id實際上是無效的。而查詢其實前端的邏輯就是廣告曝光,跟人的行為有關,所以一個id在某個時間窗口的(可能是一個campaign,半個月、幾個月)訪問行為上會有一定的重復性。
數據初始化之前,我們先利用hbase將日誌的id聚合去重,劃定TTL的范圍,一般是35天,這樣可以砍掉近35天未出現的id。另外在Redis中設置過期時間是35天,當有訪問並命中時,對key進行續命,延長過期時間,未在35天出現的自然淘汰。這樣可以針對穩定cookie或id有效,實際證明,續命的方法對idfa和imei比較實用,長期積累可達到非常理想的命中。
Hash表空間大小和Key的個數決定了沖突率(或者用負載因子衡量),再合理的范圍內,key越多自然hash表空間越大,消耗的內存自然也會很大。再加上大量指針本身是長整型,所以內存存儲的膨脹十分可觀。先來談談如何把key的個數減少。
大家先來了解一種存儲結構。我們期望將key1=>value1存儲在redis中,那麼可以按照如下過程去存儲。先用固定長度的隨機散列md5(key)值作為redis的key,我們稱之為BucketId,而將key1=>value1存儲在hashmap結構中,這樣在查詢的時候就可以讓client按照上面的過程計算出散列,從而查詢到value1。
過程變化簡單描述為:get(key1) -> hget(md5(key1), key1) 從而得到value1。
如果我們通過預先計算,讓很多key可以在BucketId空間里碰撞,那麼可以認為一個BucketId下面掛了多個key。比如平均每個BucketId下面掛10個key,那麼理論上我們將會減少超過90%的redis key的個數。
具體實現起來有一些麻煩,而且用這個方法之前你要想好容量規模。我們通常使用的md5是32位的hexString(16進制字元),它的空間是128bit,這個量級太大了,我們需要存儲的是百億級,大約是33bit,所以我們需要有一種機制計算出合適位數的散列,而且為了節約內存,我們需要利用全部字元類型(ASCII碼在0~127之間)來填充,而不用HexString,這樣Key的長度可以縮短到一半。
下面是具體的實現方式
參數bit決定了最終BucketId空間的大小,空間大小集合是2的整數冪次的離散值。這里解釋一下為何一個位元組中只有7位可用,是因為redis存儲key時需要是ASCII(0~127),而不是byte array。如果規劃百億級存儲,計劃每個桶分擔10個kv,那麼我們只需2^30=1073741824的桶個數即可,也就是最終key的個數。
碎片主要原因在於內存無法對齊、過期刪除後,內存無法重新分配。通過上文描述的方式,我們可以將人口標簽和mapping數據按照上面的方式去存儲,這樣的好處就是redis key是等長的。另外對於hashmap中的key我們也做了相關優化,截取cookie或者deviceid的後六位作為key,這樣也可以保證內存對齊,理論上會有沖突的可能性,但在同一個桶內後綴相同的概率極低(試想id幾乎是隨機的字元串,隨意10個由較長字元組成的id後綴相同的概率*桶樣本數=發生沖突的期望值<<0.05,也就是說出現一個沖突樣本則是極小概率事件,而且這個概率可以通過調整後綴保留長度控制期望值)。而value只存儲age、gender、geo的編碼,用三個位元組去存儲。
另外提一下,減少碎片還有個很low但是有效的方法,將slave重啟,然後強制的failover切換主從,這樣相當於給master整理的內存的碎片。
推薦Google-tcmalloc, facebook-jemalloc內存分配,可以在value不大時減少內存碎片和內存消耗。有人測過大value情況下反而libc更節約。
1)kv存儲的量級必須事先規劃好,浮動的范圍大概在桶個數的十到十五倍,比如我就想存儲百億左右的kv,那麼最好選擇30bit 31bit作為桶的個數。也就是說業務增長在一個合理的范圍(10 15倍的增長)是沒問題的,如果業務太多倍數的增長,會導致hashset增長過快導致查詢時間增加,甚至觸發zip-list閾值,導致內存急劇上升。
2)適合短小value,如果value太大或欄位太多並不適合,因為這種方式必須要求把value一次性取出,比如人口標簽是非常小的編碼,甚至只需要3、4個bit(位)就能裝下。
3)典型的時間換空間的做法,由於我們的業務場景並不是要求在極高的qps之下,一般每天億到十億級別的量,所以合理利用CPU租值,也是十分經濟的。
4)由於使用了信息摘要降低了key的大小以及約定長度,所以無法從redis裡面random出key。如果需要導出,必須在冷數據中導出。
5)expire需要自己實現,目前的演算法很簡單,由於只有在寫操作時才會增加消耗,所以在寫操作時按照一定的比例抽樣,用HLEN命中判斷是否超過15個entry,超過才將過期的key刪除,TTL的時間戳存儲在value的前32bit中。
6)桶的消耗統計是需要做的。需要定期清理過期的key,保證redis的查詢不會變慢。
人口標簽和mapping的數據100億條記錄。
優化前用2.3T,碎片率在2左右;優化後500g,而單個桶的平均消耗在4左右。碎片率在1.02左右。查詢時這對於cpu的耗損微乎其微。
另外需要提一下的是,每個桶的消耗實際上並不是均勻的,而是符合多項式分布的。
上面的公式可以計算桶消耗的概率分布。公式是唬人用的,只是為了提醒大家不要想當然的認為桶消耗是完全均勻的,有可能有的桶會有上百個key。但事實並不沒有那麼誇張。試想一下投硬幣,結果只有兩種正反面。相當於只有兩個桶,如果你投上無限多次,每一次相當於一次伯努利實驗,那麼兩個桶必然會十分的均勻。概率分布就像上帝施的魔咒一樣,當你面對大量的桶進行很多的廣義的伯努利實驗。桶的消耗分布就會趨於一種穩定的值。接下來我們就了解一下桶消耗分布具體什麼情況:
通過采樣統計
31bit(20多億)的桶,平均4.18消耗
100億節約了1.8T內存。相當於節約了原先的78%內存,而且桶消耗指標遠沒有達到預計的底線值15。
對於未出現的桶也是存在一定量的,如果過多會導致規劃不準確,其實數量是符合二項分布的,對於2 30桶存儲2 32kv,不存在的桶大概有(百萬級別,影響不大):
Math.pow((1 - 1.0 / Math.pow(2, 30)), Math.pow(2, 32)) * Math.pow(2, 30);
對於桶消耗不均衡的問題不必太擔心,隨著時間的推移,寫入時會對HLEN超過15的桶進行削減,根據多項式分布的原理,當實驗次數多到一定程度時,桶的分布就會趨於均勻(硬幣投擲無數次,那麼正反面出現次數應該是一致的),只不過我們通過expire策略削減了桶消耗,實際上對於每個桶已經經歷了很多的實驗發生。
總結:信息摘要在這種場景下不僅能節約key存儲,對齊了內存,還能讓Key按照多項式分布均勻的散列在更少量的key下面從而減少膨脹,另外無需在給key設置expire,也很大程度上節約了空間。
這也印證了時間換空間的基本理論,合理利用CPU租值也是需要考慮的。
關注分布式存儲技術以及分布式計算方法