Memcached与Redis(二)

2.2 Redis的经常使用数据类型html

与Memcached仅支持简单的key-value结构的数据记录不一样,Redis支持的数据类型要丰富得多。最为经常使用的数据类型主要由五种:String、Hash、List、Set和Sorted Set。在具体描述这几种数据类型以前,咱们先经过一张图来了解下Redis内部内存管理中是如何描述这些不一样数据类型的。redis

谈谈Memcached与Redis(二)

                        图1 Redis对象数据库

Redis内部使用一个redisObject对象来表示全部的key和value。redisObject最主要的信息如图1所示:type表明一个value对象具体是何种数据类型,encoding是不一样数据类型在redis内部的存储方式,好比:type=string表明value存储的是一个普通字符串,那么对应的encoding能够是raw或者是int,若是是int则表明实际redis内部是按数值型类存储和表示这个字符串的,固然前提是这个字符串自己能够用数值表示,好比:"123" "456"这样的字符串。这里须要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。经过Figure1咱们能够发现Redis使用redisObject来表示全部的key/value数据是比较浪费内存的,固然这些内存管理成本的付出主要也是为了给Redis不一样数据类型提供一个统一的管理接口,实际做者也提供了多种方法帮助咱们尽可能节省内存使用。下面咱们先来逐一的分析下这五种数据类型的使用和内部实现方式。数组

1)String安全

经常使用命令:set/get/decr/incr/mget等;数据结构

应用场景:String是最经常使用的一种数据类型,普通的key/value存储均可以归为此类;app

实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等操做时会转成数值型进行计算,此时redisObject的encoding字段为int。ide

2)Hash性能

经常使用命令:hget/hset/hgetall等url

应用场景:咱们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,经过用户ID咱们但愿获取该用户的姓名或者年龄或者生日;

实现方式:Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如图2所示,Key是用户ID, value是一个Map。这个Map的key是成员的属性名,value是属性值。这样对数据的修改和存取均可以直接经过其内部Map的Key(Redis里称内部Map的key为field), 也就是经过 key(用户ID) + field(属性标签) 就能够操做对应属性数据。当前HashMap的实现有两种方式:当HashMap的成员比较少时Redis为了节省内存会采用相似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

谈谈Memcached与Redis(二)

图2 Redis的Hash数据类型

3)List

经常使用命令:lpush/rpush/lpop/rpop/lrange等;

应用场景:Redis list的应用场景很是多,也是Redis最重要的数据结构之一,好比twitter的关注列表,粉丝列表等均可以用Redis的list结构来实现;

实现方式:Redis list的实现为一个双向链表,便可以支持反向查找和遍历,更方便操做,不过带来了部分额外的内存开销,Redis内部的不少实现,包括发送缓冲队列等也都是用的这个数据结构。

4)Set

经常使用命令:sadd/spop/smembers/sunion等;

应用场景:Redis set对外提供的功能与list相似是一个列表的功能,特殊之处在于set是能够自动排重的,当你须要存储一个列表数据,又不但愿出现重复数据时,set是一个很好的选择,而且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的;

实现方式:set 的内部实现是一个 value永远为null的HashMap,实际就是经过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的缘由。

5)Sorted Set

经常使用命令:zadd/zrange/zrem/zcard等;

应用场景:Redis sorted set的使用场景与set相似,区别是set不是自动有序的,而sorted set能够经过用户额外提供一个优先级(score)的参数来为成员排序,而且是插入有序的,即自动排序。当你须要一个有序的而且不重复的集合列表,那么能够选择sorted set数据结构,好比twitter 的public timeline能够以发表时间做为score来存储,这样获取时就是自动按时间排好序的。

实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是全部的成员,排序依据是HashMap里存的score,使用跳跃表的结构能够得到比较高的查找效率,而且在实现上比较简单。

2.3 Redis的持久化

Redis虽然是基于内存的存储系统,可是它自己是支持内存数据的持久化的,并且提供两种主要的持久化策略:RDB快照和AOF日志。咱们会在下文分别介绍这两种不一样的持久化策略。

2.3.1 Redis的RDB快照

Redis支持将当前数据的快照存成一个数据文件的持久化机制,即RDB快照。这种方法是很是好理解的,可是一个持续写入的数据库如何生成快照呢?Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,而后在子进程中循环全部的数据,将数据写成为RDB文件。

咱们能够经过Redis的save指令来配置RDB快照生成的时机,好比你能够配置当10分钟之内有100次写入就生成快照,也能够配置当1小时内有1000次写入就生成快照,也能够多个规则一块儿实施。这些规则的定义就在Redis的配置文件中,你也能够经过Redis的CONFIG SET命令在Redis运行时设置规则,不须要重启Redis。

Redis的RDB文件不会坏掉,由于其写操做是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,而后经过原子性rename系统调用将临时文件重命名为RDB文件,这样在任什么时候候出现故障,Redis的RDB文件都老是可用的。同时,Redis的RDB文件也是Redis主从同步内部实现中的一环。

可是,咱们能够很明显的看到,RDB有他的不足,就是一旦数据库出现问题,那么咱们的RDB文件中保存的数据并非全新的,从上次RDB文件生成到Redis停机这段时间的数据所有丢掉了。在某些业务下,这是能够忍受的,咱们也推荐这些业务使用RDB的方式进行持久化,由于开启RDB的代价并不高。可是对于另一些对数据安全性要求极高的应用,没法容忍数据丢失的应用,RDB就无能为力了,因此Redis引入了另外一个重要的持久化机制:AOF日志。

2.3.2 Redis的AOF日志

AOF日志的全称是append only file,从名字上咱们就能看出来,它是一个追加写入的日志文件。与通常数据库的binlog不一样的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。固然,并非发送发Redis的全部命令都要记录到AOF日志里面,只有那些会致使数据发生修改的命令才会追加到AOF文件。那么每一条修改数据的命令都生成一条日志,那么AOF文件是否是会很大?答案是确定的,AOF文件会愈来愈大,因此Redis又提供了一个功能,叫作AOF rewrite。其功能就是从新生成一份AOF文件,新的AOF文件中一条记录的操做只会有一次,而不像一份老文件那样,可能记录了对同一个值的屡次操做。其生成过程和RDB相似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程当中,全部的写操做日志仍是会写到原来老的AOF文件中,同时还会记录在内存缓冲区中。当重完操做完成后,会将全部缓冲区中的日志一次性写入到临时文件中。而后调用原子性的rename命令用新的AOF文件取代老的AOF文件。

AOF是一个写文件操做,其目的是将操做日志写到磁盘上,因此它也一样会遇到咱们上面说的写操做的5个流程。那么写AOF的操做安全性又有多高呢。实际上这是能够设置的,在Redis中对AOF调用write(2)写入后,什么时候再调用fsync将其写到磁盘上,经过appendfsync选项来控制,下面appendfsync的三个设置项,安全强度逐渐变强。

1)appendfsync no

当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,因此这一切就彻底依赖于操做系统的调试了。对大多数Linux操做系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。

2)appendfsync everysec

当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。可是当这一次的fsync调用时长超过1秒时。Redis会采起延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就无论会执行多长时间都会进行。这时候因为在fsync时文件描述符会被阻塞,因此当前的写操做就会阻塞。因此结论就是,在绝大多数状况下,Redis会每隔一秒进行一次fsync。在最坏的状况下,两秒钟会进行一次fsync操做。这一操做在大多数数据库系统中被称为group commit,就是组合屡次写操做的数据,一次性将日志写到磁盘。

3)appednfsync always

当设置appendfsync为always时,每一次写操做都会调用一次fsync,这时数据是最安全的,固然,因为每次都会执行fsync,因此其性能也会受到影响。

相关文章
相关标签/搜索