<h1>0. NoSQL 產(chǎn)品(key-value)</h1>
<pre><code>RDBMS :MySQL,Oracle ,MSSQL,PG
NoSQL? :Redis,MongoDB,列存儲存儲相關(guān)
NewSQL----->分布式數(shù)據(jù)庫架構(gòu)(學習了MongoDB)
緩存產(chǎn)品介紹:
memcached (大公司會做二次開發(fā))
redis
Tair
</code></pre>
<h1>1. Redis功能介紹</h1>
<pre><code>數(shù)據(jù)類型豐富? ? (筆試、面試)*****
支持持久化? ? ? (筆試、面試) *****
多種內(nèi)存分配及回收策略
支持事務? ? ? ? ? ? (面試)? ? ****
消息隊列、消息訂閱
支持高可用? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ****
支持分布式分片集群 (面試)? *****
緩存穿透\雪崩(筆試、面試)? *****
Redis API? ? ? ? ? ? ? ? ? **
</code></pre>
<h1>2、企業(yè)緩存產(chǎn)品介紹</h1>
<pre><code>Memcached:
優(yōu)點:高性能讀寫、單一數(shù)據(jù)類型、支持客戶端式分布式集群、一致性hash
多核結(jié)構(gòu)、多線程讀寫性能高。
缺點:無持久化、節(jié)點故障可能出現(xiàn)緩存穿透、分布式需要客戶端實現(xiàn)、跨機房數(shù)據(jù)同步困難、架構(gòu)擴容復雜度高
Redis:? 優(yōu)點:高性能讀寫、多數(shù)據(jù)類型支持、數(shù)據(jù)持久化、高可用架構(gòu)、支持自定義虛擬內(nèi)存、支持分布式分片集群、單線程讀寫性能極高
缺點:多線程讀寫較Memcached慢
新浪、京東、直播類平臺、網(wǎng)頁游戲
memcache與redis在讀寫性能的對比
memcached 適合,多用戶訪問,每個用戶少量的rw
redis? ? 適合,少用戶訪問,每個用戶大量rw
Tair:
優(yōu)點:高性能讀寫、支持三種存儲引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、支撐了幾乎所有淘寶業(yè)務的緩存。
? ? 缺點:單機情況下,讀寫性能較其他兩種產(chǎn)品較慢
</code></pre>
<h1>3、Redis使用場景介紹</h1>
<pre><code>Memcached:多核的緩存服務,更加適合于多用戶并發(fā)訪問次數(shù)較少的應用場景
Redis:單核的緩存服務,單節(jié)點情況下,更加適合于少量用戶,多次訪問的應用場景。
Redis一般是單機多實例架構(gòu),配合redis集群出現(xiàn)。
</code></pre>
<h1>4、Redis安裝部署:</h1>
<pre><code>下載:
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
</code></pre>
<h1>5、Redis基本管理操作</h1>
<h2>5.1基礎配置文件介紹</h2>
<pre><code>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
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get name
"zhangsan"
</code></pre>
<h2>5.2 redis安全配置</h2>
<pre><code>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
----------驗證-----
方法一:
[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 123 -h 10.0.0.51 -p 6379
10.0.0.51:6379> set b 2
OK
</code></pre>
<h2>5.3 在線查看和修改配置</h2>
<pre><code>CONFIG GET *
CONFIG GET requirepass
CONFIG GET r*
CONFIG SET requirepass 123
</code></pre>
<h2>5.4 redis持久化(內(nèi)存數(shù)據(jù)保存到磁盤)</h2>
<pre><code>RDB、AOF
RDB 持久化
? ? 可以在指定的時間間隔內(nèi)生成數(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
save 300 10
save 60 10000
配置分別表示:
900秒(15分鐘)內(nèi)有1個更改
300秒(5分鐘)內(nèi)有10個更改
60秒內(nèi)有10000個更改
AOF 持久化(append-only log file)
? ? 記錄服務器執(zhí)行的所有寫操作命令,并在服務器啟動時,通過重新執(zhí)行這些命令來還原數(shù)據(jù)集。
? ? AOF 文件中的命令全部以 Redis 協(xié)議的格式來保存,新命令會被追加到文件的末尾。
? ? 優(yōu)點:可以最大程度保證數(shù)據(jù)不丟
? ? 缺點:日志記錄量級比較大
AOF持久化配置
appendonly yes
appendfsync always
appendfsync everysec
appendfsync no
是否打開aof日志功能
每1個命令,都立即同步到aof
每秒寫1次
寫入工作交給操作系統(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
</code></pre>
<h1>6、Redis數(shù)據(jù)類型(筆試):</h1>
<pre><code>## 6.1 介紹
String :? ? ? 字符類型
Hash:? ? ? ? 字典類型
List:? ? ? ? 列表? ?
Set:? ? ? ? ? 集合
Sorted set:? 有序集合
</code></pre>
<div class="image-package">
<div class="image-container" style="max-width: 483px; max-height: 232px;">
<div class="image-container-fill" style="padding-bottom: 48.03%;"></div>
<div class="image-view" data-width="483" data-height="232"><img data-original-src="http://upload-images.jianshu.io/upload_images/16956686-1f727d6d23a61c5b.png" data-original-width="483" data-original-height="232" data-original-format="image/png" data-original-filesize="8085"></div>
</div>
<div class="image-caption">image.png</div>
</div>
<h2>6.2 KEY的通用操作</h2>
<pre><code>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
</code></pre>
<h2>6.3 Strings</h2>
<pre><code>應用場景
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
(3)計數(shù)器
每點一次關(guān)注,都執(zhí)行以下命令一次
127.0.0.1:6379> incr num
顯示粉絲數(shù)量:
127.0.0.1:6379> get num
暗箱操作:
127.0.0.1:6379> INCRBY num 10000
(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 的長度
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 該鍵已經(jīng)存在,返回追加后 Value的長度
incr mykey? ? ? ? ? ? ? ? ? ? ? 值增加1,若該key不存在,創(chuàng)建key,初始值設為0,增加后結(jié)果為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? ? ? ? ? ? ? ? ? 批量獲取鍵
</code></pre>
<h2>6.4 hash類型(字典類型)</h2>
<pre><code>應用場景:
存儲部分變更的數(shù)據(jù),如用戶信息等。
最接近mysql表結(jié)構(gòu)的一種類型
主要是可以做數(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)建該鍵及與其關(guān)聯(lián)的Hashes, Hashes中,key為field1 ,并設value為s ,若存在會覆蓋原value
hsetnx myhash field1 s? ?
若字段field1不存在,創(chuàng)建該鍵及與其關(guān)聯(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 鍵中所有字段的值
</code></pre>
<h2>6.5 LIST(列表)</h2>
<pre><code>應用場景
消息隊列系統(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)建該鍵及與其關(guān)聯(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個結(jié)束
lpop mykey? ? ? ? ? ? ? ? ? 獲取頭部元素,并且彈出頭部元素,出棧
lindex mykey 6? ? ? ? ? ? ? 從頭開始,獲取索引為6的元素 若下標越界,則返回nil
</code></pre>
<h2>6.6 SET 集合類型(join union)</h2>
<pre><code>應用場景:
案例:在微博應用中,可以將一個用戶所有的關(guān)注人存在一個集合中,將其所有粉絲存在一個集合。
Redis還為集合提供了求交集、并集、差集等操作,可以非常方便的實現(xiàn)如共同關(guān)注、共同喜好、二度好友等功能,
對上面的所有集合操作,你還可以使用不同的命令選擇將結(jié)果返回給客戶端還是存集到一個新的集合中。
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)建該鍵及與其關(guān)聯(lián)的set,依次插入a ,b,若key存在,則插入value中,若a 在myset中已經(jīng)存在,則插入了 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 是否已經(jīng)存在,返回值為 1 表示存在。
smembers myset? ? ? ? ? 查看set中的內(nèi)容
scard myset? ? ? ? ? ? 獲取Set 集合中元素的數(shù)量
srandmember myset? ? ? 隨機的返回某一成員
sdiff myset1 myset2 myset3? ? ? 1和2得到一個結(jié)果,拿這個集合和3比較,獲得每個獨有的值
sdiffstore diffkey myset myset2 myset3? ? ? 3個集和比較,獲取獨有的元素,并存入diffkey 關(guān)聯(lián)的Set中
sinter myset myset2 myset3? ? ? ? ? ? ? 獲得3個集合中都有的元素
sinterstore interkey myset myset2 myset3? 把交集存入interkey 關(guān)聯(lián)的Set中
sunion myset myset2 myset3? ? ? ? ? ? ? 獲取3個集合中的成員的并集
sunionstore unionkey myset myset2 myset3? 把并集存入unionkey 關(guān)聯(lián)的Set中
</code></pre>
<h2>6.7 SortedSet(有序集合)</h2>
<pre><code>應用場景:
排行榜應用,取TOP N操作
這個需求與上面需求的不同之處在于,前面操作以時間為權(quán)重,這個是以某個條件為權(quá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限制關(guān)鍵字
#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í)行順序:把索引反轉(zhuǎn)
? ? ? 位置索引:從大到小
? ? ? one 1
? ? ? two 0
#輸出結(jié)果: 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的成員,并反轉(zhuǎn)位置索引
</code></pre>
<h1>7. 發(fā)布訂閱</h1>
<div class="image-package">
<div class="image-container" style="max-width: 700px; max-height: 620px;">
<div class="image-container-fill" style="padding-bottom: 51.41%;"></div>
<div class="image-view" data-width="1206" data-height="620"><img data-original-src="http://upload-images.jianshu.io/upload_images/16956686-a1a42c3d7fe9855e.png" data-original-width="1206" data-original-height="620" data-original-format="image/png" data-original-filesize="87046"></div>
</div>
<div class="image-caption">image.png</div>
</div>
<pre><code>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 "
</code></pre>
<h1>8、Redis事務</h1>
<pre><code>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
</code></pre>
<h1>9. redis樂觀鎖實現(xiàn)(模擬買票)</h1>
<pre><code>發(fā)布一張票
set ticket 1
窗口1:
watch ticket
multi
set ticket 0? ? ? 1---->0
窗口2:
multi
set ticket 0
exec
窗口1:
exec
</code></pre>
<h1>10、 服務器管理命令</h1>
<pre><code>Info
Client list
Client kill ip:port
config get *
CONFIG RESETSTAT 重置統(tǒng)計
CONFIG GET/SET 動態(tài)修改
Dbsize
FLUSHALL 清空所有數(shù)據(jù)
select 1
FLUSHDB 清空當前庫
MONITOR 監(jiān)控實時指令
SHUTDOWN 關(guān)閉服務器
關(guān)閉數(shù)據(jù)庫:
redis-cli -a root shutdown
</code></pre>
<h1>11、redis(Master-Replicaset) *****</h1>
<h2>11.1 原理:</h2>
<pre><code>1. 副本庫通過slaveof 10.0.0.51 6379命令,連接主庫,并發(fā)送SYNC給主庫
2. 主庫收到SYNC,會立即觸發(fā)BGSAVE,后臺保存RDB,發(fā)送給副本庫
3. 副本庫接收后會應用RDB快照
4. 主庫會陸續(xù)將中間產(chǎn)生的新的操作,保存并發(fā)送給副本庫
5. 到此,我們主復制集就正常工作了
6. 再此以后,主庫只要發(fā)生新的操作,都會以命令傳播的形式自動發(fā)送給副本庫.
7. 所有復制相關(guān)信息,從info信息中都可以查到.即使重啟任何節(jié)點,他的主從關(guān)系依然都在.
8. 如果發(fā)生主從關(guān)系斷開時,從庫數(shù)據(jù)沒有任何損壞,在下次重連之后,從庫發(fā)送PSYNC給主庫
9. 主庫只會將從庫缺失部分的數(shù)據(jù)同步給從庫應用,達到快速恢復主從的目的
</code></pre>
<h2>11.2 主從數(shù)據(jù)一致性保證</h2>
<pre><code>min-slaves-to-write 1
min-slaves-max-lag? 3
</code></pre>
<h2>11.3 主庫是否要開啟持久化?</h2>
<pre><code>如果不開有可能,主庫重啟操作,造成所有主從數(shù)據(jù)丟失!
</code></pre>
<h1>12. 主從復制實現(xiàn)</h1>
<pre><code>1、環(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
2、開啟主從:
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
3、查詢主從狀態(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
</code></pre>
<h1>13 redis-sentinel(哨兵)</h1>
<pre><code>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
sentinel down-after-milliseconds mymaster 5000
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 意見的情況下, 強制開始一次自動故障遷移。
</code></pre>
<h1>14. redis cluster</h1>
<div class="image-package">
<div class="image-container" style="max-width: 700px; max-height: 533px;">
<div class="image-container-fill" style="padding-bottom: 43.72%;"></div>
<div class="image-view" data-width="1219" data-height="533"><img data-original-src="http://upload-images.jianshu.io/upload_images/16956686-f16bbe65c8764050.png" data-original-width="1219" data-original-height="533" data-original-format="image/png" data-original-filesize="89455"></div>
</div>
<div class="image-caption">image.png</div>
</div>
<h2>14.1 介紹</h2>
<h3>高性能</h3>
<pre><code>1、在多分片節(jié)點中,將16384個槽位,均勻分布到多個分片節(jié)點中
2、存數(shù)據(jù)時,將key做crc16(key),然后和16384進行取模,得出槽位值(0-16383之間)
3、根據(jù)計算得出的槽位值,找到相對應的分片節(jié)點的主節(jié)點,存儲到相應槽位上
4、如果客戶端當時連接的節(jié)點不是將來要存儲的分片節(jié)點,分片集群會將客戶端連接切換至真正存儲節(jié)點進行數(shù)據(jù)存儲
</code></pre>
<h3>高可用:</h3>
<pre><code>在搭建集群時,會為每一個分片的主節(jié)點,對應一個從節(jié)點,實現(xiàn)slaveof的功能,同時當主節(jié)點down,實現(xiàn)類似于sentinel的自動failover的功能。
1、redis會有多組分片構(gòu)成(3組)
2、redis cluster 使用固定個數(shù)的slot存儲數(shù)據(jù)(一共16384slot)
3、每組分片分得1/3 slot個數(shù)(0-5500? 5501-11000? 11001-16383)
4、基于CRC16(key) % 16384 ====》值 (槽位號)。
</code></pre>
<h2>14.2 規(guī)劃、搭建過程:</h2>
<pre><code>6個redis實例,一般會放到3臺硬件服務器
注:在企業(yè)規(guī)劃中,一個分片的兩個分到不同的物理機,防止硬件主機宕機造成的整個分片數(shù)據(jù)丟失。
端口號:7000-7005
</code></pre>
<h3>安裝集群插件</h3>
<pre><code>EPEL源安裝ruby支持
yum install ruby rubygems -y
使用國內(nèi)源
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
</code></pre>
<h3>集群節(jié)點準備</h3>
<pre><code>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
</code></pre>
<h3>啟動節(jié)點:</h3>
<pre><code>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]?
</code></pre>
<h3>將節(jié)點加入集群管理</h3>
<pre><code>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
</code></pre>
<h3>集群狀態(tài)查看</h3>
<pre><code>集群主節(jié)點狀態(tài)
redis-cli -p 7000 cluster nodes | grep master
集群從節(jié)點狀態(tài)
redis-cli -p 7000 cluster nodes | grep slave
</code></pre>
<h2>14.3 集群節(jié)點管理</h2>
<h3>增加新的節(jié)點</h3>
<pre><code>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
</code></pre>
<h3>添加主節(jié)點:</h3>
<pre><code>redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
</code></pre>
<h3>轉(zhuǎn)移slot(重新分片)</h3>
<pre><code>redis-trib.rb reshard 127.0.0.1:7000
</code></pre>
<h3>添加一個從節(jié)點</h3>
<pre><code>redis-trib.rb add-node --slave --master-id 8ff9ef5b78e6da62bd7b362e1fe190cba19ef5ae 127.0.0.1:7007 127.0.0.1:7000
</code></pre>
<h2>14.4 刪除節(jié)點</h2>
<h3>將需要刪除節(jié)點slot移動走</h3>
<pre><code>redis-trib.rb reshard 127.0.0.1:7000
49257f251824dd815bc7f31e1118b670365e861a
127.0.0.1:7006
0-1364 5461-6826 10923-12287
1365? ? ? 1366? ? 1365
</code></pre>
<h3>刪除一個節(jié)點</h3>
<pre><code>刪除master節(jié)點之前首先要使用reshard移除master的全部slot,然后再刪除當前節(jié)點
redis-trib.rb del-node 127.0.0.1:7006 8ff9ef5b78e6da62bd7b362e1fe190cba19ef5ae
---------------------
設置redis最大內(nèi)存
config set maxmemory 102400000
---------------------
</code></pre>
<h1>15.? redis的多API支持</h1>
<pre><code>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
安裝驅(qū)動:
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
+++++++++++++++++++++++++++++++++
</code></pre>
<h2>對redis的單實例進行連接操作</h2>
<pre><code>[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')
</code></pre>
<h2>sentinel集群連接并操作</h2>
<pre><code>[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')?
</code></pre>
<h2>配置讀寫分離</h2>
<pre><code>#寫節(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')?
</code></pre>
<h2>python連接rediscluster集群測試</h2>
<pre><code>使用
python3
>>> from rediscluster import StrictRedisCluster?
>>> 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 = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)?
>>> rc.set("foo", "bar")?
True?
>>> print(rc.get("foo"))?
'bar'
</code></pre>
<h1>16.一些概念</h1>
<h2>緩存穿透</h2>
<pre><code>概念
訪問一個不存在的key,緩存不起作用,請求會穿透到DB,流量大時DB會掛掉。
解決方案
采用布隆過濾器,使用一個足夠大的bitmap,用于存儲可能訪問的key,不存在的key直接被過濾;
訪問key未在DB查詢到值,也將空值寫進緩存,但可以設置較短過期時間。
</code></pre>
<h2>緩存雪崩</h2>
<pre><code>概念
大量的key設置了相同的過期時間,導致在緩存在同一時刻全部失效,造成瞬時DB請求量大、壓力驟增,引起雪崩。
解決方案
可以給緩存設置過期時間時加上一個隨機值時間,使得每個key的過期時間分布開來,不會集中在同一時刻失效。
</code></pre>
<h2>緩存擊穿</h2>
<pre><code>概念
一個存在的key,在緩存過期的一刻,同時有大量的請求,這些請求都會擊穿到DB,造成瞬時DB請求量大、壓力驟增。
解決方案
在訪問key之前,采用SETNX(set if not exists)來設置另一個短期key來鎖住當前key的訪問,訪問結(jié)束再刪除該短期key。
</code></pre>
<p>========================Redis END=======================</p>