基本介绍html
Redis是一种key-value存储形式的非关系型数据库,也是一个强大的内存型存储系统,可是它比传统的Memcached 更灵活,支持更多的数据类型,同时也能够持久化。据官方数据表示Redis读的速度是110000次/s,写的速度是81000次/s 。并且Redis支持数据持久化,众多数据结构存储,master-slave模式数据备份等多种功能。java
支持的数据类型web
先经过一张图了解下Redis内部内存管理中是如何描述这些不一样数据类型的:redis
首先Redis内部使用一个redisObject对象来表示全部的key和value,redisObject最主要的信息如上图所示:type表明一个value对象具体是何种数据类型,encoding是不一样数据类型在redis内部的存储方式,好比:type=string表明value存储的是一个普通字符串,那么对应的encoding能够是raw或者是int,若是是int则表明实际redis内部是按数值型类存储和表示这个字符串的,固然前提是这个字符串自己能够用数值表示,好比:"123" "456"这样的字符串。sql
这里须要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。经过上图咱们能够发现Redis使用redisObject来表示全部的key/value数据是比较浪费内存的,固然这些内存管理成本的付出主要也是为了给Redis不一样数据类型提供一个统一的管理接口,实际做者也提供了多种方法帮助咱们尽可能节省内存使用。数据库
Stringapi
String数据结构是简单的key-value类型,value其实不只是String,也能够是数字。缓存
经常使用命令:get、set、incr、decr、mget等。ruby
应用场景:String是最经常使用的一种数据类型,普通的key/ value 存储均可以归为此类,便可以彻底实现目前 Memcached 的功能,而且效率更高。还能够享受Redis的定时持久化,操做日志及 Replication等功能。除了提供与 Memcached 同样的get、set、incr、decr 等操做外,Redis还提供了下面一些操做:数据结构
Hash
在Memcached中,咱们常常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值,好比用户的昵称、年龄、性别、积分等,这时候在须要修改其中某一项时,一般须要将全部值取出反序列化后,修改某一项的值,再序列化存储回去。这样不只增大了开销,也不适用于一些可能并发操做的场合(好比两个并发的操做都须要修改积分)。而Redis的Hash结构可使你像在数据库中Update一个属性同样只修改某一项属性值。
经常使用命令:hget,hset,hgetall 等。
应用场景:
咱们简单举个实例来描述下Hash的应用场景,好比咱们要存储一个用户信息对象数据,包含如下信息:
用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,若是用普通的key/value结构来存储,主要有如下2种存储方式:
第一种方式将用户ID做为查找key,把其余信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增长了序列化/反序列化的开销,而且在须要修改其中一项信息时,须要把整个对象取回,而且修改操做须要对并发进行保护,引入CAS等复杂问题。
第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称做为惟一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,可是用户ID为重复存储,若是存在大量这样的数据,内存浪费仍是很是可观的。
那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,以下图:
也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取均可以直接经过其内部Map的Key(Redis里称内部Map的key为field), 也就是经过 key(用户ID) + field(属性标签) 就能够操做对应属性数据了,既不须要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。
这里同时须要注意,Redis提供了接口(hgetall)能够直接取到所有的属性数据,可是若是内部Map的成员不少,那么涉及到遍历整个内部Map的操做,因为Redis单线程模型的缘故,这个遍历操做可能会比较耗时,而另其它客户端的请求彻底不响应,这点须要格外注意。
List
经常使用方法:
Lists 就是链表,略有数据结构知识的人都应该能理解其结构。使用Lists结构,咱们能够轻松地实现最新消息排行等功能。Lists的另外一个应用就是消息队列,能够利用Lists的PUSH操做,将任务存在Lists中,而后工做线程再用POP操做将任务取出进行执行。Redis还提供了操做Lists中某一段的api,你能够直接查询,删除Lists中某一段的元素。
Redis的list是每一个子元素都是String类型的双向链表,能够经过push和pop操做从列表的头部或者尾部添加或者删除元素,这样List便可以做为栈,也能够做为队列。
Sets 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构,能够存储一些集合性的数据。
Set是集合,是String类型的无序集合,set是经过hashtable实现的,概念和数学中个的集合基本相似,能够交集,并集,差集等等,set中的元素是没有顺序的。
经常使用方法:
和Sets相比,Sorted Sets增长了一个权重参数score,使得集合中的元素可以按score进行有序排列,好比一个存储全班同窗成绩的Sorted Sets,其集合value能够是同窗的学号,而score就能够是其考试得分,这样在数据插入集合的时候,就已经进行了自然的排序。能够用Sorted Sets来作带权重的队列,好比普通消息的score为1,重要消息的score为2,而后工做线程能够选择按score的倒序来获取工做任务。让重要的任务优先执行。
经常使用方法:
pub/sub
发布订阅,相似于消息队列mq。能够选择对某个Key进行订阅,一旦这个key发布了一些消息,则全部订阅了这个Key的对象就能够收到这个消息。主要能够用在实时消息系统上,例如聊天之类的。
Transactions
NoSQL不支持事务,可是经过提供了打包执行的功能,即这个包里面的全部命令必需要一块儿执行,此外还能够锁定某个Key,在打包执行命令时若是检测到这个Key发生了变化,则直接回滚。
持久化方案
redis默认开启的RDB持久化方式,可是若是开始了AOF方式,那么在系统重启时优先冲AOF文件中回复数据
数据淘汰策略
长期将Redis做为缓存使用,不免会遇到内存空间存储瓶颈,当Redis内存超出物理内存限制时,内存数据就会与磁盘产生频繁交换,使Redis性能急剧降低。此时如何淘汰无用数据释放空间,存储新数据就变得尤其重要了。对此,Redis在生产环境中,采用配置参数maxmemory 的方式来限制内存大小。当实际存储内存超出maxmemory 参数值时会执行配置的淘汰策略。Redis 肯定驱逐某个键值对后,会删除这个数据,并将这个数据变动消息发布到本地(AOF 持久化)和从机(主从链接)。可是咱们要注意redis的删除策略和淘汰策略是有区别的。
优缺点
优势:
缺点:
redis和memcached的区别
使用注意点
使用场景
String
适用场景:适合最简单的k-v存储,相似于memcached的存储结构,短信验证码,配置信息等,就用这种类型来存储。
案例:1.微博数,粉丝数,
hash
适用场景:通常key为ID或者惟一标示,value对应的就是详情了。如商品详情,我的信息详情,新闻详情等。
案例:1.存储部分变动数据,如用户信息等
List
适用场景:由于list是有序的,比较适合存储一些有序且数据相对固定的数据。如省市区表、字典表等。由于list是有序的,适合根据写入的时间来排序,如:最新的***,消息队列等
案例:
1.在Redis中咱们的最新微博ID使用了常驻缓存,这是一直更新的。可是咱们作了限制不能超过5000个ID,所以咱们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才须要去访问数据库。咱们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其余类型数据库)只是在用户须要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
取最新N个数据的操做: 记录前N个最新登录的用户Id列表,超出的范围能够从数据库中得到。 //把当前登陆人添加到链表里 ret = r.lpush("login:last_login_times", uid) //保持链表只有N位 ret = redis.ltrim("login:last_login_times", 0, N-1) //得到前N个最新登录的用户Id列表 last_login_list = r.lrange("login:last_login_times", 0, N-1)
Sets
适用场景:能够简单的理解为ID-List的模式,如微博中一我的有哪些好友,set最牛的地方在于,能够对两个set提供交集、并集、差集操做。例如:查找两我的共同的好友等。
案例:
1.在微博应用中,能够将一个用户全部的关注人存在一个集合中,将其全部粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操做,能够很是方便的实现如共同关注、共同喜爱、二度好友等功能,对上面的全部集合操做,你还可使用不一样的命令选择将结果返回给客户端仍是存集到一个新的集合中。
交集,并集,差集:(Set) //book表存储book名称 set book:1:name ”The Ruby Programming Language” set book:2:name ”Ruby on rail” set book:3:name ”Programming Erlang” //tag表使用集合来存储数据,由于集合擅长求交集、并集 sadd tag:ruby 1 sadd tag:ruby 2 sadd tag:web 2 sadd tag:erlang 3 //即属于ruby又属于web的书? inter_list = redis.sinter("tag.web", "tag:ruby") //即属于ruby,但不属于web的书? inter_list = redis.sdiff("tag.ruby", "tag:web") //属于ruby和属于web的书的合集? inter_list = redis.sunion("tag.ruby", "tag:web") 获取某段时间全部数据去重值,这个使用Redis的set数据结构最合适了,只须要不断地将数据往set中扔就好了,set意为集合,因此会自动排重。
Sorts sets
适用场景:是set的加强版本,增长了一个score参数,自动会根据score的值进行排序。比较适合相似于top 10等不根据插入的时间来排序的数据。
案例:排行榜应用,取TOP N操做
使用: //将登陆次数和用户统一存储在一个sorted set里 zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3 ZADD key score member //当用户登陆时,对该用户的登陆次数自增1 ret = r.zincrby("login:login_times", 1, uid) //那么如何得到登陆次数最多的用户呢,逆序排列取得排名前N的用户 ret = r.zrevrange("login:login_times", 0, N-1) ZREVRANGE key start stop [WITHSCORES]
Redis集群
学习连接