七、Redis的配置文件#
## 启动redis的方式 ./redis-server /path/to/redis.conf # 可以像下面这样让在当前配置文件包含引用其他配置文件 include /path/to/local.conf include /path/to/other.conf # 指定哪些客户端可以连接使用redis Examples: bind 192.168.1.100 10.0.0.1 # 指定ip bind 127.0.0.1 ::1 # 仅限于本机可访问 # 是否处于受保护的模式,默认开启 protected-mode yes # 对外暴露的端口 port 16379 # TCP的通用配置 tcp-backlog 511 timeout 0 tcp-keepalive 300 # 是否以守护进程的方式运行,默认为no daemonize yes # 如果进程在后台运行,需要指定这个pid文件 pidfile /var/run/redis_6379.pid # 日志级别 # debug 测试开发节点 # verbose (和dubug很像,会产生大量日志) # notice (生产环境使用) # warning (only very important / critical messages are logged) loglevel notice # 日志文件名 logfile "" # 数据库的数量,默认16个 databases 16 # 是否总是显示logo always-show-logo yes # 设置redis的登陆密码(默认没有密码) # 设置完密码后,使用redis-cli登陆时,使用auth password 认证登陆 requirepass foobared # 设置能连接上redis的客户端的最大数量 maxclients 10000 # 给redis设置最大的内存容量 maxmemory <bytes> # 内存达到上限后的处理策略 # volatile-lru -> 只针对设置了过期时间的key进行LRU移除 # allkeys-lru -> 删除LRU算法的Key # volatile-lfu -> 使用具有过期集的密钥在近似的LFU中进行驱逐。 # allkeys-lfu -> 使用近似的LFU退出任何密钥。 # volatile-random -> 随机删除即将过期的key # allkeys-random -> 随机删除 # volatile-ttl -> 删除即将过期的 # noeviction -> 永不过期,返回错误 maxmemory-policy noeviction
八、Redis的持久化#
8.1、fork()系统调用#
这里很突兀的来个fork()系统调用原因是应为:Redis的单线程的,那如果主线程去做这种耗时的IO同步操作时,Redis整体的性能会被拖垮的。
fork()它是一个系统调用,一般用它来创建一个和当前进程一模一样的子进程。当在程序中调用它时,系统为新的进程分配存储、资源,将原程序中的值也复制给他。
fork()函数调用一次会返回两次,在父进程得到的返回值是子进程的pid,在子进程中得到的是0,出错则返回负数。
Redis的实现是通过fork()系统调用创建一个子进程。 由这个子进程去负责执行这些耗时的IO操作,父子进程会共享内存,然后被共享的这块内存不可写,新的数据写入到新的内存文件中
8.2、RDB#
写RDB文件是Redis的一种持久化方式。在指定的时间间隔内将内存中的数据写入到磁盘,RDB文件是一个紧凑的二进制文件,每一个文件都代表了某一个时刻(执行fork的时刻)Redis完整的数据快照,恢复数据时,将快照文件读入内存即可。
RDB持久化的详细过程:
Redis会通过系统调用fork()出一个子进程,父子进程是会共享内存的,父进程和子进程共享的这块内存就是在执行fork操作那个时刻的内存快照。由linux的copy on write机制将父子进程共享的这块内存标记为只读状态。
此时对子进程来说,它的任务就是将这块只读内存中的数据保存成RDB文件。
对父进程来说它是有可能收到写命令的,当父进程尝试往这个加了只读状态的内存地址写入数据时,就会触发保护异常,执行linux的 copy on write,也就是将原来内存对应的数据页复制出来一份后,然后对这个副本进行修改。
这里就会出现一个丢数据的概念:你想,fork出来的子进程将要保存的数据是执行fork系统调用那个时刻的内存中的数据,很快这个内存就被标记为只读了,后续的增量数据没有写入到这个只读内存中,那就算是RDB成功生成了,然后好巧,Redis挂了,这些增量的数据就会丢(所以得使用AOF辅助)
第二种RDB出现数据的丢失的情况是:RDB过程中,直接失败了,文件都没生成,不光是增量数据,原来的数据都丢了。
RDB相关配置如下
# 把下面的注释打开就会禁用掉RDB的持久化策略 # save "" # 快照相关,指的是在规定的时间内执行了多少次操作才会持久化到文件 save 900 1 # 900秒内1次 save 300 10 # 300秒内10次 save 60 10000 # 60秒内1万次 # 持久化出错了,是否让redis继续工作 stop-writes-on-bgsave-error yes # 是否压缩RBD文件(redis会采用LZF压缩算法进行压缩)需要消耗CPU资源 rdbcompression yes # 保存rbc文件时是否检验rbd文件格式 # 使用CRC64算法进行数据校验,但是这样会增加大约 10%的性能消耗 rdbchecksum yes # dump DB的文件名 dbfilename dump.rdb # rdb文件的持久化目录(当前目录) dir ./
触发保存RDB文件4种情况
- 手动执行save命令、bgsave
- 满足配置文件中配置的save相关配置项时,自动触发
- 手动执行flushall
- 关闭redisshutdown
如何让redis加载rdb文件?
只需要将rdb文件放在redis的启动目录下,redis其中时会自动加载它
RDB模式的优缺点:
优点:RDB过程中,由子进程代替主进程进行备份的IO操作。保证了主进程仍然提供高性能的服务。适合大规模的数据备份恢复过程。
缺点:
- 默认情况下,它是每隔一段时间进行一次数据备份,所以一旦出现最后一次持久化的数据丢失,将丢失大规模的数据。
- fork()子进程时会占用一定的内存空间,如果在fork()子进程的过程中,父进程夯住了,那也就是redis卡住了,不能对外提供服务。所以不要让生成RDB文件的时间间隔太长,不然每次生成的RDB文件过大对Redis本身也是有影响的。
8.3、AOF#
AOF是什么?
Append Only File,他也是Redis的持久化策略。即将所有的写命令都以日志的方式追加记录下来(只追加,不修改),恢复的时候将这个文件中的命令读出来回放。
当我们执行 flushall 命令,清空了redis在内存中的数据,appendonly.aof 同样会记录下这条命令,所以,我们想恢复数据的话,需要去除 appendonly.aof 里面的 flushall 命令
AOF相关的配置
# 默认不开启aof appendonly no # aof文件名 appendfilename "appendonly.aof" # redis通过fsync()调用告诉操作系统实际在磁盘上写入数据 # aof文件落盘的策略 # appendfsync always 每次发生数据变更,立刻记录到磁盘,但是导致redis吞吐量降低 # appendfsync everysec 可能会丢失1秒的数据 # appendfsync no appendfsync everysec # 当时用bfwriteaof时,fork一个子进程写aof文件,就算aof文件很大,也不会阻塞主进程 # 意外情况:但是当主进程、子进程同时写aof文件时,可能会出现由于子进程大量的IO操作阻塞主进程 # 当出现这种意外情况时:设置这个参数为no,可以保证数据不会丢失,但是得容忍主进程被阻塞 # 当出现这种意外情况时:设置这个参数为yes,主进程不会被阻塞主,但是不保证数据安全性 # 综上:如果应用无法忍受延迟:设置为yes。无法忍受数据丢失:设置为no no-appendfsync-on-rewrite no # 在当前aof文件的体积超过上次aof文件的体积的100%时,写新文件 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 最开始的aof文件体积至少达到60M时才重写 # 回放aof文件时,如果最后一条命令存在问题,是否允许忽略 aof-load-truncated yes # 是否允许AOF和RDB这两种持久化方式并存 aof-use-rdb-preamble yes
当aof文件出错怎么办?
redis为我们提供了修复aof文件的工具
[root@instance-lynj0v9k-19 bin]# redis-check-aof --fix appendonly.aof
aof模式的优缺点 优点:
- aof是用追加的形式写,没有随机磁盘IO那样的寻址开销,性能还是比较高的。
- aof可以更好的保护数据不丢失或者尽可能的少丢失:设置让redis每秒同步一次数据,即使redis宕机了,最多也就丢失1秒的数据。
- 即使aof真的体积很大,也可以设置后台重写,不影响客户端的重写。
- aof适合做灾难性的误删除紧急恢复:比如不小心执行了flushall,然后可以在发生rewrite之前 快速备份下aof文件,去掉末尾的 flushall,通过恢复机制恢复数据
缺点:使用aof一直追加写,导致aof的体积远大于RDB文件的体积,恢复数据、修复的速度要比rdb慢很多。
aof的重写
AOF采取的是文件追加的方式,文件的体积越来越大,为了优化这种现象,增加了重写机制,当aof文件的体积到达我们在上面的配置文件上的阕值时,就会触发重写策略,只保留和数据恢复相关的命令
手动触发重写
# redis会fork出一条新的进程 # 同样是先复制到一份新的临时文件,最后再rename,遍历每一条语句,记录下有set的语句 bgrewriteaof
8.4、RDB和AOF的选择#
- 如果我们的redis只是简单的作为缓存,那两者都不要也没事
- 如果数据需要持久化,那不要仅仅使用RDB,因为一旦发生故障,你会丢失很多数据
- 同时开启两者: 在这种情况下,redis优先加载的是aof,因为它的数据很可能比rdb更全,但是并不建议只是用aof,因为aof不是那么的安全,很可能存在潜在的bug
推荐:
- 建议在从机slave上只备份rdb文件,而且只要15分钟备份一次就够了。
- 如果启动了aof,我们尽量减少rewrite的频率,基础大小设置为5G完全可以,起步也要3G。
- 如果我们不选择aof, 而是选择了主从复制的架构实现高可用同样可以,能省掉一大笔IO操作,但是意外发生的话,会丢失十几分钟的数据。
九、发布订阅#
Redis的发布订阅模型是一种:消息通信方式,发布者发送到redis到队列中,消息的订阅者可以接收到消息,Redis的客户端可以订阅任意数量的消息
应用场景:关注订阅、消息推送、实时广播、网络聊天室
有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端
测试发布、订阅