使用redis保存对象
方法一
为该对象的类实现序列化接口,之后便能正常使用
class DemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
User u = new User();
u.setAge(18);
u.setName("hehe");
redisTemplate.opsForValue().set("k1",u);
System.out.println(redisTemplate.opsForValue().get("k1"));
}
//输出user{name='hehe', age=18}
}
方法二
把对象转为json字符串后存入
class DemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() throws JsonProcessingException {
user u = new user();
u.setAge(18);
u.setName("hehe");
String s = new ObjectMapper().writeValueAsString(u);
redisTemplate.opsForValue().set("k1",s);
System.out.println(redisTemplate.opsForValue().get("k1"));
//输出{"name":"hehe","age":18}
}
}
redis配置文件
- 网络相关
bind 127.0.0.1 #绑定ip
protected-mode yes #保护模式
port 6379 # 端口
- 通用配置
daemonize yes # 以赛扬进程的方式运行,默认是no,得自己开启
pidfile /var/run/redis_6379.pid # 如果以后台的方式运行,我们就需要指定一个pid文件
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice # 日志级别
logfile "" # 日志的文件位置名
databases 16 # 数据库数量,默认16个
always-show-logo yes # 是否总是显示logo
- 快照
# 持久化,在规定多少时间内执行多少次操作,就会持久化到文件,rdb,aof
save 900 1 # 900秒内至少有1个key进行修改,进行持久仳操作
save 300 10 # 300秒内至少有10个key进行修改
save 60 10000 # 60秒内至少有10000个key进行修改
stop-writes-on-bgsave-error yes # 持久化操作如果出错是否继续工作
rdbcompression yes # 是否压缩rdb文件,需要消耗cpu资源
rdbchecksum yes # 保存rdb文件是否进行检查效验
dir ./ # rdb保存路径
- REPLICATION 复制
主从配置,配置完所属主机后,在连上服务器后会自动让该服务器从属于主机
- SECURITY 安全
可以在这里设置密码
# requirepass foobared 去掉注释,requirepass后面加密码
用命令改密码
config get requirepass # 获得密码,如果没有登录,获取失败
config set requirepass 123456" # 设置密码
auth 123456 #登录
- CLIENTS
maxclients 10000 #连接redis最大客户数量
maxmemory <bytes> # 配置最大的内存容量
maxmemory-policy noeviction # 内存达到上限后的策略
# 1、volatile-lru:只对设置了过期时间的key进行LRU(默认值)
# 2、allkeys-lru : 删除lru算法的key
# 3、volatile-random:随机删除即将过期key
# 4、allkeys-random:随机删除
# 5、volatile-ttl : 删除即将过期的
# 6、noeviction : 永不过期,返回错误
- APPEND ONLY MODE aof配置
appendonly no # 默认不开启aof模式,默认使用rdb
appendfilename "appendonly.aof" # aof文件名
# appendfsync always # 每次修改都执行sync,比较影响性能
appendfsync everysec # 每秒执行一次sync
# appendfsync no # 不执行sync
RDB
-
在指定的时间间隔内将内存中的数据集快照写入磁盘(Snapshot快照),它恢复时是将快照文件直接读到内存里
-
redis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,等持久化完成,再用这个临时文件替换上次持久化好的文件,主进程不进行任何IO,确保了极高的性能
-
如果在进行大规模数据的恢复并且对数据恢复的完整性不是非常敏感,rdb方式比aof方式更高效
-
rdb的缺点是最后一次持久化后的数据可能丢失,默认使用rdb,一般情况不需要修改配置
保存机制 保存dump.rdb文件
- 满足配置文件里的要求(每多少秒内执行了多少次操作)
- 每次执行
flushall
都会保存 - 退出redis,
shutdown
、exit
,直接kill掉进程则不会保存
恢复rdb文件
把dump.rdb文件放在redis启动目录下即可,目录可通过config get dir
命令查看
优缺点
优点:适合大规模的数据恢复、对数据完整性不高
缺点:用子进程进行save,会占用一定内存、redis意外宕机可能最后一些修改不会保存
AOF(append only file)
- 以日志的形式记录下所有写操作,只追加在日志后面,启动redis则读取该文件重要数据结构。其实就是把以前的指定都再从头执行一遍
- 默认不开启,需要在配置文件里找到
appendonly no
改为yes - appendonly.aof文件可以被人为修改,如果被改坏了可以通过
redis-check-aof --fix appendonly.aof
指令修复aof日志
优缺点
优点:恢复的数据比较全,可在配置文件里选择每次执行操作都同步,或每秒同步一次或不同步
缺点:恢复数据没rdb那么快
持久化拓展
- 如果redis只是用来做缓存,可以不用持久化
- 如果red、aof两种持久化方式都开启,会优先使用aof进行数据恢复,因为它的数据更加完整
- 从数据库一般数据库rdb只保存
save 900 1
- 如果不使用aof,仅靠主从复制,能省掉一大笔IO,也减少重写带来的系统波动,代价是如果主从数据库同时宕机,会丢失十几分钟的数据,启动脚本比较主从数据库哪个的rdb文件更大(说明数据更全)就恢复哪个
订阅发布功能
功能 | 指令 | 备注 |
---|---|---|
订阅channel(频道) | subscribe {频道名} | |
订阅多个channel | psubscribe 频道1 频道2 | |
发送消息 | publish channel message |
订阅端
127.0.0.1:6379> subscribe hehe # 订阅了hehe频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "hehe"
3) (integer) 1
1) "message" # 消息
2) "hehe" # 哪个频道
3) "v aisg" # 具体消息
发送端
localhost:6379> publish hehe "v aisg"
(integer) 1
redis主从复制功能
简介
主从复制是指将一台redis服务器(主节点)的数据复制到其他的redis服务器(从节点),数据的复制是单向的,只能由主节点到从节点。主数据库以写为主,从数据库以读为主
默认情况下,每台redis服务器都是主节点,且一个主节点可以有0到多个从节点,一个从节点只能有一个主节点
主从复制作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
- 故障恢复:当主节点出现问题,可以由从节点提供服务,实现快速的故障恢复
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载
- 高可用基石:主从复制还是哨兵和集群能够实施的基础
环境配置
- 配置概要图
- 查看当前数据库信息
127.0.0.1:6379> info replication # 查看数据库信息
# Replication
role:master #角色
connected_slaves:0 # 从数据库数量
master_replid:9ec616b78972926387d48e6785caf43d00157ea9
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
- 配置3个redis配置文件
- 要改的四个地方
- 端口号
- pid
- log文件名
- dump.rdb
- 改完之后启动三个redis服务器
[root@localhost bin]# ps -ef | grep redis
root 5933 1 0 12:38 ? 00:00:00 redis-server 127.0.0.1:6379
root 5981 1 0 12:38 ? 00:00:00 redis-server 127.0.0.1:6380
root 6091 1 0 12:39 ? 00:00:00 redis-server 127.0.0.1:6381
root 6105 6059 0 12:40 pts/3 00:00:00 grep --color=auto redis
- 配置从机(认主机)
- 主机是不用配置的,因为默认所有redis服务器都是主机,只需要在从机上指定他的主机
- 在从机上执行
slaveof ip port
,指定完ip和对应端口后,该redis服务器自动变成从机
#从机视角
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave #变成从机
master_host:127.0.0.1 #主机ip
master_port:6379 #主机umkk
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:42
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:6cc6301a69c54232230a494cc646f8d7c8690871
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42
############################################
#主机视角
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=322,lag=1
master_replid:6cc6301a69c54232230a494cc646f8d7c8690871
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:322
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:322
意外情况
- 主机宕机:从机可以正常读出所有数据,但集群就丧失了写功能,一般会在从机中选出新的主机
- 从机宕机:某个从机宕机,主机写入了数据,等到宕机的服务器重连后
- 如果是用
salveof ip port
指令配置,则该服务器重新启动会变成主机,重新指定主机后即可看到断电期间主写入的数据 - 如果是在配置文件中配置了的,重启后直接能看到宕机期间主机写入的数据
- 如果是用
复制原理
- salve启动成功连接到master后会发送一个sync同步命令
- master接到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,master将传送整个数据文件到slave,并完成一次同步
- 两种复制方式
- 全量复制:slave接收到数据库文件后,将其存盘并加载到内存中
- 增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步
- slave重连到master上,将会执行一次全量复制
手动篡位
slaveof no one
哨兵模式(自动篡位)
- 哨兵模式是一种特殊的模式,哨兵是一个独立的进程,哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis服务器
- 哨兵作用
- 通过发送命令,让redis主从服务器返回其运行状态
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,切换主机
- 哨兵自己也可能会挂掉,所以一般会使用多个哨兵,哨兵除了监控主从服务器,还会相互监控
- 当主服务器宕机,哨兵1会检测到这个事,但并不会马上选举换人,如果后面到达一定数量的哨兵都监控到主机不可用,哨兵之间发起一次投票,通过发布订阅模式通知其他服务器切换主机
测试哨兵
- 编写配置文件
vim sentinel.conf
# sentinel monitor 被监控的名称 host port n(当n个哨兵认为主机失联,就认定它真的失联)
sentinel monitor myredis 127.0.0.1 6379 1 # 写完保存
# 更多的配置以后再找一下
- 启动哨兵
redis-sentinel myconf/sentinel.conf
- 主机如果宕机,过一会会重新选举出新的主机,如果原先的主机回来,只能当从机料
缓存穿透、击穿、雪崩
缓存穿透(缓存查不到,一直去查数据库)
用户想要查询一个数据,发现redis内存数据库里没有,也就是缓存没命中,于是向持久层数据库查询,然后也查不到,当用户很多的时候,都跑去请求持久层数据库,搞得持久层数据库压力很大,就是缓存穿透
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行效验,不符合则丢弃,从而避免了对底层存储系统造成太大查询压力
缓存空对象
当持久层数据库也拿不到数据,返回一个空值,也会将其进行缓存,同时设置一个过期时间,虽然这样能缓解数据库的压力,但是还有两个缺点
- 如果空值也要存储,可能会导致缓存中存储了很多没用的空值
- 缓存了空值之后如果数据库里对这个值
缓存击穿(查得到,缓存一过期全拥到数据库里把人整宕机)
缓存击穿是一个key非常热点像腾讯告老干妈,在不停地扛着并发,大并发集中对一点进行访问,当这个key失效的瞬间,持续的大并发就突破缓存,直接请求数据库,就像突破缓存,开了个洞
设置热点为不过期
加互斥锁
分布式锁:使用分布式锁,保证每个key同时只有一个线程去查询后端服务,其他没获得锁的只能等待
雪崩(击穿是一个key失效,雪崩是大量的缓存一起失效)
一些缓存同时过期或者缓存服务器宕机引起缓存失效(重点),然后导致大量的访问直接去到存储层
增设redis服务器,搭建集群
数据预热,在项目正式部署上线前先访问一遍数据,添加缓存
流量降级,当缓存失效后,通过加锁或队列的形式来限制数据库写、缓存的线程数量