Redis(一)基础特性
OverView
Redis is an open-source in-memory database project implementing a distributed, in-memory key-value store with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, hyperloglogs, bitmaps and spatial indexes.
上面是wiki上的Redis的介绍,可以看出,使用场景主要还是in-memory的,持久化只是个optional的。而且支持的数据类型不只是Redis In Action中的几个,随着Redis的进化,除了基本的5个类型string、map、set、sorted set、list还有其他的结构如hyperloglogs、spatial indexes、bitmaps。
- Strings
- Lists of strings
- Sets of strings (collections of non-repeating unsorted elements)
- Sorted sets of strings (collections of non-repeating elements ordered by a floating-point number called score)
- Hash tables where keys and values are strings HyperLogLogs used for approximated set cardinality size estimation.
- Geospatial data through the implementation of the geohash technique since Redis 3.2.
hyperloglogs是个算法,用于近似(不是精确)计算在multiset中的不同元素的个数的。类似的Bloomfilter结构也是近似的算法,这种算法一般是在特定的场景下,牺牲一定的准确性,但是能够大大提高空间和时间的复杂度。
HyperLogLog is an algorithm for the count-distinct problem, approximating the number of distinct elements in a multiset.
Spatial indices支持的数据库其实很多,如Mysql、ES、Mongodb,在基于空间的搜索上能够大大提高检索速度。
Spatial indices are used by spatial databases (databases which store information related to objects in space) to optimize spatial queries. Conventional index types do not efficiently handle spatial queries such as how far two points differ, or whether points fall within a spatial area of interest.
string
操作很简单,set,get,del。有点像程序中的全局变量,大型的程序,慎用。
list
作为一个key-value的数据库,支持这list有点奇怪。但这也是Redis一个非常有用的特性,用处也很广。而且用法和编程中的list很像,底层实现是链表而不是数组,对应java的linkedlist,支持基础的操作如:
- RPUSH 将给定值推入到列表的右端
- LRANGE 获取列表在给定范围上的所有值
- LINDEX 获取列表在给定位置上的单个元素
- LPOP 从列表的左端弹出一个值,并返回被弹出的值
此外还有一些高级的命令,比如从列表里面移除元素的命令、将元素插入到列表中间的命令、将列表修剪至指定长度(相当于从列表的其中一端或者两端移除元素)的命令。
set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 2的32次方 - 1 (4294967295, 每个集合可存储40多亿个成员)。
为什么不在支持的多点呢?可以看出,明显是地址空间的约束,指针是4个字节的,这样首先会节省内存,而且寻址效率高。而且再多的话,hash也会有碰撞,效率会降低。如果再有需要存储更多成员的场景,多加个集合或者Redis集群方式。
基础的操作:
- SADD key member1 [member2] 向集合添加一个或多个成员
- SCARD key 获取集合的成员数
- SMEMBERS key 返回集合中的所有成员
此外,还有很多的高级操作,如能够获取两个set的并集、差集等。
sorted set
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
基础操作:
- ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数
- ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
有序集合对象的编码可以是ziplist或者skiplist。
如果第一个元素符合以下条件的话, 就创建一个 REDIS_ENCODING_ZIPLIST 编码的有序集:
服务器属性 server.zset_max_ziplist_entries 的值大于 0 (默认为 128 )。 元素的 member 长度小于服务器属性 server.zset_max_ziplist_value 的值(默认为 64 )。 否则,程序就创建一个 REDIS_ENCODING_SKIPLIST 编码的有序集。
zset 同时使用字典和跳跃表两个数据结构来保存有序集元素。
其中, 元素的成员由一个 redisObject 结构表示, 而元素的 score 则是一个 double 类型的浮点数, 字典和跳跃表两个结构通过将指针共同指向这两个值来节约空间 (不用每个元素都复制两份)。
下图展示了一个 REDIS_ENCODING_SKIPLIST 编码的有序集:
在Java8中也有类似的使用skiplist的数据结构ConcurrentSkipListMap,在Java中使用这数据结构是为了提高并发,AVL树或红黑树在插入的时候,可能要对树进行旋转,需要锁住大量的数据。而在Redis中,本来是单线程结构,不存在锁的问题,为什么还要使用这数据结构?主要的原因是要支持按照Score进行范围性查找和处理操作,这是(高效地)实现 ZRANGE 、 ZRANK 和 ZINTERSTORE 等命令的关键。
hash
这hash不是一半的hashmap,hash的value是一组或多组key-value对,适合存储对象的结构。
基础操作:
- HMSET key field1 value1 [field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。
- HGETALL key 获取在哈希表中指定 key 的所有字段和值
事物与原子操作
Redis中很多原子操作的命令,如INCR、INCRBY、DECR、DECRBY,因为Redis本来就是单线程的,实现这操作原子性也没啥特殊的处理。
使用注意
- 与所有的数据库系统一样,key(关系型中为主键)不能太长,否则会非常浪费内存,插入,查找效率都会降低。
- 最好有一定的可读性,例如user:10000