事务
Redis事务的本质是所有命令一起执行
Redis单条命令是有原子性的,但是Redis的事务不保证原子性
开启事务 multi
命令入队
执行操作 exec
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK
exec以后此事务执行完成,若还要执行事务,则需要再开启一个事务
放弃事务:discard
编译有问题时,队列中的所有命令都不回执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> getset k1
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)
运行异常,队列中的其他命令可以正常执行
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get k2
"v2"
Redis监测功能
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
watch的监测
先将线程1的命令入队列,此时线程2改变被监视的 money的值,再执行线程一的事务,最后事务会执行失败
线程一
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby money -10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
线程二改变money
[root@com bin]# redis-cli
127.0.0.1:6379> set money 1000
OK
执行线程一事务
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
此时的乐观锁失效了,需要执行unwatch解锁,再重新上锁才能开启新的事务
Jedis
导入maven坐标
<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>
编码测试
连接redis,输出pong则连接成功
package com.txl;
import redis.clients.jedis.Jedis;
public class Testping {
public static void main(String[] args) {
Jedis jedis=new Jedis("127.0.0.1",6379);
System.out.println(jedis.ping());
jedis.close();
}
}
创建User类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.io.Serializable;
@Component
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {
private String name;
private Integer age;
}
使用RedisTemplate
import com.txl.redis01jedis.pojo.User;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.io.IOException;
@SpringBootTest
class Redis02SpringbootApplicationTests {
@Resource
private RedisTemplate<String,String> template;
@Test
void contextLoads() {
System.out.println(template);
template.opsForValue().set("v1","txllg");
System.out.println(template.opsForValue().get("v1"));
}
@Test
public void test() throws IOException {
User user=new User("txllg",21);
String jsonUser=new ObjectMapper().writeValueAsString(user);
template.opsForValue().set("user",jsonUser);
System.out.println(template.opsForValue().get("user"));
}
}
RDB持久化操作
触发生成dump.rdb的机制:
1.save的规则满足的情况下,会自动触发rdb规则
2.执行flushall命令,也会出发rdb规则
3.退出redis,也会产生rdb文件
备份就自动生成一个dump.rdb
优点:
1.适合大规模的数据恢复
2.对数据的完整性要求不高
缺点:
1.需要一点的时间间隔进程操作,如果redis意外宕机,这个最后一次的修改数据就没有了
2.fork进程的时候,需要占用一定的内存空间
aof
默认是不开启的,我们需要手动进行配置,只需要将appendonly改为yes就可以开启aof了,重启,redis就可以生效了
如果这个aof文件有错误,这时候redis是启动不起来的,我们需要修复这个文件,启用以下命令修复文件:
redis-check-aof --fix appendonly.aof
优点:
1.每一次修复都同步,文件的完整性更好
2.每秒都同步一次,可能会丢失一秒的数据
3.从不同步,效率最高
缺点:
1.相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢
2.aof的运行效率也比rdb慢
Redis发布订阅
订阅频道:
subscribe channel
127.0.0.1:6379> subscribe txllg
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "txllg"
3) (integer) 1
1) "message"
2) "txllg"
发布频道消息:
publish channel message
127.0.0.1:6379> publish txllg hello
(integer) 1
发送端发布消息,订阅了该频道的接收端的接收者就会接收到该消息
主从复制
主从复制,读写分离,80%的情况下都是读,所以让主机进行写操作,从机进行读操作,减缓服务器压力。
环境配置,只配置从库,不配置主库
查看当前库的信息:
info replication
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:7259fa24395a27382f2073e1dcc4cbfbe18f843d
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
开启多个连接,更改相关配置
修改端口
修改pid名字
修改log文件名字
修改dump.rdb文件名字
开启服务
默认情况下,每台redis服务器都是主节点,一般情况下,只需要配从机就好了
slaveof host port
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:56
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:571509779db3cdb76bfe9d7dbb943b08a8a1950e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:56
到主机中查看
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=182,lag=1
master_replid:571509779db3cdb76bfe9d7dbb943b08a8a1950e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:182
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:182
真实的配置应该是在配置文件中进行配置,这样得到的主从配置是永久的,主机可以写,从机不能写,只能读
主机断开连接,从机依然能连接到主机,并且从主机中读取
层层链路:上一个主节点连接下一个从节点,真正的主节点只有一个,也就是说只有一个可以可以写入,这时候也可以完成主从复制
如果主机断了,剩下的从节点想当主节点,执行:
slaveof no one
127.0.0.1:6381> slaveof no one
OK
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_replid:f7333843bfb01479fbcbd6ec1de63ad1e8125f14
master_replid2:89462a9ad933a3f50b26ba353096ec73a5279b22
master_repl_offset:542
second_repl_offset:543
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:528
哨兵模式
自动选举老大模式
进入到配置文件目录,新建配置文件:
[root@com ~]# cd /usr/local/bin/lconfig
[root@com lconfig]# vim sentinel.conf
编写配置文件:
sentinel monitor myredis 127.0.0.1 6379 1
1代表主机挂了,开始投票选举主机
启动哨兵
redis-sentinel lconfig/sentinel.conf
[root@com bin]# redis-sentinel lconfig/sentinel.conf
3172:X 11 Sep 2020 19:18:50.122 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3172:X 11 Sep 2020 19:18:50.122 # Redis version=6.0.7, bits=64, commit=00000000, modified=0, pid=3172, just started
3172:X 11 Sep 2020 19:18:50.122 # Configuration loaded
3172:X 11 Sep 2020 19:18:50.124 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 3172
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
3172:X 11 Sep 2020 19:18:50.126 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
3172:X 11 Sep 2020 19:18:50.130 # Sentinel ID is f6fc27d48ae08a34d44ae28fd8c13d6c5300bfc1
3172:X 11 Sep 2020 19:18:50.130 # +monitor master myredis 127.0.0.1 6379 quorum 1
3172:X 11 Sep 2020 19:18:50.132 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
如果主节点宕机了,那么哨兵会从从节点中选出一个主机
3172:X 11 Sep 2020 19:24:37.985 # +sdown master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:37.985 # +odown master myredis 127.0.0.1 6379 #quorum 1/1
3172:X 11 Sep 2020 19:24:37.985 # +new-epoch 1
3172:X 11 Sep 2020 19:24:37.985 # +try-failover master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:37.988 # +vote-for-leader f6fc27d48ae08a34d44ae28fd8c13d6c5300bfc1 1
3172:X 11 Sep 2020 19:24:37.988 # +elected-leader master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:37.988 # +failover-state-select-slave master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.051 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.051 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.103 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.474 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.474 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:38.562 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:39.452 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:39.452 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:39.541 # +failover-end master myredis 127.0.0.1 6379
3172:X 11 Sep 2020 19:24:39.541 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6381
3172:X 11 Sep 2020 19:24:39.542 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6381
3172:X 11 Sep 2020 19:24:39.542 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
3172:X 11 Sep 2020 19:25:09.593 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381
之前的主机再次回来,只能当从机
Redis缓存穿透和雪崩
缓存穿透:查不到
缓存击穿:量太大,热点数据过期,导致击穿
雪崩:某个时间点,缓存集中失效过期,redis宕机