1. 概述
据云头条报道,某公司技术部发生 2 起本年度 PO 级特大事故,造成公司资金损失 400 万,原因如下: 由于 PHP 工程师直接操作上线 redis,执行 keys wxdb(此处省略)cf8 这样的命令,导致redis锁住,导致 CPU 飙升,引起所有支付链路卡住,等十几秒结束后,所有的请求流量全部挤压到了 rds 数据库中,使数据库产生了雪崩效应,发生了数据库宕机事件 该公司表示,如再犯类似事故,将直接开除,并表示之后会逐步收回运维部各项权限
看了上面的新闻,不禁感到一惊,线上 redis 竟然因为一条指令锁住全库,这究竟是什么原因,又该如何避免呢? 本篇日志就来详细说明。
2. redis 危险指令
2.1. keys
keys 指令可以查询出所有存在的键,keys 相关命令可以进行模糊匹配,是非常方便和强大的工具。 但由于 redis 是单进程模型,如果数据量巨大,keys 命令的查询效率就显得太低了,从而会导致 Redis 锁住、CPU 飙升,这也就是上面新闻中问题的发生原因。 因此,线上 Redis 集群禁用 keys 命令是必须的。
2.2. flushdb
这个命令是用来删除 Redis 中当前所在数据库中的所有记录的。 并且此命令从不会执行失败。
2.3. flushall
这个命令是用来删除 Redis 中所有数据库中的所有记录,不只是当前所在数据库。 和 flushdb 一样,这个命令也是不会执行失败的。
2.4. config
config 命令让客户端可以修改 redis 配置,可想而知,这是非常危险的。
3. 禁用危险指令
redis 并没有提供禁用任何指令的配置或方法,但是 redis 允许我们在配置文件中将任何指令重命名为其他名字,通过这个手段,我们就可以实现禁用指令的效果了。
代码语言:javascript复制################################## SECURITY ###################################
# Require clients to issue AUTH <PASSWORD> before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
# requirepass foobared
# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to slaves may cause problems.
redis.conf 的 SECURITY 中有上述说明,我们看到了 rename-command 的用法:
代码语言:javascript复制rename-command KEYS ""
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
这样我们就可以实现命令的禁用了。 当然我们也可以通过配置这些危险指令为其他指令,让运维人员在关键时刻仍然可以使用这些命令:
代码语言:javascript复制rename-command FLUSHALL a31907b21c437f46808ea49322c91d23a
rename-command FLUSHDB qf69aZbLAX3cf3ednHM3SOlbpH71yEXLA
rename-command CONFIG FRaqbC8wSA1XvpFVjCRGryWtIIZS2TRvp
rename-command KEYS eIiGXix4A2DreBBsQwY6YHkidcDjoYA2D
再次执行上述命令就会出现:
4. Unknown command ’flushall’ reading the append only file
如上配置后,启动 redis 可能会报出这个错误。 这是因为 AOF 持久化方式需要使用 flushall 命令,安全起见,只能在配置文件中关闭 AOF 了:
代码语言:javascript复制appendonly no
5. 参考资料
https://gist.github.com/DDmitrid/0bf3ebcc41d1a5d23cf8727d5ff52f28。