近來遇到一個問題,使用redis的哈希對象存儲數據,發現redis的內存耗用是單純存進去的數據的兩倍多,希望能夠找到有效的方法縮減這部分多出來的空間。
經過一番研究,是由於存儲的時候,具體的存儲結構使用的是hashtable來存儲的,hashtable使用的內存大小是數據的兩倍。一開始的時候懷疑是SDS預留出來的空間,但是經過測試,發現SDS在初始創建對象的時候是不會預留空間的,只會在出現修改的情況下預留出一倍的空間(數據小於1M時)。具體去查看源代碼去查找問題,奈何功底太差,呵呵,沒看出在什么地方還有預留的空間。希望知道的人不吝賜教。
由於我們的數據不是太大,僅僅只是value值的長度比默認的 hash-max-ziplist-value 多出了20個字節。所以,就在考慮着增大這個值,使用ziplist來存儲數據。結果證明,確實是比hashtable少用了一半的空間。也就是說內存方面的問題確實可以通過這個問題解決,雖然沒有弄明白hashtable多用出來的空間用在了什么地方。
但是,還有一個問題需要考慮,那就是ziplist每次添加或者刪除元素都會出現內存移動的問題,那么ziplist的效率是否跟hashtable會有比較大的差距。於是就有了下邊的測試:
1. 測試機器
centos虛擬機,2G內存。
2. redis版本
redis-2.8.19,aof與rdb全部關閉。
3. 測試程序
java,使用20個線程連接redis操作數據。
4. 數據
數據量在140w大小,每條數據含有4條記錄,與實際情況相近偏大一點。每條記錄key為20個字節,value為86個字節。
5. 結果
除初始化使用了140條數據,剩余的操作都是使用了20w的數據。
初始化(140w數據) | hmset | hgetall | hmset + hgetall | hdel | hset | 內存消耗 | |
hashtable | 168秒 | 24秒 | 24秒 | 49秒 | 24秒 | 23秒 | 1.29G |
ziplist | 166秒 | 24秒 | 24秒 | 47秒 | 23秒 | 23秒 | 620M |
看上面的結果,hashtable與ziplist在數據量很小的情況下,基本上性能是相差不多的,可以在數據量很小的情況下使用ziplist來縮小使用的內存,性能上是沒有太大問題的。
分析其原因,應該是使用ziplist僅僅只是在操作記錄的時候進行了一次的memmove,但是由於數據太小,消耗也就很小了。
當然,這個我暫時還沒有測試單條數據在大數據量的情況下的性能,在這種情況下性能是否還相差不多就不好說了。
如果上面的測試存在問題,請不吝賜教。