1.介绍一下redis

  • 简单介绍:
    Redis是一款开源的、基于内存、单线程的高速缓存数据库。使用C语言编写,Redis是一个key-value存储系统,它支持丰富的数据类型,如:string、list、set、zset(sorted set)、hash。我们在项目中经常使用redis作为缓存数据库使用,因为他基于内存所以处理速度非常快,又提供了完善的持久化机制。
  • 数据库个数:16
  • 是否单线程:是
  • 默认端口号:6379

2.五种结构介绍

分别详细介绍下:

  • String:
    字符串类型是redis最基础的数据结构,首先键是字符串类型,而且其他几种结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种数据结构的学习尊定基础。字符串类型实际上可以是字符串(简单的字符串、复杂的字符串(xml、json)、数字(整数、浮点数)、二进制(图片、音频、视频)),但最大不能超过512M。
  • List :
    列表类型是用来储存多个有序的字符串,列表中的每个字符串成为元素(element),一个列表最多可以储存2的32次方-1个元素,在redis中,可以队列表两端插入(pubsh)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下表的元素等,列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发中有很多应用场景。
    优点:
    1.列表的元素是有序的,这就意味着可以通过索引下标获取某个或某个范围内的元素列表。
    2.列表内的元素是可以重复的。
  • Set :
    集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中不允许有重复的元素,并且集合中的元素是无序的,不能通过索引下标获取元素,redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,并合理的使用好集合类型,能在实际开发中解决很多实际问题。
  • Zset
    有序集合和集合有着必然的联系,他保留了集合不能有重复成员的特性,但不同得是,有序集合中的元素是可以排序的,但是它和列表的使用索引下标作为排序依据不同的是,它给每个元素设置一个分数,作为排序的依据。(有序集合中的元素不可以重复,但是csore可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)。
  • hash
    在redis中哈希类型是指键本身又是一种键值对结构,如 value={{field1,value1},......{fieldN,valueN}}

3.五种结构适用场景

  • String:
    缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysql作为储存层,绝大部分请求数据都是redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低 后端压力的作用。(redis为何具备支撑高并发的特性,下次文章讲解)。计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以一步落地到其他的数据源。如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。
    共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户-session集中管理,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。
    限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,
    会限制用户每分钟获取验证码的频率。

  • hash
    哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。
    所以常常用于用户信息等管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,

  • list
    消息队列: redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞时的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性

  • set
    标签(tag):集合类型比较典型的使用场景,如一个用户对娱乐、体育比较感兴趣,另一个可能对新闻感兴趣,这些兴趣就是标签,有了这些数据就可以得到同一标签的人,以及用户的共同爱好的标签,这些数据对于用户体验以及曾强用户粘度比较重要。(用户和标签的关系维护应该放在一个事物内执行,防止部分命令失败造成数据不一致)
    sadd=tagging(标签)
    spop/srandmember=random item(生成随机数,比如抽奖)
    sadd+sinter=social Graph(社交需求)

  • zset
    排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:
    按照时间、按照播放量、按照获得的赞数等。

4.redis的持久化之RDB

RDB:
概念:在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里
详细:Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到
一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件(dump.rdb)。
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
配置:
save X Y //X 秒内 发生了 Y 次key的变化, 发生一次rdb持久化
优势:
适合大规模的数据恢复
对数据完整性和一致性要求不高
劣势
在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑

5.redis持久化之AOF

AOF:

  • 概念:
    以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
  • 配置:
    需要将 redis.conf中的 appendonly no 改为 yes ,默认存储到 appendonly.aof 中
  • 优势:
    数据完整性比较好。
  • 劣势:
    相同数据集的数据而言,aof文件要远远大于rdb文件,运行效率不如rdb快
    相关录音

6.java操作redis

我们比较常用的两种方式:

  • jedis.jar :
    在项目中 配置对应的jedisPool , 根据jedisPool可以获取到jedis
    jedis提供与redis中几乎同名的方法,上手简单 操作方便。

  • Spring Data Redis:
    spring 提供的redis操作API 实际上底层基于jedis 并做了封装及优化,
    我们只需要在spring的配置文件中 配置出对应的redisTemplate,
    提供了便于理解的API,并让我们不必关注每一个jedis实例的管理。
    并且,Spring Data Redis 是由 cache api 整合 redis 而来 可以使用缓存注解直接引用

7.redis事务

  • redis对事务的支持是指可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

  • 涉及的命令:
    multi : 开启一个事务
    exec: 执行一个事务
    discard:取消事务,如果被watch监控 取消watch
    watch: 监控一个key 或 多个key是否发送变化
    unwatch: 取消监控

  • 在项目中,我们经常配合使用watch + multi + exec + discard 达到一个乐观锁的目的处理页面,
    比如在秒杀项目中我们的预减库存操作就是利用这个方式,用watch监控一个商品库存,开启事务尝试修改库存,如果在我们修改期间我们的这条数据被其它人修改过,那么这个事务就会提交不成功,达到一个乐观锁的目的。 redis处理事务的机制稍弱,需要我们在代码中多加控制。

8.redis的发布订阅

redis支持发布订阅模式,可以订阅一个或多个符合给定模式的频道,在发送者发送消息时,可以收到反馈。

9.redis的主从复制

redis的主从复制,又称 master/slave模式,master代表主机角色,slave代表从机

主机负责写操作,并将数据同步至从机,这样做可以帮我们实现读写分离,
而且还相当于做了容灾备份。

配置:
最简单的配置方法,直接在从机上执行 slaveof 主机IP:端口 就可以了,但是这样的配置
如果主机挂了,从机一般会一直等待主机恢复,期间只能读。

所以一般情况下的主从模式 会搭配哨兵模式一起使用,除了原有的主从配置外
还要新建sentinel.conf 哨兵配置文件,以哨兵模式启动,哨兵会定时检测主机状态,如果主机挂了,会投票选举新的主机。

缺点:
复制会有一定的延时性。
起到了读写分离的作用,但数据量更大时就得使用redis集群了

10.redis集群

redis提供的主从复制,可以缓解redis的压力,但对于互联网行业海量的数据量,主从完全没法满足业务的需求。 redis在3.0以后提供了集群模式。redis集群 采用了p2p的模式,完全去中心化,Redis把所有的key分成了16384个slot,每个redis实例扶着其中一部分的slot,集群中的所有信息(节点、端口、slot等),都通过节点间定期交换数据而更新。
redis客户端可以在任意一个Redis实例中发出请求,如果要查询的数据不在该实例中,会通过重定向命令引导客户端访问所需的实例。

配置:
搭建集群至少需要6个节点(3主3从)
需要开启每个节点的集群模式
(在conf中配置 cluster-enabled yes cluster-config-file nodes-端口.conf cluster-node-timeout 时间毫秒)
安装集群需要的管理软件 ruby环境
主从比例1比1
开启集群: redis-trib.rb create --replicas 1 IP:端口 IP:端口 IP:端口 IP:端口 IP:端口 IP:端口 . . .
相关录音

[熟悉]哨兵模式
哨兵模式: sentinel 介绍
用于监控redis集群中Master状态的工具,2.4版本以后提供。已哨兵模式启动
会检测Master的状态,如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave.Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
具体工作方式:
1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令
2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线
5):在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令
6):当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
7):若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。
若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

哨兵选举机制
1.参与选举条件:
不能有下面三个标记中的一个:SRI_S_DOWN|SRI_O_DOWN|SRI_DISCONNECTED
ping 心跳正常
优先级不能为 0(slave->slave_priority)
INFO 数据不能超时
主从连接断线会时间不能超时
2.多个候选机的排序机制

优选选择优先级高的从机
优先选择主从复制偏移量高的从机,即从机从主机复制的数据越多
优先选择有 runid 的从机
如果上面条件都一样,那么将 runid 按字典顺序排序

11.缓存穿透、雪崩

缓存穿透

缓存可能会遇到这种问题:请求cache拿不到数据,就会去存储层拿,都拿不到时,返回空值(可能会返回大量空值)。或者代码有问题,拿不到数据。就会一直请求数据。导致后端打崩。
解决方案

缓存层缓存空值。
–缓存太多空值,占用更多空间。(优化:给个空值过期时间)
–存储层更新代码了,缓存层还是空值。(优化:后台设置时主动删除空值,并缓存把值进去)

缓存雪崩
大部分缓存同时失效,比如redis挂了,客户端直接请求到数据库里面。数据库负载非常高。甚至数据库拖挂了。

解决方案
1.保持缓存层服务器的高可用。
–监控、集群、哨兵。当一个集群里面有一台服务器有问题,让哨兵踢出去。
2、依赖隔离组件为后端限流并降级。
比如推荐服务中,如果个性化推荐服务不可用,可以降级为热点数据。
3、提前演练。
演练 缓存层crash后,应用以及后端的负载情况以及可能出现的问题。
对此做一些预案设定。

[熟悉]缓存同步
在服务层发布一个接口,后台内容发生改变后,
直接调用此接口,把缓存服务清空即可,清空后,客户下 次访问 的时候就从数据库中取出,
然后再放到redis中
相关录音

[必会]redis的应用场景
各种计数,商品维度计数和用户维度计数
缓存各种集合列表,如使用list结构缓存商品列表,并支持分页
最新列表,最热列表,排行榜 *(list set zset)
消息通知 (如:未读消息数 已读消息数 。。。)

总之。 读的量大 写的量少 都可以尝试使用缓存