相关阅读:
Redis(一):Redis概述与常见问题
Redis(二):数据回收策略、持久化原理、事务、主从复制
Redis(三):常见数据结构 与 缓存击穿、缓存穿透与缓存雪崩
Redis(四):Redis的分布式锁实现
Redis(五):数据库 和 缓存 双写一致性
Redis是一款开源的内存中的数据结构存储系统,是一个基于内存运行的高性能,并支持持久化的key-value分布式NoSQL数据库。它可以用作:数据库、缓存、消息中间件。
Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,Redis支持的数据结构有:String、List、Set、Hash、Sorted Set。一个字符串类型的值能存储最大容量是512M。
因此Redis可以用来实现很多有用的功能:比方说用List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一个功能加强版的memcached来用。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
Redis也提供了持久化的选项,这些选项可以让用户将自己的数据保存到磁盘上面进行存储。根据实际情况,可以每隔一定时间将数据集导出到磁盘(快照),或者追加到命令日志中(AOF只追加文件),他会在执行写命令时,将被执行的写命令复制到硬盘里面。当然也可以关闭持久化功能,将Redis作为一个高效的网络的缓存数据功能使用。
Redis不使用表,他的数据库不会预定义或者强制去要求用户对Redis存储的不同数据进行关联。
数据库的工作模式按存储方式可分为:硬盘数据库和内存数据库。Redis 将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制,所以速度极快。
(1)硬盘数据库的工作模式:
(2)内存数据库的工作模式:
总而言之:
Redis是一款基于内存运行的高性能,并支持持久化的key-value分布式NoSQL数据库,因为基于内存,所以存写速度非常快,因此被广泛应用于缓存方向。
支持的数据结构有:String、List、Set、Hash、Sorted Set。一个字符串类型的值能存储最大容量是512M。Redis不使用表,他的数据库不会预定义或者强制去要求用户对Redis存储的不同数据进行关联。
Redis是单进程单线程的:redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
主要从“高性能”和“高并发”这两点来看待这个问题。
(1)高性能:
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在数缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可。
(2)高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
(1)完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速。
(2)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
(3)数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的
(4)使用非阻塞IO多路复用机制。
多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。
(5)使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
(1)redis支持更丰富的数据类型,支持更复杂的应用场景:Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
(2)redis可以存储的单个键值可以存储的容量更大,一个字符串类型的值能存储最大容量是512M。
(3)redis支持持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用,而memcached把所有数据全部存储在内存中。
(4)集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的。
(5)网络IO模型:Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。
(1)会话缓存(Session Cache):
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,
(2)全页缓存(FPC):
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,
(3)队列:
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。
(4)排行榜/计数器:
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单。
(5)发布/订阅(Publish, Subscribe):
1、Redis回收进程如何工作的?
一个客户端运行了新的命令,添加了新的数据。Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。一个新的命令被执行,等等。所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。
2、 Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
使用keys指令可以扫出指定模式的key列表。 如果这个redis正在给线上的业务提供服务,由于redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
3、使用过Redis做异步队列么,你是怎么用的?
(1)一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。 或者list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
(2)一次消费多次?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
pub/sub有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
(3)redis如何实现延时队列?使用sorted set,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
4、为什么redis需要把所有的数据放到内存中?
Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。
5、Redis支持的Java客户端都有哪些?官方推荐用哪个?
Redisson、Jedis、lettuce等等,官方推荐使用Redisson。
6、Redis key的过期时间和永久有效分别怎么设置?
EXPIRE和PERSIST命令。
7、redis哈希槽的概念:
Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
8、redis常见性能问题和解决方案:
(1) Master最好不要做任何持久化工作:如RDB内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
(2) 在Master AOF持久化的情况下,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。
(3) 尽量避免在压力很大的主库上增加从库。
(4) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。
(5) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内。