一、Redis先執(zhí)行指令,再記錄AOF日志的原因
Redis是一種內(nèi)存數(shù)據(jù)庫,對于大多數(shù)的操作,Redis會先將請求寫入內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),然后再異步地將修改同步到磁盤上的AOF(Append-Only File)文件中,這就是非常高效的原因。Redis的性能很大程度上取決于CPU的速度和內(nèi)存的大小。因此,Redis選擇將大部分?jǐn)?shù)據(jù)保存在內(nèi)存中,以提高運(yùn)行速度。Redis 的數(shù)據(jù)是存內(nèi)存的,斷電之后就丟了。Redis 的 AOF / RDB 相當(dāng)于有一個把硬盤當(dāng)內(nèi)存的 slave。存儲引擎數(shù)據(jù)是存硬盤的,斷電之后,可能有臟數(shù)據(jù),也可能沒有,需要 redo log / undo log 來做原子 commit。保護(hù) commit 的數(shù)據(jù)是不可能在 commit 之后寫的。存儲引擎的日志只保護(hù) uncommitted data。
二、Redis 在 Java Web 中的應(yīng)用
1、緩存
在日常對數(shù)據(jù)庫的訪問中,讀操作的次數(shù)遠(yuǎn)超寫操作,比例大概在?1:9?到?3:7,所以需要讀的可能性是比寫的可能大得多的。當(dāng)我們使用SQL語句去數(shù)據(jù)庫進(jìn)行讀寫操作時,數(shù)據(jù)庫就會去磁盤把對應(yīng)的數(shù)據(jù)索引取回來,這是一個相對較慢的過程。
如果我們把數(shù)據(jù)放在 Redis 中,也就是直接放在內(nèi)存之中,讓服務(wù)端直接去讀取內(nèi)存中的數(shù)據(jù),那么這樣速度明顯就會快上不少,并且會極大減小數(shù)據(jù)庫的壓力,但是使用內(nèi)存進(jìn)行數(shù)據(jù)存儲開銷也是比較大的,限于成本的原因,一般我們只是使用 Redis 存儲一些常用和主要的數(shù)據(jù),比如用戶登錄的信息等。
一般而言在使用 Redis 進(jìn)行存儲的時候,我們需要從以下幾個方面來考慮:
**業(yè)務(wù)數(shù)據(jù)常用嗎?命中率如何?**如果命中率很低,就沒有必要寫入緩存;**該業(yè)務(wù)數(shù)據(jù)是讀操作多,還是寫操作多?**如果寫操作多,頻繁需要寫入數(shù)據(jù)庫,也沒有必要使用緩存;**業(yè)務(wù)數(shù)據(jù)大小如何?**如果要存儲幾百兆字節(jié)的文件,會給緩存帶來很大的壓力,這樣也沒有必要。在考慮了這些問題之后,如果覺得有必要使用緩存,那么就使用它。
當(dāng)名列前茅次讀取數(shù)據(jù)的時候,讀取 Redis 的數(shù)據(jù)就會失敗,此時就會觸發(fā)程序讀取數(shù)據(jù)庫,把數(shù)據(jù)讀取出來,并且寫入 Redis 中;當(dāng)?shù)诙我约耙院笮枰x取數(shù)據(jù)時,就會直接讀取 Redis,讀到數(shù)據(jù)后就結(jié)束了流程,這樣速度就大大提高了。從上面的分析可以知道,讀操作的可能性是遠(yuǎn)大于寫操作的,所以使用 Redis 來處理日常中需要經(jīng)常讀取的數(shù)據(jù),速度提升是顯而易見的,同時也降低了對數(shù)據(jù)庫的依賴,使得數(shù)據(jù)庫的壓力大大減少。
分析了讀操作的邏輯,下面我們來看看寫操作的流程:
從流程可以看出,更新或者寫入的操作,需要多個 Redis 的操作,如果業(yè)務(wù)數(shù)據(jù)寫次數(shù)遠(yuǎn)大于讀次數(shù)那么就沒有必要使用 Redis。
2、高速讀/寫的場合
在如今的互聯(lián)網(wǎng)中,越來越多的存在高并發(fā)的情況,比如天貓雙11、搶紅包、搶演唱會門票等,這些場合都是在某一個瞬間或者是某一個短暫的時刻有成千上萬的請求到達(dá)服務(wù)器,如果單純的使用數(shù)據(jù)庫來進(jìn)行處理,就算不崩,也會很慢的,輕則造成用戶體驗極差用戶量流失,重則數(shù)據(jù)庫癱瘓,服務(wù)宕機(jī),而這樣的場合都是不允許的。所以我們需要使用 Redis 來應(yīng)對這樣的高并發(fā)需求的場合,我們先來看看一次請求操作的流程圖:
我們來進(jìn)一步闡述這個過程:
當(dāng)一個請求到達(dá)服務(wù)器時,只是把業(yè)務(wù)數(shù)據(jù)在 Redis 上進(jìn)行讀寫,而沒有對數(shù)據(jù)庫進(jìn)行任何的操作,這樣就能大大提高讀寫的速度,從而滿足高速響應(yīng)的需求;但是這些緩存的數(shù)據(jù)仍然需要持久化,也就是存入數(shù)據(jù)庫之中,所以在一個請求操作完 Redis 的讀/寫之后,會去判斷該高速讀/寫的業(yè)務(wù)是否結(jié)束,這個判斷通常會在秒殺商品為0,紅包金額為0時成立,如果不成立,則不會操作數(shù)據(jù)庫;如果成立,則觸發(fā)事件將 Redis 的緩存的數(shù)據(jù)以批量的形式一次性寫入數(shù)據(jù)庫,從而完成持久化的工作。三、AOF簡介
1、AOF持久化方式
AOF持久化方式是將redis的操作日志以追加的方式寫入磁盤文件中。AOF持久化是以日志的形式記錄服務(wù)器所處理的每一個寫、刪除操作,查詢操作不會記錄,以文本的方式記錄,可以打開文件看到詳細(xì)的操作記錄。
2、AOF實(shí)現(xiàn)方式
AOF(append only file)持久化是以獨(dú)立日志的方式記錄每次寫命令,重啟時再重新執(zhí)行AOF文件中命令達(dá)到恢復(fù)數(shù)據(jù)的目的。AOF的主要作用是解決了數(shù)據(jù)持久化的實(shí)時性,目前已經(jīng)是Redis持久化的主流方式。
3、AOF優(yōu)勢
該機(jī)制可以帶來更高的數(shù)據(jù)安全性,即數(shù)據(jù)持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。
每秒同步:事實(shí)上,每秒同步也是異步完成的,其效率也是非常高的,所差的是一旦系統(tǒng)出現(xiàn)宕機(jī)現(xiàn)象,那么這一秒鐘之內(nèi)修改的數(shù)據(jù)將會丟失。每次修改:而每修改同步,我們可以將其視為同步持久化,即每次發(fā)生的數(shù)據(jù)變化都會被立即記錄到磁盤中。不同步:可以預(yù)見,這種方式在效率上是最低的。至于無同步,無需多言,我想大家都能正確的理解它。由于該機(jī)制對日志文件的寫入操作采用的是append模式,因此在寫入過程中即使出現(xiàn)宕機(jī)現(xiàn)象,也不會破壞日志文件中已經(jīng)存在的內(nèi)容。如果我們本次操作只是寫入了一半數(shù)據(jù)就出現(xiàn)了系統(tǒng)崩潰問題,不用擔(dān)心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決數(shù)據(jù)一致性的問題。
如果日志過大,Redis可以自動啟用rewrite機(jī)制,壓縮和瘦身相關(guān)的aof文件。Redis以append模式不斷的將修改數(shù)據(jù)寫入到老的磁盤文件中,同時Redis還會創(chuàng)建一個臨時的新文件用于記錄此期間有哪些修改命令被執(zhí)行。因此在進(jìn)行rewrite切換時可以更好的保證數(shù)據(jù)安全性。
延伸閱讀1:AOF重寫機(jī)制
隨著命令不斷寫入AOF,文件會越來越大,為了解決這個問題,Redis引入了AOF重寫機(jī)制壓縮文件體積。AOF文件重寫是把Redis進(jìn)程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令同步到新AOF文件的過程。