Redis 6****
一.Redis介绍****
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
二. 下载安装****
下载epel仓库yum install epel-release -y
下载redis数据库yum install redis -y
启动redis服务systemctl start redis
2.1 Redis常见命令****
systemctl status redis 查看服务状态
systemctl stop redis 停止服务
systemctl restart redis 重启服务
ps -ef | grep redis 查看reids服务信息
systemctl enable redis redis开机启动
2.2 redis启动界面****
设置redis 远程连接和密码
vim /etc/redis.conf 如果没有vim先yum install -y vim
注释 #bind 127.0.0.1
修改protected-mode no
修改 daemonize yes
修改 requirepass Dd123=123
关闭防火墙或者开放6379端口(请自行百度)
1,yum install redis -- 安装redis数据库(-- yum安装方式的redsi配置文件在/etc/redis.conf)
2,systemctl start redis.service --开启redis服务
3,ps -ef | grep redis -- 查看redis是否开启
4,修配置文件-修改密码
requirepass foobared 注释去掉 ,修改为 requirepass 123456 //修改密码
5,systemctl restart redis.service --重启
/usr/local/bin/redis-cli进入操作
Redis基础知识****
Redis默认有16个数据库,默认的是第0个。
可以使用select进行切换数据库,
DBSIZE 查看DB大小,
keys * 查看所有的key,
清除当前数据库 flushdb,
清除全部数据库的内容flushall
2.3 Redis是单线程的****
明白Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis瓶颈是根据机器的内存和网络带宽,既可以使用单线程来实现,就使用单线程!所有就使用了单线程了!
Redis是C语言写的,官方提供数据为100000+QPS,完全不比同样使用key-vale的Memecache差!
2.4 Redis为什么单线程还这么快?****
1. 误区1:高性能的服务器一定是多线程的?
2. 误区2:多线程(CPU上下文会切换)一定比单线程效率高!
先去CPU>内存>硬盘的速度要有所了解:
核心:Redis是将所有的数据全部防止内存系统中,所以说使用单线程操作效率就是最高的,多线程(CPU上下文会切换:耗时操作!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下这个就是最佳方案!
2.5 Redis-key基本命令****
EXISTS name 判断当前key是否存在
Keys * 查看所有
Clear 清屏
Del/unlink name删除指定数据
Move name 1 移除当前key
EXPIRE name 10 设置key的过期时间,单位秒
TTL name 查看当前key的剩余时间
Type name查看当前key的一个类型
三.Redis类型****
3.1 String(字符串):****
APPEND key:追加字符串,如果当前key不存在,就相当于setkey
STRLEN key:获取字符串长度
步长:set views 初始值为0
incr views :自增1
Decr views :自减1
INCRBY views 10:可以设置步长,指定增量
DECRBY views5:可以设置步长,指定减量
字符串范围range:
GETRANGE key1 0 3(截取字符串0到3)
替换: SETRANGE key2 1 xx(替换指定位置开始的字符串)
Setex :设置过期时间
Setnx :不存在在设置。没有就创建,有提示创建失败
Mset : 同时设置多个值
Mget :同时获取多个值
Msetnx :是一个原子性的操作,要么一起成功,要么一起失败
Getset :先get再set 如果不存在,则返回nil;如果存在获取原来的值并设置新的值
Getrange<起始位置><结束位置>
Setrange<起始位置>
3.2 List****
Lpush/rpush ...从左边/右边插入一个或多个值
Lpop/rpop从左边/右边吐出一个值。值在键在,值光键亡
Rpoplush从key1列表右边吐出一个值,插入到key2列表左边
Lrange按照索引获得元素(从左到右)
Lindex按照索引获取元素
Llen获取列表长度
Linsertbefore 在value后面插入newvalue插入值
Lrem从左边删除n个value(从左到右)
Lset将key下标为index的值替换为value
3.3 Set****
Sadd 将一个或者多个value添加到key中,已经存在的忽略
Smembers取出key的值
Sismember判断集合key是否含有value值
Srem... 删除集合中某个元素
Scard返回集合个数
Srem随机吐出一个值
Srandmember随机吐出n个值不会删除
Smovevalue把集合中的值从一个集合移动到另一个
Sinter返回两个集合的交集元素
Sunion返回两个集合的并集元素
Sdiff返回两个集合的差集元素(key1中的,不包括key2的)
3.4 hash****
Hset给key中的filed键赋值value
Hget从key中field取出value
Hmset...批量设置hash值
Hexists查看哈希表中key中,给定义域field是否存在
Hkeys列出该hash集合所有field
Hvals列出该hash集合的所有value
Hincrby为哈希表key中的域filed的值增量
Hsetnx将哈希表key中的field的值设置为value。并且仅当域field不存在
3.5有序集合zset****
Zadd...将一个或者多个member元素及其score值加入到有序key中
Zrange[withscores]返回有序集合key中下标在start stop之间的元素带withscores,可以让方式一起返回到结果集
Zrangebyscore key minmax[withscores][limit offset count]返回有序集key中所有score值介于min和max之间的成员有序集合成员按score递增(从小到大)排序
Zrevrangebyscore key maxmin[withscores][limit offset count]从大的小
Zincrby为元素的scores加上增量
Zrem删除该集合,指定值的元素
Zcount统计该集合,分数区间内元素个数
Zrank返回该值在集合中的排名,从0开始
四.Redis发布订阅****
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
Redis客户端可以订阅任意数量的频道
五.新数据类型****
5.1新数据类型BITMAPS****
Setbit设置bitmaps中某个偏移的值(0或1)
Getbit获取bitmaps中某个偏移的值
Bitcount[start end]统计字符串从start字节到end字节比特值为1的数量
Bitop and(or/not/xor)[key...]bitop是一个复合操作,他可以多个bitmaps的and(交集),or(并集),not(非),xor(异或)操作并将结果保存在destkey中。
bitop and unique:users:and:20201104_03 unique:users:20201103 unique:users:20201104
(integer) 2
5.2新数据类型hyperloglog(基数的计算)****
Pfadd[element...]添加指定元素到hyperloglog
Pfcount[key...]计算HLL近似值
Pfmerge[sourcekey...]将一个或者多个HLL合并后结果存储在另一个HLL中
5.3新数据类型geospatial****
Geoadd[longitude latitude member...]添加地理位置(经度,维度,名称)
Geopos[member...]获取指定地区的坐标值
Geodist[m|km|ft|mi]获取两个位置之间的直线距离
Georadiusradius m|km|ft|mi 以给定的经纬度为中心。找出某一半径内的元素
六.测试****
6.1jedis所需要的jar包
< dependencies *>
*< dependency *>
*< groupId > redis.clients </ groupId *>
*< artifactId > jedis </ artifactId *>
*< version > 3.2.0 </ version *>
*</ dependency *>
*</ dependencies >
6.2模拟测试
public static void main ( String [] args *) {**
***//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
//测试
String value= jedis.ping () ;
System.out.println ( value ) ;
}
运行错误(解决办法为6.3 6.4)connect timed out
能够正确运行
PONG
6.3 查看/关闭防火墙
[root@192 ccy]# systemctl status firewalld 查看是否关闭
[root@192 ccy]# systemctl stop firewalld 关闭
6.4 将保护模式protected-mode 为no
[root@laptop-j04qrhqu ccy]# /usr/local/bin
bash: /usr/local/bin: 是一个目录
[root@laptop-j04qrhqu ccy]# cd /usr/local/bin
[root@laptop-j04qrhqu bin]# ./redis-cli
127.0.0.1:6379> config get protected-mode
-
"protected-mode"
-
"yes"
127.0.0.1:6379> config set protected-mode no
OK
127.0.0.1:6379> config get protected-mode
-
"protected-mode"
-
"no"
七.测试相关数据类型****
7.1 Jedis-API: key 执行添加
//操作key
@Test
public void demo1 *(){**
//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
//添加
jedis.set ( "name","ccy" ) ;
//获取
String name=jedis.get ( "name" ) ;
System.out.println ( name ) ;
Set < String > keys=jedis.keys ( "" ) ;
for ( String key :keys *){
*System.out.println ( key ) ;
*}
*}
7.2 Jedis-API :String
//设置多个key-value
jedis.mset ( "s1","v1","s2","v2" ) ;
List < String > mget=jedis.mget ( "s1","s2" ) ;
System.out.println ( mget ) ;
7.3 Jedis-API :List
//操作list
@Test
public void demo2 *(){**
***//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
jedis.lpush ( "key1","lucy","maet","java" ) ;
List < String > values=jedis.lrange ( "key1",0,-1 ) ;
System.out.println ( values ) ;
}
7.4 Jedis-API :set
@Test
public void demo3 *(){**
***//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
jedis.sadd ( "names","lucy" ) ;
jedis.sadd ( "names","mary" ) ;
Set < String > names =jedis.smembers ( "names" ) ;
System.out.println ( names ) ;
}
7.5 Jedis-API :hash
//操作hash
@Test
public void demo4 *(){**
***//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
jedis.hset ( "users","age","20" ) ;
String hget=jedis.hget ( "users","age" ) ;
System.out.println ( hget ) ;
}
}
7.6 Jedis-API :zshe
///操作zshe
@Test
public void demo5 *(){**
***//创建jedis对象
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
jedis.zadd ( "china",100d,"shanghai" ) ;
Set < String > china=jedis.zrange ( "china",0,-1 ) ;
System.out.println ( china ) ;
jedis.close () ;
}
八.模拟验证码发送
1. 输入手机号,点击发送随机生成6位数字码,
public static void main ( String [] args *) {
*String code=getCode () ;
System.out.println ( code ) ;
*}
*//1随机生成6位数字验证码
public static String getCode *(){
*Random random=new Random () ;
String code="";
for ( int i = 0; i <6 ; i++ *) {
***int rand =random.nextInt ( 10 ) ;
code+=rand;
} return code;
}
2. 两分钟内有效,把验证码放入Redis里面,设置过期时间为120秒
//2 每个手机每天只能发送三次,验证码放到Redis中,设置过期时间
public static void verifyCode ( String phone *){
//连接Redis
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
//拼接key
//手机发送次数
String countKey="VerifyCode"+phone+":count";
//验证码key
String codeKey="VerifyCode"+phone+":code";
//每个手机每天只能发送三次
String count=jedis.get ( countKey ) ;
if ( count == null *){
**//没有发送次数,第一次发送
//设置发送次数是1
jedis.setex ( countKey,246060,"1" ) ;
} else if ( Integer.parseInt ( count ) <=2 *){
*//发送次数加1
jedis.incr ( countKey ) ;
} else if ( Integer.parseInt ( count ) >2 *){
***//发送三次,不能再发送
System.out.println ( "今日发送次数已经超过三次了哦!!!!" ) ;
jedis.close () ;
return;
*}**
***//发送验证码放到Redis
String vcode=getCode () ;
jedis.setex ( codeKey,120,vcode ) ;
jedis.close () ;
}
3. 判断验证码是否符合一致,从Redis获取验证码和输入的验证码进行比较
//3 验证码校验
public static void getRedisCode ( String phone,String code *){**
*//从Redis获取验证码
Jedis jedis=new Jedis ( "192.168.1.6",6379 ) ;
//验证码key
String codekey="VerifyCode"+phone+":code";
String reidsCode=jedis.get ( codekey ) ;
//判断
if ( reidsCode.equals ( code *)){
*System.out.println ( "成功" ) ;
} else *{
***System.out.println ( "失败" ) ;
} jedis.close () ;
}
4. 每个手机每天只能发送3次验证码, incr每次发送之后+1,大于2的时候提交不能发送。
public static void main ( String [] args *) {**
*//模拟验证码发送
verifyCode ( "13656458936" ) ;
//getRedisCode("13656458936","260372");
}
已经三次后会出现
今日发送次数已经超过三次了哦!!!!
九.springboot整合Redis****
1. 添加依赖
<
< dependency *>
*< groupId > org.springframework.boot </ groupId *>
*< artifactId > spring-boot-starter-data-redis </ artifactId *>
*</ dependency *>
*
< dependency *>
*< groupId > org.apache.commons </ groupId *>
*< artifactId > commons-pool2 </ artifactId *>**
****
*</ dependency >
2. 在application.properties配置redis
#redis服务器地址
spring.redis.host=192.168.1.6
#redis服务器连接端口
spring.redis.port=6379
#redis数据库索引(默认为0)
spring.redis.database=0
#连接超时时间(毫秒)
spring.redis.timeout=1800000
#连接池最大连接数(用负值表示没有限制)
spring.redis.lettuce.pool.max-idle=20
#最大阻塞等待时间(负数表示没有限制)
spring.redis.jedis.pool.max-idle=5
#连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
3. 添加redis配置类
package com.aaa.redis_springboot.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurationSelector;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurationSelector *{**
*@Bean
public RedisTemplate < String, Object > redisTemplate ( RedisConnectionFactory factory *) {
*RedisTemplate < String, Object > template = new RedisTemplate <>() ;
RedisSerializer < String > redisSerializer = new StringRedisSerializer () ;
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 ) ;
template.setConnectionFactory ( factory ) ;
//key序列化方式
template.setKeySerializer ( redisSerializer ) ;
//value序列化
template.setValueSerializer ( jackson2JsonRedisSerializer ) ;
//value hashmap序列化
template.setHashValueSerializer ( jackson2JsonRedisSerializer ) ;
return template;
*}
*@Bean
public CacheManager cacheManager ( RedisConnectionFactory factory *) {
*RedisSerializer < String > redisSerializer = new StringRedisSerializer () ;
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 ) ;
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig *()
*.entryTtl ( Duration.ofSeconds ( 600 *))
*.serializeKeysWith ( RedisSerializationContext.SerializationPair.fromSerializer ( redisSerializer *))
*.serializeValuesWith ( RedisSerializationContext.SerializationPair.fromSerializer ( jackson2JsonRedisSerializer *))
*.disableCachingNullValues () ;
RedisCacheManager cacheManager = RedisCacheManager.builder ( factory *)
*.cacheDefaults ( config *)
*.build () ;
return cacheManager;
*}
}
*
如果factory一直下面有红线可以:降低Autowired检测的级别,将Severity的级别由之前的error改成warning或其它可以忽略的级别
4. 测试一下
@RestController
@RequestMapping ( "/redisText" *)
*public class RedisController *{
*@Autowired
private RedisTemplate redisTemplate;
@GetMapping
public String testRedis *(){
*//设置值到redis
redisTemplate.opsForValue () .set ( "name","lucy" ) ;
//从redis获取值
String name= ( String ) redisTemplate.opsForValue () .get ( "name" ) ;
return name;
*}
*}
正确结果为
lucy
如果错误的话很有可能是common-pool2版本问题。改为下图所示应该可以了
\
< dependency *>
*< groupId > org.apache.commons </ groupId *>
*< artifactId > commons-pool2 </ artifactId *>**
*</ dependency >
十.Redis事物和锁机制****
10.1基本操作****
输入multi命令开始,输入的命令依次进入命令队列中,但不会执行,直到输入exec后redis会将之前的命令队列中的命令依次执行。组队的过程通过discard来放弃组队。
10.1.1正确的示范
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> set key1 value1
QUEUED
127.0.0.1:63792> set key value2
QUEUED
127.0.0.1:63792> exec
-
OK
-
OK
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> set v1 s1
QUEUED
127.0.0.1:63792> set v2 s2
QUEUED
127.0.0.1:63792> discard
OK
127.0.0.1:6379[2]> keys *
-
"key1"
-
"key"
10.1.2现在来看错误的
错误的有两种情况
(1). 组队过程中某个命令出现了报告错误,执行时整个的所有队列都会被消失,代码如下
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> set b1 v1
QUEUED
127.0.0.1:63792> set b2 v2
QUEUED
127.0.0.1:63792> set b3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:63792> exec
(error) EXECABORT Transaction discarded because of previous errors.
(2). 如果执行阶段某个命令报出错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚,代码如下
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> set c1 v1
QUEUED
127.0.0.1:63792> incr c1
QUEUED
127.0.0.1:63792> set c2 v2
QUEUED
127.0.0.1:63792> exec
-
OK
-
(error) ERR value is not an integer or out of range
-
OK
10.2 事物冲突
10.2.1悲观锁
悲观锁,顾名思义就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次拿数据都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
10.2.2乐观锁
乐关锁,就是很乐观,每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据可以受版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用check-and set机制实现事物的。
在执行multi之前,先执行watch key1[key2],可以监视一个(多个)key,如果在事物执行之前这个(或这些)key被其他命令所改动,那么事物将被打断
第一个
127.0.0.1:6379[2]> set balance 100
OK
127.0.0.1:6379[2]> keys *
- "balance"
127.0.0.1:6379[2]> watch balance
OK
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> incrby balance 10
QUEUED
127.0.0.1:63792> exec
- (integer) 110
第二个
127.0.0.1:6379[2]> watch balance
OK
127.0.0.1:6379[2]> multi
OK
127.0.0.1:63792> incrby balance 20
QUEUED
127.0.0.1:63792> exec
(nil)
10.2.3redis事物三特性
1)单独的隔离操作
2)没有隔离级别的概念
3)不保证原子性
十一.Redis持久化****
11.1 RDB
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话将的snapsot快照,它恢复是将快照文件直接读到内存里。
11.1.1备份
Redis会将创建一个子进程进行持久化,会将数据写入到一个临时文件中,待持久化进程都结束了,再用这个临时文件替换上次持久化郝的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那rdb发送要比aof方式更加的高级。Rdb的缺点是最后一次持久化的数据可能会丢失。
11.1.2 fork
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量,环境变量,程序计算器)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
11.2 AOF
11.2.1 aof是什么
以日志形势来记录每个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只许追加但不可以改写,redis启动之初读取该文件重新构建数据,换而言之,redis重启的话根据日志文件的内容将写指令从前到后执行一次完成数据的恢复工作。
11.2.2 aof和rdb同时开启redis听谁的?
系统默认取aof的数据(数据不会存在丢失)
11.2.3修复
redis-check-aof --fix appendonly.aof
十二.主从复制
12.1简介
主机数据更新后根据配置和策略,自动同步备份master/slaver机制master以写为主,slave以读为主。特点:读写分离,性能扩展;容灾快速恢复
12.2主从复制(:%S/6379/6381)
[root@192 myredis]# vi redis6379.conf
[root@192 myredis]# ls
redis6379.conf redis.conf
[root@192 myredis]# vi redis6379.conf
[root@192 myredis]# cp redis6379.conf redis6380.conf
[root@192 myredis]# ls
redis6379.conf redis6380.conf redis.conf
[root@192 myredis]# vi redis6380.conf
[root@192 myredis]# ls
redis6379.conf redis6380.conf redis.conf
[root@192 myredis]# cp redis6379.conf redis6381.conf
[root@192 myredis]# ls
redis6379.conf redis6380.conf redis6381.conf redis.conf
[root@192 myredis]# vi redis6381.conf
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dum6379.rdb
十三.Redis集群****
13.1 redis集群配置
cluster-enabled yes 打开集群
cluster-config-file nodes-6379.conf 设置节点配置文件名
cluster-node-timeout 15000 设定节点失联时间,超过改时间(毫秒),集群自动进行主从切换。
:%s/6379/6380 修改从6379里面的内容修改成6380
redis-serve redis6379.conf 启动
ps -ef | grep redis 查看所有启动redis
cluster nodes 查看集群信息
13.2 集群操作
一共有16384个插槽 也就是说是0——16383个
cluster getkeysinslot返回count个slot中的键
十四.缓存****
14.1缓存穿透原因
缓存穿透:是指缓存和数据库中都没有的数据,而用户不断发起请求,导致数据库压力过大。
有两个原因:1.redis查询不到数据库
2.出现很多非正常URL访问
14.2缓存穿透解决方案
有四种:1对空值缓存
2.设置可访问名单
3. 采用布隆过滤器
4. 进行实时监控
14.3缓存击穿和原因
缓存击穿:是指缓存中没有,但是数据库中有的数据,这时由于并发用户特别多,同时读缓存没有读到数据,导致又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
原因:redis中的某个key过期了大量使用这个key
14.4缓存击穿解决办法
1. 预先设置热门数据
2. 实时调整
3. 使用锁
14.5雪崩
雪崩:是指缓存中数据大批量到了过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
在极少的时间段,查询大量key的集中过期情况
14.6雪崩解决方案
1. 构建多级缓存架构
2. 使用锁或队列
3. 设置过期标志更新缓存
4. 将缓存失效时间分散开
十五.本地缓存和分布式缓存****
15.1本地缓存
本地缓存就是:缓存组件和业务组件属于同一个进程,即在同一个项目中
15.2分布式缓存
分布式缓存:将所有商品服务缓存的数据都放在一个缓存中间件中
十六.分布式锁****
16.1实现方案
1. 基于数据库实现分布式锁
2. 基于缓存(Redis) 性能最高
3. 基于zookeeper 可靠性最高
16.2解决方案
16.2.1 redis实现分布式锁
setnx user 10 加锁
Del user 释放
expire user 10 锁一直没有释放就给他设置一个过期时间,自动释放
ttl user查看剩余时间
上set user 10 nx ex 12 锁之后突然出现异常,无法设置过期时间了上锁的时候同时设置过期时间就可以了
16.2.2 确保分布式锁可用条件
1.互斥性。在任意时刻,只有一个客户端能持有锁
2.不会发生死锁。即使有一个客户端在持有锁的期间崩溃没有主动解锁,也能保证后续其他客户端能加锁。
3.解铃还须系铃人,加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了
4.加锁和解锁必须具有原子性。
十七.新功能****
acl list 展示用户权限列表
acl cat 查看添加权限指令类别
acl whoami 命令查看当前用户
acl setuser lucy 添加
acl setuser user2 on >password ~cached:*+get 设置有用户名,密码,ACL权限,并开启用户
auth mary password 切换用户
17.2 IO多线程
配置文件
io-threads-do-redis yes
Io-threads 4