詳解redis

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的粉絲

微信

QQ

微博

人人開源

豆瓣

百度

2 lunix下安裝redis

2.1 redis中文官網(wǎng)

http://redis.cn/

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容