Redis基礎(chǔ)

Redis

NoSOL特點(diǎn)

  1. 方便擴(kuò)展

  2. 大數(shù)據(jù)量性能高

  3. 數(shù)據(jù)類型多樣

  4. RDBMS與NoSQL的區(qū)別

    RDMBS
    -結(jié)構(gòu)化組織
    -SQL
    -數(shù)據(jù)和關(guān)系都存在單獨(dú)的表中
    -嚴(yán)格的一致性
    -基礎(chǔ)的事務(wù)
    
    NoSQL
    -不僅僅是數(shù)據(jù)庫
    -沒有固定的查詢語言
    -鍵值對存儲(chǔ)答憔,列存儲(chǔ),文檔存儲(chǔ),圖形數(shù)據(jù)庫
    -最終一致性
    -CAP定理和BASE (異地多活)
    -高性能俺祠,高可用帖世,高可擴(kuò)
    

3V+3高

3V

? 海量Velume

? 多樣Variety

? 實(shí)時(shí)Velocity

3高

? 高并發(fā)

? 高可擴(kuò)

? 高性能

NoSQL四大分類

KV鍵值對

  • Redis 杀怠、Tair母截、memcache

文檔型數(shù)據(jù)庫(bson格式)

  • MongoDB
    • MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫惜互,主要用來處理大量的文檔
    • MongoDB是一個(gè)介于關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫中間的產(chǎn)品蹋订,MongoDB是非關(guān)系型數(shù)據(jù)庫中功能最豐富率挣,最像關(guān)系型數(shù)據(jù)庫的!
  • ConthDB

列存儲(chǔ)數(shù)據(jù)庫

  • HBase
  • 分布式文件系統(tǒng)

圖關(guān)系數(shù)據(jù)庫

  • Neo4j露戒、infoGrid;

Redis概述

==什么是Redis椒功?==

Redis(Remote Dictionary Server ),即遠(yuǎn)程字典服務(wù) 智什。是一個(gè)開源的使用ANSI C語言編寫动漾、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型荠锭、Key-Value數(shù)據(jù)庫旱眯,并提供多種語言的API。

1603116108267

redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了master-slave(主從)同步删豺。 是當(dāng)下最熱門的NoSQL技術(shù)之一础爬。

==Redis能做什么==

  1. 內(nèi)存存儲(chǔ)、持久化
  2. 效率高吼鳞,可以用于高速緩存
  3. 發(fā)布訂閱系統(tǒng)
  4. 地圖信息分析
  5. 計(jì)時(shí)器看蚜、計(jì)數(shù)器

==特性==

  1. 多樣化的數(shù)據(jù)類型
  2. 持久化
  3. 集群
  4. 事務(wù)

官網(wǎng)https://redis.io/

中文網(wǎng)http://www.redis.cn/

下載地址

1603116870640

Redis推薦在Linux服務(wù)器上搭建

Linux安裝

1、下載安裝包

2赔桌、將安裝包上傳到linux下 放到opt目錄下

1603118731453

? 解壓

1603118884773

3供炎、進(jìn)入解壓后的文件,標(biāo)紅的就是Redis的配置文件

1603119053040

4疾党、基本的環(huán)境安裝

yum install gcc-c++

安裝6.0以上版本需要升級gcc到5.3及以上,如下:升級到gcc 9.3:

yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash 
make
1603119684620
make install
1603119748015

5音诫、redis默認(rèn)安裝路徑==/usr/local/bin==

1603176988481

6、將redis配置文件復(fù)制到我們當(dāng)前的目錄下

1603177296234

7雪位、redis默認(rèn)不是后臺(tái)啟動(dòng)的竭钝,修改配置文件

1603177587025

8、啟動(dòng)redis服務(wù)

1603178990766

9雹洗、使用redis-cli進(jìn)行連接測試

1603179156826

10香罐、查看redis進(jìn)程是否開啟

ps -ef|grep redis
1603179343769

11、關(guān)閉Redis服務(wù)

shutdown
1603179551183

12时肿、再次查看進(jìn)程是否存在

1603179620707

性能測試

redis-benchmark是壓力測試工具庇茫,官方自帶的性能測試工具

redis-benchmark 命令參數(shù)!

圖片截取自菜鳥教程

1603179971678

實(shí)例測試:

#測試100個(gè)并發(fā)連接 100000請求
 redis-benchmark -h localhost -p 6379 -c 100 -n 100000
1603180898805

基礎(chǔ)知識(shí)

redis默認(rèn)有16個(gè)數(shù)據(jù)庫

1603181146408

默認(rèn)使用的是第0個(gè)

可以使用select進(jìn)行切換數(shù)據(jù)庫

127.0.0.1:6379> select 3# 切換數(shù)據(jù)庫
OK
127.0.0.1:6379[3]> DBSIZE #查看數(shù)據(jù)庫大小
(integer) 0
1603181495234
127.0.0.1:6379[3]> keys * #查看所有的key
1) "name"

清除當(dāng)前數(shù)據(jù)庫==FLUSHDB==

清除全部數(shù)據(jù)庫內(nèi)容==flushall==

127.0.0.1:6379[3]> FLUSHDB
OK
127.0.0.1:6379[3]> keys *
(empty array)

redis6.0之前是單線程的螃成,6.0引入了多線程

Redis 的瓶頸并不在 CPU旦签,而在內(nèi)存和網(wǎng)絡(luò)。內(nèi)存不夠的話寸宏,可以加內(nèi)存或者做數(shù)據(jù)結(jié)構(gòu)優(yōu)化和其他優(yōu)化等宁炫,但網(wǎng)絡(luò)的性能優(yōu)化才是大頭,網(wǎng)絡(luò) IO 的讀寫在 Redis 整個(gè)執(zhí)行期間占用了大部分的 CPU 時(shí)間氮凝,如果把網(wǎng)絡(luò)處理這部分做成多線程處理方式羔巢,那對整個(gè) Redis 的性能會(huì)有很大的提升。

Redis為什么單線程還這么快覆醇?

核心:redis是將所有的數(shù)據(jù)全部放在內(nèi)存中的朵纷,所以說使用單線程進(jìn)行操作效率就高,多線程(CPU上下文會(huì)且換:比較耗時(shí))

五大數(shù)據(jù)類型

官方文檔

1603183441252

Redis-Key

127.0.0.1:6379> keys * #查看所有的key
(empty array)
127.0.0.1:6379> set name lijie #添加一個(gè)key
OK
127.0.0.1:6379> get name
"lijie"
127.0.0.1:6379> set age 56
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> EXISTS name #判斷當(dāng)前key是否存在
(integer) 1
127.0.0.1:6379> exists user
(integer) 0
127.0.0.1:6379> move name 1 #移動(dòng)當(dāng)前數(shù)據(jù)庫的key到指定地?cái)?shù)據(jù)庫中
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name lijie
OK
127.0.0.1:6379> 
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> expire name 10 #設(shè)置key的過期時(shí)間單位是秒
(integer) 1
127.0.0.1:6379> ttl name #查看當(dāng)前可以的剩余時(shí)間
(integer) -2
127.0.0.1:6379> get name  #獲得key
(nil)
127.0.0.1:6379> del name #刪除key
(integer) 0
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> type name #查看當(dāng)前key的類型
string
127.0.0.1:6379> type age
string

String(字符串)

127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> EXISTS key1 #判斷某一個(gè)key是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 leave #追加字符串永脓,如果當(dāng)前key不存在,就相當(dāng)于增加一個(gè)key
(integer) 7
127.0.0.1:6379> get key1
"v1leave"
127.0.0.1:6379> STRLEN key1 #獲取字符串的長度
(integer) 7
127.0.0.1:6379> APPEND key1 pdd
(integer) 10
127.0.0.1:6379> STRLEN key1
(integer) 10
127.0.0.1:6379> get key1
"v1leavepdd"
##################################################
#步長
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views#自增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views#自減1
(integer) 1
127.0.0.1:6379> INCRBY views 10 #設(shè)置步長鞋仍,指定增量
(integer) 11
127.0.0.1:6379> DECRBY views 4 #設(shè)置步長常摧,指定減量
(integer) 7
##################################################
字符串范圍 range
127.0.0.1:6379> set key1 "hello Tom"  #key的值
OK
127.0.0.1:6379> get key1
"hello Tom"
127.0.0.1:6379> GETRANGE key1 0 2 #截取字符串 [0,3]
"hel"
127.0.0.1:6379> GETRANGE key1 0 -1 #獲取全部的字符串 相當(dāng)于get key1
"hello Tom"

#替換
127.0.0.1:6379> set key2 123456
OK
127.0.0.1:6379> get key2
"123456"
127.0.0.1:6379> SETRANGE key2 2 b #替換指定位置開始的字符串
(integer) 6
127.0.0.1:6379> get key2
"12b456"

#########################################################
# setex (set with expire)  設(shè)置過期時(shí)間
# setnx (set if not exist)  不存在再設(shè)置(在分布式鎖中會(huì)經(jīng)常使用)
127.0.0.1:6379> SETEX key3 30 "history" #設(shè)置key3得值為hello,30秒后過期
OK
127.0.0.1:6379> ttl key3
(integer) 19
127.0.0.1:6379> get key3
"history"
127.0.0.1:6379> setnx mykey "redis" #如果mykey 不存在,創(chuàng)建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
2) "mykey"
3) "key1"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> SETNX mykey "hello" #如果mykey存在落午,創(chuàng)建失敗
(integer) 0
127.0.0.1:6379> get mykey
"redis"
########################################################
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同時(shí)設(shè)置多個(gè)值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 #同時(shí)獲取多個(gè)值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4  #msetnx 是一個(gè)原子性的操作谎懦,要么一起成功,要么一起失敗
(integer) 0
127.0.0.1:6379> get k4
(nil)
#########################################################
set user:1 {name: lijie,age:3} #設(shè)置一個(gè)user:1對象 值為json字符串來保存一個(gè)對象

127.0.0.1:6379> mset user:1:name lijie user:1:age 60
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "lijie"
2) "60"
#########################################################
getset #先get再set
127.0.0.1:6379> getset db redis #如果不存在值溃斋,則創(chuàng)建值返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> GETSET db LeetCode #如果存在值界拦,則替換原來的值返回nil
"redis"
127.0.0.1:6379> get db
"LeetCode"

String類型的使用場景:

  • 計(jì)數(shù)器
  • 統(tǒng)計(jì)多單位的數(shù)量
  • 粉絲數(shù)
  • 對象緩存存儲(chǔ)

List (列表)

Redis列表是簡單的字符串列表,按照插入順序排序梗劫。你可以添加一個(gè)元素到列表的頭部(左邊)或者尾部(右邊)

一個(gè)列表最多可以包含 232 - 1 個(gè)元素 (4294967295, 每個(gè)列表超過40億個(gè)元素)享甸。

127.0.0.1:6379> lpush list one #將一個(gè)值或者多個(gè)值,插入到列表頭部(左)
(integer) 1
127.0.0.1:6379> lpush list two 
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1 # 獲取list中的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> LRANGE list 0 1 #通過區(qū)間來獲取具體的值
1) "three"
2) "two"
127.0.0.1:6379> RPUSH list four # #將一個(gè)值或者多個(gè)值梳侨,插入到列表尾部(右)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
#########################################################
lpop
rpop
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
127.0.0.1:6379> LPOP list #移除list的第一個(gè)元素
"three"
127.0.0.1:6379> Rpop list #移除list的最后一個(gè)元素
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
#########################################################
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1 # 通過下標(biāo)獲得list中的某一個(gè)值
"one"
127.0.0.1:6379> lindex list 0
"two"
#########################################################
LLen
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> llen list #返回列表的長度
(integer) 3

#########################################################
移除指定的值
LREM 
127.0.0.1:6379> LRANGE list 0 -1
^[[3~1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 one #移除list集合中指定個(gè)數(shù)的value蛉威,精確匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
#########################################################
trim 
127.0.0.1:6379> lpush list "hello1"
(integer) 1
127.0.0.1:6379> lpush list "hello2"
(integer) 2
127.0.0.1:6379> lpush list "hello3"
(integer) 3
127.0.0.1:6379> lpush list "hello4"
(integer) 4
127.0.0.1:6379> ltrim list 1 2 #通過下標(biāo)截取指定的長度
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "hello3"
2) "hello2"
#########################################################
rpoplpush #移動(dòng)列表的最后一個(gè)元素 到新的列表中
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "hello1"
(integer) 2
127.0.0.1:6379> RPUSH mylist "hello2"
(integer) 3
127.0.0.1:6379> RPOPLPUSH mylist otherlist#移動(dòng)列表的最后一個(gè)元素 到新的列表中
"hello2"
127.0.0.1:6379> LRANGE mylist 0 -1 #查看原來的列表
1) "hello"
2) "hello1"
127.0.0.1:6379> LRANGE otherlist 0 -1 #查看目標(biāo)列表,確實(shí)存在值
1) "hello2"

#########################################################
LSET #將列表中指定下標(biāo)的值替換為另外一個(gè)值走哺,更新操作
127.0.0.1:6379> EXISTS list#判斷這個(gè)列表是否存在
(integer) 0
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> LRANGE list 0 0
1) "value1"
127.0.0.1:6379> LSET list 0 tian #如果存在蚯嫌,更新當(dāng)前下標(biāo)的值
OK
127.0.0.1:6379> LRANGE list 0 0
1) "tian"
127.0.0.1:6379> LSET list 1 flag #如果不存在,則會(huì)保存
(error) ERR index out of range
#########################################################
LINSERT #將某個(gè)具體的value插入到列表中某個(gè)元素的前面或者后面
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "world"
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" tian
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "tian"
3) "world"
127.0.0.1:6379> LINSERT mylist after "world" flag
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "tian"
3) "world"
4) "flag"

==小結(jié)==

  • 實(shí)際上是一個(gè)鏈表丙躏,before Node after 择示,left,right都可以插入值
  • 如果key不存在晒旅,則創(chuàng)建新的鏈表
  • 如果key存在对妄,新增內(nèi)容
  • 如果移除了所有的值,就變成了空鏈表敢朱,代表不存在
  • 在兩邊插入或者改動(dòng)值剪菱,效率最高拴签!操作中間元素效率會(huì)低一點(diǎn)

消息排隊(duì)奕短!消息隊(duì)列 (Lpush Rpop)昆雀,棧(lpush Lpop)

Set(集合)

==set是無序不重復(fù)集合==

127.0.0.1:6379> SADD myset god #往set集合中添加元素
(integer) 1
127.0.0.1:6379> SADD myset oldxu
(integer) 1
127.0.0.1:6379> SADD myset wabibabo
(integer) 1
127.0.0.1:6379> SMEMBERS myset #查看指定集合中的所有值
1) "wabibabo"
2) "oldxu"
3) "god"
127.0.0.1:6379> SISMEMBER myset god #判斷某一個(gè)值是否在set集合中
(integer) 1
127.0.0.1:6379> SISMEMBER myset ooo
(integer) 0
#########################################################
127.0.0.1:6379> SCARD myset #獲取set集合中的內(nèi)容元素個(gè)數(shù)
(integer) 3
127.0.0.1:6379> sadd myset oldxu
(integer) 0
127.0.0.1:6379> sadd myset baozi
(integer) 1
127.0.0.1:6379> scard myset
(integer) 4
#########################################################
127.0.0.1:6379> srem myset god  #移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> SCARD myset
(integer) 3
127.0.0.1:6379> SMEMBERS myset
1) "baozi"
2) "wabibabo"
3) "oldxu"

#########################################################
127.0.0.1:6379> SRANDMEMBER myset #隨機(jī)抽選出一個(gè)元素
"baozi"
127.0.0.1:6379> SRANDMEMBER myset
"baozi"
127.0.0.1:6379> SRANDMEMBER myset
"wabibabo"
127.0.0.1:6379> SRANDMEMBER myset 2隨機(jī)抽選出指定個(gè)數(shù)的元素
1) "baozi"
2) "oldxu"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "wabibabo"
2) "oldxu"

#########################################################
刪除指定的key,隨機(jī)刪除key
127.0.0.1:6379> SMEMBERS myset
1) "baozi"
2) "wabibabo"
3) "oldxu"
127.0.0.1:6379> spop myset #隨機(jī)刪除set集合中的元素
"wabibabo"
127.0.0.1:6379> spop myset
"baozi"
127.0.0.1:6379> SMEMBERS myset
1) "oldxu"
#########################################################
#將一個(gè)指定的元素,移動(dòng)到另外一個(gè)集合中
127.0.0.1:6379> sadd myset qwert
(integer) 1
127.0.0.1:6379> sadd myset asdfg
(integer) 1
127.0.0.1:6379> sadd myset zxcvb
(integer) 1
127.0.0.1:6379> sadd name dingding
(integer) 1
127.0.0.1:6379> Smove myset name qwert #將一個(gè)指定的元素戴而,移動(dòng)到另外一個(gè)集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "zxcvb"
2) "asdfg"
127.0.0.1:6379> SMEMBERS name
1) "qwert"
2) "dingding"
#########################################################數(shù)字集合類:
- 差集 SDIFF
- 交集 SINTER
- 并集 sunion
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2 #差集
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2 #交集
1) "c"
127.0.0.1:6379> sunion key1 key2 #并集
1) "a"
2) "c"
3) "e"
4) "b"
5) "d"

Hash(哈希)

Map集合,key-map 它的值是一個(gè)Map集合犬钢,本質(zhì)和String類型沒有太大區(qū)別篷扩,還是一個(gè)簡單的key-value!

127.0.0.1:6379> hset myhash field1 bingb #set一個(gè)具體的key-value
(integer) 1
127.0.0.1:6379> hget myhash field1 #獲取一個(gè)字段值
"bingb"
127.0.0.1:6379> hset myhash field1 tiantian field2 libai #set多個(gè) key-value
(integer) 1
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> hset myhash field1 binggong
(integer) 1
127.0.0.1:6379> hget myhash field1
"binggong"
127.0.0.1:6379> hmset myhash field1 dingding field2 libai  #獲取多個(gè)字段值
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "dingding"
2) "libai"
127.0.0.1:6379> HGETALL myhash #獲取全部數(shù)據(jù)
1) "field1"
2) "dingding"
3) "field2"
4) "libai"
127.0.0.1:6379> HDEL myhash field1 #刪除hash指定key字段曹阔,對應(yīng)的value值也就消失了
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "libai"
#########################################################
hlen
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "libai"
127.0.0.1:6379> hlen myhash #獲取hash表中字段的數(shù)量
(integer) 1

#########################################################
HEXISTS
127.0.0.1:6379> HEXISTS myhash field1 #判斷hash中指定字段是否存在
(integer) 0
127.0.0.1:6379> HEXISTS myhash field2
(integer) 1
#########################################################
# 獲得所有field HKEYS
# 獲得所有value HVALS
127.0.0.1:6379> HKEYS myhash # 獲得所有的字段
1) "field2"
2) "filed1"
127.0.0.1:6379> HVALS myhash # 獲得所有value
1) "libai"
2) "hello"

#########################################################

127.0.0.1:6379> hset myhash field3 5 #指定增量
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1
(integer) 6
127.0.0.1:6379> HINCRBY myhash field3 -1
(integer) 5
127.0.0.1:6379> HSETNX myhash field4 bbbb #如果不存在則新增
(integer) 1
127.0.0.1:6379> HSETNX myhash field4 bbbb  #如果存在則不能設(shè)置
(integer) 0

hash適合存儲(chǔ)經(jīng)常變動(dòng)的信息半开,尤其是用戶信息之類的。hash適合與對象的存儲(chǔ)赃份,String更加適合字符串存儲(chǔ)

Zset(有序集合)

在set的基礎(chǔ)上寂拆,增加了一個(gè)用來排序的值

127.0.0.1:6379> zadd myzset 1 one #添加一個(gè)值
(integer) 1
127.0.0.1:6379> zadd myzset 2 two 3 three #添加多個(gè)值
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
#########################################################
實(shí)現(xiàn)排序
127.0.0.1:6379> zadd salary 2500 libai #添加三個(gè)用戶以及薪水
(integer) 1
127.0.0.1:6379> zadd salary 4500 dufu
(integer) 1
127.0.0.1:6379> zadd salary 200 AQ
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf #顯示全部的用戶從小到大
1) "AQ"
2) "libai"
3) "dufu"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores  #顯示全部的用戶并附帶薪水
1) "AQ"
2) "200"
3) "libai"
4) "2500"
5) "dufu"
6) "4500"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores  #顯示工資小于等于2500的員工按升序排列
1) "AQ"
2) "200"
3) "libai"
4) "2500"
127.0.0.1:6379> ZREVRANGE salary 0 -1 #從大到小進(jìn)行排序
1) "dufu"
2) "libai"
#########################################################
127.0.0.1:6379> ZRANGE salary 0 -1
1) "AQ"
2) "libai"
3) "dufu"
127.0.0.1:6379> zrem salary AQ #移除元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "libai"
2) "dufu"
127.0.0.1:6379> zcard salary #獲取有序集合中的個(gè)數(shù)
(integer) 2
#########################################################
127.0.0.1:6379> zadd myzset 1 qwert 2 asdfg 3 zxcvb 
(integer) 3
127.0.0.1:6379> zcount  myzset 1 3 #獲取指定區(qū)間的成員數(shù)量
(integer) 3
127.0.0.1:6379> zcount  myzset 1 2
(integer) 2

三種特殊數(shù)據(jù)類型

geospatial 地理位置

微信定位奢米,附近的人,打車距離計(jì)算

Redis的Geo功能可以推算地理位置的信息纠永,兩地之間的距離鬓长,方圓幾里的人

1603265547235

geoadd

#geoadd 添加地理位置
# 規(guī)則:兩極無法直接添加
# 參數(shù) key value(經(jīng)度、緯度尝江、名稱)
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shenzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2

geopos

獲得當(dāng)前定位:一定是一個(gè)坐標(biāo)值

127.0.0.1:6379> geopos china:city beijing #獲取指定的城市的精度和緯度
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city beijing chongqin
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"

GEODIST

兩人之間的距離

單位:

  • m 表示單位為米涉波。
  • km 表示單位為千米。
  • mi 表示單位為英里炭序。
  • ft 表示單位為英尺啤覆。
127.0.0.1:6379> GEODIST china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> GEODIST china:city beijing shanghai km #查看北京到上海的直線距離
"1067.3788"
127.0.0.1:6379> GEODIST china:city beijing chongqin km
"1464.0708"

GEORADIUS 以給定的經(jīng)緯度為中心, 返回鍵包含的位置元素當(dāng)中少态, 與中心的距離不超過給定最大距離的所有位置元素城侧。

獲取附近的人的地址,定位彼妻,通過半徑來查詢

127.0.0.1:6379> GEORADIUS china:city 110 20 1000 km
1) "shenzhen"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km #以110嫌佑,30 這個(gè)經(jīng)緯度為中心,尋找方圓1000km內(nèi)的城市
1) "chongqin"
2) "xian"
3) "shenzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km  withdist #顯示到中心位置的距離
1) 1) "chongqin"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord #顯示他人的定位信息
1) 1) "chongqin"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1
1) 1) "chongqin"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 2 #篩選出指定的結(jié)果
1) 1) "chongqin"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

GEORADIUSBYMEMBER

#找出位于指定元素周圍的其他元素
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city xian 500 km
1) "xian"

GEOHASH 返回一個(gè)或多個(gè)位置元素的 Geohash 表示

該命令將返回11個(gè)字符的Geohash字符串

# 將二維的經(jīng)緯度轉(zhuǎn)換為一維的字符串
127.0.0.1:6379> GEOHASH china:city beijing chongqin
1) "wx4fbxxfke0"
2) "wm5xzrybty0"

GEO底層的實(shí)現(xiàn)原理為Zset 侨歉,可以使用Zset命令來操作geo

127.0.0.1:6379> ZRANGE china:city 0 -1 #查看地圖中全部的元素
1) "chongqin"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city xian #移除指定元素
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqin"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "beijing"

Hyperloglog

什么是基數(shù)屋摇?

不重復(fù)的元素

A{1 ,2幽邓, 3 炮温,4 ,5牵舵,5} B{1柒啤,2,3畸颅,4担巩,5}

基數(shù)為5

簡介

Redis Hyperloglog 基數(shù)統(tǒng)計(jì)的算法。

優(yōu)點(diǎn):占用的內(nèi)存是固定的没炒,2^64不同元素的技術(shù)涛癌,只需要消耗12kb內(nèi)存

網(wǎng)頁的UV(一個(gè)人訪問一個(gè)網(wǎng)站多次。但還是算作一個(gè)人)

0.81%錯(cuò)誤率送火!對于UV任務(wù) 拳话,可以忽略不計(jì)

測試使用

127.0.0.1:6379> pfadd mykey a b c d e f g h i j #創(chuàng)建第一組元素 mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey #統(tǒng)計(jì)mykey 元素的基數(shù)數(shù)量
(integer) 10
127.0.0.1:6379> pfadd mykey2 a j j o f n q m #創(chuàng)建第二組元素 mykey2
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 7
127.0.0.1:6379> PFMERGE mykey3 mykey2 mykey #合并兩組 mykey mykey2 =》mykey3
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 14

Bitmap

位存儲(chǔ)

統(tǒng)計(jì)用戶信息,活躍种吸,不活躍弃衍!打卡。兩個(gè)狀態(tài)的骨稿,都可以使用Bitmap笨鸡!

Bitmap位圖姜钳,都是操作二進(jìn)制位來進(jìn)行記錄坦冠,就只有0和1兩個(gè)狀態(tài)

測試

#使用bitmap來記錄 周一到周日的打卡形耗,1代表打卡 0代表未打卡
127.0.0.1:6379> setbit sign 0 0
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
####################################################
#查看某一天是否打卡
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 4
(integer) 0
##########################################################統(tǒng)計(jì)操作,統(tǒng)計(jì)打卡的天數(shù)
127.0.0.1:6379> bitcount sign
(integer) 3

事務(wù)

Redis事務(wù)本質(zhì):一組命令的集合辙浑!一個(gè)事務(wù)中的所有命令都會(huì)被序列化激涤,在事務(wù)執(zhí)行的過程中,會(huì)按照順序執(zhí)行

一次性判呕、順序性倦踢、排他性!執(zhí)行一系列的命令

------ 隊(duì)列 set set set 執(zhí)行 ------

Redis事務(wù)沒有隔離級別的概念

所有的命令在事務(wù)中侠草,并沒有直接被執(zhí)行! 只有發(fā)起執(zhí)行命令的時(shí)候才會(huì)執(zhí)行

Redis單條命令是保證原子性的辱挥,但事務(wù)不保證原子性

redis的事務(wù):

  • 開啟事務(wù)(multi)
  • 命令入隊(duì)()
  • 執(zhí)行事務(wù)(exec)

正常開啟事務(wù)

127.0.0.1:6379> multi #開啟事務(wù)
OK
127.0.0.1:6379> set k1 v1 #命令入隊(duì)
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #執(zhí)行事務(wù)
1) OK
2) OK
3) "v1"
4) OK

放棄事務(wù)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> discard #放棄事務(wù) 事務(wù)隊(duì)列中的命令都不會(huì)被執(zhí)行
OK

編譯型異常(代碼有問題!命令錯(cuò)誤1咛椤)晤碘,事務(wù)中所有的命令都不會(huì)被執(zhí)行,錯(cuò)誤命令拋出異常

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> adahjj k3 #錯(cuò)誤的命令
(error) ERR unknown command `adahjj`, with args beginning with: `k3`, 
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec #執(zhí)行事務(wù)報(bào)錯(cuò)
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4 #所有的命令都不會(huì)被執(zhí)行
(nil)

運(yùn)行時(shí)異常(1/0)功蜓,如果事務(wù)隊(duì)列中存在語法性錯(cuò)誤园爷,那么執(zhí)行命令的時(shí)候,其他命令是可以正常執(zhí)行的

127.0.0.1:6379> set name "lijie"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr name 
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range #雖然第一條命令報(bào)錯(cuò)了式撼,但事務(wù)依舊執(zhí)行成功了
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"

監(jiān)控童社!Watch

悲觀鎖:

  • 很悲觀,認(rèn)為什么時(shí)候都會(huì)出問題著隆,無論做什么都會(huì)加鎖

樂觀鎖:

  • 很樂觀扰楼,認(rèn)為什么時(shí)候都不會(huì)出問題,所以不會(huì)上鎖美浦!更新數(shù)據(jù)的時(shí)候判斷一下弦赖,在此期間是否有人修改過這個(gè)數(shù)據(jù)
  • 獲取version
  • 更新的時(shí)候比較version

Redis監(jiān)視測試

正常執(zhí)行成功

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money #監(jiān)視 money 對象
OK
127.0.0.1:6379> multi #數(shù)據(jù)執(zhí)行期間沒有發(fā)生變動(dòng),這個(gè)時(shí)候就正常執(zhí)行成功
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

測試多線程修改值抵代,使用watch可以當(dāng)做redis的樂觀鎖操作

127.0.0.1:6379> watch money #監(jiān)視 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY out 10
QUEUED
127.0.0.1:6379> exec #執(zhí)行之前腾节,另外一個(gè)線程,修改了我們的值荤牍,這個(gè)時(shí)候就會(huì)導(dǎo)致事務(wù)執(zhí)行失敗
(nil)

如果修改失敗案腺,獲取最新的值就好

127.0.0.1:6379> unwatch # 如果發(fā)現(xiàn)事務(wù)執(zhí)行失敗,就先解鎖
OK
127.0.0.1:6379> watch money #獲取最新的值康吵,再次監(jiān)視
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 1
QUEUED
127.0.0.1:6379> INCRBY money 1
QUEUED
127.0.0.1:6379> exec #對比監(jiān)視的值是否發(fā)生了變化劈榨,如果沒有變化,那么可以執(zhí)行成功晦嵌,如果產(chǎn)生了變化就執(zhí)行失敗
1) (integer) 999
2) (integer) 1000

Jedis

Jedis是Redis官方推薦的java連接開發(fā)工具同辣!使用Java操作Redis中間件

測試

1拷姿、導(dǎo)入對應(yīng)的依賴

 <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
<!-- fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>
    </dependencies>

2、編碼測試:

  • 連接數(shù)據(jù)庫

  • 操作命令

  • 斷開連接

    public class TestPing {
        public static void main(String[] args) {
            Jedis jedis = new Jedis("localhost",6379);
            jedis.auth("dengzhuo");
            System.out.println(jedis.ping());
        }
    }
    
1603340679054

常用的API

String

List

Set

Hash

Zset

測試事務(wù)

public class TestTX {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost",6379);
        jedis.auth("dengzhuo");
        jedis.flushDB();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","lijie");
        //開啟事務(wù)
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();

        try {
            multi.set("user1",result);
            multi.set("user2",result);
            int i =1/0;
            multi.exec();//執(zhí)行事務(wù)
        } catch (Exception e) {
            multi.discard();//放棄事務(wù)
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();//關(guān)閉連接
        }
    }
}

SpringBoot整合

在SpringBoot2.x之后旱函,原來使用的jedis被替換成了lettuce

jedis:采用的直連技術(shù)响巢,多個(gè)線程操作的話,是不安全的棒妨,為了避免這種情況踪古,會(huì)使用jedis pool連接池,類型BIO模式

lettuce:采用netty券腔,實(shí)例可以在多個(gè)線程中進(jìn)行共享伏穆,不存在線程不安全的情況!可以減少線程數(shù)據(jù)纷纫,更像NIO 模式

源碼分析

 @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}//我們可以用自定義的redisTemplate來替換這個(gè)默認(rèn)的
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        //默認(rèn)的redisTemplate沒有過多設(shè)置枕扫,redis對象都是需要序列化的
        //兩個(gè)泛型都是object,object的類型辱魁,后續(xù)使用需要強(qiáng)制轉(zhuǎn)換<String,object>
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean //由于String是redis中最常使用的類型烟瞧,所以單獨(dú)提出一個(gè)bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

整合測試

1、導(dǎo)入依賴

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2商叹、配置連接

spring.redis.host= localhost
spring.redis.port=6379
spring.redis.password=******

3燕刻、測試

@SpringBootTest
class Redis02SpringbootApplicationTests {
    @Autowired
 private    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        //redisTemplate  操作不同的數(shù)據(jù)類型
        //opsForValue //操作字符串
        //opsForList
        //opsForSet
        //opsForHash
        //opsForZSet
        //opsForGeo
        //opsForHyperLogLog

        //除了基本的操作,常用的方法都可以直接通過redisTemplate操作剖笙,例如事務(wù)和卵洗,基本的CRUD

        //獲取redis的連接對象
//        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//        connection.flushAll();
//        connection.flushDb();
        redisTemplate.opsForValue().set("name","lijie");
        System.out.println(redisTemplate.opsForValue().get("name"));
    }

}
1603354537185
1603354695276
1603354820215
1603355707008

自定義RedisTemplate

@Configuration
public class RedisConfig {
    //自己定義了一個(gè)RedisTemplate
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) throws UnknownHostException {
        //為了開發(fā)方便,一般直接使用<String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(factory);
        //序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(om.getPolymorphicTypeValidator());
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

Redis.conf詳解

啟動(dòng)的時(shí)候弥咪,就通過配置文件來啟動(dòng)过蹂!

單位

1603362565546

1、配置文件unit單位對大小寫不敏感

包含

1603362709561

網(wǎng)絡(luò)

bind 127.0.0.1 #綁定的IP
protected-mode no #保護(hù)模式
port 6379 #端口設(shè)置

通用GENERAL

daemonize yes  #以守護(hù)進(jìn)程的方式運(yùn)行聚至,默認(rèn)是no酷勺,我們需要自己開啟默認(rèn)為yes
pidfile /var/run/redis_6379.pid #如果以后臺(tái)的方式運(yùn)行,就需要指定一個(gè)pid文件

#日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" #日志文件的位置
databases 16 #數(shù)據(jù)庫的數(shù)量扳躬,默認(rèn)是16個(gè)
always-show-logo yes #是否總是顯示LOGO

快照

redis是內(nèi)存數(shù)據(jù)庫脆诉,如果沒有持久化,那么數(shù)據(jù)斷電即失

#如果900s內(nèi)贷币,如果至少有一個(gè)key進(jìn)行了修改击胜,將自動(dòng)進(jìn)行持久化操作
save 900 1
#如果300s內(nèi),如果至少10個(gè)key進(jìn)行了修改役纹,將自動(dòng)進(jìn)行持久化操作
save 300 10
#如果60s內(nèi)偶摔,如果至少10000個(gè)key進(jìn)行了修改,將自動(dòng)進(jìn)行持久化操作
save 60 10000

stop-writes-on-bgsave-error yes #持久化如果出錯(cuò)促脉,是否還繼續(xù)工作
rdbcompression yes #是否壓縮 rdb 文件辰斋,策州,需要消耗一些cpu資源

rdbchecksum yes #保存rdb文件的時(shí)候,進(jìn)行錯(cuò)誤的檢查校驗(yàn)

dir ./ #rdb文件保存的目錄


SECURITY 安全

requirepass dengzhuo #密碼設(shè)置
maxclients 10000 #設(shè)置能連接上redis的最大客戶端的數(shù)量
maxmemory <bytes> #redis 配置最大的內(nèi)存容量
maxmemory-policy noeviction #內(nèi)存到達(dá)上限之后的處理策略

    volatile-lru:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中,選擇最近最久未使用的數(shù)據(jù)釋放;
    allkeys-lru:從數(shù)據(jù)集中(包括設(shè)置過期時(shí)間以及未設(shè)置過期時(shí)間的數(shù)據(jù)集中)衣吠,選擇最近最久未使用的數(shù)據(jù)釋放;
    volatile-random:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中下硕,隨機(jī)選擇一個(gè)數(shù)據(jù)進(jìn)行釋放丁逝;
    allkeys-random:從數(shù)據(jù)集中(包括了設(shè)置過期時(shí)間以及未設(shè)置過期時(shí)間)隨機(jī)選擇一個(gè)數(shù)據(jù)進(jìn)行入釋放汁胆;
    volatile-ttl:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中,選擇馬上就要過期的數(shù)據(jù)進(jìn)行釋放操作霜幼;
    noeviction:不刪除任意數(shù)據(jù)(但redis還會(huì)根據(jù)引用計(jì)數(shù)器進(jìn)行釋放),這時(shí)如果內(nèi)存不夠時(shí)嫩码,會(huì)直接返回錯(cuò)誤。

APPENDONLY ONLY 模式 aof配置

appendonly no #默認(rèn)是不開啟aof模式的罪既,默認(rèn)是使用rdb方式持久化的铸题,在大部分情況下,rdb完全夠用
appendfilename "appendonly.aof" #持久化的文件名

# appendfsync always #每次修改都會(huì) sync(同步)琢感,消耗性能
appendfsync everysec #每秒執(zhí)行一次 sync丢间,可能會(huì)丟失這一秒的數(shù)據(jù)
# appendfsync no #不執(zhí)行 sync,操作系統(tǒng)自己同步數(shù)據(jù)驹针,速度最快

Redis持久化

Redis是內(nèi)存數(shù)據(jù)庫烘挫,如果不將內(nèi)存中的數(shù)據(jù)庫狀態(tài)保存到磁盤,那么一旦服務(wù)器進(jìn)程退出柬甥,服務(wù)器中的數(shù)據(jù)庫狀態(tài)也會(huì)消失饮六,所以Redis提供了持久化功能。

RDB(Redis DataBase)

在指定的時(shí)間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤苛蒲,也就是行話講的Snapshot快照卤橄,它恢復(fù)時(shí)是將快照文件直接讀到內(nèi)存里。
Redis會(huì)單獨(dú)創(chuàng)建( fork )一個(gè)子進(jìn)程來進(jìn)行持久化臂外,會(huì)先將數(shù)據(jù)寫入到一個(gè)臨時(shí)文件中窟扑,待持久化過程都結(jié)束了,再用這個(gè)臨時(shí)文件替換上次持久化好的文件漏健。整個(gè)過程中嚎货,主進(jìn)程是不進(jìn)行任何IO操作的。這就確保了極高的性能漾肮。如果需要進(jìn)行大規(guī)模數(shù)據(jù)的恢復(fù)厂抖,且對于數(shù)據(jù)恢復(fù)的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效克懊。RDB的缺點(diǎn)是最后一次持久化后的數(shù)據(jù)可能丟失忱辅。我們默認(rèn)的就是RDB七蜘,一般情況下不需要修改這個(gè)配置!

==rdb保存的文件是dump.rdb==

1603371378785

自定義配置只要60s內(nèi)修改5次key,就會(huì)觸發(fā)rdb操作

1603371590909

觸發(fā)機(jī)制

1墙懂、save的規(guī)則滿足的情況下橡卤,會(huì)自動(dòng)觸發(fā)rdb規(guī)則

2、執(zhí)行flushall命令损搬,也會(huì)觸發(fā)rdb規(guī)則

3碧库、退出redis,也會(huì)產(chǎn)生rdb文件

備份就會(huì)自動(dòng)生成一個(gè)dump.rdb

1603372749290

恢復(fù)rdb文件

1巧勤、只需要將rdb文件放在redis啟動(dòng)目錄下就可以了嵌灰,redis啟動(dòng)的時(shí)候會(huì)自動(dòng)檢查dump.rdb恢復(fù)其中的數(shù)據(jù)

2、查看文件存在的位置

46.154.150.53:6379> config get dir
1) "dir"
2) "/usr/local/bin" #如果在這個(gè)目錄下存在dump.rdb文件颅悉,啟動(dòng)就會(huì)自動(dòng)恢復(fù)其中的數(shù)據(jù)

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

1沽瞭、適合大規(guī)模的數(shù)據(jù)恢復(fù)

2、對數(shù)據(jù)的完整性要求不高

缺點(diǎn):

1剩瓶、需要一定的時(shí)間進(jìn)行操作驹溃!如果redis意外宕機(jī)了,最后一次修改的數(shù)據(jù)就沒有了

2延曙、fork進(jìn)程的時(shí)候豌鹤,會(huì)占用一定的內(nèi)容空間

AOF(Append Only File)

將所有命令都記錄下來,history枝缔,恢復(fù)的時(shí)候就把這個(gè)文件全部在執(zhí)行一遍!

是什么

以日志的形式來記錄每個(gè)寫操作布疙,將Redis執(zhí)行過的所有指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件魂仍,redis啟動(dòng)之初會(huì)讀取該文件重新構(gòu)建數(shù)據(jù)拐辽,換言之,redis重啟的話就根據(jù)日志文件的內(nèi)容將寫指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復(fù)工作擦酌。
==Aof保存的是appendonly.aof文件==

1603374211226

默認(rèn)是不開啟的俱诸,我們需要手動(dòng)進(jìn)行配置 ! 我們只需要將appendorly改為yes就開啟了aof !

重啟,redis就可以生效了!

如果這個(gè)aof文件有錯(cuò)位赊舶,此時(shí)redis是無法啟動(dòng)的睁搭,需要修復(fù)aof文件

redis提供了一個(gè)修復(fù)工具==redis-check-aof==

1603413921777

修復(fù)之后,就能正常啟動(dòng)redis了

1603414122972

重寫規(guī)則

1603414807429

如果aof文件大于64Mb笼平,就會(huì)fork一個(gè)新的進(jìn)程來將文件進(jìn)行重寫

優(yōu)點(diǎn)和缺點(diǎn)

appendonly no #默認(rèn)是不開啟aof模式的园骆,默認(rèn)是使用rdb方式持久化的,在大部分情況下寓调,rdb完全夠用
appendfilename "appendonly.aof" #持久化的文件名

# appendfsync always #每次修改都會(huì) sync(同步)锌唾,消耗性能
appendfsync everysec #每秒執(zhí)行一次 sync,可能會(huì)丟失這一秒的數(shù)據(jù)
# appendfsync no #不執(zhí)行 sync,操作系統(tǒng)自己同步數(shù)據(jù)晌涕,速度最快

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

1滋捶、每一次修改都同步,文件的完整性會(huì)更好

2余黎、每秒同步一次重窟,可能會(huì)丟失一秒的數(shù)據(jù)

3、從不同步惧财,效率最高的

缺點(diǎn):

1巡扇、相對于數(shù)據(jù)文件來說,aof遠(yuǎn)遠(yuǎn)大于rdb垮衷,修復(fù)的速度也比rdb慢

2厅翔、Aof運(yùn)行效率也要比rdb慢。

Redis發(fā)布訂閱

Redis 發(fā)布訂閱(pub/sub)是一種消息通信模式︰發(fā)送者(pub)發(fā)送消息帘靡,訂閱者(sub)接收消息知给。

Redis 客戶端可以訂閱任意數(shù)量的頻道。

訂閱/發(fā)布消息圖:

1603415658516

下圖展示了頻道 channel1 描姚, 以及訂閱這個(gè)頻道的三個(gè)客戶端 —— client2 、 client5 和 client1 之間的關(guān)系:

img

當(dāng)有新消息通過 PUBLISH 命令發(fā)送給頻道 channel1 時(shí)戈次, 這個(gè)消息就會(huì)被發(fā)送給訂閱它的三個(gè)客戶端:

img

命令

1 PSUBSCRIBE pattern [ pattern ...]訂閱一個(gè)或多個(gè)符合給定模式的頻道。
2 PUBSUB subcommand [argument [argument ...]]查看訂閱與發(fā)布系統(tǒng)狀態(tài)澄步。
3 PUBLISH channel message將信息發(fā)送到指定的頻道
4 PUBLISH channel message將信息發(fā)送到指定的頻道冤议。
5 SUBSCRIBE channel [channel ..]訂閱給定的一個(gè)或多個(gè)頻道的信息犯眠。
6 UNSUBSCRIBE_[channel [channel ...]]指退訂給定的頻道缩滨。

測試

訂閱端:

46.154.150.53:6379> SUBSCRIBE Alibaba #訂閱一個(gè)頻道 Alibaba
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "Alibaba"
3) (integer) 1
#等待讀取推送的信息
1) "message" #消息
2) "Alibaba" #頻道
3) "hello,boy" #消息的具體內(nèi)容

1) "message"
2) "Alibaba"
3) "life"

發(fā)送端:

46.154.150.53:6379> PUBLISH Alibaba "hello,boy" #發(fā)布者發(fā)布消息到頻道
(integer) 1
46.154.150.53:6379> PUBLISH Alibaba "life"
(integer) 1

原理

Redis是使用C實(shí)現(xiàn)的刃泡,通過分析Redis源碼里的pubsud.c文件铺峭,了解發(fā)布和訂閱機(jī)制的底層實(shí)現(xiàn)墓怀,籍此加深對Redis的理解。

Redis 通過PUBLISH卫键、SUBSCRIBE 和PSUBSCRIBE等命令實(shí)現(xiàn)發(fā)布和訂閱功能傀履。

通過SUBSCRIBE 命令訂閱某頻道后,redis-server里維護(hù)了一個(gè)字典莉炉,字典的鍵就是一個(gè)個(gè)channel(頻道)钓账,而字典的值則是一個(gè)鏈表,鏈表中保存了所有訂閱這個(gè)channel的客戶端絮宁。SUBSCRIBE命令的關(guān)鍵梆暮,就是將客戶端添加到給定channel的訂閱鏈表中。

通過PUBLISH命令向訂閱者發(fā)送消息绍昂,redis-server會(huì)使用給定的頻道作為鍵啦粹,在它所維護(hù)的channel字典中查找記錄了訂閱這個(gè)頻道的所有客戶端的鏈表,遍歷這個(gè)鏈表窘游,將消息發(fā)布給所有訂閱者唠椭。

Pub/Sub從字面上理解就是發(fā)布( Publish )與訂閱(Subscribe ),在Redis中张峰,你可以設(shè)定對某一個(gè)key值進(jìn)行消息發(fā)布及消息訂閱泪蔫,當(dāng)一個(gè)key值上進(jìn)行了消息發(fā)布后,所有訂閱它的客戶端都會(huì)收到相應(yīng)的消息喘批。這一功能最明顯的用法就是用作實(shí)時(shí)消息系統(tǒng),比如普通的即時(shí)聊天铣揉,群聊等功能饶深。

Redis主從復(fù)制

概念

主從復(fù)制,是指將一臺(tái)Redis服務(wù)器的數(shù)據(jù)逛拱,復(fù)制到其他的Redis服務(wù)器敌厘。前者稱為主節(jié)點(diǎn)(master/leader),后者稱為從節(jié)點(diǎn)(slave/follower);數(shù)據(jù)的復(fù)制是單向的朽合,只能由主節(jié)點(diǎn)到從節(jié)點(diǎn)俱两。Master以寫為主,Slave以讀為主曹步。
默認(rèn)情況下宪彩,每臺(tái)Redis服務(wù)器都是主節(jié)點(diǎn);且一個(gè)主節(jié)點(diǎn)可以有多個(gè)從節(jié)點(diǎn)(或沒有從節(jié)點(diǎn)),但一個(gè)從節(jié)點(diǎn)只能有一個(gè)主節(jié)點(diǎn)讲婚。

主從復(fù)制的作用主要包括:
1尿孔、數(shù)據(jù)冗余︰主從復(fù)制實(shí)現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。
2活合、故障恢復(fù)︰當(dāng)主節(jié)點(diǎn)出現(xiàn)問題時(shí)雏婶,可以由從節(jié)點(diǎn)提供服務(wù),實(shí)現(xiàn)快速的故障恢復(fù);實(shí)際上是一種服務(wù)的冗余白指。
3留晚、負(fù)載均衡︰在主從復(fù)制的基礎(chǔ)上,配合讀寫分離告嘲,可以由主節(jié)點(diǎn)提供寫服務(wù)错维,由從節(jié)點(diǎn)提供讀服務(wù)(即寫Redis數(shù)據(jù)時(shí)應(yīng)用連接主節(jié)點(diǎn),讀Redis數(shù)據(jù)時(shí)應(yīng)用連接從節(jié)點(diǎn))状蜗,分擔(dān)服務(wù)器負(fù)載;尤其是在寫少讀多的場景下需五,通過多個(gè)從節(jié)點(diǎn)分擔(dān)讀負(fù)載,可以大大提高Redis服務(wù)器的并發(fā)量轧坎。
4宏邮、高可用(集群)基石︰除了上述作用以外,主從復(fù)制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ)缸血,因此說主從復(fù)制是Redis高可用的基礎(chǔ).

一般來說蜜氨,要將Redis運(yùn)用于工程項(xiàng)目中,只使用一臺(tái)Redis是萬萬不能的捎泻,原因如下:
1涡相、從結(jié)構(gòu)上,單個(gè)Redis服務(wù)器會(huì)發(fā)生單點(diǎn)故障坐梯,并且一臺(tái)服務(wù)器需要處理所有的請求負(fù)載价卤,壓力較大;
2、從容量上闯狱,單個(gè)Redis服務(wù)器內(nèi)存容量有限煞赢,就算一臺(tái)Redis服務(wù)器內(nèi)存容量為256G,也不能將所有內(nèi)存用作Redis存儲(chǔ)內(nèi)存哄孤,—般來說照筑,單臺(tái)Redis最大使用內(nèi)存不應(yīng)該超過20G。

電商網(wǎng)站上的商品瘦陈,一般都是一次上傳凝危,無數(shù)次瀏覽的,說專業(yè)點(diǎn)也就是"多讀少寫"晨逝。

1603418107135

主從復(fù)制蛾默,讀寫分離!80%的情況下都是在進(jìn)行讀操作!減緩服務(wù)器的壓力!架構(gòu)中經(jīng)常使用!一主二從!

只要在公司中,主從復(fù)制就是必須要使用的咏花,因?yàn)樵谡鎸?shí)的項(xiàng)目中不可能單機(jī)使用Redis !

環(huán)境配置

只配置從庫趴生,不用配置主庫

46.154.150.53:6379> info replication #查看當(dāng)前庫的信息
# Replication
role:master #角色 master
connected_slaves:0 #沒有從機(jī)
master_replid:8ff1c6abcfd4dd8bb6621f5fee5c5162ba4dd377
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

復(fù)制3個(gè)配置文件阀趴,修改對應(yīng)的信息

1603419485086

1、端口

2苍匆、pid名字

3刘急、log文件名字

4、dump.rdb文件名

修改完畢之后浸踩,啟動(dòng)3個(gè)服務(wù)器叔汁,可以通過進(jìn)程信息查詢

1603419823288

配置過密碼的需要在從機(jī)的配置文件中修改

masterauth 密碼

一主二從

==默認(rèn)情況下,每臺(tái)Redis服務(wù)器都是主節(jié)點(diǎn);== 一般情況下只用配置從機(jī)就好了

一主(79)二從(80检碗,81)

redis-cli -h 47.101.150.57 -p 6380

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379  # SLAVEOF host 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave #當(dāng)前角色是從機(jī)
master_host:127.0.0.1  #可以看到主機(jī)的信息
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1603424493
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a882caf1c2e8657e1b7edd438c2d7f3b4d7e0e1a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6380> 

#在主機(jī)中查看
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 #多了從機(jī)的配置
slave0:ip=127.0.0.1,port=6381,state=online,offset=336,lag=1
slave1:ip=127.0.0.1,port=6380,state=online,offset=336,lag=1
master_replid:c18fcb2b0f21e0a0691a232c71bb11f48ed6017f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:336

1603425296410

真實(shí)的主從配置應(yīng)該是在配置文件中配置据块,能夠保證永久性,以上的為命令配置折剃,是暫時(shí)的另假!

注意

主機(jī)可以寫,從機(jī)不能寫只能讀怕犁!主機(jī)中的所有信息和數(shù)據(jù)边篮,都會(huì)被從機(jī)保存

主機(jī)寫:

1603425744570

主機(jī)只能讀取內(nèi)容:

1603425806825

測試:主機(jī)斷開連接,從機(jī)依舊連接到主機(jī)奏甫,但是沒有寫操作戈轿,如果主機(jī)恢復(fù)運(yùn)行,從機(jī)依舊可以直接獲得主機(jī)寫的信息

如果是使用命令行來配置主從阵子,從機(jī)如果重啟了思杯,就會(huì)變回主機(jī),只要再次設(shè)置為從機(jī)挠进,依舊可以從主機(jī)中獲取值

復(fù)制原理

Slave啟動(dòng)成功連接到master 后會(huì)發(fā)送一個(gè)sync同步命令
Master接到命令色乾,啟動(dòng)后臺(tái)的存盤進(jìn)程,同時(shí)收集所有接收到的用于修改數(shù)據(jù)集命令领突,在后臺(tái)進(jìn)程執(zhí)行完畢之后杈湾,master將傳送整個(gè)數(shù)據(jù)文件到slave ,并完成一次完全同步。
全量復(fù)制︰而slave服務(wù)在接收到數(shù)據(jù)庫文件數(shù)據(jù)后攘须,將其存盤并加載到內(nèi)存中。增量復(fù)制:Master繼續(xù)將新的所有收集到的修改命令依次傳給slave殴泰,完成同步但是只要是重新連接master 于宙,一次完全同步(全量復(fù)制)將被自動(dòng)執(zhí)行

層層鏈路(級聯(lián)復(fù)制)

1603442148845

也能完成主從復(fù)制!

如果沒有主機(jī)了悍汛,可以手動(dòng)選擇一個(gè)老大

如果主機(jī)斷開了連接捞魁,可以使用==SLAVEOF no one== 使自己變成主機(jī),其他的節(jié)點(diǎn)就可以手動(dòng)連接到最新的這個(gè)主節(jié)點(diǎn)

哨兵模式

概述

主從切換技術(shù)的方法是∶當(dāng)主服務(wù)器宕機(jī)后离咐,需要手動(dòng)把一臺(tái)從服務(wù)器切換為主服務(wù)器谱俭,這就需要人工干預(yù)奉件,費(fèi)事費(fèi)力,還會(huì)造成一段時(shí)間內(nèi)服務(wù)不可用昆著。這不是一種推薦的方式县貌,更多時(shí)候,我們優(yōu)先考慮哨兵模式凑懂。Redis從2.8開始正式提供了Sentinel (哨兵)架構(gòu)來解決這個(gè)問題煤痕。
謀權(quán)篡位的自動(dòng)版,能夠后臺(tái)監(jiān)控主機(jī)是否故障接谨,如果故障了根據(jù)投票數(shù)自動(dòng)將從庫轉(zhuǎn)換為主庫摆碉。
哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令脓豪,哨兵是一個(gè)獨(dú)立的進(jìn)程巷帝,作為進(jìn)程,它會(huì)獨(dú)立運(yùn)行扫夜。其原理是哨兵通過發(fā)送命令楞泼,等待Redis服務(wù)器響應(yīng),從而監(jiān)控運(yùn)行的多個(gè)Redis實(shí)例历谍。

1603443147793

這里的哨兵有兩個(gè)作用:

  • 通過發(fā)送命令现拒,讓Redis服務(wù)器返回監(jiān)控其運(yùn)行狀態(tài),包括主服務(wù)器和從服務(wù)器望侈。
  • 當(dāng)哨兵監(jiān)測到master宕機(jī)印蔬,會(huì)自動(dòng)將slave切換成master,然后通過發(fā)布訂閱模式通知其他的從服務(wù)器脱衙,修改配置文件侥猬,讓它們切換主機(jī)。
    然而一個(gè)哨兵進(jìn)程對Redis服務(wù)器進(jìn)行監(jiān)控捐韩,可能會(huì)出現(xiàn)問題退唠,為此,我們可以使用多個(gè)哨兵進(jìn)行監(jiān)控荤胁。各個(gè)哨兵之間還會(huì)進(jìn)行監(jiān)控瞧预,這樣就形成了多哨兵模式。
1603443611896

假設(shè)主服務(wù)器宕機(jī)仅政,哨兵1先檢測到這個(gè)結(jié)果垢油,系統(tǒng)并不會(huì)馬上進(jìn)failover過程,僅僅是哨兵1主觀的認(rèn)為主服務(wù)器不可用圆丹,這個(gè)現(xiàn)象成為主觀線滩愁。當(dāng)后面的哨兵也檢測到主服務(wù)器不可用,并且數(shù)量達(dá)到一定值時(shí)辫封,那么哨兵之間就會(huì)進(jìn)行一次投票硝枉,投票的結(jié)果由一個(gè)哨兵發(fā)起廉丽,進(jìn)行failover[故障轉(zhuǎn)移]操作。切換成功后妻味,就會(huì)通過發(fā)布訂閱模式正压,讓各個(gè)哨兵把自己監(jiān)控的從服務(wù)器實(shí)現(xiàn)切換主機(jī),這個(gè)過程稱為客觀下線弧可。

測試

一主二從

1蔑匣、配置哨兵配置文件==sentinel.conf==

#sentinel monitor 被監(jiān)控的主機(jī)名稱 host port 1
sentinel monitor myredis 127.0.0.1 6379 1

如果主從服務(wù)器設(shè)置密碼,需主從服務(wù)器密碼保持一致棕诵,否則哨兵機(jī)制會(huì)失敳昧肌!
sentinel auth-pass myredis 12345678 -主密碼校套,不設(shè)置的話不能動(dòng)態(tài)切換

數(shù)字 1 代表主機(jī)掛了价脾,哨兵投票讓從機(jī)接替成為主機(jī),票數(shù)最多的就會(huì)成為主機(jī)

2笛匙、啟動(dòng)哨兵

[root@deng bin]# redis-sentinel dconfig/sentinel.conf 
13323:X 23 Oct 2020 20:31:19.928 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
13323:X 23 Oct 2020 20:31:19.928 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=13323, just started
13323:X 23 Oct 2020 20:31:19.928 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.0.8 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 13323
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

13323:X 23 Oct 2020 20:31:19.929 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
13323:X 23 Oct 2020 20:31:19.929 # Sentinel ID is 010f244aef16ebf4f40798f0176a27a86c4e8c9d
13323:X 23 Oct 2020 20:31:19.929 # +monitor master myredis 127.0.0.1 6379 quorum 1
13323:X 23 Oct 2020 20:31:32.384 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
13323:X 23 Oct 2020 20:31:42.393 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

如果Master節(jié)點(diǎn)斷開了侨把,這個(gè)時(shí)候就會(huì)從從機(jī)中隨機(jī)選擇一個(gè)服務(wù)器(這里面有一個(gè)投票算法)

1603456721075

哨兵日志

1603456834711

如果主機(jī)此時(shí)回來了,只能歸并到新的主機(jī)下妹孙,當(dāng)做從機(jī)秋柄,這就是哨兵模式的規(guī)則

哨兵模式

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

1、哨兵集群蠢正,基于主從復(fù)制骇笔,所有主從配置的優(yōu)點(diǎn)它都有

2、主從可以切換嚣崭,故障可以轉(zhuǎn)移笨触,系統(tǒng)的可用性就會(huì)更好

3、哨兵模式就是主從復(fù)制的升級雹舀,手動(dòng)到自動(dòng)芦劣,更加健壯

缺點(diǎn):

1、Redis不好在線擴(kuò)容说榆,集群容量一旦到達(dá)上限虚吟,在線擴(kuò)容就十分麻煩

2、實(shí)現(xiàn)哨兵模式的配置其實(shí)較為麻煩签财,里面有很多選擇

哨兵模式的全部配置

# 配置端口,默認(rèn)26379
port 26379

# 以守護(hù)進(jìn)程模式啟動(dòng)
daemonize yes

# 日志文件名
logfile "sentinel_26379.log"

# 存放備份文件以及日志等文件的目錄
dir "/opt/redis/data"

# sentinel monitor <master-name> <master-ip> <master-port> <quorum>
# master-name 監(jiān)控主節(jié)點(diǎn)的名稱稍味,只能由字母A-z、0-9荠卷、.、-烛愧、_ 這些符號(hào)組成
# quorum 配置多少個(gè)sentinel哨兵同意認(rèn)為Master主節(jié)點(diǎn)失聯(lián)油宜,那么這時(shí)客觀上認(rèn)為主節(jié)點(diǎn)失聯(lián)了
sentinel monitor mymaster 192.168.14.101 6379 2

# sentinel down-after-milliseconds <master-name> <milliseconds>
# 30秒ping不通主節(jié)點(diǎn)的信息掂碱,主觀認(rèn)為master宕機(jī)
sentinel down-after-milliseconds mymaster 30000

# sentinel auth-pass <master-name> <password> 
# 當(dāng)在redis實(shí)例開啟了requirepass foobared 授權(quán)密碼,這樣所有連接redis的客戶端都要提供密碼慎冤,
# 設(shè)置哨兵連接主從的密碼疼燥,注意: 必須為主從設(shè)置一樣的密碼
sentinel auth-pass mymaster 123456

# sentinel parallel-syncs <master-name> <numslaves>
# 指定了在發(fā)生failover主備切換是最多可以有多少個(gè)slave同時(shí)對新的master進(jìn)行同步,
# 這個(gè)數(shù)字越小蚁堤,完成failover的時(shí)間越長醉者,但是數(shù)字越大,意味著越多的slave因?yàn)閞eplication不可用披诗,可以通過將這個(gè)值設(shè)為1撬即,來保證# # 每次只有一個(gè)slave處于不能處理命令請求的狀態(tài)
sentinel parallel-syncs mymaster 1

# 故障轉(zhuǎn)移開始,三分鐘內(nèi)沒有完成呈队,則認(rèn)為轉(zhuǎn)移失敗剥槐,默認(rèn)三分鐘
# sentinel failover-timeout <master-name> <milliseconds>
# 故障轉(zhuǎn)移的超時(shí)時(shí)間,可以用在以下方面
# 1宪摧、同一個(gè)sentinel對同一個(gè)master兩次failover之間的時(shí)間間隔粒竖;
# 2、當(dāng)一個(gè)slave從一個(gè)錯(cuò)誤的master那里同步數(shù)據(jù)開始計(jì)算時(shí)間几于,直到slave被糾正為向正確的master那里同步數(shù)據(jù)時(shí)間蕊苗;
# 3、當(dāng)想要取消一個(gè)正在進(jìn)行的failover所需要的時(shí)間沿彭;
# 4朽砰、當(dāng)failover時(shí),配置所有slaves指向新的master所需要的最大時(shí)間膝蜈,不過即使過了這個(gè)超時(shí)锅移,slaves依然會(huì)被正確配置為指向master,但是就不按parallel-syncs所配置的規(guī)則來了。
sentinel failover-timeout mymaster 180000

# sentinel notification-script <master-name> <script-path>
# 配置當(dāng)某一事件發(fā)生時(shí)所需要執(zhí)行的腳本饱搏,可以通過腳本來通知管理員非剃,例如當(dāng)系統(tǒng)運(yùn)行不正常時(shí),發(fā)送郵件通知相關(guān)人員
# 對于腳本的運(yùn)行結(jié)果有以下規(guī)則:
# 1推沸、若腳本返回1备绽,該腳本稍后將會(huì)被再次執(zhí)行,重復(fù)次數(shù)默認(rèn)為10鬓催;
# 2肺素、若腳本返回≥2,腳本將不會(huì)重復(fù)執(zhí)行宇驾;
# 3倍靡、如果腳本在執(zhí)行過程中收到系統(tǒng)終端信號(hào)被終止了蘸朋,則與返回值為1的行為相同邑茄;
# 4、一個(gè)腳本的最大執(zhí)行時(shí)間為60s,如果超過這個(gè)時(shí)間拷橘,腳本將會(huì)被一個(gè)叫SIGKILL信號(hào)終止途戒,之后重新執(zhí)行愈魏。

# 如通知型腳本:當(dāng)sentinel有任何告警幾倍的時(shí)間發(fā)生時(shí)(比如redis實(shí)例的主搭综、客觀失效等等),將會(huì)去調(diào)用這個(gè)腳本站辉,此時(shí)腳本將通過郵件等方式通知系統(tǒng)管理員呢撞,調(diào)用該腳本時(shí),將傳給腳本兩個(gè)參數(shù):一是時(shí)間類型饰剥,二是事件的描述殊霞。如果sentinel.conf配置文件配置了這個(gè)腳本路徑,那么必須保證這個(gè)腳本存在這個(gè)路徑捐川,并且是可執(zhí)行的脓鹃,否則sentinel無法正常啟動(dòng)成功。
sentinel notification-script mymaster /var/redis/notify.sh

# sentinel client-reconfig-script <master-name> <script-path>
# 客戶端重新配置主節(jié)點(diǎn)參數(shù)腳本古沥,當(dāng)一個(gè)master由于failover發(fā)生改變時(shí)瘸右,這個(gè)腳本將會(huì)被調(diào)用,通知相關(guān)的客戶端關(guān)于master地址已經(jīng)發(fā)生改變的信息
# 以下參數(shù)將會(huì)在調(diào)用腳本時(shí)傳給腳本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前state總是 failover
# role 是 leader 或者 observer 中的一個(gè)
# <from-ip> <from-port> <to-ip> <to-port> 是用來和舊的master 和新的 master(即舊的slave)通信的
# 具備通用信岩齿,多次調(diào)用
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

Redis緩存穿透和雪崩

Redis緩存的使用太颤,極大的提升了應(yīng)用程序的性能和效率,特別是數(shù)據(jù)查詢方面盹沈。但同時(shí)龄章,它也帶來了一些問題。其中乞封,最要害的問題做裙,就是數(shù)據(jù)的一致性問題,從嚴(yán)格意義上講肃晚,這個(gè)問題無解锚贱。如果對數(shù)據(jù)的一致性要求很高,那么就不能使用緩存关串。
另外的一些典型問題就是拧廊,緩存穿透、緩存雪崩和緩存擊穿晋修。目前吧碾,業(yè)界也都有比較流行的解決方案。

緩存穿透

概念

緩存穿透的概念很簡單墓卦,用戶想要查詢一個(gè)數(shù)據(jù)倦春,發(fā)現(xiàn)redis內(nèi)存數(shù)據(jù)庫沒有,也就是緩存沒有命中,于是向持久層數(shù)據(jù)庫查詢溅漾。發(fā)現(xiàn)也沒有山叮,于是本次查詢失敗。當(dāng)用戶很多的時(shí)候添履,緩存都沒有命中,于是都去請求了持久層數(shù)據(jù)庫脑又。這會(huì)給持久層數(shù)據(jù)庫造成很大的壓力,這時(shí)候就相當(dāng)于出現(xiàn)了緩存穿透席舍。

解決方案

1603459733324

緩存穿透

概念

緩存穿透的概念很簡單滑黔,用戶想要查詢一個(gè)數(shù)據(jù),發(fā)現(xiàn)redis內(nèi)存數(shù)據(jù)庫沒有,也就是緩存沒有命中『于是向持久層數(shù)據(jù)庫查詢璃氢。發(fā)現(xiàn)也沒有,于是本次查詢失敗层皱。當(dāng)用戶很多的時(shí)候草冈,緩存都沒有命中怎棱,于是都去請求了持久層數(shù)據(jù)庫。這會(huì)給持久層數(shù)據(jù)庫造成很大的壓力吩谦,這時(shí)候就相當(dāng)于出現(xiàn)了緩存穿透。

解決方案

布隆過濾器

布隆過濾器是一種數(shù)據(jù)結(jié)構(gòu)芭挽,對所有可能查詢的參數(shù)以hash形式存儲(chǔ)滑废,在控制層先進(jìn)行校驗(yàn),不符合則丟棄袜爪,從而避免了對底層存儲(chǔ)系統(tǒng)的查詢壓力

1603460407950

緩存空對象

當(dāng)存儲(chǔ)層不命中后蠕趁,即使返回的空對象也將其緩存起來,同時(shí)會(huì)設(shè)置一個(gè)過期時(shí)間辛馆,之后再訪問這個(gè)數(shù)據(jù)將會(huì)從緩存中獲取俺陋,保護(hù)了后端數(shù)據(jù)源;

1603460720640

但是這種方法會(huì)存在兩個(gè)問題:
1、如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲(chǔ)更多的鍵腊状,因?yàn)檫@當(dāng)中可能會(huì)有很多的空值的鍵;
2诱咏、即使對空值設(shè)置了過期時(shí)間,還是會(huì)存在緩存層和存儲(chǔ)層的數(shù)據(jù)會(huì)有一段時(shí)間窗口的不一致缴挖,這對于需要保持一致性的業(yè)務(wù)會(huì)有影響袋狞。

緩存擊穿

概述

這里需要注意和緩存擊穿的區(qū)別,緩存擊穿映屋,是指一個(gè)key非常熱點(diǎn)硕并,在不停的扛著大并發(fā),大并發(fā)集中對這一個(gè)點(diǎn)進(jìn)行訪問秧荆,當(dāng)這個(gè)key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存埃仪,直接請求數(shù)據(jù)庫乙濒,就像在一個(gè)屏障上鑿開了一個(gè)洞。
當(dāng)某個(gè)key在過期的瞬間卵蛉,有大量的請求并發(fā)訪問颁股,這類數(shù)據(jù)一般是熱點(diǎn)數(shù)據(jù),由于緩存過期傻丝,會(huì)同時(shí)訪問數(shù)據(jù)庫來查詢最新數(shù)據(jù)甘有,并且回寫緩存,會(huì)導(dǎo)使數(shù)據(jù)庫瞬間壓力過大葡缰。

解決方案

設(shè)置熱點(diǎn)數(shù)據(jù)永不過期

從緩存層面來看亏掀,沒有設(shè)置過期時(shí)間,所以不會(huì)出現(xiàn)熱點(diǎn) key過期后產(chǎn)生的問題泛释。

加互斥鎖

分布式鎖∶使用分布式鎖滤愕,保證對于每個(gè)key同時(shí)只有一個(gè)線程去查詢后端服務(wù),其他線程沒有獲得分布式鎖的權(quán)限怜校,因此只需要等待即可间影。這種方式將高并發(fā)的壓力轉(zhuǎn)移到了分布式鎖,因此對分布式鎖的考驗(yàn)很大茄茁。

緩存雪崩

概念

緩存雪崩魂贬,是指在某一個(gè)時(shí)間段,緩存集中過期失效裙顽。Redis宕機(jī)!
產(chǎn)生雪崩的原因之一付燥,比如在寫本文的時(shí)候,馬上就要到雙十二零點(diǎn)锦庸,很快就會(huì)迎來一波搶購机蔗,這波商品時(shí)間比較集中的放入了緩存邑茄,假設(shè)緩存一個(gè)小時(shí)。那么到了凌晨一點(diǎn)鐘的時(shí)候慨蛙,這批商品的緩存就都過期了瘪贱。而對這批商品的訪問查詢,都落到了數(shù)據(jù)庫上牙言,對于數(shù)據(jù)庫而言酸钦,就會(huì)產(chǎn)生周期性的壓力波峰。于是所有的請求都會(huì)達(dá)到存儲(chǔ)層咱枉,存儲(chǔ)層的調(diào)用量會(huì)暴增卑硫,造成存儲(chǔ)層也會(huì)掛掉的情況。

1603461219690

其實(shí)集中過期蚕断,倒不是非常致命欢伏,比較致命的緩存雪崩,是緩存服務(wù)器某個(gè)節(jié)點(diǎn)宕機(jī)或斷網(wǎng)亿乳。因?yàn)樽匀恍纬傻木彺嫜┍溃欢ㄊ窃谀硞€(gè)時(shí)間段集中創(chuàng)建緩存葛假,這個(gè)時(shí)候障陶,數(shù)據(jù)庫也是可以頂住壓力的。無非就是對數(shù)據(jù)庫產(chǎn)生周期性的壓力而已侄刽。而緩存服務(wù)節(jié)點(diǎn)的宕機(jī)所计,對數(shù)據(jù)庫服務(wù)器造成的壓力是不可預(yù)知的,很有可能瞬間就把數(shù)據(jù)庫壓垮团秽。

解決方案

reids高可用

這個(gè)思想的含義是主胧,既然redis有可能掛掉叭首,那我多增設(shè)幾臺(tái)redis ,這樣一臺(tái)掛掉之后其他的還可以繼續(xù)工作踪栋,其實(shí)就是搭建的集群焙格。

限流降級

這個(gè)解決方案的思想是,在緩存失效后夷都,通過加鎖或者隊(duì)列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量眷唉。比如對某個(gè)key只允許一個(gè)線程查詢數(shù)據(jù)和寫緩存,其他線程等待囤官。

數(shù)據(jù)預(yù)熱

數(shù)據(jù)加熱的含義就是在正式部署之前冬阳,我先把可能的數(shù)據(jù)先預(yù)先訪問一遍,這樣部分可能大量訪問的數(shù)據(jù)就會(huì)加載到緩存中党饮。在即將發(fā)生大并發(fā)訪問前手動(dòng)觸發(fā)加載緩存不同的key肝陪,設(shè)置不同的過期時(shí)間,讓緩存失效的時(shí)間點(diǎn)盡量均勻刑顺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末见坑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捏检,更是在濱河造成了極大的恐慌,老刑警劉巖不皆,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贯城,死亡現(xiàn)場離奇詭異,居然都是意外死亡霹娄,警方通過查閱死者的電腦和手機(jī)能犯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犬耻,“玉大人踩晶,你說我怎么就攤上這事≌泶牛” “怎么了渡蜻?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長计济。 經(jīng)常有香客問我茸苇,道長,這世上最難降的妖魔是什么沦寂? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任学密,我火速辦了婚禮,結(jié)果婚禮上传藏,老公的妹妹穿的比我還像新娘腻暮。我一直安慰自己彤守,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布哭靖。 她就那樣靜靜地躺著具垫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪款青。 梳的紋絲不亂的頭發(fā)上做修,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音抡草,去河邊找鬼饰及。 笑死,一個(gè)胖子當(dāng)著我的面吹牛康震,可吹牛的內(nèi)容都是我干的燎含。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼腿短,長吁一口氣:“原來是場噩夢啊……” “哼屏箍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橘忱,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赴魁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后钝诚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颖御,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年凝颇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了潘拱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拧略,死狀恐怖芦岂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情垫蛆,我是刑警寧澤禽最,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站袱饭,受9級特大地震影響弛随,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宁赤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一舀透、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧决左,春花似錦愕够、人聲如沸走贪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坠狡。三九已至,卻和暖如春遂跟,著一層夾襖步出監(jiān)牢的瞬間逃沿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工幻锁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凯亮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓哄尔,卻偏偏與公主長得像假消,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子岭接,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Redis基本介紹 Remote Dictionary Server 高性能key-value數(shù)據(jù)庫富拗,支持BSD協(xié)...
    crossyf閱讀 327評論 0 0
  • 操作系統(tǒng):CentOS-7.8redis版本:6.0.5 本篇錘子將和大家一起學(xué)習(xí)redis的基礎(chǔ)知識(shí),文章中只會(huì)...
    愛做夢的錘子閱讀 207評論 0 1
  • 1.redis注意點(diǎn) redis是單進(jìn)程的 默認(rèn)有16個(gè)數(shù)據(jù)庫鸣戴,編號(hào)為0-15 進(jìn)入相應(yīng)數(shù)據(jù)庫: 查看數(shù)據(jù)庫的ke...
    曦夫閱讀 664評論 0 3
  • 1. 數(shù)據(jù)類型 1.1.key Redis key值是二進(jìn)制安全的啃沪,這意味著可以用任何二進(jìn)制序列作為key值。 關(guān)...
    hgjsj閱讀 490評論 0 0
  • NoSQL入門 NoSQL概述 如今窄锅,大多數(shù)的計(jì)算機(jī)系統(tǒng)(包括服務(wù)器谅阿、PC、移動(dòng)設(shè)備等)都會(huì)產(chǎn)生龐大的數(shù)據(jù)量酬滤。其實(shí)...
    奔跑的_____閱讀 298評論 0 0