Python操作redis

 

Python操作redis

分类: Redis   14744人阅读  评论(8)  收藏  举报
python redis 数据库 search import

首先确保redis已经正常启动。

 

安装

   可以去pypi上找到redis的Python模块:

   http://pypi.python.org/pypi?%3Aaction=search&term=redis&submit=search

   然后按照提示down下来redis-py-2.2.1.tar.gz

   非常标准的解压: #tar xvzf redis-py-2.2.1.tar.gz

   进入解压目录,进行Python模块的标准安装:

   python setup.py install

 

运行

   打开Python解释器:

>>> import redis
>>> r = redis.Redis(host='localhost', port=6379, db=0)   #如果设置了密码,就加上password=密码
>>> r.set('foo', 'bar')   #或者写成 r['foo'] = 'bar'
True
>>> r.get('foo')   
'bar'
>>> r.delete('foo')
True
>>> r.dbsize()   #库里有多少key,多少条数据
0
>>> r['test']='OK!'

>>> r.save()   #强行把数据库保存到硬盘。保存时阻塞
True

--------------------------------

>>> r.flushdb()   #删除当前数据库的所有数据
True

 >>> a = r.get('chang')
>>> a    # 因为是Noen对象,什么也不显示!
>>> dir(a)   
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

>>> r.exists('chang')  #看是否存在这个键值
False

>>> r.keys()   # 列出所有键值。(这时候已经存了4个了)
['aaa', 'test', 'bbb', 'key1']

 

附注A:

来看一下redis.Redis的 init() 函数定义:

 __init__(self, host='localhost', port=6379, db=0, password=None, socket_timeout=None, connection_pool=None, charset='utf-
8', errors='strict', decode_responses=False, unix_socket_path=None)

最新的redis 2.6.0加入了连接池,具体用法可以看作者博客。

 

 附注B:

其他命令API,请参照redis-Python作者的博客,写的挺清楚了:

https://github.com/andymccurdy/redis-py

 

要:现在演讲的是阿里云计算运维部高级工程师阮若夷,他带来的主题是Redis深入浅出。

时至今日,“Big data”(大数据)时代的来临已经毋庸置疑,尤其是在电信、金融等行业,几乎已经到了“数据就是业务本身”的地步。这种趋势已经让很多相信数据之力量的企业做出改变。恰逢此时,为了让更多的人了解和使用分析大数据,CSDN独家承办的大数据技术大会于今日在北京中旅大厦召开。本次大会汇集Hadoop、NoSQL、数据分析与挖掘、数据仓库、商业智能以及开源云计算架构等诸多热点话题。包括百度、淘宝、新浪等业界知名专家与参会者齐聚一堂,共同探讨大数据浪潮下的行业应对法则以及大数据时代的抉择。

Python操作redis_第1张图片

阿里云计算运维部高级工程师阮若夷

阮若夷主要介绍了Redis的特性和架构,以及Redis的容量规划、复制、持久化的原理。他同时介绍了Redis和关系型数据库表设计区别。

以下为文字实录

大家早上好,我是阿里云计算部的阮若夷,很高兴与大家一起分享这个PPT。今天的主题是Redis深入浅出。Redis这个东西已经在阿里云很多项目上都有使用到,比如说我们已经有800万用户阿里旺旺,今年年初推出云手机,还有我参与两个项目都使用到Redis。在今年年初的时候我们开始对系统进行选型,发现这个Redis代码非常优雅,代码量很短,创始人非常靠谱,我们就花了一些精力来进行研究Redis。

这是今天主题,先是介绍一下Redis的一些特性和它的一些架构,接下来是它的一些容量规划,还有它的一些复制,持久化的一些原理,最后是它和关系型数据库表设计区别。刚开始CSDN高松联系我的时候,因为是一个比较小的会议,没想到今天人这么多,不知道这个PPT适不适合在这里讲。

我们先介绍一下Redis的一些特性,甚至我们可以把我们数据结构直接定义在Redis本身,我们程序中数据结构,不需要定义,不需要使用C++或者Java,直接把这个结构定义在Redis里面。第二在Redis的现场模型,在2.4版本之前,Redis一直使用单线程处理所有的网络请求和连接工作,在2.4之后,会导致主线层延迟比较大,又加入两个新的后台进程来辅助做auxlliary。第三个是demultiplexer,并没有使用我们成熟的这类分解器,而是自己实现的。我没有记错在豆瓣里面也实现,实现代码比较少,功能还是不错的。在我参与的几个项目里,都有用到这个分离器,我认为还是比较优秀的一个模块。

接下来是replication持久化和复制功能,持久让我们可考虑更高,复制可以让我们做一定负载均衡,还能提高高可靠性。最后一点差异,Redis本身需要做一些设计的工作,不像我们只要把数据往里面存就管了,不用管,因为具有一个简单处理结构。Redis可能还要进行数据结构的选型,比如你这个适合做一个链表结构,还是做一个集合结构等。然后我们还需要对内存进行预估,因为Redis是一个全内存集合,不允许部分存在内存里,部分存在磁盘上,必须对内存进行预估,否则会导致数据丢失。

我们来看一个简单Set hello world,在Redis里面是如何进行存储的。首先这个Set hello world命令会在Redis内部产生一个安全结构,内部会包含一个key,就包括一个hell,然后会出现一个指令,都类似于这种结构,还有保存都必不可少。当我们Set hello world以这种形式存储,如果我们是一个Set hello1234567,其实是一个数字类型,是可以被转化成数字类型的。实际上,第二条命令,在Redis内部存储会去掉world,直接转成数字类型传到PDR这个数字结构里面,就可以节省空间。如果我们Redis数据小于Redis本身有一个内部这块会更节省空间,因为我们Redis在启动的时候,会启动从1到1万,如果你用户和他需要的数据是相同,他会进行复用,然后就可以通过引用技术来使用,这样我们可以更减少内存。

我们可以看到假设我们用户一个Set hello world,存储命令只是hello world10个件,这是一个12字节结构,由于2.4版本使用,在加上也是转化16字节,整个Set hello world 就需要64字节,本身内存就比较复杂,这就是一个缺陷。

这是Redis显示的一个链表结构,在List内部一个存储。这里可以看到指向一个双链表,里面有存储元素个数,能够比较快的使用Llan拿到链表长度,都是OE的一种操作,比较快速的。我们再看最常见的这个Zipmap这个数据结构,刚才刘江主编也提到有一个图片公司,前段时间有一个工程师也发了一个博文就讲到他们使用这个Zipmap节省大量内存。Zipmap需要辅助信息是非常少,不像我们刚才10字节需要54字节辅助内存,这个Zipmap整个只需要2个字节辅助,一个是开头Zipmap defect,会额外需要3个字节存储,有2个字节用于存储hello长度,一个是用于储存world长度,比如我修改成一个world单词,这样字节就少了一个字节。Zipmap数据结构是非常丑陋的,当你要多少空间的时候就会弄这么大一个空间,当你也数据修改,就直接把你数据修改掉,把后面空间往前推动,所以这是非常消耗CPU的。

在我们内存比较紧张的情况下,我们把内存作为一个CPU来进行使用。前段时间和新浪的一些同事聊天,说到他们用Zipmap以后,CPU使用率比较高,然后我在和Zipmap创始人交流一下,发现Zipmap有一个问题,本身只用一个字节来储存,一个字节只能有255个长度,是Zipmap这个数据结构本身要使用的。所以,他最大只能使用到253字节,如果你的Zipmap超过530字节就需要变更,一直做循环是比较消耗CPU的。最后作者迫于微博的一些压力,承诺在2.6版本里会把这个Zipmap从一字节变成两字节,真的很不容易。

我们看一下Redis的架构,我就说我这个演讲不太适合那么多人,很适合十几个人线下交流。我们Redis所有的KV结构都会经过一个Rehash计算,进行均分,每一个下面是连接了一个链表。比如说我们Set 一个hello world,再有一个Set命令,进行运算以后也会进行存储,以链表形式连到上一个hello world这个后面。所以,随着Redis数据慢慢增多,当我们要查找的时候就便利,当数据量变大的时候我们性能是会下降的。于是,Redis本身会有一个Rehash功能,以前是4现在变成8,把老的数据迁移到新的上面。

这张图可以看到第一个RehashT0,下面有四个列表,我会产生一个ht1可以释放8个元素,当有查找操作的时候会把ht0里面KV迁移到ht1里面来,当ht0全部被迁移到ht1之后,会把ht0和ht1数据进行一个交互,然后在把ht1给清理掉,ht0就是我们一个新的为8的Rehash表,这就是Rehash的一个过程。我们有一些容量预估的公式,也是经过对源码研究算出来的东西,假设我们存储都是string类型的KV,假如有100个,value是16字节,再加上用户存储K长度,还有haskey,还有SDS5字节长度,随着我这个K增多,bucket,Rehash也一直在扩展,扩展规律是2的恩次方,有了这个预估就能很好预估到我们现有占了多少库存,为以后扩容做准备。

这个Jemalloc的算法大小和上面有点类似,首先计算一下有多少Rehash,加上bucket大小乘以4。内容分配和以前有点不一样,假设我要分配12字节连续内存,实际上在Jemalloc会给你分配16字节长度,这时候当你下一次出现,假如变成14字节,这时候内存分布器会直接把这个指针丢还给你,他大小已经是16字节,他知道你分配没有预分配那么大,客户直接交给你,这样出现的时候性能非常好。还有一个缺陷,当我们程序越界的时候,我们往往就根本不知道了,因为这个空间其实早已经给你分配好了。

接下来讲一下Admin所有参数,这是一个静态文件,启动前需要修改它。在运行过程中我们可以使用动态修改这些参数,其中我认为这四个是比较重要的,一个是maxmemory,限制最大内存减少,可以使用Redis使用操作系统的内存大小,提前防止出现问题。Appendfsync,这个参数作用在Linux操作系统上,我们每一次系统调用并不是把数据写到磁盘上去的,实际上先把数据写到这上面,让我们文件系统正常来说30秒,时间太长了,如果在这个时间点上,操作系统有可能出现丢数据可能星,所以Redis会默认每隔一秒钟可以自动做一个动作,把数据丢失风险降低。

下面是假设我一个hash结构,没有超过512会使用压缩模式,超过512会使用hash表方式,来维持内存结构,比较耗费内存,我们尽量把这个安全都调大一点。但是我们刚才说在253-512之间是比较消耗CPU的,大家需要自己考虑一下。也许在2.6版本之后,Redis结构做一些优化,可能效果会好很多。当一个强度超过64字节,会主动进行转移成hash的格式。

我们介绍一下Redis辅助,本身是做的比较,可以说做的比较粗糙,大概几百行代码,工作原理就是这样。我们在SLAVE发布一个命令,下面跟着一个MASTERIP,建立一个连接,会发送一个SLAVE命令,MASTER收到命令之后,会把一个内存进行一个处理,这个文件会传输到SLAVE端,进行清空,MASTER增量数据,过程中产生的数据按顺序传递到SLAVE端,这个就是整个MASTER和SLAVE的一个原理。

为什么说复制功能比较丑陋呢?首先有两点缺陷,第一点当网络某点出现中断的时候,互相认为是不可控的,当网络发生控制的时候会重新建立连接,就需要重传文件,这是比较消耗资源,特别是在网络时断时不断的时候,发现MASTER五比较繁忙一些。有哪些数据在MASTER尚没有传输到SLAVE上,假如MASTER宕掉,把上面的数据进行手工操作,如果我们应该都在做这个工作,给每条数据都做一个标记,能够清楚主备之间差异,如果我们做切换会导致两边数据不一致,会导致丢数据。

我们再来看Redis持久化工作,有两种持久化方法。第一就是做Snapshot,因为是一个连续大IO的措施。实际上具有一个潜在问题,因为我们知道,我们在Linux操作系统上写一个大文件,这个大文件,Linux系统会不由自主让你把这个数据文件写到DIRECT,会导致主内存换进换出。所以,我们推荐把这块代码做一点修改,打开文件的时候我们利用这个方法,减少对主内存影响。

接下来是Aof文件,未来也是Redis主推的持久化方法。因为我们刚才说的快照其实有很多缺陷,因为快照需要我们手工,或者自动满足条件下触发快照,如果处理不好会丢数据,Aof会把变化的数据进行记录在文件里面,会把Aof数据全部进行保存。理论上来讲,只有一秒钟丢数据的可能性,就是我们刚才说了Aof的另一种模式。

在2.4版本之后,又引发了很多一些问题,也不是2.4版本,以前版本有很多问题。我们刚才也说了因为还需要删除老的Aof文件,会严重影响。在Redis启动的时候,会自动启动这两个现场,就是两个List会接受Auxiliary会把这个队列数据读出来,这样的话我们主现场就需要做Aof文件操作,其实这两个操作是互式,都会拿一把互式锁,实际上这是相互制约的。于是在2.4版本又引入一个延迟Fsync,等后台做完以后再把这个数据写到这个文件里面去。

这个Postpone fsync上线2秒钟,在2.4版本之后,最大有可能丢两秒钟的数据,我觉得有是一个提高了Redis性能,增加了一些风险。这是我们拿Redis进行比较,我们先看登录用户表,记录用户IT,记录登录次数和最后时间,所有数据都是以对表结构实现,让所有字段都是以同样规律存放,当我们有这样两个需求,我要取得对于一个登录人是谁,开发看了比较简单,我们在这个上面取,这个需求就这么搞定了。某一天这个PDU说我再提一个需求,我看一下登录次数最多的人,这个也不复杂,就能知道最后登录次数,之后再建一个索引。

每次我们有新需求的时候,都需要去进入,建索引,会影响统计计划,会影响执行计划。我们不知道这里有没有,在阿里80%都是因为这个所搭建的,建索引实际上是很有风险的一个东西。所以,我们关系型数据库每次上线一个小小需求都存在这样风险,这是不是关系型数据库存在一定缺陷,是不是不太适合我们灵活变化场景,他的存储是不是有点太呆板了。实际上我们并不以行式存储,可以以劣势存储,在这里面怎么来实现这个功能?因为题要求最后登录的人,我们可以把这个放在一个先进先出的队列里面,可以看到当用户一登录的时候我们就可以看到一个push一个用户1,用户2,用户3。这样一个设计因为不需要索引,不会影响我们现有业务,对我们现有业务冲击是非常小的,而且也是非常简单,我们代码写起来应该算是比较优雅,没有什么太大风险。

对于用户登录次数也可以用Login来实现,上面加了很多字段看起来很别扭,但是用起来还是不错。我们先把用户1登录2次等等,怎么取得哪个用户登录最多,只需要运用一个zrangebyscore,就可以拿到用户登录次数最多的一个人。根据这个case,就想这个是不是都能存储每一个不同格式,因为每个列格式都不一样,不能都按照对表形式去存储,每个列当中要取最大值最小值都需要建索引,所以有时候关系型数据库还真是比较不适合。

虽然我做了好几年DBA工作,也觉得关系型数据库需要和NoSQL结合使用,这样我们业务可以做的更好。这里总结一下Suitable scene场景。轻量级高性能消息从队列服务,生产者消费者,跨机器共享内存,实际上我们把数据都存储在这个Redis里,我们连网络层都不用写了,直接从Redis里读数据,往里加数据,另外一个进程也从这里填数据,加数据,我们代码非常简单只要读取Redis操作,这里数据结构都不需要自己设计了,代码非常短。然后第三是Redis特性,是一个数据能量受物理性能限制,Redis本身是一个小数据的东西,今天大会是一个大数据,我不知道我来这里合不合适。本身也不具备扩展的功能,扩展3.0版本里面Redis会做,总结起来就适合较小的数据,高性能操作和运算,微博,一些新闻,需要重复操作的数据,在生命到期可以参与到里面,最好能够跟别的关系型数据库一块使用,这样用起来数据又快,持久化的工作就会交给Redis去做。

你可能感兴趣的:(redis)