redis入門學習(比較全面)

一、 安裝

在centOs下安裝redis

首先需要安裝gcc依賴用於編譯解壓後的redis

就把gcc當成c語言編譯器, g++當成c++語言編譯器用就是了

yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake

下載redis壓縮包並且解壓編譯

$ wget http://download.redis.io/releases/redis-5.0.3.tar.gz
$ tar xzf redis-5.0.3.tar.gz
$ cd redis-5.0.3
$ make

這個時候redis已經安裝完成但是也可以使用一下命令將redis安裝到自定義的目錄中

make install PREFIX=/usr/redis

二、啓動Redis服務

使用默認的6379端口啓動

./bin/redis-server

使用指定端口啓動

  • 拷貝一份redis.conf
cp redis.conf /usr/redis/redis.conf
  • 修改啓動端口
vim /usr/redis/redis.conf
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 7000
  • 啓動redis
./bin/redis-server ./redis.conf

三、連接redis

連接默認端口

./bin/redis-cli

連接指定端口

./bin/redis-cli -p 7000

四、Redis中常用的與數據庫有關的指令

說明: 使用redis的默認配置器動redis服務後,默認會存在16個庫,編號從0-15
可以使用select 庫的編號 來選擇一個redis的庫

  • 清空當前的庫 FLUSHDB
  • 清空全部的庫 FLUSHALL

五、Redis中常用的與key相關的指令

1.DEL
語法 : DEL key [key …]
作用 : 刪除給定的一個或多個key 。不存在的key 會被忽略。
可用版本: >= 1.0.0
時間複雜度:
O(N),N 爲被刪除的key 的數量。
刪除單個字符串類型的key ,時間複雜度爲O(1)。
刪除單個列表、集合、有序集合或哈希表類型的key ,時間複雜度爲O(M),M爲以上數據結構內的元素數量。
返回值: 被刪除key 的數量。
2.EXISTS
語法: EXISTS key
作用: 檢查給定key 是否存在。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值: 若key 存在,返回1 ,否則返回0 。
3.EXPIRE
語法: EXPIRE key seconds
作用: 爲給定key 設置生存時間,當key 過期時(生存時間爲0 ),它會被自動刪除。
在Redis 中,帶有生存時間的key 被稱爲『易失的』(volatile)。生存時間可以通過使用DEL 命令來刪除整個key 來移除,或者被SET 和GETSET 命令覆寫(overwrite),
這意味着,如果一個命令只是修改(alter) 一個帶生存時間的key 的值而不是用一個新的key 值來代替(replace) 它的話,那麼生存時間不會被改變。
比如說,對一個key 執行INCR 命令,對一個列表進行LPUSH 命令,或者對一個哈希表執行HSET 命令,這類操作都不會修改key 本身的生存時間。
另一方面,如果使用RENAME 對一個key 進行改名,那麼改名後的key 的生存時間和改名前一樣。RENAME 命令的另一種可能是,嘗試將一個帶生存時間的key 改名成另一個帶生存時間的another_key這時舊的another_key (以及它的生存時間) 會被刪除,然後舊的key 會改名爲another_key ,因此,新的another_key 的生存時間也和原本的key 一樣。使用PERSIST 命令可以在不刪除key 的情況下,移除key 的生存時間,讓key 重新成爲一個『持久的』(persistent) key 。更新生存時間可以對一個已經帶有生存時間的key 執行EXPIRE 命令,新指定的生存時間會取代舊的生存時間。過期時間的精確度在Redis 2.4 版本中,過期時間的延遲在1 秒鐘之內——也即是,就算key 已經過期,但它還是可能在過期之後一秒鐘之內被訪問到,而在新的Redis 2.6 版本中,延遲被降低到1 毫秒之內。Redis 2.1.3 之前的不同之處
在Redis 2.1.3 之前的版本中,修改一個帶有生存時間的key 會導致整個key 被刪除,這一行爲是受當時複製(replication) 層的限制而作出的,現在這一限制已經被修復。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值:設置成功返回1 。
4.KEYS
語法 : KEYS pattern
作用 : 查找所有符合給定模式pattern 的key 。
KEYS * 匹配數據庫中所有key 。
KEYS h?llo 匹配hello ,hallo 和hxllo 等。
KEYS h*llo 匹配hllo 和heeeeello 等。
KEYS h[ae]llo 匹配hello 和hallo ,但不匹配hillo 。
特殊符號用 \ 隔開
注意: KEYS 的速度非常快,但在一個大的數據庫中使用它仍然可能造成性能問題,如果你需要從一個數據集中查找特定的key ,你最好還是用Redis 的集合結構(set) 來代替。
可用版本: >= 1.0.0
時間複雜度: O(N),N 爲數據庫中key 的數量。
返回值: 符合給定模式的key 列表。
5.MOVE
語法 : MOVE key db
作用 : 將當前數據庫的key 移動到給定的數據庫db 當中。
如果當前數據庫(源數據庫) 和給定數據庫(目標數據庫) 有相同名字的給定key ,或者key 不存在於當前數據庫,那麼MOVE 沒有任何效果。因此,也可以利用這一特性,將MOVE 當作鎖(locking) 原語(primitive)。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值: 移動成功返回1 ,失敗則返回0 。
6.PEXPIRE
語法 : PEXPIRE key milliseconds
作用 : 這個命令和EXPIRE 命令的作用類似,但是它以毫秒爲單位設置key 的生存時間,而不像EXPIRE 命令那樣,以秒爲單位。
可用版本: >= 2.6.0
時間複雜度: O(1)
返回值:設置成功,返回1 key 不存在或設置失敗,返回0
7.PEXPIREAT
語法 : PEXPIREAT key milliseconds-timestamp
作用 : 這個命令和EXPIREAT 命令類似,但它以毫秒爲單位設置key 的過期unix 時間戳,而不是像EXPIREAT那樣,以秒爲單位。
可用版本: >= 2.6.0
時間複雜度: O(1)
返回值:如果生存時間設置成功,返回1 。當key 不存在或沒辦法設置生存時間時,返回0 。(查看EXPIRE 命令獲取更多信息)
8.TTL
語法 : TTL key
作用 : 以秒爲單位,返回給定key 的剩餘生存時間(TTL, time to live)。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值:
當key 不存在時,返回-2 。
當key 存在但沒有設置剩餘生存時間時,返回-1 。
否則,以秒爲單位,返回key 的剩餘生存時間。
Note : 在Redis 2.8 以前,當key 不存在,或者key 沒有設置剩餘生存時間時,命令都返回-1 。
9.PTTL
語法 : PTTL key
作用 : 這個命令類似於TTL 命令,但它以毫秒爲單位返回key 的剩餘生存時間,而不是像TTL 命令那樣,以秒爲單位。
可用版本: >= 2.6.0
複雜度: O(1)
返回值: 當key 不存在時,返回-2 。當key 存在但沒有設置剩餘生存時間時,返回-1 。
否則,以毫秒爲單位,返回key 的剩餘生存時間。
注意 : 在Redis 2.8 以前,當key 不存在,或者key 沒有設置剩餘生存時間時,命令都返回-1 。
10.RANDOMKEY
語法 : RANDOMKEY
作用 : 從當前數據庫中隨機返回(不刪除) 一個key 。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值:當數據庫不爲空時,返回一個key 。當數據庫爲空時,返回nil 。
11.RENAME
語法 : RENAME key newkey
作用 : 將key 改名爲newkey 。當key 和newkey 相同,或者key 不存在時,返回一個錯誤。當newkey 已經存在時,RENAME 命令將覆蓋舊值。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值: 改名成功時提示OK ,失敗時候返回一個錯誤。
12.TYPE
語法 : TYPE key
作用 : 返回key 所儲存的值的類型。
可用版本: >= 1.0.0
時間複雜度: O(1)
返回值:
none (key 不存在)
string (字符串)
list (列表)
set (集合)
zset (有序集)
hash (哈希表)

六、Redis的數據類型

Redis的String類型的數據操作

命令 說明
set 設置一個key/value
get 根據key獲得對應的value
mset 一次設置多個key value
mget 一次獲得多個key的value
getset 獲得原始key的值,同時設置新值
strlen 獲得對應key存儲value的長度
append 爲對應key的value追加內容
getrange 截取value的內容
setex 設置一個key存活的有效期(秒)
psetex 設置一個key存活的有效期(毫秒)
setnx 存在不做任何操作,不存在添加
msetnx 可以同時設置多個key,只有有一個存在都不保存
decr 進行數值類型的-1操作
decrby 根據提供的數據進行減法操作
Incr 進行數值類型的+1操作
incrby 根據提供的數據進行加法操作
Incrbyfloat 根據提供的數據加入浮點數

Redis的List類型的操作

  • 數據結構圖
    在這裏插入圖片描述
命令 說明
lpush 將某個值加入到一個key列表頭部
lpushx 同lpush,但是必須要保證這個key存在
rpush 將某個值加入到一個key列表末尾
rpushx 同rpush,但是必須要保證這個key存在
lpop 返回和移除列表的第一個元素
rpop 返回和移除列表的第一個元素
lrange 獲取某一個下標區間內的元素
llen 獲取列表元素個數
lset 設置某一個指定索引的值(索引必須存在)
lindex 獲取某一個指定索引位置的元素
lrem 刪除重複元素
ltrim 保留列表中特定區間內的元素
linsert 在某一個元素之前,之後插入新元素
  • 舉例
#創建並且加入"zhangsan"到列表中
$ LPUSH name zhangsan
(integer) 1
#查看name類型
$ type name
list
#查看list列表的長度
$ llen name
(integer) 2
#在lisi元素之前插入wangwu
$ LINSERT name BEFORE lisi wangwu
(integer) 3
#查看索引爲0-2的元素
$ LRANGE name 0 2
1) "wangwu"
2) "lisi"
3) "zhangsan"

Redis的SET類型的操作

  • 數據結構圖
    在這裏插入圖片描述
命令 說明
sadd 爲集合添加元素
smembers 顯示集合中所有元素 無序
scard 返回集合中元素的個數
spop 隨機返回一個元素
smove 從一個集合中向另一個集合移動元素
srem 從集合中刪除一個元素
sismember 判斷一個集合中是否含有這個元素
srandmember 隨機返回元素
sdiff 去掉第一個集合中其它集合含有的相同元素
sinter 求交集
sunion 求和集
  • 舉例
#創建一個set並加入“flag1”
SADD myset flag1
(integer) 1
SADD myset flag2
(integer) 1
 SADD myset flag3
(integer) 1
#顯示集合中所有元素 無序
SMEMBERS myset
1) "flag1"
2) "flag3"
3) "flag2"
(integer) 1
#求和集
SUNION set myset  myset2
1) "flag2"
2) "flag3"
3) "flag4"
4) "flag1"
5) "flag6"
6) "flag5"
#判斷一個集合中是否含有這個元素
SISMEMBER myset flag1
(integer) 1
 SISMEMBER myset flag7
(integer) 0

Redis的ZSET類型的操作 sortset

數據結構
在這裏插入圖片描述

命令 說明
zadd 添加一個有序集合元素
zcard 返回集合的元素個數
zrange 返回一個範圍內的元素
zrangebyscore 按照分數查找一個範圍內的元素
zrank 返回排名
zrevrank 倒序排名
zscore 顯示某一個元素的分數
zrem 移除某一個元素
zincrby 給某個特定元素加分

舉例

 ZADD myset 1.00 flag1
(integer) 1
ZADD myset 2.00 flag2
(integer) 1
 ZADD myset 3.00 flag3
(integer) 1
 keys myset
1) "myset"
 type myset
zset
 ZRANGE myset 1 2
1) "flag2"
2) "flag3"
ZRANGE myset 1 3
1) "flag2"
2) "flag3"
 ZREVRANGE myset 1 3
1) "flag2"
2) "flag1"
127.0.0.1:6379> ZREVRANGE myset 0 3
1) "flag3"
2) "flag2"
3) "flag1"
127.0.0.1:6379> ZINCRBY myset 0.1 flag1
"1.1000000000000001"

Redis的HASH類型的操作

數據結構
在這裏插入圖片描述

命令 說明
hset 設置一個key/value對
hget 獲得一個key對應的value
hgetall 獲得所有的key/value對
hdel 刪除某一個key/value對
hexists 判斷一個key是否存在
hkeys 獲得所有的key
hvals 獲得所有的value
hmset 設置多個key/value
hmget 獲得多個key的value
hsetnx 設置一個不存在的key的值
hincrby 爲value進行加法運算
hincrbyfloat 爲value加入浮點值

舉例

127.0.0.1:6379> HSET myhash name zhangsan
(integer) 1
127.0.0.1:6379> HSET myhash age 12
(integer) 1
127.0.0.1:6379> HSET myhash sex 男
(integer) 1
127.0.0.1:6379> HSET myhash class 110
(integer) 1
127.0.0.1:6379> hget myhash class
"110"
127.0.0.1:6379> hget myhash sex
"\xe7\x94\xb7"
127.0.0.1:6379> hdel myhash sex
(integer) 1
127.0.0.1:6379> hkeys myhash
1) "name"
2) "age"
3) "class"
127.0.0.1:6379> hmset myhash number 6666 score 100
OK
127.0.0.1:6379> hkeys myhash
1) "name"
2) "age"
3) "class"
4) "number"
5) "score"
127.0.0.1:6379> hmget myhash age name class
1) "12"
2) "zhangsan"
3) "110"
127.0.0.1:6379> HINCRBY myhash class 15
(integer) 125
127.0.0.1:6379> hset myhash floatfiled 12.36
(integer) 1
127.0.0.1:6379> hincrbyfloat floatfiled 12.36 12.56
"12.56"
127.0.0.1:6379> HVALS myhash
1) "zhangsan"
2) "12"
3) "125"
4) "6666"
5) "100"
6) "12.36"

七、Redis中的持久化機制

Redis提供了兩種不同的持久化方法來將數據存儲到硬盤裏面

快照(snapshotting)

這種方式可以將某一時刻的所有數據都寫入硬盤中,當然這也是redis的默認持久化方式,保存的文件是以.rdb形式結尾的文件因此這種方式也稱之爲RDB方式

快照持久化也是redis中的默認開啓的持久化方案, 根據redis.conf中的配置,快照將被寫入dbfilename指定的文件裏面(默認是dump.rdb文件中)

# The filename where to dump the DB
dbfilename dump.rdb

根據redis.conf中的配置,快照將保存在dir選項指定的路徑上

# Note that you must specify a directory here, not a file name.
dir ./

創建快照的幾種方式

  • 客戶端可以使用BGSAVE命令來創建一個快照,當接收到客戶端的BGSAVE命令時,redis會調用fork( fork當一個進程創建子進程的時候,底層的操作系統會創建該進程的一個副本,在類unix系統中創建子進程的操作會進行優化:在剛開始的時候,父子進程共享相同內存,直到父進程或子進程對內存進行了寫之後,對被寫入的內存的共享纔會結束服務)來創建一個子進程,然後子進程負責將快照寫入磁盤中,而父進程則繼續處理命令請求

  • 客戶端還可以使用SAVE命令來創建一個快照,接收到SAVE命令的redis服務器在快照創建完畢之前將不再響應任何其他的命令

注意 : SAVE命令並不常用,使用SAVE命令在快照創建完畢之前,redis處於阻塞狀態,無法對外服務

  • 如果用戶在redis.conf中設置了save配置選項,redis會在save選項條件滿足之後自動觸發一次BGSAVE命令,如果設置多個save配置選項,當任意一個save配置選項條件滿足,redis也save

會觸發一次BGSAVE命令配置選項

save 900 1//自上次成功保存起,如果在900秒內已經發生1次寫入觸發BGSAVE
save 300 10//自上次成功保存起,如果在300秒內已經發生10次寫入觸發BGSAVE
save 60 10000//自上次成功保存起,如果在60秒內已經發生10,000次寫入觸發BGSAVE
  • 當redis通過shutdown指令接收到關閉服務器的請求時,會執行一個save命令,阻塞所有的客戶端,不再執行客戶端執行發送的任何命令,並且在save命令執行完畢之後關閉服務器

AOF(append only file)只追加文件

這種方式可以將所有客戶端執行的寫命令記錄到日誌文件中

AOF持久化機制

在redis的默認配置中AOF持久化機制 是沒有開啓的,AOF持久化會將被執行的寫命令寫到AOF的文件末尾,以此來記錄數據發生的變化,因此只要redis從頭到尾執行一次AOF文件所包含的所有寫命令,就可以恢復AOF文件的記錄的數據集.

開啓AOF持久化機制,需要修改redis.conf的配置文件,

  • 通過修改redis.conf配置中appendonly yes來開啓AOF持久化
# Please check http://redis.io/topics/persistence for more information.
appendonly no
  • 通過appendfilename指定日誌文件名字(默認爲:appendonly.aof)
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
  • 通過appendfsync指定日誌記錄頻率
# If unsure, use "everysec".
# appendfsync always //總是同步
appendfsync everysec//每秒同步一次
# appendfsync no//不開啓同步

AOF 日誌記錄頻率的選項
可選項

選項 同步頻率
always 每個redis寫命令都要同步寫入硬盤,嚴重降低redis速度
everysec 每秒執行一次同步顯式的將多個寫命令同步到磁盤
no 由操作系統決定何時同步
  • 三種日誌記錄頻率的詳細分析 :

1、如果用戶使用了always選項,那麼每個redis寫命令都會被寫入硬盤,從而將發生系統崩潰時出現的數據丟失減到最少;遺憾的是,因爲這種同步策略需要對硬盤進行大量的寫入操作,所以redis處理命令的速度會受到硬盤性能的限制;
注意 : 轉盤式硬盤在這種頻率下200左右個命令/s ; 固態硬盤(SSD) 幾百萬個命令/s;
警告 : 使用SSD用戶請謹慎使用always選項,這種模式不斷寫入少量數據的做法有可能會引發嚴重的寫入放大問題,導致將固態硬盤的壽命從原來的幾年降低爲幾個月

2、爲了兼顧數據安全和寫入性能,用戶可以考慮使用everysec選項,讓redis每秒一次的頻率對AOF文件進行同步;redis每秒同步一次AOF文件時性能和不使用任何持久化特性時的性能相差無幾,而通過每秒同步一次AOF文件,redis可以保證,即使系統崩潰,用戶最多丟失一秒之內產生的數據(推薦使用這種方式)

3、最後使用no選項,將完全有操作系統決定什麼時候同步AOF日誌文件,這個選項不會對redis性能帶來影響但是系統崩潰時,會丟失不定數量的數據

另外如果用戶硬盤處理寫入操作不夠快的話,當緩衝區被等待寫入硬盤數據填滿時,redis會處於阻塞狀態,並導致redis的處理命令請求的速度變慢(不推薦使用)

AOF文件的重寫

aof 的方式也同時帶來了另一個問題。持久化文件會變的越來越大。例如我們調用incr test命令100次,文件中必須保存全部的100條命令,其實有99條都是多餘的。因爲要恢復數據庫的狀態其實文件中保存一條set test 100就夠了。爲了壓縮aof的持久化文件Redis提供了AOF重寫機制

重寫 aof 文件的兩種方式

執行BGREWRITEAOF命令

配置redis.conf中的auto-aof-rewrite-percentage選項

BGREWRITEAOF 方式

收到此命令redis將使用與快照類似的方式將內存中的數據 以命令的方式保存到臨時文件中,最後替換原來的文件。具體過程如下

redis調用fork ,現在有父子兩個進程子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令

父進程繼續處理client請求,除了把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就能保證如果子進程重寫失敗的話並不會出問題。

當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程。然後父進程把緩存的寫命令也寫入到臨時文件。

現在父進程可以使用臨時文件替換老的aof文件,並重命名,後面收到的寫命令也開始往新的aof文件中追加。

注意 :
重寫aof文件的操作,並沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,替換原有的文件這點和快照有點類似。(AOF重寫過程完成後會刪除舊的AOF文件,刪除一個體積達幾十GB大的舊的AOF文件可能會導致系統隨時掛起
)

配置redis.conf中的auto-aof-rewrite-percentage選項

AOF重寫也可以使用auto-aof-rewrite-percentage 100
和auto-aof-rewrite-min-size 64mb來自動執行BGREWRITEAOF.

說明: 如果設置auto-aof-rewrite-percentage值爲100和auto-aof-rewrite-min-size
64mb,並且啓用的AOF持久化時,那麼當AOF文件體積大於64M,並且AOF文件的體積比上一次重寫之後體積大了至少一倍(100%)時,會自動觸發,如果重寫過於頻繁,用戶可以考慮將auto-aof-rewrite-percentage設置爲更大

兩種持久化方案的總結

AOF持久化既可以將丟失的數據的時間降低到1秒(甚至不丟失任何數據),那麼我們還有什麼理由不是用AOF呢?

注意 :
這個問題實際上並沒有這麼簡單,因爲redis會不斷將執行的寫命令記錄到AOF文件中,所以隨着redis運行,AOF文件的體積會不斷增大,在極端情況下甚至會用完整個硬盤,還有redis重啓重新執行AOF文件記錄的所有寫命令的來還原數據集,AOF文件體積非常大,會導致redis執行恢復時間過長

兩種持久化方案既可以同時使用,又可以單獨使用,在某種情況下也可以都不使用,具體使用那種持久化方案取決於用戶的數據和應用決定

無論使用AOF還是快照機制持久化,將數據持久化到硬盤都是有必要的,除了持久化外,用戶還應該對持久化的文件進行備份(最好備份在多個不同地方)

後續補充

八、Java API 調用Redis

  • 在項目中導入redis的驅動jar jedis的jar包即可
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
  • jdeis常用API測試

注意有些版本的redis默認開啓了保護模式,直接連接會報JedisDataException異常
需要在連接端輸入config set protected-mode "no"來關閉保護模式

測試代碼

public class TestJavaClientRedis {
    public static void main(String[] args) {
        //創建jedis對象
        Jedis jedis = new Jedis("192.168.211.128", 6379);
        //選擇要連接的數據庫(默認16個庫索引爲0-15)
        jedis.select(0);
        //創建一個key-value
        jedis.set("String","first");
        //創建一個list
        jedis.lpush("list","list1");
        //獲取list的指定範圍內的value
        List<String> list = jedis.lrange("list", 0, 1);
         //創建一個hash
        Map<String, String> map = new HashMap<>();
        map.put("name","zhangsan");
        map.put("age","12");
        map.put("class","110");
        jedis.hmset("map",map);
        //獲取所有的hash元素
        Map<String, String> map1 = jedis.hgetAll("map");
        for (Map.Entry<String,String> entry: map1.entrySet()) {
            System.out.println(entry);
        }     
    }
}

這裏只是簡單的測試一下,jedis常用API

九、Redis的集羣搭建

十、集羣節點的操作

十一、Spring-data操作Redis

十二、redis做緩存

十三、redis做消息隊列

十四、redis做分佈式鎖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章