Redis入门(下):Redis事务和主从复制

开始时间:2022-03-25
课程链接:Redis实战精讲

Redis配置文件

Redis的安装根目录下(/opt/redis-5.0.2),Redis在启动时会加载这个配置文件,在运行时按照配置进行工作。 这个文件有时候我们会拿出来,单独存放在某一个位置,启动的时候必须明确指定使用哪个配置文件,此文件才会生效。

Redis 的网络相关配置

  • bind:绑定IP地址,其它机器可以通过此IP访问Redis,默认绑定127.0.0.1,也可以修改为本机的IP地址。
  • port:配置Redis占用的端口,默认是6379。
  • tcp-keepalive:TCP连接保活策略,可以通过tcp-keepalive配置项来进行设置,单位为秒,假如设置为60秒,则server端会每60秒向连接空闲的客户端发起一次ACK请求,以检查客户端是否已经挂掉,对于无响应的客户端则会关闭其连接。如果设置为0,则不会进行保活检测。

进入redis.conf文件
在这里插入图片描述
我们的ip是192.168.91.128
因此修改bind后面的默认值
同时修改端口号6380
在这里插入图片描述

[root@localhost redis-5.0.2]# redis-cli -h 192.168.91.128 -p 6380
192.168.91.128:6380> 

[root@localhost redis-5.0.2]# redis-cli -h 192.168.91.128 -p 6380 shutdown

常规配置:
loglevel:配置日志级别,开发阶段配置debug,上线阶段配置notice或者warning.
logfile:指定日志文件。redis在运行过程中,会输出一些日志信息;默认情况下,这些日志信息会输出到控制台;我们可以使用logfile配置日志文件,使redis把日志信息输出到指定文件中。
databases:配置redis服务默认创建的数据库实例个数,默认值是16。

在vim的命令行模式下 输入

:/ 想要搜的文件名

可以实现类似ctrl+F的功能
指定日志文件名字
在这里插入图片描述

安全配置

为了高效性,默认不配置密码
requirepass:配置Redis的访问密码。默认不配置密码,即访问不需要密码验证。此配置项需要在protected-mode=yes时起作用。使用密码登录客户端:redis-cli -h ip -p 6379 -a pwd

Redis持久化

redis是内存数据库,它把数据存储在内存中,这样在加快读取速度的同时也对数据安全性产生了新的问题,即当redis所在服务器发生宕机后,redis数据库里的所有数据将会全部丢失。为了解决这个问题,redis提供了持久化功能——RDB和AOF(Append Only File)
在适当的时机采用适当手段把内存中的数据持久化到磁盘中,每次redis服务启动时,都可以把磁盘上的数据再次加载内存中使用。

RDB

RDB(Redis DataBase)是 Redis 默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis重启会通过加载dump.rdb文件来恢复数据。

原理:Redis会复制一个与当前进程一样的进程。
新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程,来进行持久化。
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
RDB保存的文件是dump.rdb文件 ,位置保存在Redis的启动目录。Redis每次同步数据到磁盘都会生成一个dump.rdb文件,新的dump.rdb会覆盖旧的dump.rdb文件。

配置RDB 持久化策略

       save <seconds> <changes>:配置持久化策略
       dbfilename:配置redis RDB持久化数据存储的文件
       dir:    配置redis RDB持久化文件所在目录
save <seconds> <changes>

配置复合的快照触发条件,即Redis 在seconds秒内key改变changes次,Redis把快照内的数据保存到磁盘中一次。默认的策略是:
1分钟内改变了1万次
或者5分钟内改变了10次
或者15分钟内改变了1次
如果要禁用Redis的持久化功能,则把所有的save配置都注释掉。

但他有不足,就是比如刚触发完了我的一次持久化,我再添加一些数据,很可能三个条件都不满足,那就会造成数据丢失

不过一般redis里面放的都是频繁访问的数据
会存放到mysql里面

AOF

AOF(Append Only File)

采用操作日志来记录进行每一次写操作,每次redis服务启动时,都会重新执行一遍操作日志中的指令。记录的是改数据的所有操作,而不是记录数据
如果宕机了,那就重新执行这些操作,
效率低下,redis默认不开启AOF功能。

appendonly:配置是否开启AOF策略
appendfilename:配置操作日志文件

根据数据的特点决定开启哪种持久化策略;
一般情况,开启RDB足够了。

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> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK

redis的事务只能保证部分原子性:
a)如果一组命令中,有在压入事务队列过程中发生错误的命令,则本事务中所有的命令都不执行,能够保证事务的原子性。
multi

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set kk vv
QUEUED
127.0.0.1:6379> seta kk2 vv2
(error) ERR unknown command `seta`, with args beginning with: `kk2`, `vv2`, 
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

如果一组命令中,在压入队列过程中正常,但是在执行事务队列命令时发生了错误,则只会影响发生错误的命令,不会影响其它命令的执行,不能够保证事务的原子性。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK

压入队列不报错,执行的时候报错,这个时候就不满足原子性
discard:清除所有已经压入队列中的命令,并且结束整个事务。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set kk3 32
QUEUED
127.0.0.1:6379> discard
OK

事务案例

银行卡同时取钱问题

设置一个版本号

id balance version
update table set balance=balance-dept,version=version+1
where id=xxxx and version=100

看一个例子

127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> set balance2 1000
OK
127.0.0.1:6379> set version 1
OK
127.0.0.1:6379> watch version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby balance 50
QUEUED
127.0.0.1:6379> incrby balance2 50
QUEUED
127.0.0.1:6379> incr version
QUEUED

已经排好队了,这个时候我们用watch监控了version,一旦外部让version产生了变化,那么整个事务都不执行
我们再开启一个xshell

127.0.0.1:6379> incrby version
(error) ERR wrong number of arguments for 'incrby' command
127.0.0.1:6379> incr version
(integer) 2

此时改变了version的值

127.0.0.1:6379> exec
(nil)

同理,可以放弃监控
使用

unwatch

放弃所有的监控,要在添加监控只能重新加

事务小结

  • 单独的隔离操作:事务中的所有命令都会序列化、顺序地执行。事务在执行过程中,不会被其它客户端发来的命令请求所打断,除非使用watch命令监控某些键。
  • 不保证事务的原子性:redis同一个事务中如果一条命令执行失败,其后的命令仍然可能会被执行,redis的事务没有回滚。Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。

Redis消息的订阅与发布

图一:消息订阅者(client2 、 client5 和 client1)订阅频道 channel1
在这里插入图片描述

图二:消息发布者发布消息到频道channel1,会被发送到三个订阅者:
在这里插入图片描述
比如我订阅频道ch1和ch2

127.0.0.1:6379> subscribe ch1 ch2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "ch1"
3) (integer) 1
1) "subscribe"
2) "ch2"
3) (integer) 2

订阅后这条路就一直在收听状态
我们再开一个xshell,使用publish进行发布

127.0.0.1:6379> publish ch2 nihaoma
(integer) 1
127.0.0.1:6379> publish ch1 wohenhao

这里就会实时收听

1) "message"
2) "ch2"
3) "nihaoma"
1) "message"
2) "ch1"
3) "wohenhao"

psubscribe pattern [pattern]

功能:订阅一个或多个符合给定模式的频道。模式以 * 作为通配符,例如:news.* 匹配所有以 news. 开头的频道。
返回值:订阅的信息。
可以根据这个做出消息队列

Redis主从复制

主从复制

主机数据更新后根据配置和策略,自动同步到从机的master/slave机制,Master主机以写为主,Slave从库以读为主。

主少从多、主写从读、读写分离、主写同步复制到从。

一主二从原理

  • 配从(库)不配主(库)
  • 配从(库): slaveof 主库IP 主库端口
  • 主写从读、读写分离
  • 从连前后同
  • 主断从待命、从断重新连
    搭建三台redis服务:使用一个redis模拟三台redis服务
    提供三分redis配置文件:redis6379.conf、redis6380.conf、redis6381.conf

修改
先使用

cp redis.conf redis6379.conf
cp redis.conf redis6380.conf
cp redis.conf redis6381.conf

然后修改该文件,6379.conf里面的

bind 127.0.0.1
port 6379
logfile "6379.log"
dbfilename dump6379.rdb
pidfile /var/run/redis_6379.pid

同理,按照端口号配置另外两个文件

分别使用三个redis配置文件,启动三个redis服务:

redis-server redis6379.conf &
redis-server redis6380.conf &
redis-server redis6381.conf &

在三个窗口启动三台redis服务
在这里插入图片描述
在对应的窗口链接对应服务器

redis-cli -h 127.0.0.1 -p 6379
redis-cli -h 127.0.0.1 -p 6380
redis-cli -h 127.0.0.1 -p 6381

查看主从关系

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0

默认情况下,所有的redis服务都是主机,即都能写和读,但是都还没有从机。
在6380和6381设置为从机

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
master_port:6379

回来看6379,有两个从机了

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1

主机上设置一个值

127.0.0.1:6379> set k1 v1
OK

从机就能同步了,已有的同步过去了
这个叫全量复制
现添的数据,也能同步,这个叫增量复制

127.0.0.1:6380> get k1
"v1"
127.0.0.1:6381> get k1
"v1"

从机就不能写数据了
这个叫做主写从读,读写分离

127.0.0.1:6381> set k2 v2
(error) READONLY You can't write against a read only replica.

主机宕机,从机待命

关闭6379服务:redis-cli -h 127.0.0.1 -p 6379 shutdown

在从机上看

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down

连接状态为down
依然还能读

此时重启6379
主机恢复,一切正常

[root@localhost redis-5.0.2]# redis-server redis6379.conf &

6380就恢复了

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up

从机宕机
6380关机了
此时6379就只有一个从机了

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=98,lag=1

从机恢复

[root@localhost redis-5.0.2]# redis-server redis6380.conf &
[1] 6022
[root@localhost redis-5.0.2]# redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> 

此时从机6380自己当老大了

127.0.0.1:6380> info replication
# Replication
role:master

主机6379就没有这个小弟了

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=224,lag=1

从机上位
当6379关机后
6380设置

127.0.0.1:6380> slaveof no one
OK

自己当老大了,然后让6381连6380,重新设置主从关系就行

那6379此时恢复了怎么办?
已经是孤家寡人,光杆司令了

那可以让6380重新隶属于6379
此时的关系是6379下面一个slave6380,而6380下面一个6381,6381并没有直接属于6379

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:1
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up

主机的数据是可以同步到从机和从机的从机上,但这个时候6380虽然名义上是6381的主机,但是6380已经没有写的权限了

小结

一台主机配置多台从机,一台从机又可以配置多台从机,从而形成一个庞大的集群架构。
减轻一台主机的压力,但是增加了服务间的延迟时间。

哨兵模式

从机上位的自动版。
Redis提供了哨兵的命令,哨兵命令是一个独立的进程,哨兵通过发送命令,来监控主从服务器的运行状态,如果检测到master故障了根据投票数自动将某一个slave转换master,然后通过消息订阅模式通知其它slave,让它们切换主机。
然而,一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多哨兵进行监控。

搭建哨兵模式

提供哨兵配置文件:
在redis安装目下创建配置文件:redis_sentinel.conf
创建redis_sentinel.conf文件,编辑内容,表示:指定监控主机的ip地址,port端口,得到哨兵的投票数(当哨兵投票数大于或者等于此数时切换主从关系)。

sentinel monitor dc-redis 127.0.0.1 6379 1

启动哨兵服务:

[root@localhost redis-5.0.2]# redis-sentinel redis_sentinel.conf

在这里插入图片描述
等6379关机后
投票选举继承人
在这里插入图片描述
选中了6381->上位啦!

原主机恢复,启动6379,变为了6381的小弟

[root@localhost redis-5.0.2]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up

Jedis操作Redis

使用Redis官方推荐的Jedis,在java应用中操作Redis。Jedis几乎涵盖了Redis的所有命令。操作Redis的命令在Jedis中以方法的形式出现。

建立一个普通的maven web工程
然后添加依赖

    <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>3.1.0</version>
    </dependency>

测试之前要先把redis里面的bind修改一下
进入redis6379.conf文件
将bind修改为本机ip 192.168.113.128(注意,这里本机ip不是192.168.91.128了,我不知道为什么我一顿骚操作后ip变了,反正变了就以变了后为主)
启动6379

[root@localhost redis-5.0.2]# redis-server redis6379.conf &
[1] 3749
[root@localhost redis-5.0.2]# redis-cli -h 192.168.113.128 -p 6379
192.168.113.128:6379> set k1 v1
OK
192.168.113.128:6379> set k2 v2
OK
192.168.113.128:6379> set k3 v3

并给redis设置三个键值对k1 k2 k3

此时在idea里面写代码

package BUPT;

import redis.clients.jedis.Jedis;

import java.util.Set;

public class JedisKeyTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.113.128", 6379);
        String res = jedis.ping();
        //返回pong表示正常
        System.out.println(res);
        Set<String> keys = jedis.keys("*");
        for (String key : keys
        ) {
            System.out.println(key);
        }
    }
}

注意:连接时一定要关闭防火墙!!

[root@localhost redis-5.0.2]# systemctl stop firewalld

查看返回值

PONG
k3
k1
k2

基本上命令还是以前redis的命令,只是现在这些命令变成了jedis对象的方法了
jedis敲事务

package BUPT;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class JedisKeyTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.113.128", 6379);
        String res = jedis.ping();
        //返回pong表示正常
        System.out.println(res);
        Transaction tran = jedis.multi();
        tran.set("k6", "v6");
        tran.set("k7", "v7");
        tran.set("k8", "v8");
        tran.exec();
    }
}

可视化工具

redis-desktop-manager
无脑安装,点进来就是
输入几个参数,测试能否连接
在这里插入图片描述

在这里插入图片描述

结束时间:2022-03-29

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值