深度长文整理-Redis进阶(二)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: 深度长文整理-Redis进阶(二)

七、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过程中,直接失败了,文件都没生成,不光是增量数据,原来的数据都丢了。


参考:linux的copy on write

欢迎关注大佬:三国梦回


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种情况

  1. 手动执行save命令、bgsave
  2. 满足配置文件中配置的save相关配置项时,自动触发
  3. 手动执行flushall
  4. 关闭redisshutdown


如何让redis加载rdb文件?


只需要将rdb文件放在redis的启动目录下,redis其中时会自动加载它

RDB模式的优缺点:

优点:RDB过程中,由子进程代替主进程进行备份的IO操作。保证了主进程仍然提供高性能的服务。适合大规模的数据备份恢复过程。


缺点:

  1. 默认情况下,它是每隔一段时间进行一次数据备份,所以一旦出现最后一次持久化的数据丢失,将丢失大规模的数据。
  2. 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模式的优缺点 优点:

  1. aof是用追加的形式写,没有随机磁盘IO那样的寻址开销,性能还是比较高的。
  2. aof可以更好的保护数据不丢失或者尽可能的少丢失:设置让redis每秒同步一次数据,即使redis宕机了,最多也就丢失1秒的数据。
  3. 即使aof真的体积很大,也可以设置后台重写,不影响客户端的重写。
  4. 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 时, 这个消息就会被发送给订阅它的三个客户端



测试发布、订阅



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
7月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
7月前
|
NoSQL Java Redis
Redis进阶-lua脚本
Redis进阶-lua脚本
117 0
|
7月前
|
存储 NoSQL Java
Redis进阶-细说分布式锁
Redis进阶-细说分布式锁
80 0
|
7月前
|
NoSQL Redis
Redis进阶-bind参数详解
Redis进阶-bind参数详解
421 0
|
7月前
|
NoSQL Java Redis
Redis进阶-Jedis以及Spring Boot操作 Redis 5.x Cluster
Redis进阶-Jedis以及Spring Boot操作 Redis 5.x Cluster
112 0
|
7月前
|
NoSQL 算法 Redis
Redis进阶-Redis对于过期键的三种清除策略
Redis进阶-Redis对于过期键的三种清除策略
104 0
|
6月前
|
NoSQL 数据可视化 Java
rodert单排学习redis进阶【白银一】
rodert单排学习redis进阶【白银一】
30 0
|
6月前
|
NoSQL Redis 数据库
rodert单排学习redis进阶【青铜】2
rodert单排学习redis进阶【青铜】
35 0
|
6月前
|
缓存 NoSQL Java
rodert单排学习redis进阶【青铜】1
rodert单排学习redis进阶【青铜】
43 0
|
6月前
|
NoSQL 关系型数据库 MySQL
Redis进阶-select 1. /xxx 切换数据库DBSIZE- 获取当前数据库中的key的个数flushdb-删除当前数据的所有keyflushall-删除所有表的所有库Re
Redis进阶-select 1. /xxx 切换数据库DBSIZE- 获取当前数据库中的key的个数flushdb-删除当前数据的所有keyflushall-删除所有表的所有库Re