1.redis简介
redis以solt(槽)的作为数据存储单元,每个槽中可以存储N多个键值对,redis固定具有16384个槽。redis通过redis sentinel(哨兵)提供高可用,通过redis cluster(集群)提供自动分区。
2.边路缓存思想
简单说就是查找时先从redis找,没有再找数据库,修改时先修改数据库,然后再修改redis。
3.基于docker安装redis单机版
a.拉取镜像
docker pull redis:5.0.5
b.创建并启动容器
docker run -d --name redis -p 6379 6379 --restart always redis:5.0.5
c.客户端测试
docker exec -it redis bash
在任意目录输入redis-cli即可进入redis命令行
4.Redis数据类型
Redis以key-value形式存储数据,共有String、Hash、List、Set、SortedSet(有序集合)五种数据类型,一般key都为String类型。
常用操作:
key操作:
a.exists 判断key是否存在,exists key,存在返回数字,不存在返回0
b.expire 设置key的过期时间 单位秒,expire key 秒速,成功返回1,失败返回0
c.key * 相当于select * from table,查出redis中所有数据
d.ttl 查看key剩余过期时间,ttl key,返回剩余时间,不过期返回-1, 过期返回-2
e.del 删除键值对,del key,返回被删除key的数量
String操作:
a.get 获取指定key的值,get key,返回key的值 不存在返回null
b.set 设置指定key的值,key不存在则新增,存在则修改,set key value,成功返回OK
setex time 10 "value" = set time "value" EX 10 = set并设置过期时间
setnx address "beijing" = 不存在才set,存在不做修改
incrby age = 自增1,incrby age 5 = 增加5
hash操作
a.hset 给set中的field设置值,hset key field value,成功返回1,失败返回0
b.hget 获取key中某个field的值,hget key field,返回field的内容
c.hmset 给key中的多个field设置值,hmset key field value field value,返回OK
d.hmget 一次获取多个field的值,hmget key field field,返回value列表
e.hvals 获取key中所有field的值,hvals key,返回value列表
f.hgettall 获取所有的field和value,hgettall key,返回field和value的交替显示列表
g.hdel 删掉key中的一个field,hdel key field
h.hexists 判断key中的一个field是否存在
list操作
a.rpush 向列表末尾插入一个或多个值,rpush key value value,返回列表长度
b.lpush 向列表首部插入一个或多个值,lpush key value value,返回列表长度
c.lrange 返回列表中指定区间的值,可用-1代表末尾,lrange list 0 -1,返回查询到的值
d.llen 返回列表长度,llen key,返回长度
e.lrem 删除列表中的元素,count为正表示从左往右删除的数量,负表示从右往左删除的数量,lrem key count value,返回删除数量
set操作
a.sadd 向集合添加内容不允许重复,sadd key value value value
b.scard 查看集合长度,scard key,返回集合长度
c.smembers 查看集合中元素内容,smembers key,返回集合中元素
sorted set操作
有序集合中每个value都有一个分数score,根据分数排序
a.zadd 向有序集合添加数据,zadd key score value score value,返回长度
b.zrange 返回区间内容,withscores表示带有分数,zrange key 区间 [withscores],返回值列表
5.Redis持久化能力
Redis每次启动时都会从硬盘中把数据读取到内存中·,运行过程中的数据都是内存中的数据。
Redis有两种持久化策略:RDB和AOF
a.RDB(Redis DataBase)
rdb是默认模式,可以再指定的时间间隔内生成数据快照,默认保存到dump.rdb文件中,当redis重启后会自动加载dump.rdb文件中的内容到内存中。
可以使用save(同步)或bgsave(异步)手动保存数据。
可以设置服务器配置的save选项,让服务器每隔一段时间自动执行一次bgsave命令,可以通过save选项设置多个保存条件,只要其中任一条件满足,就执行bgsave命令。
例如:
save 900 1,900秒发生了一次数据操作
save 300 10,300秒发生了十次数据操作。
优点:可以直接使用rdb文件还原数据,数据保存由子进程操作,不影响父进程做其他事情,恢复数据效率要高于aof。
缺点:每次保存点之间如果redis意外关闭,可能丢失数据、每次保存数据都要开一个子进程,可能会比较耗费性能。
b.AOF(AppendOnly File)
aof默认是关闭的,需要在配置文件redis.conf中开启,redis支持aof和rdb同时生效,如果同时存在,aof的优先级高于rdb。
原理:监听执行的命令,如果发现修改操作,直接同步到数据库文件中,同时把命令记录到日志中,即使断电,也能在下一次启动时按照日志进行恢复。
优点:相对rdb更加安全。
缺点:更加要求读写性能,相同数据集可能会大于rdb。
开启方法:redis.conf中,appendonly no改为yes,appendfilename 设置aof数据文件爱你,名称随意。
6.Redis主从复制
Redis支持集群,为了保证单一节点可靠性,也支持主从复制功能,即一个主节点拥有多个从节点,从节点是主节点的复制品。redis支持读写分离,一般主节点负责写,从节点负责读。
7.SpringbootData Redis
Srpingboot整合Spring Data Redis后提供两个对象:RedisTemplate<String,String>表示Key和value类型都是String,RedisTemplate表示key和value都使用jdk序列化器,实体类必须序列化。
这种方式较为局限,如果要使key以String序列化存储,Value以jdk序列化形式存储,那就可以使用配置类的方式:
除了字符串和JDK序列化器还有以下几个序列化器,下面一一介绍:
- JdkSerializationRedisSerializer,jdk序列化器,可以存储任意类型,但要求该类型实现Serialization序列化接口。
- StringRedisSeriallizer,String序列化器,只能存储String类型。
- OxmSerializer序列化器,这种序列化器以字符串的xml格式进行存储,解析复杂效率也低,已经很少有人使用了;
- GenericToStringSerializer序列化器需啊哟调用者传递一个对象到字符串互转的Converter转换器,使用较为麻烦。
- Jackson2JsonRedisSerializer,json转换器,存储为json形式,但是取出时返回的固定为LinkedHashMap,只能手动转为相应对象。
- GenericJackson2JsonRedisSerializer,通用json转换器,与Jackson2Json相比解决了泛型的问题,用它就没错了。
8.缓存穿透
一般情况下,客户端是访问redis,没有再访问数据库,如果客户端绕过redis,直接频繁访问数据库,就成为缓存穿透。多数出现在数据库查询为null的情况(因为一般为null存入redis)。
解决方法很简单,如果查询结果为null,依然把null放入redis中,设置这个key有效时间短一些即可。
9.缓存击穿
实际开发中,考虑到redis所在服务器的存储压力,一般都会设置key的有效时间,一定会出现键值对过期的情况,如果键值对刚刚过期,恰好就出现大量并发访问,这些数据蜂拥一般访问数据库,就叫做缓存击穿。
解决方法有两个,一是key设为永久,二是加锁,防止出现数据库的并发访问。
java中可以使用synchronized、lock加锁。
10.缓存雪崩
在一段时间中,出现大量缓存失效,造成数据库访问骤增,这就叫做缓存雪崩。
解决方法:a.永久生效,b.自定义算法,比如使有效时间随机,避免key失效时处于同一时间段。
11.缓存淘汰策略
- Lru和Lfu算法
Lru以链表为底层算法,访问较多的处于链表顶层,较少的链表底层,直至被淘汰。Lfu以计数器为底层算法,访问次数少的被淘汰。 - 消极淘汰方法(passive way)、积极淘汰方法(active way)、主动删除
消极方法读取时判断是否过期,过期则删除,积极方法周期性判断是否过期,主动删除超过阈值则删除。