安装
- 官网:https://redis.io/download (使用3.2或4.0)
- 系统安装
linux:快速安装 https://redis.io/download#installation
wget http://download.redis.io/releases/redis-4.0.9.tar.gz
tar xzf redis-4.0.9.tar.gz
cd redis-4.0.9
make - 三种方式启动redis
3.1 cd src ./redis-server直接启动
3.2 修改redis.conf的daemonize属性为yes,即改为守护进程启动,然后根据这个配置文件启动,也可以指定其他配置文件 ./redis-server /usr/local/redis-5.0.5/redis.conf
3.3 使用redis启动脚本设置开机自启动,linux配置开启自启动 /etc/init.d- 配置步骤
启动脚本 redis_init_script 位于Redis的 /utils/ 目录下
mkdir /etc/redis
cp redis.conf /etc/redis/6379.conf
将启动脚本复制到/etc/init.d目录下,本例将启动脚本命名为redisd(通常都以d结尾表示是后台自启动服务)。
cp redis_init_script /etc/init.d/redisd
设置为开机自启动,直接配置开启自启动 chkconfig redisd on - 发现错误: service redisd does not support chkconfig
解决办法,在启动脚本开头添加如下注释来修改运行级别:#!/bin/sh # chkconfig: 2345 90 10
- 设置为开机自启动服务器
chkconfig redisd on service redisd start 打开服务 service redisd stop 关闭服务
- 配置步骤
学习
- String结构
set/get 设置key对应的值为String类型的value 获取key对应的值 mget 批量获取多个key的值,如果可以不存在则返回nil incr && incrby incr对key对应的值进行加加操作,并返回新的值;incrby加指定值 setnx 设置key对应的值为String类型的value,如果key已经存在则返回0 setex 设置key对应的值为String类型的value,并设定有效期 其他命令 getrange 获取key对应value的子字符串 mset 批量设置多个key的值,如果成功表示所有值都被设置,否则返回0表示没有任何值被设置 msetnx,同mset,不存在就设置,不会覆盖已有的key getset 设置key的值,并返回key旧的值 append:给指定key的value追加字符串,并返回新字符串的长度
- hash数据结构
hset——设置key对应的HashMap中的field的value //hmset——设置多个key对应的HashMap的Field的value hget——获取key对应的HashMap中的field的value hmget——获取多个key对应的HashMap中的field的value hgetall——获取key对应的HashMap中的所有field的value hlen--返回key对应的HashMap中的field的数量
- list数据结构
lpush——在key对应的list的头部添加一个元素 lrange——获取key对应的list的指定下标范围的元素,-1表示获取所有元素 lpop——从key对应的list的尾部删除一个元素,并返回该元素 rpush——在key对应的list的尾部添加一个元素 rpop——从key对应的list的尾部删除一个元素,并返回该元素
- set数据结构
sadd——在key对应的set中添加一个元素 smembers——获取key对应的set的所有元素 spop——随机返回并删除key对应的set中的一个元素 sdiff——求给定key对应的set差集 suion——求给定key对应的set并集 sinter——求给定key对应的set交集
- sortset数据结构(set是通过hashmap存储,key对应set的元素,value是空对象 sortset是怎么存储并实现排序的呢,hashmap存储,还加了一层跳跃表 跳跃表:相当于双向链表,在其基础上添加前往比当前元素大的跳转链接)
zadd ——在key对应的zset中添加一个元素 zrange——获取key对应的zset中指定范围的元素,-1表示获取所有元素 zrem——删除key对应的zset中的一个元素 zrangebyscore——返回有序集key中,指定分数范围的元素列表,排行榜中运用 zrank——返回key对应的zset中指定member的排名。其中member按score值递增(从小到大); 排名以0为底,也就是说,score值最小的成员排名为0,排行榜中运用
- 消息订阅
PUBLISH 将信息message发送到指定的频道channel。返回收到消息的客户端数量 SUBSCRIBE 订阅给指定频道的信息 UNSUBSCRIBE 取消订阅指定的频道,如果不指定,则取消订阅所有的频道。
传统关系型数据库事务与Redis事务
- InnoDB MVCC多版本并发控制功能讲解
在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空,其实还有一列称为回滚指针,用于事务回滚,不在本文范畴)。这里的版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号, 用来和查询每行记录的版本号进行比较 - redis事务机制
MULTI 与 EXEC命令 以 MULTI 开始一个事务,然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令 DISCARD命令 DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消 WATCH命令 WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
- redis事务与传统关系型事务的比较
原子性(Atomicity): 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。如果一个事务队列中的所有命令都被成功地执行,那么称这个事务执行成功 一致性(Consistency): 1. 入队错误: 在命令入队的过程中,如果客户端向服务器发送了错误的命令,比如命令的参数数量不对,等等, 那么服务器将向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC 。 2. 执行错误: 如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响 隔离性(Isolation): WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败 持久性(Durability):因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定
redis整合(mybatis) 如何整合springboot
- 简单从数据库提取写入redis作为缓存
1.1导入依赖
1.2 导入mybatis配置文件<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <scope>test</scope> <version>1.3.2</version> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency>
- springboot内置mybatis二级缓存
- 整合步骤
//引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
- 开启缓存注解(在redisTemplate的bean上注解@EnableCaching
基本注解@CacheConfig(cacheNames="userInfoCache") 在同个redis里面必须唯一,在server上注解表明缓存name @Cacheable(查) : 来划分可缓存的方法 - 即,结果存储在缓存中的方法,以便在后续调用(具有相同的参数)时,返回缓存中的值而不必实际执行该方法 @Cacheable(key="#p0"+”_“+"#p1",unless="result==null“) @CachePut(修改、增加) : 当需要更新缓存而不干扰方法执行时,可以使用@CachePut注释。也就是说,始终执行该方法并将其结果放入缓存中(根据@CachePut选项) @CacheEvict(删除) : 对于从缓存中删除陈旧或未使用的数据非常有用,指示缓存范围内的驱逐是否需要执行而不仅仅是一个条目驱逐
- 在方法上面加入SpEL(也就是在方法上加入注解)
- springboot cache 存在什么问题
第一,生成key过于简单,容易冲突userCache::3
第二,无法设置过期时间,默认过期时间为永久不过期
第三,配置序列化方式,默认的是序列化JDKSerialazable - 解决办法springboot cache自定义项(redisconfig得类里设置成bean,)
自定义KeyGenerator
自定义cacheManager,设置缓存过期时间
自定义序列化方式,Jackson
- 整合步骤
redis分布式集群
- redis实现分布式集群配置过程
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
- @EnableRedisHttpSession(maxInactiveIntervalInSeconds=50) 开启redis session缓存
maxInactiveIntervalInSeconds指定缓存的时间
spring:session:sessions:expires:+‘sessionId’的过期时间
redis缓存优化
- 实现缓存预热,在springboot启动前,通过实现ApplicationRunner在应用加载前预加载缓存,或者实现InitializingBean在bean加载后加载缓存。
- redis缓存的回报和代价
回报:
代价:高速读写 缓存加速读写速度:CPU L1/L2/L3 Cache、Linux page Cache加速硬盘读写、浏览器缓存、Ehcache缓存数据库结果 降低后端负载 后端服务器通过前端缓存降低负载: 业务端使用Redis降低后端MySQL负载等
数据不一致 缓存层和数据层有时间窗口不一致,和更新策略有关 代码维护成本 原本只需要读写MySQL就能实现功能,但加入了缓存之后就要去维护缓存的数据,增加了代码复杂度。 堆内缓存可能带来内存溢出的风险影响用户进程,如ehCache、loadingCache 堆内缓存和远程服务器缓存redis的选择 堆内缓存一般性能更好,远程缓存需要套接字传输 用户级别缓存尽量采用远程缓存 大数据量尽量采用远程缓存,服务节点化原则
- 什么是缓存雪崩?你有什么解决方案来防止缓存雪崩?
问题描述: 如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。 由于原有缓存失效,新缓存未到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU 和内存造成巨大压力,严重的会造成数据库宕机
解决方案:- 加锁排队
key: whiltList value:1000w个uid
指定setNx whiltList value nullValue mutex
互斥锁解决,Redis的SETNX去set一个mutex key,
当操作返回成功时,再进行load db的操作并回设缓存;
否则,就重试整个get缓存的方法 - 数据预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key - 双层缓存策略
C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。 - 定时更新缓存策略
失效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存 - 设置不同的过期时间,让缓存失效的时间点尽量均匀
- 加锁排队
- 什么是缓存穿透?你有什么解决方案来防止缓存穿透?
问题描述: 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候, 在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次 无用的查询)。这样请求就绕过缓存直接查数据库
解决方案:- 采用布隆过滤器BloomFilter
将所有可能存在的数据哈 希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力 - 缓存空值
如果一个查询返回的数据为空(不管是数据不 存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库
- 采用布隆过滤器BloomFilter