一、什么是redis
Redis是一个用C语言写的,开源、支持网络、基于内存、可持久性的、非关系型,key-value数据存储系统,它可以用作数据库、缓存和消息中间件。
二、Redis与Memcached的区别
-
Redis不仅仅支持简单的k/v类型的数据,同时还提供了String(字符串)、list(链表)、set(集合)、zset(有序集合)和hash(哈希类型)等数据结构的存储;而Memcached只支持简单的数据类型String类型
-
Redis支持数据的备份,即master——slave模式的数据备份
-
Redis支持数据的持久化,可以将内存中的数据存储在磁盘中,重启的时候可以再次加载进行使用;而Memcached是把数据全部存储在内存中
-
Redis的速度比Memcached的速度快很多
-
Memcached是多线程,非阻塞IO复用网络模型;Redis使用单线程的IO复用模型
三、使用Redis的优点
-
速度快:因为数据在内存中,类似于hashmap,hashmap的优势就是查找和操作时间复杂度都是O(1)
-
支持丰富数据类型:支持String、list、set、zset、hash等数据类型
-
支持事务:redis对事务是部分支持的,如果是在入队时报错,那么都不会执行,在非入队时报错,成功的就可以去执行
-
Redis监控:同步锁的原理
-
丰富的特性:可用于缓存、消息、按key设置过期时间,过期后将自动删除,类似于cookie
四、Redis的内存回收算法
Redis中采用两种算法进行内存回收,LRU算法以及引用计数算法,在操作系统内存管理一节中,我们都学习过LRU算法(最近最久未使用算法),那么什么是LRU算法呢
1、LRU算法
LRU算法作为内存管理的一种有效算法,其含义是在内存有限的情况下,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间,那么选择淘汰哪些对象呢?LRU算法就提供了一种策略,告诉我们选择最近一段时间内,最久未使用的对象将其淘汰,至于为什么要选择最久未使用的,可以想想,最近一段时间内使用的东西,我们是不是可能一会又要用到呢~,而很长一段时间内都没有使用过的东西,也许永远都不会再使用,在操作系统中LRU算法淘汰的不是内存中的对象,而是页,当内存中数据不足时,通过LRU算法,选择一页(一般是4KB)将其交换到虚拟内存区(Swap区)
LRU算法演示
假设前提,只有三块内存空间可以使用,每一块内存空间只能存放一个对象,如A、B、C...
-
最开始时,内存空间是空的,因此依次进入A、B、C是没有问题的
-
当加入D时,就出现了问题,内存空间不够了,因此根据LRU算法,内存空间中A待的时间最为久远,选择A,将其淘汰
-
当再次引用B时,内存空间中的B又处于活跃状态,而C则变成了内存空间中,近段时间最久未使用的
-
当再次向内存空间加入E时,这时内存空间又不足了,选择在内存空间中待的最久的C将其淘汰出内存,这时的内存空间存放的对象就是E->B->D
2、引用计数算法
引用计数算法作为垃圾收集器最早的算法,有其优势,也有其劣势,虽然现在的JVM都不再采用引用计数算法进行垃圾回收【例如Sun的Java hotspot采用了火车算法进行垃圾回收】,但这种算法也并未被淘汰,在著名的单进程高并发缓存Redis中依然采用这种算法来进行内存回收【后绪会以Redis作为例子,说明该算法】
引用计数算法说直白一点,就是对于创建的每一个对象都有一个与之关联的计数器,这个计数器记录着该对象被使用的次数,垃圾收集器在进行垃圾回收时,对扫描到的每一个对象判断一下计数器是否等于0,若等于0,就会释放该对象占用的内存空间,同时将该对象引用的其他对象的计数器进行减一操作
-
两种实现方式
侵入式与非侵入性,引用计数算法的垃圾收集一般有侵入式与非侵入式两种,侵入式的实现就是将引用计数器直接根植在对象内部,用C++的思想进行解释就是,在对象的构造或者拷贝构造中进行加一操作,在对象的析构中进行减一操作,非侵入式恩想就是有一块单独的内存区域,用作引用计数器
-
算法的优点
使用引用计数器,内存回收可以穿插在程序的运行中,在程序运行中,当发现某一对象的引用计数器为0时,可以立即对该对象所占用的内存空间进行回收,这种方式可以避免FULL GC时带来的程序暂停,如果读过Redis 1.0的源码,可以发现Redis中就是在引用计数器为0时,对内存进行了回收
-
算法的劣势
采用引用计数器进行垃圾回收,最大的缺点就是不能解决循环引用的问题,例如一个父对象持有一个子对象的引用,子对象也持有父对象的引用,这种情况下,父子对象将一直存在于JVM的堆中,无法进行回收
五、Redis有哪几种数据淘汰策略
-
Noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令)
-
Allkey-lru:尝试回收使用最少使用的键(LRU),但仅限于过期集合的键,使得新添加的数据有空间存放
-
Allkey-random:回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键
-
Volatile-ttl:回收过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据哟空间存放