Python项目中用到的redis经验及数据类型

先感叹下,学东西一定要活学活用!   我用redis也有几年的历史了,今个才想到把集合可以当python list用。  最近做了几个项目都掺杂了redis, 遇到了一些个问题和开发中提高性能的方法,这都分享出来,共同学习。


下面先简单讲讲Redis集合的数据类型。

感叹爬虫很是牛逼,deny了那么多的ip地址,照样可以爬 。 无奈,这里标注下原文地址,blog.xiaorui.cc

Sets 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构,可以存储一些集合性的数据,比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。  上面说的是新浪微博的应用。  

sadd,创建一个集合,并添加数据。

[root@66 ~]# redis-cli
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379> sadd xiaorui aaa
(integer) 1
redis 127.0.0.1:6379> sadd xiaorui bbb
(integer) 1
redis 127.0.0.1:6379> sadd xiaorui ccc
(integer) 1
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379> SMEMBERS xiaorui
1) "aaa"
2) "ccc"
3) "bbb"
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379>

set集合是不能写重复的内容的

redis 127.0.0.1:6379> sadd xiaorui fuck_shencan
(integer) 1
redis 127.0.0.1:6379> sadd xiaorui fuck_shencan
(integer) 0
redis 127.0.0.1:6379>

查看集合的大小

redis 127.0.0.1:6379> SCARD xiaorui
(integer) 3
redis 127.0.0.1:6379>

删除

redis 127.0.0.1:6379> SREM xiaorui aaa
(integer) 1
redis 127.0.0.1:6379> SMEMBERS xiaorui
1) "ccc"
2) "bbb"
redis 127.0.0.1:6379>

两个集合的交集之处

redis 127.0.0.1:6379> SADD key1 a
(integer) 1
redis 127.0.0.1:6379> SADD key1 b
(integer) 1
redis 127.0.0.1:6379> SADD key1 c
(integer) 1
redis 127.0.0.1:6379> SADD key2 c
(integer) 1
redis 127.0.0.1:6379> SADD key2 d
(integer) 1
redis 127.0.0.1:6379> SADD key2 e
(integer) 1
redis 127.0.0.1:6379> SINTER key1 key2
1) "c"
redis 127.0.0.1:6379>

可以把集合当成redis list队列用,需要注意的是set集合的成员模式是不能有重复的值的。如果你的值不重复,你又蛋疼,还真的可以把set集合当成队列使用。

redis 127.0.0.1:6379> sadd myset one
(integer) 1
redis 127.0.0.1:6379> sadd myset two
(integer) 1
redis 127.0.0.1:6379> sadd myset three
(integer) 1
redis 127.0.0.1:6379> SPOP myset
"one"
redis 127.0.0.1:6379> SMEMBERS myset
1) "three"
2) "two"
redis 127.0.0.1:6379>

前两天和朋友说,我那监控平台的内存吃的厉害,他一下子蹦出一句,redis吃内存肯定很大了。。。 nima,哥只是用他的大队列。这里说下,redis做队列的强度。一把来说100w条的队列数据,占用73M 内存左 右。200w条数据内存在154M内存左右。  

redis有个brpop的堵塞获取,是个很好减少交互io的好东西,redis内部有个block的结构,每次有相应的数据变动,都会去检查该key是否有人在监听.   如果有监听,那好… 发过去.    客户端和服务端会一直保持连接. 

python处理redis的时候,最好要用pool,速度和资源明显的节省。 

>>> pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
>>> r = redis.Redis(connection_pool=pool)

新版的redis是支持管道的,pipline !   有朋友不太理解,这里的管道有什么好处。 pyhton 虽然连接redis的时候用了连接池,但是这也只是连接方面做了keepalive而已,但是每次的命令推送,他还是一次命令一个交互的。 用了pipline管道堵塞后,他会把所有的命令合成一个管道符推送到redis服务端。这样的话就省事了很多。  这个特别适用于并发大的时候。

对于redis的pub sub通信性能的问题,可以用gevent来搞定。直接导入gevent猴子就可以了。

import gevent.monkey
gevent.monkey.patch_all()
import os
import sys
import fcntl
import gevent
from gevent.socket import wait_read
  
from redis import Redis
  
PID = os.getpid()
  
red = Redis('localhost')
  
def echo_stdin():
    # make stdin non-blocking
    fcntl.fcntl(sys.stdin, fcntl.F_SETFL, os.O_NONBLOCK)
    red.publish('echo', "[%i] joined" % (PID,))
    while True:
        wait_read(sys.stdin.fileno())
        l = sys.stdin.readline().strip()
        s = "[%i] %s" % (PID, l)
        # save to log
        red.rpush('echo_log', s)
        # publish message
        red.publish('echo', s)
        if l == 'quit':
            break
  
def handler():
    pubsub = red.pubsub()
    # first subscribe, then print log (no race condition this way)
    pubsub.subscribe('echo')
    # print log
    for line in red.lrange('echo_log', 0, -1):
        print '.', line
    # print channel
    for msg in pubsub.listen():
        print '>', msg['data']
  
gevent.spawn(handler)
gevent.spawn(echo_stdin).join()

当然对于普通的set get sadd hset 也是可以配合redis来使用的。但是,没啥优势,因为redis只启用了一个进程针对数据的读写,咱们从程序中复用的那几个连接,最后取数据,还是需要调用那进程,你还不如让他老老实实的干活,别搞个多线程,让他白白折腾。 我这边做了压力测试,python2.7用个gevent后,批量的读写没什么突出的增长。

import geventredis
redis_client = geventredis.connect('127.0.0.1', 6379)
redis_client.set('foo', 'bar')
'OK'
for msg in redis_client.monitor():
    print msg

END.


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

2 Responses

  1. Life. 2016年8月3日 / 下午10:58

    “redis的堵塞取任务,最好少用,超过5个线程去brpop的话,会把redis的cpu使用率顶到80%左右,而且严重会影响别的进程的访问”话说上面结论是怎么得来的? 我用redis-py开了30个进程brpop读取本地Mac redis-server的一个空队列,CPU使用率稳定在0.0%

    • 峰云就她了 2016年8月6日 / 上午8:21

      对的,brpop已经不存在所谓性能问题了. 我们现在分布式系统里也在大量的使用brpop. 当时测试的版本有问题,已经更正.

发表评论

邮箱地址不会被公开。 必填项已用*标注