一、Redis基礎(chǔ)簡(jiǎn)介
1糊啡、Redis官方介紹
Redis是一個(gè)開(kāi)源(BSD許可)拄查,內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲(chǔ),用作數(shù)據(jù)庫(kù)悔橄,緩存和消息代理靶累。它支持?jǐn)?shù)據(jù)結(jié)構(gòu),如字符串癣疟,散列挣柬,列表,集合睛挚,帶有范圍查詢的排序集邪蛔,位圖,超級(jí)日志扎狱,具有半徑查詢和流的地理空間索引侧到。Redis具有內(nèi)置復(fù)制,Lua腳本淤击,LRU驅(qū)逐匠抗,事務(wù)和不同級(jí)別的磁盤(pán)持久性,并通過(guò)Redis Sentinel和Redis Cluster自動(dòng)分區(qū)污抬。您可以對(duì)這些類(lèi)型運(yùn)行原子操作汞贸,例如附加到字符串;遞增哈希值;將元素推送到列表中;計(jì)算集合交集绳军, 并集和差異;或者在排序集中獲得排名最高的成員。
為了實(shí)現(xiàn)其出色的性能矢腻,Redis使用內(nèi)存數(shù)據(jù)集门驾。根據(jù)您的使用情況,您可以通過(guò) 每隔一段時(shí)間將數(shù)據(jù)集轉(zhuǎn)儲(chǔ)到磁盤(pán)或通過(guò)將每個(gè)命令附加到日志來(lái)保留它多柑。如果您只需要功能豐富的網(wǎng)絡(luò)內(nèi)存緩存奶是,則可以選擇禁用持久性。
Redis還支持簡(jiǎn)單到設(shè)置的主從異步復(fù)制竣灌,具有非衬羯常快速的非阻塞第一次同步,自動(dòng)重新連接以及在網(wǎng)絡(luò)分割上的部分重新同步帐偎。其他功能包括:交易發(fā)布/訂閱逐纬、Lua腳本、鑰匙的生存時(shí)間有限削樊、LRU逐出鑰匙豁生、自動(dòng)故障轉(zhuǎn)移
您可以使用大多數(shù)編程語(yǔ)言中的Redis。Redis是用ANSI C編寫(xiě)的漫贞,適用于大多數(shù)POSIX系統(tǒng)甸箱,如Linux,* BSD迅脐,OS X芍殖,沒(méi)有外部依賴性。Linux和OS X是Redis開(kāi)發(fā)和測(cè)試的兩個(gè)操作系統(tǒng)谴蔑,我們建議使用Linux進(jìn)行部署豌骏。
lua腳本可以將redis客戶端的多個(gè)命令打包送到服務(wù)器一起執(zhí)行,保證原子性
redis為什么這么快隐锭?
(一)純內(nèi)存操作
(二)單線程操作窃躲,避免了頻繁的上下文切換(多線程需要占用更多的CPU資源)
(三)采用了非阻塞I/O多路復(fù)用機(jī)制
2、redis的數(shù)據(jù)結(jié)構(gòu)及應(yīng)用場(chǎng)景
2.1數(shù)據(jù)結(jié)構(gòu)
redis的數(shù)據(jù)結(jié)構(gòu)為key---value存儲(chǔ)钦睡,Key:是String蒂窒,Value有5個(gè)數(shù)據(jù)類(lèi)型
- 1)String: 字符串
- 2)Hash: 類(lèi)似于map、可以放對(duì)象
- 3)List:linkedlist格式 支持重復(fù)的元素
- 4)Set:不允許重復(fù)且無(wú)序
- 5)Sortedset:不允許重復(fù)荞怒,且元素有順序
2.2應(yīng)用場(chǎng)景
1)緩存數(shù)據(jù)(數(shù)據(jù)查詢洒琢,商品內(nèi)容……)
2)任務(wù)隊(duì)列(秒殺、搶購(gòu)褐桌、12306……)
3)應(yīng)用排行榜衰抑、熱門(mén)列表、 最新動(dòng)態(tài)
4)數(shù)據(jù)過(guò)期處理
5)分布式集群架構(gòu)中session的處理
6)時(shí)效性荧嵌、訪問(wèn)頻率停士、計(jì)數(shù)器
7)社交列表挖帘、記錄用戶判定信息
8)交集、并集和差集恋技、消息隊(duì)列
可參考博文: http://blog.720ui.com/2017/redis_core_use
https://www.cnblogs.com/jasonZh/p/9513948.html
?
二、redis在Linux中的操作
1逻族、常規(guī)操作
啟動(dòng)方式:
cd /usr/local
cd redis-4.0.8
cd src
1蜻底、src目錄下的./redis-server,這個(gè)需要一直保持啟動(dòng)聘鳞,當(dāng)其他操作的時(shí)候薄辅,ctrl+c退出,redis也退出了抠璃。不太方便2站楚、后臺(tái)啟動(dòng)
1)到redis目錄
2)vim redis.conf 將daemonize no該為yes
3)到src目錄 :通過(guò)配置文件啟動(dòng)redis: ./redis-server ../redis.conf3、使用redis腳本設(shè)置開(kāi)機(jī)自動(dòng)啟動(dòng):?jiǎn)?dòng)腳本 redis_init_script 位于Redis的 /utils/ 目錄下搏嗡。了解就可以了窿春,我們學(xué)習(xí)使用第二種就夠了
關(guān)閉:
在src目錄下:
./redis -cli -p 6379 shutdown當(dāng)然也可以用kill -9 進(jìn)程號(hào)
** 在Linux系統(tǒng)中,客戶端的連接**
在src目錄下:
./redis -cli -h 127.0.0.1 -p 6379-h是ip地址 -p是端口號(hào)采盒,這兒是默認(rèn)本機(jī)加6379可以省略
./redis-cli
2旧乞、redis的指令
通用指令
keys *
查看所有key
flushall
情況數(shù)據(jù)庫(kù)
2.1 value為String類(lèi)型
2.2 value為hash類(lèi)型
2.3 value為list類(lèi)型
| lpush key value [value...] | l是left的縮寫(xiě) 表示從鏈表左邊(鏈表頭)放入數(shù)據(jù) |
| lrange key start end | 查看start---end中的數(shù)據(jù),左包右包 end -1表示到最后 |
| rpush key value [value...] | 右邊插入數(shù)據(jù) r是right的縮寫(xiě) |
| lpop key | 彈出左邊第一個(gè)元素 |
| rpop key | 彈出右邊第一個(gè)元素 |
| llen key | 查看鏈表的總長(zhǎng)度 |
| blpop key [key...] timeout | 左側(cè)阻塞式彈出 |
| brpop key [key...] timeout | 右側(cè)阻塞式彈出 |
| lpushx | 和lpush類(lèi)似磅氨,但是lpushx會(huì)校驗(yàn)key是否存在尺栖,若key不存在則不進(jìn)行任何操作 |
| rpushx | 和rpush類(lèi)似,但是lpushx會(huì)校驗(yàn)key是否存在烦租,若key不存在則不進(jìn)行任何操作 |
| rpoplpush key1 key2 | 彈出key1的右邊的元素 放入key2左邊(醫(yī)院體檢業(yè)務(wù)延赌,排隊(duì)做了一項(xiàng),繼續(xù)排隊(duì)做第二項(xiàng)) |
| brpoplpush | 阻塞版本 |
| lindex key index | 獲取key中index位置的值叉橱,負(fù)數(shù)就反過(guò)來(lái)數(shù)挫以,-1為最后一個(gè) |
| lrem key count value | count>0從左邊刪除count個(gè)value
count<0從右邊刪除count個(gè)value
count=0刪除所有的value |
2.4 value為set類(lèi)型
| sadd key element [element...] | set集合中添加元素 |
| smembers key | 查看集合所有的元素 |
| sismember key element | 查看元素是否屬于該集合,1存在 0不存在 |
| srem key element [element...] | 刪除集合元素 |
| scard key | 查看集合元素?cái)?shù)量 |
| srandmember key [n] | 隨機(jī)獲取集合中某一個(gè)元素
n是正數(shù):返回n個(gè)不重復(fù)的數(shù)
n是負(fù)數(shù):返回n個(gè)可能重復(fù)的數(shù) |
| spop key [n] | 默認(rèn)彈出一個(gè)元素,或者彈出指定個(gè)數(shù)的元素 |
| sinter key1 key2 | 多個(gè)集合的交集 |
| sdiff key1 key2.... | 返回第一個(gè)集合有 后面集合都沒(méi)有的元素(差集) |
| sunion key1 key2 key3…. | 所有集合的并集 |
| sinterstore set set1 set2 | 找到set1與set2的交集 存放在set中 |
2.5 value為zset(sortedset)類(lèi)型
| zadd key score member1 score member2 | 添加元素 每個(gè)元素都會(huì)攜帶一個(gè)分?jǐn)?shù) |
| zrange key start end [withscores] | 根據(jù)下標(biāo)查看元素 默認(rèn)分?jǐn)?shù)升序排序 |
| zrevrange key start end [withscores] | 類(lèi)似上面赏迟,反取 |
| zrangebyscore key score1 socre2 | 取score1到score2分?jǐn)?shù) 之間的元素 |
| zrevrangebyscore key max min [withscores] | 反取 |
| zrem key member | 刪除元素 |
| **zcard key ** | 個(gè)數(shù) |
| zscore key member | 查看某個(gè)元素的分?jǐn)?shù) |
| zrank key member | 查看某個(gè)元素在集合中的排名,默認(rèn)按分?jǐn)?shù)升序(排名從0開(kāi)始的) |
| zrevrank key member | 反排名 |
| zincrby key increment member | 為某個(gè)元素加分 |
| **zcount key min max ** | 統(tǒng)計(jì)min到max分?jǐn)?shù)間的個(gè)數(shù) |
| zremrangebyscore key min max | 根據(jù)分?jǐn)?shù)段刪除 |
| zremrangebyrank key start end | 根據(jù)排名刪除 |
| zinterstore destination numkeys key [key...] | 這里numkeys表示需要做交集的key的個(gè)數(shù) |
| zunionstore destination numkeys key [key...] | 這里numkeys代表需要做并集的key的個(gè)數(shù) |
三屡贺、SpringBoot整合redis
1、導(dǎo)入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency><!--json工具--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
2锌杀、application.properties配置文件
# Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0)redis一共有16個(gè)庫(kù) 這兒使用0號(hào)庫(kù)
spring.redis.database=0
# Redis服務(wù)器地址 寫(xiě)你的ip
spring.redis.host=192.168.1.154
# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制 類(lèi)似于mysql的連接池
spring.redis.jedis.pool.max-active=200
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) 表示連接池的鏈接拿完了 現(xiàn)在去申請(qǐng)需要等待的時(shí)間
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.jedis.pool.max-idle=10
# 連接池中的最小空閑連接
spring.redis.jedis.pool.min-idle=0
# 連接超時(shí)時(shí)間(毫秒) 去鏈接redis服務(wù)端
spring.redis.timeout=6000
#druid
spring.druid.url=jdbc:mysql://192.168.1.154:3306/redis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
spring.druid.driverClassName=com.mysql.cj.jdbc.Driver
spring.druid.username=root
spring.druid.password=root
#最大鏈接數(shù)
spring.druid.maxActive=30
#最小鏈接數(shù)
spring.druid.minIdle=5
#獲得鏈接的最大等待時(shí)間
spring.druid.maxWait=10000
#指定mybatis配置文件地址
mybatis.config-location=classpath:mybatis/mybatis-config.xml
3甩栈、config配置類(lèi)
package com.xmcc.redis01.config;
@Configuration//表示該類(lèi)為配置類(lèi)
public class RedisConfig {
/**
* 新建restTemplate交給spring容器管理
* 注意:
* springboot其實(shí)已經(jīng)自動(dòng)注入了RedisTemplate,
* 但是泛型是RedisTemplate<Object,Object>糕再,而且沒(méi)有指定序列化的方式
* 而我們需要key都是string類(lèi)型的 量没,避免頻繁類(lèi)型轉(zhuǎn)換,所以重寫(xiě)
* 當(dāng)手動(dòng)去注入一個(gè)RedisTemplate后 springboot將不會(huì)自動(dòng)注入
*RedisConnectionFactory:springboot自動(dòng)讀取配置文件然后注入
*/
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
//設(shè)置連接工廠突想, 工廠用于創(chuàng)建連接 template.setConnectionFactory(factory);
//設(shè)置自定義序列化方式 setSerializeConfig(template,factory );
return template;
}
/**
* 為什么要序列化殴蹄?
*序列化能加快網(wǎng)絡(luò)傳輸究抓,而且redis的value都是字符串,
* 我們希望value放入任意的數(shù)據(jù)袭灯,就需要手動(dòng)去序列化為字符串刺下,這兒直接配置了,
* 以后傳入任意value的時(shí)候稽荧,就會(huì)自動(dòng)序列化
*
* 大家如果不能理解下面的配置橘茉,只需要記住是為了以后設(shè)置任意值的時(shí)候方便就可以了,以后再說(shuō)
* 比如:我們現(xiàn)在想保存一個(gè)student對(duì)象到redis姨丈,但是redis只能存字符串畅卓,那么我們需要把對(duì)象通過(guò)json工具類(lèi)轉(zhuǎn)換為字符串
* 再去存入,寫(xiě)了這個(gè)就不需要轉(zhuǎn)了蟋恬,傳入student對(duì)象翁潘,內(nèi)部自動(dòng)幫助我們轉(zhuǎn)換為字符串
*/
private void setSerializeConfig(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory redisConnectionFactory) {
//設(shè)置鏈接工廠
redisTemplate.setConnectionFactory(redisConnectionFactory);
//對(duì)字符串采取普通的序列化方式 適用于key 因?yàn)槲覀円话悴扇『?jiǎn)單字符串作為key
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//普通的string類(lèi)型的key采用 普通序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
//普通hash類(lèi)型的key也使用 普通序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//解決查詢緩存轉(zhuǎn)換異常的問(wèn)題 大家不能理解就直接用就可以了 這是springboot自帶的jackson序列化類(lèi),但是會(huì)有一定問(wèn)題
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//普通的值采用jackson方式自動(dòng)序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//hash類(lèi)型的值也采用jackson方式序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
//屬性設(shè)置完成afterPropertiesSet就會(huì)被調(diào)用歼争,可以對(duì)設(shè)置不成功的做一些默認(rèn)處理
redisTemplate.afterPropertiesSet();
}
}
4拜马、redis工具類(lèi)(針對(duì)value為string類(lèi)型)
package com.xmcc.redis01.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedisUtils {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
public Object get(String key){
return key==null?null:redisTemplate.opsForValue().get(key );
}
public boolean set(String key,Object value){
try {
redisTemplate.opsForValue().set(key, value);
return true;
}catch (Exception e){
log.error("redis set value exception:{}",e );
return false;
}
}
public boolean setex(String key,Object value,long expire){
try {
redisTemplate.opsForValue().set(key,value ,expire , TimeUnit.SECONDS );
return true;
}catch (Exception e){
return false;
}
}
public boolean expire(String key,long expire){
try{//這兒沒(méi)有ops什么的是因?yàn)槊糠N數(shù)據(jù)類(lèi)型都能設(shè)置過(guò)期時(shí)間
redisTemplate.expire(key,expire,TimeUnit.SECONDS);
return true;
}catch (Exception e){
log.error("redis set key expire exception:{}",e);
return false;
}
}
/**
*
* @param key
* @return 獲取key的過(guò)期時(shí)間
*/
public long ttl(String key){
return redisTemplate.getExpire(key);
}
/**
*
* @param keys 刪除key 可變參數(shù)
*/
public void del(String ...keys){
if(keys!=null&&keys.length>0) {
redisTemplate.delete(CollectionUtils.arrayToList(keys));
}
}
/**
*
* @param key
* @param step 傳入正數(shù) 就是加多少 傳入負(fù)數(shù)就是減多少
* @return
*/
public long incrBy(String key,long step){
return redisTemplate.opsForValue().increment(key,step);
}
/**
*
* @param key
* @param value
* @return 如果該key存在就返回false 設(shè)置不成功 key不存在就返回ture設(shè)置成功
*/
public boolean setnx(String key,Object value){
return redisTemplate.opsForValue().setIfAbsent(key,value);
}
/**
* 原子操作
* @param key
* @param value
* @param expire 在上面方法加上過(guò)期時(shí)間設(shè)置
* @return
*/
public boolean setnxAndExpire(String key,Object value,long expire){
return redisTemplate.opsForValue().setIfAbsent(key,value,expire,TimeUnit.SECONDS);
}
/**
*
* @param key
* @param value
* @return 如果該key存在就返回之前的value 不存在就返回null
*/
public Object getAndSet(String key,Object value){
return redisTemplate.opsForValue().getAndSet(key,value);
}
/**
*
* @param key
* @return 判斷key是否存在
*/
public boolean hasKey(String key){
return redisTemplate.hasKey(key);
}
}
5、redis的使用
在需要redis的地方矾飞,將redisutil注入一膨,調(diào)用對(duì)應(yīng)的方法即可。
四洒沦、redis進(jìn)階問(wèn)題
1豹绪、redis鍵過(guò)期處理機(jī)制
1.1定期刪除+惰性刪除是如何工作的呢?
定期刪除,redis默認(rèn)每個(gè)100ms檢查申眼,是否有過(guò)期的key,有過(guò)期key則刪除瞒津。需要說(shuō)明的是,redis不是每個(gè)100ms將所有的key檢查一次括尸,而是隨機(jī)抽取進(jìn)行檢查(如果每隔100ms,全部key進(jìn)行檢查巷蚪,redis豈不是卡死)。因此濒翻,如果只采用定期刪除策略屁柏,會(huì)導(dǎo)致很多key到時(shí)間沒(méi)有刪除。
于是有送,惰性刪除派上用場(chǎng)淌喻。也就是說(shuō)在你獲取某個(gè)key的時(shí)候,redis會(huì)檢查一下雀摘,這個(gè)key如果設(shè)置了過(guò)期時(shí)間那么是否過(guò)期了裸删?如果過(guò)期了此時(shí)就會(huì)刪除。
--》采用定期刪除+惰性刪除就沒(méi)其他問(wèn)題了么?
不是的阵赠,如果定期刪除沒(méi)刪除key涯塔。然后你也沒(méi)即時(shí)去請(qǐng)求key肌稻,也就是說(shuō)惰性刪除也沒(méi)生效。這樣匕荸,redis的內(nèi)存會(huì)越來(lái)越高爹谭。那么就應(yīng)該采用內(nèi)存淘汰機(jī)制。
1.2 內(nèi)存淘汰機(jī)制
**在redis.conf中有一行配置
maxmemory-policy volatile-lru
該配置就是配內(nèi)存淘汰策略的**
1)noeviction:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí)每聪,新寫(xiě)入操作會(huì)報(bào)錯(cuò)旦棉。應(yīng)該沒(méi)人用吧。
2)allkeys-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí)药薯,在鍵空間中,移除最近最少使用的key救斑。推薦使用童本,大部分情況適用。
3)allkeys-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí)脸候,在鍵空間中穷娱,隨機(jī)移除某個(gè)key。
4)volatile-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí)运沦,在設(shè)置了過(guò)期時(shí)間的鍵空間中泵额,移除最近最少使用的key。這種情況一般是把redis既當(dāng)緩存携添,又做持久化存儲(chǔ)的時(shí)候才用嫁盲。不推薦
5)volatile-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中烈掠,隨機(jī)移除某個(gè)key羞秤。依然不推薦
6)volatile-ttl:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中左敌,有更早過(guò)期時(shí)間的key優(yōu)先移除瘾蛋。不推薦常見(jiàn)選擇:
allkeys-lru:如果我們的應(yīng)用對(duì)緩存的訪問(wèn)符合冪律分布(也就是存在相對(duì)熱點(diǎn)數(shù)據(jù)),或者我們不太清楚我們應(yīng)用的緩存訪問(wèn)分布狀況矫限,我們可以選擇allkeys-lru策略哺哼。
allkeys-random:如果我們的應(yīng)用對(duì)于緩存key的訪問(wèn)概率相等,則可以使用這個(gè)策略叼风。
volatile-ttl:這種策略使得我們可以向Redis提示哪些key更適合被移除
1.3為什么不用定時(shí)刪除策略?
定時(shí)刪除,用一個(gè)定時(shí)器來(lái)負(fù)責(zé)監(jiān)視key,過(guò)期則自動(dòng)刪除取董。雖然內(nèi)存及時(shí)釋放,但是十分消耗CPU資源咬扇。在大并發(fā)請(qǐng)求下甲葬,CPU要將時(shí)間應(yīng)用在處理請(qǐng)求,而不是刪除key,因此沒(méi)有采用這一策略.
2懈贺、redis持久化
2.1 RDB
Redis持久化方案:
1经窖、RDB(默認(rèn)的持久化方案:推薦使用的)Redis DataBase 生成快照文件xxx.rdb保存到磁盤(pán)
1)自動(dòng)執(zhí)行
a)需要查看配置文件
i.save 900 1
ii.save 300 10
iii.save 60 10000
滿足三個(gè)條件中一個(gè)觸發(fā)生成快照rdb文件
b)啟動(dòng)服務(wù)器的時(shí)候坡垫,需要通過(guò)命令行啟動(dòng)
i.進(jìn)入reids的安裝目錄
ii.Redis-server.exe redis.windows.conf2)save命令 3)bgsave命令
其它配置(了解)
stop-writes-on-bgsave-error yes 后臺(tái)備份進(jìn)程出錯(cuò)時(shí),主進(jìn)程停不停止寫(xiě)入?
rdbcompression yes 導(dǎo)出的rdb文件是否壓縮
Rdbchecksum yes 導(dǎo)入rbd恢復(fù)時(shí)數(shù)據(jù)時(shí),要不要檢驗(yàn)rdb的完整性
dbfilename dump.rdb 生成的rdb文件名
dir ./ rdb文件的放置路徑
save “” 在那三個(gè)save下面加save “”表示禁用rdb
2.2 AOF
AOF是AppendOnly File的縮寫(xiě),是Redis系統(tǒng)提供了一種記錄Redis操作的持久化方案画侣,在AOF生成的文件中冰悠,將真實(shí)記錄發(fā)生在Redis上的操作,從而達(dá)到在Redis服務(wù)器重啟或者當(dāng)機(jī)之后配乱,繼續(xù)恢復(fù)之前數(shù)據(jù)狀態(tài)的機(jī)制溉卓。
1)打開(kāi)AOF
redis.conf中的appendonly yes就可以打開(kāi)AOF功能
appendfsync no:
當(dāng)設(shè)置appendfsync為no的時(shí)候,Redis不會(huì)主動(dòng)調(diào)用fsync去將AOF日志內(nèi)容同步到磁盤(pán)搬泥,所以這一切就完全依賴于操作系統(tǒng)的調(diào)試了桑寨。對(duì)大多數(shù)Linux操作系統(tǒng),是每30秒進(jìn)行一次fsync忿檩,將緩沖區(qū)中的數(shù)據(jù)寫(xiě)到磁盤(pán)上尉尾。
appendfsync everysec
當(dāng)設(shè)置appendfsync為everysec的時(shí)候,Redis會(huì)默認(rèn)每隔一秒進(jìn)行一次fsync調(diào)用燥透,將緩沖區(qū)中的數(shù)據(jù)寫(xiě)到磁盤(pán)沙咏。但是當(dāng)這一次的fsync調(diào)用時(shí)長(zhǎng)超過(guò)1秒時(shí)。Redis會(huì)采取延遲fsync的策略班套,再等一秒鐘肢藐。也就是在兩秒后再進(jìn)行fsync,這一次的fsync就不管會(huì)執(zhí)行多 長(zhǎng)時(shí)間都會(huì)進(jìn)行吱韭。這時(shí)候由于在fsync時(shí)文件描述符會(huì)被阻塞吆豹,所以當(dāng)前的寫(xiě)操作就會(huì)阻塞。
結(jié)論就是杉女,在絕大多數(shù)情況下瞻讽,Redis會(huì)每隔一秒進(jìn)行一 次fsync。在最壞的情況下熏挎,兩秒鐘會(huì)進(jìn)行一次fsync操作速勇。這一操作在大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)中被稱為group commit,就是組合多次寫(xiě)操作的數(shù)據(jù)坎拐,一次性將日志寫(xiě)到磁盤(pán)烦磁。
appendfsync always
設(shè)置appendfsync為always時(shí),每一次寫(xiě)操作都會(huì)調(diào)用一次fsync哼勇,這時(shí)數(shù)據(jù)是最安全的都伪,當(dāng)然,由于每次都會(huì)執(zhí)行fsync积担,
所以其性能也會(huì)受到影響
2)AOF重寫(xiě)
因?yàn)?AOF 持久化是通過(guò)保存被執(zhí)行的寫(xiě)命令來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài)的陨晶,那么就會(huì)涉及到很多無(wú)用的命令,比如:
set a b
set a c
set a d 其實(shí)就最后一條有意義
Redis會(huì)fork一個(gè)進(jìn)程來(lái)讀取現(xiàn)在redis生成的AOF文件,然后在內(nèi)存中去除冗余命令先誉,
在此過(guò)程中不會(huì)影響原來(lái)AOF文件的繼續(xù)寫(xiě)入湿刽,如果有新的命令,會(huì)緩存在重寫(xiě)緩沖中褐耳,當(dāng)重寫(xiě)完全結(jié)束后會(huì)替換掉原來(lái)的AOF文件
重寫(xiě)觸發(fā)條件:
1.手動(dòng)命令BGREWRITEAOF
配置自動(dòng)調(diào)用
2.3 RDB诈闺、AOF的選擇
1.宕機(jī)后,會(huì)優(yōu)先加載AOF文件
2.RDB保存的數(shù)據(jù)铃芦,AOF保存的命令雅镊,RDB文件比AOF小
3.恢復(fù)速度RDB小,更快
4.RDB一次寫(xiě)入的數(shù)據(jù)較多刃滓,時(shí)間間隔會(huì)比AOF長(zhǎng)仁烹,出現(xiàn)宕機(jī)丟失的數(shù)據(jù)會(huì)更多各有優(yōu)劣,如果能綜合就好了咧虎,所幸的是在redis4.0后晃危,通過(guò)下面配置
aof-use-rdb-preamble就可以開(kāi)啟兩者混合持久化,取長(zhǎng)補(bǔ)短
3老客、redis、mysql雙寫(xiě)一致性
解決方案:
** 先更新數(shù)據(jù)庫(kù)震叮,再刪緩存胧砰,同時(shí),利用消息隊(duì)列苇瓣,防止刪緩存失敗導(dǎo)致的臟數(shù)據(jù)**尉间。步驟如下:(1)更新數(shù)據(jù)庫(kù)數(shù)據(jù)
(2)數(shù)據(jù)庫(kù)會(huì)將操作信息寫(xiě)入binlog日志當(dāng)中
(3)訂閱程序提取出所需要的數(shù)據(jù)以及key
(4)另起一段非業(yè)務(wù)代碼,獲得該信息
(5)嘗試刪除緩存操作击罪,發(fā)現(xiàn)刪除失敗
(6)將這些信息發(fā)送至消息隊(duì)列
(7)重新從消息隊(duì)列中獲得該數(shù)據(jù)哲嘲,重試操作。備注說(shuō)明:上述的訂閱binlog程序在mysql中有現(xiàn)成的中間件叫canal媳禁,可以完成訂閱binlog日志的功能眠副。至于oracle中,博主目前不知道有沒(méi)有現(xiàn)成中間件可以使用竣稽。另外囱怕,重試機(jī)制,博主是采用的是消息隊(duì)列的方式毫别。如果對(duì)一致性要求不是很高娃弓,直接在程序中另起一個(gè)線程,每隔一段時(shí)間去重試即可岛宦,這些大家可以靈活自由發(fā)揮台丛,只是提供一個(gè)思路。
可參考:https://blog.csdn.net/hjm4702192/article/details/80518922
4砾肺、緩存相關(guān)術(shù)語(yǔ)
[緩存相關(guān)術(shù)語(yǔ)](http://www.cnblogs.com/leeSmall/p/8594542.html)
4.1緩存雪崩
緩存雪崩我們可以簡(jiǎn)單的理解為:由于原有緩存失效挽霉,新緩存未到期間(例如:我們?cè)O(shè)置緩存時(shí)采用了相同的過(guò)期時(shí)間防嗡,在同一時(shí)刻出現(xiàn)大面積的緩存過(guò)期),所有原本應(yīng)該訪問(wèn)緩存的請(qǐng)求都去查詢數(shù)據(jù)庫(kù)了炼吴,而對(duì)數(shù)據(jù)庫(kù)CPU和內(nèi)存造成巨大壓力本鸣,嚴(yán)重的會(huì)造成數(shù)據(jù)庫(kù)宕機(jī)。從而形成一系列連鎖反應(yīng)硅蹦,造成整個(gè)系統(tǒng)崩潰荣德。
解決辦法:
1、并發(fā)量較小時(shí)童芹,在從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)的時(shí)候加鎖排隊(duì)
2涮瞻、高并發(fā)時(shí),給每一個(gè)緩存數(shù)據(jù)增加相應(yīng)的緩存標(biāo)記假褪,記錄緩存的是否失效署咽,如果緩存標(biāo)記失效,則更新數(shù)據(jù)緩存生音。
3.由于redis過(guò)期時(shí)間設(shè)置得比較統(tǒng)一宁否,導(dǎo)致緩存大面積過(guò)期
這個(gè)就對(duì)緩存失效時(shí)間進(jìn)行考慮,比如多少秒加個(gè)隨機(jī)數(shù)等缀遍,避免大面積失效就可以了
4.2 redis緩存穿透
redis在項(xiàng)目中是作為緩存使用慕匠,核心目的降低后臺(tái)壓力,增加響應(yīng)速度域醇。更極端的說(shuō)在項(xiàng)目中設(shè)計(jì)redis的的初衷就是用來(lái)抗并發(fā)壓力的台谊,
舉例說(shuō)明
比如:現(xiàn)在項(xiàng)目有100萬(wàn)并發(fā)量的可能,那么從成本考慮譬挚,會(huì)讓mysql承擔(dān)5萬(wàn)并發(fā)量锅铅,redis來(lái)承擔(dān)剩下的95萬(wàn)并發(fā)。大家結(jié)合之前練習(xí)中想象一下緩存步驟:
1.查詢數(shù)據(jù)先從緩存中獲取减宣,獲取為null盐须;
2.進(jìn)入mysql查詢,然后再緩存起來(lái)
假如第二步在mysql中也沒(méi)查詢到呢蚪腋,也就是查詢到為null值丰歌,那么緩存的就是null值,下次再來(lái)查詢依然得去數(shù)據(jù)庫(kù)查詢屉凯,如果超過(guò)5萬(wàn)個(gè)請(qǐng)求都是這樣的情況立帖,那么涼了,直接擊垮mysql服務(wù)器悠砚,或者響應(yīng)效率低晓勇,用戶的查詢請(qǐng)求直接打到mysql服務(wù)器。
** 解決方案:**
一、如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在绑咱,還是系統(tǒng)故障)绰筛,我們?nèi)匀话堰@個(gè)空結(jié)果(value值使用自定義默認(rèn)值代替)進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短描融,最長(zhǎng)不超過(guò)五分鐘铝噩。通過(guò)這個(gè)直接設(shè)置的默認(rèn)值存放到緩存,這樣第二次到緩存中獲取就有值了窿克,而不會(huì)繼續(xù)訪問(wèn)數(shù)據(jù)庫(kù)骏庸,這種辦法最簡(jiǎn)單粗暴!
二年叮、降級(jí):
當(dāng)系統(tǒng)承受不住外界的壓力,可以通過(guò)限流的方式具被,保證核心業(yè)務(wù)的運(yùn)行
當(dāng)系統(tǒng)承受不住外界的壓力,可以通過(guò)關(guān)閉非核心服務(wù)的方式,保證核心業(yè)務(wù)的運(yùn)行三只损、布隆過(guò)濾器
將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中一姿,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力跃惫。
4.3 緩存預(yù)熱
緩存預(yù)熱就是系統(tǒng)上線后叮叹,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。避免在用戶請(qǐng)求的時(shí)候爆存,先查詢數(shù)據(jù)庫(kù)衬横,然后再將數(shù)據(jù)緩存的問(wèn)題!用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)终蒂!
緩存預(yù)熱解決方案:
(1)直接寫(xiě)個(gè)緩存刷新頁(yè)面,上線時(shí)手工操作下遥诉;(2)數(shù)據(jù)量不大拇泣,可以在項(xiàng)目啟動(dòng)的時(shí)候自動(dòng)進(jìn)行加載;
(3)定時(shí)刷新緩存矮锈;
5霉翔、redis布隆過(guò)濾器
首先布隆過(guò)濾器是一種數(shù)據(jù)結(jié)構(gòu),類(lèi)似于set苞笨、hash表等-->是完成在海量數(shù)據(jù)來(lái)判斷某個(gè)值一定不存在债朵,或者判斷很大可能存在
安裝使用
插件在github上面有現(xiàn)成的,所以我們需要在linux先安裝git瀑凝,按命令做就行了序芦,不需要記
yum -y install git
useradd -m -d /home/git -s /usr/bin/git-shell git
mkdir -p /data/git
cd /data/git
git init --bare project1.git
chown git.git project1.git –R
cd /home/git
mkdir .ssh
chmod 700 .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
chown git.git .ssh –R安裝bloom filter:
cd /usr/local
git clone git://github.com/RedisLabsModules/rebloom
cd rebloom
make
然后再redis的redis.conf配置文件中添加
loadmodule /usr/local/rebloom/rebloom.so
6、如何從海量數(shù)據(jù)查詢某一個(gè)前綴的key
keys 正則表達(dá)式:會(huì)返回所有匹配的key
但是數(shù)據(jù)量過(guò)大的情況下會(huì)造成服務(wù)卡頓粤咪、阻塞服務(wù)器谚中,海量數(shù)據(jù)不能使用
可以用scan命令來(lái)代替keys*
命令: SCAN cursor [MATCH pattern] [COUNT count]當(dāng)游標(biāo)數(shù)據(jù)返回0,則表示遍歷結(jié)束
7、redis的主從宪塔、讀寫(xiě)
與mysql相同磁奖,redis也提供了主從的功能,更加非常簡(jiǎn)單某筐。Mysql的一主多從不能達(dá)到主高可用比搭,只能提高并發(fā),高可用需要mysql集群南誊,redis的主從通過(guò)哨兵機(jī)制可以達(dá)到高可用
高并發(fā):?jiǎn)挝粫r(shí)間類(lèi)身诺,可以接收的請(qǐng)求數(shù)量
高可用:mysql服務(wù)器的質(zhì)量場(chǎng)景:
1.在生產(chǎn)中難以避免單臺(tái)redis出現(xiàn)故障,保證高可用可以用主從
2.單臺(tái)redis官網(wǎng)說(shuō)能抗住10w并發(fā)量弟疆,超過(guò)了10w戚长,高并發(fā),就可以主從
3.QPS瓶頸
Qps:每秒處理的查詢次數(shù)
TPS:每秒處理的事務(wù)數(shù)(從請(qǐng)求到獲得數(shù)據(jù)怠苔,稱為一個(gè)完整事務(wù)過(guò)程)
大家記住第一個(gè)單詞同廉,Q就是query縮寫(xiě),T就是transaction縮寫(xiě)3.注意
1.一個(gè)master可以有多個(gè)slave
2.一個(gè)slave只能有一個(gè)master
3.數(shù)據(jù)流向是單向的柑司,master到slave
8迫肖、redis的哨兵機(jī)制
前面學(xué)習(xí)了redis的讀寫(xiě)分離,主從復(fù)制攒驰, 讀寫(xiě)分離蟆湖,利用從節(jié)點(diǎn)來(lái)減輕主節(jié)點(diǎn)的壓力。但是如果主節(jié)點(diǎn)因?yàn)橐恍┰虿7啵l(fā)生故障宕機(jī)隅津,那么寫(xiě)操作就無(wú)法完成。這個(gè)時(shí)候可以考慮集群方式來(lái)保證主節(jié)點(diǎn)的高可用劲室,也可以在很多從節(jié)點(diǎn)中選擇一個(gè)來(lái)作為新的主節(jié)點(diǎn)(故障遷移)伦仍。
redis就提供了哨兵機(jī)制(sentinel),來(lái)自動(dòng)完成故障遷移很洋,就是就是當(dāng)主節(jié)點(diǎn)發(fā)生故障時(shí)充蓝,自動(dòng)在從節(jié)點(diǎn)中選取一個(gè)作為主節(jié)點(diǎn)。
哨兵最好為奇數(shù)個(gè):找到哨兵的配置文件(注意:哨兵跟redis是獨(dú)立的喉磁,這兒只是在一臺(tái)機(jī)器上配置)
8.1 哨兵(sentinel)的三個(gè)定時(shí)任務(wù)
1.每10秒每個(gè)sentinel對(duì)master與slave節(jié)點(diǎn)執(zhí)行info谓苟,通過(guò)info能發(fā)現(xiàn)master的slave節(jié)點(diǎn)確定主從關(guān)系
2.每2秒各個(gè)sentinel會(huì)交換對(duì)節(jié)點(diǎn)的看法以及sentinel自身的信息
原理:在master中會(huì)有一個(gè)頻道 _sentinel:hello
每個(gè)sentinel都訂閱了該頻道,就會(huì)通過(guò)該頻道發(fā)送對(duì)節(jié)點(diǎn)的看法以及sentinel自身的信息协怒,也能搜到其他sentinel發(fā)送的信息3.每一秒sentinel對(duì)其他sentinel以及主從中所有節(jié)點(diǎn)發(fā)送ping涝焙,心跳檢測(cè),作為正吃邢荆或者宕機(jī)的判斷依據(jù)
8.2 主客觀下線
主觀下線:第二句配置的30000纱皆,表示sentinel在每秒的定時(shí)任務(wù)發(fā)送ping以后湾趾,30秒都沒(méi)有回復(fù),那么sentinel就會(huì)認(rèn)為該節(jié)點(diǎn)失敗派草,這是它一個(gè)人的看法搀缠,所以叫主觀下線
客觀下線:在第一行配置的2,表示所有sentinel中有2個(gè)都認(rèn)為該redis節(jié)點(diǎn)失敗(主觀下線)近迁,那么就認(rèn)為真的失敗了艺普,就可以繼續(xù)后續(xù)操作了
原理就是發(fā)送sentinel is-master-down-by-addr(地址)到_sentinel:hello,其它訂閱的就可以獲得信息
8.3 領(lǐng)導(dǎo)的選舉
目的:只需要一個(gè)sentinel完成故障轉(zhuǎn)移就夠了
上面的sentinel is-master-down-by-addr(地址)還有一個(gè)作用鉴竭,就是sentinel節(jié)點(diǎn)告訴其它sentinel我要當(dāng)領(lǐng)導(dǎo)歧譬。規(guī)則:
1.每個(gè)做主觀下線的sentinel發(fā)送命令到其它sentinel告知master節(jié)點(diǎn)信息,以及要求其它sentinel設(shè)置發(fā)送該命令的sentinel成為領(lǐng)導(dǎo)
2.每個(gè)sentinel只會(huì)統(tǒng)一收到第一個(gè)命令的發(fā)送者成為領(lǐng)導(dǎo)搏存,投一票
3.如果有一個(gè)sentinel發(fā)現(xiàn)自己的票數(shù)超過(guò)sentinel集合半數(shù)并且超過(guò)了之前配置中的2瑰步,那么就會(huì)成為領(lǐng)導(dǎo)
4.該算法可能會(huì)有多個(gè)sentinel被選為領(lǐng)導(dǎo),這個(gè)時(shí)候就會(huì)過(guò)一段時(shí)間從新選舉
8.4 故障的轉(zhuǎn)移
1.sentinel會(huì)在slave中選取一個(gè)來(lái)做為新的master
選擇依據(jù):(了解)
1.會(huì)查看slave中是否配置的優(yōu)先級(jí)slave-priority璧眠,選擇優(yōu)先級(jí)高的(運(yùn)維人員可以根據(jù)機(jī)器的配置高低去配置優(yōu)先級(jí))
2. 如果都沒(méi)有配置那么就是相同的缩焦,會(huì)選擇偏移量最大的slave節(jié)點(diǎn)(了解即可)
3.選擇runid最小的(就是redis運(yùn)行的id,相當(dāng)于一個(gè)標(biāo)識(shí)符)2.選擇了新的master责静,sentinel就會(huì)對(duì)剩下的slave發(fā)送命令袁滥,去復(fù)制新的master,復(fù)制規(guī)則灾螃,如圖题翻,下面就是表示一個(gè)一個(gè)來(lái)
3.sentinel還會(huì)繼續(xù)監(jiān)控掛掉的master,如果master復(fù)活了腰鬼,會(huì)命令master去從屬于新選舉的master
9嵌赠、redis為什么是單線程?
因?yàn)镃PU不是Redis的瓶頸熄赡。Redis的瓶頸最有可能是機(jī)器內(nèi)存或者網(wǎng)絡(luò)帶寬猾普。(以上主要來(lái)自官方FAQ)既然單線程容易實(shí)現(xiàn),而且CPU不會(huì)成為瓶頸本谜,那就順理成章地采用單線程的方案了。
10偎窘、redis與mysql
在使用mysql的時(shí)候乌助,可以手動(dòng)新建數(shù)據(jù)庫(kù),來(lái)分類(lèi)存儲(chǔ)不同的業(yè)務(wù)數(shù)據(jù)陌知,同樣的redis默認(rèn)就有0-15的16個(gè)庫(kù)他托,默認(rèn)使用0號(hào)庫(kù)
切庫(kù)操作:
select 0……15dbsize:查看當(dāng)前庫(kù)中多少個(gè)key
flushall:清空當(dāng)前庫(kù)
也可以在配置文件配置個(gè)數(shù):databases 16
10.1 為什么需要redis
先看mysql的執(zhí)行流程:
1.有sql語(yǔ)句請(qǐng)求查詢的時(shí)候,首先到查詢緩存cache中查找仆葡,如果有立刻返回赏参,這是速度最快查詢志笼,因?yàn)椴樵兙彺嬖趦?nèi)存中,
2.如果緩存沒(méi)有把篓,進(jìn)入查詢解析器纫溃,生成解析樹(shù)(了解即可)
3.查詢優(yōu)化器(mysql對(duì)一些sql語(yǔ)句進(jìn)行優(yōu)化,比如我們之前的join驅(qū)動(dòng)表)
4.生成執(zhí)行計(jì)劃(explain)
5.進(jìn)入存儲(chǔ)引擎韧掩,索引是存儲(chǔ)引擎決定的紊浩,如果索引能返回?cái)?shù)據(jù)就不需要去表里面查詢了。
6.沒(méi)有找到疗锐,進(jìn)入表中全表掃描
結(jié)論:
通過(guò)mysql的執(zhí)行流程可以看出坊谁,如果在內(nèi)存中存在數(shù)據(jù)返回,是效率最高滑臊、速度最快的口芍。因?yàn)閙ysql的核心是注重于數(shù)據(jù)的持久安全,因此能夠基于內(nèi)存的數(shù)據(jù)庫(kù)(nosql)應(yīng)運(yùn)而生雇卷,我們學(xué)習(xí)其中最流行的redis鬓椭。
10.2 有了redis還需要mysql么?
1.在之前介紹redis時(shí)候聋庵,redis既能基于內(nèi)存膘融,也能持久化到磁盤(pán),但是主打內(nèi)存效率的redis祭玉,持久化功能遠(yuǎn)遠(yuǎn)比不上mysql氧映。而大量數(shù)據(jù)都放入內(nèi)存,需要很高的硬件支持脱货,不太現(xiàn)實(shí)
2.Mysql有完善的事務(wù)機(jī)制岛都,能滿足項(xiàng)目需求,redis雖然也有事務(wù)振峻,但是很多場(chǎng)景無(wú)法滿足
3.Redis雖然有5種數(shù)據(jù)結(jié)構(gòu)臼疫,但是過(guò)于復(fù)雜的數(shù)據(jù)關(guān)系给猾,還是無(wú)法清晰表現(xiàn)诡曙,mysql通過(guò)行和列牲芋、表與表的關(guān)系旬痹,讓數(shù)據(jù)與數(shù)據(jù)直接之間的關(guān)系一目了然每币。
所以在使用中都是redis+mysql便斥。redis主管數(shù)據(jù)緩存到內(nèi)存挚冤,用于提高查詢效率呢诬,mysql主管數(shù)據(jù)存儲(chǔ)到磁盤(pán)利诺,用于保存重要不能丟失的數(shù)據(jù)
11富蓄、redis的分布式鎖
利用setex的原子操作(在分布式環(huán)境中,redis是共用的慢逾,所以可以使用setex的成功作為獲得鎖的標(biāo)志)
@Scheduled(cron="0 */1 * * * ?")
public void cancelOrder(){
log.info("定時(shí)任務(wù)啟動(dòng)..................當(dāng)前時(shí)間:{}",new Date());
//因?yàn)閟etnxAndExpire方法設(shè)置值與設(shè)置時(shí)間是原子操作立倍,所以就可以達(dá)到分布式鎖的目的
//大家如果去看到另外的版本 setnx與expire兩個(gè)方法 是分開(kāi)的那么就不是原子操作灭红,這兩個(gè)方法,執(zhí)行期間可能會(huì)出現(xiàn)服務(wù)器宕機(jī)什么的造成死鎖
boolean flag = redisUtils.setnxAndExpire(LOCK_KEY,String.valueOf(System.currentTimeMillis() + 50000), EXPIRE);
if(flag) {
try {
log.info("獲得分布式鎖...");
進(jìn)行對(duì)應(yīng)的操作
}finally {
//不管時(shí)間到?jīng)]到口注,業(yè)務(wù)做完了就可以釋放鎖了
釋放分布式鎖
redisUtils.del(LOCK_KEY);
}