NoSQL-Redis緩存技術-運維篇
一. NoSQL 產品(key-value)
RDBMS :MySQL边臼,Oracle 属愤,MSSQL羊初,PG
NoSQL :Redis,MongoDB刻撒,列存儲存儲相關
NewSQL----->分布式數(shù)據(jù)庫架構(學習了MongoDB)
緩存產品介紹:
memcached (大公司會做二次開發(fā))
redis
Tair
二. Redis功能介紹
數(shù)據(jù)類型豐富 (筆試啸盏、面試)*****
支持持久化 (筆試重贺、面試) *****
多種內存分配及回收策略
支持事務 (面試) ****
消息隊列、消息訂閱
支持高可用 ****
支持分布式分片集群 (面試) *****
緩存穿透\雪崩(筆試回懦、面試) *****
Redis API
三. 企業(yè)緩存產品介紹
Memcached:
優(yōu)點:高性能讀寫气笙、單一數(shù)據(jù)類型、支持客戶端式分布式集群怯晕、一致性hash
多核結構潜圃、多線程讀寫性能高。
缺點:無持久化舟茶、節(jié)點故障可能出現(xiàn)緩存穿透谭期、分布式需要客戶端實現(xiàn)、跨機房數(shù)據(jù)同步困難吧凉、架構擴容復雜度高
Redis: 優(yōu)點:高性能讀寫隧出、多數(shù)據(jù)類型支持、數(shù)據(jù)持久化阀捅、高可用架構胀瞪、支持自定義虛擬內存、支持分布式分片集群饲鄙、單線程讀寫性能極高
缺點:多線程讀寫較Memcached慢
新浪赏廓、京東涵紊、直播類平臺、網頁游戲
memcache與redis在讀寫性能的對比
memcached 適合,多用戶訪問,每個用戶少量的rw
redis 適合,少用戶訪問,每個用戶大量rw
Tair:
優(yōu)點:高性能讀寫幔摸、支持三種存儲引擎(ddb摸柄、rdb、ldb)既忆、支持高可用驱负、支持分布式分片集群、支撐了幾乎所有淘寶業(yè)務的緩存患雇。
缺點:單機情況下跃脊,讀寫性能較其他兩種產品較慢
四. Redis使用場景介紹
Memcached:多核的緩存服務,更加適合于多用戶并發(fā)訪問次數(shù)較少的應用場景
Redis:單核的緩存服務苛吱,單節(jié)點情況下酪术,更加適合于少量用戶,多次訪問的應用場景翠储。
Redis一般是單機多實例架構绘雁,配合redis集群出現(xiàn)。
五. Redis安裝部署
下載:
- wget http://download.redis.io/releases/redis-3.2.12.tar.gz
解壓:
上傳至 /data - tar xzf redis-3.2.12.tar.gz
- mv redis-3.2.12 redis
安裝:
- yum -y install gcc automake autoconf libtool make
- cd redis
- make
環(huán)境變量:
- vim /etc/profile
- export PATH=/data/redis/src:$PATH
- source /etc/profile
啟動:
- redis-server &
連接測試:
- redis-cli
- 127.0.0.1:6379> set num 10
OK - 127.0.0.1:6379> get num
10
六. Redis基本管理操作
基礎配置文件介紹
配置
mkdir /data/6379
cat > /data/6379/redis.conf<<EOF
daemonize yes
port 6379
logfile /data/6379/redis.log
dir /data/6379
dbfilename dump.rdb
EOF
重啟
redis-cli shutdown
redis-server /data/6379/redis.conf
netstat -lnp|grep 63
說明
redis.conf
是否后臺運行:
daemonize yes
默認端口:
port 6379
日志文件位置
logfile /var/log/redis.log
持久化文件存儲位置
dir /data/6379
RDB持久化數(shù)據(jù)文件:
dbfilename dump.rdb
測試
- redis-cli shutdown
- redis-server /data/6379/redis.conf
- redis-cli
- 127.0.0.1:6379> set name zhangsan
OK - 127.0.0.1:6379> get name
"zhangsan"
redis安全配置
說明
redis默認開啟了保護模式援所,只允許本地回環(huán)地址登錄并訪問數(shù)據(jù)庫庐舟。
禁止protected-mode
protected-mode yes/no (保護模式,是否只允許本地訪問)
配置
(1)Bind :指定IP進行監(jiān)聽
vim /data/6379/redis.conf
bind 10.0.0.51 127.0.0.1
(2)增加requirepass {password}
vim /data/6379/redis.conf
requirepass 123456
重啟
redis-cli -a 123456 shutdown
redis-server /data/6379/redis.conf
netstat -lnp|grep 63
驗證
方法一:
[root@db03 ~]# redis-cli -a 123456
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> exit
方法二:
[root@db03 ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set a b
[root@db01 src]# redis-cli -a 123456 -h 10.0.0.51 -p 6379
10.0.0.51:6379> set b 2
OK
在線查看和修改配置
redis-cli -a 123456 #先登入
CONFIG GET * :實際業(yè)務避免此操作
CONFIG GET requirepass
CONFIG GET r*
CONFIG SET requirepass 123 #在線修改密碼
redis持久化(內存數(shù)據(jù)保存到磁盤)RDB住拭、AOF
RDB 持久化
RDB說明
- 可以在指定的時間間隔內生成數(shù)據(jù)集的 時間點快照(point-in-time snapshot)挪略。
- 優(yōu)點:速度快,適合于用做備份滔岳,主從復制也是基于RDB持久化功能實現(xiàn)的杠娱。
- 缺點:會有數(shù)據(jù)丟失
RDB持久化核心配置參數(shù)
vim /data/6379/redis.conf
dir /data/6379
dbfilename dump.rdb
save 900 1 :900秒(15分鐘)內有1個更改
save 300 10 :300秒(5分鐘)內有10個更改
save 60 10000 :60秒內有10000個更改
AOF 持久化(append-only log file)
AOF說明
- 記錄服務器執(zhí)行的所有寫操作命令,并在服務器啟動時谱煤,通過重新執(zhí)行這些命令來還原數(shù)據(jù)集摊求。
- AOF 文件中的命令全部以 Redis 協(xié)議的格式來保存,新命令會被追加到文件的末尾趴俘。
- 優(yōu)點:可以最大程度保證數(shù)據(jù)不丟
- 缺點:日志記錄量級比較大
AOF持久化配置
appendonly yes:是否打開aof日志功能
appendfsync always:每1個命令,都立即同步到aof
appendfsync everysec:每秒寫1次
appendfsync no:寫入工作交給操作系統(tǒng),由操作系統(tǒng)判斷緩沖區(qū)大小,統(tǒng)一寫入到aof
vim /data/6379/redis.conf
appendonly yes
appendfsync everysec
面試
- redis 持久化方式有哪些睹簇?有什么區(qū)別奏赘?
- rdb:基于快照的持久化寥闪,速度更快,一般用作備份磨淌,主從復制也是依賴于rdb持久化功能
- aof:以追加的方式記錄redis操作日志的文件疲憋。可以最大程度的保證redis數(shù)據(jù)安全梁只,類似于mysql的binlog
七. Redis數(shù)據(jù)類型(筆試)
String : 字符類型
Hash: 字典類型
List: 列表
Set: 集合
Sorted set: 有序集合
image.png
KEY的通用操作
說明
KEYS * keys a keys a* 查看已存在所有鍵的名字 ****
TYPE 返回鍵所存儲值的類型 ****
EXPIRE\ PEXPIRE 以秒\毫秒設定生存時間 ***
TTL\ PTTL 以秒\毫秒為單位返回生存時間 ***
PERSIST 取消生存時間設置 ***
DEL 刪除一個key
EXISTS 檢查是否存在
RENAME 變更KEY名
例子:
127.0.0.1:6379> set name zhangsan
127.0.0.1:6379> EXPIRE name 60
(integer) 1
127.0.0.1:6379> ttl name
(integer) 57
127.0.0.1:6379> set a b ex 60
OK
127.0.0.1:6379> ttl a
127.0.0.1:6379> PERSIST a
(integer) 1
127.0.0.1:6379> ttl a
(integer) -1
Strings類型
應用場景
- session 共享
- 常規(guī)計數(shù):微博數(shù)缚柳,粉絲數(shù)埃脏,訂閱、禮物
- key:value
示義
(1)
set name zhangsan
(2)
MSET id 101 name zhangsan age 20 gender m
等價于以下操作:
SET id 101
set name zhangsan
set age 20
set gender m
計數(shù)器
每點一次關注秋忙,都執(zhí)行以下命令一次
127.0.0.1:6379> incr num incr + 鍵名(顯示鍵名的刷寫量)
顯示粉絲數(shù)量:
127.0.0.1:6379> get num get + 鍵名
暗箱操作:
127.0.0.1:6379> INCRBY num 10000 INCRBY+鍵名+數(shù)字(自定義鍵名的刷寫量)
(integer) 10006
127.0.0.1:6379> get num
"10006"
127.0.0.1:6379> DECRBY num 10000
(integer) 6
127.0.0.1:6379> get num
"6"
增
set mykey "test" 為鍵設置新值彩掐,并覆蓋原有值
getset mycounter 0 設置值,取值同時進行
setex mykey 10 "hello" 設置指定 Key 的過期時間為10秒,在存活時間可以獲取value
setnx mykey "hello" 若該鍵不存在,則為鍵設置新值
mset key3 "zyx" key4 "xyz" 批量設置鍵
刪
del mykey 刪除已有鍵
改
append mykey "hello" 若該鍵并不存在,返回當前 Value 的長度
該鍵已經存在灰追,返回追加后 Value的長度
incr mykey 值增加1,若該key不存在,創(chuàng)建key,初始值設為0,增加后結果為1
decrby mykey 5 值減少5
setrange mykey 20 dd 把第21和22個字節(jié),替換為dd, 超過value長度,自動補0
查
exists mykey 判斷該鍵是否存在堵幽,存在返回 1,否則返回0
get mykey 獲取Key對應的value
strlen mykey 獲取指定 Key 的字符長度
ttl mykey 查看一下指定 Key 的剩余存活時間(秒數(shù))
getrange mykey 1 20 獲取第2到第20個字節(jié),若20超過value長度,則截取第2個和后面所有的
mget key3 key4 批量獲取鍵
hash類型(字典類型)
應用場景:
存儲部分變更的數(shù)據(jù)弹澎,如用戶信息等朴下。
最接近mysql表結構的一種類型
主要是可以做數(shù)據(jù)庫緩存。
存數(shù)據(jù):
hmset stu id 101 name zhangsan age 20 gender m
hmset stu1 id 102 name zhangsan1 age 21 gender f
取數(shù)據(jù):
HMGET stu id name age gender
HMGET stu1 id name age gender
- select concat("hmset city_",id," id ",id," name ",name," countrycode ",countrycode," district ",district," population ",population) from city limit 10 into outfile '/tmp/hmset.txt'
增
hset myhash field1 "s"
若字段field1不存在,創(chuàng)建該鍵及與其關聯(lián)的Hashes, Hashes中,key為field1 ,并設value為s 苦蒿,若存在會覆蓋原value
hsetnx myhash field1 s
若字段field1不存在,創(chuàng)建該鍵及與其關聯(lián)的Hashes, Hashes中,key為field1 ,并設value為s殴胧, 若字段field1存在,則無效
hmset myhash field1 "hello" field2 "world 一次性設置多個字段
刪
hdel myhash field1 刪除 myhash 鍵中字段名為 field1 的字段
del myhash 刪除鍵
改
hincrby myhash field 1 給field的值加1
查
hget myhash field1 獲取鍵值為 myhash,字段為 field1 的值
hlen myhash 獲取myhash鍵的字段數(shù)量
hexists myhash field1 判斷 myhash 鍵中是否存在字段名為 field1 的字段
hmget myhash field1 field2 field3 一次性獲取多個字段
hgetall myhash 返回 myhash 鍵的所有字段及其值
hkeys myhash 獲取myhash 鍵中所有字段的名字
hvals myhash 獲取 myhash 鍵中所有字段的值
LIST(列表)類型
應用場景
消息隊列系統(tǒng)
比如sina微博
在Redis中我們的最新微博ID使用了常駐緩存,這是一直更新的佩迟。
但是做了限制不能超過5000個ID团滥,因此獲取ID的函數(shù)會一直詢問Redis。
只有在start/count參數(shù)超出了這個范圍的時候音五,才需要去訪問數(shù)據(jù)庫惫撰。
系統(tǒng)不會像傳統(tǒng)方式那樣“刷新”緩存,Redis實例中的信息永遠是一致的躺涝。
SQL數(shù)據(jù)庫(或是硬盤上的其他類型數(shù)據(jù)庫)只是在用戶需要獲取“很遠”的數(shù)據(jù)時才會被觸發(fā)厨钻,
而主頁或第一個評論頁是不會麻煩到硬盤上的數(shù)據(jù)庫了。
微信朋友圈:
127.0.0.1:6379> LPUSH wechat "today is nice day !"
127.0.0.1:6379> LPUSH wechat "today is bad day !"
127.0.0.1:6379> LPUSH wechat "today is good day !"
127.0.0.1:6379> LPUSH wechat "today is rainy day !"
127.0.0.1:6379> LPUSH wechat "today is friday !"
[5,4,3,2,1]
0 1 2 3 4
[e,d,c,b,a]
0 1 2 3 4
127.0.0.1:6379> lrange wechat 0 0
1) "today is friday !"
127.0.0.1:6379> lrange wechat 0 1
1) "today is friday !"
2) "today is rainy day !"
127.0.0.1:6379> lrange wechat 0 2
1) "today is friday !"
2) "today is rainy day !"
3) "today is good day !"
127.0.0.1:6379> lrange wechat 0 3
127.0.0.1:6379> lrange wechat -2 -1
1) "today is bad day !"
2) "today is nice day !"
**增 **
lpush mykey a b 若key不存在,創(chuàng)建該鍵及與其關聯(lián)的List,依次插入a ,b坚嗜, 若List類型的key存在,則插入value中
lpushx mykey2 e 若key不存在,此命令無效夯膀, 若key存在,則插入value中
linsert mykey before a a1 在 a 的前面插入新元素 a1
linsert mykey after e e2 在e 的后面插入新元素 e2
rpush mykey a b 在鏈表尾部先插入b,在插入a
rpushx mykey e 若key存在,在尾部插入e, 若key不存在,則無效
rpoplpush mykey mykey2 將mykey的尾部元素彈出,再插入到mykey2 的頭部(原子性的操作)
刪
del mykey 刪除已有鍵
lrem mykey 2 a 從頭部開始找,按先后順序,值為a的元素,刪除數(shù)量為2個,若存在第3個,則不刪除
ltrim mykey 0 2 從頭開始,索引為0,1,2的3個元素,其余全部刪除
改
lset mykey 1 e 從頭開始, 將索引為1的元素值,設置為新值 e,若索引越界,則返回錯誤信息
rpoplpush mykey mykey 將 mykey 中的尾部元素移到其頭部
查
lrange mykey 0 -1 取鏈表中的全部元素,其中0表示第一個元素,-1表示最后一個元素苍蔬。
lrange mykey 0 2 從頭開始,取索引為0,1,2的元素
lrange mykey 0 0 從頭開始,取第一個元素,從第0個開始,到第0個結束
lpop mykey 獲取頭部元素,并且彈出頭部元素,出棧
lindex mykey 6 從頭開始,獲取索引為6的元素 若下標越界,則返回nil
SET 集合類型(join union)
應用場景:
案例:在微博應用中诱建,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合碟绑。
Redis還為集合提供了求交集俺猿、并集、差集等操作格仲,可以非常方便的實現(xiàn)如共同關注押袍、共同喜好、二度好友等功能凯肋,
對上面的所有集合操作谊惭,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中。
示義
127.0.0.1:6379> sadd lxl pg1 jnl baoqiang gsy alexsb
(integer) 5
127.0.0.1:6379> sadd jnl baoqiang ms bbh yf wxg
(integer) 5
127.0.0.1:6379> SUNION lx jnl
1) "baoqiang"
2) "yf"
3) "bbh"
4) "ms"
5) "wxg"
127.0.0.1:6379> SUNION lxl jnl
1) "gsy"
2) "yf"
3) "alexsb"
4) "bbh"
5) "jnl"
6) "pg1"
7) "baoqiang"
8) "ms"
9) "wxg"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> SINTER lxl jnl
1) "baoqiang"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> SDIFF jnl lxl
1) "wxg"
2) "yf"
3) "bbh"
4) "ms"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> SDIFF lxl jnl
1) "jnl"
2) "pg1"
3) "gsy"
4) "alexsb"
增
sadd myset a b c
若key不存在,創(chuàng)建該鍵及與其關聯(lián)的set,依次插入a ,b,若key存在,則插入value中,若a 在myset中已經存在,則插入了 d 和 e 兩個新成員。
刪
spop myset 尾部的b被移出,事實上b并不是之前插入的第一個或最后一個成員
srem myset a d f 若f不存在, 移出 a圈盔、d ,并返回2
改
smove myset myset2 a 將a從 myset 移到 myset2豹芯,
查
sismember myset a 判斷 a 是否已經存在,返回值為 1 表示存在驱敲。
smembers myset 查看set中的內容
scard myset 獲取Set 集合中元素的數(shù)量
srandmember myset 隨機的返回某一成員
sdiff myset1 myset2 myset3 1和2得到一個結果,拿這個集合和3比較,獲得每個獨有的值
sdiffstore diffkey myset myset2 myset3 3個集和比較,獲取獨有的元素,并存入diffkey 關聯(lián)的Set中
sinter myset myset2 myset3 獲得3個集合中都有的元素
sinterstore interkey myset myset2 myset3 把交集存入interkey 關聯(lián)的Set中
sunion myset myset2 myset3 獲取3個集合中的成員的并集
sunionstore unionkey myset myset2 myset3 把并集存入unionkey 關聯(lián)的Set中
SortedSet(有序集合)
應用場景:
排行榜應用铁蹈,取TOP N操作
這個需求與上面需求的不同之處在于,前面操作以時間為權重众眨,這個是以某個條件為權重木缝,比如按頂?shù)拇螖?shù)排序,
這時候就需要我們的sorted set出馬了围辙,將你要排序的值設置成sorted set的score我碟,將具體的數(shù)據(jù)設置成相應的value,
每次只需要執(zhí)行一條ZADD命令即可姚建。
示義
127.0.0.1:6379> zadd topN 0 smlt 0 fskl 0 fshkl 0 lzlsfs 0 wdhbx 0 wxg
(integer) 6
127.0.0.1:6379> ZINCRBY topN 100000 smlt
"100000"
127.0.0.1:6379> ZINCRBY topN 10000 fskl
"10000"
127.0.0.1:6379> ZINCRBY topN 1000000 fshkl
"1000000"
127.0.0.1:6379> ZINCRBY topN 100 lzlsfs
"100"
127.0.0.1:6379> ZINCRBY topN 10 wdhbx
"10"
127.0.0.1:6379> ZINCRBY topN 100000000 wxg
"100000000"
127.0.0.1:6379> ZREVRANGE topN 0 2
1) "wxg"
2) "fshkl"
3) "smlt"
127.0.0.1:6379> ZREVRANGE topN 0 2 withscores
1) "wxg"
2) "100000000"
3) "fshkl"
4) "1000000"
5) "smlt"
6) "100000"
127.0.0.1:6379>
增
- zadd myzset 2 "two" 3 "three" 添加兩個分數(shù)分別是 2 和 3 的兩個成員
刪 - zrem myzset one two 刪除多個成員變量,返回刪除的數(shù)量
改 - zincrby myzset 2 one 將成員 one 的分數(shù)增加 2矫俺,并返回該成員更新后的分數(shù)
查 - zrange myzset 0 -1 WITHSCORES 返回所有成員和分數(shù),不加- WITHSCORES,只返回成員
- zrank myzset one 獲取成員one在Sorted-Set中的位置索引值。0表示第一個位置
- zcard myzset 獲取 myzset 鍵中成員的數(shù)量
- zcount myzset 1 2 獲取分數(shù)滿足表達式 1 <= score <= 2 的成員的數(shù)量
- zscore myzset three 獲取成員 three 的分數(shù)
- zrangebyscore myzset 1 2 獲取分數(shù)滿足表達式 1 < score <= 2 的成員
inf 表示第一個成員掸冤,+inf最后一個成員
limit限制關鍵字
2 3 是索引號
zrangebyscore myzset -inf +inf limit 2 3 返回索引是2和3的成員
zremrangebyscore myzset 1 2 刪除分數(shù) 1<= score <= 2 的成員厘托,并返回實際刪除的數(shù)量
zremrangebyrank myzset 0 1 刪除位置索引滿足表達式 0 <= rank <= 1 的成員
zrevrange myzset 0 -1 WITHSCORES 按位置索引從高到低,獲取所有成員和分數(shù)
原始成員:位置索引從小到大
one 0
two 1
執(zhí)行順序:把索引反轉
位置索引:從大到小
one 1
two 0
輸出結果: two
one
zrevrange myzset 1 3 獲取位置索引,為1,2,3的成員
相反的順序:從高到低的順序
- zrevrangebyscore myzset 3 0 獲取分數(shù) 3>=score>=0的成員并以相反的順序輸出
- zrevrangebyscore myzset 4 0 limit 1 2 獲取索引是1和2的成員,并反轉位置索引
八. 發(fā)布訂閱
圖示
示義、
- PUBLISH channel msg
將信息 message 發(fā)送到指定的頻道 channel
- SUBSCRIBE channel [channel ...]
訂閱頻道稿湿,可以同時訂閱多個頻道
- UNSUBSCRIBE [channel ...]
取消訂閱指定的頻道, 如果不指定頻道铅匹,則會取消訂閱所有頻道
- PSUBSCRIBE pattern [pattern ...]
訂閱一個或多個符合給定模式的頻道,每個模式以 * 作為匹配符饺藤,比如 it* 匹配所 有以 it 開頭的頻道( it.news 包斑、 it.blog 、 it.tweets 等等)涕俗, news.* 匹配所有 以 news. 開頭的頻道( news.it 罗丰、 news.global.today 等等),諸如此類
- PUNSUBSCRIBE [pattern [pattern ...]]
退訂指定的規(guī)則, 如果沒有參數(shù)則會退訂所有規(guī)則
- PUBSUB subcommand [argument [argument ...]]
查看訂閱與發(fā)布系統(tǒng)狀態(tài)
注意:使用發(fā)布訂閱模式實現(xiàn)的消息隊列再姑,當有客戶端訂閱channel后只能收到后續(xù)發(fā)布到該頻道的消息萌抵,之前發(fā)送的不會緩存,必須Provider和Consumer同時在線元镀。
發(fā)布訂閱例子:
窗口1:
127.0.0.1:6379> SUBSCRIBE baodi
窗口2:
127.0.0.1:6379> PUBLISH baodi "jin tian zhen kaixin!"
訂閱多頻道:
窗口1:
127.0.0.1:6379> PSUBSCRIBE wang*
窗口2:
127.0.0.1:6379> PUBLISH wangbaoqiang "jintian zhennanshou "
九. Redis弱事務
示義
redis的事務是基于隊列實現(xiàn)的绍填。
mysql的事務是基于事務日志和鎖機制實現(xiàn)的。
redis是樂觀鎖機制栖疑。
開啟事務功能時(multi)
multi
command1
command2
command3
command4
exec
discard
4條語句作為一個組讨永,并沒有真正執(zhí)行,而是被放入同一隊列中蔽挠。
如果住闯,這是執(zhí)行discard,會直接丟棄隊列中所有的命令澳淑,而不是做回滾比原。
exec
當執(zhí)行exec時,對列中所有操作杠巡,要么全成功要么全失敗
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a b
QUEUED
127.0.0.1:6379> set c d
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
十. redis樂觀鎖實現(xiàn)(模擬買票)
發(fā)布一張票
set ticket 1
窗口1:
watch ticket
multi
set ticket 0 1---->0
窗口2:
multi
set ticket 0
exec
窗口1:
exec
十一. 服務器管理命令
Info
Client list
Client kill ip:port
config get *
CONFIG RESETSTAT 重置統(tǒng)計
CONFIG GET/SET 動態(tài)修改
Dbsize #顯示當前鍵值對個數(shù)
FLUSHALL 清空所有數(shù)據(jù)(生產禁用)
select 1
FLUSHDB 清空當前庫(生產禁用)
MONITOR 監(jiān)控實時指令
SHUTDOWN 關閉服務器
關閉數(shù)據(jù)庫:
redis-cli -a root shutdown
十二. redis(Master-Replicaset)主副本集
原理
- 副本庫通過slaveof 10.0.0.51 6379命令,連接主庫,并發(fā)送SYNC給主庫
- 主庫收到SYNC,會立即觸發(fā)BGSAVE,后臺保存RDB,發(fā)送給副本庫
- 副本庫接收后會應用RDB快照
- 主庫會陸續(xù)將中間產生的新的操作,保存并發(fā)送給副本庫
- 到此,我們主復制集就正常工作了
- 再此以后,主庫只要發(fā)生新的操作,都會以命令傳播的形式自動發(fā)送給副本庫.
- 所有復制相關信息,從info信息中都可以查到.即使重啟任何節(jié)點,他的主從關系依然都在.
- 如果發(fā)生主從關系斷開時,從庫數(shù)據(jù)沒有任何損壞,在下次重連之后,從庫發(fā)送PSYNC給主庫
- 主庫只會將從庫缺失部分的數(shù)據(jù)同步給從庫應用,達到快速恢復主從的目的
主從數(shù)據(jù)一致性保證(從機設置)
min-slaves-to-write 1 #從機至少一臺保存主庫新的寫入才算成功
min-slaves-max-lag 3 #同步主庫變更操作的那一臺機器在3秒內若同步不成功量窘,則立即觸發(fā)注冊失敗給用戶
主庫是否要開啟持久化?
如果不開有可能氢拥,主庫重啟操作蚌铜,造成所有主從數(shù)據(jù)丟失!主庫不開啟持久化會提高主庫性能嫩海。但是主庫若是宕機冬殃,千萬不要進行重啟,因為會重新拍攝新的空快照傳給從機叁怪,導致主從所有數(shù)據(jù)丟失
十三. 主從復制實現(xiàn)
環(huán)境:
準備兩個或兩個以上redis實例
mkdir /data/638{0..2}
配置文件示例:
cat >> /data/6380/redis.conf <<EOF
port 6380
daemonize yes
pidfile /data/6380/redis.pid
loglevel notice
logfile "/data/6380/redis.log"
dbfilename dump.rdb
dir /data/6380
requirepass 123
masterauth 123
EOF
cat >> /data/6381/redis.conf <<EOF
port 6381
daemonize yes
pidfile /data/6381/redis.pid
loglevel notice
logfile "/data/6381/redis.log"
dbfilename dump.rdb
dir /data/6381
requirepass 123
masterauth 123
EOF
cat >> /data/6382/redis.conf <<EOF
port 6382
daemonize yes
pidfile /data/6382/redis.pid
loglevel notice
logfile "/data/6382/redis.log"
dbfilename dump.rdb
dir /data/6382
requirepass 123
masterauth 123
EOF
啟動:
redis-server /data/6380/redis.conf
redis-server /data/6381/redis.conf
redis-server /data/6382/redis.conf
主節(jié)點:6380
從節(jié)點:6381审葬、6382
開啟主從:
6381/6382命令行:
redis-cli -p 6381 -a 123 SLAVEOF 127.0.0.1 6380
redis-cli -p 6382 -a 123 SLAVEOF 127.0.0.1 6380
查詢主從狀態(tài)
redis-cli -p 6380 -a 123 info replication
redis-cli -p 6381 -a 123 info replication
redis-cli -p 6382 -a 123 info replication
十四. redis-sentinel(哨兵)
1、監(jiān)控
2奕谭、自動選主涣觉,切換(6381 slaveof no one)
3、2號從庫(6382)指向新主庫(6381)
4血柳、應用透明
5官册、自動處理故障節(jié)點
- 原主庫宕機不要重啟,利用哨兵重新把之前主從的一臺從機作為新主庫难捌,其余從機再進行指向即可膝宁。若修好原宕機主庫,會進行自愈自動加入集群根吁,作為從庫加入
sentinel搭建過程
mkdir /data/26380
cd /data/26380
vim sentinel.conf
port 26380
dir "/data/26380"
sentinel monitor mymaster 127.0.0.1 6380 1(數(shù)字1代表有多少臺sentinel認為主節(jié)點宕機昆汹,一般為單數(shù)臺)
sentinel down-after-milliseconds mymaster 5000(給宕機的主庫5秒時間回復,5秒主庫起不來婴栽,則開始切換满粗,換新主)
sentinel auth-pass mymaster 123
啟動:
[root@db01 26380]# redis-sentinel /data/26380/sentinel.conf &>/tmp/sentinel.log &
==============================
如果有問題:
1、重新準備1主2從環(huán)境
2愚争、kill掉sentinel進程
3映皆、刪除sentinel目錄下的所有文件
4、重新搭建sentinel
======================================
停主庫測試:
[root@db01 ~]# redis-cli -p 6380 shutdown
[root@db01 ~]# redis-cli -p 6381
info replication
啟動源主庫(6380)轰枝,看狀態(tài)捅彻。
Sentinel管理命令:
redis-cli -p 26380
PING :返回 PONG 。
SENTINEL masters :列出所有被監(jiān)視的主服務器
SENTINEL slaves <master name>
SENTINEL get-master-addr-by-name <master name> : 返回給定名字的主服務器的 IP 地址和端口號鞍陨。
SENTINEL reset <pattern> : 重置所有名字和給定模式 pattern 相匹配的主服務器步淹。
SENTINEL failover <master name> : 當主服務器失效時从隆, 在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移缭裆。
十五. redis cluster(分布式+高可用主從)
圖示
介紹
高性能
1键闺、在多分片節(jié)點中,將16384個槽位澈驼,均勻分布到多個分片節(jié)點中
2辛燥、存數(shù)據(jù)時,將key做crc16(key),然后和16384進行取模缝其,得出槽位值(0-16383之間)
3挎塌、根據(jù)計算得出的槽位值,找到相對應的分片節(jié)點的主節(jié)點内边,存儲到相應槽位上
4榴都、如果客戶端當時連接的節(jié)點不是將來要存儲的分片節(jié)點,分片集群會將客戶端連接切換至真正存儲節(jié)點進行數(shù)據(jù)存儲
高可用
在搭建集群時漠其,會為每一個分片的主節(jié)點缭贡,對應一個從節(jié)點,實現(xiàn)slaveof的功能辉懒,同時當主節(jié)點down阳惹,實現(xiàn)類似于sentinel的自動failover的功能。
1眶俩、redis會有多組分片構成(3組)
2莹汤、redis cluster 使用固定個數(shù)的slot存儲數(shù)據(jù)(一共16384slot)
3、每組分片分得1/3 slot個數(shù)(0-5500 5501-11000 11001-16383)
4颠印、基于CRC16(key) % 16384 ====》值 (槽位號)纲岭。
規(guī)劃、搭建過程
6個redis實例线罕,一般會放到3臺硬件服務器
注:在企業(yè)規(guī)劃中止潮,一個分片的兩個分到不同的物理機,防止硬件主機宕機造成的整個分片數(shù)據(jù)丟失钞楼。
端口號:7000-7005
安裝集群插件
EPEL源安裝ruby支持
yum install ruby rubygems -y
使用國內源
gem sources -l
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove https://rubygems.org/
gem sources -l
gem install redis -v 3.3.3
集群節(jié)點準備
- mkdir /data/700{0..5}
cat > /data/7000/redis.conf <<EOF
port 7000
daemonize yes
pidfile /data/7000/redis.pid
loglevel notice
logfile "/data/7000/redis.log"
dbfilename dump.rdb
dir /data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat >> /data/7001/redis.conf <<EOF
port 7001
daemonize yes
pidfile /data/7001/redis.pid
loglevel notice
logfile "/data/7001/redis.log"
dbfilename dump.rdb
dir /data/7001
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat >> /data/7002/redis.conf <<EOF
port 7002
daemonize yes
pidfile /data/7002/redis.pid
loglevel notice
logfile "/data/7002/redis.log"
dbfilename dump.rdb
dir /data/7002
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat >> /data/7003/redis.conf <<EOF
port 7003
daemonize yes
pidfile /data/7003/redis.pid
loglevel notice
logfile "/data/7003/redis.log"
dbfilename dump.rdb
dir /data/7003
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat >> /data/7004/redis.conf <<EOF
port 7004
daemonize yes
pidfile /data/7004/redis.pid
loglevel notice
logfile "/data/7004/redis.log"
dbfilename dump.rdb
dir /data/7004
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat >> /data/7005/redis.conf <<EOF
port 7005
daemonize yes
pidfile /data/7005/redis.pid
loglevel notice
logfile "/data/7005/redis.log"
dbfilename dump.rdb
dir /data/7005
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
啟動節(jié)點
redis-server /data/7000/redis.conf
redis-server /data/7001/redis.conf
redis-server /data/7002/redis.conf
redis-server /data/7003/redis.conf
redis-server /data/7004/redis.conf
redis-server /data/7005/redis.conf
[root@db01 ~]# ps -ef |grep redis
root 8854 1 0 03:56 ? 00:00:00 redis-server *:7000 [cluster]
root 8858 1 0 03:56 ? 00:00:00 redis-server *:7001 [cluster]
root 8860 1 0 03:56 ? 00:00:00 redis-server *:7002 [cluster]
root 8864 1 0 03:56 ? 00:00:00 redis-server *:7003 [cluster]
root 8866 1 0 03:56 ? 00:00:00 redis-server *:7004 [cluster]
root 8874 1 0 03:56 ? 00:00:00 redis-server *:7005 [cluster]
將節(jié)點加入集群管理
redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
(上訴直接復制粘貼執(zhí)行就可喇闸,自動搭建,輸入yes)
集群狀態(tài)查看
集群主節(jié)點狀態(tài)
redis-cli -p 7000 cluster nodes | grep master
集群從節(jié)點狀態(tài)
redis-cli -p 7000 cluster nodes | grep slave
集群節(jié)點管理
增加新的節(jié)點
mkdir /data/7006
mkdir /data/7007
cat > /data/7006/redis.conf <<EOF
port 7006
daemonize yes
pidfile /data/7006/redis.pid
loglevel notice
logfile "/data/7006/redis.log"
dbfilename dump.rdb
dir /data/7006
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
cat > /data/7007/redis.conf <<EOF
port 7007
daemonize yes
pidfile /data/7007/redis.pid
loglevel notice
logfile "/data/7007/redis.log"
dbfilename dump.rdb
dir /data/7007
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
redis-server /data/7006/redis.conf
redis-server /data/7007/redis.conf
添加主節(jié)點
redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
轉移slot(重新分片)
redis-trib.rb reshard 127.0.0.1:7000
添加一個從節(jié)點
redis-trib.rb add-node --slave --master-id 8ff9ef5b78e6da62bd7b362e1fe190cba19ef5ae 127.0.0.1:7007 127.0.0.1:7000
刪除節(jié)點
將需要刪除節(jié)點slot移動走
redis-trib.rb reshard 127.0.0.1:7000
49257f251824dd815bc7f31e1118b670365e861a
127.0.0.1:7006
0-1364 5461-6826 10923-12287
1365 1366 1365
刪除一個節(jié)點
刪除master節(jié)點之前首先要使用reshard移除master的全部slot,然后再刪除當前節(jié)點
redis-trib.rb del-node 127.0.0.1:7006 8ff9ef5b78e6da62bd7b362e1fe190cba19ef5ae
---------------------
設置redis最大內存
config set maxmemory 102400000
---------------------
十六. redis的多API支持(python為例)
工具安裝
yum install -y python36
python3 -V
yum install -y python36-pip
pip3 install redis
pip3 install redis-py-cluster
++++++++++++源碼方式+++++++++++++++
https://redis.io/clients
下載redis-py-master.zip
安裝驅動:
unzip redis-py-master.zip
cd redis-py-master
python3 setup.py install
redis cluster的連接并操作(python2.7.2以上版本才支持redis cluster询件,我們選擇的是3.6)
https://github.com/Grokzen/redis-py-cluster
安裝redis-cluser的客戶端程序
cd redis-py-cluster-unstable
python3 setup.py install
+++++++++++++++++++++++++++++++++
對redis的單實例進行連接操作
[root@db01 ~]# redis-server /data/6379/redis.conf
python3
>>>import redis
>>>r = redis.StrictRedis(host='10.0.0.51', port=6379, db=0,password='123456')
>>>r.set('oldboy', 'oldguo')
>>>r.get('oldboy')
sentinel集群連接并操作
[root@db01 ~]# redis-server /data/6380/redis.conf
[root@db01 ~]# redis-server /data/6381/redis.conf
[root@db01 ~]# redis-server /data/6382/redis.conf
[root@db01 ~]# redis-sentinel /data/26380/sentinel.conf &
--------------------------------
## 導入redis sentinel包
>>>from redis.sentinel import Sentinel
##指定sentinel的地址和端口號
>>> sentinel = Sentinel([('localhost', 26380)], socket_timeout=0.1)
##測試燃乍,獲取以下主庫和從庫的信息
>>> sentinel.discover_master('mymaster')
>>> sentinel.discover_slaves('mymaster')
配置讀寫分離
#寫節(jié)點
>>> master = sentinel.master_for('mymaster', socket_timeout=0.1,password="123")
#讀節(jié)點
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1,password="123")
###讀寫分離測試 key
>>> master.set('oldboy', '123')
>>> slave.get('oldboy')
python連接rediscluster集群測試
使用
python3
>>> from rediscluster import RedisCluster
>>> startup_nodes = [{"host":"127.0.0.1", "port": "7000"},{"host":"127.0.0.1", "port": "7001"},{"host":"127.0.0.1", "port": "7002"}]
### Note: decode_responses must be set to True when used with python3
>>> rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
>>> rc.set("foo", "bar")
True
>>> print(rc.get("foo"))
'bar'
十七. 一些概念
緩存穿透
概念
訪問一個不存在的key,緩存不起作用宛琅,請求會穿透到DB刻蟹,流量大時DB會掛掉。
解決方案
采用布隆過濾器嘿辟,使用一個足夠大的bitmap舆瘪,用于存儲可能訪問的key片效,不存在的key直接被過濾;
訪問key未在DB查詢到值英古,也將空值寫進緩存淀衣,但可以設置較短過期時間魂拦。
緩存雪崩
概念
大量的key設置了相同的過期時間爆土,導致在緩存在同一時刻全部失效沾鳄,造成瞬時DB請求量大、壓力驟增某残,引起雪崩。
解決方案
可以給緩存設置過期時間時加上一個隨機值時間陵吸,使得每個key的過期時間分布開來玻墅,不會集中在同一時刻失效。
緩存擊穿
概念
一個存在的key壮虫,在緩存過期的一刻澳厢,同時有大量的請求,這些請求都會擊穿到DB囚似,造成瞬時DB請求量大剩拢、壓力驟增。
解決方案
在訪問key之前饶唤,采用SETNX(set if not exists)來設置另一個短期key來鎖住當前key的訪問徐伐,訪問結束再刪除該短期key。