<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)存

          共 2673字,需瀏覽 6分鐘

           ·

          2020-09-12 04:32


          來源: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的值則寫入失?。?/p>

          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é)果目標(biāo)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ù)字、英文大小寫字母以及標(biāo)點符號。

          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ù)組的下標(biāo)1260的字節(jié)

          獲取要寫入到這個字節(jié)的第幾位:10086 mod 8 = 6,需要寫入到這個字節(jié)的下標(biāo)為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映射偏移量,在線標(biāo)識為1,下線標(biāo)識為0。即可實現(xiàn)用戶上下線查詢和總在線人數(shù)的統(tǒng)計

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

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

          推薦閱讀

          阿里精選:Java 代碼精簡之道

          Java8 中用法優(yōu)雅的 Stream,性能也""優(yōu)雅""嗎?

          ElasticSearch 索引 VS MySQL 索引

          還在手動部署SpringBoot應(yīng)用?試試這個自動化插件!

          MySQL執(zhí)行計劃Explain詳解

          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  三级视频网站在线观看 | 成人久久久久久无码 | 中文无码一区二区三区四区 | 久久成人麻豆影视 | 你操我操综合 |