亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

一、兩者比較

RDB的數據不實時,同時使用兩者時服務器重啟也只會找AOF文件。那要不要只使用AOF呢?作者建議不要,因為RDB更適合用于備份數據庫(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的bug,留著作為一個萬一的手段。

1.性能:Snapshot方式的性能是要明顯高于AOF方式的,原因有兩點:

1)采用二進制方式存儲數據,數據文件比較小,加載快速.

2)存儲的時候是按照配置中的save策略來存儲,每次都是聚合很多數據批量存儲,寫入的效率很好,而AOF則一般都是工作在實時存儲或者準實時模式下。相對來說存儲的頻率高,效率卻偏低。

3) 對于redis的服務進程而言,在開始持久化時,它唯一需要做的只是fork出子進程,之后再由子進程完成這些持久化的工作,這樣就可以極大的避免服務進程執行IO操作了。

2.數據安全:AOF數據安全性高于Snapshot存儲,原因:

Snapshot存儲是基于累計批量的思想,也就是說在允許的情況下,累計的數據越多那么寫入效率也就越高,但數據的累計是靠時間的積累完成的,那么如果在長時間數據不寫入RDB,但Redis又遇到了崩潰,那么沒有寫入的數據就無法恢復了,但是AOF方式偏偏相反,根據AOF配置的存儲頻率的策略可以做到最少的數據丟失和較高的數據恢復能力。

RDB優勢:

1). 備份策略方便:一旦采用該方式,那么你的整個Redis數據庫將只包含一個文件,這對于文件備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的數據,同時還要每天歸檔一次最近30天的數據。通過這樣的備份策略,一旦系統出現災難性故障,我們可以非常容易的進行恢復。

2). 災難恢復方便:,RDB是非常不錯的選擇。因為我們可以非常輕松的將一個單獨的文件壓縮后再轉移到其它存儲介質上。

3). 性能最大化:對于Redis的服務進程而言,在開始持久化時,它唯一需要做的只是fork出子進程,之后再由子進程完成這些持久化的工作,這樣就可以極大的避免服務進程執行IO操作了。

4). 啟動效率高:相比于AOF機制,如果數據集很大,RDB的啟動效率會更高。

RDB缺點:

1). 數據的可靠性不高,沒辦法做到實時持久化:如果你想保證數據的高可用性,即最大限度的避免數據丟失,那么RDB將不是一個很好的選擇。因為系統一旦在定時持久化之前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失。

2). 影響性能:由于RDB是通過fork子進程來協助完成數據持久化工作的,因此,如果當數據集較大時,可能會導致整個服務器停止服務幾百毫秒,甚至是1秒鐘。

3)版本兼容RDB格式問題

AOF的優點:

1). 數據安全性:該機制可以帶來更高的數據安全性,即數據持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事實上,每秒同步也是異步完成的,其效率也是非常高的,所差的是一旦系統出現宕機現象,那么這一秒鐘之內修改的數據將會丟失。而每修改同步,我們可以將其視為同步持久化,即每次發生的數據變化都會被立即記錄到磁盤中??梢灶A見,這種方式在效率上是最低的。

2). 數據一致性:由于該機制對日志文件的寫入操作采用的是Append模式,因此在寫入過程中即使出現宕機現象,也不會破壞日志文件中已經存在的內容。然而如果我們本次操作只是寫入了一半數據就出現了系統崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決數據一致性的問題。

3). 如果日志過大,Redis可以自動啟用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會創建一個新的文件用于記錄此期間有哪些修改命令被執行。因此在進行rewrite切換時可以更好的保證數據安全性。

4). AOF包含一個格式清晰、易于理解的日志文件用于記錄所有的修改操作。事實上,我們也可以通過該文件完成數據的重建。

AOF的缺點:

1). 恢復速度慢:對于相同數量的數據集而言,AOF文件通常要大于RDB文件。RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。

2). 性能低:根據同步策略的不同,AOF在運行效率上往往會慢于RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。

二者選擇的標準,就是看系統是愿意犧牲一些性能,換取更高的緩存一致性(aof),還是愿意寫操作頻繁的時候,不啟用備份來換取更高的性能,待手動運行save的時候,再做備份(rdb)。rdb這個就更有些 eventually consistent的意思了。

二、Redis持久化磁盤IO方式及其帶來的問題

1、RDB持久化可能導致系統內存不足導致redis 被 oom kill

發現Redis在物理內存使用比較多,但還沒有超過實際物理內存總容量時就會發生不穩定甚至崩潰的問題。

redis持久化AOF重寫和RDB寫入都是通過fork產生子進程來操作,AOF重寫和RDB寫入都是通過fork產生子進程來操作,理論上需要兩倍的內存來完成持久化操作,但linux有寫時復制機制(copy-on-write),父子進程會共享相同的物理內存頁(只有有寫入的臟頁會被復制), 當父進程處理寫請求時會把要修改的頁創建副本,而子進程在fork操作過程中共享整個父進程內存快照。避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。

但是由于Redis的持久化使用了Buffer IO,所謂Buffer IO是指Redis對持久化文件的寫入和讀取操作都會使用物理內存的Page Cache, 而大多數數據庫系統會使用Direct IO來繞過這層Page Cache并自行維護一個數據的Cache,而當Redis的持久化文件過大(尤其是快照RDB文件),并對其進行讀寫時,磁盤文件中的數據都會被加載到物理內存中作為操作系統對該文件的一層Cache,而這層Cache的數據與Redis內存中管理的數據實際是重復存儲的,雖然內核在物理內存緊張時會做Page Cache的剔除工作,但內核很可能認為某塊Page Cache更重要,而讓你的進程開始Swap ,這時你的系統就會開始出現不穩定或者崩潰了。我們的經驗是當你的Redis物理內存使用超過內存總容量的3/5時就會開始比較危險了。

下圖是Redis在讀取或者寫入快照文件dump.rdb后的內存數據圖:

2、持久化Fork引起redis主進程阻塞

AOF重寫和RDB寫入都是通過fork產生子進程來操作,子進程占用內存大小等同于父進程,理論上需要兩倍的內存來完成持久化操作,但Linux有寫時復制機制(copy-on-write)。父子進程會共享相同的物理內存頁,當父進程處理寫請求時會把要修改的頁創建副本,而子進程在fork操作過程中共享整個父進程內存快照。避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。

測試把benchmark的11G數據寫成一個1.3的RDB文件,或者等大的AOF文件rewrite,需要80秒,在redis-cli info中可查看。啟動時載入一個AOF或RDB文件的速度與上面寫入時相同,在log中可查看。

Fork一個使用了大量內存的進程也要時間,大約10ms per GB的樣子,但Xen在EC2上是讓人郁悶的239ms (KVM和VMWare貌似沒有這個毛病),各種系統的對比,Info指令里的latest_fork_usec顯示上次花費的時間。

3、在AOF持久化重寫時,AOF重寫緩沖區的指令追加新文件和改名替換造成阻塞:

在AOF持久化過程中,所有新來的寫入請求依然會被寫入舊的AOF文件,同時放到buffer中,當rewrite完成后,會在主線程把這部分內容合并到臨時文件中之后才rename成新的AOF文件,所以rewrite過程中會不斷打印”Background AOF buffer size: xx MB, Background AOF buffer size: xxMB”,這個合并的過程是阻塞的,如果你產生了280MB的buffer,在100MB/s的傳統硬盤 上,Redis就要阻塞2.8秒!!!

4、持久化的系統IO阻塞redis主進程的問題

持久化很容易造成阻塞,不管是AOF rewrite,還是RDB bgsave,都有可能會出現阻塞,原因是一般情況下,如果Redis服務設置了appendfsync everysec, 主進程每秒鐘便會調用fsync, 將數據寫到存儲磁盤里. 但由于服務器的重寫子進程正在進行大量IO操作, 導致主進程fsync/操作被阻塞, 最終導致Redis主進程阻塞.解決方案這里就不多說了

5、Redis持久化性能調整

因為RDB文件只用作后備用途,建議只在Slave上持久化RDB文件,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。

如果啟用AOF,好處是在最惡劣情況下也只會丟失不超過兩秒數據,啟動腳本較簡單只load自己的AOF文件就可以了。代價一是帶來了持續的IO,二是AOF rewrite的最后將rewrite過程中產生的新數據寫到新文件造成的阻塞幾乎是不可避免的。只要硬盤許可,應該盡量減少AOF rewrite的頻率,AOF重寫的基礎大小默認值64M太小了,可以設到5G以上。默認超過原大小100%大小時重寫可以改到適當的數值,比如之前的 benchmark每個小時會產生40G大小的AOF文件,如果硬盤能撐到半夜系統閑時才用cron調度bgaofrewrite就好了。

如 果不Enable AOF ,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時倒掉,會丟失十幾分鐘的數據,啟 動腳本也要比較兩個Master/Slave中的RDB文件,載入較新的那個。新浪微博就選用了這種架構,見Tim的博客

三、 實際問題

1、Trouble Shooting —— Enable AOF可能導致整個Redis被Block住,在2.6.12版之前

現象描述:當AOF rewrite 15G大小的內存時,Redis整個死掉的樣子,所有指令甚至包括slave發到master的ping,redis-cli info都不能被執行。

原因分析:

官方文檔,由IO產生的Latency詳細分析, 已經預言了悲劇的發生,但一開始沒留意。

Redis為求簡單,采用了單請求處理線程結構。

打開AOF持久化功能后, Redis處理完每個事件后會調用write(2)將變化寫入kernel的buffer,如果此時write(2)被阻塞,Redis就不能處理下一個事件。

Linux規定執行write(2)時,如果對同一個文件正在執行fdatasync(2)將kernel buffer寫入物理磁盤,或者有system wide sync在執行,write(2)會被block住,整個Redis被block住。

如 果系統IO繁忙,比如有別的應用在寫盤,或者Redis自己在AOF rewrite或RDB snapshot(雖然此時寫入的是另一個臨時文件,雖然各自都在連續寫,但兩個文件間的切換使得磁盤磁頭的尋道時間加長),就可能導致 fdatasync(2)遲遲未能完成從而block住write(2),block住整個Redis。

為了更清晰的看到fdatasync(2)的執行時長,可以使用”strace -p (pid of redis server) -T -e -f trace=fdatasync”,但會影響系統性能。

Redis 提供了一個自救的方式,當發現文件有在執行fdatasync(2)時,就先不調用write(2),只存在cache里,免得被block。但如果已經 超過兩秒都還是這個樣子,則會硬著頭皮執行write(2),即使redis會被block住。此時那句要命的log會打印:“Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.” 之后用redis-cli INFO可以看到aof_delayed_fsync的值被加1。

因此,對于fsync設為everysec時丟失數 據的可能性的最嚴謹說法是:如果有fdatasync在長時間的執行,此時redis意外關閉會造成文件里不多于兩秒的數據丟失。如果fdatasync 運行正常,redis意外關閉沒有影響,只有當操作系統crash時才會造成少于1秒的數據丟失。

解決方法:

然后提了個issue,AOF rewrite時定時也執行一下fdatasync嘛, antirez三分鐘后就回復了,新版中,AOF rewrite時32M就會重寫主動調用fdatasync。

2、Redis log 一直在報錯:background: fork: Cannot allocate memory

Redis數據回寫機制

數據回寫分同步和異步兩種方式

同步回寫(SAVE), 主進程直接向磁盤回寫數據. 在數據量大的情況下會導致系統假死很長時間

異步回寫(BGSAVE), 主進程fork后, 復制自身并通過這個新的進程回寫磁盤, 回寫結束后新進程自行關閉.

由于 BGSAVE 不需要主進程阻塞, 系統也不會假死, 一般會采用 BGSAVE 來實現數據回寫.

故障分析

在小內存的進程上做fork, 不需要太多資源. 但當這個進程的內存空間以G為單位時, fork就成為一件很恐怖的操作.

在16G內存的足跡上fork 14G的進程, 系統肯定Cannot allocate memory.

主機的Redis 改動的越頻繁 fork進程也越頻繁, 所以一直在Cannot allocate memory

解決方案:

1、redis有個默認的選項:

stop-writes-on-bgsave-error yes

這個選項默認情況下,如果在RDB snapshots持久化過程中出現問題,設置該參數后,Redis是不允許用戶進行任何更新操作。

不徹底的解決方式是,將這個選項改為false,但是這樣只是當redis寫硬盤快照出錯時,可以讓用戶繼續做更新操作,但是寫硬盤仍然是失敗的;

2、徹底的解決方式:直接修改內核參數 vm.overcommit_memory

直接修改內核參數 vm.overcommit_memory = 1, Linux內核會根據參數vm.overcommit_memory參數的設置決定是否放行。

編輯/etc/sysctl.conf ,改vm.overcommit_memory=1

vm.overcommit_memory = 1,直接放行

vm.overcommit_memory = 0:則比較 此次請求分配的虛擬內存大小和系統當前空閑的物理內存加上swap,決定是否放行。

vm.overcommit_memory = 2:則會比較進程所有已分配的虛擬內存加上此次請求分配的虛擬內存和系統當前的空閑物理內存加上swap,決定是否放行。

執行sysctl -p使其生效;

vm.overcommit_memory 的作用

Linux對大部分申請內存的請求都回復"yes",以便能跑更多更大的程序。因為申請內存后,并不會馬上使用內存,將這些不會使用的空閑內存分配給其它程序使用,以提高內存利用率,這種技術叫做Overcommit。一般情況下,當所有程序都不會用到自己申請的所有內存時,系統不會出問題,但是如果程序隨著運行,需要的內存越來越大,在自己申請的大小范圍內,不斷占用更多內存,直到超出物理內存,當linux發現內存不足時,會發生OOM killer(OOM=out-of-memory)。它會選擇殺死一些進程(用戶態進程,不是內核線程,哪些占用內存越多,運行時間越短的進程越有可能被殺掉),以便釋放內存。

當oom-killer發生時,linux會選擇殺死哪些進程?選擇進程的函數是oom_badness函數(在mm/oom_kill.c中),該函數會計算每個進程的點數(0~1000)。點數越高,這個進程越有可能被殺死。每個進程的點數跟(/proc/<pid>/oom_adj)oom_score_adj有關,而且oom_score_adj可以被設置(-1000最低,1000最高)。

當發生oom killer時,會將記錄在系統日志中/var/log/messages

分享到:
標簽:Redis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定