redis 事务,持久化,日志,主从,VM
?
redis目前對(duì)事務(wù)的支持比較簡單,只能保證一個(gè)客戶端連接發(fā)起事務(wù)中的命令可以連續(xù)執(zhí)行,而中間不會(huì)插入其他客戶端的命令。
1.事務(wù)
一般情況下,redis接收到一個(gè)客戶端發(fā)送的命令,立刻執(zhí)行并返回結(jié)果。但是當(dāng)連接發(fā)出multi命令時(shí),此連接便進(jìn)入事務(wù)上下文,redis把此連接發(fā)送的命令保存到一個(gè)列隊(duì)當(dāng)中,當(dāng)此連接發(fā)送exec命令時(shí),redis便開始按順序執(zhí)行列隊(duì)中的所有命令,并將所有命令執(zhí)行的結(jié)果大包一起返回給客戶端連接,然后此連接便結(jié)束事務(wù)。
例如:
例子中可以看出set 命令發(fā)出后并沒有立即執(zhí)行,而是存放在消息列隊(duì)中。調(diào)用exec命令,set命令才開始連續(xù)執(zhí)行,最后返回執(zhí)行結(jié)果。
如果取消事務(wù),可以使用discard 命令取消一個(gè)事務(wù)例如:
?
discard命令的作用是清空事務(wù)列隊(duì)中的命令,并退出事務(wù)。
另外,redis只能保證事務(wù)的每個(gè)命令能夠連續(xù)執(zhí)行,但是事務(wù)中如果有命令執(zhí)行失敗,redis并不會(huì)回滾操作。
?2.持久化
redis 是基于內(nèi)存的數(shù)據(jù)庫,內(nèi)存數(shù)據(jù)庫有個(gè)嚴(yán)重的弊端:突然宕機(jī)或者斷電時(shí),內(nèi)容的數(shù)據(jù)不會(huì)保存。為了解決這個(gè)問題,redis提供兩種持久化方式:內(nèi)存快照(snapshotting)和日志追加(append-only file).
內(nèi)存快照方式是將內(nèi)存中的數(shù)據(jù)以快照的方式寫入二進(jìn)制文件中,默認(rèn)文件名為dump.rdb
redis每隔一段時(shí)間進(jìn)行一次內(nèi)存快照操作,客戶端使用save或者bgsave命令告訴redis需要做一次快照操作。save命令在主線程中保存內(nèi)存快照,redis由單線程處理所有請(qǐng)求,執(zhí)行save命令肯可能阻塞其他客戶端請(qǐng)求,從而不能快速的相應(yīng)請(qǐng)求,所以建議不要使用save命令。另外要注意,內(nèi)存快照每次都把數(shù)據(jù)完整的寫入到硬盤,而不是只寫入增量數(shù)據(jù)。所以如果數(shù)據(jù)量大,寫入操作比較頻繁,從而嚴(yán)重影響性能。
內(nèi)存快照相關(guān)配置:
save ?<seconds> ?<changes>
上面的配置表示經(jīng)過seconds秒或數(shù)據(jù)更改changes次進(jìn)行一次快照操作。例如下面的配置
save 1000 1
表示 1000秒或者數(shù)據(jù)更改1次就進(jìn)行快照。也可以設(shè)置多個(gè)方案
save 1000 1
save 300 39
save 19 1111
這樣,其中一個(gè)成立,redis就會(huì)進(jìn)行快照。
如果使用?bgsave 進(jìn)行快照 ? 只需要直接發(fā)送 ?bgsave 命令就可以了?
如果成功會(huì)返回
?
bgsave命令執(zhí)行之后立即返回?OK?,然后 Redis fork 出一個(gè)新子進(jìn)程,原來的 Redis 進(jìn)程(父進(jìn)程)繼續(xù)處理客戶端請(qǐng)求,而子進(jìn)程則負(fù)責(zé)將數(shù)據(jù)保存到磁盤,然后退出。
而save是直接調(diào)用主進(jìn)程所以會(huì)引起阻塞.
日志追加(aof)方式是把增加,修改數(shù)據(jù)的命令通過write函數(shù)追加到文件尾部(默認(rèn)是appendoly.aof)。redis重啟時(shí)讀取appendonly.aof文件中的所有命令并且執(zhí)行,從而把數(shù)據(jù)寫入內(nèi)容中。
另外,操作系統(tǒng)內(nèi)核的I/O接口可能存在緩存,所以日志追加方式不可能立即寫入文件中,這樣就有可能丟失部分?jǐn)?shù)據(jù)。幸運(yùn)的是redis提供了解決的方法,通過修改配置文件告訴redis應(yīng)該在什么時(shí)候使用fsync函數(shù)強(qiáng)制操作系統(tǒng)把緩存寫入磁盤。有一下三種方法:
appendonly yes #啟動(dòng)日志追加持久化方式(yes|no)
#appendfsync always #每次收到增加或者修改命令就立即強(qiáng)制寫入磁盤
appendfsync everysec #每秒強(qiáng)制寫入磁盤一次
#appendfync no#是否寫入磁盤完全依賴操作系統(tǒng)
日志追加方式有效降低數(shù)據(jù)丟失的風(fēng)險(xiǎn),同時(shí)也帶來了另外一些問題,即持久化文件不斷變大。例如調(diào)用 incr nums 命令100次,文件就會(huì)保存100條incr nums 命令,其中99條是多余的,因?yàn)榛貜?fù)數(shù)據(jù)只需要set nums 100
為了壓縮日志文件,redis 提供bgrewriteaof命令。當(dāng)redis收到此命令,就是用類似內(nèi)存快照方式將內(nèi)存的數(shù)據(jù)以命令的方式保存到臨時(shí)文件中,最后替換原來的日志文件。
3.主從同步
主從同步可以防止主機(jī)壞掉導(dǎo)致網(wǎng)站不能正常運(yùn)行,這種方法即把從機(jī)設(shè)置為主機(jī)即可。redis支持主從同步,而且配置很簡單。redis主從同步的有點(diǎn)如下:
master(主)可以有多個(gè)slave(從)
多個(gè)slave連接到同一個(gè)master,slave還可以連接其他slave形成圖形結(jié)構(gòu)。
不會(huì)阻塞master。當(dāng)一個(gè)或者多個(gè)slave與master初次同步數(shù)據(jù)時(shí),master可以繼續(xù)處理客戶請(qǐng)求。相反,slave在初次同步數(shù)據(jù)時(shí)會(huì)阻塞而不能處理客戶端的請(qǐng)求(2.2以后不會(huì)阻塞)。
主從同步用來提高系統(tǒng)的伸縮性,比如多個(gè)slave專門用戶客戶端的讀請(qǐng)求。
在master服務(wù)器上禁止數(shù)據(jù)持久化,只在slave服務(wù)器上進(jìn)行數(shù)據(jù)持久化。
?redis主從同步非常簡單,設(shè)置好slave(從)服務(wù)器后,slave自動(dòng)和master建立連接,發(fā)送SYNC命令。無論是第一次同步建立的連接還是斷開后重新建立的連接,master都啟動(dòng)一個(gè)后臺(tái)進(jìn)程,將內(nèi)存數(shù)據(jù)以快照的形式寫入文件中,同時(shí)master主進(jìn)程開始收集新的寫命令并且緩存起來。master后臺(tái)進(jìn)程完成內(nèi)存快照后,把數(shù)據(jù)文件發(fā)給slave,slave將文件保存到磁盤上,然后把數(shù)據(jù)加載到內(nèi)存中。接著master把緩存命令發(fā)給slave,后續(xù)master收到的寫命令都通過開始建立的連接發(fā)送給slave,當(dāng)master與slave斷開連接,slave自動(dòng)重新建立連接。如果master同時(shí)收到多個(gè)slave發(fā)來的請(qǐng)求,其只啟動(dòng)一個(gè)進(jìn)程寫數(shù)據(jù)庫鏡像,然后發(fā)送給所有slave。
redis主從同步過程分為兩個(gè)階段,第一階段如下:
1.slave服務(wù)器主動(dòng)連接到master服務(wù)器
2.slave服務(wù)器發(fā)送sycn命令到master服務(wù)器請(qǐng)求同步·
3.master服務(wù)器備份數(shù)據(jù)庫到rdb文件
4.master服務(wù)器把rdb文件傳輸給slave服務(wù)器
5。slave服務(wù)器清空數(shù)據(jù)庫數(shù)據(jù),把rdb文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫
完成第一個(gè)階段,接下來master服務(wù)器把用戶所有更改數(shù)據(jù)的操作,通過命令的形似轉(zhuǎn)發(fā)給slave服務(wù)器,slave服務(wù)器只需要執(zhí)行master服務(wù)器發(fā)送過來的命令就可以達(dá)到同步的效果。
相對(duì)于mysql來說,redis主從復(fù)制的配置很簡答,只需要在slave服務(wù)器配置文件下添加
slaveof ? master服務(wù)器ip:端口
例如:
slaveof 192.168.1.123:6379
4.虛擬內(nèi)存
redis的數(shù)據(jù)保存在內(nèi)存中,可能出現(xiàn)物理內(nèi)存不足的情況。物理內(nèi)存不足時(shí),redis會(huì)使用虛擬內(nèi)存(VM)。
VM是redis2.0新加的功能,之前redis把數(shù)據(jù)庫中的所有數(shù)據(jù)放在內(nèi)存中,隨著redis的不斷運(yùn)行,使用內(nèi)存會(huì)越來越大,最終導(dǎo)致內(nèi)存不住。redis的VM與操作系統(tǒng)的VM相似,把很少訪問的vlaue保存到磁盤中。與此同時(shí),redis把value對(duì)應(yīng)的key放在內(nèi)存中,為了能夠讓redis快速定位到被被換出的value所在的磁盤位置,從而將其導(dǎo)入的內(nèi)存中。
操作系統(tǒng)也有虛擬內(nèi)存功能,為什么redis要重復(fù)‘制造輪子‘呢?主要原因有兩點(diǎn):
1.操作系統(tǒng)的VM是基于頁的概念,比如linux系統(tǒng)中內(nèi)個(gè)頁是4kb,而redis大多數(shù)對(duì)象遠(yuǎn)小于4kb,一頁行可能有多個(gè)redis對(duì)象。另外redis的集合對(duì)象類型與list,set可能存放在多個(gè)頁上面。故redis自己實(shí)現(xiàn)可能達(dá)到控制換入的粒度。
2.redis將交換到磁盤的對(duì)象壓縮,保存到磁盤的對(duì)象可以取出指針和對(duì)象元素信息。一般壓縮后的對(duì)象比內(nèi)存中對(duì)象小10倍,這樣redis的vm比操作系統(tǒng)的VM少做很多I/O操作。
配置redis的VM
#開啟VM
vm-enabled yes
#交換出來的value文件保存路徑
vm-swap-file /tmp/redis.swap
#redis使用最大內(nèi)存上線,超過后開始使用交換空間 ?單位字節(jié)
vm-max-memory ?268435456
#設(shè)置每個(gè)頁面的大小為32字節(jié)
vm-page-size 32
#最多在文件使用多少頁面,swap文件的大小等于vm-page-size * vm-page
vm-pages 134217728
#用于執(zhí)行value對(duì)象換出換入的工作線程數(shù)。0表示不使用工作線程
vm-max-threads 4
redis的vm只把value交換到磁盤中,而key依然存儲(chǔ)在內(nèi)存中,目的是讓開啟VM的redis和完全使用內(nèi)存的redis性能基本保持一致。如果由于太多key而造成內(nèi)存不住問題,redis的VM并不能解決。
和炒作系統(tǒng)一樣,redis也按照頁交換對(duì)象。一頁只能保存一個(gè)對(duì)象,但是一個(gè)對(duì)象可以保存在多頁中。
當(dāng)redis使用的內(nèi)存沒有超過設(shè)置的vm-max-memory之前,不把任何value交換到磁盤中;當(dāng)超過最大內(nèi)存限制后,redis根據(jù)一下算法尋找一個(gè)對(duì)象交換到磁盤中:
swappability=age*log(size_in_memory);
其中age代表這個(gè)對(duì)象距離上一次被訪問的時(shí)間,size_in_memry是這個(gè)對(duì)象在內(nèi)存中占用的空間大小。redis采取的策略是把那些很少訪問,而且占用內(nèi)存又比較大的對(duì)象交換的齒盤空間中,但是第二個(gè)因素所占的權(quán)重更低,所以在公式中取log值。因?yàn)榻粨Q大對(duì)象時(shí),需要占用更多的I/O和cpu資源。
應(yīng)該更具自己的應(yīng)用設(shè)置vm-page-size,設(shè)置太大浪費(fèi)磁盤空間,設(shè)置太小照成swap文件出現(xiàn)過多碎片。
vm-max-threads 表示用于交換任務(wù)的工作線程數(shù)量,建議不要將vm-max-threads設(shè)置為0,設(shè)置為0時(shí)交換過程在主線程進(jìn)行,從而阻塞其他用戶。但也不是設(shè)置越大越好,因?yàn)樘嗟墓ぷ骶€程導(dǎo)致操作系統(tǒng)使用更多的時(shí)間來切換線程,從而降低效率。推薦吧vm-max-threads設(shè)置為服務(wù)器的cpu核心數(shù)。
為了理解VM子系統(tǒng)如何工作,需要了解對(duì)象在swap文件中如何存儲(chǔ)。
swap文件中采用rdb文件的存儲(chǔ)格式。swap文件被分割成固定數(shù)量的頁,每頁占用指定的數(shù)量的字節(jié)空間。在redis.conf中更具自己業(yè)務(wù)需求配置一下兩個(gè)參數(shù):
vm-page-size 設(shè)置每頁的大小,默認(rèn)值為32.
vm-pages設(shè)置能夠使用的頁數(shù),默認(rèn)值為134217728
redis在內(nèi)存中保存一個(gè)bitmap以映射這些頁是否被占用,每bit代表一個(gè)對(duì)應(yīng)磁盤空間的頁是否被占用。內(nèi)存中保存這樣一份映射表極大的增強(qiáng)了redis性能,同時(shí),對(duì)內(nèi)存的使用又非常少。
在持久化備份的時(shí)候,也會(huì)備份swap 中的數(shù)據(jù)只不過在備份時(shí)swap變?yōu)橹蛔x了,父進(jìn)程和后臺(tái)主進(jìn)程只能訪問swap。而父進(jìn)程不能將value換入。
當(dāng)一個(gè)value 交換到磁盤時(shí),value對(duì)應(yīng)的redis object 將被VM Pointer,VM pointer保存value在磁盤的信息。
交換過程:
從內(nèi)存交換到swap中:
第一步。計(jì)算保存這個(gè)對(duì)象需要占用swap文件中多少頁
第二步:在swap中尋找一段連續(xù)的空白頁空間保存這個(gè)對(duì)象
第三步:把對(duì)象寫入swap
從swap中交換到內(nèi)存中
從swap文件交換到內(nèi)存比較簡單,因?yàn)樵赩M Pointer 中已記錄對(duì)象在swap文件的頁起始地址和占用頁數(shù),只要更具VM Pointer 把磁盤的對(duì)象換入內(nèi)存即可。
?
轉(zhuǎn)載于:https://www.cnblogs.com/phpshen/p/6292988.html
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的redis 事务,持久化,日志,主从,VM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP的几种排序算法的比较
- 下一篇: MySQL存储过程和函数(一)