"\u003Cdiv\u003E\u003Ch1\u003E\u003Cstrong\u003E簡介\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp\u003ERedis是一個開源(BSD許可)的內存數據結構存儲,用作數據庫、緩存和消息代理。它支持諸如\u003Cstrong\u003E字符串、散列、列表、集、帶範圍查詢的排序集、位圖、hyperloglog、帶半徑查詢和流的地理空間索引\u003C\u002Fstrong\u003E等數據結構。\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp3.pstatp.com\u002Flarge\u002Fpgc-image\u002F3661d7eaa82844bbbebe60396b99fb48\" img_width=\"640\" img_height=\"413\" alt=\"程序員進階架構筆記:Redis事務+持久化+優化 你不得不掌握的技術\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp\u003ERedis具有內置的複製、Lua腳本、LRU清除、事務和不同級別的磁盤持久性,並通過Redis Sentinel和Redis集羣的自動分區提供高可用性。\u003C\u002Fp\u003E\u003Ch1\u003E\u003Cstrong\u003E事務\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp\u003E爲了保證多條命令組合的原子性,Redis提供了簡單的事務功能以及集成Lua腳本來解決這個問題。簡單介紹Redis中事務的使用方法以及它的侷限性。\u003C\u002Fp\u003E\u003Cp\u003ERedis提供了簡單的事務功能,將一組需要一起執行的命令放到multi和exec兩個命令之間。\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003Emulti\u003C\u002Fstrong\u003E命令代表事務\u003Cstrong\u003E開始\u003C\u002Fstrong\u003E。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003Eexec\u003C\u002Fstrong\u003E命令代表事務\u003Cstrong\u003E結束\u003C\u002Fstrong\u003E。\u003C\u002Fli\u003E\u003Cli\u003E它們之間的命令是原子順序執行的。\u003C\u002Fli\u003E\u003Cli\u003E它\u003Cstrong\u003E不支持事務中的回滾特性\u003C\u002Fstrong\u003E。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Ch1\u003E\u003Cstrong\u003E發佈訂閱\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp\u003ERedis提供了基於“發佈\u002F訂閱”模式的消息機制,此種模式下,消息發佈者和訂閱者不進行直接通信,發佈者客戶端向指定的頻道(channel)發佈消息,訂閱該頻道的每個客戶端都可以收到該消息。\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002F23d76e3d6e6645ac88587eca18cc96b3\" img_width=\"640\" img_height=\"289\" alt=\"程序員進階架構筆記:Redis事務+持久化+優化 你不得不掌握的技術\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cstrong\u003E發佈消息\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cpre\u003Epublish channel:sports \"Tim won the championship\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E訂閱消息\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cpre\u003Esubscribe channel:sports\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E有關訂閱命令有兩點需要\u003Cstrong\u003E注意\u003C\u002Fstrong\u003E:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E客戶端在執行訂閱命令之後進入了訂閱狀態,只能接收subscribe、\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cblockquote\u003E\u003Cp\u003Epsubscribe、unsubscribe、punsubscribe的四個命令。\u003C\u002Fp\u003E\u003C\u002Fblockquote\u003E\u003Cul\u003E\u003Cli\u003E新開啓的訂閱客戶端,無法收到該頻道之前的消息,因爲Redis不會對發佈的消息進行持久化。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003ERedis發佈訂閱與成熟MQ的比較\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003EMQ支持\u003Cstrong\u003E多種消息協議\u003C\u002Fstrong\u003E,包括AMQP,MQTT,Stomp等,並且支持JMS規範,但Redis沒有提供對這些協議的支持;\u003C\u002Fli\u003E\u003Cli\u003EMQ提供\u003Cstrong\u003E持久化功能\u003C\u002Fstrong\u003E,但Redis無法對消息持久化存儲,一旦消息被髮送,如果沒有訂閱者接收,那麼消息就會丟失;\u003C\u002Fli\u003E\u003Cli\u003EMQ提供了消息傳輸保障,當客戶端連接超時或事務回滾等情況發生時,\u003Cstrong\u003E消息會被重新發送給客戶端\u003C\u002Fstrong\u003E,Redis沒有提供消息傳輸保障。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E總之,MQ所提供的功能遠比Redis發佈訂閱要複雜,畢竟Redis不是專門做發佈訂閱的,但是如果系統中已經有了Redis,並且需要基本的發佈訂閱功能,就沒有必要再安裝MQ了,因爲可能MQ提供的功能大部分都用不到,而且你可以容忍redis發佈訂閱的缺點的話,可以考慮用它。\u003C\u002Fp\u003E\u003Ch1\u003E\u003Cstrong\u003E持久化\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp\u003ERedis支持\u003Cstrong\u003ERDB和AOF兩種持久化機制\u003C\u002Fstrong\u003E,持久化功能有效地避免因進程退出造成的數據丟失問題,當下次重啓時利用之前持久化的文件即可實現數據恢復。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003ERDB持久化\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003ERDB持久化是把當前進程數據生成快照保存到硬盤的過程,觸發RDB持久化過程分爲手動觸發和自動觸發。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003ERDB的優缺點\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E優點:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003ERDB是一個緊湊壓縮的二進制文件,代表Redis在某個時間點上的數據快照。非常適用於備份,全量複製等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。\u003C\u002Fli\u003E\u003Cli\u003ERedis加載RDB恢復數據遠遠快於AOF的方式。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003E缺點:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003ERDB方式數據沒辦法做到實時持久化\u002F秒級持久化。因爲bgsave每次運行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。\u003C\u002Fli\u003E\u003Cli\u003ERDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB版本,存在老版本Redis服務無法兼容新版RDB格式的問題。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003E針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EAOF持久化\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EAOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啓時再重新執行AOF文件中的命令達到恢復數據的目的。\u003C\u002Fp\u003E\u003Cp\u003EAOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E開啓AOF,通過修改redis.conf配置文件\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cpre\u003Eappendonly yes ##默認不開啓。\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003EAOF文件名通過appendfilename配置設置,默認文件名appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EAOF的工作流程如下圖:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp3.pstatp.com\u002Flarge\u002Fpgc-image\u002Fbfe5662480a44bb283d49ff58e163571\" img_width=\"460\" img_height=\"540\" alt=\"程序員進階架構筆記:Redis事務+持久化+優化 你不得不掌握的技術\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Col\u003E\u003Cli\u003E所有的寫入命令會追加到aof_buf(緩衝區)中。\u003C\u002Fli\u003E\u003Cli\u003EAOF緩衝區根據對應的策略向硬盤做同步操作。\u003C\u002Fli\u003E\u003Cli\u003E隨着AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。\u003C\u002Fli\u003E\u003Cli\u003E當Redis服務器重啓時,可以加載AOF文件進行數據恢復。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003E溫馨提示\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E場景:\u003C\u002Fstrong\u003EAOF文件可能存在結尾不完整的情況,比如機器突然掉電導致AOF尾部文件命令寫入不全。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E解決方法:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E對於錯誤格式的AOF文件,先進行\u003Cstrong\u003E備份\u003C\u002Fstrong\u003E,然後採用redis-check-aof --fix命令進行修復,修復後使用diff-u對比數據的差異,找出丟失的數據,有些可以人工修改補全。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003ERedis爲我們提供了aof-load-truncated配置來兼容這種情況\u003C\u002Fstrong\u003E,默認開啓。加載AOF時,當遇到此問題時會忽略並繼續啓動,同時打印如下警告日誌:\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cpre\u003E# !!! Warning: short read while loading the AOF file !!!\u003Cbr\u003E# !!! Truncating the AOF at offset 397856725 !!!\u003Cbr\u003E# AOF loaded anyway because aof-load-truncated is enabled\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Ch1\u003E\u003Cstrong\u003E持久化的優化\u003C\u002Fstrong\u003E\u003C\u002Fh1\u003E\u003Cp\u003ERedis持久化功能一直是影響Redis性能的高發地。主要有以下方面\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E1. fork操作\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E起因\u003C\u002Fstrong\u003E:對於高流量的Redis實例OPS可達5萬以上,如果fork操作耗時在秒級別將拖慢Redis幾萬條命令執行,對線上應用延遲影響非常明顯。正常情況下fork耗時應該是每GB消耗20毫秒左右。可以在info stats統計中查latest_fork_usec指標獲取最近一次fork操作耗時,單位微秒。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E優化\u003C\u002Fstrong\u003E:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E優先使用物理機或者高效支持fork操作的虛擬化技術,避免使用Xen。\u003C\u002Fli\u003E\u003Cli\u003E控制Redis實例最大可用內存,fork耗時跟內存量成正比,線上建議每個Redis實例內存控制在10GB以內。\u003C\u002Fli\u003E\u003Cli\u003E合理配置Linux內存分配策略,避免物理內存不足導致fork失敗。\u003C\u002Fli\u003E\u003Cli\u003E降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量複製等。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003ECPU\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003ECPU開銷分析。子進程負責把進程內的數據分批寫入文件,這個過程屬於CPU密集操作,通常子進程對單核CPU利用率接近90%。\u003C\u002Fli\u003E\u003Cli\u003ECPU消耗優化。Redis是CPU密集型服務,不要做綁定單核CPU操作。由於子進程非常消耗CPU,會和父進程產生單核資源競爭。\u003C\u002Fli\u003E\u003Cli\u003E不要和其他CPU密集型服務部署在一起,造成CPU過度競爭。如果部署多個Redis實例,儘量保證同一時刻只有一個子進程執行重寫工作。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E內存\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E內存消耗優化:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E同CPU優化一樣,如果部署多個Redis實例,儘量保證同一時刻只有一個子進程在工作。\u003C\u002Fli\u003E\u003Cli\u003E避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003E硬盤\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E優化方法如下:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E不要和其他高硬盤負載的服務部署在一起。如:存儲服務、消息隊列服務等。\u003C\u002Fli\u003E\u003Cli\u003EAOF重寫時會消耗大量硬盤IO,可以開啓配置no-appendfsync-on-rewrite,默認關閉。表示在AOF重寫期間不做fsync操作。\u003C\u002Fli\u003E\u003Cli\u003E當開啓AOF功能的Redis用於高流量寫入場景時,如果使用普通機械磁盤,寫入吞吐一般在100MB\u002Fs左右,這時Redis實例的瓶頸主要在AOF同步硬盤上。\u003C\u002Fli\u003E\u003Cli\u003E對於單機配置多個Redis實例的情況,可以配置不同實例分盤存儲AOF文件,分攤硬盤寫入壓力。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E注:配置no-appendfsync-on-rewrite=yes時,在極端情況下可能丟失整個AOF重寫期間的數據,需要根據數據安全性決定是否配置。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EAOF追加阻塞\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E當開啓AOF持久化時,常用的同步硬盤的策略是\u003Cstrong\u003Eeverysec\u003C\u002Fstrong\u003E,用於平衡性能和數據安全性。對於這種方式,Redis使用另一條線程每秒執行fsync同步硬盤。當系統硬盤資源繁忙時,會造成Redis主線程阻塞,\u003C\u002Fp\u003E\u003Cdiv class=\"pgc-img\"\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002F9ee8af7f951942d982fcd8fe9e2adcaf\" img_width=\"515\" img_height=\"443\" alt=\"程序員進階架構筆記:Redis事務+持久化+優化 你不得不掌握的技術\" inline=\"0\"\u003E\u003Cp class=\"pgc-img-caption\"\u003E\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cstrong\u003E阻塞流程分析:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E主線程負責寫入AOF緩衝區。\u003C\u002Fli\u003E\u003Cli\u003EAOF線程負責每秒執行一次同步磁盤操作,並記錄最近一次同步時間。\u003C\u002Fli\u003E\u003Cli\u003E主線程負責對比上次AOF同步時間:如果距上次同步成功時間在2秒內,主線程直接返回。如果距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操作完成。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E\u003Cstrong\u003E本文到此結束!喜歡的朋友可以點點關注和轉發,感謝支持。持續更新更多的乾貨。\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E幹這行人多,但是能堅持下去的沒多少,這也是爲什麼寒潮下,牛人還是牛人,苦的是這些底層技術人,要想不被淘汰,那麼就只有一條,努力堅持,每天進步一點點,牛人都是這麼積累下來的。加油吧兄弟!\u003C\u002Fp\u003E\u003C\u002Fdiv\u003E"'.slice(6, -6), groupId: '6717130534524289550
相關文章