注意:Redis支持多個數據庫,並且每個數據庫的數據是隔離的不能共享,並且基於單機才有,如果是集群就沒有數據庫的概念。
Redis是一個字典結構的存儲服務器,而實際上一個Redis實例提供了多個用來存儲數據的字典,客戶端可以指定將數據存儲在哪個字典中。這與我們熟知的在一個關系數據庫實例中可以創建多個數據庫類似,所以可以將其中的每個字典都理解成一個獨立的數據庫。
每個數據庫對外都是一個從0開始的遞增數字命名,Redis默認支持16個數據庫(可以通過配置文件支持更多,無上限),可以通過配置databases來修改這一數字。客戶端與Redis建立連接后會自動選擇0號數據庫,不過可以隨時使用SELECT命令更換數據庫,如要選擇1號數據庫:
redis> SELECT 1 OK redis [1] > GET foo (nil)
然而這些以數字命名的數據庫又與我們理解的數據庫有所區別。首先Redis不支持自定義數據庫的名字,每個數據庫都以編號命名,開發者必須自己記錄哪些數據庫存儲了哪些數據。另外Redis也不支持為每個數據庫設置不同的訪問密碼,所以一個客戶端要么可以訪問全部數據庫,要么連一個數據庫也沒有權限訪問。最重要的一點是多個數據庫之間並不是完全隔離的,比如FLUSHALL命令可以清空一個Redis實例中所有數據庫中的數據。綜上所述,這些數據庫更像是一種命名空間,而不適宜存儲不同應用程序的數據。比如可以使用0號數據庫存儲某個應用生產環境中的數據,使用1號數據庫存儲測試環境中的數據,但不適宜使用0號數據庫存儲A應用的數據而使用1號數據庫B應用的數據,不同的應用應該使用不同的Redis實例存儲數據。由於Redis非常輕量級,一個空Redis實例占用的內在只有1M左右,所以不用擔心多個Redis實例會額外占用很多內存。
每個數據庫都有屬於自己的空間,不必擔心之間的key沖突。
不同的數據庫下,相同的key取到各自的值。
flushdb命令清除數據,只會清除當前的數據庫下的數據,不會影響到其他數據庫。
flushall命令會清除這個實例的數據。在執行這個命令前要格外小心。
數據庫的數量是可以配置的,默認情況下是16個。修改redis.conf下的databases指令:
databases 64
redis沒有提供任何方法來關聯標識不同的數據庫。因此,需要你來跟蹤什么數據存儲到哪個數據庫下。
因此上面的快開啟200個實例的場景,可以使用不同的數據庫來存儲,而不必開啟如此那么多的實例。
redis多個數據庫 內存怎么分配的
2、當redis 服務器 初始化時,會預先分配 16 個數據庫(該數量可以通過配置文件配置),所有數據庫保存到結構 redisServer 的一個成員 redisServer.db 數組中。當我們選擇數據庫 select number 時,程序直接通過 redisServer.db[number] 來切換數據庫。有時候當程序需要知道自己是在哪個數據庫時,直接讀取 redisDb.id 即可。
3、既然我們知道一個數據庫的所有 鍵值都存儲在redisDb.dict中,那么我們要知道如果找到key的位置,就有必要了解一下dict 的結構了:
typedef struct dict {
// 特定於類型的處理 函數
dictType *type;
// 類型處理 函數的私有數據
void *privdata;
// 哈希表(2個)
dictht ht[2];
// 記錄 rehash 進度的標志,值為-1 表示 rehash 未進行
int rehashidx;
// 當前正在運作的安全 迭代器數量
int iterators;
} dict;
由上述的結構可以看出,redis 的字典使用 哈希表作為其底層實現。dict 類型使用的兩個指向 哈希表的指針,其中 0 號哈希表(ht[0])主要用於存儲數據庫的所有 鍵值,而1號哈希表主要用於程序對 0 號哈希表進行 rehash 時使用,rehash 一般是在添加新值時會觸發,這里不做過多的贅述。所以redis 中查找一個key,其實就是對進行該dict 結構中的 ht[0] 進行查找操作。
4、既然是哈希,那么我們知道就會有哈希碰撞,那么當多個鍵哈希之后為同一個值怎么辦呢?redis采取鏈表的方式來存儲多個哈希碰撞的鍵。也就是說,當根據key的 哈希值找到該列表后,如果列表的長度大於1,那么我們需要遍歷該鏈表來找到我們所查找的key。當然,一般情況下鏈表長度都為是1,所以 時間復雜度可看作o(1)。
二、當redis 拿到一個key 時,如果找到該key的位置。
了解了上述知識之后,我們就可以來分析redis如果在內存找到一個key了。
1、當拿到一個key后, redis 先判斷當前庫的0號哈希表是否為空,即:if (dict->ht[0].size == 0)。如果為true直接返回 NULL。
2、判斷該0號哈希表是否需要rehash,因為如果在進行rehash,那么兩個表中者有可能存儲該key。如果正在進行rehash,將調用一次_dictRehashStep方法,_dictRehashStep 用於對數據庫字典、以及哈希鍵的字典進行被動 rehash,這里不作贅述。
3、計算哈希表,根據當前字典與key進行 哈希值的計算。
4、根據 哈希值與當前字典計算哈希表的索引值。
5、根據索引值在哈希表中取出鏈表,遍歷該鏈表找到key的位置。一般情況,該鏈表長度為1。
6、當 ht[0] 查找完了之后,再進行了次rehash判斷,如果未在rehashing,則直接結束,否則對ht[1]重復345步驟。
到此我們就找到了key在內存中的位置了。
轉自:https://www.cnblogs.com/EasonJim/p/7818004.html