点滴

redis实战

redis的持久化

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

snapshotting 方式

快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis 在n 秒内如果超过m 个key 被修改就自动做快照,下面是默认的快照保存配置
save 900 1 #900 秒内如果超过1 个key 被修改,则发起快照保存
save 300 10 #300 秒内容如超过10 个key 被修改,则发起快照保存
1.redis 调用fork,现在有了子进程和父进程。
2.父进程继续处理client 请求,子进程负责将内存内容写入到临时文件。由于os 的实时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os 会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址空间内的数据是fork时刻整个数据库的一个快照。
3.当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。client 也可以使用save 或者bgsave 命令通知redis 做一次快照持久化。save 操作是在主线程中保存快照的,由于redis 是用一个主线程来处理所有client 的请求,这种方式会阻塞所有client 请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步变更数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io 操作,可能会严重影响性能。

aof 方式

另外由于快照方式是在一定间隔时间做一次的,所以如果redis 意外down 掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof 持久化方式。下面介绍Append-only file:aof 比快照方式有更好的持久化性,是由于在使用aof 持久化方式时,redis 会将每一个收到的写命令都通过write 函数追加到文件中(默认是appendonly.aof)。当redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于os 会在内核中缓存 write 做的修改,所以可能不是立即写到磁盘上。这样aof 方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis 我们想要通过fsync 函数强制os 写入到磁盘的时机。有三种方式如下(默认是:每秒fsync 一次)

appendonly yes //启用aof 持久化方
appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
appendfsync no //完全依赖os,性能最好,持久化没保证

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 文件中追加。

发布及订阅消息

发布订阅(pub/sub)是一种消息通信模式,主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似。pub/sub 不仅仅解决发布者和订阅者直接代码级别耦合也解决两者在物理部署上的耦合。redis 作为一个pub/sub 的server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscribe 和psubscribe 命令向redisserver 订阅自己感兴趣的消息类型,redis 将消息类型称为通道(channel)。当发布者通过publish 命令向redis server 发送特定类型的消息时。订阅该消息类型的全部client 都会收到此消息。这里消息的传递是多对多的。一个client 可以订阅多个channel,也可以向多个channel发送消息。

Pipeline 批量发送请求

利用pipeline 的方式从client 打包多条命令一起发出,不需要等待单条命令的响应返回,而redis 服务端会处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端。

打赏一下

热评文章