文章目录

  • 一、缓存分类
  • 二、Redis与Memcached的区别
  • 1、线程模型
  • 2、数据结构
  • 3、 淘汰策略
  • 4、持久化
  • 5、 高可用
  • 6、集群化
  • 三、Redis虚拟内存机制
  • 四、Redis 事务机制
  • 1、Redis 事务机制
  • 2、redis事务命令
  • 3、事务3阶段
  • 4、redis的事务特性


一、缓存分类

首先了解下Java缓存分类:

本地缓存:Ehcache、GuavaCache、Caffeine等

分布式缓存:Redis、Memcached

二、Redis与Memcached的区别

两者都是非关系型内存键值数据库,现在公司一般都是用 Redis 来实现缓存,为什么不用Memcached呢?接下来分析一下它们的区别:

1、线程模型

Memcached处理请求采用多线程模型,并且基于IO多路复用技术,主线程接收到请求后,分发给子线程处理。

优点是当某个请求处理比较耗时,不会影响到其他请求的处理。缺点是CPU的多线程切换必然存在性能损耗,同时,多线程在访问共享资源时必然要加锁,也会在一定程度上降低性能。

Redis同样采用IO多路复用技术,但它处理请求采用是单线程模型,从接收请求到处理数据都在一个线程中完成。

缺点一旦某个请求处理耗时比较长,那么整个Redis就会阻塞住,直到这个请求处理完成后返回,才能处理下一个请求,使用Redis时一定要避免复杂的耗时操作。由于Redis是内存数据库,它的访问速度非常地快,所以它的性能瓶颈不在于CPU,而在于内存和网络带宽,这也是作者采用单线程模型的主要原因。同时,单线程对于程序开发非常友好,调试起来也很方便。开发多线程程序必然会增加一定的调试难度。

Redis6.0又进一步完善了多线程,在接收请求和发送请求时使用多线,进一步提高了处理性能。

2、数据结构

Memcached支持的数据结构很单一,仅支持string类型的操作。并且对于value的大小限制必须在1MB以下,过期时间不能超过30天。使用Memcached时,我们只能把数据序列化后写入到Memcached中。然后再从Memcached中读取数据,再反序列化为我们需要的格式。

Redis对于不同的数据结构可以采用不同的操作方法,非常灵活。
Redis支持的具体数据类型可查看:Redis数据类型

3、 淘汰策略

Memcached必须设置整个实例的内存上限,数据达到上限后触发LRU淘汰机制,优先淘汰不常用使用的数据。但它的数据淘汰机制存在一些问题:刚写入的数据可能会被优先淘汰掉,这个问题主要是它本身内存管理设计机制导致的。

Redis没有限制必须设置内存上限,如果内存足够使用,Redis可以使用足够大的内存。同时Redis提供了多种淘汰策略
Redis内存淘汰策略可查看:内存淘汰策略

4、持久化

Memcached不支持数据的持久化,如果Memcached服务宕机,那么这个节点的数据将全部丢失。

Redis支持将数据持久化磁盘上,提供RDB和AOF两种方式。

5、 高可用

Memcached没有主从复制架构,只能单节点部署,如果节点宕机,那么该节点数据全部丢失。业务需要对这种情况做兼容处理,当某个节点不可用时,把数据写入到其他节点以降低对业务的影响。

Redis拥有主从复制架构和哨兵节点,在主节点宕机时,主动把从节点提升为主节点,继续提供服务。主从两个节点还可以提供读写分离功能,进一步提高程序访问的性能。

6、集群化

Memcached的集群化是在客户端采用一致性哈希算法向指定节点发送数据,当一个节点宕机时,其他节点会分担这个节点的请求。

而Redis集群化采用的是每个节点维护一部分虚拟槽位,通过key的哈希计算,将key映射到具体的虚拟槽位上,这个槽位再映射到具体的Redis节点。同时每个Redis节点都包含至少一个从节点,组成主从架构,进一步提高每个节点的高可用能力。当增加或下线节点时,需要手动触发数据迁移,重新进行哈希槽位映射。

Redis

Memcached

线程模型

单线程

多线程

数据结构

string , list, hash, set、 zset、geo、 hyperLogLog

仅支持string、value最大1M、过期时间不能超过30天

淘汰策略

LRU、LFU、随机等多种策略

LRU

管道与事务

支持

不支持

持久化

支持

不支持

高可用

主从复制+哨兵

不支持

如果你的业务需要各种数据结构给予支撑,同时要求数据的高可用保障,那么选择Redis是比较合适的。

如果你的业务非常简单,只是简单的set/get,并且对于内存使用并不高,那么使用简单的Memcached足够。

三、Redis虚拟内存机制

特别的,Redis直接自己构建了VM机制 ,不会像一般的系统会调用系统函数处理,会浪费一定的时间去移动和请求。

虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。

【补充面试高频问题】redis为什么快?
1、完全基于内存,省去磁盘I/O的消耗
2、数据结构高效,专门设计,对数据操作也简单
3、采用单线程避免了上下文切换和锁的问题
4、采用I/O多路复用模型,非阻塞IO
5、底层模型不同,构建了自己的VM机制(也就是上边提到的虚拟内存机制);

四、Redis 事务机制

1、Redis 事务机制

Redis通过一组命令集合,来实现事务机制。可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入。

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

简言之就是顺序性一次性排他性的执行一个队列中的一系列命令。

2、redis事务命令

中国平替redis的内存数据库 替代redis的缓存_分布式缓存


MULTI命令标志着事务的开始。该命令的作用是将客户端的REDIS_MULTI选项打开,让客户端从非事务状态切换到事务状态。

3、事务3阶段

开启事务:以MULTI 开启一个事务
命令入队:将多个命令入队到事务中,接到这些命令不会立即执行,而是放到等待执行的事务队列里面
执行事务:由EXEC命令触发事务

eg:假设使用watch检测id,初始值10,正常执行:

127.0.0.1:6379> WATCH id
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR id
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 11
127.0.0.1:6379>

放弃事务:

127.0.0.1:6379> WATCH id
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR id
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get id
1) (integer) 10

WATCH命令用于在事务开始之前监视任意数量的键: 当调用EXEC命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。

127.0.0.1:6379> set id 50
OK
127.0.0.1:6379> 


这时候执行到EXEC时会报错
127.0.0.1:6379> WATCH id
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR id
QUEUED
127.0.0.1:6379> EXEC
(ni1) 
127.0.0.1:6379> get id
1) (integer) 20
  • 若在事务队列中存在语法性错误,则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。eg:对“hello”的值执行 incr
  • 若在事务队列中存在命令性错误,则执行EXEC命令时,所有命令都不会执行:eg:geta a
    这些错误通常只会出现在开发环境中, 而很少会在实际的生产环境中出现。

4、redis的事务特性

  • 原子性:事务队列中的命令要么就全部都执行,要么就一个都不执行。
    但是Redis不支持事务回滚机制(rollback),严格意义上不算是原子性,不支持事务回滚是因为这种复杂的功能和Redis追求简单高效的设计主旨不相符。
  • 一致性: 一个事务执行后,不破坏原数据库的完整性约束。Redis事务满足原子性要求。可能破坏Redis事务一致性的三种错误情况:入队错误、执行错误、服务器停机。
    1)入队错误:类似于上述拼写错误,会在入队时被检查出来,并导致整个事务的失败,数据库会回到事务执行前的状态,因此不破坏数据库的完整性约束。
    2)执行错误:执行错误会导致该条命令失败,不会对数据库做出任何修改,所以也不影响事物的一致性
    3)服务器宕机:若在事务执行的过程中,服务器出现宕机现象,其在重启后会根据rdb或aof持久化文件恢复到事务执行前的状态或者变成空白数据库,而这两种状态都是一致的
  • 隔离性:事务的隔离性是指多个事务在并发执行的过程中,彼此互不干扰。Redis的事务总是以串行的方式运行的是具有隔离性的。
  • 持久性: 当服务器运行在AOF持久化模式下,并且appendfsync选项的值为always时,程序总会在执行命令之后调用同步(sync)函数,将命令数据真正地保存到硬盘里。

小结:redis 特点

  • 所有数据存储在内存中,高速读写
  • 提供丰富多样的数据类型:string、 hash、list、 set、 sorted set、bitmap、hyperloglog、Geospatial(五种基本数据类型+后三种特殊的数据结构类型)
  • 提供了 AOF 和 RDB 两种数据的持久化保存方式,保证了 Redis 重启后数据不丢失
  • Redis 的所有操作都是原子性的,还支持对几个操作合并后的原子性操作,支持事务
  • 默认端口6379