redis数据结构
Redis是一种存储key-value的内存型数据库,它的key都是字符串类型,value支持存储5种类型的数据:String(字符串类型)、List(列表类型)、Hash(哈希表类型、即key-value类型)、Set(无序集合类型,元素不可重复)、Zset(有序集合类型,元素不可重复)。
针对这5种数据类型,Redis在底层都是使用的redisObject对象表示的。redisObject有3个重要的属性:type、encoding、ptr。
其中,type表示value的数据类型,也就是我们上面说的5种数据类型(REDIS_STRING、REDIS_LIST、REDIS_HASH、REDIS_SET、REDIS_ZSET);encoding表示value的编码,即底层使用了哪种数据结构;ptr是一个指向保存value的底层数据结构的指针。
其中type和ptr属性不用做过多的解释,一看就知道什么意思,本篇文章主要分析value的encoding编码,也就是不同数据类型的value对应的底层数据结构是什么以及数据结构的原理分析。
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的 *** 作,而且这些 *** 作都是原子性的。
在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改 *** 作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
内存快照(将内存中的数据在某一时刻的状态记录至磁盘中) 。现实可以理解为拍照。
想象下如果100个人(数据)在拍照,那首先想到的问题这100个人给谁拍照?拍照的同时如果有人"动"了怎么办?基于这些场景繁衍以下问题:
全量快照 ,一次性记录所有数据,保证数据的完整性
Redis 两个命令生成 RDB 文件, save 和 bgsave。
save:在主线程中执行,导致阻塞;
bgsave:创建一个子进程,用于写入 RDB 文件,避免主线程阻塞。(Redis默认配置项使用bgsave)。
采用bgsave因为Redis会fock一个子进程处理,所以读肯定没问题,修改是怎么处理的呢?
Redis借助 *** 作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写 *** 作。具体流程:
主线程 fork 出 bgsave 子进程后,bgsave 子进程实际是复制了主线程的页表。这些页表中,就保存了在执行 bgsave 命令时,主线程的所有数据块在内存中的物理地址。这样一来,bgsave 子进程生成 RDB 时,就可以根据页表读取这些数据,再写入磁盘中。如果此时,主线程接收到了新写或修改 *** 作,那么,主线程会使用写时复制机制。具体来说,写时复制就是指,主线程在有写 *** 作时,才会把这个新写或修改后的数据写入到一个新的物理地址中,并修改自己的页表映射。
如图:
bgsave 子进程复制主线程的页表以后,假如主线程需要修改虚页 7 里的数据,那么,主线程就需要新分配一个物理页(假设是物理页 53),然后把修改后的虚页 7 里的数据写到物理页 53 上,而虚页 7 里原来的数据仍然保存在物理页 33 上。这个时候,虚页 7 到物理页 33 的映射关系,仍然保留在 bgsave 子进程中。所以,bgsave 子进程可以无误地把虚页 7 的原始数据写入 RDB 文件。
一、频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
二、bgsave 子进程需要通过 fork *** 作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。
快照的恢复速度快,频率无法把控,频率太低,宕机,丢失数据比较多。频率太高,产生额外开销。
混合使用 AOF 日志和内存快照 ,内存快照以一定的频率执行,在两次快照之间, 使用 AOF 日志记录 这期间的所有命令 *** 作。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)