最近項目中需要使用Redis,剛好這兩天有時間,便總結記錄一下Redis的安裝,以及如何在.NET中使用Redis。
Redis是一個用的比較廣泛的Key/Value的內(nèi)存數(shù)據(jù)庫。目前新浪微博、Github、StackOverflow 等大型應用中都用其作為緩存,和Memcached類似,但是支持數(shù)據(jù)的持久化,解決了斷電后數(shù)據(jù)完全丟失的情況。而且它支持更多的類型,除了string外,還支持lists(鏈表)、sets(集合)和zsets(有序集合)幾種數(shù)據(jù)類型。
Redis的官網(wǎng)為: http://redis.io/。
1.Redis安裝
redis的安裝非常的簡單,而且Redis并不依賴其他環(huán)境和標準庫,很容易上手,這可能也是它流行的一個原因。這里為了測試方便,用的都是windows 環(huán)境下測試。下載Windows版本Redis。
redis.windows.conf //是redis的配置文件。 redis-server.exe //服務器端。 redis-cli //命令行客戶端。 redis-benchmark //Redis性能測試工具,測試Redis在你的系統(tǒng)及你的配置下的讀寫性能。
2.啟動服務
在命令行輸入如下命令 :
redis-server redis.windows.conf
同時也可以該命令保存為文件 startup.bat,下次就可以直接啟動了。
如果提示redis-server 不是內(nèi)部命令。將該目錄加到環(huán)境變量里面即可。
3. redis相關配置
1. port 端口號,例如6379
2. bind 實例綁定的訪問地址127.0.0.1
3. requirepass 訪問的密碼
4. maxheap 記得把這個配置節(jié)點打開,否者redis 服務無法啟動。例如maxheap 1024000000
5. timeout:請求超時時間
6. logfile:log文件位置
7. databases:開啟數(shù)據(jù)庫的數(shù)量
8. dbfilename:數(shù)據(jù)快照文件名(只是文件名,不包括目錄)
4. 連接測試
在命令行輸入如下命令:
redis-cli –h 127.0.0.1 –p 6379
參數(shù)分別為host、port,如果設置了密碼,則必須要加上-a 123456,123456為登錄密碼。否則會提示沒有權限登錄系統(tǒng)。
如下圖所示。
最后
以上就把redis 在windows 下的安裝和配置都講完了,是不是特別簡單。
其實linux 下的安裝和配置基本也差不多。
NoSQL介紹
Redis介紹
Redis的安裝
Redis的基本數(shù)據(jù)類型
SpringBoot整合Redis
Redis主從復制、安全、哨兵
Redis事物、持久化機制、發(fā)布與訂閱模式
Redis集群
NoSQL 是 Not Only SQL 的縮寫,意即"不僅僅是SQL"的意思,泛指非關系型的數(shù)據(jù)庫。強調(diào)Key-Value Stores和文檔數(shù)據(jù)庫的優(yōu)點,而不是單純的反對RDBMS。
NoSQL產(chǎn)品是傳統(tǒng)關系型數(shù)據(jù)庫的功能閹割版本,通過減少用不到或很少用的功能,來大幅度提高產(chǎn)品性能
NoSQL產(chǎn)品 redis、mongodb Membase、HBase
3.1什么是Redis?
Redis 是完全開源免費的,遵守BSD協(xié)議,是一個高性能的key-value數(shù)據(jù)庫。
Redis 與其他 key - value 緩存產(chǎn)品有以下三個特點:
Redis支持數(shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時候可以再次加載進行使用。
Redis不僅僅支持簡單的key-value類型的數(shù)據(jù),同時還提供list,set,zset,hash等數(shù)據(jù)結構的存儲。
Redis支持數(shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
3.2 Redis應用場景
主要能夠體現(xiàn) 解決數(shù)據(jù)庫的訪問壓力。
例如:短信驗證碼時間有效期、session共享解決方案
3.3 Redis優(yōu)勢
性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
豐富的數(shù)據(jù)類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作。
原子 – Redis的所有操作都是原子性的,同時Redis還支持對幾個操作全并后的原子性執(zhí)行。
豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
3.4 Redis與其他key-value存儲有什么不同?
Redis有著更為復雜的數(shù)據(jù)結構并且提供對他們的原子性操作,這是一個不同于其他數(shù)據(jù)庫的進化路徑。Redis的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結構的同時對程序員透明,無需進行額外的抽象。
Redis運行在內(nèi)存中但是可以持久化到磁盤,所以在對不同數(shù)據(jù)集進行高速讀寫時需要權衡內(nèi)存,因為數(shù)據(jù)量不能大于硬件內(nèi)存。在內(nèi)存數(shù)據(jù)庫方面的另一個優(yōu)點是,相比在磁盤上相同的復雜的數(shù)據(jù)結構,在內(nèi)存中操作起來非常簡單,這樣Redis可以做很多內(nèi)部復雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產(chǎn)生的,因為他們并不需要進行隨機訪問。
4.1 windows 安裝redis
4.2 linux 安裝redis
Redis的官方下載網(wǎng)址是:http://redis.io/download (這里下載的是Linux版的Redis源碼包)
Redis服務器端的默認端口是6379。
這里以虛擬機中的Linux系統(tǒng)如何安裝Redis進行講解。
在windows系統(tǒng)中下載好Redis的源碼包。
PING 結果表示成功
4.2.4 停止redis
redis-cli shutdown 或者 kill redis進程的pid
4.2.5 關閉防火墻
使用redisclient-win32.x86.1.5
6.1 字符串類型(String)
redis 127.0.0.1:6379> SET mykey "redis" OK redis 127.0.0.1:6379> GET mykey "redis"
在上面的例子中,SET和GET是redis中的命令,而mykey是鍵的名稱。
Redis字符串命令用于管理Redis中的字符串值。以下是使用Redis字符串命令的語法。
redis 127.0.0.1:6379> COMMAND KEY_NAME
示例
redis 127.0.0.1:6379> SET mykey "redis" OK redis 127.0.0.1:6379> GET mykey "redis"
在上面的例子中,SET和GET是redis中的命令,而mykey是鍵的名稱。
Redis字符串命令
下表列出了一些用于在Redis中管理字符串的基本命令。
編號命令描述說明
1SET key value此命令設置指定鍵的值。
2GET key獲取指定鍵的值。
3GETRANGE key start end獲取存儲在鍵上的字符串的子字符串。
4GETSET key value設置鍵的字符串值并返回其舊值。
5GETBIT key offset返回在鍵處存儲的字符串值中偏移處的位值。
6MGET key1 [key2…]獲取所有給定鍵的值
7SETBIT key offset value存儲在鍵上的字符串值中設置或清除偏移處的位
8SETEX key seconds value使用鍵和到期時間來設置值
9SETNX key value設置鍵的值,僅當鍵不存在時
10SETRANGE key offset value在指定偏移處開始的鍵處覆蓋字符串的一部分
11STRLEN key獲取存儲在鍵中的值的長度
12MSET key value [key value …]為多個鍵分別設置它們的值
13MSETNX key value [key value …]為多個鍵分別設置它們的值,僅當鍵不存在時
14PSETEX key milliseconds value設置鍵的值和到期時間(以毫秒為單位)
15INCR key將鍵的整數(shù)值增加1
16INCRBY key increment將鍵的整數(shù)值按給定的數(shù)值增加
17INCRBYFLOAT key increment將鍵的浮點值按給定的數(shù)值增加
18DECR key將鍵的整數(shù)值減1
19DECRBY key decrement按給定數(shù)值減少鍵的整數(shù)值
20APPEND key value將指定值附加到鍵
6.2 列表類型(List)
Redis列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)
一個列表最多可以包含 232 - 1 個元素 (4294967295, 每個列表超過40億個元素)。
redis 127.0.0.1:6379> LPUSH runoobkey redis (integer) 1 redis 127.0.0.1:6379> LPUSH runoobkey mongodb (integer) 2 redis 127.0.0.1:6379> LPUSH runoobkey mysql (integer) 3 redis 127.0.0.1:6379> LRANGE runoobkey 0 10 1) "mysql" 2) "mongodb" 3) "redis"
Redis 列表命令
下表列出了列表相關的基本命令:
序號命令及描述
1BLPOP key1 [key2 ] timeout
移出并獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發(fā)現(xiàn)可彈出元素為止。
2BRPOP key1 [key2 ] timeout
移出并獲取列表的最后一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發(fā)現(xiàn)可彈出元素為止。
3BRPOPLPUSH source destination timeout
從列表中彈出一個值,將彈出的元素插入到另外一個列表中并返回它; 如果列表沒有元素會阻塞列表直到等待超時或發(fā)現(xiàn)可彈出元素為止。
4LINDEX key index
通過索引獲取列表中的元素
5LINSERT key BEFORE|AFTER pivot value
在列表的元素前或者后插入元素
6LLEN key
獲取列表長度
7LPOP key
移出并獲取列表的第一個元素
8LPUSH key value1 [value2]
將一個或多個值插入到列表頭部
9LPUSHX key value
將一個值插入到已存在的列表頭部
10LRANGE key start stop
獲取列表指定范圍內(nèi)的元素
11LREM key count value
移除列表元素
12LSET key index value
通過索引設置列表元素的值
13LTRIM key start stop
對一個列表進行修剪(trim),就是說,讓列表只保留指定區(qū)間內(nèi)的元素,不在指定區(qū)間之內(nèi)的元素都將被刪除。
14RPOP key
移除并獲取列表最后一個元素
15RPOPLPUSH source destination
移除列表的最后一個元素,并將該元素添加到另一個列表并返回
16RPUSH key value1 [value2]
在列表中添加一個或多個值
17RPUSHX key value
為已存在的列表添加值
6.3 Redis 集合(Set)
Redis的Set是string類型的無序集合。集合成員是唯一的,這就意味著集合中不能出現(xiàn)重復的數(shù)據(jù)。
Redis 中 集合是通過哈希表實現(xiàn)的,所以添加,刪除,查找的復雜度都是O(1)。
集合中最大的成員數(shù)為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。
實例
redis 127.0.0.1:6379> SADD runoobkey redis (integer) 1 redis 127.0.0.1:6379> SADD runoobkey mongodb (integer) 1 redis 127.0.0.1:6379> SADD runoobkey mysql (integer) 1 redis 127.0.0.1:6379> SADD runoobkey mysql (integer) 0 redis 127.0.0.1:6379> SMEMBERS runoobkey 1) "mysql" 2) "mongodb" 3) "redis"
在以上實例中我們通過 SADD 命令向名為 runoobkey 的集合插入的三個元素。
Redis 集合命令
下表列出了 Redis 集合基本命令:
序號命令及描述
1SADD key member1 [member2]
向集合添加一個或多個成員
2SCARD key
獲取集合的成員數(shù)
3SDIFF key1 [key2]
返回給定所有集合的差集
4SDIFFSTORE destination key1 [key2]
返回給定所有集合的差集并存儲在 destination 中
5SINTER key1 [key2]
返回給定所有集合的交集
6SINTERSTORE destination key1 [key2]
返回給定所有集合的交集并存儲在 destination 中
7SISMEMBER key member
判斷 member 元素是否是集合 key 的成員
8SMEMBERS key
返回集合中的所有成員
9SMOVE source destination member
將 member 元素從 source 集合移動到 destination 集合
10SPOP key
移除并返回集合中的一個隨機元素
11SRANDMEMBER key [count]
返回集合中一個或多個隨機數(shù)
12SREM key member1 [member2]
移除集合中一個或多個成員
13SUNION key1 [key2]
返回所有給定集合的并集
14SUNIONSTORE destination key1 [key2]
所有給定集合的并集存儲在 destination 集合中
15SSCAN key cursor [MATCH pattern] [COUNT count]
迭代集合中的元素
6.4 Redis 有序集合(sorted set)
Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯(lián)一個double類型的分數(shù)。redis正是通過分數(shù)來為集合中的成員進行從小到大的排序。
有序集合的成員是唯一的,但分數(shù)(score)卻可以重復。
集合是通過哈希表實現(xiàn)的,所以添加,刪除,查找的復雜度都是O(1)。 集合中最大的成員數(shù)為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。
實例
redis 127.0.0.1:6379> ZADD runoobkey 1 redis (integer) 1 redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb (integer) 1 redis 127.0.0.1:6379> ZADD runoobkey 3 mysql (integer) 1 redis 127.0.0.1:6379> ZADD runoobkey 3 mysql (integer) 0 redis 127.0.0.1:6379> ZADD runoobkey 4 mysql (integer) 0 redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES 1) "redis" 2) "1" 3) "mongodb" 4) "2" 5) "mysql" 6) "4"
在以上實例中我們通過命令 ZADD 向 redis 的有序集合中添加了三個值并關聯(lián)上分數(shù)。
Redis 有序集合命令
下表列出了 redis 有序集合的基本命令:
序號命令及描述
1ZADD key score1 member1 [score2 member2]
向有序集合添加一個或多個成員,或者更新已存在成員的分數(shù)
2ZCARD key
獲取有序集合的成員數(shù)
3ZCOUNT key min max
計算在有序集合中指定區(qū)間分數(shù)的成員數(shù)
4ZINCRBY key increment member
有序集合中對指定成員的分數(shù)加上增量 increment
5ZINTERSTORE destination numkeys key [key …]
計算給定的一個或多個有序集的交集并將結果集存儲在新的有序集合 key 中
6ZLEXCOUNT key min max
在有序集合中計算指定字典區(qū)間內(nèi)成員數(shù)量
7ZRANGE key start stop [WITHSCORES]
通過索引區(qū)間返回有序集合成指定區(qū)間內(nèi)的成員
8ZRANGEBYLEX key min max [LIMIT offset count]
通過字典區(qū)間返回有序集合的成員
9ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]
通過分數(shù)返回有序集合指定區(qū)間內(nèi)的成員
10ZRANK key member
返回有序集合中指定成員的索引
11ZREM key member [member …]
移除有序集合中的一個或多個成員
12ZREMRANGEBYLEX key min max
移除有序集合中給定的字典區(qū)間的所有成員
13ZREMRANGEBYRANK key start stop
移除有序集合中給定的排名區(qū)間的所有成員
14ZREMRANGEBYSCORE key min max
移除有序集合中給定的分數(shù)區(qū)間的所有成員
15ZREVRANGE key start stop [WITHSCORES]
返回有序集中指定區(qū)間內(nèi)的成員,通過索引,分數(shù)從高到底
16ZREVRANGEBYSCORE key max min [WITHSCORES]
返回有序集中指定分數(shù)區(qū)間內(nèi)的成員,分數(shù)從高到低排序
17ZREVRANK key member
返回有序集合中指定成員的排名,有序集成員按分數(shù)值遞減(從大到小)排序
18ZSCORE key member
返回有序集中,成員的分數(shù)值
19ZUNIONSTORE destination numkeys key [key …]
計算給定的一個或多個有序集的并集,并存儲在新的 key 中
20ZSCAN key cursor [MATCH pattern] [COUNT count]
迭代有序集合中的元素(包括元素成員和元素分值)
6.5 Redis 哈希(Hash)
Redis hash 是一個string類型的field和value的映射表,hash特別適合用于存儲對象。
Redis 中每個 hash 可以存儲 232 - 1 鍵值對(40多億)。
實例
127.0.0.1:6379> HMSET runoobkey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000 OK 127.0.0.1:6379> HGETALL runoobkey 1) "name" 2) "redis tutorial" 3) "description" 4) "redis basic commands for caching" 5) "likes" 6) "20" 7) "visitors" 8) "23000"
hset key mapHey MapValue
在以上實例中,我們設置了 redis 的一些描述信息(name, description, likes, visitors) 到哈希表的 runoobkey 中。
Redis hash 命令
下表列出了 redis hash 基本的相關命令:
序號命令及描述
1HDEL key field2 [field2]
刪除一個或多個哈希表字段
2HEXISTS key field
查看哈希表 key 中,指定的字段是否存在。
3HGET key field
獲取存儲在哈希表中指定字段的值。
4HGETALL key
獲取在哈希表中指定 key 的所有字段和值
5HINCRBY key field increment
為哈希表 key 中的指定字段的整數(shù)值加上增量 increment 。
6HINCRBYFLOAT key field increment
為哈希表 key 中的指定字段的浮點數(shù)值加上增量 increment 。
7HKEYS key
獲取所有哈希表中的字段
8HLEN key
獲取哈希表中字段的數(shù)量
9HMGET key field1 [field2]
獲取所有給定字段的值
10HMSET key field1 value1 [field2 value2 ]
同時將多個 field-value (域-值)對設置到哈希表 key 中。
11HSET key field value
將哈希表 key 中的字段 field 的值設為 value 。
12HSETNX key field value
只有在字段 field 不存在時,設置哈希表字段的值。
13HVALS key
獲取哈希表中所有值
14HSCAN key cursor [MATCH pattern] [COUNT count]
迭代哈希表中的鍵值對。
7.1 引入Maven依賴
<!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
7.2 Java代碼
public class TestRedis { private Jedis jedis; @Before public void setup() { //連接redis服務器,192.168.0.100:6379 jedis=new Jedis("192.168.0.100", 6379); //權限認證 jedis.auth("admin"); } /** * redis存儲字符串 */ @Test public void testString() { //-----添加數(shù)據(jù)---------- jedis.set("name","xinxin");//向key-->name中放入了value-->xinxin System.out.println(jedis.get("name"));//執(zhí)行結果:xinxin jedis.append("name", " is my lover"); //拼接 System.out.println(jedis.get("name")); jedis.del("name"); //刪除某個鍵 System.out.println(jedis.get("name")); //設置多個鍵值對 jedis.mset("name","liuling","age","23","qq","476777XXX"); jedis.incr("age"); //進行加1操作 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq")); } /** * redis操作Map */ @Test public void testMap() { //-----添加數(shù)據(jù)---------- Map<String, String> map=new HashMap<String, String>(); map.put("name", "xinxin"); map.put("age", "22"); map.put("qq", "123456"); jedis.hmset("user",map); //取出user中的name,執(zhí)行結果:[minxr]-->注意結果是一個泛型的List //第一個參數(shù)是存入redis中map對象的key,后面跟的是放入map中的對象的key,后面的key可以跟多個,是可變參數(shù) List<String> rsmap=jedis.hmget("user", "name", "age", "qq"); System.out.println(rsmap); //刪除map中的某個鍵值 jedis.hdel("user","age"); System.out.println(jedis.hmget("user", "age")); //因為刪除了,所以返回的是null System.out.println(jedis.hlen("user")); //返回key為user的鍵中存放的值的個數(shù)2 System.out.println(jedis.exists("user"));//是否存在key為user的記錄 返回true System.out.println(jedis.hkeys("user"));//返回map對象中的所有key System.out.println(jedis.hvals("user"));//返回map對象中的所有value Iterator<String> iter=jedis.hkeys("user").iterator(); while (iter.hasNext()){ String key=iter.next(); System.out.println(key+":"+jedis.hmget("user",key)); } } /** * jedis操作List */ @Test public void testList(){ //開始前,先移除所有的內(nèi)容 jedis.del("java framework"); System.out.println(jedis.lrange("java framework",0,-1)); //先向key java framework中存放三條數(shù)據(jù) jedis.lpush("java framework","spring"); jedis.lpush("java framework","struts"); jedis.lpush("java framework","hibernate"); //再取出所有數(shù)據(jù)jedis.lrange是按范圍取出, // 第一個是key,第二個是起始位置,第三個是結束位置,jedis.llen獲取長度 -1表示取得所有 System.out.println(jedis.lrange("java framework",0,-1)); jedis.del("java framework"); jedis.rpush("java framework","spring"); jedis.rpush("java framework","struts"); jedis.rpush("java framework","hibernate"); System.out.println(jedis.lrange("java framework",0,-1)); } /** * jedis操作Set */ @Test public void testSet(){ //添加 jedis.sadd("user","liuling"); jedis.sadd("user","xinxin"); jedis.sadd("user","ling"); jedis.sadd("user","zhangxinxin"); jedis.sadd("user","who"); //移除noname jedis.srem("user","who"); System.out.println(jedis.smembers("user"));//獲取所有加入的value System.out.println(jedis.sismember("user", "who"));//判斷 who 是否是user集合的元素 System.out.println(jedis.srandmember("user")); System.out.println(jedis.scard("user"));//返回集合的元素個數(shù) } @Test public void test() throws InterruptedException { //jedis 排序 //注意,此處的rpush和lpush是List的操作。是一個雙向鏈表(但從表現(xiàn)來看的) jedis.del("a");//先清除數(shù)據(jù),再加入數(shù)據(jù)進行測試 jedis.rpush("a", "1"); jedis.lpush("a","6"); jedis.lpush("a","3"); jedis.lpush("a","9"); System.out.println(jedis.lrange("a",0,-1));// [9, 3, 6, 1] System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //輸入排序后結果 System.out.println(jedis.lrange("a",0,-1)); } @Test public void testRedisPool() { RedisUtil.getJedis().set("newname", "中文測試"); System.out.println(RedisUtil.getJedis().get("newname")); }
8.1、引入maven依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
8.2、新增配置文件信息
######################################################## ###Redis (RedisConfiguration) ######################################################## spring.redis.database=0 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=123456 spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 spring.redis.timeout=5000
8.3、Java代碼
@Service
public class RedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void setStr(String key, String value) {
setStr(key, value, null);
}
public void setStr(String key, String value, Long time) {
stringRedisTemplate.opsForValue().set(key, value);
if (time !=null)
stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
}
public Object getKey(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
public void delKey(String key) {
stringRedisTemplate.delete(key);
}
}
克隆三臺linux虛擬機
9.1.1、克隆虛擬機
9.1.2、生成新的mack地址
9.1.3、主從復制配置
redis主從復制
概述
1、redis的復制功能是支持多個數(shù)據(jù)庫之間的數(shù)據(jù)同步。一類是主數(shù)據(jù)庫(master)一類是從數(shù)據(jù)庫(slave),主數(shù)據(jù)庫可以進行讀寫操作,當發(fā)生寫操作的時候自動將數(shù)據(jù)同步到從數(shù)據(jù)庫,而從數(shù)據(jù)庫一般是只讀的,并接收主數(shù)據(jù)庫同步過來的數(shù)據(jù),一個主數(shù)據(jù)庫可以有多個從數(shù)據(jù)庫,而一個從數(shù)據(jù)庫只能有一個主數(shù)據(jù)庫。
2、通過redis的復制功能可以很好的實現(xiàn)數(shù)據(jù)庫的讀寫分離,提高服務器的負載能力。主數(shù)據(jù)庫主要進行寫操作,而從數(shù)據(jù)庫負責讀操作。
主從復制過程
主從復制過程:見下圖
過程:
1:當一個從數(shù)據(jù)庫啟動時,會向主數(shù)據(jù)庫發(fā)送sync命令,
2:主數(shù)據(jù)庫接收到sync命令后會開始在后臺保存快照(執(zhí)行rdb操作),并將保存期間接收到的命令緩存起來
3:當快照完成后,redis會將快照文件和所有緩存的命令發(fā)送給從數(shù)據(jù)庫。
4:從數(shù)據(jù)庫收到后,會載入快照文件并執(zhí)行收到的緩存的命令。
9.1.3.1 修改redis.conf
修改從redis中的 redis.conf文件
slaveof 192.168.33.130 6379
masterauth 123456— 主redis服務器配置了密碼,則需要配置
10.1 什么是哨兵機制
Redis的哨兵(sentinel) 系統(tǒng)用于管理多個 Redis 服務器,該系統(tǒng)執(zhí)行以下三個任務:
· 監(jiān)控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的Master和Slave是否運作正常。
· 提醒(Notification):當被監(jiān)控的某個 Redis出現(xiàn)問題時, 哨兵(sentinel) 可以通過 API 向管理員或者其他應用程序發(fā)送通知。
· 自動故障遷移(Automatic failover):當一個Master不能正常工作時,哨兵(sentinel) 會開始一次自動故障遷移操作,它會將失效Master的其中一個Slave升級為新的Master, 并讓失效Master的其他Slave改為復制新的Master; 當客戶端試圖連接失效的Master時,集群也會向客戶端返回新Master的地址,使得集群可以使用Master代替失效Master。
哨兵(sentinel) 是一個分布式系統(tǒng),你可以在一個架構中運行多個哨兵(sentinel) 進程,這些進程使用流言協(xié)議(gossipprotocols)來接收關于Master是否下線的信息,并使用投票協(xié)議(agreement protocols)來決定是否執(zhí)行自動故障遷移,以及選擇哪個Slave作為新的Master.
每個哨兵(sentinel) 會向其它哨兵(sentinel)、master、slave定時發(fā)送消息,以確認對方是否”活”著,如果發(fā)現(xiàn)對方在指定時間(可配置)內(nèi)未回應,則暫時認為對方已掛(所謂的”主觀認為宕機” Subjective Down,簡稱sdown).
若“哨兵群”中的多數(shù)sentinel,都報告某一master沒響應,系統(tǒng)才認為該master"徹底死亡"(即:客觀上的真正down機,Objective Down,簡稱odown),通過一定的vote算法,從剩下的slave節(jié)點中,選一臺提升為master,然后自動修改相關配置.
雖然哨兵(sentinel) 釋出為一個單獨的可執(zhí)行文件 redis-sentinel ,但實際上它只是一個運行在特殊模式下的 Redis 服務器,你可以在啟動一個普通 Redis 服務器時通過給定 --sentinel 選項來啟動哨兵(sentinel).
哨兵(sentinel) 的一些設計思路和zookeeper非常類似
單個哨兵(sentinel)
10.2 哨兵模式修改配置
實現(xiàn)步驟:
1.拷貝到etc目錄
cp sentinel.conf /usr/local/redis/etc
2.修改sentinel.conf配置文件
sentinel monitor mymast 192.168.110.133 6379 1 #主節(jié)點 名稱 IP 端口號 選舉次數(shù)
3. 修改心跳檢測 5000毫秒
sentinel down-after-milliseconds mymaster 5000
4.sentinel parallel-syncs mymaster 2 — 做多多少合格節(jié)點
5. 啟動哨兵模式
./redis-server /usr/local/redis/etc/sentinel.conf --sentinel &
6. 停止哨兵模式
11.1、Redis事物
Redis 事務可以一次執(zhí)行多個命令, 并且?guī)в幸韵聝蓚€重要的保證:
事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執(zhí)行。事務在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。
事務是一個原子操作:事務中的命令要么全部被執(zhí)行,要么全部都不執(zhí)行。
一個事務從開始到執(zhí)行會經(jīng)歷以下三個階段:
開始事務。
命令入隊。
執(zhí)行事務。
11.2、實例
以下是一個事務的例子, 它先以 MULTI 開始一個事務, 然后將多個命令入隊到事務中, 最后由 EXEC 命令觸發(fā)事務, 一并執(zhí)行事務中的所有命令:
redis 127.0.0.1:6379> MULTI OK redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" QUEUED redis 127.0.0.1:6379> GET book-name QUEUED redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series" QUEUED redis 127.0.0.1:6379> SMEMBERS tag QUEUED redis 127.0.0.1:6379> EXEC 1) OK 2) "Mastering C++ in 21 days" 3) (integer) 3 4) 1) "Mastering Series" 2) "C++" 3) "Programming"
11.3、Redis 事務命令
下表列出了 redis 事務的相關命令:
序號命令及描述
1DISCARD
取消事務,放棄執(zhí)行事務塊內(nèi)的所有命令。
2EXEC
執(zhí)行所有事務塊內(nèi)的命令。
3MULTI
標記一個事務塊的開始。
4UNWATCH
取消 WATCH 命令對所有 key 的監(jiān)視。
5WATCH key [key …]
監(jiān)視一個(或多個) key ,如果在事務執(zhí)行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷。
12.1、什么是Redis持久化
什么是Redis持久化,就是將內(nèi)存數(shù)據(jù)保存到硬盤。
Redis 持久化存儲 (AOF 與 RDB 兩種模式)
12.2、RDB持久化
RDB 是在某個時間點將數(shù)據(jù)寫入一個臨時文件,持久化結束后,用這個臨時文件替換上次持久化的文件,達到數(shù)據(jù)恢復。
優(yōu)點:使用單獨子進程來進行持久化,主進程不會進行任何 IO 操作,保證了 redis 的高性能
缺點:RDB 是間隔一段時間進行持久化,如果持久化之間 redis 發(fā)生故障,會發(fā)生數(shù)據(jù)丟失。所以這種方式更適合數(shù)據(jù)要求不嚴謹?shù)臅r候
這里說的這個執(zhí)行數(shù)據(jù)寫入到臨時文件的時間點是可以通過配置來自己確定的,通過配置redis 在 n 秒內(nèi)如果超過 m 個 key 被修改這執(zhí)行一次 RDB 操作。這個操作就類似于在這個時間點來保存一次 Redis 的所有數(shù)據(jù),一次快照數(shù)據(jù)。所有這個持久化方法也通常叫做 snapshots。
RDB 默認開啟,redis.conf 中的具體配置參數(shù)如下;
#dbfilename:持久化數(shù)據(jù)存儲在本地的文件 dbfilename dump.rdb #dir:持久化數(shù)據(jù)存儲在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動的redis-cli,則數(shù)據(jù)會存儲在當前src目錄下 dir ./ ##snapshot觸發(fā)的時機,save ##如下為900秒后,至少有一個變更操作,才會snapshot ##對于此值的設置,需要謹慎,評估系統(tǒng)的變更操作密集程度 ##可以通過“save “””來關閉snapshot功能 #save時間,以下分別表示更改了1個key時間隔900s進行持久化存儲;更改了10個key300s進行存儲;更改10000個key60s進行存儲。 save 900 1 save 300 10 save 60 10000 ##當snapshot時出現(xiàn)錯誤無法繼續(xù)時,是否阻塞客戶端“變更操作”,“錯誤”可能因為磁盤已滿/磁盤故障/OS級別異常等 stop-writes-on-bgsave-error yes ##是否啟用rdb文件壓縮,默認為“yes”,壓縮往往意味著“額外的cpu消耗”,同時也意味這較小的文件尺寸以及較短的網(wǎng)絡傳輸時間 rdbcompression yes
12.3、AOF持久化
Append-only file,將“操作 + 數(shù)據(jù)”以格式化指令的方式追加到操作日志文件的尾部,在 append 操作返回后(已經(jīng)寫入到文件或者即將寫入),才進行實際的數(shù)據(jù)變更,“日志文件”保存了歷史所有的操作過程;當 server 需要數(shù)據(jù)恢復時,可以直接 replay 此日志文件,即可還原所有的操作過程。AOF 相對可靠,它和 mysql 中 bin.log、apache.log、zookeeper 中 txn-log 簡直異曲同工。AOF 文件內(nèi)容是字符串,非常容易閱讀和解析。
優(yōu)點:可以保持更高的數(shù)據(jù)完整性,如果設置追加 file 的時間是 1s,如果 redis 發(fā)生故障,最多會丟失 1s 的數(shù)據(jù);且如果日志寫入不完整支持 redis-check-aof 來進行日志修復;AOF 文件沒被 rewrite 之前(文件過大時會對命令進行合并重寫),可以刪除其中的某些命令(比如誤操作的 flushall)。
缺點:AOF 文件比 RDB 文件大,且恢復速度慢。
我們可以簡單的認為 AOF 就是日志文件,此文件只會記錄“變更操作”(例如:set/del 等),如果 server 中持續(xù)的大量變更操作,將會導致 AOF 文件非常的龐大,意味著 server 失效后,數(shù)據(jù)恢復的過程將會很長;事實上,一條數(shù)據(jù)經(jīng)過多次變更,將會產(chǎn)生多條 AOF 記錄,其實只要保存當前的狀態(tài),歷史的操作記錄是可以拋棄的;因為 AOF 持久化模式還伴生了“AOF rewrite”。
AOF 的特性決定了它相對比較安全,如果你期望數(shù)據(jù)更少的丟失,那么可以采用 AOF 模式。如果 AOF 文件正在被寫入時突然 server 失效,有可能導致文件的最后一次記錄是不完整,你可以通過手工或者程序的方式去檢測并修正不完整的記錄,以便通過 aof 文件恢復能夠正常;同時需要提醒,如果你的 redis 持久化手段中有 aof,那么在 server 故障失效后再次啟動前,需要檢測 aof 文件的完整性。
AOF 默認關閉,開啟方法,修改配置文件 reds.conf:appendonly yes
##此選項為aof功能的開關,默認為“no”,可以通過“yes”來開啟aof功能
##只有在“yes”下,aof重寫/文件同步等特性才會生效
appendonly yes
##指定aof文件名稱
appendfilename appendonly.aof
##指定aof操作中文件同步策略,有三個合法值:always everysec no,默認為everysec
appendfsync everysec
##在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認為“no”
no-appendfsync-on-rewrite no
##aof文件rewrite觸發(fā)的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才會觸發(fā)rewrite,默認“64mb”,建議“512mb”
auto-aof-rewrite-min-size 64mb
##相對于“上一次”rewrite,本次rewrite觸發(fā)時aof文件應該增長的百分比。
##每一次rewrite之后,redis都會記錄下此時“新aof”文件的大小(例如A),那么當aof文件增長到A*(1 + p)之后
##觸發(fā)下一次rewrite,每一次aof記錄的添加,都會檢測當前aof文件的尺寸。
auto-aof-rewrite-percentage 100
AOF 是文件操作,對于變更操作比較密集的 server,那么必將造成磁盤 IO 的負荷加重;此外 linux 對文件操作采取了“延遲寫入”手段,即并非每次 write 操作都會觸發(fā)實際磁盤操作,而是進入了 buffer 中,當 buffer 數(shù)據(jù)達到閥值時觸發(fā)實際寫入(也有其他時機),這是 linux 對文件系統(tǒng)的優(yōu)化,但是這卻有可能帶來隱患,如果 buffer 沒有刷新到磁盤,此時物理機器失效(比如斷電),那么有可能導致最后一條或者多條 aof 記錄的丟失。通過上述配置文件,可以得知 redis 提供了 3 中 aof 記錄同步選項:
always:每一條 aof 記錄都立即同步到文件,這是最安全的方式,也以為更多的磁盤操作和阻塞延遲,是 IO 開支較大。
everysec:每秒同步一次,性能和安全都比較中庸的方式,也是 redis 推薦的方式。如果遇到物理服務器故障,有可能導致最近一秒內(nèi) aof 記錄丟失(可能為部分丟失)。
no:redis 并不直接調(diào)用文件同步,而是交給操作系統(tǒng)來處理,操作系統(tǒng)可以根據(jù) buffer 填充情況 / 通道空閑時間等擇機觸發(fā)同步;這是一種普通的文件操作方式。性能較好,在物理服務器故障時,數(shù)據(jù)丟失量會因 OS 配置有關。
其實,我們可以選擇的太少,everysec 是最佳的選擇。如果你非常在意每個數(shù)據(jù)都極其可靠,建議你選擇一款“關系性數(shù)據(jù)庫”吧。
AOF 文件會不斷增大,它的大小直接影響“故障恢復”的時間, 而且 AOF 文件中歷史操作是可以丟棄的。AOF rewrite 操作就是“壓縮”AOF 文件的過程,當然 redis 并沒有采用“基于原 aof 文件”來重寫的方式,而是采取了類似 snapshot 的方式:基于 copy-on-write,全量遍歷內(nèi)存中數(shù)據(jù),然后逐個序列到 aof 文件中。因此 AOF rewrite 能夠正確反應當前內(nèi)存數(shù)據(jù)的狀態(tài),這正是我們所需要的;rewrite 過程中,對于新的變更操作將仍然被寫入到原 AOF 文件中,同時這些新的變更操作也會被 redis 收集起來(buffer,copy-on-write 方式下,最極端的可能是所有的 key 都在此期間被修改,將會耗費 2 倍內(nèi)存),當內(nèi)存數(shù)據(jù)被全部寫入到新的 aof 文件之后,收集的新的變更操作也將會一并追加到新的 aof 文件中,此后將會重命名新的 aof 文件為 appendonly.aof, 此后所有的操作都將被寫入新的 aof 文件。如果在 rewrite 過程中,出現(xiàn)故障,將不會影響原 AOF 文件的正常工作,只有當 rewrite 完成之后才會切換文件,因為 rewrite 過程是比較可靠的。
觸發(fā) rewrite 的時機可以通過配置文件來聲明,同時 redis 中可以通過 bgrewriteaof 指令人工干預。
redis-cli -h ip -p port bgrewriteaof
因為 rewrite 操作 /aof 記錄同步 /snapshot 都消耗磁盤 IO,redis 采取了“schedule”策略:無論是“人工干預”還是系統(tǒng)觸發(fā),snapshot 和 rewrite 需要逐個被執(zhí)行。
AOF rewrite 過程并不阻塞客戶端請求。系統(tǒng)會開啟一個子進程來完成。
12.4、AOF與RDB區(qū)別
OF 和 RDB 各有優(yōu)缺點,這是有它們各自的特點所決定:
Redis 發(fā)布訂閱(pub/sub)是一種消息通信模式:發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。
Redis 客戶端可以訂閱任意數(shù)量的頻道。
下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關系:
當有新消息通過 PUBLISH 命令發(fā)送給頻道 channel1 時, 這個消息就會被發(fā)送給訂閱它的三個客戶端:
13.1實例
以下實例演示了發(fā)布訂閱是如何工作的。在我們實例中我們創(chuàng)建了訂閱頻道名為 redisChat:
redis 127.0.0.1:6379> SUBSCRIBE redisChat Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "redisChat" 3) (integer) 1
現(xiàn)在,我們先重新開啟個 redis 客戶端,然后在同一個頻道 redisChat 發(fā)布兩次消息,訂閱者就能接收到消息。
redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique" (integer) 1 redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com" (integer) 1 # 訂閱者的客戶端會顯示如下消息 1) "message" 2) "redisChat" 3) "Redis is a great caching technique" 1) "message" 2) "redisChat" 3) "Learn redis by runoob.com"
Redis 發(fā)布訂閱命令
下表列出了 redis 發(fā)布訂閱常用命令:
序號命令及描述
1PSUBSCRIBE pattern [pattern …]
訂閱一個或多個符合給定模式的頻道。
2PUBSUB subcommand [argument [argument …]]
查看訂閱與發(fā)布系統(tǒng)狀態(tài)。
3PUBLISH channel message
將信息發(fā)送到指定的頻道。
4PUNSUBSCRIBE [pattern [pattern …]]
退訂所有給定模式的頻道。
5SUBSCRIBE channel [channel …]
訂閱給定的一個或多個頻道的信息。
6UNSUBSCRIBE [channel [channel …]]
指退訂給定的頻道。