配色: 字号:
redis介绍
2017-03-31 | 阅:  转:  |  分享 
  
Redis介绍林超旗2011.10.16主要内容简介与配置特性数据类型持久化机制及问题主从复制及问题命令总结思考简介
与配置Redis官网是这么描述的:Redisisanopensource,advancedkey-valuest
ore.Itisoftenreferredtoasadatastructureserversincekey
scancontainstrings,hashes,lists,setsandsortedsets.Redi
s是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
从2010年3月15日起,Redis的开发工作由VMware主持。启动流程及处理流程:http://blog.nosqlfan.
com/html/1413.html启动流程命令处理流程daemonize:是否以后台daemon方式运行pidfil
e:pid文件位置port:监听的端口号,默认端口号是6379timeout:请求超时时间loglevel:log信息
级别logfile:log文件位置databases:开启数据库的数量save:保存快照的频率,第一个表示多
长时间,第三个表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。rdbcompress
ion:是否使用压缩dbfilename:数据快照文件名(只是文件名,不包括目录)dir:数据快照的保存目录(这个是目录)
appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率
。appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次f
sync、不调用fsync等待系统自己同步)#Redis的复制配置#slaveofrt>#masterauth#连接时所需的密码#requirepassfoobar
ed#最大客户端连接数#maxclients128#最大内存使用率maxmemory设置最大内存,达
到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。Re
dis特性速度快 Redis使用标准C编写实现,而且将所有数据加载到内存中,所以速度非常快。官方提供的数据表明,在一个普通的L
inux机器上,Redis读写速度分别达到81000/s和110000/s。持久化 由于所有数据保持在内存中(2.0版本开始可
以只将部分数据的value放在内存,见“虚拟内存”),所以对数据的更新将异步地保存到磁盘上,Redis提供了一些策略来保存数据,比
如根据时间或更新次数。数据结构 可以将Redis看做“数据结构服务器”。目前,Redis支持5种数据结构。自动操作 Red
is对不同数据类型的操作是自动的,因此设置或增加key值,从一个集合中增加或删除一个元素都能安全的操作。支持多种语言 Redi
s支持多种语言,诸如Ruby,Python,TwistedPython,PHP,Erlang,Tcl,Perl,L
ua,Java,Scala,Clojure等。主-从复制 Redis支持简单而快速的主-从复制。官方提供了一个数据,Sl
ave在21秒即完成了对Amazon网站10Gkeyset的复制。Sharding 很容易将数据分布到多个Redis实例中
,但这主要看该语言是否支持。目前支持Sharding功能的语言只有PHP、Ruby和Scala。数据类型及操作方法string
(字符串)list(双向链表)set(无序集合)zset(有序集合)hash(hash表)string类型string
是redis最基本的类型,而且string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序
列化的对象从内部实现来看其实string可以看作byte数组,最大上限是1G字节string类型的值也可视为integer,从
而可以让“incr”命令族操作,这种情况下,该integer的值限制在64位有符号数在list、set和zset中包含的独立的元
素类型都是string类型list类型redis的list类型其实就是一个每个子元素都是string类型的双向链表,所以[l
r]push和[lr]pop命令的算法时间复杂度都是O(1),另外list会记录链表的长度,所以llen操作也是O(1).可以通
过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列list的最大长度是2^32-
1个元素set类型set就是redisstring的无序集合,不允许有重复元素set的最大元素数是2^32-1对set的
操作还有交集、并集、差集等zset类型zset是set的一个升级版本,在set的基础上增加了一个顺序属性,这一属性在添加修改
元素时可以指定,每次指定后zset会自动安装指定值重新调整顺序。可以理解为一张表,一列存value,一列存顺序。操作中的key理解
为zset的名字。zset的最大元素数是2^32-1。对于已经有序的zset,仍然可以使用sort命令,通过指定asc|des
c参数对其进行排序。hash类型redisHash类型对数据域和值提供了映射,这一结构很方便表示对象在Hash中可以只保存
有限的几个“域”,而不是将所有的“域”作为key,这可以节省内存持久化机制redis一共支持四种持久化方式,分别是:定时快照
方式(snapshot)——默认方式基于语句追加文件的方式(aof)虚拟内存(vm)——已放弃Diskstore方式
——实验中前两种是基于全部数据都在内存中,即小数据量下提供磁盘落地功能后两种方式则是作者在尝试存储数据超过物理内存时,即大数据
量的数据存储,后两种持久化方式仍然是在实验阶段,并且vm方式基本已经被作者放弃实际能在生产环境用的只有前两种,换句话说redis
目前还只能作为小数据量存储(全部数据能够加载在内存中),海量数据存储方面并不是redis所擅长的领域定时快照方式(snapsho
t)快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配
置设置自动做快照持久化的方式。可以配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置save
9001#900秒内如果超过1个key被修改,则发起快照保存save30010#300秒内容如超过10个key被修改
,则发起快照保存save6010000client也可以使用save或者bgsave命令通知redis做一次快照持久化。
save操作是在主线程中保存快照的,由于redis是用一个主线程来处理所有client的请求,这种方式会阻塞所有client请求
,所以不推荐使用;每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必
然会引起大量的磁盘io操作,可能会严重影响性能。另外由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,
就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof持久化方式保存过程如下 1.redis调
用fork,现在有子进程和父进程。 2.父进程继续处理client请求,子进程负责将内存内容写入到临时文件。由于os的写时复制
机制(copyonwrite)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共
享的页面。所以子进程的地址空间内的数据是fork时刻整个数据库的一个快照。 3.当子进程将快照写入临时文件完毕后,用临时文件替
换原来的快照文件,然后子进程退出。缺点是定时快照只是代表一段时间内的内存映像,所以系统重启会丢失上次快照与重启之间所有的数据
。基于语句追加方式(aof)aof比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命
令都通过write函数追加到文件中(默认是appendonly.aof)。当redis重启时会通过重新执行文件中保存的写命令来在
内存中重建整个数据库的内容。当然由于os会在内核中缓存write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还
是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis我们想要通过fsync函数强制os写入到磁盘的时机。有三种方式如
下(默认是:每秒fsync一次)appendonlyyes//启用aof持久化方式#appen
dfsyncalways//每次收到写命令就立即写盘,最慢,但保证完全的持久化,不推荐使用appendfsyncev
erysec//每秒钟强制写入磁盘一次,推荐#appendfsyncno//完全依赖os,性能最好,持久化没
保证持久化文件会变的越来越大。例如我们调用incrtest命令100次,文件中必须保存全部的100条命令,其实有99条都是多余
的。因为要恢复数据库的状态其实文件中保存一条settest100就够了。为了压缩aof的持久化文件。redis提供了bgrew
riteaof命令。收到此命令redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。
保存过程如下 1.redis调用fork,现在有父子两个进程 2.子进程根据内存中的数据库快照,往临时文件中写入重建数据
库状态的命令 3.父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证
如果子进程重写失败的话并不会出问题。 4.当子进程把快照内容以命令方式写入临时文件中后,子进程发信号通知父进程。然后父进程把缓存
的写命令也写入到临时文件。 5.现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中
追加。缺点log文件体积过大时系统重启恢复数据非常慢,几十G的数据可能要几小时才能加载完;每条命令都要写log,读写性能会有所
下降虚拟内存(vm)虚拟内存方式是Redis来进行用户空间的数据换入换出的一个策略,此种方式在实现的效果上比较差,主要问题是
代码复杂,重启慢,复制慢等等,目前已经被作者放弃。diskstore方式diskstore方式是作者放弃了虚拟内存方式后选择的
一种新的实现方式,也就是传统的B-tree的方式,目前仍在实验阶段,后续是否可用我们可以拭目以待。持久化磁盘IO方式及问题用
户态与内核态 CPU来说一共有0~3四个特权级,0级最高,3级最低,对于Unix/Linux来说,只使用了0级特权级和3级特权级
,当程序运行在3级特权级上时,就可以称之为运行在用户态,当程序运行在0级特权级上时,就可以称之为运行在内核态 一条工作在0级特权
级的指令具有了CPU能提供的最高权力,而一条工作在3级特权级的指令具有CPU提供的最低或者说最基本权力 虽然用户态下和内核态下工
作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序b
ufferio bufferio实现起来比较简单,该机制在用户态与内核态进行数据交互时需要进行数据拷贝操作,如果应用涉及到大
量数据传输任务,那么bufferio的效率将很低directio directio机制应用了虚拟内存映射机制,可以将用户
态虚拟内存映射块重映射到内核地址空间,这样用户态的某段地址和内核态的某段地址映射到了相同的物理块,内核空间和用户空间在交互数据时就
无需数据拷贝了,这种模式在IO的效率上最高redis的持久化使用了bufferioRedis对持久化文件的写入和读取操作都
会使用物理内存的PageCache,而大多数数据库系统会使用DirectIO来绕过这层PageCache并自行维护一个数据的
Cache,而当Redis的持久化文件过大(尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内存中作为操作系统
对该文件的一层Cache,而这层Cache的数据与Redis内存中管理的数据实际是重复存储的,虽然内核在物理内存紧张时会做Page
Cache的剔除工作,但内核很可能认为某块PageCache更重要,而让你的进程开始Swap,这时你的系统就会开始出现不稳定
或者崩溃了经验:当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了由于fork调用的内存会采用操作系统的CO
W机制,所以内存不会马上加倍,只有在最坏的情况下,也就是在dump的时候主进程中的数据完全被修改了才COPY出两倍的内存来主从
复制Redis的复制功能是完全建立在基于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redi
s的复制功能,就一定会有内存快照发生,那么首先要注意你的系统内存容量规划——物理内存使用量不要超过3/5配置slave服务器很简
单,只需要在配置文件中加入如下配置slaveof192.168.1.16379#指定master的ip和端口下面是关
于redis主从复制的一些特点1.master可以有多个slave2.除了多个slave连到相同的master外,slave也
可以连接其他slave形成图状结构3.主从复制不会阻塞master。也就是说当一个或多个slave与master进行初次同步数据
时,master可以继续处理client发来的请求。相反slave在初次同步数据时则会阻塞不能处理client的请求。4.主从复
制可以用来提高系统的可伸缩性,我们可以用多个slave专门用于client的读请求,比如sort操作可以使用slave来处理。也
可以用来做简单的数据冗余5.可以在master禁用数据持久化,只需要注释掉master配置文件中的所有save配置,然后只在s
lave上配置数据持久化。主从复制的过程当设置好slave服务器后,slave会建立和master的连接,然后发送sync命
令。无论是第一次同步建立的连接还是连接断开后的重新连接,master都会启动一个后台进程,将数据库快照保存到文件中,同时mas
ter主进程会开始收集新的写命令并缓存起来。后台进程完成写文件后,master就发送文件给slave,slave将文件保存到磁盘
上,然后加载到内存恢复数据库快照到slave上。接着master就会把缓存的命令转发给slave。而且后续master收到的写
命令都会通过开始建立的连接发送给slave。从master到slave的同步数据的命令和从client发送的命令使用相同的协议
格式。当master和slave的连接断开时slave可以自动重新建立连接。如果master同时收到多个slave发来的同步连接
命令,只会使用启动一个进程来写数据库镜像,然后发送给所有slave。Redis复制流程在Slave和Master端各自是一套状态
机流转,涉及的状态信息是:Slave端:REDIS_REPL_NONEREDIS_REPL_CONNECTREDIS_R
EPL_CONNECTEDMaster端:REDIS_REPL_WAIT_BGSAVE_STARTREDIS_REPL_W
AIT_BGSAVE_ENDREDIS_REPL_SEND_BULKREDIS_REPL_ONLINE整个状态机流程过程如下
:Slave端在配置文件中添加了slaveof指令,于是Slave启动时读取配置文件,初始状态为REDIS_REPL_CONN
ECT。Slave端在定时任务serverCron(Redis内部的定时器触发事件)中连接Master,发送sync命令,然后
等待master发送回其内存快照文件。Master端收到sync命令简单判断是否有正在进行的内存快照子进程,没有则立即开始内存
快照,有则等待其结束,当快照完成后会将该文件发送给Slave端。Slave端接收Master发来的内存快照文件,保存到本地,待
接收完成后,清空内存表,重新读取Master发来的内存快照文件,重建整个内存表数据结构,并最终状态置位为REDIS_REPL_C
ONNECTED状态,Slave状态机流转完成。Master端在发送快照文件过程中,接收的任何会改变数据集的命令都会暂时先保存
在Slave网络连接的发送缓存队列里(list数据结构),待快照完成后,依次发给Slave,之后收到的命令相同处理,并将状态置位为
REDIS_REPL_ONLINE。Redis复制机制的缺陷Slave从库在连接Master主库时,Master会进行内存
快照,然后把整个快照文件发给Slave,也就是没有象MySQL那样有复制位置的概念,即无增量复制,这会给整个集群搭建带来非常多的问
题比如一台线上正在运行的Master主库配置了一台从库进行简单读写分离,这时Slave由于网络或者其它原因与Master断开了连
接,那么当Slave进行重新连接时,需要重新获取整个Master的内存快照,Slave所有数据跟着全部清除,然后重新建立整个内存表
,一方面Slave恢复的时间会非常慢,另一方面也会给主库带来压力改进方法参考:http://www.infoq.com/cn/
articles/tq-redis-copy-build-scalable-cluster命令总结连接操作相关的命令对val
ue操作的命令对String操作的命令对List操作的命令对Set操作的命令对zset(sortedset)操作的命令
对Hash操作的命令持久化远程服务控制对value操作的命令exists(key):确认一个key是否存在del(key
):删除一个keytype(key):返回值的类型keys(pattern):返回满足给定pattern的所有keyrand
omkey:随机返回key空间的一个keyrename(oldname,newname):将key由oldname重命名为ne
wname,若newname存在则删除newname表示的keydbsize:返回当前数据库中key的数目expire:设定一
个key的活动时间(s)ttl:获得一个key的活动时间select(index):按索引查询move(key,dbind
ex):将当前数据库中的key转移到有dbindex索引的数据库flushdb:删除当前选择数据库中的所有keyflushal
l:删除所有数据库中的所有key对String操作的命令set(key,value):给数据库中名称为key的string赋
予值valueget(key):返回数据库中名称为key的string的valuegetset(key,value):给名称
为key的string赋予上一次的valuemget(key1,key2,…,keyN):返回库中多个string(它们的
名称为key1,key2…)的valuesetnx(key,value):如果不存在名称为key的string,则向库中添加s
tring,名称为key,值为valuesetex(key,time,value):向库中添加string(名称为key,值
为value)同时,设定过期时间timemset(key1,value1,key2,value2,…keyN,valu
eN):同时给多个string赋值,名称为keyi的string赋值valueimsetnx(key1,value1,
key2,value2,…keyN,valueN):如果所有名称为keyi的string都不存在,则向库中添加strin
g,名称keyi赋值为valueiincr(key):名称为key的string增1操作incrby(key,integ
er):名称为key的string增加integerdecr(key):名称为key的string减1操作decrby(key
,integer):名称为key的string减少integerappend(key,value):名称为key的strin
g的值附加valuesubstr(key,start,end):返回名称为key的string的value的子串对List
操作的命令rpush(key,value):在名称为key的list尾添加一个值为value的元素lpush(key,va
lue):在名称为key的list头添加一个值为value的元素llen(key):返回名称为key的list的长度lran
ge(key,start,end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)ltrim
(key,start,end):截取名称为key的list,保留start至end之间的元素lindex(key,inde
x):返回名称为key的list中index位置的元素lset(key,index,value):给名称为key的list中
index位置的元素赋值为valuelrem(key,count,value):删除count个名称为key的list中值为
value的元素。count为0,删除所有值为value的元素,count>0从头至尾删除count个值为value的元素,cou
nt<0从尾到头删除|count|个值为value的元素。lpop(key):返回并删除名称为key的list中的首元素rpo
p(key):返回并删除名称为key的list中的尾元素blpop(key1,key2,…keyN,timeout):l
pop命令的block版本。即当timeout为0时,若遇到名称为keyi的list不存在或该list为空,则命令结束。如果ti
meout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对keyi+1开始的list执行pop操作。brp
op(key1,key2,…keyN,timeout):rpop的block版本。参考上一命令。rpoplpush(sr
ckey,dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部对
Set操作的命令sadd(key,member):向名称为key的set中添加元素membersrem(key,membe
r):删除名称为key的set中的元素memberspop(key):随机返回并删除名称为key的set中一个元素smov
e(srckey,dstkey,member):将member元素从名称为srckey的集合移到名称为dstkey的集合s
card(key):返回名称为key的set的基数sismember(key,member):测试member是否是名称为
key的set的元素sinter(key1,key2,…keyN):求交集sinterstore(dstkey,key
1,key2,…keyN):求交集并将交集保存到dstkey的集合sunion(key1,key2,…keyN):求
并集sunionstore(dstkey,key1,key2,…keyN):求并集并将并集保存到dstkey的集合sd
iff(key1,key2,…keyN):求差集sdiffstore(dstkey,key1,key2,…keyN)
:求差集并将差集保存到dstkey的集合smembers(key):返回名称为key的set的所有元素srandmembe
r(key):随机返回名称为key的set的一个元素对zset(sortedset)操作的命令zadd(key,scor
e,member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新
该元素的顺序。zrem(key,member):删除名称为key的zset中的元素memberzincrby(key,i
ncrement,member):如果在名称为key的zset中已经存在元素member,则该元素的score增加increm
ent;否则向集合中添加该元素,其score的值为incrementzrank(key,member):返回名称为key的z
set(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“ni
l”zrevrank(key,member):返回名称为key的zset(元素已按score从大到小排序)中member元素
的rank(即index,从0开始),若没有member元素,返回“nil”zrange(key,start,end):返回
名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素zrevrange(key,
start,end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素
zrangebyscore(key,min,max):返回名称为key的zset中score>=min且score<=
max的所有元素zcard(key):返回名称为key的zset的基数zscore(key,element):返回名称为k
ey的zset中元素element的scorezremrangebyrank(key,min,max):删除名称为key的z
set中rank>=min且rank<=max的所有元素zremrangebyscore(key,min,max)
:删除名称为key的zset中score>=min且score<=max的所有元素zunionstore/zinte
rstore(dstkeyN,key1,…,keyN,WEIGHTSw1,…wN,AGGREGATESUM|MIN|MA
X):对N个zset求并集和交集,并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score,在进行AGGREGATE
运算前,都要乘以对于的WEIGHT参数。如果没有提供WEIGHT,默认为1。默认的AGGREGATE是SUM,即结果集合中元素的s
core是所有集合对应元素进行SUM运算的值,而MIN和MAX是指,结果集合中元素的score是所有集合对应元素中最小值和最大值。
对Hash操作的命令hset(key,field,value):向名称为key的hash中添加元素field<—>valu
ehget(key,field):返回名称为key的hash中field对应的valuehmget(key,field1,
…,fieldN):返回名称为key的hash中fieldi对应的valuehmset(key,field1,valu
e1,…,fieldN,valueN):向名称为key的hash中添加元素fieldi<—>valueihincrby
(key,field,integer):将名称为key的hash中field的value增加integerhexists(k
ey,field):名称为key的hash中是否存在键为field的域hdel(key,field):删除名称为key的ha
sh中键为field的域hlen(key):返回名称为key的hash中元素个数hkeys(key):返回名称为key的has
h中所有键hvals(key):返回名称为key的hash中所有键对应的valuehgetall(key):返回名称为key的
hash中所有的键(field)及其对应的value持久化save:将数据同步保存到磁盘bgsave:将数据异步保存到磁盘
lastsave:返回上次成功将数据保存到磁盘的Unix时戳shundown:将数据同步保存到磁盘,然后关闭服务远程服务控制info:提供服务器的信息和统计monitor:实时转储收到的请求slaveof:改变复制策略设置config:在运行时配置Redis服务器连接操作相关的命令quit:关闭连接(connection)auth:简单密码认证命令使用举例:http://redis.readthedocs.org/en/latest/index.html命令手册:http://redis.io/commands思考应用场景http://www.infoq.com/cn/articles/tq-why-choose-redishttp://blog.nosqlfan.com/html/2925.htmlhttp://blog.nosqlfan.com/html/2235.html如何设计键值http://blog.nosqlfan.com/html/3033.htmlhttp://blog.nosqlfan.com/html/3033.html如何集群化http://blog.nosqlfan.com/html/3302.html监控&运维http://blog.nosqlfan.com/html/2692.htmlhttp://blog.nosqlfan.com/html/324.html其它http://timyang.net/data/redis-capacity/http://timyang.net/data/redis-misunderstanding/http://blog.nosqlfan.com/html/1282.htmlhttp://blog.nosqlfan.com/html/1413.htmlhttp://simonwillison.net/static/2010/redis-tutorial/Page?Page?
献花(0)
+1
(本文系关平藏书首藏)