NoSQL-Redis-day13緩存技術(shù)-運維篇

<h1>0. NoSQL 產(chǎn)品(key-value)</h1>

<pre><code>RDBMS :MySQL,Oracle ,MSSQL,PG

NoSQL? :Redis,MongoDB,列存儲存儲相關(guān)

NewSQL-----&gt;分布式數(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 &amp;

連接測試:

redis-cli

127.0.0.1:6379&gt; set num 10

OK

127.0.0.1:6379&gt; get num

10

</code></pre>

<h1>5、Redis基本管理操作</h1>

<h2>5.1基礎配置文件介紹</h2>

<pre><code>mkdir /data/6379

cat &gt; /data/6379/redis.conf&lt;&lt;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&gt; set name zhangsan

OK

127.0.0.1:6379&gt; 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&gt; set name zhangsan

OK

127.0.0.1:6379&gt; exit

方法二:

[root@db03 ~]# redis-cli

127.0.0.1:6379&gt; auth 123456

OK

127.0.0.1:6379&gt; set a b

[root@db01 src]# redis-cli -a 123 -h 10.0.0.51 -p 6379

10.0.0.51:6379&gt; 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&gt; set name zhangsan

127.0.0.1:6379&gt; EXPIRE name 60

(integer) 1

127.0.0.1:6379&gt; ttl name

(integer) 57

127.0.0.1:6379&gt; set a b ex 60

OK

127.0.0.1:6379&gt; ttl a

127.0.0.1:6379&gt; PERSIST a

(integer) 1

127.0.0.1:6379&gt; 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&gt; incr num

顯示粉絲數(shù)量:

127.0.0.1:6379&gt; get num

暗箱操作:

127.0.0.1:6379&gt; INCRBY num 10000

(integer) 10006

127.0.0.1:6379&gt; get num

"10006"

127.0.0.1:6379&gt; DECRBY num 10000

(integer) 6

127.0.0.1:6379&gt; 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&gt; LPUSH wechat "today is nice day !"

127.0.0.1:6379&gt; LPUSH wechat "today is bad day !"

127.0.0.1:6379&gt; LPUSH wechat "today is good? day !"

127.0.0.1:6379&gt; LPUSH wechat "today is rainy? day !"

127.0.0.1:6379&gt; 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&gt; lrange wechat? 0 0

1) "today is friday !"

127.0.0.1:6379&gt; lrange wechat? 0 1

1) "today is friday !"

2) "today is rainy? day !"

127.0.0.1:6379&gt; lrange wechat? 0 2

1) "today is friday !"

2) "today is rainy? day !"

3) "today is good? day !"

127.0.0.1:6379&gt; lrange wechat? 0 3

127.0.0.1:6379&gt; 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&gt; sadd lxl pg1 jnl baoqiang gsy alexsb

(integer) 5

127.0.0.1:6379&gt; sadd jnl baoqiang ms bbh yf wxg

(integer) 5

127.0.0.1:6379&gt; SUNION lx jnl

1) "baoqiang"

2) "yf"

3) "bbh"

4) "ms"

5) "wxg"

127.0.0.1:6379&gt; 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&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt; SINTER lxl jnl

1) "baoqiang"

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt; SDIFF jnl lxl

1) "wxg"

2) "yf"

3) "bbh"

4) "ms"

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt;

127.0.0.1:6379&gt; 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&gt; zadd topN 0 smlt 0 fskl 0 fshkl 0 lzlsfs 0 wdhbx 0 wxg

(integer) 6

127.0.0.1:6379&gt; ZINCRBY topN 100000 smlt

"100000"

127.0.0.1:6379&gt; ZINCRBY topN 10000 fskl

"10000"

127.0.0.1:6379&gt; ZINCRBY topN 1000000 fshkl

"1000000"

127.0.0.1:6379&gt; ZINCRBY topN 100 lzlsfs

"100"

127.0.0.1:6379&gt; ZINCRBY topN 10 wdhbx

"10"

127.0.0.1:6379&gt; ZINCRBY topN 100000000 wxg

"100000000"

127.0.0.1:6379&gt; ZREVRANGE topN 0 2

1) "wxg"

2) "fshkl"

3) "smlt"

127.0.0.1:6379&gt; ZREVRANGE topN 0 2 withscores

1) "wxg"

2) "100000000"

3) "fshkl"

4) "1000000"

5) "smlt"

6) "100000"

127.0.0.1:6379&gt;

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 &lt;= score &lt;= 2 的成員的數(shù)量

zscore myzset three? ? ? ? ? ? ? ? 獲取成員 three 的分數(shù)

zrangebyscore myzset? 1 2? ? ? ? ? ? ? 獲取分數(shù)滿足表達式 1 &lt; score &lt;= 2 的成員

#-inf 表示第一個成員,+inf最后一個成員

#limit限制關(guān)鍵字

#2? 3? 是索引號

zrangebyscore myzset -inf +inf limit 2 3? 返回索引是2和3的成員

zremrangebyscore myzset 1 2? ? ? ? 刪除分數(shù) 1&lt;= score &lt;= 2 的成員,并返回實際刪除的數(shù)量

zremrangebyrank myzset 0 1? ? ? ? ? ? ? 刪除位置索引滿足表達式 0 &lt;= rank &lt;= 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&gt;=score&gt;=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&gt; SUBSCRIBE baodi

窗口2:

127.0.0.1:6379&gt; PUBLISH baodi "jin tian zhen kaixin!"

訂閱多頻道:

窗口1:

127.0.0.1:6379&gt; PSUBSCRIBE wang*

窗口2:

127.0.0.1:6379&gt; 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&gt; set a b

OK

127.0.0.1:6379&gt; MULTI

OK

127.0.0.1:6379&gt; set a b

QUEUED

127.0.0.1:6379&gt; set c d

QUEUED

127.0.0.1:6379&gt; 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----&gt;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 &gt;&gt; /data/6380/redis.conf &lt;&lt;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 &gt;&gt;? /data/6381/redis.conf &lt;&lt;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 &gt;&gt;? /data/6382/redis.conf &lt;&lt;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? &amp;&gt;/tmp/sentinel.log &amp;

==============================

如果有問題:

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 &lt;master name&gt;

SENTINEL get-master-addr-by-name &lt;master name&gt; : 返回給定名字的主服務器的 IP 地址和端口號。

SENTINEL reset &lt;pattern&gt; : 重置所有名字和給定模式 pattern 相匹配的主服務器。

SENTINEL failover &lt;master name&gt; : 當主服務器失效時, 在不詢問其他 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 &gt; /data/7000/redis.conf &lt;&lt;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 &gt;&gt; /data/7001/redis.conf &lt;&lt;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 &gt;&gt; /data/7002/redis.conf &lt;&lt;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 &gt;&gt;? /data/7003/redis.conf &lt;&lt;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 &gt;&gt; /data/7004/redis.conf &lt;&lt;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 &gt;&gt; /data/7005/redis.conf &lt;&lt;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 &gt; /data/7006/redis.conf &lt;&lt;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 &gt;? /data/7007/redis.conf &lt;&lt;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

&gt;&gt;&gt;import redis

&gt;&gt;&gt;r = redis.StrictRedis(host='10.0.0.51', port=6379, db=0,password='123456')

&gt;&gt;&gt;r.set('oldboy', 'oldguo')

&gt;&gt;&gt;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 &amp;

--------------------------------

## 導入redis sentinel包

&gt;&gt;&gt;from redis.sentinel import Sentinel?

##指定sentinel的地址和端口號

&gt;&gt;&gt; sentinel = Sentinel([('localhost', 26380)], socket_timeout=0.1)?

##測試,獲取以下主庫和從庫的信息

&gt;&gt;&gt; sentinel.discover_master('mymaster')?

&gt;&gt;&gt; sentinel.discover_slaves('mymaster')?

</code></pre>

<h2>配置讀寫分離</h2>

<pre><code>#寫節(jié)點

&gt;&gt;&gt; master = sentinel.master_for('mymaster', socket_timeout=0.1,password="123")?

#讀節(jié)點

&gt;&gt;&gt; slave = sentinel.slave_for('mymaster', socket_timeout=0.1,password="123")?

###讀寫分離測試? key? ?

&gt;&gt;&gt; master.set('oldboy', '123')?

&gt;&gt;&gt; slave.get('oldboy')?

</code></pre>

<h2>python連接rediscluster集群測試</h2>

<pre><code>使用

python3

&gt;&gt;&gt; from rediscluster import StrictRedisCluster?

&gt;&gt;&gt; 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?

&gt;&gt;&gt; rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)?

&gt;&gt;&gt; rc.set("foo", "bar")?

True?

&gt;&gt;&gt; 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>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容