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