Redis学习笔记
- 概述:
- 一、Redis五大数据类型
- 1.1 Redis-key
- 1.2 String
- 1.3 List
- 1.4 Set
- 1.5 Hash
- 1.6 Zset
- 二、Redis三种特殊数据类型
- 2.1 geospatial
- 2.2 hyperloglog
- 2.3 Bitmap
- 三、Redis基本的事务操作
- 四、Redis的乐观锁
- 监视测试
- 五、使用Jedis操作Redis
- 1、导入对应的依赖
- 2、编码测试
- 3、常用API
- 六、通过Jetis再次理解事务
- 七、SpringBoot集成Redis
- 八、自定义RedisTemplate
- 九、RedisConfig配置文件详解
- 十、Redis持久化
- 1、RDB(Redis DataBase)
- 2、AOF(Append Only File)
- 十一、Redis订阅发布
- 十二、Redis主从复制
- 哨兵模式
- 十三、Redis缓存穿透和雪崩
- 缓存穿透
- 布隆过滤器
- 缓存过滤器
- 缓存击穿
- 设置热点数据永不过期
- 加互斥锁
- 缓存雪崩
- Redis高可用
- 限流降级
- 数据预热
概述:
作为学习Redis的学习笔记,学习的课程时b站的up主,遇见狂神说,一边学代码,一边学做人!全体起立!配置redis这里不讲解了,教程喝多,本学习笔记是在linux配置redis后学习所记!
视频链接https://www.bilibili.com/video/BV1S54y1R7SB?p=1
狂神:只要学不死,就往死里学
一、Redis五大数据类型
1.1 Redis-key
1.2 String
1.3 List
1.4 Set
set(集合),其中的值不可以重复。
sadd myset "hello" #set集合中添加元素
sadd myset "xwy"
sadd myset "love"
smembers myset #查看值
sismember myset hello #是否存在hello
scard myset #元素个数
remove
srem myset "hello" #移除set的元素 hello
#set是无序不重复集合 可以随机获取
srandmember myset #随机抽出一个元素
srandmember myset 2 # 随机抽出俩元素
#随机移除key
spop myset #随机删除一些set集合的元素
#将一个指定的值,移动到另外一个key中
smove myset myset2 "xwy" # 将xwy移动到myset2
微博、b站,共同关注功能(并集)
数字集合类:
- 并集 sunion key1 key2
- 交集 sinter key1 key2
- 差集 sdiff key1 key2 # key1 key2不同的元素
微博 A用户将所有关注的人放在一个set集合中!将他的粉丝也放在一个集合里
共同关注、共同爱好,二度好友
1.5 Hash
Hash(哈希)
Map集合: key-Map集合!相当于key - <key-value>,value是一个Map集合,本质和string没有太大区别
hset myhash filed1 hello
hget myhash filed1
hmset myhash filed1 hello filed2 world # set多个key-vlaue
hget myhash filed1 filed2
hgetall myhash # 获取全部的hash值
hdel myhash filed1 # 删除指定的hash的key字段,对用的value也就消失了
hlen myhash # 获取长度
hexists myhash filed1 # 判断是否存在
hkeys myhash # 只获取key
hvals myhash # 只获取values
incr decr
hincr myhash filed3 1 # 加一
hdecr myhash filed3 1
hsetnx myhash filed4 hello # 如果不存在则可以设置,存在则不可以设置
hash存储变更的数据,尤其是用户信息的保存,经常变动的信息,hash适合对象的存储,string适合字符串的存储。
1.6 Zset
Zset(有序集合),在set的基础上增加了一个值。set k1 v1 ; zset k1 score v1
zadd myset 1 one
zadd myset 2 two 3 three # 添加多个值
zrange myset 0 -1
#排序如何实现?
zadd salary 2500 xwy
zadd salary 599 xxx
zadd salary 8000 xsk
zrangebyscore salary -inf +inf #从无穷小到无穷大(相当于遍历所有的)
zrangebyscore salary -inf +inf with scores # 带上score
zrevrange salary 0 -1 #从大到小
zrem salary xwy #移除
zcard salary #获取数量
zcount salary 1 3 #获取指定区间的成员数量
案例:
set 排序,存储班级成绩表,工资表排序
普通消息:1 重要消息 2 带权重判断
排行榜应用,取top N
二、Redis三种特殊数据类型
2.1 geospatial
朋友圈定位,附近的人,打车距离计算
Redis的Geo在Redis3.2版本加入,可以推算地理位置的信息,比如两地的距离,方圆几里的人
#getadd
#两极无法添加,实际我们是使用java程序一次性倒入所有
geoadd china:city 116.40 39.90 beijing
geoadd china:city 121.47 31.23 shanghai
geoadd china:city 106.50 29.53 chongqing
geoadd china:city 114.05 22.52 shenzhen
geoadd china:city 120.16 30.24 hangzhou
# geopos
#获取指定城市的经纬度
#获取当前定位:一定是一个坐标值
geopos china:city beijing
geopos china:city beijing chongqing
#geodist
#m 米 、 km 千米 、 mi 英里 、 ft 英尺
geodist china:city beijing shanghai km #计算距离
#附近的人?(获取附近的人定位),通过半径来查询
#georadius
georadius china:city 110 30 1000 km withdist #显示到中间的距离
georadius china:city 110 30 1000 km withcoord #结显示他人的定位信息
georadius china:city 110 30 1000 km withdist withcoord count 200 # 以 110,30 为中心,半径 1000km 的 200 个城市
#georadiusbymember
#找出位于指定元素周围的其他元素
georadiusbymember china:city beijing 1000 km
#geohash
#返回11位的字符的geohash字符串
#将二维的经纬度转换成一维的字符串,如果两个字符串越相近,距离越近
#不常用
geohash china:city beijing chongqing
geo的底层实现原理就是zset,我们可以使用zset命令操作geo!
2.2 hyperloglog
什么事基数?
A{1,3,5,7,9}
B{1,3,5,7,8}
基数(不重复的元素) =5 ,可以接受误差!
简介
Redis 2.8.9更新了Hyperloglog数据结构。
Redis Hyperloglog基数统计的算法。
优点:占用内存的固定的,2^64不同元素的技术,只需要12kb内存!
网页的UV(一个人访问一个网站多次,但是还是算做一个人)
传统的方式是使用set,保存用户id,然后统计set的元素作为标准判断。
这个方式如果保存大量用户id,就会比较麻烦!
0.81%错误率!可以接受!统计uv任务,可以忽略不计!如果不允许容错,就使用set或者自己的数据类型!
pfadd mykey a b c d e f g h i j
pfcount mykey #统计基数数量
pfmerge mykey mykey2 mykey3 # 合并两组元素到mykey3!
2.3 Bitmap
位存储
统计疫情感染人数: 0 0 0 1 0
统计粉丝活跃、用户登陆未登陆、365天打卡!
只要是两个状态的都可以使用bitmap!
都是操作二进制位来进行记录,只有0和1两个状态
#周一到周六的打卡记录
setbit sign 0 1
setbit sign 1 1
setbit sign 2 0
setbit sign 3 1
setbit sign 4 1
setbit sign 5 0
#查看某一天是否打卡
getbit sign 3
#统计打卡天数
bitcount sign
三、Redis基本的事务操作
MySQL: ACID!
Redis单条命令保证原子性,但是事务不保证原子性
**Redis事务没有隔离级别的概念!**所有的命令在事务中,并没有直接被执行,只有发起执行命令才会执行!
Redis事务本质,一组命令的集合!一个事物的所有命令都会被序列化,在食物执行的过程中,会按照顺序执行!
一次性、顺序性、排他性!
redis的事务:
- 开启事务:Multi
- 命令入队:…
- 执行事务:exec
multi
set k1 v1
set k2 v2
set k3 v3
exec
#放弃事务
multi
set k1 v1
set k2 v2
set k3 v3
discard
#编译型异常(代码有问题,命令有错),事务中的所有命令都不会被执行!
multi
set k1 v1
set k2 v2
set k3 v3
getset k3 #错误语句
exec
#不会执行所有的命令
#运行时异常(1/0),如果事务队列中存在语法性错误!其他命令正常,错误命令报错!
multi
set k1 “vvvv”
incr k1
exec
#只有错误语句没有被执行!
四、Redis的乐观锁
监控
悲观锁:
- 悲观,什么时候都出问题,无论做什么都会加锁
乐观锁:
- 很乐观,认为什么时候都不会出问题,不回上锁,更新数据的时候才判断一下,在此期间有没有修改过数据
- 获取version
- 更新的时候比较version
监视测试
set money 100
set out 0
watch money #监视money
multi #事务正常结束,数据期间没有发生变动,这个时候正常执行
decrby money 20
decrby out 20
exec
#再开一个客户端测试多线程修改值,watch当作redis的乐观锁操作
set money 100
set out 0
watch money #监视money
multi
decrby money 20
decrby out 20
#重新开一个客户端
set money 200
#回第一个客户端
exec #错误
unwatch #事务失败,先解锁
watch #再加锁
multi
decrby money 10
exec #成功
五、使用Jedis操作Redis
我们使用java操作Redis
什么是Jedis,是Redis官方推荐的Java连接工具,是java操作Redis的中间件
1、导入对应的依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
2、编码测试
- 连接数据库
- 操作命令
- 断开连接
package com.xwy.test;
import redis.clients.jedis.Jedis;
/**
* @author levi
* @create 2020/7/25 12:57 下午
*/
public class TestPing {
public static void main(String[] args){
Jedis jedis = new Jedis("ip",6379);
System.out.println(jedis.ping());
}
}
3、常用API
所有代码类似命令!
六、通过Jetis再次理解事务
事务
JSONObject jsonObject = new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","xwy");
Transaction multi = jedis.multi(); //开启事务
String result = jsonObject.toJSONString();
try{
multi.set("user1",result);
multi.set("user2",result);
multi.exec();
}catch (Exception e){
multi.discard();
e.printStackTrace();//放弃事务;
}finally {
System.out.println(jedis.get("user1"));
jedis.close();
}
七、SpringBoot集成Redis
springboot2.x后,原来的jedis被替换成了lettuce
jedis:采用的直连,多个线程操作是不安全的,想要避免不安全,使用jetis pool连接池,更像BIO模式
lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据,更像NIO模式:
整合测试
- 导入依赖
- 配置连接
spring.redis.host=39.97.184.172
spring.redis.port=6379
- 测试
package com.xwy;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootO2ApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
//opsForValue 操作字符串 类似string
//opsForList 操作List
//ops。。。
// //获取redis连接对象
// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// connection.flushAll();
// connection.flushDb();
redisTemplate.opsForValue().set("mykey","xwy");
System.out.println(redisTemplate.opsForValue().get("mykey"));
}
}
八、自定义RedisTemplate
首先测试:
关于对象的保存:
需要讲对象序列化!
可以成功获取值!
不同的方式的配置类:(写好的固定模版,企业中拿去直接使用!!!)
在真实的开发中,一般都自己封装RedisUtil
由于代码太多,先留个坑
九、RedisConfig配置文件详解
#1、配置文件 unit单位对大小写不敏感!
2、bind ip #绑定的IP
3、protected-mode #保护模式
#通用
4、daemonize yes #以守护进程方式运行,默认是no 需要改为yes
5、pidfile /var/run/redis_6379.pid # 如果后台运行,需要制定pid文件
6、loglevel notice #日志
logfile "" #输出的日志文件位置名
7、databse 16 # 默认是16个数据库
# 快照
#持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb.aof
#redis是内存数据库,如果没有持久化,数据断电即失
8、#如果900s内,如果至少有一个key进行了修改,就需要持久化操作
save 900 1
9、stop-writes-on-bgsave-error yes # 持久化出错还要不要继续执行
10、rdbcompression yes # 是否压缩rdb文件,需要小号一些cpu资源
11、rdbchecksum yes #保存rdb文件的时候,是否要进行错误检查校验
12、dir ./ #rdb 文件保存的目录
#安全
13、密码
#限制
14、maxclients 1000 #设置能连接redis的最大客户端数量
15、maxmemory <bytes> #设置redis配置的最大内存容量
16、maxmemory-policy noeviction #内存达到上限之后的处理策略
#移除过期的key
#报错
#。。。。
#APPEND ONLY模式 aof配置
17、appendonly no #默认是不开启aof模式 默认是rdb方式持久化,在大部分情况下,rdb完全够用
18、appendfilename “appendonly.aof“ #持久化文件的名字
19 #appendfsync always #每次修改都会sync 消耗性能
#appendfsync everysec #每秒执行一次,可能会丢失这一秒的数据
#appendfsync no #不执行sync
十、Redis持久化
Redis是一个内存数据库,不提供持久化那么数据断电即失!
1、RDB(Redis DataBase)
触发机制
- save的规则满足的情况下,出发rdb规则
- 执行flushall,也会触发
- 推出redis,也会产生一个rdb文件
备份自动生成一个dump.rdb
如果恢复rdb文件
1、只需要将rdb文件放在redis启动目录下,redis启动自动检查dump.rdb回复其中的数据
2、查看需要存在的位置
config get dir
优点:
- 适合大规模的数据恢复
- 对数据完整性的要求并不高,
缺点
- 需要一定的时间间隔进行进程操作,如果redis意外宕机,这个最后一次修改的数据就没有了。
- fork进程的时候,会占用一定的内容空间。
2、AOF(Append Only File)
将所有命令都记录下来,history,回复的时候就把这个文件全部执行一遍!
AOF保存的文件时appendonly.aof!!
默认是不开启的,需要手动配置!!appendonly on改为yes!!!重启redis就可以开启!!
如果aof文件有错误,redis启动不起来!我们需要修复!
redis给我们提供了一个工具,叫redis-check-aof!!!
redis-check-aof --fix appendonly.aof
优点和缺点
优点
- 每一次修改都同步,文件完整性更好
- 每秒同步一次可能会丢失一秒数据
- 从不同步效率最高
缺点
- 相对于数据文件来说,aof远远大于rdb,修复的速度比rdb慢
- 运行效率比rdb慢,所有redis默认的持久化策略是rdb!
十一、Redis订阅发布
通信 队列 发送者 订阅者
Redis发布订阅(pub/sub)是一种消息通信模式。微信、微博、关注系统
Redis可以订阅任意数量的频道。
角色
消息发送者、频道、接受者
测试
subscribe kuangshenshuo #建立频道
#去另一个终端!
publish kuangshenshuo "hello kuangshen" #发送消息
使用场景:
- 实时消息系统
- 实时聊天(频道作为聊天室,将信息回显给所有人)
- 订阅、关注系统
稍微复杂的场景使用消息中间件MQ做
十二、Redis主从复制
数据复制是单向的,只能从主节点到从节点!!
主从复制,读写分离!80%的情况下都是独操作!减缓服务器压力,架构中常用!一主二从!
作用
- 数据冗余
- 故障恢复
- 负载均衡
- 高可用(集群)
一般来说,Redis运用于工程,只使用一台是万万不可的!!!
- 结构上,单台redis服务器会发生单点故障,并且一台服务器要处理所有的负载,压力较大
- 容量上,单台redis内存容量有限,一般来说,单台redis最大使用内存不要超过20G。
环境配置
127.0.0.1:6379> info replication #查看当前库的信息
# Replication
role:master # 角色
connected_slaves:0 #没有从机
master_replid:c35253ec819f702ff5d100cd6b88bebd5f897a15
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
#在两个从机中配置!!
slaveof 127.0.0.0.1 6379
真实的配置应该是在配置文件中配置,这里使用的是命令,是暂时的!!
细节
- 主机可以写,从机只能读不能写!!主机中的所有信息和数据都会被从机自动保存!!
- 主机断开连接,从机依旧连接到主机,但是没有写操作了,如果住机会来了,从机仍然能获得主机写的信息!!
- 如果是使用命令行配置的,从机重启会变成主机,重新变为主机,重新变为从机后,立马会从主机中获取值!
复制原理
如果没有老大了,能不能选择一个老大出来呢?
slaveof no one #如果主机断开可以篡位,是自己变为主机!
其他节点手动变为我的从节点!手动!主机回来之后,只能重新配置,光杆司令!
哨兵模式
哨兵模式(自动选举老大的模式)
哨兵是一个独立的进程!
测试
#1 配置
#进入redis.conf所在的文件夹
vim sentinel.conf
#写入
sentinel monitor myredis 127.0.0.1 6379 1 #被监控的名称 主机 端口号 1
#后面的数字1 代表主机挂了,slave投票看让谁接替成为主机,票数最多的,成为主机!
#2 启动
#bin
redis-sentinel kconfig/sentinel.conf
如果主机master宕机,就会从从机中随机选一个作为主机!!主机回来后,自动现任主机的从机!
优缺点
优点:
- 哨兵集群,基于主从复制模式,所有主从配置的优点都有
- 主从可以切换,故障可以转移,可用性就会更好
- 哨兵模式是主从模式爹升级,手冻到自动,更加健壮
缺点:
- Redis不好在线扩容,集群容量达到上限,在线扩容十分麻烦
- 实现哨兵模式的配置其实是很麻烦的,有很多选择
哨兵模式的全部配置
十三、Redis缓存穿透和雪崩
缓存穿透
概念
用户想要查询一个数据,但是缓存内没有,数据库也没有,于是查询失败,但是用户很多的情况下,缓存都没有命中,于是都去请求数据库,这就给数据库造成很大压力,出现缓存穿透!!
解决方案
布隆过滤器
缓存过滤器
问题
- 如果空值能够被缓存起来,就意味着缓存需要更多的空间,因为当中很多空值的键
- 即使对空值设置了过期时间,但是还是会存在缓存层和存储层数据会有一段时间窗口的不一致,这对于需要保持数据一致性的业务会有影响
缓存击穿
火力全部被压在一个地方!
微博服务器宕机!
概述
解决方案
设置热点数据永不过期
从缓存层面看,没有设置过期时间,所以不会出现热点key过期后产生的问题
加互斥锁
分布式锁,保证每一个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可,这种发式将高并发的压力转移到了分布式锁,对分布式锁的考验很大!
缓存雪崩
概念
解决方案
Redis高可用
redis可能挂掉,那么多增加几台redis,一台挂掉其他可以继续工作,搭建集群,异地多活
限流降级
缓存失效,通过加锁或者队列空值数据库写缓存的线程数量
数据预热
正式部署前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动出发缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀。