ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
5种数据结构组成了Redis的基础,其他没有关联特定数据结构的命令也有很多。我们已经看过一些这样的命令:`info`,`select`, `flushdb`, `multi`, `exec`, `discard`, `watch`和`keys`。这一章将看看其他的一些重要命令。 ## 使用期限(Expiration) Redis允许你标记一个关键字的使用期限。你可以给予一个Unix时间戳形式(自1970年1月1日起)的绝对时间,或者一个基于秒的存活时间。这是一个基于关键字的命令,因此其不在乎关键字表示的是哪种类型的数据结构。 ~~~ expire pages:about 30 expireat pages:about 1356933600 ~~~ 第一个命令将会在30秒后删除掉关键字(包括其关联的值)。第二个命令则会在2012年12月31日上午12点删除掉关键字。 这让Redis能成为一个理想的缓冲引擎。通过`ttl`命令,你可以知道一个关键字还能够存活多久。而通过`persist`命令,你可以把一个关键字的使用期限删除掉。 ~~~ ttl pages:about persist pages:about ~~~ 最后,有个特殊的字符串命令,`setex`命令让你可以在一个单独的原子命令里设置一个字符串值,同时里指定一个生存期(这比任何事情都要方便)。 ~~~ setex pages:about 30 '<h1>about us</h1>....' ~~~ ## 发布和订阅(Publication and Subscriptions) Redis的列表数据结构有`blpop`和`brpop`命令,能从列表里返回且删除第一个(或最后一个)元素,或者被堵塞,直到有一个元素可供操作。这可以用来实现一个简单的队列。 (译注:对于`blpop`和`brpop`命令,如果列表里没有关键字可供操作,连接将被堵塞,直到有另外的Redis客户端使用`lpush`或`rpush`命令推入关键字为止。) 此外,Redis对于消息发布和频道订阅有着一流的支持。你可以打开第二个`redis-cli`窗口,去尝试一下这些功能。在第一个窗口里订阅一个频道(我们会称它为`warnings`): ~~~ subscribe warnings ~~~ 其将会答复你订阅的信息。现在,在另一个窗口,发布一条消息到`warnings`频道: ~~~ publish warnings "it's over 9000!" ~~~ 如果你回到第一个窗口,你应该已经接收到`warnings`频道发来的消息。 你可以订阅多个频道(`subscribe channel1 channel2 ...`),订阅一组基于模式的频道(`psubscribe warnings:*`),以及使用`unsubscribe`和`punsubscribe`命令停止监听一个或多个频道,或一个频道模式。 最后,可以注意到`publish`命令的返回值是1,这指出了接收到消息的客户端数量。 ## 监控和延迟日志(Monitor and Slow Log) `monitor`命令可以让你查看Redis正在做什么。这是一个优秀的调试工具,能让你了解你的程序如何与Redis进行交互。在两个`redis-cli`窗口中选一个(如果其中一个还处于订阅状态,你可以使用`unsubscribe`命令退订,或者直接关掉窗口再重新打开一个新窗口)键入`monitor`命令。在另一个窗口,执行任何其他类型的命令(例如`get`或`set`命令)。在第一个窗口里,你应该可以看到这些命令,包括他们的参数。 在实际生产环境里,你应该谨慎运行`monitor`命令,这真的仅仅就是一个很有用的调试和开发工具。除此之外,没有更多要说的了。 随同`monitor`命令一起,Redis拥有一个`slowlog`命令,这是一个优秀的性能剖析工具。其会记录执行时间超过一定数量微秒的命令。在下一章节,我们会简略地涉及如何配置Redis,现在你可以按下面的输入配置Redis去记录所有的命令: ~~~ config set slowlog-log-slower-than 0 ~~~ 然后,执行一些命令。最后,你可以检索到所有日志,或者检索最近的那些日志: ~~~ slowlog get slowlog get 10 ~~~ 通过键入`slowlog len`,你可以获取延迟日志里的日志数量。 对于每个被你键入的命令,你应该查看4个参数: * 一个自动递增的id * 一个Unix时间戳,表示命令开始运行的时间 * 一个微妙级的时间,显示命令运行的总时间 * 该命令以及所带参数 延迟日志保存在存储器中,因此在生产环境中运行(即使有一个低阀值)也应该不是一个问题。默认情况下,它将会追踪最近的1024个日志。 ## 排序(Sort) `sort`命令是Redis最强大的命令之一。它让你可以在一个列表、集合或者分类集合里对值进行排序(分类集合是通过标记来进行排序,而不是集合里的成员)。下面是一个`sort`命令的简单用例: ~~~ rpush users:leto:guesses 5 9 10 2 4 10 19 2 sort users:leto:guesses ~~~ 这将返回进行升序排序后的值。这里有一个更高级的例子: ~~~ sadd friends:ghanima leto paul chani jessica alia duncan sort friends:ghanima limit 0 3 desc alpha ~~~ 上面的命令向我们展示了,如何对已排序的记录进行分页(通过`limit`),如何返回降序排序的结果(通过`desc`),以及如何用字典序排序代替数值序排序(通过`alpha`)。 `sort`命令的真正力量是其基于引用对象来进行排序的能力。早先的时候,我们说明了列表、集合和分类集合很常被用于引用其他的Redis对象,`sort`命令能够解引用这些关系,而且通过潜在值来进行排序。例如,假设我们有一个Bug追踪器能让用户看到各类已存在问题。我们可能使用一个集合数据结构去追踪正在被监视的问题: ~~~ sadd watch:leto 12339 1382 338 9338 ~~~ 你可能会有强烈的感觉,想要通过id来排序这些问题(默认的排序就是这样的),但是,我们更可能是通过问题的严重性来对这些问题进行排序。为此,我们要告诉Redis将使用什么模式来进行排序。首先,为了可以看到一个有意义的结果,让我们添加多一点数据: ~~~ set severity:12339 3 set severity:1382 2 set severity:338 5 set severity:9338 4 ~~~ 要通过问题的严重性来降序排序这些Bug,你可以这样做: ~~~ sort watch:leto by severity:* desc ~~~ Redis将会用存储在列表(集合或分类集合)中的值去替代模式中的`*`(通过`by`)。这会创建出关键字名字,Redis将通过查询其实际值来排序。 在Redis里,虽然你可以有成千上万个关键字,类似上面展示的关系还是会引起一些混乱。幸好,`sort`命令也可以工作在散列数据结构及其相关域里。相对于拥有大量的高层次关键字,你可以利用散列: ~~~ hset bug:12339 severity 3 hset bug:12339 priority 1 hset bug:12339 details "{id: 12339, ....}" hset bug:1382 severity 2 hset bug:1382 priority 2 hset bug:1382 details "{id: 1382, ....}" hset bug:338 severity 5 hset bug:338 priority 3 hset bug:338 details "{id: 338, ....}" hset bug:9338 severity 4 hset bug:9338 priority 2 hset bug:9338 details "{id: 9338, ....}" ~~~ 所有的事情不仅变得更为容易管理,而且我们能通过`severity`或`priority`来进行排序,还可以告诉`sort`命令具体要检索出哪一个域的数据: ~~~ sort watch:leto by bug:*->priority get bug:*->details ~~~ 相同的值替代出现了,但Redis还能识别`->`符号,用它来查看散列中指定的域。里面还包括了`get`参数,这里也会进行值替代和域查看,从而检索出Bug的细节(details域的数据)。 对于太大的集合,`sort`命令的执行可能会变得很慢。好消息是,`sort`命令的输出可以被存储起来: ~~~ sort watch:leto by bug:*->priority get bug:*->details store watch_by_priority:leto ~~~ 使用我们已经看过的`expiration`命令,再结合`sort`命令的`store`能力,这是一个美妙的组合。 ## 小结 这一章主要关注那些非特定数据结构关联的命令。和其他事情一样,它们的使用依情况而定。构建一个程序或特性时,可能不会用到使用期限、发布和订阅或者排序等功能。但知道这些功能的存在是很好的。而且,我们也只接触到了一些命令。还有更多的命令,当你消化理解完这本书后,非常值得去浏览一下[完整的命令列表](http://redis.io/commands)。