国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Redis 持久化方式

2019-11-08 20:38:37
字體:
來源:轉載
供稿:網友

非常感謝http://blog.csdn.net/zhu_tianwei/article/details/44893055

Redis由于支持非常豐富的內存數據結構類型,如何把這些復雜的內存組織方式持久化到磁盤上是一個難題,所以Redis的持久化方式與傳統數據庫的方式有比較多的差別,Redis一共支持四種持久化方式,分別是:1.定時快照方式(Snapshotting)2.基于語句追加文件的方式(Append-only file)3.虛擬內存(vm)4.Diskstore方式在設計思路上,前兩種是基于全部數據都在內存中,即小數據量下提供磁盤落地功能,而后兩種方式則是作者在嘗試存儲數據超過物理內存時,即大數據量的數據存儲,截止到本文,后兩種持久化方式仍然是在實驗階段,并且vm方式基本已經被作者放棄,所以實際能在生產環境用的只有前兩種,換句話說Redis目前還只能作為小數據量存儲(全部數據能夠加載在內存中),海量數據存儲方面并不是Redis所擅長的領域。下面分別介紹下這幾種持久化方式:一、定時快照方式(Snapshotting)快照是默認的持久化方式。這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名為dump.rdb。可以通過配置設置自動做快照持久化的方式。我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是默認的快照保存配置:

[plain] view plain copy PRint?在CODE上查看代碼片save 900 1  #900秒內如果超過1個key被修改,則發起快照保存  save 300 10 #300秒內容如超過10個key被修改,則發起快照保存  save 60 10000  快照保存過程:1.redis調用fork,現在有了子進程和父進程。2.父進程繼續處理client請求,子進程負責將內存內容寫入到臨時文件。由于os的寫時復制機制(copy%20on%20write)父子進程會共享相同的物理頁面,當父進程處理寫請求時os會為父進程要修改的頁面創建副本,而不是寫共享的頁面。所以子進程的地址空間內的數據是fork時刻整個數據庫的一個快照。3.當子進程將快照寫入臨時文件完畢后,用臨時文件替換原來的快照文件,然后子進程退出(fork一個進程入內在也被復制了,即內存會是原來的兩倍)。client%20也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主線程中保存快照的,由于redis是用一個主線程來處理所有%20client的請求,這種方式會阻塞所有client請求。所以不推薦使用。另一點需要注意的是,每次快照持久化都是將內存數據完整寫入到磁盤一次,并不是增量的只同步臟數據。如果數據量大的話,而且寫操作比較多,必然會引起大量的磁盤io操作,可能會嚴重影響性能。另外由于快照方式是在一定間隔時間做一次的,所以如果redis意外down掉的話,就會丟失最后一次快照后的所有修改。如果應用要求不能丟失任何修改的話,可以采用aof持久化方式。二、基于語句追加方式(Append-only%20file)aof比快照方式有更好的持久化性,是由于在使用aof持久化方式時,redis會將每一個收到的寫命令都通過write函數追加到文件中(默認是appendonly.aof)。當redis重啟時會通過重新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。當然由于os會在內核中緩存%20write做的修改,所以可能不是立即寫到磁盤上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過配置文件告訴redis我們想要通過fsync函數強制os寫入到磁盤的時機。有三種方式如下(默認是:每秒fsync一次):[plain] view%20plain copy print?appendonly yes           #啟用aof持久化方式  # appendfsync always   #每次收到寫命令就立即強制寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用  appendfsync everysec     #每秒鐘強制寫入磁盤一次,在性能和持久化方面做了很好的折中,推薦  # appendfsync no    #完全依賴os,性能最好,持久化沒保證  aof%20的方式也同時帶來了另一個問題。持久化文件會變的越來越大。例如我們調用incr%20test命令100次,文件中必須保存全部的100條命令,其實有99條都是多余的。因為要恢復數據庫的狀態其實文件中保存一條set%20test%20100就夠了。為了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照類似的方式將內存中的數據以命令的方式保存到臨時文件中,最后替換原來的文件。具體過程如下:1.redis調用fork%20,現在有父子兩個進程2.子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令3.父進程繼續處理client請求,除了把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就能保證如果子進程重寫失敗的話并不會出問題。4.當子進程把快照內容寫入已命令方式寫到臨時文件中后,子進程發信號通知父進程。然后父進程把緩存的寫命令也寫入到臨時文件。5.現在父進程可以使用臨時文件替換老的aof文件,并重命名,后面收到的寫命令也開始往新的aof文件中追加。需要注意到是重寫aof文件的操作,并沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點類似。三、虛擬內存方式(desprecated)首先說明:在Redis-2.4后虛擬內存功能已經被deprecated了,原因如下:1)slow%20restart重啟太慢2)slow%20saving保存數據太慢3)slow%20replication上面兩條導致%20replication%20太慢4)complex%20code代碼過于復雜下面還是介紹一下redis的虛擬內存。redis的虛擬內存與os的虛擬內存不是一碼事,但是思路和目的都是相同的。就是暫時把不經常訪問的數據從內存交換到磁盤中,從而騰出寶貴的內存空間用于其他需要訪問的數據。尤其是對于redis這樣的內存數據庫,內存總是不夠用的。除了可以將數據分割到多個redis%20server外。另外的能夠提高數據庫容量的辦法就是使用vm把那些不經常訪問的數據交換的磁盤上。如果我們的存儲的數據總是有少部分數據被經常訪問,大部分數據很少被訪問,對于網站來說確實總是只有少量用戶經常活躍。當少量數據被經常訪問時,使用vm不但能提高單臺redis%20server數據庫的容量,而且也不會對性能造成太多影響。redis沒有使用os提供的虛擬內存機制而是自己在用戶態實現了自己的虛擬內存機制,作者在自己的blog專門解釋了其中原因。http://antirez.com/post/redis-virtual-memory-story.html主要的理由有兩點:1.os%20的虛擬內存是已4k頁面為最小單位進行交換的。而redis的大多數對象都遠小于4k,所以一個os頁面上可能有多個redis對象。另外redis的集合對象類型如list,set可能存在與多個os頁面上。最終可能造成只有10%key被經常訪問,但是所有os頁面都會被os認為是活躍的,這樣只有內存真正耗盡時os才會交換頁面。2.相比于os的交換方式。redis可以將被交換到磁盤的對象進行壓縮,保存到磁盤的對象可以去除指針和對象元數據信息。一般壓縮后的對象會比內存中的對象小10倍。這樣redis的vm會比os%20vm能少做很多io操作。下面是vm相關配置:[plain] view%20plain copy print?slaveof 192.168.1.1 6379  #指定master的dsKeyToPath(key):  char path[1024];  char *hashKey = sha1(key);  path[0] = hashKey[0];  path[1] = hashKey[1];  path[2] = '/';  path[3] = hashKey[2];  path[4] = hashKey[3];  path[5] = '/';  memcpy(path + 6, hashKey, 40);  return path;  存儲算法(如key%20==%20apple):[cpp] view%20plain copy print?dsSet(key, value, expireTime):  // d0be2dc421be4fcd0172e5afceea3970e2f3d940  char *hashKey = sha1(key);  // d0/be/d0be2dc421be4fcd0172e5afceea3970e2f3d940  char *path = dsKeyToPath(hashKey);  FILE *fp = fopen(path, "w");  rdbSaveKeyValuePair(fp, key, value, expireTime);  fclose(fp)  獲取算法:[cpp] view%20plain copy print?dsGet(key):  char *hashKey = sha1(key);  char *path = dsKeyToPath(hashKey);  FILE *fp = fopen(path, "r");  robj *val = rdbLoadObject(fp);  return val;  

不過DiskStore有個缺點,就是有可能發生兩個不同的Key生成一個相同的SHA1%20Hash值,這樣就有可能出現丟失數據的問題。不過這種情況發生的幾率比較少,所以是可以接受的。根據作者的意圖,未來可能使用B+tree來替換這種高度依賴文件系統的實現方法。

另外,Redis持久化磁盤IO方式及其帶來的問題

有Redis線上運維經驗的人會發現Redis在物理內存使用比較多,但還沒有超過實際物理內存總容量時就會發生不穩定甚至崩潰的問題,有人認為是基于快照方式持久化的fork系統調用造成內存占用加倍而導致的,這種觀點是不準確的,因為fork%20調用的copy-on-write機制是基于操作系統頁這個單位的,也就是只有有寫入的臟頁會被復制,但是一般你的系統不會在短時間內所有的頁都發生了寫入而導致復制,那么是什么原因導致Redis崩潰的呢?答案是Redis的持久化使用了Buffer%20IO造成的,所謂Buffer%20IO是指Redis對持久化文件的寫入和讀取操作都會使用物理內存的Page%20Cache,而大多數數據庫系統會使用Direct%20IO來繞過這層Page%20Cache并自行維護一個數據的Cache,而當Redis的持久化文件過大(尤其是快照文件),并對其進行讀寫時,磁盤文件中的數據都會被加載到物理內存中作為操作系統對該文件的一層Cache,而這層Cache的數據與Redis內存中管理的數據實際是重復存儲的,雖然內核在物理內存緊張時會做Page%20Cache的剔除工作,但內核很可能認為某塊Page%20Cache更重要,而讓你的進程開始Swap%20,這時你的系統就會開始出現不穩定或者崩潰了。我們的經驗是當你的Redis物理內存使用超過內存總容量的3/5時就會開始比較危險了。下圖是Redis在讀取或者寫入快照文件dump.rdb后的內存數據圖:總結:1.根據業務需要選擇合適的數據類型,并為不同的應用場景設置相應的緊湊存儲參數。2.當業務場景不需要數據持久化時,關閉所有的持久化方式可以獲得最佳的性能以及最大的內存使用量。3.如果需要使用持久化,根據是否可以容忍重啟丟失部分數據在快照方式與語句追加方式之間選擇其一,不要使用虛擬內存以及diskstore方式。4.不要讓你的Redis所在機器物理內存使用超過實際內存總量的3/5。

轉至:

http://blog.csdn.net/freebird_lb/article/details/7778981

http://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storage


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 勃利县| 白河县| 罗江县| 广汉市| 资阳市| 五大连池市| 长寿区| 沧州市| 南皮县| 太原市| 湘乡市| 临沭县| 广宗县| 垣曲县| 利辛县| 汉阴县| 深州市| 任丘市| 军事| 襄樊市| 卓尼县| 襄城县| 北流市| 宜川县| 高雄市| 黑龙江省| 滨州市| 仙桃市| 肥东县| 元氏县| 澎湖县| 吉隆县| 祁阳县| 大同市| 新干县| 乐山市| 镇安县| 瓮安县| 英吉沙县| 任丘市| 巴南区|