<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          這么設(shè)計,Redis 10億數(shù)據(jù)量只需要100MB內(nèi)存

          共 2806字,需瀏覽 6分鐘

           ·

          2020-09-14 20:57

          點擊上方“碼農(nóng)突圍”,馬上關(guān)注
          這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包
          真愛,請設(shè)置“星標”或點個“在看”

          來源:www.toutiao.com/i6767642839267410445
          本文主要和大家分享一下redis的高級特性:bit位操作。
          本文redis試驗代碼基于如下環(huán)境:
          操作系統(tǒng):Mac OS 64位 版本:Redis 5.0.7 64 bit 運行模式:standalone mode

          redis位操作

          reids位操作也叫位數(shù)組操作、bitmap,它提供了SETBIT、GETBIT、BITCOUNT、BITTOP四個命令用于操作二進制位數(shù)組。
          先來看一波基本操作示例:

          SETBIT

          語法:SETBIT key offset value
          即:命令 key 偏移量 0/1
          setbit命令用于寫入位數(shù)組指定偏移量的二進制位設(shè)置值,偏移量從0開始計數(shù),且只允許寫入1或者0,如果寫入非0和1的值則寫入失敗:

          GETBIT

          語法:GETBIT key offset
          即:命令 key 偏移量
          gitbit命令用于獲取位數(shù)組指定偏移量上的二進制值:

          BITCOUNT

          語法:BITCOUNT key
          即:命令 key
          bitcount命令用于獲取指定key的位數(shù)組中值為1的二進制位的數(shù)量,之前我們寫入了偏移量0的值為1,偏移量10 的值為1,偏移量8的值為0:

          BITOP

          語法:BITOP operation destkey key [key…]
          即:命令 操作 結(jié)果目標key key1 key2 …
          bitop命令可以對多個位數(shù)組的key進行and(按位與)、or(按位或)、xor(按位異或)運算,并將運算結(jié)果設(shè)置到destkey中:

          底層數(shù)據(jù)結(jié)構(gòu)分析

          SDS是redis中的一種數(shù)據(jù)結(jié)構(gòu),叫做簡單動態(tài)字符串(Simple Dynamic String),并且它是一種二進制安全的,在大多數(shù)的情況下redis中的字符串都用SDS來存儲。
          SDS的數(shù)據(jù)結(jié)構(gòu):
          struct?sdshdr?{
          ?#記錄buff數(shù)組中已使用字節(jié)的數(shù)量
          ?#也是SDS所保存字符串的長度
          ?int?len;
          ?#記錄buff數(shù)組中未使用字節(jié)的數(shù)量
          ?int?free;
          ?#字節(jié)數(shù)組,字符串就存儲在這個數(shù)組里
          ?char?buff\[\];
          }
          數(shù)據(jù)存儲示例:
          SDS的優(yōu)點:
          1. 時間復(fù)雜度為O(1)
          2. 杜絕緩沖區(qū)溢出
          3. 減少修改字符串長度時候所需的內(nèi)存重分配次數(shù)
          4. 二進制安全的API操作
          5. 兼容部分C字符串函數(shù)
          redis中的位數(shù)組采用的是String字符串?dāng)?shù)據(jù)格式來存儲,而字符串對象使用的正是上文說的SDS簡單動態(tài)字符串?dāng)?shù)據(jù)結(jié)構(gòu)。
          大家都知道的是一個字節(jié)用的是8個二進制位來存儲的,也就是8個0或者1,即一個字節(jié)可以存儲十進制0~127的數(shù)字,也即包含了所有的數(shù)字、英文大小寫字母以及標點符號。
          1Byte=8bit 1KB=1024Byte 1MB=1024KB 1GB=1024MB
          位數(shù)組在redis存儲世界里,每一個字節(jié)也是8位,初始都是:
          0?0?0?0?0?0?0?0
          而位操作就是在對應(yīng)的offset偏移量上設(shè)置0或者1,比如將第3位設(shè)置為1,即:
          0?0?0?0?1?0?0?0
          #對應(yīng)redis操作即:
          setbit?key?3?1
          在此基礎(chǔ)上,如果要在偏移量為13的位置設(shè)置1,即:
          setbit?key?13?1
          #對應(yīng)redis中的存儲為:
          0?0?1?0?|?0?0?0?0?|?0?0?0?0?|?1?0?0?0

          時間復(fù)雜度

          GETBIT命令時間復(fù)雜度O(1)
          STEBIT命令時間復(fù)雜度O(1)
          BITCOUNT命令時間復(fù)雜度O(n)
          BITOP命令時間復(fù)雜度O(n)、O(n2)
          我們來看GETBIT以及SETBIT命令的時間復(fù)雜度為什么是O(1),當(dāng)我們執(zhí)行一個SETBIT key 10086 1的值的時候,reids的計算方式如下:
          獲取到要寫入位數(shù)組中的哪個字節(jié):10086÷8=1260,需要寫入到位數(shù)組的下標1260的字節(jié)
          獲取要寫入到這個字節(jié)的第幾位:10086 mod 8 = 6,需要寫入到這個字節(jié)的下標為6即第7位上去。
          通過這兩種計算方式大家可以清晰的看到,位操作的GETBIT和SETBIT都是常量計算,因此它的時間復(fù)雜度為O(1)。
          而BITCOUNT命令需要對整個位數(shù)組的所有元素進行遍歷算出值為1的有多少個,當(dāng)然redis對于大數(shù)據(jù)了的bit執(zhí)行bitcount命令會有一整套復(fù)雜的優(yōu)化的算法,但是核心思路還是這個意思,無非是減少部分遍歷查詢次數(shù)。比如以128位為一次遍歷,那么他的遍歷次數(shù)就是所有的位數(shù)除以128。
          BITTOP命令則是根據(jù)不同的操作有不同的執(zhí)行方式。比如AND操作,則需要查看位值為1的即可。

          存儲空間計算

          根據(jù)上面的介紹,相信大家已經(jīng)知道了基于redis的位數(shù)組數(shù)據(jù)結(jié)構(gòu)存儲的數(shù)據(jù)占用內(nèi)存大小是怎么計算的了。比如有100億的數(shù)據(jù),那么它需要的字節(jié)數(shù)組:
          1000000000÷8÷1024÷1024≈119.21MB
          也就是存儲10億的數(shù)據(jù)只需要119MB左右的內(nèi)存空間,這對于現(xiàn)在動輒16G、32G集群版的redis,完全沒有問題。
          需要注意的是,如果你的數(shù)據(jù)量不大,那就不要把起始偏移量搞的很大,這樣也是占空間的,比如我們只需要存儲幾百條數(shù)據(jù),但是其中的偏移量卻很大,這就會造成了很大的內(nèi)存空間浪費。

          應(yīng)用場景

          實際項目開發(fā)中有很多業(yè)務(wù)都適合采用redis的bit來實現(xiàn)。

          用戶簽到場景

          每天的日期字符串作為一個key,用戶Id作為offset,統(tǒng)計每天用戶的簽到情況,總的用戶簽到數(shù)

          活躍用戶數(shù)統(tǒng)計

          用戶日活、月活、留存率等均可以用redis位數(shù)組來存儲,還是以每天的日期作為key,用戶活躍了就寫入offset為用戶id的位值1。
          同理月活也是如此。

          用戶是否在線以及總在線人數(shù)統(tǒng)計

          同樣是使用一個位數(shù)組,用戶的id映射偏移量,在線標識為1,下線標識為0。即可實現(xiàn)用戶上下線查詢和總在線人數(shù)的統(tǒng)計

          APP內(nèi)用戶的全局消息提示小紅點

          現(xiàn)在大多數(shù)的APP里都有站內(nèi)信的功能,當(dāng)有消息的時候,則提示一個小紅點,代表用戶有新的消息。

          最近熱文

          ? ?字節(jié)跳動發(fā)半個月工資獎金,員工:以后我住公司了
          ???思科前員工刪庫跑路,損失達 1600 多萬
          ???如何破解“僅三天可見”的朋友圈?
          ???Java反射到底慢在哪?

          最近整理了一份大廠算法刷題指南,包括一些刷題技巧,在知乎上已經(jīng)有上萬贊。同時還整理了一份6000頁面試筆記。關(guān)注下面公眾號,在公眾號內(nèi)回復(fù)「刷題」,即可免費獲取!回復(fù)「加群」,可以邀請你加入讀者群!



          明天見(??ω??)??

          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久人妻少妇嫩草AV蜜桃漫画 | 欧美日韩一级黄色片 | 毛片毛片毛片多人 | 大香蕉国产精品 | 涩涩大香蕉|