1.Redis是什么2.Redis优缺点3.Redis为什么是单线程,6版本之后为什么又变成了多线程4.Redis应用场景5.Redis和Memcached的区别6.Redis数据结构与底层实现7.持久化机制8.Redis事务9.Redis过期策略10.内存淘汰机制11.Redis常见的部署方式有哪些12.高并发和高可用方案13.如何保证缓存与数据库双写一致性14.Redis的雪崩,穿透和击穿15.Redis如何实现消息队列16.Redis如何实现分布式锁1.Redis是什么Redis是一个使用C语言编写的,高性能非关系型的键值对数据库。与传统的数据库不同,Redis的数据是存储在内存中的,所以读写速度非常快,被广泛应用在缓存方向。Redis可以将数据写入磁盘中,保证了数据的安全不丢失,而且Redis的操作是原子性的。2.Redis优缺点优点:基于内存操作,内存读写速度快单线程,避免线程切换开销及多线程的竞争问题。单线程是指网络请求使用一个线程来处理,即一个线程处理所有网络请求,Redis运行时不止有一个线程,比如数据持久化还会另起线程支持多种数据结构支持持久化支持事务。支持主从复制缺点:对结构化查询的支持比较差数据库容量受到物理内存的限制,不适用作海量数据的高性能读写较难支持在线扩容3.Redis为什么是单线程,6版本之后为什么又变成了多线程避免过多的上下文切换开销。避免同步机制的开销实现简单,方便维护引入多线程:可以充分利用服务器CPU资源,单线程模型的主线程只能利用一个CPU多线程任务可以分摊Redis同步IO读写的负荷4.Redis应用场景缓存数据共享分布式比如分布式session,由于在集群或分布式环境下,不同的tomcat管理各自的session,而且通过复制的方式会极大的影响效率。将登录成功后的session信息,存放在Redis中,这样多个服务器(tomcat)可以共享session信息分布式锁string的set命令增加了一些参数:EX:设置键的过期时间(秒)PX:设置键的过期时间(毫秒)NX:只在键不存在时,才对键进行设置操作。XX:只在键已经存在时,才对键进行设置操作。由于这个操作是原子性的,可以简单实现一个分布式锁set lock_key locked NX EX 1如果这个操作返回false,说明key的添加不成功,也就是当前有人占用这把锁。而如果返回true,说明获得了这把锁,设置了过期时间也可以释放锁。5.Redis和Memcached的区别数据类型:Redis数据类型丰富,Memcached只有string持久化:redis数据可以持久化,Memcached不可以线程模型:Redis使用单线程的多路IO复用模型,Memcached使用多线程的非阻塞IO模型内存管理:Redis单线程,Memcached多线程集群:Redis提供主从同步机制和cluster集群部署能力。Memcached没有提供原生集群6.Redis数据结构与底层实现1.数据类型string:能表达字符串,整数,浮点数hash:键值对集合list:可以存储有序,可重复的元素set:无序去重的集合。set提供了交集,并集等方法,对于实现共同好友,共同关注等功能特别方便zset:有序set。内部维护了一个score的参数来实现。适用于排行榜和带权重的消息队列等场景Bitmap:位图,可以认为是一个以位为单位的数组,数组的每个单元只能存0或者1Hyperloglog:是用做基数统计的算法Geospatial:主要用于存储地理位置信息,并对存储的信息进行操作,适用场景如定位,附近的人等2.应用场景String        存储mysql中某个字段的值        生成自增id        set nx用作分布式锁hash存储对象list            消息队列            列表:用户列表,商品列表set            共同好友zset            排行榜3.底层原理String:使用了SDS(动态字符串对象),加入了free和len字段,获取字符串长度只需要O(1)hash:小于一个阈值的话使用压缩列表作为底层实现,其他的时候使用字典作为底层实现,字典就类似于java中的HashMaplist:底层是快速列表,快速列表是由压缩列表和双向列表组成的快速列表里的每一个节点都维护一个ziplist,ziplist是真正存放数据的地方。只有新增一个超过64长度的字符串或者ziplist包含的节点超过512,才会转化成双向链表。set:inset和哈希表。inset可以理解为数组,元素个数不小于512并且可以用整型表示时使用zset:ziplist和skiplist,有序集合保存的元素数量小于128 && 有序集合保存的所有元素的长度小于64字节时使用ziplist当ziplist作为zset的底层存储结构时,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值当skiplist作为zset的底层存储结构时,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系※ Redis底层结构详细讲解:我们先看看一个Redis整体的结构:RedisDB相当于Redis的数据库当Redis服务器初始化时,会预先分配16个数据库(编号0-15)SDS跳跃表将有序链表中的部分节点分层,每一层都是一个有序链表字典字典dict又称散列表Redis整个数据库是用字典来存储的,对Redis进行crud操作其实就是对字典中的数据进行crudRedis字典包括:字典(dict),Hash表(dictht),Hash表节点(dictEntry)Redis字典除了主数据库的K-V数据存储外,还可以用于:散列表对象,哨兵模式中的主从节点管理等不同的应用中,字典的形态都可能不同,dictType是为了实现各种形态的字典而抽象出来的操作函数(多态)扩容流程:rehash​ 1)初次申请默认分配4个dictEntry,非初次申请为当前hash表容量的一倍​ 2)迁移过程非常慢压缩列表ziplist是由一系列特殊编码的连续内存块组成的顺序型数据结构应用场景:sorted-set和hash元素个数少且是小整数或短字符串list用快速链表数据结构存储,而快速链表是双向列表和压缩列表的组合整数集合整数集合(intset)是一个有序的,存储整数的连续存储结构当Redis集合类型的元素都是整数并且都处在64位有符号整数范围内(2的64次方),使用该结构体存储快速列表快速列表(quicklist)是Redis底层重要的数据结构,是列表的底层实现7.持久化机制持久化就是把内存的数据写到磁盘中,防止服务宕机导致内存数据丢失RDB:RDB 持久化机制,是对 Redis 中的数据执行周期性的持久化。AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 Redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。8.Redis事务1)使用MULTI开启一个事务2)在开启事务的时候,每次操作的命令都将会被插入到一个队列中,同时这个命令并不会被真的执行3)EXEC命令提交(不支持回滚)WATCH命令可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行(类似于乐观锁)。执行EXEC命令之后,就会自动取消监控。9.Redis过期策略定期删除 + 惰性删除定期删除:指的是Redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查是否过期,如果过期就删除惰性删除:在你获取某个key的时候,检查一下是否已经过期,过期了此时就会删除10.内存淘汰机制过期策略仍然可能导致有大量过期key堆积在内存中,这个时候我们可以走内存淘汰机制volatile-lru:LRU(Least Recently Used),最近使用。利用LRU算法移除设置了过期时间的keyallkeys-lru:当内存不足以容纳新写入数据时,从数据集中移除最近最少使用的keyvolatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰volatile-random:从已设置过期时间的数据集中任意选择数据淘汰allkeys-random:从数据集中任意选择数据淘汰no-eviction:禁止删除数据,当内存不足以容纳新写入数据时,新写入操作会报错11.Redis常见的部署方式有哪些1)单机版:很少使用。内存容量有限,处理能力有限,无法高可用2)Redis主从:master挂了之后需要手动指定新的master3)Redis Sentinel(哨兵):哨兵可以选举新的master。但每个节点存储的数据是一样的,浪费内存空间。数据量不是很多,集群规模不是很大,需要自动容错容灾的时候使用4)Redis Cluster:主要针对海量数据+高并发+高可用的场景。12.高并发和高可用方案**高并发:**通过主从实现单机的Redis,能够承载的QPS大概就在上万到几万不等,对于缓存来说,一般是用来支撑读高并发的。因此架构做成主从架构,一主多从,主负责写,并且将数据复制到其他的slave节点,从节点负责读。主从复制:1)当启动一个从节点时,它从发送一个PSYNC命令给主节点2)如果是从节点初次连接到主节点,那么会触发一次全量复制。此时主节点会启动一个后台线程,开始生成一份RDB快照文件。3)同时还会将从客户端client新收到的所有写命令缓存到内存中。RDB 文件生成完毕后, 主节点会将RDB文件发送给从节点,从节点会先将RDB文件写入本地磁盘,然后再从本地磁盘加载到内存中4)接着主节点会将内存中缓存的写命令发送到从节点,从节点同步这些数据5)如果从节点跟主节点之间网络出现故障,连接断开了,会自动重连,连接之后主节点仅会将部分缺失的数据同步给从节点**高可用:**哨兵Sentinel哨兵是一个独立的进程,可以独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。执行流程​ 1)启动并初始化SentinelSentinel是一个特殊的Redis服务器,不会进行持久化Sentinel会创建2个连向主服务器的网络连接:命令连接和订阅连接​ 2)哨兵检测检测主观下线状态:我(Sentinel)没有接收到主服务器的回复​ 3)哨兵确认检测客观下线状态:监控所有其他Sentinel发送查询命令,确认主服务器宕机​ 4)哨兵故障转移选举Leader:通过Raft协议Redis Cluster:进一步提升性能13.如何保证缓存与数据库双写一致性14.Redis的雪崩,穿透和击穿缓存雪崩解决方案:事前:Redis高可用,主从 + 哨兵,Redis Cluster,避免全盘崩溃事中:本地ehcache缓存 + hystrix限流&降级,避免mysql被打死事后:Redis持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据缓存穿透解决方案:将数据库中所有可能的数据哈希映射到布隆过滤器。然后对每个请求进行如下判断:请求数据的key不存在于布隆过滤器中,可以确定数据就一定不会存在于数据库中,系统可以立即返回不存在请求数据的key存在于布隆过滤器中,则继续再向缓存中查询使用布隆过滤器能够对访问的请求起到了一定的初筛作用,避免了因数据不存在引起的查询压力缓存击穿缓存击穿,就是说某个key非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个key在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开一个洞。若缓存的数据是基本不会发送更新的,则可尝试将该热点数据设置为永不过期若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,则可以采用基于Redis,zk等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存15.Redis如何实现消息队列List:基于List结构来模拟消息队列PubSub:基本的点对点消息模型Stream:较完善的消息队列模型List底层是双向链表,可以利用List的添加取出命令来实现模拟消息队列lpush和brpop16.Redis如何实现分布式锁三个命令:setnx,expire,delete第一步:setnx key val(setnx就是,若key不存在,则存入键值对,若ket存在,则什么都不做,返回0)第二步:expire key(为key设置一个过期时间)第三步:delete key(删除指定key)
点赞 12
评论 5
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务