1.Redis相关知识
默认16个数据库,类似数组下标从0开始,初始默认使用0号库。
使用命令:
切换数据库 select <dbid> 如:select 8
查看当前数据库key数量 dbsize
清空当前库 flushdb
通杀全部数据库 flushall
redis是单线程+多路IO复用技术
多路复用是指使用一个线程来检查多个文件描述符的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直 到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行。
2.Redis 键key
keys * 查看当前库所有key
exists key 判断某个key是否存在
type key 查看key是什么类型
del key 删除指定key数据
unlink key 根据value选择非阻塞删除
仅将keys从keyspace元数据中删除,真正的删除会从后续异步删除
expire key 10 为给定的key设置过期时间
ttl key 查看还有多少秒过期 -1 表示永不过期 -2 表示已经过期
3. Redis字符串(String)
简介:
String 类型是二进制安全的。意味着Redis的String可以包含任何数据,比如jpg图片,或者序列化对象。
String类型Redis最基本数据类型,一个Redis中字符串value最多可以是512M。
数据结构:
String的数据结构为简单动态字符串。是可以修改的字符串,内部实现类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
命令:
set key value 添加键值对
get key 查询对应键值
append key value 将给定value追加到原值末尾
strlen key 获取值的长度
setnx key value 只有key 不存在时 设置key值
incr key 将key中存储的数字值增1(只能是数字值操作,如果为空,新增值为1)
decr key 将key中存储的数字值减1
incrby/decrby key 步长 将key中存储的数字值增减
mset k1 v1 k2 v2 同时设置一个或者多个key-value对
mget k1 k2 同时获取一个或者多个 value
msetnx k1 v1 k2 v2 同时设置一个或者多个key-value对,当且仅当所有给定key都不存在。
原子性,有一个失败则都是失败
getrange k1 起始位置 结束位置
setrange key 起始位置 value 在第几个位置插入数据,覆写起始位置后的值
setex key 过期时间 value 设置键值的同时设置过期时间
getset key value 以旧换新,设置新值同时获取旧值。
4. Redis列表(List)
简介:单键多值
Redis列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部或者尾部。
它的底层实际是一个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
数据结构:
List的数据结构为快速链表quickList,首先在列表较少的情况下使用一块连续的内存存储,这个结构式ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续内存。当数据量比较多的时候才会改成quicklist。
命令:
lpush/rpush k1 v1 v2 v3 ... 从左边/右边插入一个或多个值。
lpop/rpop k1 从左边、右边吐出一个值。
rpoplpush k1 k2 从右边吐出一个值,插入k2左边
lrange k sart stop 按索引获取元素从左到右
lindex k index 按照索引下标获取元素
llen k 获取列表长度
linsert k1 before v newvalue
lrem k n v 从左边删除n个value
lset k index v 将列表k下标为index的值替换成value
5.Redis集合(Set)
简介: Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重,当需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择。Redis的Set是String类型的无序集合。它的底层其实是一个value为null的hash表,所以增加,删除,查询的复杂度都是O(1)。
数据结构:
Set数据结构是dict字典,字典是用哈希表实现的。
命令:
sadd k v1 v2 v3 将一个或者多个member元素加入集合key中,已经存在的member元素将会被忽略。
smembers k 取出该集合的所有值
sismember k v 判断集合key是否含有v值 有为 1 没有为 0
scard k 返回集合元素的个数
srem k v1 v2 删除集合中的某个元素
spop k 随机从该集合中吐出一个值
srandmember k n 随机从该集合中取出n个值,不会从集合中删除
smove source destination v 把集合中一个值从一个集合移动到另一个集合
sinter k1 k2 返回两个集合交集元素
sunion k1 k2 返回集合的并集
sdiff k1 k2 返回两个集合的差集
6.Redis哈希(Hash)
简介:
Redis hash是一个键值对集合。
Redis hash是一个String类型的filed和value 的映射表,hash特别适合用于存储对象。
类似于Java里面的Map<String,Object>
用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息。
数据结构:
Hash类型对应数据结构有两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable
命令:
hset k field v 给k集合中的field键赋值value
hget k1 field 从k集合field取出value
hmset k field1 v1 field2 v2 批量设置hash值
hexists k field 查看哈希表key 中,给定域field是否存在
hkeys k 列出该hash集合的所有field
hvals k 列出该hash集合所有value
hincrby k field increment· 为哈希key中的域增加增量
hsetnx k field value 将哈希表key中的域field的值设置为value,当且仅当域field不存在·
7.Redis有序集合Zset(sorted set)
简介:
Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。
不同之处是有序集合的每个成员关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以重复。
因为元素是有序的,所以可以很快的根据评分或者次序来获得一个范围的元素。
访问有序集合的中间元素也是非常快。
数据结构:
SortedSet(zset)是Redis提供的一种非常特别的数据结构,一方面它等价于Java的数据结构Map<String,Double>,可以给每个元素value赋一个权重score,另一方面又类似于TreeSet,内部的元素会按照权重score进行排序,可以的得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset底层使用了两个数据结构:
①hash,hash的作用就是关联元素value和权重socre,保障元素value的唯一性,可以通过元素value找到相应score值,
②跳跃表,跳跃表的目的在于给元素value排序,根据socre的范围获取元素列表。
命令:
zadd key score value score value 将一个或者多个member元素及其score值加入到有序集key当中。
zrange key start stop 【withscores【 返回有序集key中,下标在start stop之间的元素 带withscores 可以让分数一起和值返回到结果集
zrangebyscore key min max 【withscores】【limit offset count】返回有序集key中,所有score值介于min和max之间(包含min或max,从小到大排列)的成员
zrevrangebyscore key max min【withscores】【limit offset count】返回有序集key中,所有score值介于min和max之间成员(从大到小排列)
zincrby k increment v 为元素的score加上增量
zrem k v 删除该集合下指定元素
zcount k min max 统计该集合,分数区间个数
zrank k v 返回该值在集合中的排名,从0开始
8.Redis的发布和订阅
Redis发布订阅是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis客户端可以订阅任意数量的频道。
发布订阅命令行实现:
① 打开客户端订阅 channel1
subscribe channel
② 打开另一个客户端,给channel1发布消息hello
publish channel1 hello
9. Bitmaps
简介:
现代计算机用二级制作为信息的基础单位,1个字节等于8位,例如 “abc”字符串是由3个字节组成,但实际计算机存储时将其用二级制表示,“abc” 分布对应ASCII码分别是 97、98、99,对应二进制是01100001、01100010、01100011。合理地使用操作位能够有效地提高内存使用率和开发效率。
Redis提高了Bitmaps这个数据类型可以实现对位地操作:
①Bitmaps本身不是一种数据类型,实际就是字符串但是它可以对字符串的位进行操作
②Bitmaps单独提高一套命令,所以在Redis中使用Bitmaps和使用字符串不同。可以将Bitmaps想象成一个以位单位的数组,数组每个单位只能存储0和1,数组下标在Bitmaps中叫偏移量。
命令:
setbit key offset value 设置Bitmaps中某个偏移量的值(0或1)offset:偏移量从0开始
getbit key offset 取出Bitmaps中某个偏移量的值
bitcount key 【start end】统计字符串从start字节到end字节比特值为1的数量
10.Redis整合SpringBoot
1.引入依赖
2.application.properties配置redis
3.添加redis配置类
@Configuration
//开启缓存
@EnableCaching
public class RedisConfig {
/**
* 重写 redis序列化方,使用Json方式
* @param redisConnectionFactory redis连接工厂
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 重写redis注解序列化,使用Json方式
* @param redisConnectionFactory
* @return
*/
@Bean
@Primary
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L))
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration)
.build();
}
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
}
private RedisSerializer<Object> valueSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
4.测试
@RestController
public class RedisController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@GetMapping("/getcode")
public String getCode(){
return stringRedisTemplate.opsForValue().get("k1").toString();
}
}
11.Redis事务
简介:
Redis事务是一个单独的隔离操作:事务中的所有命令都会被序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis事务主要作用就是串联多个命令防止别的命令插队。
命令:Multi、Exec、discard
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
组队的过程可以通过discard来放弃组队。
注意:
组队中某个命令出现报错,执行时整个的所有队列都会被取消
如果执行阶段某个命令报出来错误,则只有报错的命令不会被执行,其他命令都执行。
WATCH key [key.....] :
在执行multi之前,先执行watch key1 【key2】,可以监视一个(多个)key,如果在事务执行之前这个key被其他命令所改动,那么事务将被打断。
UNWATCH key :
取消在执行WATCH命令之后,EXEC命令或者DISCARD命令先被执行的话,那么就不需要在执行UNWATCH了
12.Redis持久化之RDB
简介:在指定时间间隔内将内存中的数据集快照写入磁盘,也就是说的Snapshot快照,它恢复时是将快照文件直接读入内存里。
备份如何执行:Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束后,在用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不会进行任何IO操作,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB缺点是最后一次持久化可能数据丢失。
Fork:Fork作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序技术器)数值和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
dump.rdb文件:在redis.conf中配置文件名称,默认为dump.rdb。
优势:
适合大规模的数据恢复
对数据完整性和一致性要求不高更合适使用
节省磁盘空间
恢复速度快
缺点:
Fork的时候,内存中的数据被克隆了一份,大致2倍膨胀性能需要考虑。
虽然Redis在fork时使用写时拷贝技术,但是如果数据庞大时比较消耗性能
在备份周期一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改
13.Redis持久化之AOF
简介: 以日志的形式来记录每个写操作,(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之后会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
AOF持久化流程:
1) 客户端的请求写命令会被append追加到AOF缓存区内;
2)AOF缓冲区根据AOF持久化策略【always,everysec,no】将操作sync同步到磁盘的AOF文件中;
3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的。
AOF默认不开启 可以在redis.conf中配置文件名称,默认为appendonly.aof ,AOF文件保存的路径与RDB的路径一致。
AOF和RDB同时开启,系统默认取AOF的数据(数据不会丢失)
14.主从复制
简介:主机数据跟新后,根据配置和策略,自动同步到备机的master、salaver,Master以写为主,Slave以读为主。
步骤:
1.创建、myredis文件夹
2.复制redis.conf配置文件到文件夹中
3.配置一主两从,创建三个配置文件 redis6379.conf redis6380.conf redis6381.conf
4.配置从(库)不配主库:slaveof ip port 成为某个实例的从服务器
原理:
1.当从服务器连接主服务器之后,从服务器向向主服务器发送进行数据同步消息
2.主服务器接到从服务器发送过来同步消息后,把主服务器数据进行持久化放到rdb中,把rdb文件发送给从服务器,从服务器拿到rdb进行读取。
3.每次主服务进行写操作,同步从服务器数据。
slaveof no one 将从机变为主机
15.哨兵模式
简介 :能够后台监控主机是否故障,如果故障了根据投票数自动将从机库转为主库。
步骤:
1.自定义。myredis目录下新建sentinel.conf 文件
2.配置哨兵,填写内容 sentinel monitor mymaster127.0.0.1 6379 1
(其中mymaster 为启动对象起的服务器名称, 1为至少有多少个哨兵同意)
16.集群
Redis集群实现了对Redis水平扩容,即启动N个redis节点,将整个数据库分步存储在N个节点中,每个节点存储总数的1/N.
Redis集群通过分区来提高一定程度的可用性:即使集群中的有一部节点失效或者无法通讯,集群也可以继续处理命令请求
17.缓存穿透
简介:
1.应用服务器压力变大了
2.redis命中率降低
3.一直查询数据库
原因:
1.redis查询不到数据库
2.出现很多非正常url访问
解决方案:
一个一定不存在缓存及查询不到的数据,由于缓存时不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这个将导致不存在的数据每次请求都要存储层去查询,失去了缓存的意义。
1)对空值进行缓存:如果一个查询返回的数据为空(不管数据是否存在),任然将这个空结果进行缓存,设置空结果的过期时间会很短,最长不超过5分钟。
2) 设置可访问名单(白名单)
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面id进行比较,如果访问id不在bitmap里面,进行拦截,不允许访问。
3) 采用布隆过滤器:
实际是一个很长的二进制向量和一系列随机映射函数 。
18.缓存击穿
简介:
1.数据库访问压力瞬间增加
2.redis里面没有大量出现key过期
3.redis正常运行
原因:
redis某个key过期了,大量访问使用这个key
解决方案:
key可能会在某些时间点被超高并发量地访问,是一种非常“热点”的数据,这个时候需要考虑:缓存被击穿问题
1)预先设置热门数据,在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key时长
2)实时调用:现场监控哪些热门数据热点,使用调用key的过期时长
3)使用锁
19.缓存雪崩
简介:
1.数据库压力变大服务器崩溃
原因:
1.极少时间段,查询大量key的集中过期情况
解决方案:
1)构建多级缓存架构:nginx缓存 + redis缓存 + 其他缓存
2)使用锁或队列:用加锁或者队列的方式保证不会有大量的线程对数据库一次性进行读或者读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。
3)将缓存失效分散开:比如将原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,很难引发集体失效的事件。
20.分布式锁
一、
1)使用setnx上锁,通过del释放锁
2)锁一直没有释放,设置key过期时,自动释放。
set k v nx ex time