搜尋
首頁資料庫Redisredis奇葩資料型態與群集知識有哪些

    多樣的資料型別

    string 類型簡單方便,支援空間預先分配,也就是每次都會多分配點空間,這樣string 如果下次變長的話,就不需要額外的申請空了,當然前提是剩餘的空間夠用。

    List 類型可以實作簡單的訊息佇列,但注意可能存在訊息遺失哦,它不持 ACK 模式。

    Hash 表有點像是關係型資料庫,但是當hash 表越來越大的時候,請注意,避免使用hgetall 之類的語句,因為請求大量的資料會導致redis阻塞,這樣後面的兄弟們就得等待了。

    set 集合類型可以幫你做一些統計,例如你要統計某天活躍的用戶,可以直接把用戶ID丟到集合裡,集合支持一些騷操作,例如sdiff 可以取得集合之間的差集,sunion 可以取得集合之間的並集,功能很多,但是一定需要謹慎,因為牛逼的功能是有代價的,這些操作需要耗費一些CPU 和IO 資源,可能會導致阻塞,因此大集合之間的騷操作要慎用,

    zset 可以說是最閃耀的星星,可以做排序,因為可以排序,因此應用場景挺多,比如點讚前xx名用戶,延時隊列等等。

    bitmap 位圖的好處就是在於節省空間,特別在做一些統計類的方面,比如要統計某一天有多少個用戶簽到了並且某個用戶是否簽到了,如果不用bitmap的話,你可能會想到用set。

    SADD day 1234//签到就添加到集合
    SISMEMBER day 1234//判断1234是否签到
    SCARD day   //有多少个签到的

    set 在功能上可以滿足,但是相較於bitmap的話,set要更耗費儲存空間,set的底層主要是由整數集合或hashtable 組成,整數集合只有在資料量非常小的情況下才會使用,一般是小於512個元素,同時元素必須都是整數,對於set來說,整數集合的資料更加緊湊,他們在內存是上連續的,查詢的話只能是二分查找了,時間複雜度是O(logN),而hashtable 就不同了,這裡的hashtable 和redis 的5大資料型別中的hash是一樣的,只不過沒有value 而已,value 指向個null,同時也不存在衝突,因為這裡是集合,但是需要考慮rehash 相關問題。 ok,扯的有點遠,我們說的用戶簽到問題,在用戶非常多的情況下,set 的話肯定會用到hashtable,hashtable 的話,其實每個元素都是個dictEntry 結構體

    typedef struct dictEntry {
        // 键
        void *key;
        // 值
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
        } v;
        // 指向下个哈希表节点,形成链表
        struct dictEntry *next;
    } dictEntry;

    從這個結構體可以看到什麼呢?首先雖然值union(沒有value)和next(沒有衝突)是空的,但是結構體本身需要空間,還需要加上個key,這個佔用空間是實打實的,而如果用bitmap 的話,一個bit位就可以代表一個數字,很省空間,我們來看看bitmap 的方式如何設定和統計。

    SETBIT day 1234 1//签到
    GETBIT day 1234//判断1234是否签到
    BITCOUNT day//有多少个签到的

    bf 這是redis4.0 之後支援的布隆過濾器RedisBloom,但需要單獨載入對應的module,當然我們也可以基於上述的bitmap 來實作自己的布隆過濾器,不過既然redis已經支援了,透過RedisBloom 可以減少我們的開發時間,布隆過濾器是乾嘛的,我這裡就不贅述了,直接來看看RedisBloom 相關的用法吧。

    # 可以通过docker的方式快速拉取镜像来玩耍
    docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest
    docker exec -it redis-redisbloom bash
    redis-cli
    # 相关操作
    bf.reserve sign 0.001 10000
    bf.add sign 99 //99这个用户加入
    bf.add exists 99//判断99这个用户是否存在

    因為布隆過濾器是存在誤判的,所有bf 支持自定義誤判率,0.001就代表誤判率,10000 代表布隆過濾器可以存儲的元素個數,當實際存儲的元素個數超過這個數值的時候,誤判率會提高。

    HyperLogLog 可以用來統計,它的優點就是佔用的儲存空間極小,只需要 12KB 的記憶體就可以統計 2^64 個元素,那它主要統計什麼呢?其實主要就是基數統計,像是像UV 這種,從功能上來說UV 可以用set 或者hash 來存儲,但是缺點就是耗費存儲,容易使之變成大key,如果想要節省空間,bitmap 也可以,12KB空間的bitmap 只能統計12*1024*8=98304個元素,而HyperLogLog 卻可以統計2^64 個元素,但是這麼牛逼的技術其實是有誤差的,HyperLogLog 是基於機率來統計的,標準誤算率是0.81%,在統計海量資料且對精度要求不那麼高的場景下,HyperLogLog 在節省空間這塊還是很優秀的。

    PFADD uv 1 2 3 //1 2 3是活跃用户
    PFCOUNT uv //统计

    GEO 是可以应用在地理位置的业务上,比如微信附近的人或者附近的车辆等等,先来看一下如果没有GEO 这种数据结构,你如何知道你附近的人?首先得上报自己的地理位置信息吧,比如经度 116.397128,纬度 39.916527,此时可以用 string、hash 数据类型存储,但是如果要查找你附近的人,string 和 hash 这种就无能为例了,你不可能每次都要遍历全部的数据来判断,这样太耗时了,当然你也不可能通过 zset 这种数据结构来把经纬度信息当成权重,但是如果我们能把经纬度信息通过某种方式转换成一个数字,然后当成权重好像也可以,这时我们只需通过zrangebyscore key v1 v2也可以找到附近的人。真的需要这么麻烦吗?于是 GEO 出现了,GEO 转换经纬度为数字的方法是“二分区间,区间编码”,这是什么意思呢?以经度为例,它的范围是[-180,180],如果要采用3位编码值,那么就是需要二分3次,二分后落在左边的用0表示,右边的用1表示,以经度是121.48941 来说,第一次是在[0,180]这个区间,因此记1,第二次是在[90,180],因此再记1,第三次是在[90,135],因此记0。纬度也是同样的逻辑,假设此时对应的纬度编码后是010,最后把经纬度合并在一起,需要注意的是经度的每个值在偶数位,纬度的每个值在奇数位。

    1 1 0   //经度
     0 1 0  //纬度
    ------------
    101100 //经纬度对应的数值

    原理是这样,我们再来看看 redis 如何使用 GEO:

    GEOADD location 112.123456 41.112345 99 //上报用户99的地理位置信息
    GEORADIUS location  112.123456 41.112345 1 km ASC COUNT 10 //获取附近1KM的人

    搞懂集群

    生产环境用单实例 redis 的应该比较少,单实例的风险在于:

    1. 单点故障即服务故障,没有backup

    2. 单实例压力大,又要提供读,又要提供写

    于是我们首先想到的就是经典的主从模式,而且往往是一主多从,这是因为大部分应用都是读多写少的情况,我们的主负责更新,从负责提供读,就算我们的主宕机了,我们也可以选择一个从来充当主,这样整个应用依然可以提供服务。

    复制过程的细节

    当一个 redis 实例首次成为某个主的从的时候,这时主得把数据发给它,也就是 rdb 文件,这个过程 master 是要 fork 一个子进程来处理的,这个子进程会执行 bgsave 把当前的数据重新保存一下,然后准备发给新来的从,bgsave 的本质是读取当前内存中的数据然后保存到 rdb 文件中,这个过程涉及大量的 IO,如果直接在主进程中来处理的话,大概率会阻塞正常的请求,因此使用个子进程是个明智的选择。

    那 fork 的子进程在 bgsave 过程中如果有新的变更请求会怎么办?

    严格来说子进程出来的一瞬间,要保存的数据应该就是当时那个点的快照数据,所以是直接把当时的内存再复制一份吗?不复制的话,如果这期间又有变更改怎么办?其实这要说到写实复制(COW)机制,首先从表象上来看内存是一整块空间,其实这不太好维护,因此操作系统会把内存分成一小块一小块的,也就是内存分页管理,一页的大小一般是4K、8K或者16K等等,redis 的数据都是分布在这些页面上的,出于效率问题,fork 出来的子进程是和主进程是共享同一块的内存的,并不会复制内存,如果这期间主进程有数据变更,那么为了区分,这时最快捷的做法就是把对应的数据页重新复制一下,然后主的变更就在这个新的数据页上修改,并不会修改来的数据页,这样就保证了子进程处理的还是当时的快照。

    以上说的变更是从快照的角度来考虑的,如果从数据的一致性来说,当快照的 rdb 被从库应用之后,这期间的变更该如何同步给从库?答案是缓冲区,这个缓冲区叫做 replication buffer,主库在收到需要同步的命令之后,会把期间的变更都先保存在这个缓冲区中,这样在把 rdb 发给从库之后,紧接着会再把 replication buffer 的数据也发给从库,最终主从就保持了一致。

    replication buffer不是万能的补给剂

    我们来看看 replication buffer 持续写入的时间有多长。

    1. 我们知道主从同步的时候,主库会执行 fork 来让子进程完成相应地工作,因此子进程从开始执行 bgsave 到执行完毕这期间,变更是要写入 replication buffer 的。

    2. rdb 生成好之后,需要把它发送给从库,这个网络传输是不是也需要耗点时间,这期间也是要写入 replication buffer 的。

    3. 从库在收到 rdb 之后需要把 rdb 应用到内存里,这期间从库是阻塞的,无法提供服务,因此这期间也是要写入 replication buffer 的。

    replication buffer 既然是buffer,那麼它的大小就是有限的,如果說上面3個步驟中,只要有一個耗時長,就會導致replication buffer 快速成長(前提是有正常的寫入),當replication buffer 超過了限制之後就會導致主庫和從庫之間的連接斷開,斷開之後如果從庫再次連接上來就會導致重新開始複製,然後重複同樣的漫長的複製步驟,因此這個replication buffer 的大小還是很關鍵的,一般需要根據寫入的速度、每秒寫入的量和網路傳輸的速度等因素來綜合判斷。

    從庫網路不好和主庫斷了該怎麼辦?

    正常來說,只要主從之間的連接建立好了,後面主庫的變更可以直接發給從庫,讓從庫直接回放,但是我們並不能保證網絡環境是百分之百的通暢的,因此也要考慮從庫和主庫之間的斷聯問題。

    應該是在 redis2.8 以前,只要從庫斷聯,哪怕只有很短的時間,後面從庫再次連接上來的時候,主庫也會直接無腦的進行全量同步。在2.8 版本及以後,開始支援增量複製了,增量複製的原理就是得有個緩衝區來保存變更的記錄,這裡這個緩衝區叫做repl_backlog_buffer,這個緩衝區從邏輯上來說是個環形緩衝區,寫滿了就會從頭開始覆蓋,所以也有大小限制。在從庫重新連接上來的時候,從庫會告訴主庫:“我當前已經複製到了xx位置”,主庫收到從庫的消息之後開始查看xx位置的數據是否還在repl_backlog_buffer 中,如果在的話,直接把xx後面的資料發給從函式庫即可,如果不在的話,那無能為力了,只能再次進行全量同步。

    需要一個管理者

    在主從模式下,如果主庫掛了,我們可以把一個從庫升級成主庫,但是這個過程是手動的,靠人力來操作,不能使損失降到最低,還是需要一套自動管理和選舉的機制,這就是哨兵,哨兵它本身也是個服務,只不過它不處理數據的讀寫而已,它只負責管理所有的redis 實例,哨兵每隔一段時間會和各個redis 通訊(ping 操作),每個redis 實例只要在規定的時間內及時回复,就可以表明自己的立場。當然哨兵本身也可能有宕機或網路不通的情況,因此一般哨兵也會搭建個哨兵集群,這個集群的個數最好是奇數,例如3個或5這個這種,奇數的目的主要就是為了選舉(少數服從多數)。

    當某個哨兵在發起ping 後沒有及時收到pong,那麼就會把這個redis 實例標記下線,此時它還是不是真正的下線,這時其他的哨兵也會判定當前這個哨兵是不是真正的下線,當大多數哨兵都認定這個redis 是下線狀態,那麼就會把它從集群中踢出去,如果下線的是從庫,那麼還好,直接踢出去就ok ,如果是主庫還要觸發選舉,選舉也不是盲目選舉,肯定是要選出最合適的那個從來充當新的主庫。這個最適合充當主庫的函式庫,一般會按照以下優先權來決定:

    1. 權重,每個從函式庫其實都可以設定一個權重,權重越高的從庫會被優先選擇

    2. 複製的進度,每個從庫複製的進度可能是不一樣的,優先選擇當前和主庫資料差距最小的那個

    3. 服務的ID,其實每個redis 實例都有自己的ID,如果以上條件都一樣,那麼會選擇ID 最小的那個函式庫來充當主函式庫

    更強的橫向伸縮性

    主從模式解決了單點故障問題,同時讀寫分離技術使得應用支撐能力更強,哨兵模式可以自動監管集群,實現自動選主,自動剔除故障節點的能力。

    正常來說只要讀的壓力越來越大,我們可以加入從函式庫來緩解,那如果主庫壓力很大怎麼辦?這就得提到接下來要說的分片技術了,我們只需要把主庫切成幾片,部署到不同的機器上即可。這個分片就是redis 中的槽概念了,當分片的時候,redis 會默認分成0~16383 也就是一共16384 個槽,然後把這些槽平均分到每個分片節點上就可以起到負載均衡的作用了。每個 key 具體該分到哪一個槽中,主要是先 CRC16 得到一個 16bit 的數字,然後這個數字再對 16384 取模即可:

    crc16(key)%16384

    客户端将缓存插槽信息,以便在每个键到达时只需计算即可确定该将其发送到哪个实例进行处理。但是客户端缓存的槽信息并不是一成不变的,比如在增加实例的时候,这时候会导致重新分片,那么原来客户端缓存的信息就会不准确,一般这时候会发生两个常见的错误,严格来说也不是错误,更像一种信息,一个叫做MOVED,一个叫做ASK。moved的意思就说,原来是实例A负责的数据,现在被迁移到了实例B,MOVED 代表的是迁移完成的,但是 ASK 代表的是正在迁移过程中,比如原来是实例A负责的部分数据,现在被迁移到了实例B,剩下的还在等待迁移中,当数据迁移完毕之后 ASK 就会变成 MOVED,然后客户端收到 MOVED 信息之后就会再次更新下本地缓存,这样下次就不会出现这两个错误了。

    以上是redis奇葩資料型態與群集知識有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
    REDIS:鍵值數據存儲的指南REDIS:鍵值數據存儲的指南May 02, 2025 am 12:10 AM

    Redis是一個開源的內存數據結構存儲,用作數據庫、緩存和消息代理,適合需要快速響應和高並發的場景。 1.Redis使用內存存儲數據,提供微秒級的讀寫速度。 2.它支持多種數據結構,如字符串、列表、集合等。 3.Redis通過RDB和AOF機制實現數據持久化。 4.使用單線程模型和多路復用技術高效處理請求。 5.性能優化策略包括LRU算法和集群模式。

    REDIS:緩存,會話管理等REDIS:緩存,會話管理等May 01, 2025 am 12:03 AM

    Redis的功能主要包括緩存、會話管理和其他功能:1)緩存功能通過內存存儲數據,提高讀取速度,適用於電商網站等高頻訪問場景;2)會話管理功能在分佈式系統中共享會話數據,並通過過期時間機制自動清理;3)其他功能如發布-訂閱模式、分佈式鎖和計數器,適用於實時消息推送和多線程系統等場景。

    REDIS:探索其核心功能和好處REDIS:探索其核心功能和好處Apr 30, 2025 am 12:22 AM

    Redis的核心功能包括內存存儲和持久化機制。 1)內存存儲提供極快的讀寫速度,適用於高性能應用。 2)持久化通過RDB和AOF兩種方式確保數據不丟失,選擇依據應用需求。

    REDIS的服務器端操作:它提供的REDIS的服務器端操作:它提供的Apr 29, 2025 am 12:21 AM

    Redis'sserver-sedierations offerfunctions andTriggersForexeCutingCompleXoperationsontheserver.1)函數functionsAllowCompOustomoperationsInlua,JavaScript,javaScript,orredis'sscriptinglanguigh,增強效率和增強性。 2)

    REDIS:數據庫還是服務器?揭開角色的神秘面紗REDIS:數據庫還是服務器?揭開角色的神秘面紗Apr 28, 2025 am 12:06 AM

    redisisbothadatabaseandaserver.1)asadatabase,ituseSin-memorystorageforfastaccess,ifealforreal-timeapplications andCaching.2)Asaserver,ItsupportsPub/submessagingAndluAsessingandluAsessingandluascriptingftingftingftingftingftingftingftingfinteral-timecommunicationandserverserverserverserverserverserverserver-soperations。

    REDIS:NOSQL方法的優勢REDIS:NOSQL方法的優勢Apr 27, 2025 am 12:09 AM

    Redis是NoSQL數據庫,提供高性能和靈活性。 1)通過鍵值對存儲數據,適合處理大規模數據和高並發。 2)內存存儲和單線程模型確保快速讀寫和原子性。 3)使用RDB和AOF機制進行數據持久化,支持高可用性和橫向擴展。

    REDIS:了解其架構和目的REDIS:了解其架構和目的Apr 26, 2025 am 12:11 AM

    Redis是一种内存数据结构存储系统,主要用作数据库、缓存和消息代理。它的核心特点包括单线程模型、I/O多路复用、持久化机制、复制与集群功能。Redis在实际应用中常用于缓存、会话存储和消息队列,通过选择合适的数据结构、使用管道和事务、以及进行监控和调优,可以显著提升其性能。

    REDIS與SQL數據庫:關鍵差異REDIS與SQL數據庫:關鍵差異Apr 25, 2025 am 12:02 AM

    Redis和SQL數據庫的主要區別在於:Redis是內存數據庫,適用於高性能和靈活性需求;SQL數據庫是關係型數據庫,適用於復雜查詢和數據一致性需求。具體來說,1)Redis提供高速數據訪問和緩存服務,支持多種數據類型,適用於緩存和實時數據處理;2)SQL數據庫通過表格結構管理數據,支持複雜查詢和事務處理,適用於電商和金融系統等需要數據一致性的場景。

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    Dreamweaver Mac版

    Dreamweaver Mac版

    視覺化網頁開發工具

    WebStorm Mac版

    WebStorm Mac版

    好用的JavaScript開發工具

    MinGW - Minimalist GNU for Windows

    MinGW - Minimalist GNU for Windows

    這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

    EditPlus 中文破解版

    EditPlus 中文破解版

    體積小,語法高亮,不支援程式碼提示功能

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    將Eclipse與SAP NetWeaver應用伺服器整合。