引子
今天遇到一個面試題,若是機器內存是4G,redis已經佔用了2G內存,這裏redis執行RDB持久化,可否持久化成功? 上一秒還在說本身熟悉redis,下一秒就被光速打臉了,發現本身竟然沒有深刻了解過redis的RDB持久化的機制。面試
1、Redis持久化的方式
redis持久化方式分爲兩種,分別是RDB和AOF。redis
- RDB(Redis DataBase):將某一時刻內存的數據以二進制的形式保存到磁盤中,RDB的數據完整性比不上AOF,可是對redis的QPS不會有太大的影響。
- AOF(Append Only File):將redis執行的命令按順序不斷追加到文件中,相似於MySQL的binlog日誌。 其中,RDB持久化又涉及到兩個操做命令,save和bgsave。
- save:通常是手動操做,會阻塞redis主進行執行。
- bgsave:經過配置文件來完成的RDB,執行的是bgsave命令,redis會fork一個子進程來執行持久化,只有在fork子進程的過程當中會短暫阻塞redis主進程,持久化的過程不會對主進行有影響。
2、fork和copyonwrite
Redis執行RDB持久化,主要依賴的是fork和copyonwrite技術。
fork函數是操做系統的API,用於從一個進程中建立一個子進程,這個子進程和父進程共享全部的內存信息、上下文、代碼區、引用的資源等。可是,這樣在子進程執行持久化的過程當中,主進程把內存中的數據修改了會怎麼辦呢?這裏就會使用到copyonwrite技術。ide
- 當主進程fork一個子進程出來後,內核會把主進程全部的內存頁都設置成read-only,此時,主進程和子進程都指向一樣的內存地址。
- 當主進程須要對內存進行修改時,發現須要修改的內存頁是read-only狀態,此時會觸發一頁異常中斷(page-fault)。內核會把須要修改的數據頁複製一份,把主進程的地址指向新的複製數據頁。
- 最後主進程再在新的內存數據頁上進行修改操做。
3、總結
根據上面的技術,redis在執行RDB持久化的時候,持久化的內存數據就只會是fork子進程那一刻的內存數據,後續新的請求對持久化不會有影響。回到上面的面試題,redis是能夠執行持久化成功的。函數
4、其它問題
- RDB的過程當中,每次更新數據都須要複製一份原有的數據,對redis的性能是否會有影響? 由於redis的使用場景大部分是讀多寫少的場景,所以更新數據時須要先對原數據複製對redis帶來的性能影響是能夠接受的。