最近开始学习中间件,慢慢开始明白了这些中间件官网文档所蕴含的意义,它是对中间件本身一个相当准确的描述和介绍,是一个我们可以快速了解一个中间件并学习怎么使用的公共入口,同市面上各种书籍和教程相比,它对于我们开发人员来说更像是一个源码的存在,因此,学习官方文档是十分必要的。本篇文章是我自己在阅读Redis官网文档学习的过程中觉得比较有用的部分的记录,如果有翻译或表达不准确的地方欢迎指证。
Redis是一个开源的基于BSD协议开源的内存数据结构存储,被用于作为数据库,缓存和消息服务器。支持的数据类型有:String,List,Sets,Sorted sets(支持下标范围查询),hashes,bitmaps,hyperloglogs,geospatial(支持半径查询)和streams(流,具体实现就是redis作为消息服务器使用发布订阅模式)。
以上是我摘选官网的一部分翻译文本,后面还有一小部分关于高可用集群描述,本篇不关心那些所以也就没写。下面针对数据类型部分的文档做了摘要和翻译,如有不准确的地方欢迎指正。
Redis的key是二进制安全的,这意味着你可以使用任意的二进制序列作为key来存储数据,普通的字符串"foo",JPEG文件内容,甚至空字符串也可以作为key。
再来看几个有关于key的规则:
最简单的数据类型,它同时也是memcached中使用的数据类型。
使用场景:例如:缓存html文本
value的最大大小同样为512M
对于字符串比较有趣的操作是自增和自减,存储类型是字符串,但是我们可以通过incr和decr命令对一些数字字符串做计算。命令不做过多介绍,简单说下官方文档描述的原理:
命令会将字符串转换为数字,然后进行计算,之后再set给对应key的value
官方文档再讨论其他复杂数据类型之前,对Redis的缓存过期做了一下介绍:
你可以为一个key设置一个超时时间,这个时间就是key存活的时间。当时间耗尽,这个key会被自动销毁,就像执行了del命令。
超时时长的简要信息:
可以设置秒和毫秒
关于超时时长的信息是备份并存储在磁盘上的,当你的Redis服务器停掉,这个时间其实还是会耗尽的(这意味着Redis保存着value)。
这里有关超时的第三条规则我可以理解超时信息存储在磁盘上,但是Redis宕机(在已经做了持久化设置的情况下),之后超时的结果我不是太确定,需要具体操作来得到结果。
Redis的Lists数据结构是通过Linked list实现的,作为开发人员我想大家都明白,链表结构的集合添加元素是很快的,但是它的查询需要进行遍历比较慢。对于这个缺点官方文档是这么描述的:
它的缺点是什么呢?通过下表访问一个数组实现的集合是很快速的,但是链表实现的集合中需要做大量的下标比对工作。
Redis的lists通过实现链表来实现是基于数据库系统觉得快速的向非常长的列表中添加数据更为重要。
Redis列表允许两头添加元素(LPUSH,RPUSH),在获取元素时支持LPOP和RPOP他们的作用是获取两头的元素并将其从列表中移除。
使用案例:
上述第一种情况也可以通过Ltrim命令来实现,它会保留一定范围的元素,其他的全部舍弃,也就是保留我们最新的动态。
在实现上述的消费者生产者模式过程中,存在缺点,比如列表中没有元素,那么消费者就需要一直尝试去pop元素,它有以下几个缺点:
Redis为了解决这个问题实现了阻塞操作BRPOP等等,它会等待直到有新元素添加到列表中再返回。当然它也可以设置超时时间,设置为0则一直等待。这个命令可以指定多个列表,当指定多个列表时为了保证第一个列表新增元素马上得到通知需要注意以下几点:
列表的创建和空元素状态下销毁是由Redis来负责的,不需要我们自己去create和destroy;
key-value pairs,键值对;还是比较简单的,官方文档也没有做过多介绍,只是指出对于特别小的hash数据,Redis做了优化会占用更小的内存。
Redis sets是无序的字符串集合不允许重复元素存储,对于每一次查询sets会返回任意顺序结果。sets支持很多操作比如判断成员是否存在,查询交集和差集。
Sorted Sets类似一个hash和无序set的混合体。同set类似,sorted set由唯一,不重复的字符串元素组成,因此某种程度上说sorted set就是一个set。
不管怎么样set中的元素是无序的,sorted set中的每个元素都关联一个浮点数值,被称为score,这也就是说为什么sorted set跟hash类似。
他们的排序规则如下:
- 如果A和B带有不同的score,那么如果A.score>B.score则A>B
- 如果A和B带有相同的score,那么通过A和B的字典排序来决定他们的大小。
再来看官网关于有序set的实现的描述:
sorted set基于包含一个跳表和hash table实现的,因此每次我们添加一个元素它的时间复杂度是O(log(N)).当我们获取元素的时候我们不需要去做任何工作,他们已经是有序的了。
注意:LRANGE中的0和-1代表从0开始的所有元素
有序集合可以通过score的范围来获取指定范围内的数据,也可以通过下表来获取。
另外还可以通过集合元素的字典排序来获取元素,比如我们放入score完全相同的多个元素,可以通过元素的字典排序进行范围获取: ZRANGEBYLEX, ZREVRANGEBYLEX, ZREMRANGEBYLEX and ZLEXCOUNT
Bitmaps和Hyperloglogs这两种类型从官方文档的描述我不是太能了解他们的实现,后期再补充。
Stream自5.0版本开始引入,它用一种更加抽象的方式构建了log数据结构,log的本质是完整的,通常是追加模式,Redis Streams基本上也是一种追加数据结构。至少从概念上,因为streams作为一种内存中的抽象数据类型,它实现了更强大的操作,突破了log文件自身的局限性。
使得streams如此复杂的原因,即便数据结构本身很简单,其实是它实现了额外的非强制的特性:一个阻塞set允许一组消费者等待生产者添加新数据到stream,概念上被称为消费者组。、
消费者组由消息中间件kafka引入。Redis实现了一个类似但完全不同的概念,目标都是一样的,允许一组客户端协同消费相同stream不同区的消息。
官方文档建议的最好的理解stream的方法是通过命令实践操作,本篇不做过多介绍,只摘取文档中重点部分介绍。
Stream是一个追加型数据结构,基本的写命令是XADD,追加一个entry(实体)到指定的Stream中。entry不是一个简单的字符串,由一个或多个键值对组成,是结构化的。
XADD mystream * sensor-id 1234 temperature 19.8
由命令看mystream是指定的stream名称,* 其实是需要我们提供的一个entry id,一般不需要自己提供,Redis会根据* 做自增处理自动为我们生成id。
id的参数格式:-
XADD somestream 0-1 field value milliseconds Time是当前Redis节点的时间,sequenceNumber是单一毫秒内创建的entry数,64bit。
NOTE:我们可以指定明确的ID规则,也就是不适用默认的毫秒-序号,但是后增的id不能小于之前的id。
在官方文档中我没有找到有关这个数据结构的介绍,它是通过坐标来添加元素的,代表的是一个元素的位置。来看下官方文档的描述:
Adds the specified geospatial items (latitude, longitude, name) to the specified key. Data is stored into the key as a sorted set, in a way that makes it possible to later retrieve items using a query by radius with the GEORADIUS or GEORADIUSBYMEMBER commands.
添加指定的地理空间项(纬度,经度,名称)到指定的key。数据作为一个有序set存储到key中,这使得后续通过半径查询GEORADIUS变为可能。
The command takes arguments in the standard format x,y so the longitude must be specified before the latitude. There are limits to the coordinates that can be indexed: areas very near to the poles are not indexable. The exact limits, as specified by EPSG:900913 / EPSG:3785 / OSGEO:41001 are the following:
经度纬度的设定是由限制的,临近两极的坐标是不能索引的。精确的限制如下:
有效的经度范围:-180~180度
有效的纬度范围:-85.05112878~85.05112878度
当试图设定超出范围的经纬度时,会报错。
有关Stream的更多内容我想需要一个单独的章节来介绍,对于Redis的数据类型的文档介绍就到此为止了。