一、Redis简介
redis是一个NoSQL,也就是非关系型数据库,以key-value的形式保存数据,它是基于内存保存数据的,所以存取数据的速度较SQL而言快很多,并且它是单线程的。
问:为什么Redis快?
1.单线程,减少上下文切换;2.操作内存;3.复用IO,非阻塞;4.特定的存储类型
复用IO
首先说说传统IO,传统IO同步阻塞,用户A和服务器产生连接传输时,如果此时用户B需要和服务器连接,那么用户B的操作会被阻塞住,这就是一个同步阻塞的模型,一个线程处理一个流。缺点就是效率低。如果使用多线程的话也有线程切换和维护的开销。
所以,可以使用一个线程维护多个IO,可以采取轮训的方式,但是呢,一直轮训的话对CPU资源也是一种浪费,于是,就有了复用IO,并且有三种方式实现。
复用IO select、poll:select和poll在轮训时,会先去判断流有没有传输数据,如果没有则阻塞住,有就读取数据,阻塞就节约了CPU资源,但是呢还是会去对所有维护的流进行轮询,所以就有了事件驱动的方式epoll。另外,这两种方式线程不安全。
复用IO epoll:epoll受IO事件驱动,当有IO发生时,会直接开始这些IO操作,而不会去轮训所有的流再判断是否有数据。epoll线程安全。
二、Redis的value数据类型
1.string:一个key对应字符串类型,使用jedis: jedis.set(key, value);
2.list:一个key对应一个字符串的集合,链表,使用jedis: jedis.lpush(key, value1, value2...);
3.hash:一个key对应字典散列,一个key可以对应多个field-value,这多个field-value组合在一起就类似一个对象。
比如:一个key叫“student”,使用jedis
public void hset() { //写法一 jedis.hset("student", "name", "xiaoming"); //写法二 Map<String, String> student = new HashMap<>(); student.put("name", "xiaoming"); jedis.hset("student", student); }
4.set:一个key对应一个set集合,使用jedis: jedis.sadd(key, value1, value2...);
5.zset:一个key对应一个zset集合,使用jedis:
public void hset() { //写法一 jedis.zadd("student", 10.0, "Math"); //写法二 Map<String, Double> student = new HashMap<>(); student.put("English", 20.0); student.put("Physics", 30.0); jedis.zadd("student", student); }
三、Redis的配置
1.配置RDB与AOF模式实现数据持久化:
(1)RDB快照:在redis.conf里配置
①save 900 1:900秒内有1个key改变则同步;
②save 300 10:如上类推;
③save 60 10000:如上类推;
特点:通过IO同步数据,同步的时候慢,恢复的时候快;
(2)AOF模式,append-only-file:在redis.conf里配置
①appendfsync always:每当key改版就同步;
②appendfsync everysec:每秒同步;
③appendfsync no:只有内存满了不能再保存时同步;
特点:同步的是指令,在恢复的时候没有RDB快;
持久化机制
某一时刻写入到磁盘
RDB(默认)
原理:单独创建(fork)一模一样的子进程来进行持久化,先将数据写入到一个临时文件,最终生成dump.rdb文件
问:rdb文件位置:redis.conf里的 dir ./就是dump.rdb文件存放的位置
问:为什么要fork子进程:主进程不进行IO,确保了Redis主进程的高性能
问:什么时候进行持久化:
执行shutdown命令式,如果没有配置AOF,进行bgsave;
配置redis.conf中的 save配置,进行bgsave,属于定时;
执行命令:save(主进程进行持久化),bgsave(后台持久化,子进程持久化)
问:RDB的缺点:宕机时,没法进行备份
AOF(Append only file)
原理:将redis的操作日志以追加的方式写入文件,读操作时不会记录的
问:如何触发AOF:通过配置
no 频率很低
always 频率高,每次修改都记录,数据安全,但是效率低,开销大
everysec 一秒一次,快,可能丢失1秒内的数据(最好用这个)
问:AOF的好处:解决了RDB可能会宕机而丢失持久化数据的问题
问:AOF会fork子进程吗:不会,但是重写会fork子进程
问:AOF的备份文件中的命令是什么意思(jedis给redis发送的命令也是如此):
*2 表示命令有2个字符串
*3 表示命令有3个字符串
$6 表示命令的长度是6
SELECT 0 选择redis的数据库,第0号
问:AOF重写机制:(redis优化关键)
起因:set del命令会一直累加,而不会抵消,会一直占用存储。所以需要重写机制,来为appendonly.aof文件优化
**!!! redis.conf配置文件中:auto-aof-rewrite-min-size 64Mb (默认)
第一次触发是64Mb,下次触发根据配置:auto-aof-rewrite-percentage 100 (默认百分之百),下次触发的阈值就是第一次触发之后的大小的两倍
混合持久化(redis4.0特性,AOF使用RDB特性)
配置:aof-use-rdb-preamble yes 默认是no
优点:AOF机制将命令转化为二进制数据的方式保存在.aof文件中,节省空间
问:什么时候触发:重写时触发
2.配置主从复制:在redis.conf里配置
slaveof xxx.xxx.xxx.xxx:port
bind 0.0.0.0
3.配置哨兵模式:主服务器宕机,重新选取主服务器
参考:https://www.cnblogs.com/kerwinC/p/6069864.html
4.过期策略:
(1)定期删除:定时遍历判断是否过期并进行删除;
(2)惰性删除:key改变时判断是否过期,随后进行删除;
第一个占用时间,第二个占用空间,一般会结合起来用。
四、Redis的应用场景
1.分布式锁(string):利用setnx(key, value)的set if not exist特性,如果key存在则不做任何操作,并返回1,如果key不存在,则添加一个值为value的key到redis中;
2.计数器(string):一个帖子被浏览的数量, key(帖子id)-value(数量) ;
3.消息队列(list):list的可以边进边出的特性;
4.微博/Twitter的用户消息列表(list): key(用户id)-value(信息的集合)
5.微博的点赞、签到(set): key(某微博的like)-value(like微博的用户的集合)
6.可能认识的人模型(set): key(某用户id)-value(某用户关注的人的集合) ,利用用户之间关注的人的集合的交集和差集筛选出可能认识的人;
7.电商商品标签筛选(set): key(商品标签)-value(拥有此商品标签的商品集合) ,选择不同的商品标签,筛选出交集的商品;
8.用户积分排行榜(zset): key(某排行榜)-value(用户-分数的映射集合) ,根据分数进行排序。
五、缓存雪崩、缓存击穿
1.缓存雪崩:
当缓存崩掉时,请求全部到了数据库,这时可能会导致数据库假死,甚至崩溃。
解决:
(1)Redis配置集群和哨兵模式保持高可用;
(2)本地ehcache也进行缓存,或者使用hystrix熔断机制来限流/降级;
(3)雪崩之后,使用持久化恢复数据;
2.缓存击穿:
当大量查询不存在的key的请求时,请求直接落到数据库上,也可能导致假死、崩溃。
解决:
(1)把不存在的key也放进redis中,比如id值为负的key,从-9999到-1对应空的value。
六、redis缓存过期策略
1.缓存过期策略:设置expire过期时间
2.三种策略:
主动删除:一直判断key有无过期,一旦过期,立马删除。优点:不占空间,key过期时效性好,缺点:很吃性能
惰性删除:下次get时判断有无过期,过期则删除。优点:性能好,缺点:占空间
定期删除:周期判断有无key过期。优缺点介于主动删除和惰性删除之间
七、redis缓存淘汰策略
1.什么情况下会发生缓存淘汰
在redis达到了最大的存储内存时,需要对缓存进行清除而让新的数据被set进去,最大存储内存通过 maxmemory 配置。
2.缓存淘汰的6种策略(policies)
neoviction:不淘汰任何已存在的缓存,返回报错信息
allkeys-random:在所有的key中随机删除
allkeys-lru:在所有的key中,根据最少使用算法,对最少使用的key进行删除
volatile-random:在设置了expire过期时间的key中,进行随机删除
volatile-lru:在设置了expire过期时间的key中,根据最少使用算法,对最少使用的key进行删除
volatile-ttl:在设置了expire过期时间的key中,对即将过期的key进行删除
3.缓存淘汰的优缺点
针对不同的情况使用不同的淘汰策略,对于有热点数据和非热点数据类型的缓存时,用lru是最好的。另外设置expire会消耗服务器CPU,所以可以通过设置allkeys-lru,不设置expire的方式来优化redis的效率。
4.近似LRU算法
Redis 使用的并不是完全LRU算法。自动驱逐的 key , 并不一定是最满足LRU特征的那个。 而是通过近似LRU算法,,抽取少量的 key 样本,,然后删除其中访问时间最古老的那个key。
所以Redis3.0之后,优化了其LRU算法,通过可以配置样本 maxmemory-samples 的方式提升算法精度,相反的,会更加消耗服务器的CPU。一般设置到10时就非常接近真实的LRU的算法的精度了。
八、redis常用命令
info [selection]
https://www.runoob.com/redis/server-info.html