1. 程式人生 > >Redis超級新手指南-上篇(福祿篇)

Redis超級新手指南-上篇(福祿篇)

Redis簡介

Redis是一款開源的、高效能的鍵-值儲存(key-value store)。它常被稱作是一款資料結構伺服器(data structure server)。Redis的鍵值可以包括字串(strings)型別,同時它還包括雜湊(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等資料型別。 對於這些資料型別,你可以執行原子操作。例如:對字串進行附加操作(append);遞增雜湊中的值;向列表中增加元素;計算集合的交集、並集與差集等。
為了獲得優異的效能,Redis採用了記憶體中(in-memory)資料集(dataset)的方式。同時,Redis支援資料的持久化,你可以每隔一段時間將資料集轉存到磁碟上(snapshot),或者在日誌尾部追加每一條操作命令(append only file,aof)。

Redis同樣支援主從複製(master-slave replication),並且具有非常快速的非阻塞首次同步( non-blocking first synchronization)、網路斷開自動重連等功能。同時Redis還具有其它一些特性,其中包括簡單的事物支援、釋出訂閱 ( pub/sub)、管道(pipeline)和虛擬記憶體(vm)等 。
Redis具有豐富的客戶端,支援現階段流行的大多數程式語言。php常用的是phpredis( http://redis.io/clients )

Redis安裝

下載最新穩定版 redis-3.2.3 ( http://redis.io/download )
tar zxvf redis-3.2.3   解壓縮


cd src              進入src目錄
make               編譯Redis
make test       可以測試一下(本步可省略)
make install    安裝,預設安裝目錄是 /usr/local/bin,生成如圖5個二進位制檔案,可以將其拷到新建目錄下,例如:  /usr/local/redis/bin


cp  原始碼/src/redis.conf   /usr/local/redis/etc     配置檔案複製
cd /usr/local/redis
./bin/redis-server ./etc/redis.conf                    啟動Redis服務
此時redis已經執行,但要獲得好的效能,還需要對配置檔案進行合理的配置

Redis配置

1. Redis預設不是以守護程序的方式執行,可以通過該配置項修改,使用yes啟用守護程序
    daemonize no
2. 當Redis以守護程序方式執行時,Redis預設會把pid寫入/var/run/redis.pid檔案,可以通過pidfile指定
    pidfile /var/run/redis.pid
3. 指定Redis監聽埠,預設埠為6379,作者在自己的一篇博文中解釋了為什麼選用6379作為預設埠,因為6379在手機按鍵上MERZ對應的號碼,而MERZ取自義大利歌女Alessia Merz的名字
    port 6379
4. 繫結的主機地址
    bind 127.0.0.1
5.當 客戶端閒置多長時間後關閉連線,如果指定為0,表示關閉該功能
    timeout 300
6. 指定日誌記錄級別,Redis總共支援四個級別:debug、verbose、notice、warning,預設為verbose
    loglevel verbose

7. 日誌記錄方式,預設為標準輸出,如果配置Redis為守護程序方式執行,而這裡又配置為日誌記錄方式為標準輸出,則日誌將會發送給/dev/null
    logfile stdout
8. 設定資料庫的數量,預設資料庫為0,可以使用SELECT <dbid>命令在連線上指定資料庫id
    databases 16
9. 指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案,可以多個條件配合
    save <seconds> <changes>
    Redis預設配置檔案中提供了三個條件:
    save 900 1
    save 300 10
    save 60 10000
    分別表示900秒(15分鐘)內有1個更改,300秒(5分鐘)內有10個更改以及60秒內有10000個更改。
10. 指定儲存至本地資料庫時是否壓縮資料,預設為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫檔案變的巨大
    rdbcompression yes

11. 指定本地資料庫檔名,預設值為dump.rdb
    dbfilename dump.rdb
12. 指定本地資料庫存放目錄
    dir ./
13. 設定當本機為slav服務時,設定master服務的IP地址及埠,在Redis啟動時,它會自動從master進行資料同步
    slaveof <masterip> <masterport>
14. 當master服務設定了密碼保護時,slav服務連線master的密碼
    masterauth <master-password>
15. 設定Redis連線密碼,如果配置了連線密碼,客戶端在連線Redis時需要通過AUTH <password>命令提供密碼,預設關閉
    requirepass foobared
16. 設定同一時間最大客戶端連線數,預設無限制,Redis可以同時開啟的客戶端連線數為Redis程序可以開啟的最大檔案描述符數,如果設定 maxclients 0,表示不作限制。當客戶端連線數到達限制時,Redis會關閉新的連線並向客戶端返回max number of clients reached錯誤資訊
    maxclients 128

17. 指定Redis最大記憶體限制,Redis在啟動時會把資料載入到記憶體中,達到最大記憶體後,Redis會先嚐試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大記憶體設定,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放記憶體,Value會存放在swap區
    maxmemory <bytes>
18. 指定是否在每次更新操作後進行日誌記錄,Redis在預設情況下是非同步的把資料寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的資料丟失。因為 redis本身同步資料檔案是按上面save條件來同步的,所以有的資料會在一段時間內只存在於記憶體中。預設為no
    appendonly no
19. 指定更新日誌檔名,預設為appendonly.aof
     appendfilename appendonly.aof
20. 指定更新日誌條件,共有3個可選值:    no:表示等作業系統進行資料快取同步到磁碟(快)    always:表示每次更新操作後手動呼叫fsync()將資料寫到磁碟(慢,安全)    everysec:表示每秒同步一次(折衷,預設值)
    appendfsync everysec

21. 指定是否啟用虛擬記憶體機制,預設值為no,簡單的介紹一下,VM機制將資料分頁存放,由Redis將訪問量較少的頁即冷資料swap到磁碟上,訪問多的頁面由磁碟自動換出到記憶體中(在後面的文章我會仔細分析Redis的VM機制)
     vm-enabled no
22. 虛擬記憶體檔案路徑,預設值為/tmp/redis.swap,不可多個Redis例項共享
     vm-swap-file /tmp/redis.swap
23. 將所有大於vm-max-memory的資料存入虛擬記憶體,無論vm-max-memory設定多小,所有索引資料都是記憶體儲存的(Redis的索引資料 就是keys),也就是說,當vm-max-memory設定為0的時候,其實是所有value都存在於磁碟。預設值為0
     vm-max-memory 0
24. Redis swap檔案分成了很多的page,一個物件可以儲存在多個page上面,但一個page上不能被多個物件共享,vm-page-size是要根據儲存的 資料大小來設定的,作者建議如果儲存很多小物件,page大小最好設定為32或者64bytes;如果儲存很大大物件,則可以使用更大的page,如果不 確定,就使用預設值
     vm-page-size 32
25. 設定swap檔案中的page數量,由於頁表(一種表示頁面空閒或使用的bitmap)是在放在記憶體中的,,在磁碟上每8個pages將消耗1byte的記憶體。
     vm-pages 134217728

26. 設定訪問swap檔案的執行緒數,最好不要超過機器的核數,如果設定為0,那麼所有對swap檔案的操作都是序列的,可能會造成比較長時間的延遲。預設值為4
     vm-max-threads 4
27. 設定在向客戶端應答時,是否把較小的包合併為一個包傳送,預設為開啟
    glueoutputbuf yes
28. 指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的雜湊演算法
    hash-max-zipmap-entries 64
    hash-max-zipmap-value 512
29. 指定是否啟用重置雜湊,預設為開啟
    activerehashing yes
30. 指定包含其它的配置檔案,可以在同一主機上多個Redis例項之間使用同一份配置檔案,而同時各個例項又擁有自己的特定配置檔案
    include /path/to/local.conf

Redis支援的資料型別

Keys 
非二進位制安全的字元型別( not binary-safe strings )
Values
Strings         (Binary-safe strings )
Lists              (Lists of binary-safe strings )
Sets              (Sets of binary-safe strings)
Sorted sets (Sorted sets of binary-safe strings )
Hash

redis本質上一個key-value 資料庫,所以我們首先來看看他的key.首先key也是字串型別,由於key不是binary safe的字串,所以像“my key”和“mykey\n”這樣包含空格和換行的key是不允許的。
我們在使用的時候可以自己定義一個Key的格式。例如 object-type:id:field 
Key不要太長。佔記憶體,查詢慢。
Key不要太短。u:1000:pwd   不如   user:1000:password  可讀性好

持久化

redis是一個支援持久化的記憶體資料庫,也就是說redis需要經常將記憶體中的資料同步到磁碟來保證持久化,這是相對memcache來說的一個大的優勢。redis支援兩種持久化方式,一種是 Snapshotting(快照)也是預設方式,另一種是Append-only file(縮寫aof)的方式。 
Snapshotting       快照是預設的持久化方式。這種方式將記憶體中資料以快照的方式寫入到二進位制檔案中,預設的檔名為dump.rdb。可以配置自動做快照持久 化的方式。我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是預設的快照儲存配置 save 900 1  #900秒內如果超過1個key被修改,則發起快照儲存 save 300 10 #300秒內容如超過10個key被修改,則發起快照儲存 save 60 10000

Append-only file     aof 比快照方式有更好的持久化性,是由於在使用aof持久化方式時,redis會將每一個收到的寫命令都通過write函式追加到檔案中(預設是 appendonly.aof)。當redis重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。當然由於os會在核心中快取 write做的修改,所以可能不是立即寫到磁碟上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過配置檔案告訴redis我們想要 通過fsync函式強制os寫入到磁碟的時機。有三種方式如下(預設是:每秒fsync一次) appendonly yes              //啟用aof持久化方式 # appendfsync always      //每次收到寫命令就立即強制寫入磁碟,最慢的,但是保證完全的持久化,不推薦使用 appendfsync everysec     //每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,推薦 # appendfsync no    //完全依賴os,效能最好,持久化沒保證

主從複製

主從複製允許多個slave server擁有和master server相同的資料庫副本。下面是關於redis主從複製的一些特點
1.master可以有多個slave
2.除了多個slave連到相同的master外,slave也可以連線其他slave形成圖狀結構
3.主從複製不會阻塞master。也就是說當一個或多個slave與master進行初次同步資料時,master可以繼續處理client發來的請求。相反slave在初次同步資料時則會阻塞,不能處理client的請求。
4.主從複製可以用來提高系統的可伸縮性(我們可以用多個slave 專門用於client的讀請求,比如sort操作可以使用slave來處理),也可以用來做簡單的資料冗餘。
5.可以在master禁用資料持久化,只需要註釋掉master 配置檔案中的所有save配置,然後只在slave上配置資料持久化。


事務






釋出訂閱(pub/sub )

釋出訂閱(pub/sub)是一種訊息通訊模式。訂閱者可以通過subscribe和psubscribe命令向redis server訂閱自己感興趣的訊息型別,redis將訊息型別稱為通道(channel)。當釋出者通過publish命令向redis server傳送特定型別的訊息時。訂閱該訊息型別的全部client都會收到此訊息。這裡訊息的傳遞是多對多的。一個client可以訂閱多個 channel,也可以向多個channel傳送訊息。
Subscribe
Unsubscribe
Psubscribe
Punsubscribe
Publish

釋出訂閱(pub/sub )演示

客戶端1


客戶端2


客戶端3


管道(pipeline)

redis是一個cs模式的tcp server,使用和http類似的請求響應協議。一個client可以通過一個socket連線發起多個請求命令。每個請求命令發出後client通常 會阻塞並等待redis服務處理,redis處理完後請求命令後會將結果通過響應報文返回給client。基本的通訊過程如下
Client: INCR X Server: 1 Client: INCR X Server: 2 Client: INCR X Server: 3 Client: INCR X Server: 4
基本上四個命令需要8個tcp報文才能完成。由於通訊會有網路延遲,假如從client和server之間的包傳輸時間需要0.125秒。那麼上面的四個命令8個報文至少會需要1秒才能完成。 
利用pipeline的方式從client打包多條命令一起發出,不需要等待單條命令的響應返回,而redis服務端會處理完多條命令後會將多條命令的處理結果打包到一起返回給客戶端。通訊過程如下 Client: INCR X Client: INCR X Client: INCR X Client: INCR X Server: 1 Server: 2 Server: 3 Server: 4

虛擬記憶體(vm)

redis沒有使用os提供的虛擬記憶體機制而是自己實現了自己的虛擬記憶體機制 ,但是思路和目的都是相同的。就是暫時把不經常訪問的資料從記憶體交換到磁碟中,從而騰出記憶體空間用於其他需要訪問的資料。尤其是對於redis這樣的記憶體資料庫,記憶體總是不夠用的。除了可以將資料分割到多個redis server外。另外的能夠提高資料庫容量的辦法就是使用vm把那些不經常訪問的資料交換的磁碟上。如果我們的儲存的資料總是有少部分資料被經常訪問,大 部分資料很少被訪問,對於網站來說確實總是隻有少量使用者經常活躍。當少量資料被經常訪問時,使用vm不但能提高單臺redis server資料庫的容量,而且也不會對效能造成太多影響。
vm-enabled yes                          #開啟vm功能
vm-swap-file /tmp/redis.swap         #交換的value儲存的檔案路徑/tmp/redis.swap
vm-max-memory 1000000            #最大記憶體上限,超過後開始交換value到磁碟檔案
vm-page-size 32                    #每個頁面的大小32個位元組
vm-pages 134217728                 #最多使用在檔案中使用多少頁面
vm-max-threads 4                    #用於執行value物件換入換出的工作執行緒數量,0表示不使用工作執行緒

redis效能


Redis部署


redis應用場景

1.取最新N個數據的操作
比如典型的取你網站的最新文章,通過下面方式,我們可以將最新的5000條評論的ID放在Redis的List集合中,並將超出集合部分從資料庫獲取
使用LPUSH latest.comments<ID>命令,向list集合中插入資料 
插入完成後再用LTRIM latest.comments 0 5000命令使其永遠只儲存最近5000個ID 
然後我們在客戶端獲取某一頁評論時可以用下面的邏輯(虛擬碼) 
FUNCTION get_latest_comments(start,num_items):
   id_list = redis.lrange("latest.comments",start,start+num_items-1)
   IF id_list.length < num_items 
   id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...") 
   END 
RETURN id_list 
END 
如果你還有不同的篩選維度,比如某個分類的最新N條,那麼你可以再建一個按此分類的List,只存ID的話,Redis是非常高效的。

2.排行榜應用,取TOP N操作
這個需求與上面需求的不同之處在於,前面操作以時間為權重,這個是以某個條件為權重,比如按頂的次數排序,這時候就需要我們的sorted set出馬了,將你要排序的值設定成sorted set的score,將具體的資料設定成相應的value,每次只需要執行一條ZADD命令即可。
3.需要精準設定過期時間的應用
比如你可以把上面說到的sorted set的score值設定成過期時間的時間戳,那麼就可以簡單地通過過期時間排序,定時清除過期資料了,不僅是清除Redis中的過期資料,你完全可以把Redis裡這個過期時間當成是對資料庫中資料的索引,用Redis來找出哪些資料需要過期刪除,然後再精準地從資料庫中刪除相應的記錄。
4.計數器應用
Redis的命令都是原子性的,你可以輕鬆地利用INCR,DECR命令來構建計數器系統。
5.Uniq操作,獲取某段時間所有資料排重值
這個使用Redis的set資料結構最合適了,只需要不斷地將資料往set中扔就行了,set意為集合,所以會自動排重。
6.實時系統,反垃圾系統
通過上面說到的set功能,你可以知道一個終端使用者是否進行了某個操作,可以找到其操作的集合並進行分析統計對比等。沒有做不到,只有想不到。
7.Pub/Sub構建實時訊息系統
Redis的Pub/Sub系統可以構建實時的訊息系統,比如很多用Pub/Sub構建的實時聊天系統的例子。
8.構建佇列系統
使用list可以構建佇列系統,使用sorted set甚至可以構建有優先順序的佇列系統。
9.做開源伺服器叢集session共享元件(tomcat,resin等)

Redis總結

Redis使用最佳方式是全部資料in-memory。 
Redis更多場景是作為Memcached的替代者來使用。 
當需要除key/value之外的更多資料型別支援時,使用Redis更合適。 
當儲存的資料不能被剔除時,使用Redis更合適。(持久化)