天天看點

redis系列--你真的入門了嗎?redis4.0入門~

前言

redis作為nosql家族中非常熱門的一員,也是被大型網際網路公司所青睐,無論你是開發、測試或者運維,學習掌握它總會為你的職業生涯增色添彩。

當然,你或多或少已經了解redis,但是你是否了解其中的某些細節,本片文章将詳細介紹redis基礎,後續也會介紹其進階部分如、持久化、複制、叢集等内容,希望對你有所幫助。

自redis3.0釋出已經3年了,redis目前官方提供的redis穩定版本是4.0,以下示例均在4.0版本上進行。

一、redis簡介

概述

redis(REmote DIctionary Server)是一個由Salvatore Sanfilippo寫key-value存儲系統,它由C語言編寫、遵守BSD協定、支援網絡、可基于記憶體亦可持久化的日志型、Key-Value類型的資料庫,并提供多種語言的API。和Memcached類似,它支援存儲的value類型相對更多,包括string(字元串)、list(連結清單)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些資料類型都支援push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支援各種不同方式的排序。與memcached一樣,為了保證效率,資料都是緩存在記憶體中。差別的是redis會周期性的把更新的資料寫入磁盤或者把修改操作寫入追加的記錄檔案,并且在此基礎上實作了master-slave(主從)同步,redis在3.0版本推出叢集模式。

特點、優勢

  • k、v鍵值存儲以及資料結構存儲(如清單、字典)
  • 所有資料(包括資料的存儲)操作均在記憶體中完成
  • 單線程服務(這意味着會有較多的阻塞情況),采用epoll模型進行請求響應,對比nginx
  • 支援主從複制模式,更提供高可用主從複制模式(哨兵)
  • 去中心化分布式叢集
  • 豐富的程式設計接口支援,如Python、Golang、Java、php、Ruby、Lua、Node.js 
  • 功能豐富,除了支援多種資料結構之外,還支援事務、釋出/訂閱、消息隊列等功能
  • 支援資料持久化(AOF、RDB)

對比memcache

  • memcache是一個分布式的記憶體對象緩存系統,并不提供持久存儲功能,而redis擁有持久化功能
  • memcache資料存儲基于LRU(簡單說:最近、最少使用key會被剔除),而redis則可以永久儲存(服務一直運作情況下)
  • memcache是多線程的(這是memcache優勢之一),也就意味着阻塞情況少,而redis是單線程的,阻塞情況相對較多
  • 兩者性能上相差不大
  • memcache隻支援簡單的k、v資料存儲,而redis支援多種資料格式存儲。
  • memcache是多線程、非阻塞IO複用網絡模型,而redis是單線程IO複用模型

二、開始

源碼部署

yum install gcc -y  #安裝C依賴
wget http://download.redis.io/redis-stable.tar.gz  #下載下傳穩定版本
tar zxvf redis-stable.tar.gz  #解壓
cd redis-stable
make PREFIX=/opt/app/redis install   #指定目錄編譯,也可以不用指定
make install
mkdir /etc/redis   #建立配置目錄
cp redis.conf /etc/redis/6379.conf # 拷貝配置檔案
cp utils/redis_init_script /etc/init.d/redis  #拷貝init啟動腳本針對6.X系統
chmod a+x  /etc/init.d/redis  #添加執行權限
vi /etc/redis/6379.conf #修改配置檔案: 
bind 0.0.0.0      #監聽位址
maxmemory 4294967296   #限制最大記憶體(4G):
daemonize yes   #背景運作

####啟動與停止
/etc/init.d/redis start
/etc/init.d/redis stop      

檢視是否成功安裝

#執行用戶端工具
redis-cli 
#輸入指令info
127.0.0.1:6379> info
# Server
redis_version:4.0.10
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:cf83e9c690dbed33
redis_mode:standalone
os:Linux 2.6.32-642.el6.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll      

二進制檔案說明

redis安裝完成後會有以下可執行檔案(window下是exe檔案)生成,下面是各個檔案的作用。

redis-server       #Redis伺服器和Sentinel伺服器,啟動時候可使用--sentinel指定為哨兵
redis-cli         #Redis指令行用戶端 
redis-benchmark      #Redis性能測試工具 
redis-check-aof      #AOF檔案修複工具 
redis-check-dump     #RDB檔案檢測工具 
redis-sentinel       #Sentinel伺服器,4.0版本已經做了軟連結到redis-server      

三、配置詳解

redis所有的配置參數都可以通過用戶端通過“CONFIG GET 參數名” 擷取,參數名支援通配符,如*代表所有。所得結果并按照順序分組,第一個傳回結果是參數名,第二個結果是參數對應的值。

redis系列--你真的入門了嗎?redis4.0入門~

除了檢視配置還可以使用CONFIG SET修改配置,寫入配置檔案使用CONFIG REWRITE,使用時是需要注意某些關于服務配置參數慎重修改,如bind。

redis系列--你真的入門了嗎?redis4.0入門~

配置參數以及解釋,需要注意的是,有些配置是4.0.10新增的,有些配置已經廢除,如vm相關配置,和叢集相關配置在叢集篇章在進行補充。

logfile
#日志檔案位置及檔案名稱

bind 0.0.0.0
#監聽位址,可以有多個 如bind 0.0.0.0 127.0.0.1

daemonize yes
#yes啟動守護程序運作,即背景運作,no表示不啟用

pidfile /var/run/redis.pid 
# 當redis在背景運作的時候,Redis預設會把pid檔案在在/var/run/redis.pid,也可以配置到其他地方。
# 當運作多個redis服務時,需要指定不同的pid檔案和端口

port 6379
# 指定redis運作的端口,預設是6379

unixsocket 
#sock檔案位置

unixsocketperm
#sock檔案權限

timeout 0
# 設定用戶端連接配接時的逾時時間,機關為秒。當用戶端在這段時間内沒有發出任何指令,那麼關閉該連接配接, 0是關閉此設定

loglevel debug
# 指定日志記錄級别,Redis總共支援四個級别:debug、verbose、notice、warning,預設為verbose

logfile ""
# 日志檔案配置,預設值為stdout,标準輸出,若背景模式會輸出到/dev/null

syslog-enabled
# 是否以syslog方式記錄日志,yes開啟no禁用,與該配置相關配置syslog-ident 和syslog-facility local0 分别是指明syslog的ident和facility

databases 16
#配置可用的資料庫個數,預設值為16,預設資料庫為0,資料庫範圍在0-(database-1)之間

always-show-logo yes #4.0以後新增配置
#是否配置日志顯示redis徽标,yes顯示no不顯示


################################ 快照相關配置 #################################

save 900 1
save 300 10
save 60 10000
#配置快照(rdb)促發規則,格式:save <seconds> <changes>
#save 900 1  900秒内至少有1個key被改變則做一次快照
#save 300 10  300秒内至少有300個key被改變則做一次快照
#save 60 10000  60秒内至少有10000個key被改變則做一次快照

dbfilename  dump.rdb
#rdb持久化存儲資料庫檔案名,預設為dump.rdb

stop-write-on-bgsave-error yes 
#yes代表當使用bgsave指令持久化出錯時候停止寫RDB快照檔案,no則代表繼續寫

rdbchecksum yes
#開啟rdb檔案校驗

dir "/etc"
#資料檔案存放目錄,rdb快照檔案和aof檔案都會存放至該目錄


################################# 複制相關配置參數 #################################

slaveof <masterip> <masterport>  
#設定該資料庫為其他資料庫的從資料庫,設定當本機為slave服務時,設定master服務的IP位址及端口,在Redis啟動時,它會自動從master進行資料同步

masterauth <master-password>
#主從複制中,設定連接配接master伺服器的密碼(前提master啟用了認證)

slave-serve-stale-data yes
# 當從庫同主機失去連接配接或者複制正在進行,從機庫有兩種運作方式:
# 1) 如果slave-serve-stale-data設定為yes(預設設定),從庫會繼續相應用戶端的請求
# 2) 如果slave-serve-stale-data是指為no,除了INFO和SLAVOF指令之外的任何請求都會傳回一個錯誤"SYNC with master in progress"

repl-ping-slave-period 10
#從庫會按照一個時間間隔向主庫發送PING指令來判斷主伺服器是否線上,預設是10秒

repl-timeout 60
#設定主庫批量資料傳輸時間或者ping回複時間間隔逾時時間,預設值是60秒
# 一定要確定repl-timeout大于repl-ping-slave-period

repl-backlog-size 1mb
#設定複制積壓大小,隻有當至少有一個從庫連入才會釋放。

slave-priority 100
#當主庫發生當機時候,哨兵會選擇優先級最高的一個稱為主庫,從庫優先級配置預設100,數值越小優先級越高

min-slaves-to-write 3
min-slaves-max-lag 10
#設定某個時間斷内,如果從庫數量小于該某個值則不允許主機進行寫操作,以上參數表示10秒内如果主庫的從節點小于3個,則主庫不接受寫請求,min-slaves-to-write 0代表關閉此功能。


################################## 安全相關配置 ###################################

requirepass
#用戶端連接配接認證的密碼,預設為空,即不需要密碼,若配置則指令行使用AUTH進行認證

maxclients 10000
# 設定同一時間最大用戶端連接配接數,4.0預設10000,Redis可以同時打開的用戶端連接配接數為Redis程序可以打開的最大檔案描述符數,
# 如果設定 maxclients 0,表示不作限制。
# 當用戶端連接配接數到達限制時,Redis會關閉新的連接配接并向用戶端傳回max number of clients reached錯誤資訊

maxmemory 4gb
#設定最大使用的記憶體大小

maxmemory-policy noeviction
#設定達到最大記憶體采取的政策:
# volatile-lru -> 利用LRU算法移除設定過過期時間的key (LRU:最近使用 Least Recently Used )
# allkeys-lru -> 利用LRU算法移除任何key
# volatile-random -> 移除設定過過期時間的随機key
# allkeys->random -> remove a random key, any key
# volatile-ttl -> 移除即将過期的key(minor TTL)
# 4.0預設noeviction代表不删除任何key,隻在寫操作時候傳回錯誤。

maxmemory-samples 5
#LRU,LFU等算法樣本設定,預設5個key


############################## AOF相關配置###############################

appendonly no
# 設定AOF持久化,yes開啟,no禁用,開啟後redis會把所接收到的每一次寫操作請求都追加到appendonly.aof檔案中,當redis重新啟動時,會從該檔案恢複出之前的狀态。
# 但是這樣會造成appendonly.aof檔案過大,是以redis還支援了BGREWRITEAOF指令,對appendonly.aof 進行重寫。

appendfilename "appendonly.aof"
#設定AOF檔案名

appendfsync everysec
# AOF檔案寫政策,Redis支援三種同步AOF檔案的政策:
# no: 不進行同步,交給作業系統去執行 ,速度較快
# always: always表示每次有寫操作都調用fsync方法強制核心将該寫操作寫入到檔案,速度會慢, 但是安全,因為每次寫操作都在AOF檔案中.
# everysec: 表示對寫操作進行累積,每秒同步一次,折中方案.
# 預設是"everysec",按照速度和安全折中這是最好的。

no-appendfsync-on-rewrite no
# AOF政策設定為always或者everysec時,背景處理程序(背景儲存或者AOF日志重寫)會執行大量的I/O操作
# 在某些Linux配置中會阻止過長的fsync()請求。注意現在沒有任何修複,即使fsync在另外一個線程進行處理,為了減緩這個問題,可以設定下面這個參數no-appendfsync-on-rewrite

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
#當AOF檔案增長到一定大小的時候Redis能夠調用BGREWRITEAOF對日志檔案進行重寫,它是這樣工作的:Redis會記住上次進行些日志後檔案的大小(如果從開機以來還沒進行過重寫,那日子大小在開機的時候确定)。
#基礎大小會同現在的大小進行比較。如果現在的大小比基礎大小大制定的百分比,重寫功能将啟動
# 同時需要指定一個最小大小用于AOF重寫,這個用于阻止即使檔案很小但是增長幅度很大也去重寫AOF檔案的情況
# 設定 percentage 為0就關閉這個特性
#auto-aof-rewrite-percentage 代表AOF檔案每次重寫檔案大小(以百分數代表),100表示百分之百,即當檔案增加了1倍(100%),則開始重寫AOF檔案
#auto-aof-rewrite-min-size  設定最小重寫檔案大小,避免檔案小而執行太多次的重寫

aof-load-truncated yes
#當redis突然運作崩潰時,會出現aof檔案被截斷的情況,Redis可以在發生這種情況時退出并加載錯誤,以下選項控制此行為。
#如果aof-load-truncated設定為yes,則加載截斷的AOF檔案,Redis伺服器啟動發出日志以通知使用者該事件。
#否則,如果該選項設定為no,則伺服器将中止并顯示錯誤并停止啟動。當該選項設定為no時,使用者需要在重新開機之前使用“redis-check-aof”實用程式修複AOF檔案在進行重新開機


################################## 慢查詢配置 ###################################


slowlog-log-slower-than 10000
 #Redis Slow Log 記錄超過特定執行時間的指令。執行時間不包括I/O計算比如連接配接用戶端,傳回結果等,隻是指令執行時間,可以通過兩個參數設定slow log:一個是告訴Redis執行超過多少時間被記錄的參數slowlog-log-slower-than(微秒,是以1000000代表一分鐘
#另一個是slow log 的長度。當一個新指令被記錄的時候最早的指令将被從隊列中移除
 
slowlog-max-len 128
#慢查詢指令記錄隊列長度設定,該隊列占用記憶體,可以使用SLOWLOG RESET清空隊列



############################### 進階配置 ###############################

hash-max-zipmap-entries 512
hash-max-zipmap-value 64
# 當hash中包含超過指定元素個數并且最大的元素沒有超過臨界時,hash将以一種特殊的編碼方式(大大減少記憶體使用)來存儲,這裡可以設定這兩個臨界值
# Redis Hash對應Value内部實際就是一個HashMap,實際這裡會有2種不同實作,
# 這個Hash的成員比較少時Redis為了節省記憶體會采用類似一維數組的方式來緊湊存儲,而不會采用真正的HashMap結構,對應的value redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding為ht。

list-max-ziplist-size -2
#Lists也以特殊方式編碼,以節省大量空間。
#可以指定每個内部清單節點允許的條目數
#作為固定的最大大小或最大元素數。
#對于固定的最大大小,使用-5到-1表示:
#-5:最大大小:64 Kb < - 不建議用于正常工作負載
#-4:最大尺寸:32 Kb < - 不推薦
#-3:最大尺寸:16 Kb < - 可能不推薦
#-2:最大尺寸:8 Kb < - 好
#-1:最大尺寸:4 Kb < - 良好
#正數意味着存儲_exactly_元素數量
#每個清單節點。
#性能最高的選項通常為-2(8 Kb大小)或-1(4 Kb大小)

zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# list資料類型多少節點以下會采用去指針的緊湊存儲格式。
# list資料類型節點值大小小于多少位元組會采用緊湊存儲格式。

activerehashing yes
# Redis将在每100毫秒時使用1毫秒的CPU時間來對redis的hash表進行重新hash,可以降低記憶體的使用
# 當你的使用場景中,有非常嚴格的實時性需要,不能夠接受Redis時不時的對請求有2毫秒的延遲的話,把這項配置為no。
# 如果沒有這麼嚴格的實時性要求,可以設定為yes,以便能夠盡可能快的釋放記憶體

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
#用戶端輸出緩沖區限制可用于強制斷開用戶端,由于某種原因,沒有足夠快地從伺服器讀取資料,常見的原因是Pub / Sub用戶端不能像很快的消費一條消息,可以為三種不同類型的用戶端設定不同的限制:
#normal - >普通用戶端,包括MONITOR用戶端
#subve - >從伺服器用戶端
#pubsub - >用戶端訂閱了至少一個pubsub通道或模式
#設定方法:client-output-buffer-limit 軟限制大小 硬限制大小 秒數
#當用戶端達到硬限制大小則立即斷開連接配接,當用戶端達到軟限制時候并且在設定的秒數緩沖大小任然超了,則在設定的秒數後斷開連接配接      

四、資料類型以及相關操作

通常使用redis不外乎使用其常用的5中資料類型:string、list、hash、set、sorted_set,在3.2版本以後新添加geo經緯度支援,以下将對其類型的常用操作做說明。

指令使用前言

通大多資料庫一樣,redis所有的指令提供了幫助,可以使用help +指令名稱檢視其使用方法,幫助資訊中不僅有指令用法,還有指令始于版本資訊,分組等。

為了友好的使用,redis還将所有指令都進行了分組,同時使用help+@+組名進行檢視每個組中所有指令,以下是所有分組資訊。

上面以及介紹如何檢視指令使用方法,是以在以下資料類型操作時候,隻舉例常用的指令,更多指令參考https://redis.io/commands

注意:redis在3.2版本新增geo資料類型。

generic       #一般指令組,對大多數類型适用
string        #字元串類型指令組,使用所有字元串類型
list          #清單類型指令組
set           #集合類型指令組
sorted_set    #有序集合指令組
hash          #hash操作指令組
pubsub        #釋出指令組
transactions  #事務操作指令組
connection    #連接配接相關指令組
server        #伺服器相關指令組
scripting     #lua 腳本指令組
hyperloglog   #hyperloglog類型指令組,redis在 2.8.9 版本添加了 HyperLogLog 結構
cluster       #叢集相關指令組
geo           #經緯度相關指令組,适用于3.2.0以後的版本      

示例:檢視事務操作所有指令

redis系列--你真的入門了嗎?redis4.0入門~

key操作

常用:

DEL key #删除某個key
KEYS pattern  #檢視符合正則的所有key
EXISTS key [key ...] #判斷某個key是否存在,可支援多個,傳回存在的個數
EXPIRE key seconds #重新整理某個key過期時間
MOVE key db  #移動key到某個資料庫      

示例:

redis系列--你真的入門了嗎?redis4.0入門~

string操作

字元串操作中需要注意的是,redis中的整型也當作字元串處理。

SET key value [EX seconds] [PX milliseconds] [NX|XX]  #設定key為指定的字元串值。
#參數:
#EX seconds – 設定鍵key的過期時間,機關時秒
#PX milliseconds – 設定鍵key的過期時間,機關時毫秒
#NX – 隻有鍵key不存在的時候才會設定key的值
#XX – 隻有鍵key存在的時候才會設定key的值

APPEND key value  #如果 key 已經存在,并且值為字元串,那麼這個指令會把 value 追加到原來值(value)的結尾。 如果 key 不存在,那麼它将首先建立一個空字元串的key,再執行追加操作,這種情況 APPEND 将類似于 SET 操作。

GET key #擷取key值,不存在則傳回nil

GETRANGE key start end #擷取指定key值的索引開始位置和結束位置所對應的值,索引從0開始

GETSET key value  #設定新的key值,并擷取設定之前的值,如果key不存在則設定,并傳回nil

MGET key [key ...]   #批量擷取key的值

MSET key value [key value ...] #批量設定key的值

DECR key #數字類型的key自減操作,key類型不是數字則報錯

INCR key  #數字類型key 自加操作,與DECR相反

DECRBY key decrement  #數字類型key指定減少數值

INCRBY key increment   #數字類型key指定增加數值,與DECRBY相反

STRLEN key  #擷取key長度      
redis系列--你真的入門了嗎?redis4.0入門~

list操作

清單中的元素索引從0開始,倒數的元素可以用“-”+倒數位置表示,如-2,代表倒數第二個元素,-1則代表最後一個元素。

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

一個清單最多可以包含 232 - 1 個元素 (4294967295, 每個清單超過40億個元素)。

LPUSH key value [value ...]  #從清單左邊放入一個或者多個元素

LPUSHX key value  #當清單存在時,從左邊放入一個元素

RPUSH key value [value ...]  #從清單右邊放入一個或者多個元素

RPUSHX key value  #當清單存在時,從右邊放入一個元素

LSET key index value  #根據索引設定清單中元素的值,當list不存在是報錯

LINDEX key index  #根據清單索引擷取元素值,索引從0開始

LINSERT key BEFORE|AFTER pivot value  #在清單中,基于某個基準點插入值,pivot代表基準點

LLEN key #擷取清單長度

LRANGE key start stop  #根據索引擷取清單中的元素,清單索引最後一個可以使用-1

LREM key count value  #從存于 key 的清單裡移除前 count 次出現的值為 value 的元素
#count > 0: 從頭往尾移除值為 value 的元素
#count < 0: 從尾往頭移除值為 value 的元素
#count = 0: 移除所有值為 value 的元素

LPOP key  #從清單左邊删除一個元素

RPOP key  #從清單右邊删除一個元素

RPOPLPUSH source destination  #删除source清單中的删除最後一個元素将其追加到destination清單

LTRIM key start stop  #根據索引start和stop保留清單元素      
redis系列--你真的入門了嗎?redis4.0入門~

hash操作

hash操作所有指令都以H開頭。

Redis hash 是一個string類型的field和value的映射表,hash特别适合用于存儲對象。

Redis 中每個 hash 可以存儲 232 - 1 鍵值對(40多億)。

HDEL key field [field ...]  #删除hash表中一個或多個字段

HEXISTS key field  #判斷hash表中字段是否存在

HGET key field  #擷取hash表中字段的值

HGETALL key  #擷取hash表中所有字段

HSET key field value  # 設定hash表中字段的值

HSETNX key field value  #隻有當字段不存在時候才設定hash表中字段值,

HLEN key  #擷取hash表中字段個數

HVALS key  #擷取hash表中所有字段的值

HKEYS key  #擷取hash表中所有的字段

HSTRLEN key field #擷取hash表中指定字段的值的長度

HMSET key field value [field value ...]  #批量設定hash表中字段的值

HMGET key field [field ...]  #批量擷取hash表中字段的值      
redis系列--你真的入門了嗎?redis4.0入門~

集合set操作

Redis 的 Set 是 String 類型的無序集合。集合成員是唯一的,這就意味着集合中不能出現重複的資料。

Redis 中集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是 O(1)。

集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。

SADD key member [member ...]  #添加一個或多個元素到集合中

SREM key member [member ...]  #删除一個或多個集合中的元素

SCARD key  #擷取集合中元素數量

SMEMBERS key  #傳回集合中所有的元素

SINTER key [key ...] #擷取兩個或兩個以上集合的交集

SUNION key [key ...]  #擷取兩個或兩個以上集合的并集

SDIFF key [key ...]     #擷取兩個或者兩個以上集合的差集

SISMEMBER key member  #判斷元素是否是在指定集合中

SMOVE source destination member #移動一個集合中的元素到另一個集合

SPOP key [count]  #移除count個集合中元素,count可選參數,預設為1,即移除一個      

有序集合操作

Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重複的成員。

不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。

有序集合的成員是唯一的,但分數(score)卻可以重複。

集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是O(1)。 集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。

ZADD key [NX|XX] [CH] [INCR] score member [score member ...]  #向一個有序集合添加成員(元素)
#參數:
#XX: 僅僅更新存在的成員,不添加新成員。
#NX: 不更新存在的成員。隻添加新成員。
#CH: 修改傳回值為發生變化的成員總數,原始是傳回新添加成員的總數 (CH 是 changed 的意思)。更改的元素是新添加的成員,已經存在的成員更新分數。 是以在指令中指定的成員有相同的分數将不被計算在内。注:在通常情況下,ZADD傳回值隻計算新添加成員的數量。
#INCR: 當ZADD指定這個選項時,成員的操作就等同ZINCRBY指令,對成員的分數進行遞增操作。

ZCARD key  #擷取有序集合中元素個數

ZCOUNT key min max  #指定分數範圍的元素個數

ZINCRBY key increment member  #為有序集的元素的score值加上增加指定的increment

ZRANGE key start stop [WITHSCORES]  #根據有序集合中分數區間擷取集合中的元素

ZRANGE key start stop [WITHSCORES]  #擷取有序集合中元素的排名

ZREM key member [member ...]  #删除有序集合中一個或多個元素

ZSCORE key member  #設定元素在集合中的分數      

GEO類型操作

Redis的GEO是 3.2 版本的新特性,對GEO(地理位置)的支援。這個功能可以将使用者給定的地理位置資訊儲存起來, 并對這些資訊進行操作。

geo類型指令不多,總共6個是以這裡全部列舉出來了。

GEOADD key longitude latitude member [longitude latitude member ...]  #将指定的地理空間位置(緯度、經度、名稱)添加到指定的key中

GEODIST key member1 member2 [unit]  #傳回兩個給定位置之間的距離。如果兩個位置之間的其中一個不存在, 那麼指令傳回空值。指定機關的參數 unit 必須是以下機關的其中一個:

#m 表示機關為米
#km 表示機關為千米
#mi 表示機關為英裡
#ft 表示機關為英尺

GEOPOS key member [member ...]  #從key裡傳回所有給定位置元素的位置(經度和緯度)

GEOHASH key member [member ...]  #傳回一個或多個位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技術,使用Geohash位置52點整數編碼。由于編碼和解碼過程中所使用的初始最小和最大坐标不同,編碼的編碼也不同于标準。此指令傳回一個标準的Geohash

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]  
#以給定的經緯度為中心, 傳回鍵包含的位置元素當中, 與中心的距離不超過給定最大距離的所有位置元素。

#範圍可以使用以下其中一個機關:

#m 表示機關為米。
#km 表示機關為千米。
#mi 表示機關為英裡。
#ft 表示機關為英尺。
#在給定以下可選項時, 指令會傳回額外的資訊:

#WITHDIST: 在傳回位置元素的同時, 将位置元素與中心之間的距離也一并傳回。 距離的機關和使用者給定的範圍機關保持一緻。
#WITHCOORD: 将位置元素的經度和次元也一并傳回。
#WITHHASH: 以 52 位有符号整數的形式, 傳回位置元素經過原始 geohash 編碼的有序集合分值。 這個選項主要用于底層應用或者調試, 實際中的作用并不大。
#指令預設傳回未排序的位置元素。 通過以下兩個參數, 使用者可以指定被傳回位置元素的排序方式:

#ASC: 根據中心的位置, 按照從近到遠的方式傳回位置元素。
#DESC: 根據中心的位置, 按照從遠到近的方式傳回位置元素。
#在預設情況下, GEORADIUS 指令會傳回所有比對的位置元素。 雖然使用者可以使用 COUNT <count> 選項去擷取前 N 個比對元素, 但是因為指令在内部可能會需要對所有被比對的元素進行處理, 是以在對一個非常大的區域進行搜尋時, 即使隻使用 COUNT 選項去擷取少量元素, 指令的執行速度也可能會非常慢。 但是從另一方面來說, 使用 COUNT 選項去減少需要傳回的元素數量, 對于減少帶寬來說仍然是非常有用的。

#傳回值:
  #在沒有給定任何 WITH 選項的情況下, 指令隻會傳回一個像 [“New York”,”Milan”,”Paris”] 這樣的線性(linear)清單。
  #在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等選項的情況下, 指令傳回一個二層嵌套數組, 内層的每個子數組就表示一個元素

  #在傳回嵌套數組時, 子數組的第一個元素總是位置元素的名字。 至于額外的資訊, 則會作為子數組的後續元素, 按照以下順序被傳回:
    #以浮點數格式傳回的中心與位置元素之間的距離, 機關與使用者指定範圍時的機關一緻。
    #geohash 整數。
    #由兩個元素組成的坐标,分别為經度和緯度。

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
#這個指令和 GEORADIUS 指令一樣, 都可以找出位于指定範圍内的元素, 但是 GEORADIUSBYMEMBER 的中心點是由給定的位置元素決定的。      

操作示例:

redis系列--你真的入門了嗎?redis4.0入門~

五、釋出訂閱

Redis 釋出訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

Redis 用戶端可以訂閱任意數量的頻道。

下圖代表其釋出訂閱之間的關系

redis系列--你真的入門了嗎?redis4.0入門~

運作原理

每個Redis 伺服器程序都維持着一個表示伺服器狀态的 redis.h/redisServer結構, 結構的pubsub_channels 屬性是一個字典, 這個字典就用于儲存訂閱頻道的資訊:

struct redisServer {
    // ...
    dict *pubsub_channels;
    // ...
};      

其中,字典的鍵為正在被訂閱的頻道, 而字典的值則是一個連結清單, 連結清單中儲存了所有訂閱這個頻道的用戶端。

比如說,在下圖展示的這個pubsub_channels示例中,client1 、 client2 和 client3 就訂閱了 channel1 , 而client3也同時訂閱了channel2。

當用戶端調用SUBSCRIBE指令時, 程式就将用戶端和要訂閱的頻道在pubsub_channels字典中關聯起來。

redis系列--你真的入門了嗎?redis4.0入門~

SUBSCRIBE 指令的行為可以用僞代碼表示如下:

def SUBSCRIBE(client, channels):

    // 周遊所有輸入頻道
    for channel in channels:

        // 将用戶端添加到連結清單的末尾
        redisServer.pubsub_channels[channel].append(client)      

通過pubsub_channels字典, 程式隻要檢查某個頻道是否為字典的鍵, 就可以知道該頻道是否正在被用戶端訂閱; 隻要取出某個鍵的值, 就可以得到所有訂閱該頻道的用戶端的資訊。

了解了pubsub_channels字典的結構之後, 解釋PUBLISH指令的實作就非常簡單了: 當調用PUBLISH channel message指令, 程式首先根據channel定位到字典的鍵, 然後将資訊發送給字典值連結清單中的所有用戶端。

訂閱模式

redis的釋出訂閱不僅僅提供簡單的訂閱頻道,還提供模式比對訂閱。模式訂閱使用指令PSUBSCRIBE實作。

redisServer.pubsub_patterns屬性是一個連結清單,連結清單中儲存着所有和模式相關的資訊:

struct redisServer {
    // ...
    list *pubsub_patterns;
    // ...
};      

連結清單中的每個節點都包含一個redis.h/pubsubPattern結構:

typedef struct pubsubPattern {
    redisClient *client;
    robj *pattern;
} pubsubPattern;      

client 屬性儲存着訂閱模式的用戶端,而 pattern 屬性則儲存着被訂閱的模式。

每當調用 PSUBSCRIBE指令訂閱一個模式時, 程式就建立一個包含用戶端資訊和被訂閱模式的pubsubPattern結構, 并将該結構添加到redisServer.pubsub_patterns連結清單中。

作為例子,下圖展示了一個包含兩個模式的 pubsub_patterns 連結清單, 其中 client123 和 client256 都正在訂閱 tweet.shop.* 模式:

redis系列--你真的入門了嗎?redis4.0入門~

通過周遊整個pubsub_patterns連結清單,程式可以檢查所有正在被訂閱的模式,以及訂閱這些模式的用戶端。

當執行PUBLISH進行指令向channel指令發送消息時,PUBLISH除了将message 發送到所有訂閱channel的用戶端之外, 它還會将channel和pubsub_patterns中的模式進行對比, 如果channel和某個模式比對的話, 那麼也将message 發送到訂閱那個模式的用戶端,例如一個用戶端訂閱了aa.bb.*頻道,那麼他會收到來自所有aa.bb開頭的所有頻道消息。

相關指令

PSUBSCRIBE pattern [pattern ...]  #使用模式訂閱一個或多個符合給定模式的頻道

PUNSUBSCRIBE [pattern [pattern ...]]  #退訂所有給定模式的頻道

SUBSCRIBE channel [channel ...]   #訂閱給定的一個或多個頻道的資訊

UNSUBSCRIBE [channel [channel ...]]   #指退訂給定的頻道

PUBSUB subcommand [argument [argument ...]]  #檢視訂閱與釋出系統狀态

PUBLISH channel message   #将資訊發送到指定的頻道      

實踐

在以下示例中,将分别用SUBSCRIBE指令訂閱aa.bb和使用PSUBSCRIBE模式訂閱頻道aa.bb*。

SUBSCRIBE訂閱:

redis系列--你真的入門了嗎?redis4.0入門~

PSUBSCRIBE訂閱:

redis系列--你真的入門了嗎?redis4.0入門~

此時我們使用PUBSH向aa.bb發送消息,傳回接受到的頻道數,兩個訂閱者都能收到消息。

redis系列--你真的入門了嗎?redis4.0入門~

訂閱者1:

redis系列--你真的入門了嗎?redis4.0入門~

模式訂閱者:

redis系列--你真的入門了嗎?redis4.0入門~

小結

  • 訂閱資訊由伺服器程序維持的redisServer.pubsub_channels字典儲存,字典的鍵為被訂閱的頻道,字典的值為訂閱頻道的所有用戶端。
  • 當有新消息發送到頻道時,程式周遊頻道(鍵)所對應的(值)所有用戶端,然後将消息發送到所有訂閱頻道的用戶端上。
  • 訂閱模式的資訊由伺服器程序維持的redisServer.pubsub_patterns連結清單儲存,連結清單的每個節點都儲存着一個pubsubPattern結構,結構中儲存着被訂閱的模式,以及訂閱該模式的用戶端。程式通過周遊連結清單來查找某個頻道是否和某個模式比對。
  • 當有新消息發送到頻道時,除了訂閱頻道的用戶端會收到消息之外,所有訂閱了比對頻道的模式的用戶端,也同樣會收到消息。
  • 退訂頻道和退訂模式分别是訂閱頻道和訂閱模式的反操作。

六、事務

所謂事務應具有以下特效:原子性(Atomicity), 一緻性(Consistency),隔離性(Isolation),持久性(Durability),簡稱ACID,但redis所提供的事務比較簡單,它通過MULTI、EXEC、DISCARD和WATCH等指令實作事務。

而Redis隻支援簡單的事務,将執行指令放入隊列緩存,當程式中有異常或指令出錯,執行DISCARD清空緩存隊列不執行隊列中指令,其事務過程有以下特點:

  • 事務是一個單獨的隔離操作:事務中的所有指令都會序列化、按順序地執行。事務在執行的過程中,不會被其他用戶端發送來的指令請求所打斷。
  • 事務是一個泛原子操作(這裡我以泛原子稱呼,在某些情況redis的事務不是原子性的,後續會說明):事務中的指令要麼全部被執行,要麼全部都不執行。

EXEC 指令負責觸發并執行事務中的所有指令:

  • 如果用戶端在使用 MULTI 開啟了一個事務之後,卻因為斷線而沒有成功執行 EXEC ,那麼事務中的所有指令都不會被執行。
  • 另一方面,如果用戶端成功在開啟事務之後執行 EXEC ,那麼事務中的所有指令都會被執行。

特别說明文中的泛原子操作:

  • redis在開啟事務以後,若執行指令具有顯示的錯誤或者用戶端中斷則此次事務在執行EXEC指令時會調用DISCARD清空緩存隊列不執行隊列中的所有任務,此時是原子性的。
  • 當執行指令過程中,指令沒有顯示的報錯(例如LSET操作設定一個不存在的list),而是在EXEC調用時候某個指令出錯,那麼在這之前已經執行的指令将不會復原,是以嚴格說來,redis并不支援原子性。

涉及指令

MULTI  #用于标記事務塊的開始。Redis會将後續的指令逐個放入隊列中,然後才能使用EXEC指令執行緩存隊列中的指令。

EXEC  #執行緩存隊列中的指令

DISCARD  #清除所有先前在一個事務中放入隊列的指令,然後恢複正常的連接配接狀态,如果使用了WATCH指令,那麼DISCARD指令就會将目前連接配接監控的所有鍵取消監控。

WATCH key [key ...]   #當某個事務需要按條件執行時,就要使用這個指令将給定的鍵設定為受監控的

UNWATCH  #清除所有先前為一個事務監控的鍵,如果你調用了EXEC或DISCARD指令,那麼就不需要手動調用UNWATCH指令      

樂觀鎖機制

樂觀鎖:總是認為不會産生并發問題,每次去取資料的時候總認為不會有其他線程對資料進行修改,是以不會上鎖,但是在更新時會判斷其他線程在這之前有沒有對資料進行修改,一般會使用版本号機制或檢查再設定(CAS)操作實作。

redis通過WATCH指令實作樂觀鎖,作為WATCH指令的參數的鍵會受到Redis的監控,Redis能夠檢測到它們的變化。在執行EXEC指令之前,如果Redis檢測到至少有一個鍵被修改了,那麼整個事務便會中止運作,然後EXEC指令會傳回一個nil值,提醒使用者事務運作失敗。

注意:WATCH指令需要在MULTI之前執行,不然redis會将其一個指令放入緩存隊列中。

示例:在以下示例中通過一個用戶端開啟事務監聽name鍵,另一個用戶端在執行EXEC之前修改name鍵,此次事務将不會執行,并傳回nil,如下。

redis系列--你真的入門了嗎?redis4.0入門~
redis系列--你真的入門了嗎?redis4.0入門~

原子性實踐

為示範redis嚴格意義上将不支援原子性,做了一些簡單實踐。

redis系列--你真的入門了嗎?redis4.0入門~

從上面的結果可以看出,在開啟事務前name 值為Rose,在開啟事務先後執行了SET指令和LSET指令,但是LSET指令是錯誤的,當我們調用EXEC執行事務完事務以後,在回頭看事務中的SET指令已經生效,并未復原,因為在次過程中該指令沒有顯示的報錯,是以可以說redis的事務不支援原子性。

以上為本文所有内容,希望對你有所幫助!