ajax請求Token(未經測試)
阿新 • • 發佈:2020-07-16
- Redis是什麼
- 介紹:Redis是一個開源的key-value儲存系統。和Memcached類似,它支援儲存的value型別相對更多,包括string(字串)、list(連結串列)、set(集合)、zset(sorted set --有序集合)和hash(雜湊型別)。這些資料型別都支援push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,Redis支援各種不同方式的排序。與memcached一樣,為了保證效率,資料都是快取在記憶體中。區別的是Redis會週期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了master-slave(主從)同步。
- 常用位置
- 配合關係型資料庫做快取記憶體
- 高頻次,熱門訪問的資料,降低資料庫IO
- 實時計算中常常用於儲存臨時資料,用於存放以下特點的資料:
- 高頻次
- 讀寫時效性高
- 總資料量不大
- 臨時性
- 做分散式鎖:分散式鎖需要訪問資料和寫入資料兩個操作一起完成,因為redis是單執行緒的,保證了每個指令的原子性,而且有一個命令是setnx讓寫入和檢視在一起執行。所以經常用來做分散式鎖。
- Redis與類似產品的對比
- 和hbase對比
- 共同點
- 基於key-value(s)方式的儲存,不適合進行分析查詢。
- 不同點
- 資料量:hbase資料量遠遠大於redis
- 效能: Redis 存取效率更高,使用經常變化的資料。
- 資料儲存時效性:redis 更適用於高頻訪問的臨時資料
- hbase 更適合長期儲存
- 全量資料不再記憶體中
- 和Memcached對比
- 共同點
- key-value模式
- 一般是作為快取資料庫輔助持久化的資料庫
- 全量資料都在記憶體中
- 不同點
- redis還支援多種資料結構的儲存,比如 list、set、hash、zset等。Memcached只支援string
- redis支援持久化,主要用作備份恢復
- Redis啟動與配置
- 去官網下載包解壓
- 配置 redis.conf,也可不配置,直接使用自帶的配置檔案啟動,不改配置的話,只能在本機訪問。直接拷貝redis資料夾下的redis.conf檔案修改。
#後臺啟動
2daemonize yes
3 4# 開啟則遠端機器不能訪問redis-server,不開啟保護則遠端機器訪問時需要加密碼,requirepass項配置密碼
5# 如果開啟了protected-mode,那麼在沒有設定bind ip且沒有設密碼的情況下,Redis只允許接受本機的相應
6protected-mode no
7 8# 客戶端登入redis服務的密碼
9#requirepass 123
10 11#是繫結本機的IP地址,(準確的是:本機的網絡卡對應的IP地址,每一個網絡卡都有一個IP地址),而不是redis允許來自其他計算機的IP地址。
12# 生產環境要寫你應用伺服器的地址
13# bind 127.0.0.1
14 15#server埠號
16port 6379
17 18# rdb和aof檔案的儲存路徑,
19dir ./
20 21# rdb的檔名
22dbfilename dump6379.rdb
23 24# aof持久化開啟/關閉
25appendonly yes
26 27# aof的檔名稱
28appendfilename "appendonly6379.aof"
29 30# aof多久存檔一次,即同步頻率設定,共三種策略,一般選每秒存
31# 每次操作存
32#appendfsync always
33# 每秒存
34appendfsync everysec
35# 不主動進行同步,把同步時機交給作業系統 大約分鐘級
36#appendfsync no
37 38# 系統載入時或者上次重寫完畢時,Redis會記錄此時AOF大小,設為base_size,如果Redis的AOF當前大小>= base_size +base_size*100% (預設)且當前大小>=64mb(預設)的情況下,Redis會對AOF進行重寫
39auto-aof-rewrite-percentage 100
40auto-aof-rewrite-min-size 64mb
41 42# 程序號
43pidfile /var/run/redis_6379.pid
44 45# rdb的儲存策略 900秒之後存了一次、300秒之後存了10次、300秒之後存了10000次
46save 900 1
47save 300 10
48save 60 10000
49 50# 當Redis無法寫入磁碟的話,直接關掉Redis的寫操作
51stop-writes-on-bgsave-error yes
52 53# 進行rdb儲存時,將檔案壓縮
54rdbcompression yes
55 56#在儲存快照後,還可以讓Redis使用CRC64演算法來進行資料校驗,但是這樣做會增加大約10%的效能消耗,如果希望獲取到最大的效能提升,可以關閉此功能
57rdbchecksum yes
58 59# 在哨兵自動切換主機時,首先通過這個有限級判斷,越小越高
60slave-priority 100
- 啟動
- 服務端啟動
2
2
1
redis-server 配置檔案的名字
2# 如 redis-server redis.conf
- 客戶端啟動
4
4
1
redis-cli -h 主機 -p 埠
2#如 redis-cli -h 127.0.0.1 -p 6379
3 4# 若有密碼,再在客戶端執行 auth 密碼
- 測試驗證:
2
2
1
ping
2#返回pong成功
- 關閉服務
3
3
1
進入客戶端後執行shutdown
2或者
3直接 redis-cli -p 6378 shutdown
- Redis的命令列操作
- 選擇資料庫
4
4
1
# 預設16個數據庫,類似陣列下標從0開始,初始預設使用0號庫
2select <dbid>
3 4如 select 1
- 五大資料型別對應的操作
- 五大資料型別都可用的操作
16
16
1
keys *
2查詢當前庫的所有鍵
3exists <key>
4判斷某個鍵是否存在
5del <key>
6刪除某個鍵
7expire <key> <seconds>
8為鍵值設定過期時間,單位秒。
9ttl <key>
10檢視還有多少秒過期,-1表示永不過期,-2表示已過期
11dbsize
12檢視當前資料庫的key的數量
13flushdb
14清空當前庫
15flushall
16通殺全部庫(會觸發rdb存檔)
- String
23
23
1
String是Redis最基本的型別,你可以理解成與Memcached一模一樣的型別,一個key對應一個value。
2 3String型別是二進位制安全的。意味著Redis的string可以包含任何資料。比如jpg圖片或者序列化的物件。
4 5String型別是Redis最基本的資料型別,一個Redis中字串value最多可以是512M
6 7 8get <key>
9查詢對應鍵值
10set <key> <value>
11新增鍵值對
12setex <key> <過期時間> <value>
13設定鍵值的同時,設定過期時間,單位秒。
14setnx <key> <value>
15只有在 key 不存在時設定 key 的值
16incr <key>
17將 key 中儲存的數字值增1
18只能對數字值操作,如果為空,新增值為1
19mset <key1> <value1> <key2> <value2> .....
20同時設定一個或多個 key-value對
21mget <key1> <key2> <key3> .....
22同時獲取一個或多個 value
23 - List
18
18
1
單鍵多值
2Redis 列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素導列表的頭部(左邊)或者尾部(右邊)。
3它的底層實際是個雙向連結串列,對兩端的操作效能很高,通過索引下標的操作中間的節點效能會較差。
4 5lpush/rpush <key> <value1> <value2> <value3> ....
6從左邊/右邊插入一個或多個值。
7lpop/rpop <key>
8從左邊/右邊吐出一個值。
9值在鍵在,值光鍵亡
10rpoplpush <key1> <key2>
11從<key1>列表右邊吐出一個值,插到<key2>列表左邊。
12lrange <key> <index>
13按照索引下標獲得元素(從左到右)
14lindex <key> <index>
15按照索引下標獲得元素(從左到右)
16llen <key>
17獲得列表長度
18 - set
18
18
1
Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要儲存一個列表資料,又不希望出現重複資料時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要介面,這個也是list所不能提供的。
2Redis的Set是string型別的無序集合。它底層其實是一個value為null的hash表,所以新增,刪除,查詢的複雜度都是O(1)。
3 4sadd <key> <value1> <value2> .....
5將一個或多個 member 元素加入到集合 key 當中,已經存在於集合的 member 元素將被忽略。
6smembers <key>
7取出該集合的所有值。
8sismember <key> <value>
9判斷集合<key>是否為含有該<value>值,有返回1,沒有返回0
10srem <key> <value1> <value2> ....
11刪除集合中的某個元素。
12sinter <key1> <key2>
13返回兩個集合的交集元素。
14sunion <key1> <key2>
15返回兩個集合的並集元素。
16sdiff <key1> <key2>
17返回兩個集合的差集元素。
18 - hash
19
19
1
Redis hash 是一個鍵值對集合。
2Redis hash是一個string型別的field和value的對映表,hash特別適合用於儲存物件。
3類似Java裡面的Map<String,Object>
4 5 6hset <key> <field> <value>
7給<key>集合中的 <field>鍵賦值<value>
8hget <key1> <field>
9從<key1>集合<field> 取出 value
10hmset <key1> <field1> <value1> <field2> <value2>...
11批量設定hash的值
12hexists key <field>
13檢視雜湊表 key 中,給定域 field 是否存在。
14hgetall <key>
15列出該hash集合的所有field和values
16hincrby <key> <field> <increment>
17為雜湊表 key 中的域 field 的值加上增量 increment
18 19 - zset (sorted set)
21
1
Redis有序集合zset與普通集合set非常相似,是一個沒有重複元素的字串集合。不同之處是有序集合的沒有成員都關聯了一個評分(score) ,這個評分(score)被用來按照從最低分到最高分的方式排序集合中的成員。集合的成員是唯一的,但是評分可以是重複了 。
2因為元素是有序的, 所以你也可以很快的根據評分(score)或者次序(position)來獲取一個範圍的元素。訪問有序集合的中間元素也是非常快的,因此你能夠使用有序集合作為一個沒有重複成員的智慧列表。
3zadd <key> <score1> <value1> <score2> <value2>...
6將一個或多個 member 元素及其 score 值加入到有序集 key 當中。
7zrange <key> <start> <stop> [WITHSCORES]
8返回有序集 key 中,下標在<start> <stop>之間的元素
9帶WITHSCORES,可以讓分數一起和值返回到結果集。
10有序輸出從小到大
11zrevrange <key> <start> <stop> [WITHSCORES]
12同上,逆序按評分從大到小
13zincrby <key> <increment> <value>
14為元素的score加上增量
15zrem <key> <value>
16刪除該集合下,指定值的元素
17zcount <key> <min> <max>
18統計該集合,分數區間內的元素個數
19zrank <key> <value>
20返回該值在集合中的排名,從0開始。
21 - Redis的持久化(2個不同形式的持久化方式):
- RDB (Redis DataBase):
- 介紹:在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,也就是行話講的Snapshot快照,它恢復時是將快照檔案直接讀到記憶體裡。用到Linux的寫時複製技術
- 自動存檔(bgsave):fork子程序存檔,但是整個過程主程序是不進行任何IO操作。
- 手動存檔(save):主程序存檔,其他操作全部阻塞
- AOF (Append Of File):
- 介紹:以日誌的形式來記錄每個寫操作,將Redis執行過的所有寫指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,Redis啟動之初會讀取該檔案重新構建資料,換言之,Redis重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作。
- AOF檔案故障恢復:redis-check-aof --fix appendonly.aof 檢測aof檔案的正確性並修復
- redis正確使用aof備份的方式,(若在使用過程中新增aof方式增加資料可靠性):
- 先在客戶端中執行下面命令,設定aof開啟,這時會產生一個描述當前redis的aof檔案(有所有的redis資料)
1
1
1
config set appendonly yes
- 然後再更改配置檔案中的aof的設定,這樣停止服務後aof檔案就會保留
- 經典問題
- AOF和RDB同時開啟,redis聽誰的?聽aof的
- Redis如何實現重寫?
答:AOF檔案持續增長而過大時,會fork出一條新程序來將檔案重寫(也是先寫臨時檔案最後再rename),遍歷新程序的記憶體中資料,每條記錄有一條的Set語句。重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似。 - sentinal是如何使得原來的下屬服從新主的,是修改了配置檔案了麼?
答:確實改配置檔案 但是更主要的是sentinel 會發送slaveof命令 給相關的機器 - 備份是如何執行的?
答:Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的資料可能丟失。 - Redis的主從複製
- 一主多從或鏈型結構
- 一主多從
- 鏈式結構
- 常用命令
10
10
1
# 僕跟隨主的命令
2#ip 和port為主的,這個命令在從上執行
3slaveof <ip> <port>
4 5# 僕不跟隨主的命令,自己變為主(反客為主),需要其他從再確認主
6slaveof no one
7 8# 列印主從複製的相關資訊
9info replication
10 - 經典問題
- 切入點問題?slave1、slave2是從頭開始複製還是從切入點開始複製?比如從k4進來,那之前的123是否也可以複製
答:redis從機會複製全量資料。mysql的主從則只從當前。不同資料庫的特點決定不同的複製策略 - 從機是否可以寫?set可否? 不可以寫只可讀
- 主機shutdown後情況如何?從機是上位還是原地待命
答:從機原地待命,所以一般會使用哨兵監控主機自動切換從機 - 哨兵模式(sentinal)
- 功能
- 反客為主的自動版,能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫.
- 哨兵可以做路由功能,可以路由jedis的請求到主機
- 配置和啟動命令
- 配置 sentinel.conf
4
4
1
# mymaster:是主機名
2# 1 :當有一個哨兵認為主機掛掉的時候就需要切換主
3sentinel monitor mymaster 192.168.11.103 6379 1
4protected-mode no
- 啟動
- 先啟動主從機,並執行slaveof配置主機
- 執行 redis-sentinel sentinel.conf
- 當主機掛掉,根據切換主機規則,從機自動上位
- 生產環境哨兵怎麼用?
- 每個從配一個哨兵,主也配一個哨兵
- 主掛掉哨兵會發起投票,當投票數大於配置檔案的數時,切換主機
- 切換主機規則根據三個條件判斷,優先順序、偏移量最大的(偏移量是指獲得原主資料最多的),選擇runid最小的從服務
- Redis叢集
- 介紹:
- Redis 叢集實現了對Redis的水平擴容,即啟動N個redis節點,將整個資料庫分佈儲存在這N個節點中,每個節點儲存總資料的1/N。
- 是一個無中心的叢集!!!
- 配置與啟動
- 配置:叢集模式,在之前配置基礎上加上如下幾項
9
9
1
# 開啟叢集模式
2cluster-enabled yes
3# 設定節點配置檔名
4cluster-config-file nodes-6379.conf
5# 設定節點失聯時間,超過該時間(毫秒),叢集自動進行主從切換。
6cluster-node-timeout 15000
7 8# 預設是yes ,如果選no那麼即使某一部分的slot完全下線(包括從機),叢集也會繼續以現存的資料提供服務。
9cluster-require-full-coverage yes
- 啟動
- 服務端啟動
- 啟動所有redis-server
- 然後進行合體指令(需要先安裝ruby,)
13
13
1
安裝ruby環境
21、 yum -y install ruby-libs ruby ruby-irb ruby-rdoc rubygems
32、拷貝redis-3.2.0.gem到/opt目錄下
43、執行在opt目錄下執行 gem install --local redis-3.2.0.gem
5 6# 切換到redis的src資料夾下
7cd /opt/redis-3.2.3/src
8 9# 此處不要用127.0.0.1, 請用真實IP地址
10# 一個叢集至少要有三個主節點
11# 選項 --replicas 1 表示我們希望為叢集中的每個主節點建立一個從節點
12# 分配原則儘量保證每個主資料庫執行在不同的IP地址,每個從庫和主庫不在一個IP地址上。
13./redis-trib.rb create --replicas 1 192.168.75.102:6379 192.168.75.102:6380 192.168.75.102:6381 192.168.75.102:6389 192.168.75.102:6390 192.168.75.102:6391
- 客戶端啟動:
使用redis-cli -c -h <host> -p <prot> 啟動客戶端,-c 引數實現自動重定向。不加-c引數會報錯。 - 叢集中的常用指令
13
13
1
# 命令檢視叢集資訊
2cluster nodes
3 4# 不在一個slot下的鍵值,是不能使用mget,mset等多鍵操作。
5# 可以通過{}來定義組的概念,從而使key中{}內相同內容的鍵值對放到一個slot中去。
6mset k1{k} v1 k2{k} v2 k2{k} v2
7 8# 計算鍵 key 應該被放置在哪個槽上。
9CLUSTER KEYSLOT <key>
10# 返回槽 slot 目前包含的鍵值對數量。
11CLUSTER COUNTKEYSINSLOT <slot>
12# 返回 count 個 slot 槽中的鍵。
13CLUSTER GETKEYSINSLOT <slot> <count>
- 經典問題
- 目前市面上的redis叢集方案
- 客戶端方案,早期方案通過JedisShardInfo來實現分片
問題:1 分片規則耦合在客戶端。 2 需要自己實現很多功能。 3 不提供高可用 - 第三方代理中介軟體模式:twemproxy、 codis
問題:1 成為瓶頸和風險點 2 版本基本上不再更新了 - redis3.0以後出的官方redis-cluster方案
問題:有高可用,但沒有讀寫分離 - 什麼是slots
- 一個 Redis 叢集包含 16384 個插槽(hash slot), 資料庫中的每個鍵都屬於這 16384 個插槽的其中一個, 叢集使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽, 其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。
- 叢集中的每個節點負責處理一部分插槽。 舉個例子, 如果一個叢集可以有主節點, 其中:
- 節點 A 負責處理 0 號至 5500 號插槽。
- 節點 B 負責處理 5501 號至 11000 號插槽。
- 節點 C 負責處理 11001 號至 16383 號插槽。
- 如果主節點下線?從節點能否自動升為主節點?
答:會 - 主節點恢復後,主從關係會如何?
答:恢復後變為從 - 如果所有某一段插槽的主從節點都當掉,redis服務是否還能繼續?
答:redis.conf中的引數 cluster-require-full-coverage 。 預設是yes ,如果選no那麼即使某一部分的slot完全下線(包括從機),叢集也會繼續以現存的資料提供服務。 - Idea訪問Redis
- 建立maven工程,新增maven加依賴
8
8
1
<!-- Java的Redis客戶端Jedis -->
2<dependencies>
3<dependency>
4<groupId>redis.clients</groupId>
5<artifactId>jedis</artifactId>
6<version>3.2.0</version>
7</dependency>
8</dependencies>
- 編寫程式碼
- 普通的Jedis開發
78
78
1
package com.shuai;
2 3import redis.clients.jedis.Jedis;
4 5import java.util.*;
6 7/**
8* @author Shuai
9* @create 2020-07-14 0:17
10*/
11public class Test1 {
12public static void main(String[] args) {
13 14//連線本地的 Redis 服務
15Jedis jedis = new Jedis("hadoop102", 6379);
16//檢視服務是否執行,打出pong表示OK
17System.out.println("connection is OK==========>: " + jedis.ping());
18 19//---------下面的全是邏輯程式碼,環境準備只需要第一行程式碼-----
20//key
21Set<String> keys = jedis.keys("*");
22for (Iterator iterator = keys.iterator(); iterator.hasNext(); ) {
23String key = (String) iterator.next();
24System.out.println(key);
25}
26System.out.println("jedis.exists====>" + jedis.exists("k2"));
27System.out.println(jedis.ttl("k1"));
28 29//Jedis-API: String
30System.out.println(jedis.get("k1"));
31jedis.set("k4", "k4_Redis");
32System.out.println("----------------------------------------");
33jedis.mset("str1", "v1", "str2", "v2", "str3", "v3");
34System.out.println(jedis.mget("str1", "str2", "str3"));
35 36//Jedis-API: List
37List<String> list = jedis.lrange("mylist", 0, -1);
38for (String element : list) {
39System.out.println(element);
40}
41 42//Jedis-API: set
43jedis.sadd("orders", "jd001");
44jedis.sadd("orders", "jd002");
45jedis.sadd("orders", "jd003");
46Set<String> set1 = jedis.smembers("orders");
47for (Iterator iterator = set1.iterator(); iterator.hasNext(); ) {
48String string = (String) iterator.next();
49System.out.println(string);
50}
51jedis.srem("orders", "jd002");
52 53//Jedis-API: hash
54jedis.hset("hash1", "userName", "lisi");
55System.out.println(jedis.hget("hash1", "userName"));
56Map<String, String> map = new HashMap<String, String>();
57map.put("telphone", "13810169999");
58map.put("address", "atguigu");
59map.put("email", "[email protected]");
60jedis.hmset("hash2", map);
61List<String> result = jedis.hmget("hash2", "telphone", "email");
62for (String element : result) {
63System.out.println(element);
64}
65 66//Jedis-API: zset
67jedis.zadd("zset01", 60d, "v1");
68jedis.zadd("zset01", 70d, "v2");
69jedis.zadd("zset01", 80d, "v3");
70jedis.zadd("zset01", 90d, "v4");
71Set<String> s1 = jedis.zrange("zset01", 0, -1);
72for (Iterator iterator = s1.iterator(); iterator.hasNext(); ) {
73String string = (String) iterator.next();
74System.out.println(string);
75}
76}
77}
78 - 叢集的Jedis開發
1
package com.shuai;
2 3import redis.clients.jedis.HostAndPort;
4import redis.clients.jedis.JedisCluster;
5import redis.clients.jedis.JedisPoolConfig;
6 7import java.util.HashSet;
8import java.util.Set;
9 10/**
11* @author Shuai
12* @create 2020-07-16 17:13
13*/
14public class JedisClusterTest {
15public static void main(String[] args) {
16JedisCluster jedisCluter = JedisClusterTest.getJedisCluter();
17jedisCluter.set("k111", "v111");
18jedisCluter.set("k222", "v222");
19jedisCluter.set("k333", "v333");
20System.out.println(jedisCluter.get("k111"));
21System.out.println(jedisCluter.get("k222"));
22System.out.println(jedisCluter.get("k333"));
23}
24 25public static JedisCluster jedisCluster = null;
26 27public static JedisCluster getJedisCluter() {
28if (jedisCluster == null) {
29Set<HostAndPort> hostAndPortSet = new HashSet<>();
30hostAndPortSet.add(new HostAndPort("192.168.75.102", 6379));
31hostAndPortSet.add(new HostAndPort("hadoop102", 6380));
32hostAndPortSet.add(new HostAndPort("hadoop102", 6381));
33 34JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
35jedisPoolConfig.setMaxTotal(20);
36jedisPoolConfig.setBlockWhenExhausted(true);
37jedisPoolConfig.setMaxWaitMillis(2000);
38jedisPoolConfig.setMaxIdle(5);
39jedisPoolConfig.setMinIdle(5);
40jedisPoolConfig.setTestOnBorrow(true);
41 42JedisCluster jedisCluster = new JedisCluster(hostAndPortSet, jedisPoolConfig);
43return jedisCluster;
44} else {
45return jedisCluster;
46}
47}
48}
49