Redis入門--進階詳解
阿新 • • 發佈:2020-08-26
# Redis
## NoSql入門和概述
### 入門概述
#### 網際網路時代背景下大機遇,為什麼用nosql
##### 1.單機MySQL的美好年代
* 在90年代,一個網站的訪問量一般都不大,用單個數據庫完全可以輕鬆應付,在那個時候,更多的都是靜態網頁,動態互動型別的網站不多
* ![image-20200819133746031](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153852390-1269859330.png)
* 上述架構下,我們來看看資料儲存的瓶頸是什麼?
1. 資料量的總大小 一個機器放不下時
2. 資料的索引(B+ Tree)一個機器的記憶體放不下時
3. 訪問量(讀寫混合)一個例項不能承受
##### 2.Memcached(快取)+MySQL+垂直拆分
* 後來,隨著訪問量的上升,幾乎大部分使用MySQL架構的網站在資料庫上都開始出現了效能問題,web程式不再僅僅專注在功能上,同時也在追求效能。程式設計師們開始大量的使用快取技術來緩解資料庫的壓力,優化資料庫的結構和索引。開始比較流行的是通過檔案快取來緩解資料庫壓力,但是當訪問量繼續增大的時候,多臺web機器通過檔案快取不能共享,大量的小檔案快取也帶了了比較高的IO壓力。在這個時候,Memcached就自然的成為一個非常時尚的技術產品
* ![image-20200819135316004](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153852729-901440485.png)
* Memcached作為一個獨立的分散式的快取伺服器,為多個web伺服器提供了一個共享的高效能快取服務,在Memcached伺服器上,又發展了根據hash演算法來進行多臺Memcached快取服務的擴充套件,然後又出現了一致性hash來解決增加或減少快取伺服器導致重新hash帶來的大量快取失效的弊端
##### 3.MySQL主從讀寫分離
* 由於資料庫的寫入壓力增加,Memcached只能緩解資料庫的讀取壓力。讀寫集中在一個數據庫上讓資料庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫效能和讀庫的可擴充套件性。Mysql的master-slave模式成為這個時候的網站標配了
* ![image-20200819140121843](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153853396-385518163.png)
##### 4.分表分庫+水平拆分+mysql叢集
* 在Memcached的快取記憶體,MySQL的主從複製,讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而資料量的持續猛增,由於MyISAM使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM
* 同時,開始流行使用分表分庫來緩解寫壓力和資料增長的擴充套件問題。這個時候,分表分庫成了一個熱門技術,是面試的熱門問題也是業界討論的熱門技術問題。也就在這個時候,MySQL推出了還不太穩定的表分割槽,這也給技術實力一般的公司帶來了希望。雖然MySQL推出了MySQL Cluster叢集,但效能也不能很好滿足網際網路的要求,只是在高可靠性上提供了非常大的保證
* ![image-20200819141000786](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153854064-373767494.png)
##### 5.MySQL的擴充套件性瓶頸
* MySQL資料庫也經常儲存一些大文字欄位,導致資料庫表非常的大,在做資料庫恢復的時候就導致非常的慢,不容易快速恢復資料庫。比如1000萬4KB大小的文字就接近40GB的大小,如果能把這些資料從MySQL省去,MySQL將變得非常的小。關係資料庫很強大,但是它並不能很好的應付所有的應用場景。MySQL的擴充套件性差(需要複雜的技術來實現),大資料下IO壓力大,表結構更改困難,正是當前使用MySQL的開發人員面臨的問題
##### 6.今天系統是什麼樣子
* ![image-20200819141451036](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153854960-1625564455.png)
##### 7.為什麼要用NoSQL
* 今天我們可以通過第三方平臺(如:Google,Facebook等)可以很容易的訪問和抓取資料。使用者的個人資訊,社交網路,地理位置,使用者生成的資料和使用者操作日誌已經成倍的增加。我們如果要對這些使用者資料進行挖掘,那SQL資料庫已經不適合這些應用了, NoSQL資料庫的發展也卻能很好的處理這些大的資料
* ![image-20200819141649524](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153855535-1772526744.png)
#### 是什麼
* NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”
* **泛指非關係型的資料庫**。隨著網際網路web2.0網站的興起,傳統的關係資料庫在應付web2.0網站,特別是超大規模和高併發的SNS型別的web2.0純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關係型的資料庫則由於其本身的特點得到了非常迅速的發展。NoSQL資料庫的產生就是為了解決大規模資料集合多重資料種類帶來的挑戰,尤其是大資料應用難題,包括超大規模資料的儲存
* (例如谷歌或Facebook每天為他們的使用者收集萬億位元的資料)。**這些型別的資料儲存不需要固定的模式**,**無需多餘操作就可以橫向擴充套件**
#### 能幹嘛
##### 易擴充套件
* NoSQL資料庫種類繁多,但是一個共同的特點都是去掉關係資料庫的關係型特徵。資料之間無關係,這樣就非常容易擴充套件。也無形之間,在架構的層面上帶來了可擴充套件的能力
##### 大資料量高效能
* NoSQL資料庫都具有非常高的讀寫效能,尤其在大資料量下,同樣表現優秀,這得益於它的無關係性,資料庫的結構簡單
* 一般MySQL使用Query Cache,每次表的更新Cache就失效,是一種大粒度的Cache,
在針對web2.0的互動頻繁的應用,Cache效能不高。而NoSQL的Cache是記錄級的,
是一種細粒度的Cache,所以NoSQL在這個層面上來說就要效能高很多
##### 多樣靈活的資料模型
* NoSQL無需事先為要儲存的資料建立欄位,隨時可以儲存自定義的資料格式。而在關係資料庫裡,
增刪欄位是一件非常麻煩的事情。如果是非常大資料量的表,增加欄位簡直就是一個噩夢
##### 傳統RDBMS VS NOSQL
* RDBMS vs NoSQL
* | RDBMS | NoSQL |
| :--------------------------: | :-----------------------------------------: |
| 高度組織化結構化資料 | 代表著不僅僅是SQL |
| 結構化查詢語言(SQL) | 沒有宣告性查詢語言 |
| 資料和關係都儲存在單獨的表中 | 沒有預定義的模式 |
| 資料操縱語言,資料定義語言 | 鍵 - 值對儲存,列儲存,文件儲存,圖形資料庫 |
| 嚴格的一致性 | 最終一致性,而非ACID屬性 |
| 基礎事務 | 非結構化和不可預知的資料 |
| | CAP定理 |
| | 高效能,高可用性和可伸縮性 |
#### 去哪裡下
* Redis
* Memcache
* Mongdb
#### 怎麼玩
* KV
* Cache
* Persistence
* ......
### 3V+3高
#### 大資料時代的3V
* 海量Volume
* 多樣Variety
* 實時Velocity
#### 網際網路需求的3高
* 高併發
* 高可擴
* 高效能
### 當下的NoSQL經典應用
#### 當下的應用是sql和nosql一起使用
#### 阿里巴巴中文站商品資訊如何存放
* 和我們相關的,多資料來源多資料型別的儲存問題![image-20200819170618027](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153856525-683363412.png)
##### 1.商品基本資訊
* 名稱、價格,出廠日期,生產廠商等
* 關係型資料庫:mysql/oracle目前淘寶在去O化(也即拿掉Oracle),**注意,淘寶內部用的Mysql是裡面的大牛自己改造過的**
* **為什麼去IOE**:2008年,王堅加盟阿里巴巴成為集團首席架構師,即現在的首席技術官。這位前微軟亞洲研究院常務副院長被馬雲定位為:將幫助阿里巴巴集團建立世界級的技術團隊,並負責集團技術架構以及基礎技術平臺搭建。
在加入阿里後,帶著技術基因和學者風範的王堅就在阿里巴巴集團提出了被稱為“去IOE”**(在IT建設過程中,去除IBM小型機、Oracle資料庫及EMC儲存裝置)**的想法,並開始把雲端計算的本質,植入阿里IT基因。
王堅這樣概括“去IOE”運動和阿里雲之間的關係:“去IOE”徹底改變了阿里集團IT架構的基礎,是阿里擁抱雲端計算,產出計算服務的基礎。“去IOE”的本質是分佈化,讓隨處可以買到的Commodity PC架構成為可能,使雲端計算能夠落地的首要條件。
##### 2.商品描述、詳情、評價資訊(多文字類)
+ 多文字資訊描述類,IO讀寫效能變差
+ 文件資料庫MongDB中
##### 3.商品的圖片
* 商品圖片展示類
* 分散式的檔案系統中
* 淘寶自己的TFS
* Google的GFS
* Hadoop的HDFS
##### 4.商品的關鍵字
* 搜尋引擎,淘寶內用
* ISearch
##### 5.商品的波段性的熱點高頻資訊
* 記憶體資料庫
* Tair、Redis、Memcache
##### 6.商品的交易、價格計算、積分累計
* 外部系統,外部第3方支付介面
* 支付寶
##### 7.總結大型網際網路應用(大資料、高併發、多樣資料型別)的難點和解決方案
* 難點
* 資料型別多樣性
* 資料來源多樣性和變化重構
* 資料來源改造而資料服務平臺不需要大面積重構
* 解決辦法
* EAI和統一資料平臺服務
* 阿里、淘寶:UDSL
* 是什麼![image-20200820090726321](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153857458-2102412683.png)
* 什麼樣![image-20200820091124556](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153858560-1942272251.png)
1. 對映
2. API
3. 熱點快取
4. ......
### NoSQL資料模型簡介
#### 以一個電商客戶、訂單、訂購、地址模型來對比下關係型資料庫和非關係型資料庫
##### 傳統的關係型資料庫你如何設計?
* ER圖(1:1/1:N/N:N,主外來鍵等常見)![image-20200820095922687](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153859297-1446664528.png)
##### NoSQL你如何設計
* 什麼是BSON:BSON()是一種類json的一種二進位制形式的儲存格式,簡稱Binary JSON,它和JSON一樣,支援內嵌的文件物件和陣列物件
* BSON資料模型
* ````
{
"customer":{
"id":1136,
"name":"Z3",
"billingAddress":[{"city":"beijing"}],
"orders":[
{
"id":17,
"customerId":1136,
"orderItems":[{"productId":27,"price":77.5,"productName":"thinking in java"}],
"shippingAddress":[{"city":"beijing"}]
"orderPayment":[{"ccinfo":"111-222-333","txnid":"asdfadcd334","billingAddress":{"city":"beijing"}}],
}
]
}
}
````
##### 兩者對比,問題和難點
* 為什麼上述的情況可以用聚合模型來處理
* 高併發的操作是不太建議有關聯查詢的,網際網路公司用冗餘資料來避免關聯查詢
* 分散式事務是支援不了太多的併發的
* 啟發學生,想想關係模型資料庫你如何查?如果按照我們新設計的BSon,是不是查詢起來很可愛
#### 聚合模型
* KV鍵值對
* BSON
* 列族
* 顧名思義,是按列儲存資料的。最大的特點是方便儲存結構化和半結構化資料,方便做資料壓縮,對針對某一列或者某幾列的查詢有非常大的IO優勢![image-20200820104717957](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153900024-1534135078.png)
* 圖形![image-20200820104751889](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153900858-1321820469.png)
### NoSQL資料庫的四大分類
#### KV鍵值:典型介紹
* 新浪:BerkeleyDB+redis
* 美團:redis+tair
* 阿里、百度:memcache+redis
#### 文件型資料庫(bson格式比較多):典型介紹
* CouchDB
* MongoDB
* MongoDB 是一個基於分散式檔案儲存的資料庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴充套件的高效能資料儲存解決方案
* MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的
#### 列儲存資料庫
* Cassandra、HBase
* 分散式檔案系統
#### 圖關係資料庫
* 它不是放圖形的,放的是關係比如:朋友圈社交網路、廣告推薦系統,社交網路,推薦系統等。專注於構建關係圖譜
* Neo4j,InfoGrid
#### 四者對比
* ![image-20200820111234007](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153901635-223231725.png)
### 在分散式資料庫中CAP原理CAP+BASE
#### 傳統的ACID分別是什麼
* A (Atomicity) 原子性
原子性很容易理解,也就是說事務裡的所有操作要麼全部做完,要麼都不做,事務成功的條件是事務裡的所有操作都成功,只要有一個操作失敗,整個事務就失敗,需要回滾。比如銀行轉賬,從A賬戶轉100元至B賬戶,分為兩個步驟:1)從A賬戶取100元;2)存入100元至B賬戶。這兩步要麼一起完成,要麼一起不完成,如果只完成第一步,第二步失敗,錢會莫名其妙少了100元。
* C (Consistency) 一致性
一致性也比較容易理解,也就是說資料庫要一直處於一致的狀態,事務的執行不會改變資料庫原本的一致性約束。
* I (Isolation) 獨立性
所謂的獨立性是指併發的事務之間不會互相影響,如果一個事務要訪問的資料正在被另外一個事務修改,只要另外一個事務未提交,它所訪問的資料就不受未提交事務的影響。比如現有有個交易是從A賬戶轉100元至B賬戶,在這個交易還未完成的情況下,如果此時B查詢自己的賬戶,是看不到新增加的100元的
* D (Durability) 永續性
永續性是指一旦事務提交後,它所做的修改將會永久的儲存在資料庫上,即使出現宕機也不會丟失。
#### CAP
* C:Consistency(強一致性)
* A:Availability(可用性)
* P:Partition tolerance(分割槽容錯性)
#### CAP的三選二
* CAP理論就是說在分散式儲存系統中,最多隻能實現上面的兩點。而由於當前的網路硬體肯定會出現延遲丟包等問題,**所以分割槽容忍性是我們必須需要實現的**。所以我們只能在一致性和可用性之間進行權衡,沒有NoSQL系統能同時保證這三點
* C:強一致性 、A:高可用性 、P:分散式容忍性
* CA 傳統Oracle資料庫
* AP 大多數網站架構的選擇
* CP Redis、Mongodb
* 注意:分散式架構的時候必須做出取捨。一致性和可用性之間取一個平衡。多餘大多數web應用,其實並不需要強一致性。因此犧牲C換取P,這是目前分散式資料庫產品的方向
#### 經典CAP圖
* CAP理論的核心是:一個分散式系統不可能同時很好的滿足一致性,可用性和分割槽容錯性這三個需求,
最多隻能同時較好的滿足兩個。因此,根據 CAP 原理將 NoSQL 資料庫分成了滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三 大類:
* CA - 單點叢集,滿足一致性,可用性的系統,通常在可擴充套件性上不太強大
* CP - 滿足一致性,分割槽容忍必的系統,通常效能不是特別高
* AP - 滿足可用性,分割槽容忍性的系統,通常可能對一致性要求低一些
* ![image-20200820113420911](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153902331-1553780397.png)
#### BASE
* > BASE就是為了解決關係資料庫強一致性引起的問題而引起的可用性降低而提出的解決方案。
* BASE其實是下面三個術語的縮寫:
* 基本可用(Basically Available)
* 軟狀態(Soft state)
* 最終一致(Eventually consistent)
* 它的思想是**通過讓系統放鬆對某一時刻資料一致性的要求來換取系統整體伸縮性和效能上改觀**。為什麼這麼說呢,緣由就在於大型系統往往由於地域分佈和極高效能的要求,不可能採用分散式事務來完成這些指標,要想獲得這些指標,我們必須採用另外一種方式來完成,這裡BASE就是解決這個問題的辦法
#### 分散式+叢集簡介
* 分散式系統(distributed system
* 由多臺計算機和通訊的軟體元件通過計算機網路連線(本地網路或廣域網)組成。分散式系統是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是作業系統),而不是硬體。分散式系統可以應用在在不同的平臺上如:Pc、工作站、區域網和廣域網上等。
* 簡單來講:
1. > 分散式:不同的多臺伺服器上面部署不同的服務模組(工程),他們之間通過Rpc/Rmi之間通訊和呼叫,對外提供服務和組內協作
2. > 叢集:不同的多臺伺服器上面部署相同的服務模組,通過分散式排程軟體進行統一的排程,對外提供服務和訪問
## Redis入門介紹
### 入門概述
#### 是什麼
* Redis:REmote DIctionary Server(遠端字典伺服器)
* 是完全開源免費的,用C語言編寫的,遵守BSD協議,是一個高效能的(key/value)分散式記憶體資料庫,基於記憶體執行,並支援持久化的NoSQL資料庫,是當前最熱門的NoSql資料庫之一,也被人們稱為資料結構伺服器
* Redis 與其他 key - value 快取產品(memcache)有以下三個特點
1. Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用
2. Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存
3. Redis支援資料的備份,即master-slave模式的資料備份
#### 能幹嘛
* 記憶體儲存和持久化:redis支援非同步將記憶體中的資料寫到硬碟上,同時不影響繼續服務
* 取最新N個數據的操作,如:可以將最新的10條評論的ID放在Redis的List集合裡面
* 模擬類似於HttpSession這種需要設定過期時間的功能
* 釋出、訂閱訊息系統
* 定時器、計數器
#### 去哪下
* [Redis官網地址](Http://www.redis.cn/)
#### 怎麼玩
* 資料型別、基本操作和配置
* 持久化和複製,RDB/AOF
* 事務的控制
* 複製
* ......
### Redis的安裝
#### 下載redis到/opt目錄
* 第三方軟體習慣放置於/opt目錄下
#### 執行make、make install命令
* 注意gcc版本
* 詳細操作參考:[升級gcc](https://blog.csdn.net/baidu_37313657/article/details/106027207)
#### Redis啟動
* 進入預設安裝目錄 /usr/local/bin
* redis-server redis.conf(自定義的conf檔案)
* redis-cli -p 6379
### Redis啟動後雜項基礎知識講解
#### 單程序
* 單程序模型來處理客戶端的請求。對讀寫等事件的響應是通過對epoll函式的包裝來做到的。Redis的實際處理速度完全依靠主程序的執行效率
* Epoll是Linux核心為處理大批量檔案描述符而作了改進的epoll,是Linux下多路複用IO介面select/poll的增強版本,它能顯著提高程式在大量併發連線中只有少量活躍的情況下的系統CPU利用率
#### 預設16個數據庫,類似陣列下表從零開始,初始預設使用零號庫
* 設定資料庫的數量,預設資料庫為0,可以使用SELECT 命令在連線上指定資料庫id
databases 16
#### Select命令切換資料庫
* ````
select 0
````
#### Dbsize檢視當前資料庫的key的數量
#### keys列出庫中所有的key
* keys *
* keys k? 類似模糊查詢
#### FlushDb:清空當前庫
#### FlushALL:通殺所有庫
#### 統一密碼管理,16個庫都是同樣密碼,要麼都OK要麼一個也連線不上
#### Redis索引都是從零開始
#### 為什麼預設埠是6379
## Redis資料型別
### Redis的五大資料型別
#### String(字串)
* string是redis最基本的型別,你可以理解成與Memcached一模一樣的型別,一個key對應一個value
* string型別是二進位制安全的。意思是redis的string可以包含任何資料。比如jpg圖片或者序列化的物件
* string型別是Redis最基本的資料型別,一個redis中字串value最多可以是512M
#### Hash(雜湊,類似java裡的Map)
* Redis hash 是一個鍵值對集合
* Redis hash是一個string型別的field和value的對映表,hash特別適合用於儲存物件
* 類似Java裡面的Map
#### List(列表)
* Redis 列表是簡單的字串列表,按照插入順序排序,你可以新增一個元素到列表的頭部(左邊)或尾部
* 它的底層實際是個連結串列
#### Set(集合)
* Redis的Set是string型別的無序無重複集合。它是通過HashTable實現實現的
* 注意:new HashSet 底層相當於new HashMap(詳情檢視JDK原始碼)
#### Zset(sorted set :有序集合)
* Redis zset 和 set 一樣也是string型別元素的集合,且不允許重複的成員,**不同的是每個元素都會關聯一個double型別的分數**
* redis正是通過分數來為集合中的成員進行從小到大的排序。**zset的成員是唯一的,但分數(score)卻可以重複**。
### 哪裡去獲得redis常見資料型別操作命令
#### redis命令參考大全
* [redis命令](Http://redisdoc.com/)
* ![image-20200820165059258](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153903109-1791888346.png)
* ![image-20200820165119310](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153903685-631804743.png)
* ![image-20200820165200159](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153903930-1127877048.png)
* ![image-20200820165214255](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153904502-1781710218.png)
### Redis鍵(key)
#### 常用
* ![image-20200820165303078](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153905188-168665660.png)
#### 案例
* keys *
* exists key的名字,判斷某個key是否存在
* move key db --->當前庫就沒有了,被移除了
* expire key 秒鐘:為給定的key設定過期時間
* ttl key 檢視還有多少秒過期,-1表示永不過期,-2表示已過期
* type key 檢視你的key是什麼型別
### Redis字串(String)
#### 常用
* ![image-20200820170745693](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153905984-1446156128.png)
* ![image-20200820170753026](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153906439-1836336250.png)
#### 單值單Value
#### 案例
##### set/get/del/append/strlen
##### Incr/decr/incrby/decrby,一定要是數字才能進行加減
##### getrange/setrange
* getrange:獲取指定區間範圍內的值,類似between......and的關係![image-20200820171427145](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153907065-2047744524.png)
* setrange設定指定區間範圍內的值,格式是setrange key值 具體值![image-20200820171437617](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153908120-2138051353.png)
##### setex(set with expire)鍵秒值/setnx(set if not exist)
* setex:設定帶過期時間的key,動態設定
* setex 鍵 秒值 真實值
* ![image-20200820171828050](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153908825-279056449.png)
* setnx:只有在 key 不存在時設定 key 的值
* ![image-20200820171915018](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153909229-1822531255.png)
##### mset/mget/msetnx
* mset:同時設定一個或多個 key-value 對![image-20200820173029642](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153909901-1346828693.png)
* mget:獲取所有(一個或多個)給定 key 的值![image-20200820173040024](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153910539-2014668715.png)
* msetnx:同時設定一個或多個 key-value 對,當且僅當所有給定 key 都不存在![image-20200820173052240](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153911227-1636534016.png)
##### getset(先get再set)
* getset:將給定 key 的值設為 value ,並返回 key 的舊值(old value),簡單一句話,先get然後立即set![image-20200820173346485](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153911815-173414056.png)
### Redis列表(List)
#### 常用
* ![image-20200821092422433](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153912480-1079974069.png)
* ![image-20200821092433593](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153913207-418684324.png)
#### 單值多Value
#### 案例
##### lpush(列表頭部)/rpush(尾部)/lrange
##### lpop/rpop
* ![image-20200821094109630](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153913795-1659491161.png)
##### lindex,按照索引下標獲得元素(從上到下)
##### llen
##### lrem key 刪N個value
* 從left往right刪除2個值等於v1的元素,返回的值為實際刪除的數量
* LREM list3 0 值,表示刪除全部給定的值。零個就是全部值
##### ltrim key 開始index 結束index,擷取指定範圍的值後再賦值給key
##### rpoplpush 源列表 目的列表
##### lset key index value
##### linsert key before/after 值1 值2
##### 效能總結
* 它是一個字串連結串列,left、right都可以插入新增;如果鍵不存在,建立新的連結串列;如果鍵已存在,新增內容;如果值全移除,對應的鍵也就消失了。
* > 連結串列的操作無論是頭和尾效率都極高,但假如是對中間元素進行操作,效率就很慘淡了。
### Redis集合(Set)
#### 常用
* ![image-20200821100807572](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153914498-1081722142.png)
#### 單值多Value
#### 案例
##### sadd/smembers/sismember
* ![image-20200821101118880](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153915194-1479351936.png)
##### scard,獲取集合裡面的元素個數
* ![image-20200821101210932](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153915744-211305736.png)
##### srem key value 刪除集合中元素
##### srandmember key 某個整數(隨機出幾個數)
##### spop key 隨機出棧
##### smove key1 key2 在key1裡某個值 作用是將key1裡的某個值賦給key2
##### 數學集合類
1. 差集:sdiff 在第一個set裡面而不在後面任何一個set裡面的項
2. 交集:sinter
3. 並集:sunion
### Redis雜湊(Hash)
#### 常用
#### KV模式不變,但V是一個鍵值對
#### 案例
##### hset/hget/hmset/hmget/hgetall/hdel(*)
* ![image-20200821103636188](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153916202-909817659.png)
##### hlen
##### hexists key 在key裡面的某個值的key
##### hkeys/hvals
* ![image-20200821103904313](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153916804-366447669.png)
##### hincrby/hincrbyfloat
* ![image-20200821104104363](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153917485-1183196803.png)
##### hsetnx
* 不存在賦值,存在了無效
### Redis有序集合Zset(sorted set)
#### 常用
* ![image-20200821104609766](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153918109-1105736138.png)
* ![image-20200821104617462](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153918926-720872533.png)
#### 區別set
* > 在set基礎上,加一個score值,之前set是k1 v1 v2 v3,現在zset是k1 score1 v1 score2 v2
#### 案例
##### zadd/zrange
* ![image-20200821105020090](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153919575-4654078.png)
##### zrangebyscore key 開始score 結束score
* withscores
* ( 不包含
* Limit 作用是返回限制 limit 開始下標步 多少步
* ![image-20200821105407685](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153919943-299520116.png)
##### zrem key 某score下對應的value值,作用是刪除元素
* 刪除元素,格式是zrem zset的key 項的值,項的值可以是多個,zrem key score某個對應值,可以是多個值
##### zcard/zcount key score區間/zrank key values值,作用是獲得下標值/zscore key 對應值,獲得分數
* zcard :獲取集合中元素個數
* zcount :獲取分數區間內元素個數,zcount key 開始分數區間 結束分數區間
* zrank: 獲取value在zset中的下標位置
* zscore:按照值獲得對應的分數
##### zrevrank key values值,作用是逆序獲得下標值
##### zrevrange
* ![image-20200821110223102](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153920519-1120403173.png)
##### zrevrangebyscore key 結束score 開始score
* zrevrangebyscore zset1 90 60 withscores 分數是反著來的
## 解析配置檔案redis.conf
### Units單位
* ![image-20200821112126413](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153921064-954027801.png)
* 配置大小單位,開頭定義了一些基本的度量單位,只支援bytes,不支援bit
* 對大小寫不敏感
### INCLUDES包含
* 可以通過includes包含,redis.conf可以作為總閘,包含其他
### GENERAL通用
#### Daemonize 守護執行緒方式啟動
#### Pidfile
#### Port
#### Tcp-backlog
* 設定tcp的backlog,backlog其實是一個連線佇列,backlog佇列總和=未完成三次握手佇列 + 已經完成三次握手佇列。
* 在高併發環境下你需要一個高backlog值來避免慢客戶端連線問題。注意Linux核心會將這個值減小到/proc/sys/net/core/somaxconn的值,所以需要確認增大somaxconn和tcp_max_syn_backlog兩個值
來達到想要的效果
#### Timeout
#### Bind
#### Tcp-keepalive
* 單位為秒,如果設定為0,則不會進行Keepalive檢測,建議設定成60
#### Loglevel
* debug (development/testing)
* verbose
* notice (production probably)
* warning
#### Logfile
#### Syslog-enabled
#### Syslog-ident
#### Syslog-facility
#### Databases
### SNAPSHOTTING快照(*)
#### Save
* 格式: save 秒鐘 寫操作的次數
* > RDB是整個記憶體的壓縮過的Snapshot,RDB的資料結構,可以配置複合的快照觸發條件,
* > 預設是1分鐘內改了1萬次,或5分鐘內改了10次,或15分鐘內改了1次
* save 900 1
* save 300 5
* save 60 10000
* 禁用
* 如果想禁用RDB持久化的策略,只要不設定任何save指令,或者給save傳入一個空字串引數也可以
* save “ ”
#### Stop-writes-on-bgsave-error
* 如果儲存出錯 停止寫操作的意思
* 如果配置成no,表示你不在乎資料不一致或者有其他的手段發現和控制
#### rdbcompression
* rdbcompression:對於儲存到磁碟中的快照,可以設定是否進行壓縮儲存。如果是的話,redis會採用
LZF演算法進行壓縮。如果你不想消耗CPU來進行壓縮的話,可以設定為關閉此功能
#### rdbchecksum
* rdbchecksum:在儲存快照後,還可以讓redis使用CRC64演算法來進行資料校驗,但是這樣做會增加大約
10%的效能消耗,如果希望獲取到最大的效能提升,可以關閉此功能
#### dbfilename
#### dir
* 獲取目錄:config get dir
### REPLICATION複製
### SECURITY安全
* 訪問密碼的檢視、設定和取消
### LIMITS限制
* Maxclients
* 設定redis同時可以與多少個客戶端進行連線。預設情況下為10000個客戶端。當你無法設定程序檔案控制代碼限制時,redis會設定為當前的檔案控制代碼限制值減去32,因為redis會為自身內部處理邏輯留一些控制代碼出來。如果達到了此限制,redis則會拒絕新的連線請求,並且向這些連線請求方發出“max number of clients reached”以作迴應。
* Maxmemory
* 設定redis可以使用的記憶體量。一旦到達記憶體使用上限,redis將會試圖移除內部資料,移除規則可以通過maxmemory-policy來指定。如果redis無法根據移除規則來移除記憶體中的資料,或者設定了“不允許移除”,
那麼redis則會針對那些需要申請記憶體的指令返回錯誤資訊,比如SET、LPUSH等。
* 但是對於無記憶體申請的指令,仍然會正常響應,比如GET等。如果你的redis是主redis(說明你的redis有從redis),那麼在設定記憶體使用上限時,需要在系統中留出一些記憶體空間給同步佇列快取,只有在你設定的是“不移除”的情況下,才不用考慮這個因素
* Maxmemory-policy
* LRU演算法:leastest recently use 最近最少使用
* Volatile-lru:使用LRU演算法移除key,只對設定了過期時間的鍵
* Allkeys-lru :使用LRU演算法移除key
* Volatile-random :在過期集合中移除隨機的key,只對設定了過期時間的鍵
* Allkeys-random :移除隨機的key
* Volatile-ttl :移除那些TTL值最小的key,即那些最近要過期的key
* Noeviction :不進行移除,針對寫操作,只是返回錯誤資訊
* Maxmemory-samples
* 設定樣本數量,LRU演算法和最小TTL演算法都並非是精確的演算法,而是估算值,所以你可以設定樣本的大小,redis預設會檢查這麼多個key並選擇其中LRU的那個
### APPEND ONLY MODE追加(*)
#### appendonly
#### appendfilename
#### Appendfsync
* ![image-20200825112928988](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153921656-2123125502.png)
* > 三種策略
* Always:同步持久化 每次發生資料變更會被立即記錄到磁碟 效能較差但資料完整性比較好
* Everysec:出廠預設推薦,非同步操作,每秒記錄 如果一秒內宕機,有資料丟失
* No
#### No-appendfsync-on-rewrite:重寫時是否可以運用Appendfsync,用預設no即可,保證資料安全性
#### Auto-aof-rewrite-min-size:設定重寫的基準值
#### Auto-aof-rewrite-percentage:設定重寫的基準值
### 常見配置redis.conf介紹(*)
#### 引數說明
* redis.conf 配置項說明如下:
1. Redis預設不是以守護程序的方式執行,可以通過該配置項修改,使用yes啟用守護程序
daemonize no
2. 當Redis以守護程序方式執行時,Redis預設會把pid寫入/var/run/redis.pid檔案,可以通過pidfile指定
pidfile /var/run/redis.pid
3. 指定Redis監聽埠,預設埠為6379,作者在自己的一篇博文中解釋了為什麼選用6379作為預設埠,因為6379在手機按鍵上MERZ對應的號碼,而MERZ取自義大利歌女Alessia Merz的名字
port 6379
4. 繫結的主機地址
bind 127.0.0.1
5. 當 客戶端閒置多長時間後關閉連線,如果指定為0,表示關閉該功能
timeout 300
6. 指定日誌記錄級別,Redis總共支援四個級別:debug、verbose、notice、warning,預設為verbose
loglevel verbose
7. 日誌記錄方式,預設為標準輸出,如果配置Redis為守護程序方式執行,而這裡又配置為日誌記錄方式為標準輸出,則日誌將會發送給/dev/null
logfile stdout
8. 設定資料庫的數量,預設資料庫為0,可以使用SELECT 命令在連線上指定資料庫id
databases 16
9. 指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案,可以多個條件配合
save
Redis預設配置檔案中提供了三個條件:
save 900 1
save 300 10
save 60 10000
分別表示900秒(15分鐘)內有1個更改,300秒(5分鐘)內有10個更改以及60秒內有10000個更改。
10. 指定儲存至本地資料庫時是否壓縮資料,預設為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫檔案變的巨大
rdbcompression yes
11. 指定本地資料庫檔名,預設值為dump.rdb
dbfilename dump.rdb
12. 指定本地資料庫存放目錄
dir ./
13. 設定當本機為slav服務時,設定master服務的IP地址及埠,在Redis啟動時,它會自動從master進行資料同步
slaveof
14. 當master服務設定了密碼保護時,slav服務連線master的密碼
masterauth
15. 設定Redis連線密碼,如果配置了連線密碼,客戶端在連線Redis時需要通過AUTH 命令提供密碼,預設關閉
requirepass foobared
16. 設定同一時間最大客戶端連線數,預設無限制,Redis可以同時開啟的客戶端連線數為Redis程序可以開啟的最大檔案描述符數,如果設定 maxclients 0,表示不作限制。當客戶端連線數到達限制時,Redis會關閉新的連線並向客戶端返回max number of clients reached錯誤資訊
maxclients 128
17. 指定Redis最大記憶體限制,Redis在啟動時會把資料載入到記憶體中,達到最大記憶體後,Redis會先嚐試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大記憶體設定,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放記憶體,Value會存放在swap區
maxmemory
18. 指定是否在每次更新操作後進行日誌記錄,Redis在預設情況下是非同步的把資料寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的資料丟失。因為 redis本身同步資料檔案是按上面save條件來同步的,所以有的資料會在一段時間內只存在於記憶體中。預設為no
appendonly no
19. 指定更新日誌檔名,預設為appendonly.aof
appendfilename appendonly.aof
20. 指定更新日誌條件,共有3個可選值:
no:表示等作業系統進行資料快取同步到磁碟(快)
always:表示每次更新操作後手動呼叫fsync()將資料寫到磁碟(慢,安全)
everysec:表示每秒同步一次(折衷,預設值)
appendfsync everysec
21. 指定是否啟用虛擬記憶體機制,預設值為no,簡單的介紹一下,VM機制將資料分頁存放,由Redis將訪問量較少的頁即冷資料swap到磁碟上,訪問多的頁面由磁碟自動換出到記憶體中(在後面的文章我會仔細分析Redis的VM機制)
vm-enabled no
22. 虛擬記憶體檔案路徑,預設值為/tmp/redis.swap,不可多個Redis例項共享
vm-swap-file /tmp/redis.swap
23. 將所有大於vm-max-memory的資料存入虛擬記憶體,無論vm-max-memory設定多小,所有索引資料都是記憶體儲存的(Redis的索引資料 就是keys),也就是說,當vm-max-memory設定為0的時候,其實是所有value都存在於磁碟。預設值為0
vm-max-memory 0
24. Redis swap檔案分成了很多的page,一個物件可以儲存在多個page上面,但一個page上不能被多個物件共享,vm-page-size是要根據儲存的 資料大小來設定的,作者建議如果儲存很多小物件,page大小最好設定為32或者64bytes;如果儲存很大大物件,則可以使用更大的page,如果不 確定,就使用預設值
vm-page-size 32
25. 設定swap檔案中的page數量,由於頁表(一種表示頁面空閒或使用的bitmap)是在放在記憶體中的,,在磁碟上每8個pages將消耗1byte的記憶體。
vm-pages 134217728
26. 設定訪問swap檔案的執行緒數,最好不要超過機器的核數,如果設定為0,那麼所有對swap檔案的操作都是序列的,可能會造成比較長時間的延遲。預設值為4
vm-max-threads 4
27. 設定在向客戶端應答時,是否把較小的包合併為一個包傳送,預設為開啟
glueoutputbuf yes
28. 指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的雜湊演算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
29. 指定是否啟用重置雜湊,預設為開啟(後面在介紹Redis的雜湊演算法時具體介紹)
activerehashing yes
30. 指定包含其它的配置檔案,可以在同一主機上多個Redis例項之間使用同一份配置檔案,而同時各個例項又擁有自己的特定配置檔案
include /path/to/local.conf
## Redis持久化(*)
### 總體介紹
#### [官網](https://redis.io/topics/persistence)
### RDB(Redis DataBase)
#### 是什麼
* 在**指定的時間間隔**內將記憶體中的資料集快照寫入磁碟,也就是行話講的Snapshot快照,它恢復時是將快照檔案直接讀到記憶體裡
* Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的資料可能丟失
#### Fork
* Fork的作用是複製一個與當前程序一樣的程序,新程序的多有資料(變數、環境變數、程式計數器等)數值都和原程序一致,但是是一個全新的程序,並作為原程序的子程序
#### Rdb 儲存的是dump.rdb檔案
* save 命令 迅速備份 快速生成rdb檔案
#### 配置檔案的位置(參照解析配置檔案的快照)
#### 如何觸發RDB快照
##### 配置檔案預設的快照配置
* 預設是1分鐘內改了1萬次,或5分鐘內改了10次,或15分鐘內改了1次
* save 900 1
* save 300 5
* save 60 10000
##### 命令save或者是bgsave
* 都可以迅速 立刻生成dump.rdb檔案
* Save:save時只管儲存,其它不管,全部阻塞
* BGSAVE:Redis會在後臺非同步進行快照操作,快照同時還可以響應客戶端請求。可以通過lastsave
命令獲取最後一次成功執行快照的時間
##### 執行flushall命令,也會產生dump.rdb檔案,但裡面是空的,**無意義**
#### 如何恢復
* 將備份檔案 (dump.rdb) 移動到 redis 安裝目錄並啟動服務即可
* CONFIG GET dir獲取目錄
#### 優勢
##### 適合大規模的資料恢復
##### 對資料完整性和一致性要求不高
#### 劣勢
##### 在一定間隔時間做一次備份,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改
##### Fork的時候,記憶體中的資料被克隆了一份,大致2倍的膨脹性需要考慮
#### 如何停止
##### 動態所有停止RDB儲存規則的方法:redis-cli config set save ""
#### 小總結
* ![image-20200824163646437](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153922313-908461014.png)
### AOF(Append Only File)
#### [官網](https://redis.io/topics/persistence)
#### 是什麼
* 以日誌的形式來記錄每個寫操作,將Redis執行過的所有寫指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作
#### AOF儲存的是appendonly.aof檔案
#### 配置位置
* ![image-20200824165305534](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153922911-1289994335.png)
* > 見解析配置檔案---APPEND ONLY MODE追加
#### AOF啟動/修復/恢復
##### 正常恢復
* 啟動:設定Yes,修改預設的appendonly no,改為yes
* 將有資料的aof檔案複製一份儲存到對應目錄(config get dir)
* 恢復:重啟redis然後重新載入
##### 異常恢復
* 啟動:設定Yes,修改預設的appendonly no,改為yes
* 備份被寫壞的AOF檔案
* > 修復:Redis-check-aof --fix aof檔案 進行修復
* 恢復:重啟redis然後重新載入
#### Rewrite
##### 是什麼
* ![image-20200825145521166](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153924242-346087942.png)
* AOF採用檔案追加方式,檔案會越來越大為避免出現此種情況,**新增了重寫機制,當AOF檔案的大小超過所設定的閾值時**,Redis就會啟動AOF檔案的內容壓縮,只保留可以恢復資料的最小指令集.可以使用命令bgrewriteaof
##### 重寫原理
* AOF檔案持續增長而過大時,會fork出一條新程序來將檔案重寫(也是先寫臨時檔案最後再rename),遍歷新程序的記憶體中資料,每條記錄有一條的Set語句。重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似
##### 觸發機制
* Redis會記錄上次重寫時的AOF大小,預設配置是當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發
#### 優勢
* 每修改同步:appendfsync always 同步持久化 每次發生資料變更會被立即記錄到磁碟 效能較差但資料完整性比較好
* 每秒同步:appendfsync everysec 非同步操作,每秒記錄 如果一秒內宕機,有資料丟失
* 不同步:appendfsync no 從不同步
#### 劣勢
* 相同資料集的資料而言aof檔案要遠大於rdb檔案,恢復速度慢於rdb
* Aof執行效率要慢於rdb,每秒同步策略效率較好,不同步效率和rdb相同
#### 小總結
* ![image-20200825150532205](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153925167-1807008539.png)
### 總結(Which one)
#### 官網建議
* ![image-20200825150754530](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153925714-388010132.png)
#### 比較:
* RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存
* AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾,Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大
* 只做快取:如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式.
#### 同時開啟兩種持久化方式
* 在這種情況下,**當redis重啟的時候會優先載入AOF檔案來恢復原始的資料**,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要**完整**
* RDB的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案。那要不要只使用AOF呢?作者建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的bug,留著作為一個萬一的手段。
#### 效能建議
* 因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。
* 如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自己的AOF檔案就可以了。**代價一是帶來了持續的IO,二是AOF rewrite的最後將rewrite過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的**。只要硬碟許可,應該儘量減少AOF rewrite的頻率,**AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。預設超過原大小100%大小時重寫可以改到適當的數值**。
* 如果不Enable AOF ,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時倒掉,會丟失十幾分鐘的資料,啟動指令碼也要比較兩個Master/Slave中的RDB檔案,載入較新的那個。新浪微博就選用了這種架構
## Redis的事務
### 是什麼
#### 官網
* [redis事務官網地址](https://redis.io/topics/transactions)
#### 概述
- 可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,按順序地序列化執行而不會被其它命令插入,不許加塞
### 能幹嘛
* > 一個佇列中,一次性、順序性、排他性的執行一系列命令
### 怎麼玩
* ![image-20200825152828326](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153926306-122184274.png)
#### 常用命令
* ![image-20200825154559232](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153926995-58948500.png)
#### Case1:正常執行
* ![image-20200825160149485](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153927594-1434995955.png)
#### Case2:放棄事務
* ![image-20200825160247490](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153927843-1815532779.png)
#### Case3:全體連坐
* ![image-20200825160548308](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153928574-94697076.png)
#### Case4:冤頭債主
* 即使錯了,但是加入進隊列了queued ,而不是像case3在執行時直接報錯並沒有加入佇列
* ![image-20200825161143350](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153929183-1803803904.png)
#### Case5:watch監控
##### 悲觀鎖/樂觀鎖/CAS(Check And Set)
* 悲觀鎖
* 悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會block直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖
* 樂觀鎖
* 樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量
* 樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新
* CAS
##### 初始化信用卡可用餘額和欠額
* ![image-20200825163006942](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153929740-115927439.png)
##### 無加塞篡改,先監控再開啟multi,保證兩筆金額變動在同一個事務內
* ![image-20200825163528898](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153930360-626698813.png)
##### 有加塞篡改
* 監控了key,如果key被修改了,後面一個事務的執行失效
* ![image-20200825164416433](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153931046-1511739744.png)
##### unwatch
* 取消監控
* ![image-20200825164449923](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153931827-1791596074.png)
##### 一旦執行了exec之前加的監控鎖都會被取消掉了
##### 小結
* > Watch指令,類似**樂觀鎖**,事務提交時,如果Key的值已被別的客戶端改變,比如某個list已被別的客戶端push/pop過了,整個事務佇列都不會被執行
* 通過WATCH命令在事務執行之前監控了多個Keys,倘若在WATCH之後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回Nullmulti-bulk應答以通知呼叫者事務執行失敗
### 3階段
#### 開啟
* 以MULTI開始一個事務
#### 入隊
* 將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務佇列裡面
#### 執行
* 執行:由EXEC命令觸發事務
### 3特性
* 單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷
* 沒有隔離級別的概念:佇列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行,也就不存在”事務內的查詢要看到事務裡的更新,在事務外查詢不能看到”這個讓人萬分頭痛的問題
* > 不保證原子性:redis同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾---部分支援事務
## Redis的釋出和訂閱
### 是什麼
#### 概述
* 程序間的一種訊息通訊模式:傳送者(pub)傳送訊息,訂閱者(sub)接收訊息
#### 訂閱/釋出訊息圖
* ![image-20200825170025577](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153932303-125831367.png)
### 命令
* ![image-20200825171423258](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153933037-1532575811.png)
### 案例
#### 先訂閱後釋出後才能收到訊息
#### 操作
##### 1.1.可以一次性訂閱多個,SUBSCRIBE c1 c2 c3
##### 1.2 訊息釋出,PUBLISH c2 hello-redis
##### 2.1 訂閱多個,萬用字元*, PSUBSCRIBE new*
##### 2.2 收取訊息, PUBLISH new1 redis2015
![image-20200825172439405](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153933836-1736101495.png)
## Redis的複製(Master/Slave)
### 是什麼
#### 官網
* [redis主從複製](https://redis.io/topics/replication)
* 行話:也就是我們所說的主從複製,主機資料更新後根據配置和策略,自動同步到備機的master/slaver機制,**Master以寫為主,Slave以讀為主**
### 能幹嘛
#### 讀寫分離
#### 容災恢復
### 怎麼玩
#### 1.配從(庫)不配主(庫)
#### 2.從庫配置:slaveof 主庫IP 主庫埠
* 每次與master斷開之後,都需要重新連線,除非你配置進redis.conf檔案
* Info replication
#### 3.修改配置檔案細節操作
##### 3.1 拷貝多個redis.conf檔案
* ![image-20200826091338977](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153934817-1916078738.png)
##### 3.2 開啟daemonize yes
* ![image-20200826091353854](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153935724-286742694.png)
##### 3.3 Pid檔名字
##### 3.4 指定埠
##### 3.5 Log檔名字
* ![image-20200826091407130](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153937130-298418714.png)
##### 3.6 Dump.rdb名字
* ![image-20200826091437126](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153937708-1241030040.png)
#### 4.常用3招
##### 一主二僕
* Init
* > info replication 檢視資訊
* ![image-20200826093819448](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153938695-1837307103.png)
* 一個Master兩個Slave
* ![image-20200826102020559](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153939618-1766480773.png)
* 日誌檢視
* 主機日誌![image-20200826102345554](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153940575-1188228742.png)
* 從機日誌![image-20200826102358780](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153941457-678520569.png)
* info replication![image-20200826102406629](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153941923-665828135.png)
* > 主從問題演示
* 1.切入點問題?slave1、slave2是從頭開始複製還是從切入點開始複製?比如從k4進來,那之前的123是否也可以複製
答:切入點複製,不需要從頭複製
* 2.從機是否可以寫?set可否?
答:從機只讀,不可set
* 3.主機shutdown後情況如何?從機是上位還是原地待命
答:原地待命,不上位
* 4.主機又回來了後,主機新增記錄,從機還能否順利複製
答:可以順利複製
* 5.其中一臺從機down後情況如何?依照原有它能跟上大部隊嗎?
答:恢復後,會取消之前的主從設定,變為master。 重新slaveof即可
##### 薪火相傳
* > 上一個Slave可以是下一個slave的Master,Slave同樣可以接收其他slaves的連線和同步請求,那麼該slave作為了鏈條中下一個的master,可以有效減輕master的寫壓力(**去中心化**)
* 中途變更轉向:會清除之前的資料,重新建立拷貝最新的
* Slaveof 新主庫IP 新主庫埠
##### 反客為主
* SLAVEOF no one
* 使當前資料庫停止與其他資料庫的同步,轉成主資料庫
### 複製原理
##### 複製流程
1. Slave啟動成功連線到master後會傳送一個sync命令
2. Master接到命令啟動後臺的存檔程序,同時收集所有接收到的用於修改資料集命令,在後臺程序執行完畢之後,master將傳送整個資料檔案到slave,以完成一次完全同步
3. 全量複製:而slave服務在接收到資料庫檔案資料後,將其存檔並載入到記憶體中
4. 增量複製:Master繼續將新的所有收集到的修改命令依次傳給slave,完成同步
5. 但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行
### 哨兵模式(Sentinel)
#### 是什麼
* > 反客為主的自動版,能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫
#### 使用步驟
##### 1.調整結構,6379帶著80、81
##### 2.新建sentinel.conf檔案,名字絕不能錯
##### 3.配置哨兵,填寫內容
* sentinel monitor 被監控資料庫名字(自己起名字) 127.0.0.1 6379 1![image-20200826114111819](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153942588-2120895029.png)
* 上面最後一個數字1,表示主機掛掉後salve投票看讓誰接替成為主機,得票數多少後成為主機
##### 4.啟動哨兵
* Redis-sentinel /opt/redis-6.0.6/sentinel.conf
* ![image-20200826131456634](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153943400-240722610.png)
##### 5.正常主從演示
##### 6.原有的master掛了
##### 7.投票新選
* 哨兵監控到原有的主節點失效,自動投票選舉新主節點![image-20200826131717334](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153944376-1252726056.png)
##### 8.重新主從繼續開工,info replication檢視
* ![image-20200826131754157](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153945398-1806427083.png)
##### 9.問題:如果之前的master重啟回來,會不會雙master衝突?
* 不會
* 保持新選舉的master,原先宕機的master,會變成新master的子節點
* ![image-20200826131904566](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153946410-1949324593.png)
#### 一組sentinel能同時監控多個Master
### 複製的缺點
#### 複製延時
* 由於**所有的寫操作都是先在Master上操作**,然後同步更新到Slave上,所以從Master同步到Slave機器有一定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增加也會使這個問題更加嚴重
## Redis的Java客戶端Jedis
### Jedis官網
#### 基礎用法
* [jedis基礎用法](https://github.com/xetorthio/jedis)
#### 高階用法
* [jedis高階用法](https://github.com/xetorthio/jedis/wiki/AdvancedUsage)
### Jedis常用API
#### 測試連通性
* ![image-20200826134620655](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153946866-1681678953.png)
#### 5+1
##### 一個key
##### 五大資料型別
* ![image-20200826134659501](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153947533-270394538.png)
* ![image-20200826134718606](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153947879-1590501527.png)
* ![image-20200826134800726](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153948612-2042773432.png)
#### 事務提交
##### 日常
* ![image-20200826135550088](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153949398-285214023.png)
##### 加鎖
* > 通俗點講,watch命令就是標記一個鍵,如果標記了一個鍵, 在提交事務前如果該鍵被別人修改過,那事務就會失敗,這種情況通常可以在程式中重新再嘗試一次
* 首先標記了鍵balance,然後檢查餘額是否足夠,不足就取消標記,並不做扣減; 足夠的話,就啟動事務進行更新操作
* 如果在此期間鍵balance被其它人修改, 那在提交事務(執行exec)時就會報錯, 程式中通常可以捕獲這類錯誤再重新執行一次,直到成功
* ![image-20200826135626627](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153949915-1497621336.png)
#### 主從複製
1. 6379,6380啟動,先各自先獨立
2. 主寫
3. 從讀
4. ![image-20200826135752167](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153950593-860600842.png)
### JedisPool
#### 獲取Jedis例項需要從JedisPool中獲取
#### 用完Jedis例項需要返還給JedisPool
#### 如果Jedis在使用過程中出錯,則也需要還給JedisPool
#### 案例
##### JedisPoolUtil
* ![image-20200826141642380](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153951429-1204091082.png)
##### JedisPool.getResource()
* ![image-20200826141553090](https://img2020.cnblogs.com/blog/1875400/202008/1875400-20200826153952155-1789180076.png)
#### 配置總結all
##### JedisPool的配置引數大部分是由JedisPoolConfig的對應項來賦值的。
1. maxActive:控制一個pool可分配多少個jedis例項,通過pool.getResource()來獲取;如果賦值為-1,則表示不限制;如果pool已經分配了maxActive個jedis例項,則此時pool的狀態為exhausted
2. maxIdle:控制一個pool最多有多少個狀態為idle(空閒)的jedis例項
3. whenExhaustedAction:表示當pool中的jedis例項都被allocated完時,pool要採取的操作;
預設有三種:
* WHEN_EXHAUSTED_FAIL:表示無jedis例項時,直接丟擲NoSuchElementException
* WHEN_EXHAUSTED_BLOC:則表示阻塞住,或者達到maxWait時丟擲JedisConnectionException;
* WHEN_EXHAUSTED_GROW:則表示新建一個jedis例項,也就說設定的maxActive無用;
4. maxWait:表示當borrow一個jedis例項時,最大的等待時間,如果超過等待時間,則直接拋JedisConnectionException;
5. testOnBorrow:獲得一個jedis例項的時候是否檢查連線可用性(ping());如果為true,則得到的jedis例項均是可用的;
6. testOnReturn:return 一個jedis例項給pool時,是否檢查連線可用性(ping())
7. testWhileIdle:如果為true,表示有一個idle object evitor執行緒對idle object進行掃描,如果validate失敗,此object會被從pool中drop掉;這一項只有在timeBetweenEvictionRunsMillis大於0時才有意義;
8. timeBetweenEvictionRunsMillis:表示idle object evitor兩次掃描之間要sleep的毫秒數;
9. numTestsPerEvictionRun:表示idle object evitor每次掃描的最多的物件數;
10. minEvictableIdleTimeMillis:表示一個物件至少停留在idle狀態的最短時間,然後才能被idle object evitor