redis-day3:持久化、主从复制、事务

持久化

redis 是一个支持持久化的内存数据库,也就是说redis 需要经常将内存中的数据同步到磁盘来保证持久化。redis 支持两种持久化方式,一种是Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。

snapshotting

快照是默认的持久化方式。默认已打开。写入的文件默认是dump.rdb。
这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n 秒内如果超过m 个key 被修改就自动做快照,下面是默认的快照保存配置:(编辑 redis.conf可见)
save 900 1 # 900 秒内如果超过1 个key 被修改,则发起快照保存
save 300 10 # 300 秒内容如超过10 个key 被修改,则发起快照保存
save 60 10000 # 60 秒内容如超过10000 个key 被修改,则发起快照保存

快照保存的过程:

  1. redis调用fork,产生子进程
  2. 父进程继续处理client请求,子进程负责将内存内容写入临时文件。由于os 的实时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os 会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址空间内的数据是fork时刻整个数据库的一个快照。
  3. 当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。

client 也可以使用save 或者bgsave 命令通知redis 做一次快照持久化。save 操作是在主线程中保存快照的,由于redis 是用一个主线程来处理所有client 的请求,这种方式会阻塞所有client 请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步变更数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io 操作,可能会严重影响性能。

aof (append-only file)

另外由于快照方式是在一定间隔时间做一次的,所以如果redis 意外down 掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof 持久化方式。

快照和aof方式可以同时使用.

aof 比快照方式有更好的持久化性,是由于在使用aof 持久化方式时,redis 会将每一个收到的写命令都通过write 函数追加到文件中(默认是appendonly.aof)。当redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于os 会在内核中缓存write 做的修改,所以可能不是立即写到磁盘上。这样aof 方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis 我们想要通过fsync 函数强制os 写入到磁盘的时机。有三种方式如下(默认是:每秒fsync 一次)(编辑redis.conf)

  • appendonly yes #启用aof 持久化方式
  • appendfsync always #收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
  • appendfsync everysec 3每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
  • appendfsync no #完全依赖os,性能最好,持久化没保证
    可以查看vim /usr/local/redis/src/appendonly.aof文件,命令就保存在此

aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100 次,文件中必须保存全部的100 条命令,其实有99 条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100 就够了。为了压缩aof 的持久化文件。redis 提供了bgrewriteaof 命令。收到此命令redis 将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。具体过程如下:

  1. redis 调用fork ,现在有父子两个进程
  2. 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
  3. 父进程继续处理client 请求,除了把写命令写入到原来的aof 文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
  4. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
  5. 现在父进程可以使用临时文件替换老的aof 文件,并重命名,后面收到的写命令也开始往新的aof 文件中追加。
    需要注意到是重写aof 文件的操作,并没有读取旧的aof 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof 文件,这点和快照有点类似。

主从复制

主从复制由master负责读,其他slave负责写,主从数据一致:

  1. master 可以拥有多个slave
  2. 多个slave 可以连接同一个master 外,还可以连接到其他slave
  3. 主从复制不会阻塞master,在同步数据时,master 可以继续处理client 请求
  4. 提高系统的伸缩性

redis 主从复制过程:
当配置好slave 后,slave 与master 建立连接,然后发送sync 命令。无论是第一次连接还是重新连接,master 都会启动一个后台进程,将数据库快照保存到文件中,同时master 主进程会开始收集新的写命令并缓存。后台进程完成写文件后,master 就发送文件给slave,slave将文件保存到硬盘上,再加载到内存中,接着master 就会把缓存的命令转发给slave,后续master 将收到的写命令发送给slave。如果master 同时收到多个slave 发来的同步连接命令,master 只会启动一个进程来写数据库镜像,然后发送给所有的slave。

配置slave

  1. 在slave机器中将redis.conf(/usr/local/redis/)中的port改成6378;
  2. 在该文件修改或增加一行:
    slaveof 192.168.1.1 6379 #指定master 的ip 和端口

判断主从使用info命令:
role:master (或slave)

事务控制

redis 对事务的支持目前还比较简单。redis 只能保证一个client 发起的事务中的命令可以连续的执行,而中间不会插入其他client 的命令。由于redis 是单线程来处理所有client 的请求的所以做到这点是很容易的。一般情况下redis 在接受到一个client 发来的命令后会立即处理并返回处理结果,但是当一个client 在一个连接中发出multi 命令有,这个连接会进入一个事务上下文,该连接后续的命令并不是立即执行,而是先放到一个队列中。当从此连接受到exec 命令后,redis 会顺序的执行队列中的所有命令。并将所有命令的运行结果打包到一起返回给client.然后此连接就结束事务上下文。

使用事务 multi和exec之间的命令

redis 127.0.0.1:6379> get age
"33"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set age 10
QUEUED
redis 127.0.0.1:6379> set age 20
QUEUED
redis 127.0.0.1:6379> exec

取消事务

redis 127.0.0.1:6379> get age
"20"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set age 30
QUEUED
redis 127.0.0.1:6379> set age 40
QUEUED
redis 127.0.0.1:6379> discard
OK
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值