1 初認(rèn)始redis
1.1起源
redis是一個開源的基于c語言編寫,支持網(wǎng)絡(luò)也開源支持內(nèi)存持久化的日志類型,key-value 型nosql 數(shù)據(jù)庫,并提供多種語言的api,從10年3月開始redis開發(fā)工作有vmware支持.從13年5月開始,redis有pivotal贊助
1.2 特性
1 速度塊理論上每秒處理10W次請求
2 廣泛的語言支持
3 持久化
4 多種語言結(jié)構(gòu)
5 主從復(fù)制
6高可用和分布式
1.3 redis的粉絲
微信
微博
人人開源
豆瓣
百度
2 lunix下安裝redis
2.1 redis中文官網(wǎng)
2.2 安裝流程
cd /usr/local/
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
tar -zxvf redis-5.0.5.tar.gz
cd redis-5.0.5
yum install gcc
make
./src/redis-server? ? ? ? ? ? #啟動reids
出現(xiàn)如下錯誤
cd src && make allmake[1]: 進入目錄“/usr/local/redis-5.0.5/src”? ? CC Makefile.depmake[1]: 離開目錄“/usr/local/redis-5.0.5/src”make[1]: 進入目錄“/usr/local/redis-5.0.5/src”? ? CC adlist.oIn file included from adlist.c:34:0:zmalloc.h:50:31: 致命錯誤:jemalloc/jemalloc.h:沒有那個文件或目錄 #include <jemalloc/jemalloc.h>
刪除解壓目錄,重新make
3 常用基本配置項
3.1 常用配置項
命令實例說明
daemonizedaemonize yes是否后臺運行,默認(rèn)no
portport 6379設(shè)置默認(rèn)端口號 默認(rèn)6379
logfilelogfile日志文件設(shè)置日志文件
databasesdatabases 255設(shè)置redis數(shù)據(jù)庫總量上限是255
dirdir數(shù)據(jù)文件目錄設(shè)置數(shù)據(jù)文件存儲目錄
requirepassrequirepass 12345設(shè)置使用密碼
3.2 啟動命令加上配置文件
./src/redis-server redis.cut.conf
3.3 客戶端交互
./src/redis-cli -p 6666 -a 123456
3.4 redis殺死
./src/redis-cli -p 6666 -a 123456 shutdown
4 redis的通用指令
ping? 測試redis網(wǎng)絡(luò)
exit 退出redis客戶端
shutdown 關(guān)閉redis服務(wù)器
通用命令
命令示例說明
selectselect 0選擇0號數(shù)據(jù)庫
keyskeys he* | he[h-1] * | ph?根據(jù)Pattern表達式查詢符合條件的key(不要再生產(chǎn)環(huán)境中使用)
dbsizedbsize返回key的總數(shù)
existsexists a檢查key==a是不是存在
deldel a刪除key=a的數(shù)據(jù)
expireexpire hello 20設(shè)置key=hello? 20 秒后過期
ttlttl hello檢查key=a的過期時間
5 redis數(shù)據(jù)結(jié)構(gòu)
5.1 支持的數(shù)據(jù)結(jié)構(gòu)
String? 字符串類型
Hash? hash類型(類似java 的map)
List? 列表類型
Set? 集合類
ZSet? 有序集合類型
5.1 redis的字符串類型

5.2 字符串使用的場景
1 緩存
2 秒殺(使用計算器)
3 分布式鎖
4 配置中心
5 對象序列化
6計數(shù)器
5.3 redis字符串指令
命令示例說明使用頻率
getget hello獲取key=hello的結(jié)果常用
setset hello world設(shè)置key=hello,value=hello常用
msetmset hello world java best一次設(shè)置多個kv常用
mgetmget hello java一次獲取多個kv常用
deldel hello刪除key=hello一般
incr/decrincr count /decr countkey值自增/自減1一般
incrby/decrbyincrby count 99/decrby count 99自增自減指定步長很少
5.4 redis的hash數(shù)據(jù)結(jié)構(gòu)

hash類型用于存儲結(jié)構(gòu)化數(shù)據(jù)
hash類型可以看作map 中的map
命令示例使用頻率說明
hgethget user:1:info age經(jīng)常獲取hash中key=age的值
hsethset user:1:info age 23經(jīng)常設(shè)置hash中age=23
hmsethmset user:2:Info age 30 name kaka經(jīng)常設(shè)置hash中多個值
hmgethmget user:2:info age name一般獲取hash中多個值
hgetallhmget user:2:info一般獲取hash所有值
hdelhdel user:1:info age一般刪除user:1的age
hexistshexists user:1:info name一般檢查是不是存在
hlenhlen user:1:info很少獲取指定的長度
注意 hash key的命名規(guī)則:對象類型:數(shù)字:屬性
5.5 string-json和hash再處理json數(shù)據(jù)下對比
命令優(yōu)點缺點
string-json序列化編程簡單 節(jié)約內(nèi)存序列化開銷 無法更新部分屬性
hash直觀 可以部分更新多層嵌套實現(xiàn)困難 序列化和反序列化麻煩
string-json的存儲數(shù)據(jù)如下
{
? name:"aaa"
? ,info :{
? ? ? ? age:12
? ? }
}
hash存儲數(shù)據(jù)如下
5.6 list結(jié)構(gòu)數(shù)據(jù)
list列表是簡單的字符串列表,按照插入的順序排序.你可以添加一個元素到列表的前邊或者是后邊
一個列表最多可以包含2的32次方-1個元素(每個列表超過40億個元素)
5.7 list常用指令
命令說明
rpush listkey c b a右邊插入
lpush listkey f e d左邊插入
rpop listkey右邊移除
lpop listkey左邊移除
llen listkey獲取list集合的長度
lrange listkey 0 2從下標(biāo)是0的開始獲取兩個元素
lrange listkey 1 -1獲取子集從1 到-1 之間的元素 -1從右邊數(shù)
5.8 set結(jié)構(gòu)數(shù)據(jù)

redis的Set是string類型的沒有順序的集合,集合成員是唯一的 .這就標(biāo)識這集合中不會出現(xiàn)重復(fù)數(shù)據(jù)
redis中集合是通過哈希表實現(xiàn) 的,所以添加 刪除 查找的速度非???/p>
集合中做多可以存儲40億個數(shù)據(jù)
命令示例說明使用頻率
saddsadd a b添加元素高
sremsrem a b移除元素高
scardscard user:1:flollow計算集合數(shù)量一般
smemberssmembers user:1:flollow獲取所有的集合元素(不推薦)低
srandmembersrandmember user:1:flollow隨機挑選三個元素低
spopspop user:1:flollow隨機彈出元素低
sdiffsdiff set1 set2差集低
sintersinter set1 set2交集低
sunionsunion set1 set2并集低
set應(yīng)用的場景
1微關(guān)系:共同關(guān)注的人
2 抽獎
5.9 zset
1 概述
zset是string類型的有序集合,集合成員是唯一的.這就意味這集合中不可以出現(xiàn)重復(fù)數(shù)據(jù)
增加score數(shù)據(jù)用做排序
2 常用指令
命令示例說明使用頻率
zaddzadd key score elemments添加元素到集合中高
zscorezscore key element得到分?jǐn)?shù)低
zcardzcard key元素總數(shù)高
zremzrem key element刪除數(shù)據(jù)一般
zrangezrange key scope withscoreres獲取排序索引數(shù)量高
zcountzcount key scope獲取排序數(shù)據(jù)總量低
zrangebyscorezrangebyscore key獲取按分?jǐn)?shù)排名的數(shù)據(jù)低
zrankzrank key element獲得排名低
zadd palyer:rank 100 cluo 200 meixu 600 erduo
zrem palyer:rank erduo
zrange palyer:rank 0 -1 #按順序排列數(shù)據(jù)
zrange palyer:rank 0 -1 withscores? ? ? 排序增加分?jǐn)?shù)
zcount palyer:rank 100 200? 分?jǐn)?shù)100到200的數(shù)量
zrangebyscore palyer:rank 100 200 withscores? 按排序列出數(shù)據(jù)并且分?jǐn)?shù)一起顯示
3 使用場景

6 redis客戶端
RedisDesktopManager 如果鏈接補上再配置文件中增加? bind 0.0.0.0
7 java客戶端jedis
jedis是java開發(fā)的redis客戶端工具包,用于java語言與redis語言進項交互
jedis只是對redis的命令進行了封裝,掌握了reids命令就可以輕松使用jedis
jedis遵從Resp協(xié)議開發(fā)規(guī)范,具有很好的通用性和可讀性
依賴
<dependency>
?? <groupId>com.yugabyte</groupId>
?? <artifactId>jedis</artifactId>
?? <version>2.9.0-yb-11</version>
</dependency>
測試jedis
@Test
public void testJedis() throws Exception{
?? //創(chuàng)建一個Redis通道
?? Jedis jedis = new Jedis("192.168.132.128", 6666, 1000);
?? try {
? ? ?? jedis.auth("123456");//設(shè)置登錄密碼
? ? ?? jedis.select(3);//選擇第四個數(shù)據(jù)庫,數(shù)據(jù)庫下標(biāo)從0開始
? ? ?? jedis.flushDB();//清空第四個數(shù)據(jù)庫
? ? ?? jedis.set("hello", "world"); //jedis.xxx方法名字就是命令
? ? ?? System.out.println( jedis.get("hello"));
? ? ?? jedis.mset(new String[]{"a", "1", "b", "2", "c" ,"3"});
? ? ?? List<String> strs =? jedis.mget(new String[]{"a", "c"});
? ? ?? System.out.println(strs);
? ? ?? System.out.println(jedis.incr("c"));
? ? ?? System.out.println(jedis.del("b"));;
?? } catch (Exception e) {
? ? ?? throw e;
?? }finally {
? ? ?? jedis.close();//釋放鏈接
?? }
}
?
@Test
public void testHash() throws Exception {
?? Jedis jedis = new Jedis("192.168.132.128", 6666, 1000);
?? try {
? ? ?? jedis.auth("123456");//設(shè)置登錄密碼
? ? ?? jedis.select(3);//選擇第四個數(shù)據(jù)庫,數(shù)據(jù)庫下標(biāo)從0開始
? ? ?? jedis.flushDB();//清空第四個數(shù)據(jù)庫
? ? ?? jedis.hset("user:1:info", "name", "齊毅");
? ? ?? jedis.hset("user:1:info", "age", "35");
? ? ?? jedis.hset("user:1:info", "height", "180");
? ? ?? String name = jedis.hget("user:1:info", "name");
? ? ?? System.out.println(name);
? ? ?? Map user1 = jedis.hgetAll("user:1:info");
? ? ?? System.out.println(user1);
?? } catch (Exception e) {
? ? ?? throw e;
?? }finally {
? ? ?? jedis.close();//釋放鏈接
?? }
}
8 JedisPool
1 依賴
<dependency>
?? <groupId>com.yugabyte</groupId>
?? <artifactId>jedis</artifactId>
?? <version>2.9.0-yb-11</version>
</dependency>
測試
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
?
/**
* 連接池測試類
*/
public class JedisPoolTestor {
?? @Test
?? public void testJedisPool(){
? ? ?? GenericObjectPoolConfig config = new JedisPoolConfig();
? ? ?? config.setMaxTotal(100); //設(shè)置連接池中最多允許放100個Jedis對象
? ? ?? //我的建議maxidle與maxTotal一樣
? ? ?? config.setMaxIdle(100);//設(shè)置連接池中最大允許的空閑連接
? ? ?? config.setMinIdle(10);//設(shè)置連接池中最小允許的連接數(shù)
? ? ?? config.setTestOnBorrow(false); //借出連接的時候是否測試有效性,推薦false
? ? ?? config.setTestOnReturn(false); //歸還時是否測試,推薦false
? ? ?? config.setTestOnCreate(false); //創(chuàng)建時是否測試有效
? ? ?? config.setBlockWhenExhausted(true);//當(dāng)連接池內(nèi)jedis無可用資源時,是否等待資源 ,true
? ? ?? config.setMaxWaitMillis(1000); //沒有獲取資源時最長等待1秒,1秒后還沒有的話就報錯
? ? ?? //創(chuàng)建jedis,這句話運行后就自動根據(jù)上面的配置來初始化jedis資源了
?
? ? ?? JedisPool pool = new JedisPool(config , "192.168.186.6" , 6379);
? ? ?? Jedis jedis = null;
? ? ?? try {
? ? ? ? ?? jedis = pool.getResource(); //從連接池中"借出(borrow)"一個jedis對象
? ? ? ? ?? jedis.auth("12345");
? ? ? ? ?? jedis.set("abc" , "bbb");
? ? ? ? ?? System.out.println(jedis.get("abc"));
? ? ?? } catch (Exception e) {
? ? ? ? ?? e.printStackTrace();
? ? ?? } finally {
? ? ? ? ?? if(jedis != null){
? ? ? ? ? ? ?? jedis.close();//在使用連接池的時候,close()方法不再是關(guān)閉,而是歸還(return)
? ? ? ? ?? }
? ? ?? }
?
?
?? }
}
3 直連和連接池
優(yōu)點缺點
直連簡單粗暴 適應(yīng)少數(shù)鏈接的場景jedis線程不安全,存再鏈接泄露問題
連接池jedis對象預(yù)先生成,降低開銷,偏于鏈接資源進行監(jiān)控和控制實用麻煩,參數(shù)較多,規(guī)劃不合理容易問題
9 springboot+spring cache實現(xiàn)聲明式緩存
redis在開發(fā)中最重要的應(yīng)用就是緩存。利用內(nèi)存的高吞吐解決數(shù)據(jù)查詢慢的問題
spring cache 是spring生態(tài)的一員。用于對主流緩存組件進行一致性訪問,通過暴露統(tǒng)一的接口,讓我們輕松的使用并進行組件之間的切換
spring cache的對緩存的支持
Collection
ConcurrentMap
Redis
Ehcache
Google GuavaCache
Hazlcast
JCache
聲明式緩存
聲明書緩存通俗來說是采用注解的形式對當(dāng)前應(yīng)用的非侵入式擴展
聲明式緩存是spring cache默認(rèn)支持,底層采用spring aop技術(shù)實現(xiàn)
10 內(nèi)部運行原理

內(nèi)存處理速度快,納秒級別
非阻塞io,io多路復(fù)用,基于事件完成讀寫
避免線程切換和資源浪費
一次只能使用使用一條命令
經(jīng)量不要使用慢命令
keys
flushall
flushdb
exec
save
bgsave
11 Rdb
reids所有數(shù)據(jù)保存到內(nèi)存中,為了防止數(shù)據(jù)丟失,會異步把數(shù)據(jù)保存到硬盤上
快照===》mysql Dump,? reids RDB
寫日志==》 mysql Binlog? ,habse hlog? ,? redis aof
11.2 Rdb執(zhí)行流程

11.3 Rdb 使用方式
save 同步保存
bgsave 異步保存
自動保存
11.4 Rdb的配置項目
save 60 1
自動保存策略 60秒內(nèi)有一個key發(fā)生變化就自動保存
dbfilename dbdump.rdb
設(shè)置rdb名字
dir ./
rdb文件保存的位置
stop-writes-on-bgsave-error yes
發(fā)生中斷時候?qū)懭?建議開啟
rdbcompression yes
數(shù)據(jù)文件壓縮建議開啟
rdbchecksum yes
開啟crc64錯誤校驗 建議開啟
12 AOF

aof策略
always? 隨時寫入 (不推薦)
everysec 每秒寫入(推薦)
no? 依賴os規(guī)則寫入(不推薦)
比較
命令alwayseverysecno
優(yōu)點不丟失數(shù)據(jù)每秒一次同步丟1秒數(shù)據(jù)不用管
缺點io開銷大,丟1秒數(shù)據(jù)不可控
AOF重寫
原生aof重寫aof
原生的rpush mylist a? rpush mylist brpush? ? ? ? ? ? ? ? ? 重寫后mylist a b
aof實現(xiàn)方式
bgrewriteof 命令
aof重寫配置
aof常用配置
參數(shù)說明
appendonly? yes開啟aof
appendfilename? aof66.aofaof日志文件名
appendfsync? everysec每秒記錄一次日志
no-appendfsync-on-rewrite yes重寫過程中是不是向日志文件中寫入yes 重寫過程中不向aof文件中追加日志,等rewrite執(zhí)行完后在寫入? ? ? no 代表重寫執(zhí)行時候也向aof中追加信息
auto-aof-rewrite-percentage 100觸發(fā)重寫文件的百分比 默認(rèn)是100%
auto-aof-rewrite-min-size? 64mb觸發(fā)最小aof文件尺寸
bgrewriteaof? 自動保存aof文件
rewrite說明
aof文件小于64mb 不重寫
aof第一大于64m自動重寫,壓縮到33m
Rdb和aof對比
rdb和aof都開啟的情況下 會采用aof來回復(fù)數(shù)據(jù)
日常開發(fā),官方推薦使用aof
redis主從同步底層使用的是rdb
13? redis 主從復(fù)制
13.1單機部署的缺陷
單機故障
容量瓶頸(一臺機器的內(nèi)存是有限的 )
QPS瓶頸(每秒請求數(shù)量10W次在特殊的環(huán)境下不夠用)
13.2 主從復(fù)制是高可用的基礎(chǔ)

13.3 主從的特性
一個master可以有多個slave
一個slave只能有一個master
數(shù)據(jù)流是單向的,master到slave
主從復(fù)制的底層依賴RDB的方式進行全量覆蓋
13.4? 主從復(fù)制的實現(xiàn)
slaveof /slaveof? no one
配置文件
13.5 用客戶端命令配置主從同步
slave端操作如下
./src/redis-cli -p 6379 -a 123456? 進入客戶端
slaveof node-4 6379? 在從節(jié)點上執(zhí)行同步命令,會清除掉自己有的數(shù)據(jù)和從節(jié)點進行同步
config set masterauth 123456? 設(shè)置master密碼
info replication? 查看同步信息
slaveof no one解除從屬關(guān)系
13.6 用配置文件使用主從復(fù)制
命令方式配置的主從重啟后會失效 建議采用配置文件的方式
daemonize yes
port 6379
logfile redis.log
databases? 12
dir ./redisdata
requirepass 123456
?
slaveof node-4 6379
masterauth 123456
slave-read-only yes
14 redis的配置與啟動
14.1 主從面臨的高可用問題
如上主節(jié)點掛掉 從節(jié)點變成master 但是程序中怎么辦,同步修改問題
14.2 redis sentinel(哨兵)

是一個分布式架構(gòu),包含若干個sentinel節(jié)點和reids數(shù)據(jù)節(jié)點,每個sentinel節(jié)點會對數(shù)據(jù)節(jié)點和其他的sentinel節(jié)點進行監(jiān)視,當(dāng)發(fā)現(xiàn)節(jié)點不可達時候?qū)?jié)點做下線處理(標(biāo)識)
1 有sentinel來代理進行訪問
2 如果reids集群的master 節(jié)點掛掉,sentinel選舉新的master,
所有的節(jié)點向新的master節(jié)點同步數(shù)據(jù)
14.3 sentinel節(jié)點配置
daemonize yes
port 26379(默認(rèn)節(jié)點)
logfile sentinel.log
dir ./redisdata
sentinel monitor? mymaster? 10.10.10.0 6379 2
<!--監(jiān)控redis集群主節(jié)點名字為mymaster ip為10.10.10.0 端口號為6379 的有兩個sentinel鏈接不上該master,就自動轉(zhuǎn)移故障-->
sentinel down-after-milliseconds mymaster 20000
<!--20秒ping不通就認(rèn)為該節(jié)點有故障-->
sentinel parallel-syncs mymaster 1
<!--故障轉(zhuǎn)移后是并行復(fù)制還是串行復(fù)制-->
sentinel failover-timeout mymaster 600000
<!--故障開始10分鐘沒有完成轉(zhuǎn)移工作認(rèn)為轉(zhuǎn)移失敗-->
故障轉(zhuǎn)移master節(jié)點的redis文件也需要做 masterauth 123456? 密碼認(rèn)證
14.4 sentinel 實現(xiàn)故障轉(zhuǎn)移
mavne依賴
<dependency>
?? <groupId>com.yugabyte</groupId>
?? <artifactId>jedis</artifactId>
?? <version>2.9.0-yb-11</version>
</dependency>
代碼實現(xiàn)
String nodename = "node-3";
Set<String> set = new HashSet<String>();
set.add("node-3:26379");
set.add("node-4:26379");
set.add("node-5:26379");
JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(nodename, set,"123456");
Jedis resource = jedisSentinelPool.getResource();
resource.select(6);
resource.set("test", "2020-12-12");
resource.close();
15 redis開發(fā)規(guī)范
15.1 key的規(guī)范
業(yè)務(wù)名:表名:id
減少key的長度,不超過39個字符
key 不要包含特殊字符
15.2 java對象存儲方案
javaredis類型說明使用場景
javabeanstring保存對象json序列化字符串,使用簡單,節(jié)省key。缺點無法局部調(diào)整,序列化和反序列化要重新計算保存相對穩(wěn)定數(shù)據(jù),如電商平臺的商品,檔案
javabeanhash最符合javabean的特征的保存方式,有點key松散管理,可以局部修改數(shù)據(jù),缺點hash=》object需要額外的編碼同上
list/setstringjson序列化存小數(shù)據(jù),修改不多,優(yōu)點節(jié)省空間 缺點無法調(diào)整排行旁
list/setn/a變化頻率高,數(shù)據(jù)不斷刷新,不要放到redis中做緩存股票實時行情,銷售金額等等
15.3 開發(fā)建議
不要使用直連,采用jedispool方式開發(fā)
建議使用springcache聲明式緩存
15.4 reids安全建議
redis不要在外網(wǎng)被訪問 禁止 bind 0.0.0.0
更改redis默認(rèn)端口
使用非root用戶
redis設(shè)置強度高的密碼。別和登錄密碼相同
定期備份,save命令
防火墻
16 內(nèi)存和回收策略
info memory
used_memory:13490096數(shù)據(jù)占用了多少內(nèi)存(字節(jié))
used_memory_human:12.87M數(shù)據(jù)占用了多少內(nèi)存(單位)
used_memory_rss:13490096操作系統(tǒng)已分配的內(nèi)存量
used_memory_peak:15301192占用內(nèi)存的峰值(字節(jié))
used_memory_peak_human:14.59M占用內(nèi)存的峰值(帶單位的)
used_memory_lua:31744lua引擎所占用的內(nèi)存大小(字節(jié))
mem_fragmentation_ratio:1.00內(nèi)存碎片率
16.2設(shè)置內(nèi)存上限
32位系統(tǒng)最大的可以使用內(nèi)存是3G
64位系統(tǒng)默認(rèn)最大為可以使用的內(nèi)存
maxmemory配置項用于設(shè)置最大內(nèi)存
maxmemory? 1gb
maxmemory? 120mb
一般預(yù)留30% 的內(nèi)存
16.3 內(nèi)存回收策略
超過最大內(nèi)存后自動觸發(fā)相應(yīng)的策略
由maxmemory-policy選項控制
– maxmemory-policy volatile-lru
– maxmemory-policy allkeys-lru
內(nèi)存回收六種策略
1. noeviction : 永不過期,返回錯誤(默認(rèn))
2. volatile-lru:在即將過期數(shù)據(jù)刪除使用最少的key(推薦)
3. allkeys-lru :在所有數(shù)據(jù)中刪除lru算法的key(推薦)
4. volatile-random:隨機刪除即將過期key
allkeys-random:所有key隨機刪除
volatile-ttl : 按到期時間順序,刪除即將過期的key