这篇文章主要讲解了“Redis中的Redis Streams有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis中的Redis Streams有什么作用”吧!
如果你想记录一系列的结构化数据,并且确定数据库是足够大的,你可能会说:我们以追加写入的方式打开一个文件,每一行记录是一个CSV数据项:
time=1553096724033,cpu_temp=23.4,load=2.3
time=1553096725029,cpu_temp=23.2,load=2.1
这看起来很简单,然后人们一直这样做了好多年,并且一直持续着:如果你知道你在做什么,那么这将成为一种固定的模式。如果同样的事情发生在内存中会怎样呢?内存的顺序写入能力更强,并且会自动移除掉CSV文件的一些限制:
很难批量查询
太多的冗余信息:每个条目的时间几乎相同,字段也相同。但是移除字段会降低灵活性,就不能再增加别的字段了
每个条目的偏移量都是它在文件中的字节偏移量,而如果我们修改了文件结构,那么这些偏移量就会失效。所以这里缺少一个唯一标识的ID。
不能删除条目,只能标记无效。如果不重写日志的话,又没有垃圾回收,重写日志经常会因为各种原因出错,所以最好不要重写。
不过使用这样的CSV条目也有一些好处:没有固定格式,字段可以改变,生成比较容易,而且存储格式比较紧凑。我们保留了其优点,去掉了限制,于是设计出了像Redis Sorted Set这样的混合数据结构——Redis Streams。他们看起来像基本数据结构一样,但是为了得到这样的效果,内部是有多种表现形式的。
Redis Streams是一种通过基数树连接的增量压缩的宏节点。(好难理解的概念,把原话贴出来:Redis Streams are represented as delta-compressed macro nodes that are linked together by a radix tree)。它的作用是,快速查找一个随机项,获取范围值,删除旧值来创建一个有大小上限的流。对程序员来说,我们的接口和CSV文件很相似:
1> XADD mystream * cpu-temp 23.4 load 2.3
2"1553097561402-0"
3> XADD mystream * cpu-temp 23.2 load 2.1
4"1553097568315-0"
通过这个例子可以看到,XADD命令自动生成并返回了一个entry ID。它是单调递增的,并且有两部分组成,<时间>-<数量>,时间是毫秒级,而数量则是同一毫秒生成的entry数量递增。
所以第一个从上面所说的"追加写入CSV"文件抽象出来概念就是,如果用星号作为XADD命令的ID参数,就从服务器获取了一个entry ID。这个ID不仅仅是entry的唯一标识,也和entry加入流的时间有关。XRANGE命令可以批量获取或获取单个数据项。
1> XRANGE mystream 1553097561402-0 1553097561402-0
21) 1) "1553097561402-0"
3 2) 1) "cpu-temp"
4 2) "23.4"
5 3) "load"
6 4) "2.3"
在这个例子中,为了得到单个数据项,我用了相同的ID作为起始和结束值。然而我可以获取任意范围的数据项,并且用COUNT参数限制结果的数量。我也可以将起止参数都设置为时间戳,获取一段时间内的数据项。
1> XRANGE mystream 1553097560000 1553097570000
21) 1) "1553097561402-0"
3 2) 1) "cpu-temp"
4 2) "23.4"
5 3) "load"
6 4) "2.3"
72) 1) "1553097568315-0"
8 2) 1) "cpu-temp"
9 2) "23.2"
10 3) "load"
11 4) "2.1"
篇幅原因,我们不再展示更多的Streams API了。我们有相关的文档,感兴趣的同学可以去阅读。目前为止,我们只需要关注基本使用方法:XADD用来增加数据,XRANGE(或XREAD)用来读取数据。我们来看一下我为什么说Streams是一个强大的数据结构。
前几天我和一个最近在学习Redis的朋友一起建模一个应用程序:这是一个用来追踪当地网球场、球员和比赛的app。很明显,球员是一个小的模型,在Redis中只需要用一个hash就足够了,key的形式可以是player:<id\>。当你进一步使用Redis建模时,就会意识到你需要去追踪指定网球俱乐部的一场比赛。如果球员1和球员2打了一场比赛,球员1获胜。那么我们可以这样来记录:
1> XADD club:1234.matches * player-a 1 player-b 2 winner 1
2"1553254144387-0"
通过这样简单的操作,我们就可以获得如下的信息:
一场比赛的唯一标识:流里的ID
不需要创建一个表示比赛的对象
分页查询比赛情况,或者查看某场比赛是否在指定时间就进行
在Streams出现之前,我们需要创建一个Sorted Set,分数是时间。Sorted Set的元素是比赛的ID(存在一个Hash里)。这不仅是增加了工作量,而且还造成了更多的内存浪费,比你想象的要多得多。
现在看起来Streams像是一个追加模式的,以时间为分数,元素是小型Hash的Sorted Set。简而言之,这是Rediscover建模环境中的一次革命。
上面的例子不仅仅是固化模式的问题,相比旧有的Sorted Set+ Hash的模式,Streams对内存的节省做了很好的优化,然而这一点是不容易被发现的。
假设我们要记录100万场比赛,
Sorted Set + Hash的内存使用量是220MB(242RSS)
Stream的内存使用量是16.8MB(18.11RSS)
这不仅仅是一个数量级的差异(实际上是13倍的差异),这意味着我们旧有的模式实在是太浪费了,而新的模式是完美可行的。Redis Streams还有其他神奇的地方:宏节点可以包括多个元素,它们使用叫做listpack的数据进行编码。listpacks会对二进制形式的整数进行编码,即时它是语义字符串。最重要的是,我们使用了增量压缩和相同字段压缩。我们可以通过ID或时间进行查询,因为宏节点是用基数树连接的。基数树叶被设计为使用很少的内存。所有的事情都使用极少的内存,但有趣的是,用户并不能从语义上看到使Streams更加高效的实现细节。
现在我们来做一个简单的计算,如果我保存了100万个entry,使用了18MB内存,那么1000万个就是180MB,1亿个使用1.8GB,保存10亿数据也只使用18GB内存。
有一个比较重要的事情需要注意,在我看来,上面我们用来记录网球比赛的例子与把Redis Streams作为一个时间序列来使用非常不同。没错,逻辑上我们仍然是记录一类事件,但本质上的区别是记录日志和创建一个entry并存入对象的不同。在使用时间序列时,我们只是记录一个外部事件,而不需要真的展示一个对象。你可能认为这个区别不重要,但事实不是这样。对Redis用户来说很重要的是,如果需要保存一系列有序的对象,并且给每个对象赋一个ID,那么就需要使用Redis Streams。
然而即时是一个简单的时间序列,也是一个很大的用例,因为在Streams出现之前,Redis在面对这种用例时令人有些绝望。一个节省内存,并且灵活的流,对开发者来说是一个重要的工具。
感谢各位的阅读,以上就是“Redis中的Redis Streams有什么作用”的内容了,经过本文的学习后,相信大家对Redis中的Redis Streams有什么作用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。