您的科学家非常关注是否可以这样做,他们没有停止思考是否应该这样做。
————Dr。伊恩·马尔科姆(Ian Malcolm),在侏罗纪公园
“最佳实践”已成为技术的一种说法。当然,您可以使用给定的工具执行某些操作,但这真的是个好主意吗?这个话题一次又一次出现的事实说明了我们工具的灵活性。最佳实践非常适合初学者从一开始就学习正确的东西。问题是,有时候,作为软件工程师,我们对这些最佳实践的记忆不完善。其他时候,我们通过不阅读手册,只是将方形钉锤入圆孔来实现我们需要做的事情,而没有意识到我们在硬模式下无意中玩了游戏。
因此,让我们采用另一种方法:让我们看看最坏的做法,而不是查看最佳做法。我们已经看到客户,开放源代码的用户,甚至工具实施的模式也会大打出手,令人头晕。当然,我们以前没有集中这种智慧,所以让我们从七种Redis“最差实践”开始。

1.无密码
基于我在网上看到的大量代码示例(实际上,甚至可能是几年前的一些示例),很多人都不会为自己的Redis实例设置密码。为了使这在当前版本的Redis中成为真正最糟糕的做法,您必须在redis.conf中努力尝试,以向整个Internet开放一个无密码的Redis实例。但是,较旧的版本确实允许这种做法。为什么放弃密码是个坏主意?没有密码,将找到您的服务器。一旦找到它,就会发生各种各样的恶作剧,从刷新数据库到通过运行高复杂度命令停止Redis,一直到更改文件(通过CONFIG SET / GET)。
TL; DR:您将是h4x0r3d,没有密码。
最佳做法:设置密码并使用AUTH。
2.按键
奇怪的是,KEYS是人们在Redis中学习的第一个命令之一,即使使用起来很糟糕(在生产中)。对于那些谁是开明的,足以不知道KEYS,它在给定的数据库中的所有密钥(或模式)的完整的迭代。当然,这可能很有用,尤其是对于调试而言,如果键的数量很少,那么就没什么大不了的。但是,随着扩展,KEYS成为隐藏的杀手er。考虑以下四个事实:
Redis是(出于实用目的)单线程
Redis可以容纳2 个32键
键(非值)最大为512MB
KEYS是O(n)操作。
因此,当您有数十个键时,编写依赖于KEYS的应用程序就可以了-但是随着越来越多的键,此操作花费的时间越来越长。在这段时间里,Redis只会进行数据库中的所有键操作。想象一下必须做4,294,967,295件事,您会理解为什么它不会很快。最后,KEYS是一个同步命令,因此建立所有这些键的响应(尤其是如果它们是大键)将需要一段时间,更不用说通过电线发送它所花费的时间了。
TL; DR:Redis变得比您预期的更大,并且KEYS可能长时间阻塞您的Redis服务器。
最佳实践的替代方案:使用SCAN,它将迭代分散到许多调用中,而不是一次占用整个服务器。
3.编号数据库/ SELECT
Redis的作者Salvatore Sanfilippo曾经将编号数据库称为他在Redis中犯下的最严重的设计错误。这种设计选择是在构建看起来像做某件事但实际上又做另一件事的警告故事。值得庆幸的是,尽管这种情况在野外变得不那么普遍了,但Redis仍具有使用SELECT命令在不同“数据库”之间切换的功能。每个数据库都是从关键角度隔离的。因此,数据库0上的键foo:bar 可以与foo:bar 完全不同在数据库9中。这听起来不错,对吗?问题在于这些数据库没有以任何其他方式隔离。在数据库0上运行KEYS仍将冻结数据库9。实际上,您似乎可以在每个数据库上运行独立的工作负载,但实际上它们根本不是独立的。
简直是无礼,但不是最糟糕的做法,对吗?嗯,问题在于整个生态系统中都没有很好地支持编号数据库。编号数据库棺材的第一个,也是最可怕的缺点是,任何集群系统(开源或Redis Enterprise集群)都不支持它们。实际上,您将永远无法离开Redis的单个节点。另外,某些模块不支持编号数据库。
TL; DR:编号的数据库不执行您认为的操作,然后使您陷入扩展的困境。
最佳实践替代方法:运行隔离的Redis实例-它的开销很低,为什么不呢?如果您正在运行Redis Enterprise,则默认情况下数据库是隔离的/多租户的。
4. HGETALL,LRANGE,SMEMBERS和ZRANGE的无限回报
这些命令归为一个有趣的类:在大多数情况下有用且良性,但在其他时候却被诅咒。Redis中的哈希数据结构允许您在一个键下设置一系列字段/值对**-HGETALL**是一个简单的命令,可让您一次检索哈希中的所有内容。很好,因为在大多数情况下,您最多要处理三位数的字段。像键一样,每个哈希可以有2 32个字段和值。在大多数情况下,您不会在这么多地方遥不可及,但是在某些情况下,根据代码的性质(或逻辑错误),您可以积累大量字段和值,从而随着时间的推移增加字段的数量。然后,您运行HGETALL并接收成千上万个字段和值,每个字段和值可能高达512MB,这意味着您实际上遇到了与KEYS相同的问题。
LRANGE的情况可能更糟。LRANGE从给定范围内的列表中获取项目;得到所有物品范围0 -1会成功的 Redis中的列表是有效链接的列表,这意味着必须依次访问每个元素(以获取指向下一个元素的指针)。到现在为止,您可能已经猜到了2 32个元素(每个元素最多512MB)是最大的,并且您可以累积非常多的元素。如果您将“列表”用作队列,则使工作人员离线几分钟会导致列表大小快速增长。
故事与“排序集”和“集”大致相同。它们可以存储大量数据,每个数据量可能非常大。当您请求所有这些请求时,这可能会花费一些时间。
TL; DR:Redis可以存储非常大的数据结构。除非您知道结果数,否则预期结果数将为2的32次方。
最佳实践备选方案:执行命令的指令该完整性检查的数据结构的大小(HLEN为散列,LLEN为列表,SCARD为集和ZCARD为有序集合)。
5.每个连接一个请求
许多数据库使用REST的概念作为主要接口,将纯旧的HTTP请求发送到带有编码为POST的参数的端点。数据库获取信息,并以状态码作为响应将其返回,并关闭连接。Redis应该以不同的方式使用-连接应该是持久的,并且您应该根据需要向长期连接提出请求。但是,好心的开发人员有时会创建连接,运行命令并关闭连接。虽然每个命令打开和关闭连接在技术上是可行的,但这远非最佳,而且不必要地降低了Redis的整体性能。
使用OSS Cluster API时,客户端将根据需要维护与节点的连接,因此您可以在任何给定时间向不同节点打开多个连接。使用Redis Enterprise,连接实际上是到代理的,它可以解决群集级别连接的复杂性。
TL; DR:Redis连接旨在使无数操作保持打开状态。
最佳实践替代方案:通过多个命令保持连接打开。
6.热键
Redis可以轻松保存您的应用程序运营数据的核心信息,其中包含有价值且经常访问的信息。但是,如果将访问集中到不断访问的几条数据中,则会创建所谓的热键问题。在Redis集群中,关键实际上是确定数据在集群中存储位置的因素。数据基于散列密钥而存储在一个单一的主要位置中。因此,当您一次又一次地访问单个键时,实际上是一次又一次地访问单个节点/分片。让我们换一种说法:如果您有一个99个节点的集群,并且您的单个密钥在一秒钟内可以收到一百万个请求,那么所有这些请求将全部发送到一个节点,而不会分散到其他98个节点上。
Redis甚至提供工具来查找您的热键所在的位置。将redis-cli与–热键 参数以及您需要连接的任何其他参数:
$ redis-cli --hotkeys
TL; DR:不要创建少量频繁访问的密钥。
最佳实践替代方案:尽可能的,最好的防御是避免造成局势的发展模式。将数据写入驻留在不同分片中的多个键将使您可以更频繁地访问相同的数据。
7.将临时Redis作为主数据库运行
Redis通常用作应用程序的主要存储引擎。与将Redis用作缓存不同,将Redis用作主数据库需要两个额外的功能才能有效。任何主数据库都应该真正具有高可用性。如果缓存出现故障,则通常您的应用程序处于掉电状态。如果主数据库出现故障,您的应用程序也会发生故障。同样,如果缓存出现故障,然后您将其重新启动为空,那也没什么大不了的。但是,对于主数据库而言,这是一笔不小的数目。Redis可以轻松处理这些情况,但是与作为缓存运行相比,它们通常需要不同的配置。
TL; DR:Redis作为主数据库很棒,但是您必须通过启用正确的功能来支持它。
最佳实践替代方案:使用Redis开源,您需要设置Redis Sentinel以实现高可用性。在Redis Enterprise中,它是您创建数据库时只需打开的一项核心功能。至于持久性,Redis Enterprise和开源Redis都通过AOF或快照提供持久性,因此您的实例以您离开它们的方式开始备份。
以上是Redis的七个最糟糕的做法。关注“墨天轮”网站,发现更多Redis精彩文章。
原文链接: https://redislabs.com/blog/7-redis-worst-practices/




