在写入Redis (SET foo bar)期间,我得到以下错误:

MISCONF Redis被配置为保存RDB快照,但当前为 无法在磁盘上持久保存。可能修改数据集的命令是 禁用。有关错误的详细信息,请查看Redis日志。

基本上我理解的问题是,redis是不能在磁盘上保存数据,但不知道如何摆脱这个问题。

下面的问题也有同样的问题,它在很久以前就被抛弃了,没有答案,很可能没有尝试解决这个问题。


当前回答

在我的情况下,这只是特权,我需要允许Redis接受传入的请求。

所以我重启了Redis服务通过Homebrew brew服务停止Redis和brew服务启动Redis和运行Redis服务器本地Redis -server。命令提示符要求我允许传入请求,然后它开始工作。

其他回答

在我的例子中,它与磁盘空闲空间有关。(你可以用df -h bash命令检查它)当我释放一些空间时,这个错误消失了。

我在使用AFS磁盘空间的服务器上工作时遇到了这个问题,因为我的身份验证令牌已经过期,当redis-server试图保存时产生了Permission Denied响应。我通过刷新我的令牌来解决这个问题:

kinit USERNAME_HERE -l 30d && aklog

此错误是由于BGSAVE失败导致的。在BGSAVE期间,Redis会fork一个子进程来将数据保存到磁盘上。虽然BGSAVE失败的确切原因可以从日志中检查(通常在linux机器上的/var/log/redis/redis-server.log),但很多时候bgive失败是因为fork不能分配内存。很多时候,由于操作系统的优化冲突,fork无法分配内存(尽管机器有足够的可用RAM)。

可以从Redis常见问题中阅读:

Redis background saving schema relies on the copy-on-write semantic of fork in modern operating systems: Redis forks (creates a child process) that is an exact copy of the parent. The child process dumps the DB on disk and finally exits. In theory the child should use as much memory as the parent being a copy, but actually thanks to the copy-on-write semantic implemented by most modern operating systems the parent and child process will share the common memory pages. A page will be duplicated only when it changes in the child or in the parent. Since in theory all the pages may change while the child process is saving, Linux can't tell in advance how much memory the child will take, so if the overcommit_memory setting is set to zero fork will fail unless there is as much free RAM as required to really duplicate all the parent memory pages, with the result that if you have a Redis dataset of 3 GB and just 2 GB of free memory it will fail. Setting overcommit_memory to 1 says Linux to relax and perform the fork in a more optimistic allocation fashion, and this is indeed what you want for Redis.

Redis不需要像操作系统认为的那样多的内存来写入磁盘,所以可能会预先导致fork失败。

要解决这个问题,您可以:

修改/etc/sysctl.conf,增加:

vm.overcommit_memory=1

然后重新启动sysctl:

在FreeBSD上:

sudo /etc/rc.d/sysctl reload

在Linux上:

sudo sysctl -p /etc/sysctl.conf

如果你正在使用docker/docker-compose,并且想要阻止redis写入文件,你可以创建一个redis配置并挂载到容器中

docker.compose.override.yml

  redis:¬
      volumes:¬
        - ./redis.conf:/usr/local/etc/redis/redis.conf¬
      ports:¬
        - 6379:6379¬

您可以从这里下载默认配置

在redis.conf文件中,确保注释掉这3行

save 900 1
save 300 10
save 60 10000

您可以在这里查看更多删除持久数据的解决方案

现在,Redis的写访问问题在官方的Redis docker容器中重新出现,给客户端这个错误消息。

来自官方Redis映像的Redis试图将.rdb文件写入containers /data文件夹中,这是相当不幸的,因为它是一个根目录拥有的文件夹,而且它也是一个非持久化的位置(如果容器/pod崩溃,写入那里的数据将消失)。

所以在一个小时的不活动后,如果你以非根用户运行你的redis容器(例如docker run -u 1007而不是默认的docker run -u 0),你会在你的服务器日志中得到一个非常详细的错误信息(参见docker logs redis):

1:M 29 Jun 2019 21:11:22.014 * 1 changes in 3600 seconds. Saving...
1:M 29 Jun 2019 21:11:22.015 * Background saving started by pid 499
499:C 29 Jun 2019 21:11:22.015 # Failed opening the RDB file dump.rdb (in server root dir /data) for saving: Permission denied
1:M 29 Jun 2019 21:11:22.115 # Background saving error

所以你需要做的是将容器的/data文件夹映射到一个外部位置(非根用户,这里:1007,有写权限,比如主机上的/tmp),例如:

docker run --rm -d --name redis -p 6379:6379 -u 1007 -v /tmp:/data redis

所以这是官方docker镜像的错误配置(应该写入/tmp而不是/data),产生了这个“定时炸弹”,你很可能只会在生产中遇到…在某个特别安静的假日周末过夜:/