有序集合 (zset) 中的时间序列是 Redis 中对时间序列数据进行建模的典型方式。有序集合由具有评分的唯一成员组成,所有成员都存储在一个键下。对有序集合使用此数据类型意味着让评分作为某种时间指示(通常是毫秒精度的时间戳,但不总是),并且成员是记录的数据。唯一的需要注意的是,由于这是集合的一种形式,因此仅允许唯一成员,并且尝试记录与先前成员具有相同值的时间序列项只会更新评分。为了说明此问题,请看以下随着时间推移记录温度的示例
时间戳 | 温度摄氏度 |
1511533205001 | 21 |
1511533206001 | 22 |
1511533207001 | 21 |
如果您仅使用ZADD将此内容直接作为有序集添加,您将错过一些数据点
反模式
> ZADD temperature 1511533205001 21 (integer) 1 > ZADD temperature 1511533206001 22 (integer) 1 > ZADD temperature 1511533207001 21 (integer) 0 >
temperature -inf +inf WITHSCORES 1) "22" 2) "1511533206001" 3) "21" 4) "1511533207001"
反模式
请注意第三个 ZADD 如何返回 0 – 这表示未将新成员添加到有序集中。然后,在 ZRANGEBYSCORE 中,我们可以看到该有序集仅有两个条目 (…7001 和 …6001),而缺少 …5001。为什么?在这种情况下,因为 …7001 和 …5001 都具有相同的成员 (21),所以我们仅更新了该成员的分数。这不好!
有多种方法可以解决此问题。首先是要包含一些具有足够熵的随机数据来确保唯一性。我们来检查一下此方法。首先,我们将在 0(包含)和 1(不包含)之间创建一个伪随机浮点数,然后将其添加到我们的时间戳。对于我们的示例,我们以十进制形式保留它以便于阅读(在实际工作负载中,为了节省存储空间,您最好只需将其转换回 8 个原始字节)。
> ZADD temperature2 1511533205001 21:1511533205001.2583 (integer) 1 > ZADD temperature2 1511533206001 22:1511533206001.941678 (integer) 1 > ZADD temperature2 1511533207001 21:1511533207001.732015 (integer) 1 > ZRANGEBYSCORE temperature2 -inf +inf WITHSCORES 1) "21:1511533205001.2583" 2) "1511533205001" 3) "22:1511533206001.941678" 4) "1511533206001" 5) "21:1511533207001.732015" 6) "1511533207001"
正如您所见,所有 ZADD 都会返回表示新添加内容的 1,而 ZRANGEBYSCORE 会返回所有值。这是一个可行的办法,但是它效率不高,会浪费字节来确保唯一性,从而增加了存储开销。对于大多数用例,唯一性将由您的应用程序直接放弃。需要注意的是,如果您的数据已经唯一(例如,一些包含 UUID 的数据),那么显然不需要添加唯一性。
使用此方法,您可以访问所有有序集方法,以便进行分析和操作
‡ ZINTERSTORE 和 ZUNIONSTORE 是多键操作。在分片环境中工作时,应小心确保新键最终位于同一分片上,否则这些命令将以错误结束。