Redis進(jìn)階:事務(wù)+持久化+優(yōu)化

簡介

Redis是一個開源(BSD許可)的內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲,用作數(shù)據(jù)庫、緩存和消息代理。它支持諸如字符串、散列、列表、集、帶范圍查詢的排序集、位圖、hyperloglog、帶半徑查詢和流的地理空間索引等數(shù)據(jù)結(jié)構(gòu)。

image

Redis具有內(nèi)置的復(fù)制、Lua腳本、LRU清除、事務(wù)和不同級別的磁盤持久性,并通過Redis Sentinel和Redis集群的自動分區(qū)提供高可用性。

事務(wù)

為了保證多條命令組合的原子性,Redis提供了簡單的事務(wù)功能以及集成Lua腳本來解決這個問題。簡單介紹Redis中事務(wù)的使用方法以及它的局限性。

Redis提供了簡單的事務(wù)功能,將一組需要一起執(zhí)行的命令放到multi和exec兩個命令之間。

  • multi命令代表事務(wù)開始。
  • exec命令代表事務(wù)結(jié)束
  • 它們之間的命令是原子順序執(zhí)行的。
  • 不支持事務(wù)中的回滾特性。

發(fā)布訂閱

Redis提供了基于“發(fā)布/訂閱”模式的消息機(jī)制,此種模式下,消息發(fā)布者和訂閱者不進(jìn)行直接通信,發(fā)布者客戶端向指定的頻道(channel)發(fā)布消息,訂閱該頻道的每個客戶端都可以收到該消息。

image

發(fā)布消息

publish channel:sports "Tim won the championship

訂閱消息

subscribe channel:sports

有關(guān)訂閱命令有兩點(diǎn)需要注意

  • 客戶端在執(zhí)行訂閱命令之后進(jìn)入了訂閱狀態(tài),只能接收subscribe、

psubscribe、unsubscribe、punsubscribe的四個命令。

  • 新開啟的訂閱客戶端,無法收到該頻道之前的消息,因為Redis不會對發(fā)布的消息進(jìn)行持久化。

Redis發(fā)布訂閱與成熟MQ的比較

  1. MQ支持多種消息協(xié)議,包括AMQP,MQTT,Stomp等,并且支持JMS規(guī)范,但Redis沒有提供對這些協(xié)議的支持;
  2. MQ提供持久化功能,但Redis無法對消息持久化存儲,一旦消息被發(fā)送,如果沒有訂閱者接收,那么消息就會丟失;
  3. MQ提供了消息傳輸保障,當(dāng)客戶端連接超時或事務(wù)回滾等情況發(fā)生時,消息會被重新發(fā)送給客戶端,Redis沒有提供消息傳輸保障。

總之,MQ所提供的功能遠(yuǎn)比Redis發(fā)布訂閱要復(fù)雜,畢竟Redis不是專門做發(fā)布訂閱的,但是如果系統(tǒng)中已經(jīng)有了Redis,并且需要基本的發(fā)布訂閱功能,就沒有必要再安裝MQ了,因為可能MQ提供的功能大部分都用不到,而且你可以容忍redis發(fā)布訂閱的缺點(diǎn)的話,可以考慮用它。

持久化

Redis支持RDB和AOF兩種持久化機(jī)制,持久化功能有效地避免因進(jìn)程退出造成的數(shù)據(jù)丟失問題,當(dāng)下次重啟時利用之前持久化的文件即可實(shí)現(xiàn)數(shù)據(jù)恢復(fù)。

RDB持久化

RDB持久化是把當(dāng)前進(jìn)程數(shù)據(jù)生成快照保存到硬盤的過程,觸發(fā)RDB持久化過程分為手動觸發(fā)和自動觸發(fā)。

RDB的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  1. RDB是一個緊湊壓縮的二進(jìn)制文件,代表Redis在某個時間點(diǎn)上的數(shù)據(jù)快照。非常適用于備份,全量復(fù)制等場景。比如每6小時執(zhí)行bgsave備份,并把RDB文件拷貝到遠(yuǎn)程機(jī)器或者文件系統(tǒng)中(如hdfs),用于災(zāi)難恢復(fù)。
  2. Redis加載RDB恢復(fù)數(shù)據(jù)遠(yuǎn)遠(yuǎn)快于AOF的方式。

缺點(diǎn):

  1. RDB方式數(shù)據(jù)沒辦法做到實(shí)時持久化/秒級持久化。因為bgsave每次運(yùn)行都要執(zhí)行fork操作創(chuàng)建子進(jìn)程,屬于重量級操作,頻繁執(zhí)行成本過高。
  2. RDB文件使用特定二進(jìn)制格式保存,Redis版本演進(jìn)過程中有多個格式的RDB版本,存在老版本Redis服務(wù)無法兼容新版RDB格式的問題。

針對RDB不適合實(shí)時持久化的問題,Redis提供了AOF持久化方式來解決。

AOF持久化

AOF(append only file)持久化:以獨(dú)立日志的方式記錄每次寫命令,重啟時再重新執(zhí)行AOF文件中的命令達(dá)到恢復(fù)數(shù)據(jù)的目的。

AOF的主要作用是解決了數(shù)據(jù)持久化的實(shí)時性,目前已經(jīng)是Redis持久化的主流方式。

開啟AOF,通過修改redis.conf配置文件

appendonly yes ##默認(rèn)不開啟。

AOF文件名通過appendfilename配置設(shè)置,默認(rèn)文件名appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定。

AOF的工作流程如下圖:

image
  1. 所有的寫入命令會追加到aof_buf(緩沖區(qū))中。
  2. AOF緩沖區(qū)根據(jù)對應(yīng)的策略向硬盤做同步操作。
  3. 隨著AOF文件越來越大,需要定期對AOF文件進(jìn)行重寫,達(dá)到壓縮的目的。
  4. 當(dāng)Redis服務(wù)器重啟時,可以加載AOF文件進(jìn)行數(shù)據(jù)恢復(fù)。

溫馨提示

場景:AOF文件可能存在結(jié)尾不完整的情況,比如機(jī)器突然掉電導(dǎo)致AOF尾部文件命令寫入不全。

解決方法:

  1. 對于錯誤格式的AOF文件,先進(jìn)行備份,然后采用redis-check-aof --fix命令進(jìn)行修復(fù),修復(fù)后使用diff-u對比數(shù)據(jù)的差異,找出丟失的數(shù)據(jù),有些可以人工修改補(bǔ)全。
  2. Redis為我們提供了aof-load-truncated配置來兼容這種情況,默認(rèn)開啟。加載AOF時,當(dāng)遇到此問題時會忽略并繼續(xù)啟動,同時打印如下警告日志:
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 397856725 !!!
# AOF loaded anyway because aof-load-truncated is enabled

持久化的優(yōu)化

Redis持久化功能一直是影響Redis性能的高發(fā)地。主要有以下方面

1. fork操作

起因:對于高流量的Redis實(shí)例OPS可達(dá)5萬以上,如果fork操作耗時在秒級別將拖慢Redis幾萬條命令執(zhí)行,對線上應(yīng)用延遲影響非常明顯。正常情況下fork耗時應(yīng)該是每GB消耗20毫秒左右。可以在info stats統(tǒng)計中查latest_fork_usec指標(biāo)獲取最近一次fork操作耗時,單位微秒。

優(yōu)化

  1. 優(yōu)先使用物理機(jī)或者高效支持fork操作的虛擬化技術(shù),避免使用Xen。
  2. 控制Redis實(shí)例最大可用內(nèi)存,fork耗時跟內(nèi)存量成正比,線上建議每個Redis實(shí)例內(nèi)存控制在10GB以內(nèi)。
  3. 合理配置Linux內(nèi)存分配策略,避免物理內(nèi)存不足導(dǎo)致fork失敗。
  4. 降低fork操作的頻率,如適度放寬AOF自動觸發(fā)時機(jī),避免不必要的全量復(fù)制等。

CPU

  • CPU開銷分析。子進(jìn)程負(fù)責(zé)把進(jìn)程內(nèi)的數(shù)據(jù)分批寫入文件,這個過程屬于CPU密集操作,通常子進(jìn)程對單核CPU利用率接近90%。
  • CPU消耗優(yōu)化。Redis是CPU密集型服務(wù),不要做綁定單核CPU操作。由于子進(jìn)程非常消耗CPU,會和父進(jìn)程產(chǎn)生單核資源競爭。
  • 不要和其他CPU密集型服務(wù)部署在一起,造成CPU過度競爭。如果部署多個Redis實(shí)例,盡量保證同一時刻只有一個子進(jìn)程執(zhí)行重寫工作。

內(nèi)存

內(nèi)存消耗優(yōu)化:

  1. 同CPU優(yōu)化一樣,如果部署多個Redis實(shí)例,盡量保證同一時刻只有一個子進(jìn)程在工作。
  2. 避免在大量寫入時做子進(jìn)程重寫操作,這樣將導(dǎo)致父進(jìn)程維護(hù)大量頁副本,造成內(nèi)存消耗。

硬盤

優(yōu)化方法如下:

  • 不要和其他高硬盤負(fù)載的服務(wù)部署在一起。如:存儲服務(wù)、消息隊列服務(wù)等。
  • AOF重寫時會消耗大量硬盤IO,可以開啟配置no-appendfsync-on-rewrite,默認(rèn)關(guān)閉。表示在AOF重寫期間不做fsync操作。
  • 當(dāng)開啟AOF功能的Redis用于高流量寫入場景時,如果使用普通機(jī)械磁盤,寫入吞吐一般在100MB/s左右,這時Redis實(shí)例的瓶頸主要在AOF同步硬盤上。
  • 對于單機(jī)配置多個Redis實(shí)例的情況,可以配置不同實(shí)例分盤存儲AOF文件,分?jǐn)傆脖P寫入壓力。

注:配置no-appendfsync-on-rewrite=yes時,在極端情況下可能丟失整個AOF重寫期間的數(shù)據(jù),需要根據(jù)數(shù)據(jù)安全性決定是否配置。

AOF追加阻塞

當(dāng)開啟AOF持久化時,常用的同步硬盤的策略是everysec,用于平衡性能和數(shù)據(jù)安全性。對于這種方式,Redis使用另一條線程每秒執(zhí)行fsync同步硬盤。當(dāng)系統(tǒng)硬盤資源繁忙時,會造成Redis主線程阻塞,

image

阻塞流程分析:

  1. 主線程負(fù)責(zé)寫入AOF緩沖區(qū)。
  2. AOF線程負(fù)責(zé)每秒執(zhí)行一次同步磁盤操作,并記錄最近一次同步時間。
  3. 主線程負(fù)責(zé)對比上次AOF同步時間:如果距上次同步成功時間在2秒內(nèi),主線程直接返回。如果距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操作完成。

本文到此結(jié)束!喜歡的朋友可以點(diǎn)點(diǎn)關(guān)注和轉(zhuǎn)發(fā),感謝支持。持續(xù)更新更多的干貨

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Redis高可用概述 在介紹Redis高可用之前,先說明一下在Redis的語境中高可用的含義。 我們知道,在w...
    空語閱讀 1,681評論 0 2
  • 企業(yè)級redis集群架構(gòu)的特點(diǎn) 海量數(shù)據(jù) 高并發(fā) 高可用 要達(dá)到高可用,持久化是不可減少的,持久化主要是做災(zāi)難恢復(fù)...
    lucode閱讀 2,283評論 0 7
  • 本文檔翻譯自http://redis.io/topics/persistence。 這篇文章提供了 Redis 持...
    daos閱讀 739評論 0 10
  • 一般我都會忽略自己的年齡,也不愿去想自己的年齡。不過客觀地來講,我已經(jīng)要奔四了! 奔四意味著我將迎來四十的門檻,過...
    我就是00后閱讀 416評論 0 0
  • Docker--------修改Docker0網(wǎng)橋默認(rèn)網(wǎng)段 網(wǎng)橋docker0 1.背景 Docker 服務(wù)啟動后...
    華木公子閱讀 858評論 0 0

友情鏈接更多精彩內(nèi)容