分享

Redis的管理(二)

 WindySky 2016-04-18

(4)lset

设置list中指定下标的元素值(从0开始)。

  1. redis 127.0.0.1:6379> rpush mylist4 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> rpush mylist4 "two"
  4. (integer) 2
  5. redis 127.0.0.1:6379> rpush mylist4 "three"
  6. (integer) 3
  7. redis 127.0.0.1:6379> lset mylist4 0 "four"
  8. OK
  9. redis 127.0.0.1:6379> lset mylist4 -2 "five"
  10. OK
  11. redis 127.0.0.1:6379> lrange mylist4 0 -1
  12. 1) "four"
  13. 2) "five"
  14. 3) "three"
  15. redis 127.0.0.1:6379>

此处依次插入了one、two、three,然后将下标为0的值设置为four,再将下标为?2的值设置为five。

(5)lrem

从与key对应的list中删除count个和value相同的元素,使用count查询。

count>0时,按从头到尾的顺序删除,具体代码如下:

  1. redis 127.0.0.1:6379> rpush mylist5 "hello"
  2. (integer) 1
  3. redis 127.0.0.1:6379> rpush mylist5 "hello"
  4. (integer) 2
  5. redis 127.0.0.1:6379> rpush mylist5 "foo"
  6. (integer) 3
  7. redis 127.0.0.1:6379> rpush mylist5 "hello"
  8. (integer) 4
  9. redis 127.0.0.1:6379> lrem mylist5 2 "hello"
  10. (integer) 2
  11. redis 127.0.0.1:6379> lrange mylist5 0 -1
  12. 1) "foo"
  13. 2) "hello"
  14. redis 127.0.0.1:6379>
count<0时,按从尾到头的顺序删除,具体代码如下:
  1. redis 127.0.0.1:6379> rpush mylist6 "hello"
  2. (integer) 1
  3. redis 127.0.0.1:6379> rpush mylist6 "hello"
  4. (integer) 2
  5. redis 127.0.0.1:6379> rpush mylist6 "foo"
  6. (integer) 3
  7. redis 127.0.0.1:6379> rpush mylist6 "hello"
  8. (integer) 4
  9. redis 127.0.0.1:6379> lrem mylist6 -2 "hello"
  10. (integer) 2
  11. redis 127.0.0.1:6379> lrange mylist6 0 -1
  12. 1) "hello"
  13. 2) "foo"
  14. redis 127.0.0.1:6379>
count=0时,删除全部,具体代码如下:
  1. redis 127.0.0.1:6379> rpush mylist7 "hello"
  2. (integer) 1
  3. redis 127.0.0.1:6379> rpush mylist7 "hello"
  4. (integer) 2
  5. redis 127.0.0.1:6379> rpush mylist7 "foo"
  6. (integer) 3
  7. redis 127.0.0.1:6379> rpush mylist7 "hello"
  8. (integer) 4
  9. redis 127.0.0.1:6379> lrem mylist7 0 "hello"
  10. (integer) 3
  11. redis 127.0.0.1:6379> lrange mylist7 0 -1
  12. 1) "foo"
  13. redis 127.0.0.1:6379>

(6)ltrim

保留指定key值范围内的数据:

  1. redis 127.0.0.1:6379> rpush mylist8 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> rpush mylist8 "two"
  4. (integer) 2
  5. redis 127.0.0.1:6379> rpush mylist8 "three"
  6. (integer) 3
  7. redis 127.0.0.1:6379> rpush mylist8 "four"
  8. (integer) 4
  9. redis 127.0.0.1:6379> ltrim mylist8 1 -1
  10. OK
  11. redis 127.0.0.1:6379> lrange mylist8 0 -1
  12. 1) "two"
  13. 2) "three"
  14. 3) "four"
  15. redis 127.0.0.1:6379>

(7)lpop

从list的头部删除元素,并返回删除元素的内容:

  1. redis 127.0.0.1:6379> lrange mylist 0 -1
  2. 1) "hello"
  3. 2) "world"
  4. redis 127.0.0.1:6379> lpop mylist
  5. "hello"
  6. redis 127.0.0.1:6379> lrange mylist 0 -1
  7. 1) "world"
  8. redis 127.0.0.1:6379>

(8)rpop

从list的尾部删除元素,并返回删除元素的内容:

  1. redis 127.0.0.1:6379> lrange mylist2 0 -1
  2. 1) "hello"
  3. 2) "world"
  4. redis 127.0.0.1:6379> rpop mylist2
  5. "world"
  6. redis 127.0.0.1:6379> lrange mylist2 0 -1
  7. 1) "hello"
  8. redis 127.0.0.1:6379>

(9)rpoplpush

从第一个list的尾部移除元素并将其添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子性的。如果第一个list为空或者不存在,则返回nil。

  1. redis 127.0.0.1:6379> lrange mylist5 0 -1
  2. 1) "three"
  3. 2) "foo"
  4. 3) "hello"
  5. redis 127.0.0.1:6379> lrange mylist6 0 -1
  6. 1) "hello"
  7. 2) "foo"
  8. redis 127.0.0.1:6379> rpoplpush mylist5 mylist6
  9. "hello"
  10. redis 127.0.0.1:6379> lrange mylist5 0 -1
  11. 1) "three"
  12. 2) "foo"
  13. redis 127.0.0.1:6379> lrange mylist6 0 -1
  14. 1) "hello"
  15. 2) "hello"
  16. 3) "foo"
  17. redis 127.0.0.1:6379>

(10)lindex

返回名称为key的list中index位置的元素。

  1. redis 127.0.0.1:6379> lrange mylist5 0 -1
  2. 1) "three"
  3. 2) "foo"
  4. redis 127.0.0.1:6379> lindex mylist5 0
  5. "three"
  6. redis 127.0.0.1:6379> lindex mylist5 1
  7. "foo"
  8. redis 127.0.0.1:6379>

(11)llen

返回与key对应的list的长度。

  1. redis 127.0.0.1:6379> llen mylist5
  2. (integer) 2
  3. 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中添加元素。

  1. redis 127.0.0.1:6379> sadd myset "hello"
  2. (integer) 1
  3. redis 127.0.0.1:6379> sadd myset "world"
  4. (integer) 1
  5. redis 127.0.0.1:6379> sadd myset "world"
  6. (integer) 0
  7. redis 127.0.0.1:6379> smembers myset
  8. 1) "world"
  9. 2) "hello"
  10. redis 127.0.0.1:6379>

此处向myset中添加了3个元素,但由于第3个元素跟第2个元素相同,所以第3个元素没有添加成功。最后用smembers来查看myset中的所有元素。

(2)srem

删除名称为key的set中的元素member。

  1.  redis 127.0.0.1:6379> sadd myset2 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> sadd myset2 "two"
  4. (integer) 1
  5. redis 127.0.0.1:6379> sadd myset2 "three"
  6. (integer) 1
  7. redis 127.0.0.1:6379> srem myset2 "one"
  8. (integer) 1
  9. redis 127.0.0.1:6379> srem myset2 "four"
  10. (integer) 0
  11. redis 127.0.0.1:6379> smembers myset2
  12. 1) "three"
  13. 2) "two"
  14. redis 127.0.0.1:6379>

此处向myset2中添加了3个元素后,再调用srem来删除one和four,但由于元素中没有four,所以,srem命令执行失败。

(3)spop

随机返回并删除名称为key的set中的一个元素。

  1. redis 127.0.0.1:6379> sadd myset2 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> sadd myset2 "two"
  4. (integer) 1
  5. redis 127.0.0.1:6379> sadd myset2 "three"
  6. (integer) 1
  7. redis 127.0.0.1:6379> srem myset2 "one"
  8. (integer) 1
  9. redis 127.0.0.1:6379> srem myset2 "four"
  10. (integer) 0
  11. redis 127.0.0.1:6379> smembers myset2
  12. 1) "three"
  13. 2) "two"
  14. redis 127.0.0.1:6379>

此处向myset3中添加了3个元素后,再调用spop来随机删除一个元素,可以看到three元素被删除了。

(4)sdiff

返回所有给定key与第一个key的差集。

  1. redis 127.0.0.1:6379> sadd myset2 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> sadd myset2 "two"
  4. (integer) 1
  5. redis 127.0.0.1:6379> sadd myset2 "three"
  6. (integer) 1
  7. redis 127.0.0.1:6379> srem myset2 "one"
  8. (integer) 1
  9. redis 127.0.0.1:6379> srem myset2 "four"
  10. (integer) 0
  11. redis 127.0.0.1:6379> smembers myset2
  12. 1) "three"
  13. 2) "two"
  14. redis 127.0.0.1:6379>


可以看到,myset2与myset3中不同的元素只是three,所以只有three出现在查询结果中。

也可以将myset2和myset3交换顺序后再行查看结果。

  1. redis 127.0.0.1:6379> sdiff myset3 myset2
  2. 1) "one"
  3. redis 127.0.0.1:6379>

结果只显示了myset3与myset2中不同的元素。

(5)sdiffstore

返回所有给定key与第一个key的差集,并将结果保存为另一个key。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> sdiffstore myset4 myset2 myset3
  8. (integer) 1
  9. redis 127.0.0.1:6379> smembers myset4
  10. 1) "three"
  11. redis 127.0.0.1:6379>

(6)sinter

返回所有给定key的交集。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> sinter myset2 myset3
  8. 1) "two"
  9. redis 127.0.0.1:6379>

通过本例可以看出,myset2和myset3的交集two出现在查询结果中。

(7)sinterstore

返回所有给定key的交集,并将结果存为另一个key。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> sinterstore myset5 myset2 myset3
  8. (integer) 1
  9. redis 127.0.0.1:6379> smembers myset5
  10. 1) "two"
  11. redis 127.0.0.1:6379>

通过本例的结果可以看出,myset2和myset3的交集被保存到了myset5中。

(8)sunion

返回所有给定key的并集。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> sunion myset2 myset3
  8. 1) "three"
  9. 2) "one"
  10. 3) "two"
  11. redis 127.0.0.1:6379>

通过本例的结果可以看出,并集包含了myset2和myset3的全部内容。

(9)sunionstore

返回所有给定key的并集,并将结果保存为另一个key。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> sunionstore myset6 myset2 myset3
  8. (integer) 3
  9. redis 127.0.0.1:6379> smembers myset6
  10. 1) "three"
  11. 2) "one"
  12. 3) "two"
  13. redis 127.0.0.1:6379>

通过本例的结果可以看出,myset2和myset3的并集被保存到了myset6中。

(10)smove

从第一个key对应的set中移除member并将其添加到第二个对应的set中。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "three"
  3. 2) "two"
  4. redis 127.0.0.1:6379> smembers myset3
  5. 1) "two"
  6. 2) "one"
  7. redis 127.0.0.1:6379> smove myset2 myset7 three
  8. (integer) 1
  9. redis 127.0.0.1:6379> smembers myset7
  10. 1) "three"
  11. redis 127.0.0.1:6379>

通过本例可以看到,myset2的成员three被移到myset7中。

(11)scard

返回名称为key的set的元素个数。

  1. redis 127.0.0.1:6379> scard myset2
  2. (integer) 1
  3. redis 127.0.0.1:6379>

通过本例可以看到,myset2的成员数量为1。

(12)sismember

测试member是否为名称为key的set中的元素。

  1. redis 127.0.0.1:6379> smembers myset2
  2. 1) "two"
  3. redis 127.0.0.1:6379> sismember myset2 two
  4. (integer) 1
  5. redis 127.0.0.1:6379> sismember myset2 one
  6. (integer) 0
  7. redis 127.0.0.1:6379>

通过本例可以看到,two是myset2的成员,而one不是。

(13)srandmember

随机返回名称为key的set中的一个元素,但不删除该元素。

  1. redis 127.0.0.1:6379> smembers myset3
  2. 1) "two"
  3. 2) "one"
  4. redis 127.0.0.1:6379> srandmember myset3
  5. "two"
  6. redis 127.0.0.1:6379> srandmember myset3
  7. "one"
  8. 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指令进行排序。如果该元素已经存在,则更新该元素的顺序。

  1. redis 127.0.0.1:6379> zadd myzset 1 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> zadd myzset 2 "two"
  4. (integer) 1
  5. redis 127.0.0.1:6379> zadd myzset 3 "two"
  6. (integer) 0
  7. redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
  8. 1) "one"
  9. 2) "1"
  10. 3) "two"
  11. 4) "3"
  12. redis 127.0.0.1:6379>

此处向myzset中添加了one和two成员,并且two被设置了2次,那么将以最后一次的设置为准,最后将所有元素按顺序显示出来。

(2)zrem

删除名称为key的zset中的元素(member)。

  1. redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "3"
  6. redis 127.0.0.1:6379> zrem myzset two
  7. (integer) 1
  8. redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
  9. 1) "one"
  10. 2) "1"
  11. redis 127.0.0.1:6379>

可以看到,two被删除了。

(3)zincrby

如果在名称为key的zset中已经存在元素(member),则该元素的score增加(increment);否则向集合中添加该元素,其score的值为increment。

  1. redis 127.0.0.1:6379> zadd myzset2 1 "one"
  2. (integer) 1
  3. redis 127.0.0.1:6379> zadd myzset2 2 "two"
  4. (integer) 1
  5. redis 127.0.0.1:6379> zincrby myzset2 2 "one"
  6. "3"
  7. redis 127.0.0.1:6379> zrange myzset2 0 -1 withscores
  8. 1) "two"
  9. 2) "2"
  10. 3) "one"
  11. 4) "3"
  12. redis 127.0.0.1:6379>

这里将元素one的score从1增加了2,即增加到了3。

(4)zrank

返回名称为key的zset中member的排名(按score从小到大排序),即将two的下标标为1。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zrank myzset3 two
  11. (integer) 1
  12. redis 127.0.0.1:6379>

(5)zrevrank

返回名称为key的zset中member的排名(按score从大到小排序)。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zrank myzset3 two
  11. (integer) 1
  12. redis 127.0.0.1:6379>

(6)zrevrange

在名称为key的zset中,检索从开始到结束的所有元素,按score从大到小进行排序,再取出全部元素。

  1. redis 127.0.0.1:6379> zrevrange myzset3 0 -1 withscores
  2. 1) "five"
  3. 2) "5"
  4. 3) "three"
  5. 4) "3"
  6. 5) "two"
  7. 6) "2"
  8. 7) "one"
  9. 8) "1"
  10. redis 127.0.0.1:6379>

(7)zrangebyscore

返回集合中score在给定区间的元素。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zrangebyscore myzset3 2 3 withscores
  11. 1) "two"
  12. 2) "2"
  13. 3) "three"
  14. 4) "3"
  15. redis 127.0.0.1:6379>

这里返回了score在2~3区间的元素。

(8)zcount

返回集合中score在给定区间的数量。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zcount myzset3 2 3
  11. (integer) 2
  12. redis 127.0.0.1:6379>

这里计算了score在2~3之间的元素数目。

(9)zcard

返回集合中元素的个数。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zcard myzset3
  11. (integer) 4
  12. redis 127.0.0.1:6379>

从本例看出,myzset3集合的元素数量为4。

(10)zscore

返回给定元素对应的score。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zscore myzset3 two
  11. "2"
  12. redis 127.0.0.1:6379>

(11)zremrangebyrank

删除集合中排名在给定区间的元素。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. 7) "five"
  9. 8) "5"
  10. redis 127.0.0.1:6379> zremrangebyrank myzset3 3 3
  11. (integer) 1
  12. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  13. 1) "one"
  14. 2) "1"
  15. 3) "two"
  16. 4) "2"
  17. 5) "three"
  18. 6) "3"
  19. redis 127.0.0.1:6379>

此处将myzset3中按从小到大排序结果中下标为3的元素删除了。

(12)zremrangebyscore

删除集合中score在给定区间的元素。

  1. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  2. 1) "one"
  3. 2) "1"
  4. 3) "two"
  5. 4) "2"
  6. 5) "three"
  7. 6) "3"
  8. redis 127.0.0.1:6379> zremrangebyscore myzset3 1 2
  9. (integer) 2
  10. redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
  11. 1) "three"
  12. 2) "3"
  13. 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。


  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多