課程計劃html
1. REDIS 入 門 | (瞭解) | (操做) | |
---|---|---|---|
2. 數據類型 | (重點) | (操做) | (理解) |
3. 經常使用指令 | (操做) | ||
4. Jedis | (重點) | (操做) | |
5. 持 久 化 | (重點) | (理解) | |
6. 數據刪除與淘汰策略 | (理解) | ||
7. 主從複製 | (重點) | (操做) | (理解) |
8. 哨 兵 | (重點) | (操做) | (理解) |
9. Cluster集羣方案 | (重點) | (操做) | (理解) |
10. 企業級緩存解決方案 | (重點) | (理解) | |
11. 性能指標監控 | (瞭解) |
在這個部分,咱們將學習如下3個部分的內容,分別是:java
◆ Redis 簡介(NoSQL概念、Redis概念)linux
◆ Redis 的下載與安裝git
◆ Redis 的基本操做github
在講解NoSQL的概念以前呢,咱們先來看一個現象:redis
(1)問題現象sql
每一年到了過年期間,你們都會自覺自發的組織一場活動,叫作春運!之前咱們買票都是到火車站排隊,後來呢有了12306,有了他之後就更方便了,咱們能夠在網上買票,可是帶來的問題,你們也很清楚,春節期間買票進不去,進去了刷不着票。什麼緣由呢,人太多了!數據庫
除了這種作鐵路的,它系統作的不專業之外,還有馬爸爸作的淘寶,它面臨同樣的問題。淘寶也崩,也是用戶量太大!做爲咱們整個電商界的東哥來講,他第一次作圖書促銷的時候,也遇到了服務器崩掉的這樣一個現象,緣由一樣是由於用戶量太大!編程
(2)現象特徵json
再來看這幾個現象,有兩個很是類似的特徵:
第一,用戶比較多,海量用戶
第二,高併發
這兩個現象出現之後,對應的就會形成咱們的服務器癱瘓。核心本質是什麼呢?其實並非咱們的應用服務器,而是咱們的關係型數據庫。關係型數據庫纔是最終的罪魁禍首!
(3)形成緣由
什麼樣的緣由致使的整個系統崩掉的呢:
1.性能瓶頸:磁盤IO性能低下
關係型數據庫菜存取數據的時候和讀取數據的時候他要走磁盤IO。磁盤這個性能自己是比較低的。
2.擴展瓶頸:數據關係複雜,擴展性差,不便於大規模集羣
咱們說關係型數據庫,它裏面表與表之間的關係很是複雜,不知道你們能不能想象一點,就是一張表,經過它的外鍵關聯了七八張表,這七八張表又經過她的外鍵,每張又關聯了四五張表。你想一想,查詢一下,你要想拿到數據,你就要從A到B、B到C、C到D的一直這麼關聯下去,最終很是影響查詢的效率。同時,你想擴展下,也很難!
(4)解決思路
面對這樣的現象,咱們要想解決怎麼版呢。兩方面:
一,下降磁盤IO次數,越低越好。
二,去除數據間關係,越簡單越好。
下降磁盤IO次數,越低越好,怎麼搞?我不用你磁盤不就好了嗎?因而,內存存儲的思想就提出來了,我數據不放到你磁盤裏邊,放內存裏,這樣是否是效率就高了。
第二,你的數據關係很複雜,那怎麼辦呢?乾脆簡單點,我斷開你的關係,我不存關係了,我只存數據,這樣不就沒這事了嗎?
把這兩個特徵一合併一塊兒,就出來了一個新的概念:NoSQL
(1)概念
NoSQL:即 Not-Only SQL( 泛指非關係型的數據庫),做爲關係型數據庫的補充。 做用:應對基於海量用戶和海量數據前提下的數據處理問題。
他說這句話說的很是客氣,什麼意思呢?就是咱們數據存儲要用SQL,可是呢能夠不只僅用SQL,還能夠用別的東西,那別的東西叫什麼呢?因而他定義了一句話叫作NoSQL。這個意思就是說咱們存儲數據,能夠不光使用SQL,咱們還能夠使用非SQL的這種存儲方案,這就是所謂的NoSQL。
(2)特徵
可擴容,可伸縮。SQL數據關係過於複雜,你擴容一下難度很高,那咱們Nosql 這種的,不存關係,因此它的擴容就簡單一些。
大數據量下高性能。包數據很是多的時候,它的性能高,由於你不走磁盤IO,你走的是內存,性能確定要比磁盤IO的性能快一些。
靈活的數據模型、高可用。他設計了本身的一些數據存儲格式,這樣能保證效率上來講是比較高的,最後一個高可用,咱們等到集羣內部分再去它!
(3)常見 Nosql 數據庫
目前市面上常見的Nosql產品:Redis、memcache、HBase、MongoDB
(4)應用場景-電商爲例
咱們以電商爲例,來看一看他在這裏邊起到的做用。
第一類,在電商中咱們的基礎數據必定要存儲起來,好比說商品名稱,價格,生產廠商,這些都屬於基礎數據,這些數據放在MySQL數據庫。
第二類,咱們商品的附加信息,好比說,你買了一個商品評價了一下,這個評價它不屬於商品自己。就像你買一個蘋果,「這個蘋果很好吃」就是評論,可是你能說很好吃是這個商品的屬性嘛?不能這麼說,那只是一我的對他的評論而已。這一類數據呢,咱們放在另一個地方,咱們放到MongoDB。它也能夠用來加快咱們的訪問,他屬於NoSQL的一種。
第三,圖片內的信息。注意這種信息相對來講比較固定,他有專用的存儲區,咱們通常用文件系統來存儲。至因而不是分佈式,要看你的系統的一個整個 瓶頸 了?若是說你發現你須要作分佈式,那就作,不須要的話,一臺主機就搞定了。
第四,搜索關鍵字。爲了加快搜索,咱們會用到一些技術,有些人可能瞭解過,像分ES、Lucene、solr都屬於搜索技術。那說的這麼熱鬧,咱們的電商解決方案中還沒出現咱們的redis啊!注意第五類信息。
第五,熱點信息。訪問頻度比較高的信息,這種東西的第二特徵就是它具備波段性。換句話說他不是穩定的,它具備一個時效性的。那麼這類信息放哪兒了,放到咱們的redis這個解決方案中來進行存儲。
具體的咱們從咱們的整個數據存儲結構的設計上來看一下。
咱們的基礎數據都存MySQL,在它的基礎之上,咱們把它連在一起,同時對外提供服務。向上走,有一些信息加載完之後,要放到咱們的MongoDB中。還有一類信息,咱們放到咱們專用的文件系統中(好比圖片),就放到咱們的這個搜索專用的,如Lucene、solr及集羣裏邊,或者用ES的這種技術裏邊。那麼剩下來的熱點信息,放到咱們的redis裏面。
概念:Redis (Remote Dictionary Server:遠程詞典服務器) 是用 C 語言開發的一個開源的高性能(內存型)鍵值對(key-value)數據庫。
特徵:
(1)數據間沒有必然的關聯關係;
(2)內部採用單線程機制進行工做;
(3)高性能。官方提供測試數據,50個併發執行100000 個請求,讀的速度是110000 次/s,寫的速度是81000次/s。
(4)多數據類型支持
字符串類型,string
列表類型,list
hash set
散列類型,zset/sorted_set
集合類型
有序集合類型
(5)支持持久化,能夠進行數據災難恢復
(1)爲熱點數據加速查詢(主要場景)。如熱點商品、熱點新聞、熱點資訊、推廣類等高訪問量信息等。
(2)即時信息查詢。如各位排行榜、各種網站訪問統計、公交到站信息、在線人數信息(聊天室、網站)、設備信號等。
(3)時效性信息控制。如驗證碼控制、投票控制等。
(4)分佈式數據共享。如分佈式集羣架構中的 session 分離 (5)消息隊列
後期全部資料分4中不一樣色塊顯示,詳情以下:
本課程所示,均基於Center OS7安裝Redis。
安裝的時候可能還會須要安裝gcc環境:因此能夠參照:
http://blog.sina.com.cn/s/blog_ae829c5c0102z27v.html
(1)下載並安裝Redis
下載安裝包:
wget http://download.redis.io/releases/redis-5.0.0.tar.gz
解壓安裝包:
tar –xvf redis-5.0.0.tar.gz
編譯(在解壓的目錄中執行):
make
安裝(在解壓的目錄中執行):
make install
(2)redis相關命令
redis-server,服務器啓動命令 客戶端啓動命令
redis-cli,redis核心配置文件
redis.conf,RDB文件檢查工具(快照持久化文件)
redis-check-dump,AOF文件修復工具
redis-check-aof
資料中找到「Redis-x64-3.2.100.msi」
雙擊進行安裝:選擇目錄,勾選添加環境變量
打開cmd:執行redis-server "D:\Program Files\Redis\redis.windows.conf"
出現Server started便可
注意:這個窗口不可關閉,一旦關閉redis服務將中止
沒有出現上述圖片,而是報錯:「 listening socket 127.0.0.1:6379: bind: No error 」
解決
客戶端鏈接redis服務:如能出現以下效果即說明redis服務真正啓動成功
找到資料:「redis-desktop-manager-0.8.8.384.exe」
雙擊安裝,默認安裝便可
雙擊桌面「RedisDesktopManager」圖標,打開redis桌面管理工具
創建鏈接
輸入鏈接內容:
左側出現鏈接
雙擊鏈接:出現redis默認的15個庫
到此爲止,說明圖形化客戶端鏈接redis服務成功
啓動服務器——參數啓動
redis-server [--port port]
範例
redis-server --port 6379
啓動服務器——配置文件啓動
redis-server config_file_name
範例
redis-server redis.conf
啓動客戶端
redis-cli [-h host] [-p port]
範例
redis-cli –h 61.129.65.248 –p 6384
注意:服務器啓動指定端口使用的是--port,客戶端啓動指定端口使用的是-p。-的數量也不一樣。
建立配置文件存儲目錄
mkdir conf
建立服務器文件存儲目錄(包含日誌、數據、臨時配置文件等)
mkdir data
建立快速訪問連接
ln -s redis-5.0.0 redis
修改啓動配置文件redis.conf/redis.windows.conf
配置項介紹:
設置服務器以守護進程的方式運行,開啓後服務器控制檯中將打印服務器運行信息(同日志內容相同)
daemonize yes|no # 改成yes就是後臺啓動,看不到以前的歡迎信息,cmd窗口關閉也沒影響
#windows版本的redis不支持後臺啓動,配置也沒有用
綁定主機地址:bind ip
bind 127.0.0.1 #指定當前redis服務運行在哪一個ip上(通常都指定爲本機)
設置服務器端口
port 6379 #6379是redis的默認端口
日誌文件
logfile "日誌文件名"
設置服務器文件保存地址:dir path
dir "/redis/data"
windows配置爲:dir "./data"(須要在redis安裝的目錄新建data文件夾)
啓動
配置爲後臺啓動以後,能夠經過ps查看是否啓動
開發的時候,咱們仍是經過前臺啓動,由於查看日誌方便
殺掉進程:kill 9 6457
從新配置daemonize no
屏蔽logfile (若是不屏蔽,日誌仍是會寫入日誌文件,不會直接在cmd窗口顯示)
服務器容許客戶端鏈接最大數量,默認0,表示無限制。當客戶端鏈接到達上限後,Redis會拒絕新的鏈接
maxclients count
客戶端閒置等待最大時長,達到最大值後關閉對應鏈接。如需關閉該功能,設置爲 0
timeout seconds
設置服務器以指定日誌記錄級別
loglevel debug|verbose|notice|warning
日誌記錄文件名
logfile filename
注意:日誌級別開發期設置爲verbose便可,生產環境中配置爲notice,簡化日誌輸出量,下降寫日誌IO的頻度。
咱們須要會如下操做:
功能性命令
幫助信息查閱
退出指令
清除屏幕信息
設置 key,value 數據
set key value
範例
set name itheima
根據 key 查詢對應的 value,若是不存在,返回空(nil)
get key
範例
get name
獲取命令幫助文檔
help [command]
範例
help set
獲取組中全部命令信息名稱
help [@group-name]
範例
help @string
1.6.4 退出命令行客戶端模式
退出客戶端
quit 或 exit
快捷鍵
Ctrl+C
到這裏,Redis 入門的相關知識,咱們就所有學習完了,再來回顧一下,這個部分咱們主要講解了哪些內容呢?
首先,咱們對Redis進行了一個簡單介紹,包括NoSQL的概念、Redis的概念等
而後,咱們介紹了Redis 的下載與安裝。包括下載與安裝、服務器與客戶端啓動、以及相關配置文件(3類)
最後,咱們介紹了Redis 的基本操做。包括數據讀寫、退出與幫助信息獲取
在這個部分,咱們將學習一共要學習三大塊內容:
首先須要瞭解一下數據類型
接下來將針對着咱們要學習的數據類型進行逐一的講解,如string、hash、list、set等
最後咱們經過一個案例來總結前面的數據類型的使用場景
在講解數據類型以前,咱們得先思考一個問題,數據類型既然是用來描述數據的存儲格式的,若是你不知道哪些數據將來會進入到咱們來的redis中,那麼對應的數據類型的選擇,你就會出現問題,咱們一塊來看一下:
(1)原始業務功能設計
秒殺。他這個裏邊數據變化速度特別的快,訪問量也特別的高,用戶大量涌入之後都會針對着一部分數據進行操做,這一類要記住。
618活動。對於咱們京東的618活動、以及天貓的雙11活動,相信你們不用說都知道這些數據必定要進去,由於他們的訪問頻度實在過高了。
排隊購票。咱們12306的票務信息。這些信息在原始設計的時候,他們就註定了要進redis。
(2)運營平臺監控到的突發高頻訪問數據
此類平臺臨時監控到的這些數據,好比說如今出來的一個八卦的信息,這個新聞一旦出現之後呢,順速的被圍觀了,那麼這個時候,這個數據就會變得訪量特別高,那麼這類信息也要進入進去。
(3)高頻、複雜的統計數據
在線人數。好比說直播如今很火,直播裏邊有不少數據,例如在線人數。進一我的出一我的,這個數據就要跳動,那麼這個訪問速度很是的快,並且訪量很高,而且它裏邊有一個複雜的數據統計,在這裏這種信息也要進入到咱們的redis中。
投票排行榜。投票投票類的信息他的變化速度也比較快,爲了追求一個更快的一個即時投票的名次變化,這種數據最好也放到redis中。
基於以上數據特徵咱們進行分析,最終得出來咱們的Redis中要設計5種 數據類型:
string、hash、list、set、sorted_set/zset(應用性較低)
在學習第一個數據類型以前,先給你們介紹一下,在隨後這部份內容的學習過程當中,咱們每一種數據類型都分紅三塊來說:
首先是講下它的基本操做
接下來說一些它的擴展操做
最後咱們會去作一個小的案例分析
在學習string這個數據形式以前,咱們先要明白string究竟是修飾什麼的
咱們知道redis 自身是一個 Map,其中全部的數據都是採用 key : value 的形式存儲
對於這種結構來講,咱們用來存儲數據必定是一個值前面對應一個名稱,咱們經過名稱來訪問後面的值。
前面這一部分咱們稱爲key,後面的一部分稱爲value,而咱們的數據類型,他必定是修飾value的。
數據類型指的是存儲的數據的類型,也就是 value 部分的類型,key 部分永遠都是字符串。
(1)存儲的數據:單個數據,最簡單的數據存儲類型,也是最經常使用的數據存儲類型。
string,他就是存一個字符串兒,注意是value那一部分是一個字符串,它是redis中最基本、最簡單的存儲數據的格式。
(2)存儲數據的格式:一個存儲空間保存一個數據
每個空間中只能保存一個字符串信息,這個信息裏邊若是是存的純數字,他也能當數字使用,咱們來看一下,這是咱們的數據的存儲空間。
(3)存儲內容:一般使用字符串,若是字符串以整數的形式展現,能夠做爲數字操做使用.
一個key對一個value,而這個itheima就是咱們所說的string類型,固然它也能夠是一個純數字的格式。
(1)基礎指令
添加/修改數據添加/修改數據
set key value
獲取數據
get key
刪除數據
del key
斷定性添加數據 (瞭解)
setnx key value #SET if Not eXists (大寫組成命令)
添加/修改多個數據
mset key1 value1 key2 value2 … #m:Multiple 多個 many
獲取多個數據
mget key1 key2 …
獲取數據字符個數(字符串長度)
strlen key #STRing LENgth
追加信息到原始信息後部(若是原始信息存在就追加,不然新建)
append key value
演示:
(2)單數據操做與多數據操做的選擇之惑
即set 與mset的關係。這對於這兩個操做來講,沒有什麼你應該選哪一個,而是他們本身的特徵是什麼,你要根據這個特徵去比對你的業務,看看究竟適用於哪一個。
假如說這是咱們如今的服務器,他要向redis要數據的話,它會發出一條指令。那麼當這條指令發過來的時候,好比說是這個set指令過來,那麼它會把這個結果返回給你,這個時候咱們要思考這裏邊一共通過了多長時間。
首先,發送set指令要時間,這是網絡的一個時間,接下來redis要去運行這個指令要消耗時間,最終把這個結果返回給你又有一個時間,這個時間又是一個網絡的時間,那咱們能夠理解爲:一個指令發送的過程當中須要消耗這樣的時間.
可是若是說如今不是一條指令了,你要發3個set的話,還要多長時間呢?對應的發送時間要乘3了,由於這是三個單條指令,而運行的操做時間呢,它也要乘3了,但最終返回的也要發3次,因此這邊也要乘3。
因而咱們能夠獲得一個結論:單指令發3條它須要的時間,假定他們兩個同樣,是6個網絡時間加3個處理時間,若是咱們把它合成一個mset呢,咱們想想。
假如說用多指令發3個指令的話,其實只須要發一次就好了。這樣咱們能夠獲得一個結論,多指令發3個指令的話,其實它是兩個網絡時間加上3個redis的操做時間,爲何這寫一個小加號呢,就是由於畢竟發的信息量變大了,因此網絡時間有可能會變長。
那麼經過這張圖,你就能夠獲得一個結論,咱們單指令和多指令他們的差異就在於你發送的次數是多仍是少。當你影響的數據比較少的時候,你能夠用單指令,也能夠用多指令。可是一旦這個量大了,你就要選擇多指令了,他的效率會高一些。
下面咱們來看一string的擴展操做,分紅兩大塊:一塊是對數字進行操做的,第二塊是對咱們的key的時間進行操做的。
設置數值數據增長指定範圍的值
incr key #相似於i++ incrby key increment #至關於i+n incrbyfloat key increment #能夠操做小數 #increment 增長
設置數值數據減小指定範圍的值
decr key #相似於i-- decrby key increment #至關於i-n #decrement 減小
設置數據具備指定的生命週期 (***)
setex key seconds value *** psetex key milliseconds value #expire : 有效期,期限
演示:
數據操做不成功的反饋與數據正常操做之間的差別
表示運行結果是否成功 : 例如setnx
(integer) 0 → false 失敗
(integer) 1 → true 成功
表示運行結果值:例如獲取數據長度 strlen
(integer) 3 → 3 3個
(integer) 1 → 1 1個
數據未獲取到時,對應的數據爲(nil),等同於null
數據最大存儲量:512MB
string在redis內部存儲默認就是一個字符串,當遇到增減類操做incr,decr時會轉成數值型進行計算
注意:redis雖然能夠存儲數字,可是數字在內部存儲時依然是字符串類型
按數值進行操做的數據,若是原始數據不能轉成數值,或超越了redis 數值上限範圍,將報錯
上限是:9223372036854775807(也就是java中Long型數據最大值,Long.MAX_VALUE)
redis全部的操做都是原子性的,採用單線程處理全部業務,命令是一個一個執行的,所以無需考慮併發帶來的數據影響.
它的應用場景在於:主頁高頻訪問信息顯示控制,例如新浪微博大V主頁顯示粉絲數與微博數量。
咱們來思考一下:這些信息是否是你進入大V的頁面兒之後就要讀取這寫信息的啊,那這種信息必定要存儲到咱們的redis中,由於他的訪問量過高了!那這種數據應該怎麼存呢?咱們來一起看一下方案!
(1)在redis中爲大V用戶設定用戶信息,以用戶主鍵和屬性值做爲key,後臺設定定時刷新策略便可。
eg: user:id:3506728370:fans → 12210947 eg: user:id:3506728370:blogs → 6164 eg: user:id:3506728370:focuses → 83 #eg就是例子的意思
演示:
這個用戶的id爲123456,這個大v存儲了blogs和fans倆信息,分開存儲
(2)也能夠使用json格式保存數據
eg: user:id:3506728370 → {「fans」:12210947,「blogs」:6164,「 focuses 」:83 }
(3) key 的設置約定
數據庫中的熱點數據key命名慣例:由表名:主鍵名:主鍵值:字段名,做爲key名
表名 | 主鍵名 | 主鍵值 | 字段名 | |
---|---|---|---|---|
eg1: | order | id | 29437595 | name |
eg2: | equip | id | 390472345 | type |
eg3: | news | id | 202004150 | title |
下面咱們來學習第二個數據類型hash
對象類數據的存儲若是具備較頻繁的更新需求操做會顯得笨重!
在正式學習以前,咱們先來看一個關於數據存儲的困惑:
好比說前面咱們用以上形式存了數據,若是咱們用單條去存的話,它存的條數會不少。
但若是咱們用json格式,它存一條數據就夠了。
問題來了,假如說如今粉絲數量發生變化了,你要把整個值都改了。
可是用單條存的話就不存在這個問題,你只須要改其中一個就好了。
這個時候咱們就想,有沒有一種新的存儲結構,能幫咱們解決這個問題呢。
咱們一起來分析一下:
如上圖所示:單條的話是對應的數據在後面放着。
仔細觀察:咱們看左邊是否是長得都如出一轍啊,都是對應的表名、ID等的一系列的東西。
咱們能夠將右邊紅框中的這個區域給他封起來。
那若是要是這樣的形式的話,以下圖,咱們把它一合併,並把右邊的東西給他變成這個格式,這不就好了嗎?
這個圖其實你們並不陌生:
第一,你前面學過一個東西叫hashmap不就這格式嗎?
第二,redis自身不也是這格式嗎?那是什麼意思呢?
注意,這就是咱們要講的第二種格式,hash。
在右邊對應的值,咱們就存具體的值,那左邊兒這就是咱們的key。
問題來了,那中間的這一塊叫什麼呢?這個東西咱們給他起個名兒,叫作field字段。
那麼右邊兒總體這塊兒空間咱們就稱爲hash,也就是說hash是存了一個key value的存儲空間。
總結:
hash的結構是:key:{field:value,field2:value2}
在redis中的hash的值,能夠理解爲是一個對象
新的存儲需求:對一系列存儲的數據進行編組,方便管理,典型應用存儲對象信息
須要的存儲結構:一個存儲空間保存多個鍵值對數據
hash類型:底層使用哈希表結構實現數據存儲
如上圖所示,這種結構叫作hash,左邊一個key,對右邊一個存儲空間。這裏要明確一點,右邊這塊兒存儲空間叫hash,也就是說hash是指的一個數據類型,他指的不是一個數據,是這裏邊的一堆數據,那麼它底層呢,是用hash表的結構來實現的。
值得注意的是:
若是field數量較少,存儲結構優化爲類數組結構
若是field數量較多,存儲結構使用HashMap結構
添加/修改數據
hset key field value #h:hash
獲取數據
hget key field hgetall key
刪除數據
hdel key field1 [field2] #能夠刪除多個field,空格分隔便可
設置field的值,若是該field存在則不作任何操做
hsetnx key field value
添加/修改多個數據
hmset key field1 value1 field2 value2 …
獲取多個數據
hmget key field1 field2 …
獲取哈希表中字段的數量
hlen key
獲取哈希表中是否存在指定的字段
hexists key field
演示:hash的key是user:123
這裏刪除了一個還剩下一個,又增長3個,按理說長度應該是4的。這裏缺顯示的是5,這個多是老師對視頻截圖以後出的問題·
在看完hash的基本操做後,咱們再來看他的拓展操做,他的拓展操做相對比較簡單:
獲取哈希表中全部的字段名或字段值
hkeys key hvals key
設置指定字段的數值數據增長指定範圍的值
hincrby key field increment hincrbyfloat key field increment
演示:
(1)hash類型中value只能存儲字符串,不容許存儲其餘數據類型,不存在嵌套現象。若是數據未獲取到,對應的值爲(nil)
(2)每一個 hash 能夠存儲 (2的32次方 - 1) 個鍵值對
(3)hash類型十分貼近對象的數據存儲形式,而且能夠靈活添加刪除對象屬性。但hash設計初衷不是爲了存儲大量對象而設計 的,切記不可濫用,更不能夠將hash做爲對象列表使用
(4)hgetall 操做能夠獲取所有屬性,若是內部field過多,遍歷總體數據效率就很會低,有可能成爲數據訪問瓶頸
雙11活動日,銷售手機充值卡的商家對移動、聯通、電信的30元、50元、100元商品推出搶購活動,每種商品搶購上限1000 張。
也就是商家有了,商品有了,數量有了。最終咱們的用戶買東西就是在改變這個數量。那你說這個結構應該怎麼存呢?對應的商家的ID做爲key,而後這些充值卡的ID做爲field,最後這些數量做爲value。而咱們所謂的操做是其實就是increa這個操做,只不過你傳負值就好了。看一看對應的解決方案。
以商家id做爲key
將參與搶購的商品id做爲field
將參與搶購的商品數量做爲對應的value
搶購時使用降值的方式控制產品數量
注意:實際業務中還有超賣等實際問題,這裏不作討論
演示:
前面咱們存數據的時候呢,單個數據也能存,多個數據也能存
可是這裏面有一個問題,咱們存多個數據用hash的時候它是沒有順序的
咱們平時操做,實際上數據不少狀況下都是有順序的,那有沒有一種可以用來存儲帶有順序的這種數據模型呢
list就專門來幹這事兒
數據存儲需求:存儲多個數據,並對數據進入存儲空間的順序進行區分
須要的存儲結構:一個存儲空間保存多個數據,且經過數據能夠體現進入順序
list類型:保存多個數據,底層使用雙向鏈表存儲結構實現
先來經過一張圖,回憶一下順序表、鏈表、雙向鏈表。
下圖爲將cnpc插入前的圖示
下圖爲將cnpn插入後的圖示
順序表:想要插入cnpc,須要將後邊的元素都向後移動,比較麻煩
鏈表:想要插入cnpc,須要將頭指針和huawei的鏈條斷開,而後從新鏈接
鏈表的形式,插入挺高效,就是查詢比較慢,若是要查詢alibaba,就須要從頭查到尾
雙向鏈表:它的鏈條是雙向的
想要插入cnpc,也是須要斷開頭指針和華爲的鏈條,從新鏈接,因此插入也高效
可是查詢也是高效的,查詢能夠雙向查詢
雖然查詢alibaba也是從頭開始查詢,可是若是這時再查詢tencent,就能夠反向直接查詢到
list對應的存儲結構是什麼呢?裏邊存的這個東西是個列表,他有一個對應的名稱。
就是key存一個list的這樣結構。對應的基本操做,你實際上是能夠想到的。
來看一下,由於它是雙向的,因此他左邊右邊都能操做,它對應的操做結構兩邊都能進數據。這就是鏈表的一個存儲結構。
往外拿數據的時候怎麼拿呢?一般是從一端拿,固然另外一端也能拿。
若是兩端都能拿的話,這就是個雙端隊列,兩邊兒都能操做。若是隻能從一端進一端出,這個模型我們前面瞭解過,叫作棧。
lpush,rpush,lrange
隊列(排隊),先進先出
棧堆:摞(摞東西),先進後出
最後看一下他的基本操做
添加/修改數據
lpush key value1 [value2] …… rpush key value1 [value2] …… #l:left #r:right
獲取數據:由於列表存儲的數據有順序,因此能夠經過索引來獲取
lrange key start stop # range:範圍,查詢某個範圍的數據。stop若是寫-1,意味着直接查詢全部 lindex key index #index:索引,查詢某個索引的數據 llen key
獲取並移除數據:刪除以後會返回被刪除的數據
lpop key #左側刪除末尾數據(刪除最左側的數據) rpop key #右側刪除末尾數據(刪除最右側的數據)
演示:
分析:
移除指定數據:不返回刪除的數據
lrem key count value #rem remove移除 #count 能夠刪除多個,若是list中存儲了倆a,就能夠是 lrem list1 2 a
規定時間內獲取並移除數據:規定時間內取數據,能取到就返回,取不到就返回nil
blpop key1 [key2] timeout brpop key1 [key2] timeout brpoplpush source destination timeout #b:block:阻塞,塊
演示:
(1)list中保存的數據都是string類型的,數據總容量是有限的,最多 (2的32次方- 1) 個元素(4294967295)。
(2)list具備索引的概念,可是操做數據時一般以隊列的形式進行入隊出隊操做,或以棧的形式進行入棧出棧操做
(3)獲取所有數據操做結束索引設置爲-1
(4)list能夠對數據進行分頁操做,一般第一頁的信息來自於list,第2頁及更多的信息經過數據庫的形式加載
企業運營過程當中,系統將產生出大量的運營數據,如何保障多臺服務器操做日誌的統一順序輸出?
假如如今你有多臺服務器,每一臺服務器都會產生它的日誌,假設你是一個運維人員,你想看它的操做日誌,你怎麼看呢?打開A機器的日誌看一看,打開B機器的日誌再看一看嗎?這樣的話你會可能會瘋掉的!由於左邊看的有可能它的時間是11:01,右邊11:02,而後再看左邊11:03,它們自己是連續的,可是你在看的時候就分紅四個文件了,這個時候你看起來就會很麻煩。能不能把他們合併呢?答案是能夠的!怎麼作呢?創建起redis服務器。當他們須要記日誌的時候,記在哪兒,所有發給redis。等到你想看的時候,經過服務器訪問redis獲取日誌。而後獲得之後,就會獲得一個完整的日誌信息。那麼這裏面就能夠獲取到完整的日誌了,依靠什麼來實現呢?就依靠咱們的list的模型的順序來實現。進來一組數據就往裏加,誰先進來誰先加進去,它是有必定的順序的。
依賴list的數據具備順序的特徵對信息進行管理
使用隊列模型解決多路信息彙總合併的問題
使用棧模型解決最新消息的問題
演示:
先進先出,就用rpush放入,lrange取出便可
新的存儲需求:存儲大量的數據,在查詢方面提供更高的效率
須要的存儲結構:可以保存大量的數據,高效的內部存儲機制,便於查詢
set類型:與hash存儲結構徹底相同,僅存儲field,不存儲值(存儲的值都是nil),而且field是不容許重複的
經過這個名稱,你們也基本上可以認識到和咱們Java中的set徹底同樣。咱們如今要存儲大量的數據,而且要求提升它的查詢效率。用list這種鏈表形式,它的查詢效率是不高的,那怎麼辦呢?這時候咱們就想,有沒有高效的存儲機制。其實前面咱講Java的時候說過hash表的結構就很是的好,可是這裏邊咱們已經有hash了,他作了這麼一個設定,幹嗎呢,他把hash的存儲空間給改一下,右邊你原來存數據改掉,所有存空,那你說數據放哪兒了?放到原來的filed的位置,也就在這裏邊存真正的值,那麼這個模型就是咱們的set 模型。
set類型:與hash存儲結構徹底相同,僅存儲field,不存儲值(存儲的值都是nil),而且field是不容許重複的
看一下它的整個結構:
添加數據
sadd key member1 [member2]
獲取所有數據
smembers key #s:set #members:成員,set集合中每個元素叫作成員
刪除數據
srem key member1 [member2]
獲取集合數據總量
scard key
判斷集合中是否包含指定數據
sismember key member #ismember:是成員麼,是集合中的成員麼
隨機獲取集合中指定數量的數據 (瞭解)
srandmember key [count] #rand:random隨即
隨機獲取集中的某個數據並將該數據移除集合
spop key [count]
演示
求兩個集合的交、並、差集
sinter key1 [key2 …] #intersection : 交叉,交集 sunion key1 [key2 …] # union :聯合 sdiff key1 [key2 …] # difference:不一樣,差異
求兩個集合的交、並、差集並存儲到指定集合中
sinterstore destination key1 [key2 …] sunionstore destination key1 [key2 …] sdiffstore destination key1 [key2 …] # store:存儲 # destination:目的
將指定數據從原始集合中移動到目標集合中
smove source destination member #move:移動 #source:源
經過下面一張圖回憶一下交、並、差
演示:
set 類型不容許數據重複,若是添加的數據在 set 中已經存在,將只保留一份。
set 雖然與hash的存儲結構相同,可是沒法啓用hash中存儲值的空間。
(1)黑名單
資訊類信息類網站追求高訪問量,可是因爲其信息的價值,每每容易被不法分子利用,經過爬蟲技術, 快速獲取信息,個別特種行業網站信息經過爬蟲獲取分析後,能夠轉換成商業機密進行出售。例如第三方火 車票、機票、酒店刷票代購軟件,電商刷評論、刷好評。
同時爬蟲帶來的僞流量也會給經營者帶來錯覺,產生錯誤的決策,有效避免網站被爬蟲反覆爬取成爲每一個網站都要考慮的基本問題。在基於技術層面區分出爬蟲用戶後,須要將此類用戶進行有效的屏蔽,這就是黑名單的典型應用。
ps:不是說爬蟲必定作摧毀性的工做,有些小型網站須要爬蟲爲其帶來一些流量。
(2)白名單
對於安全性更高的應用訪問,僅僅靠黑名單是不能解決安全問題的,此時須要設定可訪問的用戶羣體, 依賴白名單作更爲苛刻的訪問驗證。
基於經營戰略設定問題用戶發現、鑑別規則
週期性更新知足規則的用戶黑名單,加入set集合
用戶行爲信息達到後與黑名單進行比對,確認行爲去向
黑名單過濾IP地址:應用於開放遊客訪問權限的信息源
黑名單過濾設備信息:應用於限定訪問設備的信息源
黑名單過濾用戶:應用於基於訪問權限的信息源
使用微信的過程當中,當微信接收消息後,會默認將最近接收的消息置頂,當多個好友及關注的訂閱號同時發送消息時,該排序會不停的進行交替。
同時還能夠將重要的會話設置爲置頂。
一旦用戶離線後,再次打開微信時,消息該按照什麼樣的順序顯示。
咱們分析一下:
100這臺手機表明你。而200、300、400這三臺表明你好友的手機。
在這裏有一些東西須要交代一下,由於咱們每一個人的都會對本身的微信中的一些比較重要的人設置會話置頂,將他的那條對話放在最上面。咱們假定這我的有兩個會話置頂的好友,分別是400和500,而這裏邊就包含400.
下面呢,咱們就來發這個消息,第一個發消息的是300,他發了個消息給100。發完之後,這個東西應該怎麼存儲呢?在這裏面必定要分開,記錄置頂的這些人的會話,對應的會話顯示順序和非置頂的必定要分兩。
這裏面咱們建立兩個模型,一個是普通的,一個是置頂的,而上面的這個置頂的用戶呢,咱們用set來存儲,由於不重複。而下面這些由於有順序,很容易想到用list去存儲,否則你怎麼表達順序呢?
上圖分析:
set指定存儲的是置頂好友:400和500
置頂好友和普通好友的聊天消息,經過list保存
那當300發給消息給100之後,這個時候咱們先斷定你在置頂人羣中嗎?不在,那好,300的消息對應的順序就應該放在普通的列表裏邊。而在這裏邊,咱們把300加進去。第一個數據也就是如今300。
上圖分析:
接下來400,發了個消息。判斷一下,他是須要置頂的,因此400將進入list的置頂裏邊放着。目前尚未特殊的地方。
上圖分析:
再來200發消息了,和剛纔的斷定方法同樣,先看在不在置頂裏,不在的話進普通,而後在普通裏邊把200加入就好了,OK,到這裏目前尚未順序變化。(右進右出)
接下來200又發消息過來,同一我的給你連發了兩條,那這個時候200的消息到達之後,先判斷是否在置頂範圍,不在,接下來他要放在list普通中,這裏你要注意一點,由於這裏邊已經有200,因此進來之後先幹一件事兒,把200殺掉,沒有200,而後再把200加進來,那你想一下,如今這個位置順序是什麼呢?就是新的都在右邊,對不對?
還記得咱們說list模型,若是是一個雙端隊列,它是能夠兩頭進兩頭出。固然咱們雙端從一頭進一頭出,這就是棧模型,如今我們運用的就是list模型中的棧模型(假設:右進右出)。
上圖分析:
如今300發消息,先斷定他在不在,不在,用普通的隊列,接下來按照剛纔的操做,無論你裏邊原來有沒有300,我先把300殺掉,沒了,200天然就填到300的位置了,他如今是list裏面惟一一個,而後讓300進來,注意是從右側進來的,那麼如今300就是最新的。
上圖分析:
那麼到這裏呢,咱們讓100來讀取消息。你以爲這個消息順序應該是什麼樣的?首先置頂的400有一個,他跑在最上面,而後list普通若是出來的話,300是最新的消息,而200在他後面的。用這種形式,咱們就能夠作出來他的消息順序來。
看一下最終的解決方案:
依賴list的數據具備順序的特徵對消息進行管理,將list結構做爲棧使用(一端進一段出)
置頂與普通會話分別建立獨立的list分別管理
當某個list中接收到用戶消息後,將消息發送方的id從list的一側加入list(上邊的案例是右側)
多個相同id發出的消息反覆入棧會出現問題,在入棧以前不管是否具備當前id對應的消息,先刪除對應id
推送消息時先推送置頂會話list,再推送普通會話list,推送完成的list清除全部數據 消息的數量,也就是微信用戶對話數量採用計數器的思想另行記錄,伴隨list操做同步更新
演示
最終結果是200,300,400,跟我們分析的正好相反,由於這裏是左側添加的
想要實現跟分析同樣的結果,使用rpush便可
總結一下,在整個數據類型的部分,咱們主要介紹了哪些內容:
首先咱們瞭解了一下數據類型,接下來針對着咱們要學習的數據類型,進行逐一講解了string、hash、list、set等,最後經過一個案例總結了一下前面的數據類型的使用場景。
在這部分中呢,咱們家學習兩個知識,第一個是key的經常使用指令,第二個是數據庫的經常使用指令
和前面咱們學數據類型作一下區分,前面你學的那些指令呢,都是針對某一個數據類型操做的,如今學的都是對全部的操做的
來看一下,咱們在學習Key的操做的時候,咱們先想一下的操做咱們應該學哪些東西
key是一個字符串,經過key獲取redis中保存的數據
對於key自身狀態的相關操做,例如:刪除,斷定存在,獲取類型等
對於key有效性控制相關操做,例如:有效期設定,斷定是否有效,有效狀態的切換等
對於key快速查詢操做,例如:按指定策略查詢key
刪除指定key
del key
獲取key是否存在
exists key
獲取key的類型
type key
演示
排序
sort
更名
rename key newkey renamenx key newkey
演示
爲指定key設置有效期
expire key seconds *** pexpire key milliseconds expireat key timestamp pexpireat key milliseconds-timestamp
獲取key的有效時間
ttl key # ttl:time to live:存活時間(過時時間) pttl key
切換key從時效性轉換爲永久性
persist key #persist 繼續存在,堅持
演示
查詢key
keys pattern
查詢模式規則
*匹配任意數量的任意符號 ? 配合一個任意符號 [] 匹配一個指定符號
keys * keys 查詢全部 it* keys 查詢全部以it開頭 *heima 查詢全部以heima結尾 keys ??heima 查詢全部前面兩個字符任意,後面以heima結尾 查詢全部以 keys user:? user:開頭,最後一個字符任意 keys u[st]er:1 查詢全部以u開頭,以er:1結尾,中間包含一個字母,s或t
演示
在這個地方咱們來說一下數據庫的經常使用指令,在講這個東西以前,咱們先思考一個問題:
假如說大家十我的同時操做redis,會不會出現key名字命名衝突的問題。
必定會,爲何?由於你的key是由程序而定義的。你想寫什麼寫什麼,那在使用的過程當中你們都在不停的加,遲早有一天他會衝突的。
redis在使用過程當中,伴隨着操做數據量的增長,會出現大量的數據以及對應的key。
那這個問題咱們要不要解決?要!怎麼解決呢?咱們最好把數據進行一個分類,除了命名規範咱們作統一之外,若是還能把它分開,這樣是否是衝突的機率就會小一些了,這就是我們下面要說的解決方案!
redis爲每一個服務提供有16個數據庫,編號從0到15
每一個數據庫之間的數據相互獨立
在對應的數據庫中劃出一塊區域,說他就是幾,你就用幾那塊,同時,其餘的這些均可以進行定義,一共是16個,這裏邊須要注意一點,他們這16個共用redis的內存。沒有說誰大誰小,也就是說數字只是表明了一起區域,區域具體多大未知。這是數據庫的一個分區的一個策略!
切換數據庫 ***
select index
其餘操做
ping
演示
數據移動
move key db
數據總量
dbsize
數據清除
flushdb # 清除當前庫的數據 flushall # 清除全部庫的數據 #flush:沖洗,沖掉
演示
在學習完redis後,咱們如今就要用Java來鏈接redis了,也就是咱們的這一章要學的Jedis了
在這個部分,咱們主要講解如下3個內容:
HelloWorld(Jedis版)
Jedis簡易工具類開發z
可視化客戶端
對於咱們如今的數據來講,它是在咱們的redis中,而最終咱們是要作程序。那麼程序就要和咱們的redis進行鏈接。
幹什麼事情呢?兩件事:程序中有數據的時候,咱們要把這些數據所有交給redis管理。
同時,redis中的數據還能取出來,回到咱們的應用程序中。
那在這個過程當中,在Java與redis之間打交道的這個東西就叫作Jedis.
簡單說,Jedis就是提供了Java與redis的鏈接服務的,裏邊有各類各樣的API接口,你能夠去調用它。
除了Jedis外,還有沒有其餘的這種鏈接服務呢?其實還有不少,瞭解一下:
Java語言鏈接redis服務 Jedis(SpringData、Redis 、 Lettuce)
其它語言:C 、C++ 、C# 、Erlang、Lua 、Objective-C 、Perl 、PHP 、Python 、Ruby 、Scala
(1)jar包導入:資料中「jar/jedis-3.1.0.jar」
下載地址:https://mvnrepository.com/artifact/redis.clients/jedis
(2)客戶端鏈接redis
鏈接redis
Jedis jedis = new Jedis("localhost", 6379);
操做redis
jedis.set("name", "itheima"); jedis.get("name");
關閉redis鏈接
jedis.close();
API文檔
http://xetorthio.github.io/jedis/
建立:com.itheima.JedisTest
public class JedisTest { public static void main(String[] args) { //1.獲取鏈接對象 Jedis jedis = new Jedis("127.0.0.1",6379); //2.執行操做 jedis.set("age","39"); // jedis提供的方法與redis命令基本一致 String hello = jedis.get("hello"); System.out.println(hello); jedis.lpush("list1","a","b","c","d"); List<String> list1 = jedis.lrange("list1", 0, -1); for (String s:list1 ) { System.out.println(s); } jedis.sadd("set1","abc","abc","def","poi","cba"); Long len = jedis.scard("set1"); System.out.println(len); //3.關閉鏈接 jedis.close(); } }
報錯:
修改配置文件bind爲虛擬機真實ip
修改程序
Jedis jedis = new Jedis("192.168.40.130",6379); //ip須要爲redis服務所在的真實ip
注意:若是配置文件的ip修改過,而且將redis重啓,而後代碼中也改了ip以後,仍是鏈接不上那多是linux的防火牆問題:
#關閉防火牆 systemctl stop firewalld #重啓redis服務
前面咱們作的程序仍是有點兒小問題,就是咱們的Jedis對象的管理是咱們本身建立的,真實企業開發中是不可能讓你去new一個的,那接下來我們就要作一個工具類,簡單來講,就是作一個建立Jedis的這樣的一個工具。
JedisPool:Jedis提供的鏈接池技術
poolConfig:鏈接池配置對象
host:redis服務地址
port:redis服務端口號
JedisPool的構造器以下: (源碼)
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) { this(poolConfig, host, port, 2000, (String)null, 0, (String)null); }
建立jedis的配置文件:jedis.properties
jedis.host=192.168.40.130 jedis.port=6379 jedis.maxTotal=50 #控制一個pool可分配多少個jedis實例 jedis.maxIdle=10 #控制一個pool最多有多少個狀態爲idle(空閒的)的jedis實例 # 就是說若是沒人用jedis,那麼這個池子裏就只有10個jedis實例 # 若是用的人很是多,可是不會超過50個
建立JedisUtils:com.itheima.util.JedisUtils,使用靜態代碼塊初始化資源
public class JedisUtils { private static int maxTotal; private static int maxIdel; private static String host; private static int port; private static JedisPoolConfig jpc; private static JedisPool jp; static { ResourceBundle bundle = ResourceBundle.getBundle("jedis"); maxTotal = Integer.parseInt(bundle.getString("jedis.maxTotal")); maxIdel = Integer.parseInt(bundle.getString("jedis.maxIdel")); host = bundle.getString("jedis.host"); port = Integer.parseInt(bundle.getString("jedis.port")); //Jedis鏈接池配置 jpc = new JedisPoolConfig(); jpc.setMaxTotal(maxTotal); jpc.setMaxIdle(maxIdel); jp = new JedisPool(jpc,host,port); } }
對外訪問接口,提供jedis鏈接對象,鏈接從鏈接池獲取,在JedisUtils中添加一個獲取jedis的方法:getJedis
public static Jedis getJedis(){ Jedis jedis = jp.getResource(); return jedis; }
測試類:使用鏈接池
package com.itheima; import com.itheima.util.JedisUtils; import redis.clients.jedis.Jedis; public class JedisTest { public static void main(String[] args) { //1.獲取鏈接對象 // Jedis jedis = new Jedis("192.168.40.130",6379); Jedis jedis = JedisUtils.getJedis(); //2.執行操做 // jedis.set("age","39"); // String hello = jedis.get("hello"); // System.out.println(hello); // jedis.lpush("list1","a","b","c","d"); // List<String> list1 = jedis.lrange("list1", 0, -1); // for (String s:list1 ) { // System.out.println(s); // } jedis.sadd("set1","abc","abc","def","poi","cba"); Long len = jedis.scard("set1"); System.out.println(len); //3.關閉鏈接 jedis.close(); } }
4.3.1 Redis Desktop Manager
下面呢,進入到持久化的學習.這部份內容理解的東西多,操做的東西少。在這個部分,咱們將講解四個東西:
持久化簡介
RDB
AOF
RDB與AOF區別
不知道你們有沒有碰見過,就是正工做的時候停電了,若是你用的是筆記本電腦還好,你有電池
但若是你用的是臺式機呢,那恐怕就比較災難了
假如你如今正在寫一個比較重要的文檔,若是你要使用的是word,這種辦公自動化軟件的話,他一旦遇到停電,其實你不用擔憂,由於它會給你生成一些其餘的文件
其實他們都在作一件事兒,幫你自動恢復,有了這個文件,你前面的東西就再也不丟了。那什麼是自動恢復呢?你要先了解他的整個過程。
咱們說自動恢復,其實基於的一個前提就是他提早把你的數據給存起來了。你日常操做的全部信息都是在內存中的,而咱們真正的信息是保存在硬盤中的,內存中的信息斷電之後就消失了,硬盤中的信息斷電之後還能夠保留下來!
咱們將文件由內存中保存到硬盤中的這個過程,咱們叫作數據保存,也就叫作持久化。
可是把它保存下來不是你的目的,最終你還要把它再讀取出來,它加載到內存中這個過程,咱們叫作數據恢復,
這就是咱們所說的word爲何斷電之後還可以給你保留文件,由於它執行了一個自動備份的過程,也就是經過自動的形式,把你的數據存儲起來,那麼有了這種形式之後,咱們的數據就能夠由內存到硬盤上實現保存。
(1)什麼是持久化
利用永久性存儲介質將數據進行保存,在特定的時間將保存的數據進行恢復的工做機制稱爲持久化 。
持久化用於防止數據的意外丟失,確保數據安全性。
(2)持久化過程保存什麼?
咱們知道一點,計算機中的數據所有都是二進制,若是如今我要你給我保存一組數據的話,你有什麼樣的方式呢,其實最簡單的就是如今長什麼樣,我就記下來就好了,那麼這種是記錄純粹的數據,也叫作快照存儲,也就是它保存的是某一時刻的數據狀態。
還有一種形式,它不記錄你的數據,它記錄你全部的操做過程,好比說你們用idea的時候,有沒有遇到過寫錯了ctrl+z撤銷,而後ctrl+y還能恢復,這個地方它也是在記錄,可是記錄的是你全部的操做過程,那我想問一下,操做過程,我都給你留下來了,你說數據還會丟嗎?確定不會丟,由於你全部的操做過程我都保存了。這種保存操做過程的存儲,用專業術語來講能夠說是日誌,這是兩種不一樣的保存數據的形式啊。
總結一下:
第一種:將當前數據狀態進行保存,快照形式,存儲數據結果,存儲格式簡單,關注點在數據。(Ctrl+c加Ctrl+v)
第二種:將數據的操做過程進行保存,日誌形式,存儲操做過程,存儲格式複雜,關注點在數據的操做過程。
RDB:Redis DataBase
手動執行一次保存操做
save
save指令相關配置
設置本地數據庫文件名,默認值爲 dump.rdb,一般設置爲dump-端口號.rdb
dbfilename filename
設置存儲.rdb文件的路徑,一般設置成存儲空間較大的目錄中,目錄名稱data
dir path
設置存儲至本地數據庫時是否壓縮數據,默認yes,設置爲no,節省 CPU 運行時間,但存儲文件變大
rdbcompression yes|no
設置讀寫文件過程是否進行RDB格式校驗,默認yes,設置爲no,節約讀寫10%時間消耗,單存在數據損壞的風險
rdbchecksum yes|no
演示
增長dbfilename配置(屏蔽logfile)
從新啓動redis
查看data目錄的文件
而後在啓動redis服務的窗口,能夠看到db saved on disk
關閉服務
啓動服務:發現從硬盤讀取了數據
查詢
以前咱們退出redis,從新進入,以前的數據就丟失了,如今沒有丟失,就是由於在退出以前save保存了
save指令工做原理
須要注意一個問題,來看一下,如今有四個客戶端各自要執行一個指令,把這些指令發送到redis服務器後,他們執行有一個前後順序問題,假定就是按照1234的順序放過去的話,那會是什麼樣的?
記得redis是個單線程的工做模式,它會建立一個任務隊列,全部的命令都會進到這個隊列裏邊,在這兒排隊執行,執行完一個消失一個,當全部的命令都執行完了,OK,結果達到了。
可是若是如今咱們執行的時候save指令保存的數據量很大會是什麼現象呢?
他會很是耗時,以致於影響到它在執行的時候,後面的指令都要等,因此說這種模式是不友好的,這是save指令對應的一個問題,當cpu執行的時候會阻塞redis服務器,直到他執行完畢,因此說咱們不建議你們在線上環境用save指令。
以前咱們講到了當save指令的數據量過大時,單線程執行方式形成效率太低,那應該如何處理?
此時咱們能夠使用:bgsave指令,bg實際上是background的意思,後臺執行的意思
手動啓動後臺保存操做,但不是當即執行
bgsave
bgsave指令相關配置
後臺存儲過程當中若是出現錯誤現象,是否中止保存操做,默認yes
stop-writes-on-bgsave-error yes|no
演示
bgsave指令工做原理
當執行bgsave的時候,客戶端發出bgsave指令給到redis服務器。
注意,這個時候服務器立刻回一個結果告訴客戶端後臺已經開始了,與此同時它會建立一個子進程,使用Linux的fork(分叉)函數建立一個子進程,讓這個子進程去執行save相關的操做
此時咱們能夠想一下,咱們主進程一直在處理指令,而子進程在執行後臺的保存,它會不會干擾到主進程的執行嗎?
答案是不會,因此說他纔是主流方案。
子進程開始執行以後,它就會建立RDB文件把它存起來,操做完之後他會把這個結果返回,也就是說bgsave的過程分紅兩個過程,
第一個是服務端拿到指令直接告訴客戶端開始執行了;
另一個過程是一個子進程在完成後臺的保存操做,操做完之後回一個消息。
設置自動持久化的條件,知足限定時間範圍內key的變化數量達到指定數量即進行持久化
save second changes
參數
second:監控時間範圍
changes:監控key的變化量
範例:
save 900 1 #900s以內只要有1個key發生改變,就會保存 save 300 10 save 60 10000
演示:
刪除數據庫文件
配置
從新啓動redis
鏈接redis,添加數據
觀察rdb文件
若是再設置兩個,那麼rdb文件就會被修改(文件的修改時間會變)
save配置工做原理
方式 | SAVE指令 | BGSAVE指令 |
---|---|---|
讀寫 | 同步 | 異步 |
阻塞客戶端指令 | 是 | 否 |
額外內存消耗 | 否 | 是 |
啓動新進程 | 否 | 是 |
RDB特殊啓動形式
以前已經介紹了三種,還有三種瞭解一下便可:
服務器運行過程當中重啓
debug reload
關閉服務器時指定保存數據
shutdown save
全量複製(在主從複製中詳細講解)
RDB優勢:
RDB是一個緊湊壓縮的二進制文件,存儲效率較高
RDB內部存儲的是redis在某個時間點的數據快照,很是適合用於數據備份,全量複製等場景
RDB恢復數據的速度要比AOF快不少
應用:服務器中每X小時執行bgsave備份,並將RDB文件拷貝到遠程機器中,用於災難恢復。
RDB缺點
RDB方式不管是執行指令仍是利用配置,沒法作到實時持久化,具備較大的可能性丟失數據
bgsave指令每次運行要執行fork操做建立子進程,要犧牲掉一些性能
Redis的衆多版本中未進行RDB文件格式的版本統一,有可能出現各版本服務之間數據格式沒法兼容現象
爲何要有AOF,這得從RDB的存儲的弊端提及:
存儲數據量較大,效率較低,基於快照思想,每次讀寫都是所有數據,當數據量巨大時,效率很是低
大數據量下的IO性能較低
基於fork建立子進程,內存產生額外消耗
宕機帶來的數據丟失風險
那解決的思路是什麼呢?
不寫全數據,僅記錄部分數據
下降區分數據是否改變的難度,改記錄數據爲記錄操做過程
對全部操做均進行記錄,排除丟失數據的風險
AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啓時再從新執行AOF文件中命令 達到恢復數據的目的。與RDB相比能夠簡單理解爲由記錄數據改成記錄數據產生的變化
AOF的主要做用是解決了數據持久化的實時性,目前已是Redis持久化的主流方式
AOF寫數據過程
啓動AOF相關配置
開啓AOF持久化功能,默認no,即不開啓狀態
appendonly yes|no
AOF持久化文件名,默認文件名爲appendonly.aof,建議配置爲appendonly-端口號.aof
appendfilename filename
AOF持久化文件保存路徑,與RDB持久化文件保持一致便可
dir
AOF寫數據策略,默認爲everysec
appendfsync always|everysec|no
AOF寫數據三種策略(appendfsync)
always(每次):每次寫入操做均同步到AOF文件中數據零偏差,性能較低,不建議使用。
everysec(每秒):每秒將緩衝區中的指令同步到AOF文件中,在系統忽然宕機的狀況下丟失1秒內的數據 數據準確性較高,性能較高,建議使用,也是默認配置
no(系統控制):由操做系統控制每次同步到AOF文件的週期,總體過程不可控
演示:
修改配置(而且清除data目錄中的全部文件)
鏈接
查看日誌文件,發現有了(雖然只是登錄了,沒執行任何命令,可是1s已通過去了,這個文件就會生成,只不過裏邊沒有記錄東西)
執行指令
查看日誌文件
select 0 , 是默認執行的一個指令,默認操做的是0號庫
*3表明這個指令分爲3部分
再次執行指令
再次查看日誌
執行其餘命令,可是若是執行的命令,沒有影響數據,是不會記錄的
查看日誌,發現只有一次del name4
中止重啓
從新查詢數據,發現是有的,加載日誌文件成功
場景:AOF寫數據遇到的問題,若是連續執行以下指令該如何處理
什麼叫AOF重寫?
隨着命令不斷寫入AOF,文件會愈來愈大,爲了解決這個問題,Redis引入了AOF重寫機制壓縮文件體積。
AOF文件重寫是將Redis進程內的數據轉化爲寫命令同步到新AOF文件的過程。
簡單說就是將對同一個數據的若干個條命令執行結果 轉化成 最終結果數據對應的指令進行記錄。
AOF重寫做用
下降磁盤佔用量,提升磁盤利用率
提升持久化效率,下降持久化寫時間,提升IO性能
下降數據恢復用時,提升數據恢復效率
AOF重寫規則
進程內具備時效性的數據,而且數據已超時將再也不寫入文件
非寫入類的無效指令將被忽略,只保留最終數據的寫入命令
如del key一、 hdel key二、srem key三、set key4 1十一、set key4 222等
如select指令雖然不更改數據,可是更改了數據的存儲位置,此類命令一樣須要記錄
對同一數據的多條寫命令合併爲一條命令
如lpushlist1 a、lpush list1 b、lpush list1 c能夠轉化爲:lpush list1 a b c。
爲防止數據量過大形成客戶端緩衝區溢出,對list、set、hash、zset等類型,每條指令最多寫入64個元素
AOF重寫方式
手動重寫
bgrewriteaof # 這是一個redis指令,不是配置
演示:
中止服務和客戶端,而後清除data內的全部文件
執行指令:設置幾個數據,而後手動重寫
接下來再設置數據
查看日誌文件:發現重寫以前的都看不懂了,重寫以後的仍是以前的
再次設置多個相同的指令
查看日誌:發現仍是以前的,可是這裏會有屢次記錄(咱們須要經過重寫簡化)
收手動重寫
手動重寫:發現已經重寫完畢
手動重寫原理分析:
自動重寫
自動重寫觸發條件設置
auto-aof-rewrite-min-size size # 達到指定大小就自動重寫,size能夠指定多少兆:2MB 、 4MB auto-aof-rewrite-percentage percent #按照存儲佔用總體的百分比自動重寫,percent指定10%,達到10%就能夠自動重寫
自動重寫觸發比對參數( 運行指令info Persistence獲取具體信息 )
aof_current_size aof_base_size
自動重寫觸發條件公式:
aof_current_size:aof當前尺寸,若是大於auto-aof-rewrite-min-siz:aof重寫的最小尺寸,就重寫
aof_base_size:aof的基礎尺寸,就是目前已經備份的總大小
aof_current_size:就是當前即將要備份的大小
上邊的公式寫反了:應該是aof_current_size - aof_base_size
持久化方式 | RDB | AOF |
---|---|---|
佔用存儲空間 | 小(數據級:壓縮) | 大(指令級:重寫) |
存儲速度 | 慢 | 快 |
恢復速度 | 快 | 慢 |
數據安全性 | 會丟失數據 | 依據策略決定 |
資源消耗 | 高/重量級 | 低/輕量級 |
啓動優先級 | 低 | 高 |
RDB與AOF的選擇之惑
對數據很是敏感,建議使用默認的AOF持久化方案
AOF持久化策略使用everysecond,每秒鐘fsync一次。該策略redis仍能夠保持很好的處理性能,當出 現問題時,最多丟失0-1秒內的數據。
注意:因爲AOF文件存儲體積較大,且恢復速度較慢
數據呈現階段有效性,建議使用RDB持久化方案
數據能夠良好的作到階段內無丟失(該階段是開發者或運維人員手工維護的),且恢復速度較快,階段 點數據恢復一般採用RDB方案
注意:利用RDB實現緊湊的數據持久化會使Redis降的很低,慎重總結:
綜合比對
RDB與AOF的選擇其實是在作一種權衡,每種都有利有弊
如不能承受數分鐘之內的數據丟失,對業務數據很是敏感,選用AOF
如能承受數分鐘之內的數據丟失,且追求大數據集的恢復速度,選用RDB
災難恢復選用RDB