這一節(jié)我們先簡單聊一下redis配置與版本注意事項,涉及到配置,鍵的過期、32位redis和64位的區(qū)別,后續(xù)我們再來了解Redis LRU鍵的驅(qū)逐策略以及具體的優(yōu)化策略。
1、配置redis
如果要運行一個高效的redis,我們必須要理解redis.conf文件中所有的內(nèi)存相關(guān)指令,當然redis.conf文件提供了豐富內(nèi)聯(lián)文檔使我們可以更好的理解、更改和測試相關(guān)配置項,本節(jié)我們先簡單回顧用來配置redis的內(nèi)存相關(guān)的指令,這些都可以在redis.conf文件中進行設(shè)置,在運行時我們可以通過CONFIG SET指令來設(shè)置。
- rdbchecksum:默認值為Yes,將一個65位的冗余檢驗碼(CRC64)放在RDB快照文件的尾末(RDB是redis持久化文件的一種,請參考面試官問:Redis數(shù)據(jù)丟失咋辦?如何持久化它?),以此來發(fā)防止文件損壞,當redis開啟子進程將數(shù)據(jù)持久化到RDB快照文件時,而我們需要注意的是對快照文件進行CRC64校驗會增加10%的內(nèi)存使用。
- activerehashing:如果設(shè)置為yes,那么redis會在每隔100毫秒會重新哈希,重新哈希會是釋放已經(jīng)刪除的鍵所占用的內(nèi)存空間,如果對redis服務(wù)器沒有指定硬性響應(yīng)時間,建議設(shè)置為no,從而及時釋放內(nèi)存,說白設(shè)置為no可以提高響應(yīng)速率,但內(nèi)存占用較大,設(shè)置為yes后及時釋放了內(nèi)存空間,但遇到高并發(fā)量的客戶端時可能降低了響應(yīng)時間。
- slave-of:主從復(fù)制可以提高可伸縮性,如果你的redis運行在集群環(huán)境中我們可以通過slave-of指令將redis切換到從模式,這是該從實例可以從另一個被指定為主實例的redis中復(fù)制數(shù)據(jù),主從模式下提升redis的冗余度是在內(nèi)存、硬件和網(wǎng)絡(luò)IO之間做出的權(quán)衡。
2、鍵過期
保證redis數(shù)據(jù)庫不會內(nèi)存溢出簡單有可靠的方法是為鍵設(shè)置過期時間,有了過期時間鍵會自動被驅(qū)逐,為你應(yīng)用程序設(shè)計一套高效的過期策略可以使你的內(nèi)存需求更高效可控,我們需要注意的是一旦在鍵上調(diào)用EXPIRE命令來設(shè)置過期時間,該超時只能通過刪除或替換鍵的方式清除,任何改變值的操作都不能清除該設(shè)置的超時:
redis>SET myname aa #設(shè)置一個key為myname的鍵
ok
redis>EXPIRE myname 300 #過期時間設(shè)為300秒
(integer) 1
redis>TTL myname #檢測一下過期時間
(integer) 287
redis>AppEND myname pp #使用append命令追加值
(integer) 4
redis>GET myname #查看新值
"aapp"
redis>TTL myname #再次檢測一下過期時間
"259"
可以看到值被修改后超時依然存在,如果需要清除這個超時設(shè)置可以在這個鍵上調(diào)用set或getset命令,ttl返回-1表示沒有設(shè)置超時時間的默認值:
redis> TTL myname #檢測過期時間
(integer) 200
redis> SET myname cc #set命令
ok
redis> TTL myname #再次檢測過期時間 值為-1
(integer) -1
redis>persist myname #也可以使用persist命令來清除鍵的過期時間:
(integer) 1
redis>persist myname #也可以使用persist命令來清除鍵的過期時間:
(integer) 1
需要注意的是如果對一個鍵設(shè)了過期時間,但此時數(shù)據(jù)庫進程被關(guān)閉了,在redis重啟之后會自動驅(qū)逐該鍵值。
3、32位的redis
對于小于3GB數(shù)據(jù)集情況下,在32位redis實例中要比64為版本小、這里我們來看兩個redis實例:redisIns32,redisIns64,然后在Python命令行創(chuàng)建測試函數(shù),分別對每個實例設(shè)置10000個鍵值對:
>>> def myrRedisTest():
for i in range(10000):
key = "uuid:{}".format(i)
value=uuid.uuid4()
redisIns32.set(key,value)
redisIns64.set(key,value)
>>>def myrRedisTest()
再來看下redis中使用INFO memory查看內(nèi)存使用情況:
#32位redis實例輸出
redis>INFO memory
...
used_memory_human:11.87M #redis分配的內(nèi)存大小
used_peak_human:11.87M #redis使用峰值內(nèi)存
...
#64位redis實例輸出
redis>INFO memory
...
used_memory_human:14.18M #redis分配的內(nèi)存大小
used_peak_human:14.18M #redis使用峰值內(nèi)存
...
我們看到了相同的數(shù)據(jù)32位實例和64位實例的內(nèi)部占用差異,下面我們列舉一百萬個整數(shù)、浮點數(shù)、字符串、哈希結(jié)構(gòu)以及列表使用的內(nèi)存對比。
整數(shù)、浮點數(shù)、字符串的測試對比:
一百萬個整數(shù)、浮點數(shù)、字符串redis使用版本比較
- 圖中顯示如果使用整數(shù),64位redis多使用了36%的內(nèi)存,只要redis總使用內(nèi)存不超過4GB,那32位版本的redis節(jié)省的內(nèi)存也是很可觀了。
- 對于大量使用集合字符串的應(yīng)用來說,顯然64位版本的redis多出的內(nèi)存不太明顯,僅僅多了22%,并且64位版本的redis對字符串有大量的額外空間和編碼優(yōu)化,所以推薦使用64位版本。
哈希結(jié)構(gòu)對比:
哈希數(shù)據(jù)結(jié)構(gòu)內(nèi)存使用對比
對于哈希結(jié)構(gòu)來說,無論存儲什么類型,32位和64位之間差異都是基本定在了19-19.56之間。
列表結(jié)構(gòu)對比
列表數(shù)據(jù)結(jié)構(gòu)的內(nèi)存使用對比
可以看到在32位限制之下,列表非常適合存儲整數(shù)和浮點數(shù),字符串在32位和64位之間的內(nèi)存使用率差異最小。
32位版本redis的注意事項
- 由于32位版本的redis并未在用戶群中廣發(fā)部署和測試,較于64位版本來說可能有未發(fā)現(xiàn)的bug。
- 諸如BITOP和BITCOUNT的位操作、字符串都在64位版本上做了優(yōu)化。
- 如果redis配置中參數(shù)maxmemory值設(shè)置的過于接近4GB,那么redis在通信、復(fù)制、IO緩存都有可能阻塞甚至崩潰。
個人理解有所紕漏,還請老鐵們多多指教,下一節(jié)我們來講解【Redis LRU鍵的驅(qū)逐策略】后續(xù)持續(xù)更新!