Redis学习04之 List列表
前两节学习了String和Hash, Hash可以把关连性的字段组合到一起用一个KEY, key值多同样会耗费内存和CPU, 在这点上Hash要优于String, 当然String在字符操作上如追加、部分值更新、Key 过期上更加灵活, 都是为特定的场景制定,这里学习另一个数据结构LIST列表,List顾名思义可以认为左右延伸的队列,一种有序存放的数据结构。
常用的操作有
推入
LPUSH:将元素推入到列表左端
RPUSH:将元素推入到列表右端
LPUSHX、RPUSHX:只对已存在的列表执行推入操作
移除
LPOP:弹出列表最左端的元素
RPOP:弹出列表最右端的元素
RPOPLPUSH:将右端弹出的元素推入到左端
其它
LSET 更新列表指定值
LTRIM 截断指定位置的值
LLEN 列表长度
测试命令
[root@ANBOB.COM ~]# redis-cli 127.0.0.1:6379> lpush Order u1 (integer) 1 127.0.0.1:6379> lpush Order u2 (integer) 2 127.0.0.1:6379> lpush Order u3 (integer) 3 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 127.0.0.1:6379> rpush Order u5 (integer) 4 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 127.0.0.1:6379> lindex Order 0 "u3" 127.0.0.1:6379> lindex Order 1 "u2" 127.0.0.1:6379> rpush Order 9 (integer) 5 127.0.0.1:6379> rpush Order u1 (integer) 6 127.0.0.1:6379> rpush Order u9 (integer) 7 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 7) "u9" 127.0.0.1:6379> rpushx Order u9 (integer) 8 127.0.0.1:6379> rpushx Order u10 (integer) 9 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 7) "u9" 8) "u9" 9) "u10" 127.0.0.1:6379> rpushx Order u10 (integer) 10 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 7) "u9" 8) "u9" 9) "u10" 10) "u10" 127.0.0.1:6379> rpushx Order u11 (integer) 11 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 7) "u9" 8) "u9" 9) "u10" 10) "u10" 11) "u11" 127.0.0.1:6379> rpushx Order1 u11 (integer) 0 127.0.0.1:6379> lrange Order1 0 -1 (empty array) 127.0.0.1:6379> lpush Order u100 u200 u300 (integer) 14 127.0.0.1:6379> lrange Order1 0 -1 (empty array) 127.0.0.1:6379> lrange Order 0 -1 1) "u300" 2) "u200" 3) "u100" 4) "u3" 5) "u2" 6) "u1" 7) "u5" 8) "9" 9) "u1" 10) "u9" 11) "u9" 12) "u10" 13) "u10" 14) "u11" 127.0.0.1:6379> lpop u300 (nil) 127.0.0.1:6379> lpop Order "u300" 127.0.0.1:6379> lrange Order 0 -1 1) "u200" 2) "u100" 3) "u3" 4) "u2" 5) "u1" 6) "u5" 7) "9" 8) "u1" 9) "u9" 10) "u9" 11) "u10" 12) "u10" 13) "u11" 127.0.0.1:6379> lpop Order "u200" 127.0.0.1:6379> lpop Order "u100" 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 7) "u9" 8) "u9" 9) "u10" 10) "u10" 11) "u11" 127.0.0.1:6379> rpop Order "u11" 127.0.0.1:6379> rpop Order "u10" 127.0.0.1:6379> rpoplpush Order Last "u10" 127.0.0.1:6379> rpoplpush Order Last "u9" 127.0.0.1:6379> rpoplpush Order Last "u9" 127.0.0.1:6379> lrange Order 0 -1 1) "u3" 2) "u2" 3) "u1" 4) "u5" 5) "9" 6) "u1" 127.0.0.1:6379> lrange Last 0 -1 1) "u9" 2) "u9" 3) "u10" 127.0.0.1:6379> llen Order (integer) 6 127.0.0.1:6379> llen last (integer) 0 127.0.0.1:6379> llen LAST (integer) 0 127.0.0.1:6379> llen Last (integer) 3
应用场景
FIFO 队列,如下发短信,或秒杀活动
>>> import redis
>>> import json
>>>
>>> client = redis.Redis()
>>>
>>> for i in range(100):
... print('telnum {0:011d} add completed!'.format(i))
... tel={'telnum':str(i).zfill(011)}
... client.rpush('phone_queue',json.dumps(tel))
...
telnum 00000000000 add completed!
1L
telnum 00000000001 add completed!
2L
telnum 00000000002 add completed!
3L
telnum 00000000003 add completed!
4L
...
模拟下发短信
sendsms.py
import redis
import json
client = redis.Redis()
def send_sms(tel):
print('----{}----'.format(tel))
return 1
next_phone_info = ''
while True:
phone_bytes = client.lpop('phone_queue')
if not phone_bytes:
print('All message send completed!')
break
phone_info = json.loads(phone_bytes)
print phone_info
print type(phone_info)
retry = phone_info.get('retry', 0)
telnum = phone_info['telnum']
rest = send_sms(telnum)
if rest:
print('The telnum {} send completed...'.format(telnum))
continue
if retry >= 3:
print('The telnum {} send failed. try 3 times'.format(telnum))
continue
next_phone_info = {'telnum':telnum, 'retry': retry+1}
client.rpush('phone_queue', json.dumps(next_phone_info))
[root@ANBOB.COM sendsms]# python sendsms.py
----000000000----
The telnum 000000000 send completed...
----000000001----
The telnum 000000001 send completed...
----000000002----
The telnum 000000002 send completed...
----000000003----
The telnum 000000003 send completed...
----000000004----
The telnum 000000004 send completed...
...
由于Redis是一个单线程、单进程的数据库,及时从多台服务器同时从一个公共REDIS数据库里POP数据也不会读取重复, redisk会自动排队,不用担心分布式进程重复发送问题。如上面的逻辑,发送如果失败会放回列表的右侧,重新发送。
另外对于秒杀活动,使用传统关系型数据库的事务和锁,如只限前200用户购买,可能因为锁并发堵塞产生不公平的现象,同时数据库可能也无法承担这么高的大事务量, 此时可以应用和redis协调部署,把购买用户丢进LIST的右测队列,如果llen长度超过200,前台就直接break请求就OK,减少了对数据库无效的冲击。
同样也可以做如关系型数据库中的分页查询
[root@ANBOB.COM list]# vi paging.py
class Paging:
def __init__(self, client, key):
self.client = client
self.key = key
def add(self, item):
self.client.lpush(self.key, item)
def get_page(self, page_number, item_per_page):
"""
"""
start_index = (page_number - 1) * item_per_page
end_index = page_number * item_per_page - 1
return self.client.lrange(self.key, start_index, end_index)
def size(self):
"""
"""
return self.client.llen(self.key)
[root@ANBOB.COM list]# python paging.py
[root@ANBOB.COM list]# python
Python 2.7.5 (default, Nov 20 2015, 02:00:19)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from redis import Redis
>>> from paging import Paging
>>> client = Redis(decode_responses=True)
>>> topics = Paging(client, "user-topics")
>>> for i in range(20):
... topics.add(i)
...
>>> topics.get_page(2, 5)
[u'14', u'13', u'12', u'11', u'10']
–over —
上一篇: Redis学习05之 SET集合
下一篇: Redis学习03之 HASH
对不起,这篇文章暂时关闭评论。