由於工作慢慢從原來的少量用戶的企業內部應用慢慢轉化為了大量用戶的企業內部應用或者直接轉為了線上高並發應用,因而也漸漸的開始使用memcached、Redis等緩存服務器,為了便於自身的學習和記憶,特此成文。本文以window下的redis使用為例,實際中redis服務器會搭建在Linux服務器上。

-
Redis核心特性簡潔
借鑒知乎大牛的評價,Redis的快是因為:單進程單線程的避免了不必要的上下文切換和競爭條件;其絕大多數操作都是內存操作,雖然也支持虛擬內存;非阻塞IO。、
需要理解的幾個知識點:
單進程單線程:Redis是以實例為單位的,當多個連接請求服務時,實際還是串行的。記得之前看到Redis中有Database的概念,當時還產生過懷疑,就是是不是以database為維度來看,問過身邊的技術大牛,大體是認為這只是一個數據存儲區域的划分,便於管理,而不干擾單線程的概念。
Epoll(poll:投票): 這是一個Linux的概念,常常在ngnix和apache比較時提及。簡單來說就是,異步的處理請求,當一個連接請求服務時,服務器並不是馬上給它創建一個線程,然后等待獲取資源后得到服務,而是將該請求打包到一個請求隊列中,按照順序一個個的被服務,因此不會浪費線程資源,也就造成了nginx最大連接數是apache的很多倍。因為redis是單線程的,所以所有的並發請求都會被放入隊列。
No blocking IO: 非阻塞IO在Redis中就比如說,當連接在獲取pop一個list中的數據時,如果當前list沒有就會直接返回nil,而不會等待其他連接設置該值。簡單來說就是,有就是有,沒有就是沒有,爺不等你。
-
Redis所支持的數據結構包括以下五種(這樣看起來還是比memcached豐富很多):
String:字符串、整數和浮點數,與memcached相似
List:是一個字符串鏈表,支持對鏈表的兩端進行push/pop操作
Set:是一個支持沒有重復數據的無序字符串集合,支持常見集合操作(交、並、差)
Hash:是一張哈希表,(Redis其實也是一張hash表,只是value可以有5中類型)
Zset:一個無重復的有序集合,每個字符串映射到一個浮點數分數,按分數排序
-
Redis服務器安裝包所包含工具:
Redis-server: Redis服務器的daemon啟動程序
Redis-cli: Redis命令行操作工具,-h表示主機名或ip,-p表示端口號
Redis-benchmark: Redis性能測試工具,測試redis在你的系統及配置下的讀寫性能,跑跑感覺還停炫酷,俺機器10000requests完成時間在0.24秒
Redis-stat: Redis狀態監測工具,可以監測Redis當前狀態及延遲狀況
Redis-check-dump: Redis dump數據文件的修復工具,dump數據文件在本章后面會講到
Redis-check-aof: Redis aof日志文件修復工具
-
配置文件參數解釋
| 參數 | 解釋 |
| Daemonize | Linux中shell終止會退出,因而需要設置為支持 |
| Pidfile | Pid文件位置 |
| Port | 監聽的端口號 |
| Timeout | 當客戶端長時間無請求,服務器會關閉該連接 |
| Loglevel | Log信息級別,總共支持四個級別,debug、verbose(冗長的)、notice、warning |
| Logfile | Log文件位置 |
| databases | 開啟數據庫的數量,使用"select庫ID"方式切換操作各個數據庫 |
| Save** | 保存快照的頻率,第一個*表示多長時間,第三個*表示執行多少次寫操作 |
| Rdbcompression | 是否使用壓縮 |
| Dbfilename | 數據快照文件名,默認dump.rdb |
| Dir | 數據快照的保存目錄 |
| Appendonly | 是否開啟appendonlylog,開啟后每次寫操作會記一條log,這會提高數據抗分險能力,但影響效率 |
| appendfsync | Appendonlylog如何同步到磁盤(三個選項,分別是always每次寫都強制調用fsync、everysec每秒啟用一次fsync、no不調用fsync等待系統自己同步) |
-
事務
讓我萬萬沒有想到的是,Redis作為NoSQL數據庫同樣提供了事務機制,並且使用起來非常的便捷,概念上也和SQL版本的事務操作一一對應,真心點個贊,接下來用一個表格簡述。
| Redis事務操作 | 對應SQL中的事務操作 | 解釋 |
| MULTI | BEGIN TRANSACTION | 開啟事務 |
| EXEC | COMMIT | 提交事務 |
| DISCARD | ROLLBACK | 回滾事務 |
| WATCH, UNWATCH | 監控指定的key,如果出現修改,則回滾整個事務 |
Tip:
-
Redis中事務存在部分提交,即在一段事務中有的部分出錯不會影響事務的正常運行,這一點和關系型數據庫的事務模型有很大的區別。
-
在Append-Only模式下,Redis會將事務內所有的寫操作全部寫入磁盤,如果在寫入過程中出現意外,Redis會在重啟時執行一致性檢測,如出項此類問題會提示錯誤信息,此時我們可以受用redis-check-aof工具對該部分進行回滾,修復服務器。
-
WATCH命令可以提供基於CAS(check-and-set)的樂觀鎖機制。例如多個連接同時修改某個key時會存在競態征用的情況,注意這個征用於Redis的單線程機制無關,而是由於我們在應用程序中緩存了數據,造成設置時的問題。
| Var = GET mykey Val = val + 1 SET mykey $val | WATCH mykey Val = GET mykey Val = val + 1 MULTI SET mykey $val EXEC |
-
Redis的主從復制
在Redis中配置Master-Slave非常的簡單,其中一個Master可以同步多個Slave,Slave也可以相互同步,類似一種樹形結構,Master/Slave Server均采用非阻塞的方式同步數據,一般來說還是使用Master寫,Slave讀的讀寫分離的方式。同步機制的大體過程為,Slave啟動並連接到Master后,它將主動發送一個SYNC命令。之后Master將啟動后台存盤進程,同時收集和處理數據集修改命令,然后將整個數據庫文件發送到Slave完成一次同步。
Slave的配置
可以命令行配置也可以新增配置文件配置,后者更加方便。只需在新建的Slave配置文件中添加如下內容即可完成單機多Redis服務器的配置:
port 6480 ;Slaveof 127.0.0.1 6379
-
Redis的持久化
快照snapshot,默認情況下,Redis會將數據集的快照dump到dump.rdb文件中,可以通過修改配置文件來修改Redis服務器快照的頻率,對應redis.conf文件中的save配置節點。Dump快照的機制是:Redis先fork子進程;子進程將快照數據寫入到臨時RDB文件中;當子進程完成寫入后,再用臨時文件代替老的文件。
AOF文件,如果應用場景需要很高的數據持久性,可以使用aof機制,將appendonly配置節設置為開啟,之后再啟動redis就會加載AOF文件的信息來構建最新的數據到內存。其同步方式的配置包括appendfsync always/everysec/no。當出現AOF文件壞損時,先復制一份損壞文件,然后執行redis-check-aof --fix<filename>命令來修復壞損的AOF文件。
Tip:在Redis中可以使用copy的方式在線備份正在運行的Redis數據文件,redis每次dump都是將內容先保存在一個臨時文件中,之后利用rename變更文件名,因此任意時間copy的數據文件都是安全和一致的,因此在實踐中(linux環境下)可以通過cron job的方式備份Redis數據文件。
-
其他
Redis中數據集過大時,可以考慮在所有的Keys和常用的10%左右的Keys對應的values存儲在內存的情況下,將不常用90%的Values放在硬盤中,不過這種用法並不是非常的推薦,如果要使用盡量將交換文件放在固態硬盤中,其相關的配置如下所示:
| Vm-enable yes; Vm-max-memory (bytes); vm-pages 100000; vm-page-size 32; vm-max-threads 4 |

-
使用步驟
-
啟動Redis
D:\redis>redis-server.exe redis.conf
Tip: 需要注意的是在window7 64位系統中需要在maxheap修正設置
# maxheap <bytes>
maxheap 1024000000
-
開啟客戶端工具進行測試
D:\redis>redis-cli.exe -h 127.0.0.1 -p 6379
這兒直接雙擊客戶端工具也是OK的,默認監聽端口為6379
-
設置值和獲取值
127.0.0.1:6379>set city Beijing
127.0.0.1:6379>get city
這樣redis最簡單的使用就完成了,是不是So easy!
Tip:Windows版本下載路徑MSOpenTech/redis on Windows https://github.com/MSOpenTech/redis

Redis在.net平台下最常見的組件時StackExchange.Redis和ServiceStack.Redis,前者是現在的主流,后者已經由原有的開源免費轉化為了商業軟件,不支持學習。它們的安裝都非常方便,在Nuget中查詢redis,前兩個就是。StackExchange.Redis客戶端組件的詳細學習推薦大家去"吾破"大神的博客http://www.cnblogs.com/bnbqian/p/4962855.html看看,其API的使用相對比較簡單,基本都可以和之后附加的命令對應,唯一需要注意的是客戶端連接基礎類ConnectionMultiplexer中配置正確的ConfigurationOptions。此外,Stephen Liu的Redis學習手冊非常詳細,也是很好的學習參考http://www.cnblogs.com/stephen-liu74/archive/2012/04/16/2370212.html,實際使用中有任何問題,歡迎大家和我一起探討。
Tip: 平時自己使用公司封裝的Redis組件相對比較簡單,只需要在配置系統中配置好Redis的名稱即可使用,其中使用生產者-消費者模式的隊列來控制並發。
StackExchange.Redis的使用文檔,http://www.cnblogs.com/bnbqian/p/4962855.html

| 命令 | 解釋 |
| String | |
| GET, SET, DEL | 讀取/設置/刪除值 |
| APPEND,GETRANGE, SETRANGE,GETBIT,SETBIT | 常見字符串操作 |
| Bitcount, bitop(AND\OR\NOT\XOR) | 前者為計算字符串中bit位為1的個數,后者為對兩個不同key進行位操作 |
| INCRBY, DECRBY | 前者是整數的遞增,遞減操作,后者為浮點數的相應操作。若不為數字型,系統會返回類型錯誤信息 |
| List | |
| RPUSH, lPUSH | 從右側、左側插入一個字符串 |
| LRANGE | 從list中取出一個范圍內的字符串,(0, -1)表示取出全部 |
| LINDEX, LLEN | 前者獲取指定為的字符串,index從0開始, 后者獲得列表長度 |
| LPOP, RPOP | 彈出左邊、右邊的字符串並返回它 |
| LTRIM,LLSET | 前者對List進行修剪,只保留范圍內的部分,后者設置list指定索引的值 |
| LINSERT list-name BEFORE valueA valueB | 在列表list-name中,將valueB插入到值valueA所對應子項之前 |
| RPOPLPUSH source destination | 在一個原子操作中,將列表source的尾部元素彈出插入到destination的頭部 |
| BLPOP, BRPOP timeout | 阻塞的方式彈出,可以設置超時時間,不太支持使用 |
| Set | |
| SADD, SREM | 添加\刪除元素 |
| SISMEMBER, SMEMBERS | 前者判斷指定元素是否在集合中;后者SMEMBERS返回所有元素,不推薦使用 |
| SCARD | 返回集合中元素個數 |
| SRANDMEMBER, SPOP | 前者返回隨機的元素;后者返回隨機元素並移除 |
| SMOVE source destination member | 將member元素從source移動到destination |
| SINTER,SUNION, SDIFF | 集合的交、並、差操作 |
| Hash | |
| HSET, HGET, HDEL, HEXISTS, HLEN, HINCRBY | 常見操作,添加元素,獲取元素,刪除元素,判斷存在,獲取大小,對hash值做遞增操作 |
| HSETNX | 前者相對之前的set操作多了一個判斷存在的操作,若存在就什么也不做,若不存在則插入 |
| HGETALL, HKEYS, HVALUES | 獲取所有的key和value並以單列列表的形式展示;獲取所有key;獲取所有value |
| HMGET, HMSET | 批量的添加和獲取 |
| Zset | |
| ZADD, ZCARD, ZCOUNT, ZREM | 添加;查詢數量;獲得指定的2個scores之間的數量;刪除指定對象 |
| ZRANGE[WITHSCORES],ZRANK, ZSCORE | 返回索引在start和stop之間的成員列表;獲得索引值;獲得分數,注意索引值是系統內置的,分數是設置的 |
| ZRANGEBYSORE[WITHSCORES] [LIMIT offset count] | 通過分數值獲取范圍內列表 |
| ZREVRANGE, ZREVRANK, ZREVRANGEBYSCORE | 反序操作 |
| ZREMRANGEBYRANK, ZREMRANGEBYSCORE | 通過索引或者分數刪除范圍內元素 |
| 多個ZSET的操作 | 相對比較復雜,建議需要時查看文檔 |
| Key | |
| KEYS pattern [*, ?, regex] | 查詢當前數據庫中指定條件的key |
| DEL key | 刪除指定的key,對於String元素時間復雜度為O(1),對於其他類型為O(n) |
| Exists key, TYPE key | 前者判斷key是否存在;后者獲取key的類型 |
| MOVE key db | 將當前數據庫中的key移動到指定的另一個數據庫 |
| RENAME, RENAMENX | 更換Key名稱 |
| PERSIST key | 將該key的過期時間移除,即持續有效 |
| EXPIRE/EXPIRE key seconds/timestamp | 設置指定key的超時時間 |
| TTL key, RANDOMKEY | 獲取該key的超時描述信息,無超時時間限制為-1; 隨機取一個key |
| TYPE key | |
| 補充 | |
| Flushdb | 清空當前選擇的數據庫 |
| Select n | 選擇指定數據庫,默認為16個,索引0-15 |
.更詳細的命令可以參見http://redis.io/commands
Tip:
Redis在Ubuntu下安裝非常簡單:sudo apt install redis-server即可,如果需要客戶端工具則再安裝redis-tools
在CentOS下,由於默認Yum沒有redis,需要先安裝epel源,yun install epel-release,然后安裝yum install redis即可,免得需要下載源碼在make install.之后通過chkconfig redis on, service redis start即可開啟服務。此外,centos作為默認的服務器發行版,會默認開啟防火牆iptables,可以添加自己允許訪問的接口,比如6379,vi /etc/sysconfig/iptables:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
之后重啟服務:service iptables restart,注意一定要ACCEPT放在REJECT之前。
推薦個redis client: https://github.com/caoxinyu/RedisClient.git
