(4)lset
设置list中指定下标的元素值(从0开始)。
- redis
127.0.0.1:6379> rpush mylist4
"one"
- (integer) 1
- redis
127.0.0.1:6379> rpush mylist4
"two"
- (integer) 2
- redis
127.0.0.1:6379> rpush mylist4
"three"
- (integer) 3
- redis
127.0.0.1:6379> lset mylist4 0
"four"
- OK
- redis
127.0.0.1:6379> lset mylist4 -2
"five"
- OK
- redis
127.0.0.1:6379> lrange mylist4 0
-1
- 1) "four"
- 2)
"five"
- 3) "three"
- redis
127.0.0.1:6379>
此处依次插入了one、two、three,然后将下标为0的值设置为four,再将下标为?2的值设置为five。
(5)lrem
从与key对应的list中删除count个和value相同的元素,使用count查询。
count>0时,按从头到尾的顺序删除,具体代码如下:
- redis
127.0.0.1:6379> rpush mylist5
"hello"
- (integer) 1
- redis
127.0.0.1:6379> rpush mylist5
"hello"
- (integer) 2
- redis
127.0.0.1:6379> rpush mylist5
"foo"
- (integer) 3
- redis
127.0.0.1:6379> rpush mylist5
"hello"
- (integer) 4
- redis
127.0.0.1:6379> lrem mylist5 2
"hello"
- (integer) 2
- redis
127.0.0.1:6379> lrange mylist5 0
-1
- 1) "foo"
- 2)
"hello"
- redis
127.0.0.1:6379>
count<0时,按从尾到头的顺序删除,具体代码如下:
- redis
127.0.0.1:6379> rpush mylist6
"hello"
- (integer) 1
- redis
127.0.0.1:6379> rpush mylist6
"hello"
- (integer) 2
- redis
127.0.0.1:6379> rpush mylist6
"foo"
- (integer) 3
- redis
127.0.0.1:6379> rpush mylist6
"hello"
- (integer) 4
- redis
127.0.0.1:6379> lrem mylist6 -2
"hello"
- (integer) 2
- redis
127.0.0.1:6379> lrange mylist6 0
-1
- 1) "hello"
- 2)
"foo"
- redis
127.0.0.1:6379>
count=0时,删除全部,具体代码如下:
- redis
127.0.0.1:6379> rpush mylist7
"hello"
- (integer) 1
- redis
127.0.0.1:6379> rpush mylist7
"hello"
- (integer) 2
- redis
127.0.0.1:6379> rpush mylist7
"foo"
- (integer) 3
- redis
127.0.0.1:6379> rpush mylist7
"hello"
- (integer) 4
- redis
127.0.0.1:6379> lrem mylist7 0
"hello"
- (integer) 3
- redis
127.0.0.1:6379> lrange mylist7 0
-1
- 1) "foo"
- redis
127.0.0.1:6379>
(6)ltrim
保留指定key值范围内的数据:
- redis
127.0.0.1:6379> rpush mylist8
"one"
- (integer) 1
- redis
127.0.0.1:6379> rpush mylist8
"two"
- (integer) 2
- redis
127.0.0.1:6379> rpush mylist8
"three"
- (integer) 3
- redis
127.0.0.1:6379> rpush mylist8
"four"
- (integer) 4
- redis
127.0.0.1:6379> ltrim mylist8 1
-1
- OK
- redis
127.0.0.1:6379> lrange mylist8 0
-1
- 1) "two"
- 2)
"three"
- 3) "four"
- redis
127.0.0.1:6379>
(7)lpop
从list的头部删除元素,并返回删除元素的内容:
- redis
127.0.0.1:6379> lrange mylist 0
-1
- 1) "hello"
- 2)
"world"
- redis
127.0.0.1:6379> lpop
mylist
- "hello"
- redis
127.0.0.1:6379> lrange mylist 0
-1
- 1)
"world"
- redis
127.0.0.1:6379>
(8)rpop
从list的尾部删除元素,并返回删除元素的内容:
- redis
127.0.0.1:6379> lrange mylist2 0
-1
- 1) "hello"
- 2)
"world"
- redis
127.0.0.1:6379> rpop
mylist2
- "world"
- redis
127.0.0.1:6379> lrange mylist2 0
-1
- 1)
"hello"
- redis
127.0.0.1:6379>
(9)rpoplpush
从第一个list的尾部移除元素并将其添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子性的。如果第一个list为空或者不存在,则返回nil。
- redis
127.0.0.1:6379> lrange mylist5 0
-1
- 1) "three"
- 2)
"foo"
- 3) "hello"
- redis
127.0.0.1:6379> lrange mylist6 0
-1
- 1) "hello"
- 2)
"foo"
- redis
127.0.0.1:6379> rpoplpush mylist5
mylist6
- "hello"
- redis
127.0.0.1:6379> lrange mylist5 0
-1
- 1)
"three"
- 2) "foo"
- redis
127.0.0.1:6379> lrange mylist6 0
-1
- 1) "hello"
- 2)
"hello"
- 3) "foo"
- redis
127.0.0.1:6379>
(10)lindex
返回名称为key的list中index位置的元素。
- redis
127.0.0.1:6379> lrange mylist5 0
-1
- 1) "three"
- 2)
"foo"
- redis
127.0.0.1:6379> lindex mylist5
0
- "three"
- redis
127.0.0.1:6379> lindex mylist5
1
- "foo"
- redis
127.0.0.1:6379>
(11)llen
返回与key对应的list的长度。
- redis
127.0.0.1:6379> llen
mylist5
- (integer) 2
- redis
127.0.0.1:6379>
4.set
Redis的set是string类型的无序集合,set元素最多可以包含232个元素。
set通过hash table实现,所以添加、删除和查找的复杂度都是O(1)。hash
table会随着添加或者删除操作自动调整大小。需要注意的是,调整hash
table大小时同步(获取写锁)会阻塞其他读写操作,所以可能会改用跳表(skip list)来实现(跳表已用于sorted
set)。关于set集合类型除了基本的添加、删除操作,其他操作还包括对集合取并集(union)、交集(intersection)、差集(difference)。通过这些操作可以很容易就能实现sns中的好友推荐和Blog的tag功能。下面详细介绍set相关命令。
(1)sadd
向名称为key的set中添加元素。
- redis
127.0.0.1:6379> sadd myset
"hello"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset
"world"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset
"world"
- (integer)
0
- redis
127.0.0.1:6379> smembers
myset
- 1)
"world"
- 2)
"hello"
- redis
127.0.0.1:6379>
此处向myset中添加了3个元素,但由于第3个元素跟第2个元素相同,所以第3个元素没有添加成功。最后用smembers来查看myset中的所有元素。
(2)srem
删除名称为key的set中的元素member。
- redis
127.0.0.1:6379> sadd myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"two"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"three"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"four"
- (integer)
0
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379>
此处向myset2中添加了3个元素后,再调用srem来删除one和four,但由于元素中没有four,所以,srem命令执行失败。
(3)spop
随机返回并删除名称为key的set中的一个元素。
- redis
127.0.0.1:6379> sadd myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"two"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"three"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"four"
- (integer)
0
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379>
此处向myset3中添加了3个元素后,再调用spop来随机删除一个元素,可以看到three元素被删除了。
(4)sdiff
返回所有给定key与第一个key的差集。
- redis
127.0.0.1:6379> sadd myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"two"
- (integer)
1
- redis
127.0.0.1:6379> sadd myset2
"three"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"one"
- (integer)
1
- redis
127.0.0.1:6379> srem myset2
"four"
- (integer)
0
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379>
可以看到,myset2与myset3中不同的元素只是three,所以只有three出现在查询结果中。
也可以将myset2和myset3交换顺序后再行查看结果。
- redis
127.0.0.1:6379> sdiff myset3
myset2
- 1)
"one"
- redis
127.0.0.1:6379>
结果只显示了myset3与myset2中不同的元素。
(5)sdiffstore
返回所有给定key与第一个key的差集,并将结果保存为另一个key。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> sdiffstore myset4
myset2 myset3
- (integer)
1
- redis
127.0.0.1:6379> smembers
myset4
- 1)
"three"
- redis
127.0.0.1:6379>
(6)sinter
返回所有给定key的交集。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> sinter myset2
myset3
- 1)
"two"
- redis
127.0.0.1:6379>
通过本例可以看出,myset2和myset3的交集two出现在查询结果中。
(7)sinterstore
返回所有给定key的交集,并将结果存为另一个key。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> sinterstore myset5
myset2 myset3
- (integer)
1
- redis
127.0.0.1:6379> smembers
myset5
- 1)
"two"
- redis
127.0.0.1:6379>
通过本例的结果可以看出,myset2和myset3的交集被保存到了myset5中。
(8)sunion
返回所有给定key的并集。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> sunion myset2
myset3
- 1)
"three"
- 2)
"one"
- 3)
"two"
- redis
127.0.0.1:6379>
通过本例的结果可以看出,并集包含了myset2和myset3的全部内容。
(9)sunionstore
返回所有给定key的并集,并将结果保存为另一个key。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> sunionstore myset6
myset2 myset3
- (integer)
3
- redis
127.0.0.1:6379> smembers
myset6
- 1)
"three"
- 2)
"one"
- 3)
"two"
- redis
127.0.0.1:6379>
通过本例的结果可以看出,myset2和myset3的并集被保存到了myset6中。
(10)smove
从第一个key对应的set中移除member并将其添加到第二个对应的set中。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"three"
- 2)
"two"
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> smove myset2 myset7
three
- (integer)
1
- redis
127.0.0.1:6379> smembers
myset7
- 1)
"three"
- redis
127.0.0.1:6379>
通过本例可以看到,myset2的成员three被移到myset7中。
(11)scard
返回名称为key的set的元素个数。
- redis
127.0.0.1:6379> scard
myset2
- (integer)
1
- redis
127.0.0.1:6379>
通过本例可以看到,myset2的成员数量为1。
(12)sismember
测试member是否为名称为key的set中的元素。
- redis
127.0.0.1:6379> smembers
myset2
- 1)
"two"
- redis
127.0.0.1:6379> sismember myset2
two
- (integer)
1
- redis
127.0.0.1:6379> sismember myset2
one
- (integer)
0
- redis
127.0.0.1:6379>
通过本例可以看到,two是myset2的成员,而one不是。
(13)srandmember
随机返回名称为key的set中的一个元素,但不删除该元素。
- redis
127.0.0.1:6379> smembers
myset3
- 1)
"two"
- 2)
"one"
- redis
127.0.0.1:6379> srandmember
myset3
- "two"
- redis
127.0.0.1:6379> srandmember
myset3
- "one"
- redis
127.0.0.1:6379>
5.sorted sets
和set一样,sorted
set也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score。sorted set的是skip
list和hash table的混合体。
当元素被添加到集合中时,则该元素到score的映射被添加到hash
table中。所以给定一个元素,获取score的开销是O(1),另一个score到元素的映射被添加到skip
list,并按照score排序,所以就可以有序地获取集合中的元素。添加、删除操作的开销都是O(log(N)),和skip
list的开销一致。Redis的skip list实现使用双向链表,这样就可以逆序从尾部获取所需元素。sorted
set最常作为索引来使用。可以把要排序的字段作为score存储,对象的ID作为元素进行存储。下面是sorted
set的相关命令。
(1)zadd
向名称为key的zset中添加元素(member),并使用score指令进行排序。如果该元素已经存在,则更新该元素的顺序。
- redis
127.0.0.1:6379> zadd myzset 1
"one"
- (integer)
1
- redis
127.0.0.1:6379> zadd myzset 2
"two"
- (integer)
1
- redis
127.0.0.1:6379> zadd myzset 3
"two"
- (integer)
0
- redis
127.0.0.1:6379> zrange myzset 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"3"
- redis
127.0.0.1:6379>
此处向myzset中添加了one和two成员,并且two被设置了2次,那么将以最后一次的设置为准,最后将所有元素按顺序显示出来。
(2)zrem
删除名称为key的zset中的元素(member)。
- redis
127.0.0.1:6379> zrange myzset 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"3"
- redis
127.0.0.1:6379> zrem myzset
two
- (integer)
1
- redis
127.0.0.1:6379> zrange myzset 0 -1
withscores
- 1)
"one"
- 2)
"1"
- redis
127.0.0.1:6379>
可以看到,two被删除了。
(3)zincrby
如果在名称为key的zset中已经存在元素(member),则该元素的score增加(increment);否则向集合中添加该元素,其score的值为increment。
- redis
127.0.0.1:6379> zadd myzset2 1
"one"
- (integer)
1
- redis
127.0.0.1:6379> zadd myzset2 2
"two"
- (integer)
1
- redis
127.0.0.1:6379> zincrby myzset2 2
"one"
- "3"
- redis
127.0.0.1:6379> zrange myzset2 0 -1
withscores
- 1)
"two"
- 2)
"2"
- 3)
"one"
- 4)
"3"
- redis
127.0.0.1:6379>
这里将元素one的score从1增加了2,即增加到了3。
(4)zrank
返回名称为key的zset中member的排名(按score从小到大排序),即将two的下标标为1。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zrank myzset3
two
- (integer)
1
- redis
127.0.0.1:6379>
(5)zrevrank
返回名称为key的zset中member的排名(按score从大到小排序)。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zrank myzset3
two
- (integer)
1
- redis
127.0.0.1:6379>
(6)zrevrange
在名称为key的zset中,检索从开始到结束的所有元素,按score从大到小进行排序,再取出全部元素。
- redis
127.0.0.1:6379> zrevrange myzset3 0 -1
withscores
- 1)
"five"
- 2)
"5"
- 3)
"three"
- 4)
"3"
- 5)
"two"
- 6)
"2"
- 7)
"one"
- 8)
"1"
- redis
127.0.0.1:6379>
(7)zrangebyscore
返回集合中score在给定区间的元素。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zrangebyscore myzset3 2
3 withscores
- 1)
"two"
- 2)
"2"
- 3)
"three"
- 4)
"3"
- redis
127.0.0.1:6379>
这里返回了score在2~3区间的元素。
(8)zcount
返回集合中score在给定区间的数量。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zcount myzset3 2
3
- (integer)
2
- redis
127.0.0.1:6379>
这里计算了score在2~3之间的元素数目。
(9)zcard
返回集合中元素的个数。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zcard
myzset3
- (integer)
4
- redis
127.0.0.1:6379>
从本例看出,myzset3集合的元素数量为4。
(10)zscore
返回给定元素对应的score。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zscore myzset3
two
- "2"
- redis
127.0.0.1:6379>
(11)zremrangebyrank
删除集合中排名在给定区间的元素。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- 7)
"five"
- 8)
"5"
- redis
127.0.0.1:6379> zremrangebyrank myzset3
3 3
- (integer)
1
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- redis
127.0.0.1:6379>
此处将myzset3中按从小到大排序结果中下标为3的元素删除了。
(12)zremrangebyscore
删除集合中score在给定区间的元素。
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"one"
- 2)
"1"
- 3)
"two"
- 4)
"2"
- 5)
"three"
- 6)
"3"
- redis
127.0.0.1:6379> zremrangebyscore
myzset3 1 2
- (integer)
2
- redis
127.0.0.1:6379> zrange myzset3 0 -1
withscores
- 1)
"three"
- 2)
"3"
- redis
127.0.0.1:6379>
此处将myzset3中按从小到大排序结果的score在1~2之间的元素删除了。
11.3 FAQ
Q:Redis的内存用完该怎么办?
A:操作系统的malloc(
)返回NULL值的情况并不常见,通常服务器将开始交换,Redis的性能会降低,所以可能会出现差错。info命令用于报告Redis内存的使用情况,所以可以通过写脚本来监控Redis服务器。还可以使用配置文件的maxmemory选项,限制Redis可以使用的内存。如果达到内存使用上限,即给出错误的写入命令提示(但将继续接受只读命令)。
Q:有什么方法可以使Redis的内存使用率降低?
A:最好使用Redis的哈希、列表、排序集、整数集,因为这些具有更为紧凑的工作方式。
Q:Redis具有高层次的操作和功能,但需要在内存中工作,如果没有数据集较大的内存,该怎么办?
A:Redis的开发商在过去的虚拟内存和其他系统进行试验,以便大于RAM的数据集。然而,许多大用户解决多个Redis节点之间分布的大型数据集的问题,仍使用客户端的哈希。同时Redis的集群,自动分发和Redis的子集的热备实施,许多可用的案例可能是一个很好的解决方案。
Q:单线程的Redis怎样利用多台CPU?
A:只需在同一台机器上启动Redis的多个实例,将其当作不同的服务器即可。单一的实例在某些时候可能是不够用的,所以如果想使用多个CPU,这就需要开始思考早期的一些数据段。这里需要注意的是,使用Redis
Pipelining在Linux系统上运行,每秒可以提供500K的请求,因此,如果应用程序主要使用O(N)或O(log(N))命令,会消耗更多的CPU。
注意
Redis
Pipelining用于解决因客户端和服务器的网络延迟而造成的请求延迟。这一功能其实很早就有,即使较早版本的Redis,也能使用这个功能。此功能可以将一系列请求连续发送到Server端,不必等待Server端的返回信息,而Server端会将请求放进一个有序的管道中,执行完成后,再一次性将返回值发送回来。
小结
本章对Redis数据结构、性能及其在生产环境中的主从配置进行了详细介绍。尤其是对常用命令和各种数据类型的操作。写好客户端后的调试以及调优工序还是比较重要的,希望大家多多掌控。
下一章将介绍基于分布式文件存储的数据库-MongoDB。
|