先感叹下,学东西一定要活学活用! 我用redis也有几年的历史了,今个才想到把集合可以当python list用。 最近做了几个项目都掺杂了redis, 遇到了一些个问题和开发中提高性能的方法,这都分享出来,共同学习。
下面先简单讲讲Redis集合的数据类型。
sadd,创建一个集合,并添加数据。
[[email protected] ~]# 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>
查看集合的大小
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队列用,当然队列项目中我还是会用redis list类型。
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内存左右。
原文:http://rfyiamcool.blog.51cto.com/1030776/1435539
redis的堵塞取任务,最好少用,超过5个线程去brpop的话,会把redis的cpu使用率顶到80%左右,而且严重会影响别的进程的访问,如果确定任务不是每时每刻都有的情况下,最好在你的程序控制下他的访问频次和时间的间隔。
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() #http://rfyiamcool.blog.51cto.com/1030776/1435539 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
python在运维项目中用到的redis数据类型