目录
如何使用redis实现记录用户登入了多少天,连续登入了多少天?
Redis中mset(批量)和set(单次)操作的区别是什么?
Redis中mset(批量)和set(单次)操作的区别是什么?
Redis集群
Redis集群模式下Leader选举?
答:每个节点都会定期向其他节点发送PING
消息来检查节点是否可达。如果一个节点在node - timeout
时间(默认 15 秒)内没有收到另一个节点的PONG
响应,就会将对方标记为疑似下线,如果超过半数节点都认为该节点下线时,该节点会被标注为已下线。这时将开启选举,1)slave发现自己的master变为FAIL;2)将自己记录的集群选举轮次标记加1,并广播信息给集群中其他节点;3)其他节点收到该信息,只有master响应,判断请求者的合法性,并发送结果;4)尝试选举的slave收集master返回的结果,收到超过半数master的统一后变成新Master;5)广播Pong消息通知其他集群节点。
Redis的集群是怎么实现的?
答:1)集群至少需要6个节点才能组成高可用集群,且每个节点要开启集群模式;2)各节点之间通过 Gossip 协议进行通信;3)Reids有一套被称作环的哈希算法,就是用节点IP+编号对16384个槽进行求模取余,对数据和节点进行哈希;4)一个主可以有多个从,主要用于数据备份和故障恢复,当主节点故障时,从节点会进行投票选举,超过半数票,将自己升级为主节点,实现故障迁移。
Redis主从的同步策略?
答:分为全量同步和增量同步,全量同步分为三个阶段:1)同步快照阶段:msster创建并发送快照给slave,slave载入并解析快照,master此时将产生的新命令存储到缓冲区;2)同步写缓冲阶段:master向slave同步存储在缓冲区的写命令;3)同步增量阶段:master向slave同步写命令;增量同步:slave完成初始化,master每执行一个写命令就向slave发送发送相同的命令,slave接收并执行;
Redis分布式锁的特性?
答:1)互斥性:保证同一时间只有一个客户端可以拿到锁;2)安全性:只有加锁的服务才有解锁权限; 3)避免死锁:出现死锁就会导致后续的任何服务都拿不到锁,不能再对共享资源进行任何操作了;4)保证加锁与解锁操作是原子性操作, 加锁分为a.设置key set(key,value)b.给key设置过期时间;使用分布式锁:1)使用redis命令 set key value NX EX max-lock-time 实现加锁;2)使用redis命令 EVAL 实现解锁。
Redis集群 一致性hash的原理?
答:1)集群根据数据和节点对16384个slots(槽位)进行求模取余;2)集群默认会对key值使用crc16算法得到一个整数值;3)通过整数值找到具体槽位;4)在根据槽位值和Redis节点的对应关系找到具体的节点进行存储;缺点是:容易发生数据倾斜,解决办法是添加虚拟节点;
Redis集群,高可用,原理?
答:1)主观下线: 集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong消息作为响应。如果在cluster-node-timeout时间内通信一直失败,则发送节点会认为接收节点存在故障,把接受节点标记为主观下线(pfail)状态; 2)客观下线:a)当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播;b)假设节点a标记节点b为主观下线,一段时间后节点a通过消息把节点b的状态发送到其他节点,当其他节点收到消息并解析出消息体中含有b的pfail状态,把节点b加入下线报告链表;c)当某一节点c收到节点b的pfail状态时,此时有超过一半的槽主节点都标记了节点b为pfail状态时,则标记故障节点b为客观下线;d)向集群广播一条pfail消息,通知集群内的所有节点标记故节点b为客观下线状态并立刻生效,同时通知故障节点b的从节点触发故障转移流程;3)故障恢复:a)资格检查:若从节点与主节点断线时间超过一定时间,则不具备资格;b)准备选举时间:当从节点符合故障转移资格后,要等待一段选举时间后才开始选举在故障节点的所有从节点中,复制偏移量最大的那个从节点最先开始(与主节点的数据最一致)进行选举,然后是次大的节点开始选举.....剩下其余的从节点等待到它们的选举时间到达后再进行选举;c)发起选举;d)选举投票:只有持有槽的主节点才具有一张唯一的选票,从从节点收集到N/2 + 1个持有槽的主节点投票时,从节点可以执行替换主节点操作;e)替换主节点。
Redis缓存分片?
答:集群分片最少要有6个才能组成高可用集群,其中三个主节点,三个从节点,三个主节点会分配槽处理客户端的请求,通过范围分片,哈希分片,一致性哈希算法,哈希槽等方法对数据分片;
Redis有几种部署方式?哨兵机制和集群的区别是啥?
答:单机模式:优点:架构简单,部署方便,高性能,性价比高;缺点:不保证数据的可靠性,缓存失效后数据丢失;性能受限;哨兵(Sentinel)模式:优点:部署简单;能够解决主从的高可用切换问题;能通过哨兵监控各个节点; 缺点:部署主从比较繁琐;资源浪费备节点不提供服务;不能读写分离;集群模式;优点:无中心架构;可数据共享,动态分布数据;可扩展性高;高可用,运维成本较低;缺点:客户端实现复杂;数据通过异步,不能保证数据强一致性;批量操作KEY受限制;
Redis的并发竞争问题如何解决?
答:主要是发生在并发写;解决办法:1)利用redis自带的incr(1.为key储存的数字值加上一,2.如果key储存的值不能被解释为数字,那么INCR 命令将返回一个错误。)命令;2)使用乐观锁的方式进行解决(成本较低,非阻塞,性能较高);3)使用watch命令:WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值);4)这个是针对客户端来的,在代码里要对redis操作的时候,针对同一key的资源,就先进行加锁(java里的synchronized或lock);5)利用redis的setnx实现内置的锁,当且仅当key不存在,将key的值设置为value,并且返回1;若是给定的key已经存在,则setnx不做任何动作,返回0。
Redis中哨兵的作用?
答:哨兵(sentinel) 系统用于管理多个 Redis 服务器,其实也是运行在特殊模式下的 Redis 服务器,主要有:1)监控(Monitoring): 哨兵会不断地检查你的Master和Slave是否运作正常;2) 提醒(Notification):当 Redis出现问题时, 通过 API 向管理员或者其他应用程序发送通知;3)自动故障迁移:当Master故障时,其中的Slave升级为新的Master,并让其它Slave改为新的master;
Redis实现消息队列?
答:Redis的消息队列有两种模式,一种是发布者和订阅者模式,另外一种是生产者和消费者模式, 发布者和订阅者模式:发布者发送消息到队列,每个订阅者都能收到一样的消息。 生产者和消费者模式:生产者将消息放入队列,多个消费者共同监听,谁先抢到资源,谁就从队列中取走消息。注意,每个消息只能被一个消费者接收。
Redis基础
Redis⾼性能的原因大概可以讲一些?
答:1)存储速度快: Redis读写数据完全基于内存。2)数据类型存储丰富: Redis支持多种不同类型的数据结构, 包括集合、有序集合、哈希等。3)单线程单进程模型: Redis内部主要是使用单线程的IO复用模型,并支持使用select、poll、epoll的等方式的事件处理器, 单线程模型可以充分利用CPU资源,将速度优势发挥到最大。4)分布式集群:Redis除了支持单机模式,主从模式以外还自带了Redis集群。
如何使用redis实现记录用户登入了多少天,连续登入了多少天?
答:用Bitmap实现,计算天数: 前提(Id是唯一的数字,比如id为5),那么你第一天 用户5 登录了,你可以存储为一...第二天...二...以此类推,到最后一天,以当天为起点,然后往前面推算,凡是碰到1的,就把他给统计,碰到0,就不再给用户继续统计,即可!
如何对Redis进行性能调优?
答:1.性能优化:a.避免使用复杂度过高的命令;b.操作bigkey;c.内存碎片整理;d.fork操作优化;e.内存大页配置;2.数据管理:a.AOF配置的优化;b.集中过期处理;e.数据淘汰策略;3.网络磁盘:a.连接管理;b.数据传输优化;c.Swap的使用;
Redis为什么引入了多线程?
答:主要是在网络I/O处理上增加了多线程,增加的原因和优势:1)网络I/O瓶颈;2)提升宽度利用率;3)减低延迟;4)充分利用多核CPU;
Redis线上操作最佳实践有那些?
答:1)优化数据结构;2)设置合理的过期时间;3)使用持久化策略;4)监控和报警;5)规模化和高可用性;6)设计良好的命名空间;7)减少网络延迟;8)参数调优;9)客户端重试策略;10)访问控制和安全;
Redis单线程为什么还这么快?
答:1)命令执行基于内存操作;2)命令执行时候单线程操作,没有线程切换开销;3)基于IO多路复用机制提升Redis的I/O利用率;4)高效的数据存储结构,比如:跳表、压缩列表等;
Redis实现语言以及Redis是什么?
答:C语言;redis是非关系型的键值对数据库,可以根据键以o(1)的时间复杂度查询或插入关联值,是以内存方式存储的,并内置了复制,磁盘持久化、事务、SSL客户端代理等功能,通过哨兵和自动化分区提高可用性;
系统有海量的活跃数据,怎么统计日活?
答:用bitmap(位图),比如:setbit插入数据;用getbit获取数据;用bitcount统计数据;bitmap(位图)的存储原理是: 在setbit插入数据时,在key后面有个offset偏移量,通过偏移量设置bit的值,bit的底层其实是String类型,最多能存512M,通过bitcount key 0 -1其中key是需要统计的用户,0和-1是偏移量,这样就实现了天的统计;夸天统计是将key按位于(and),而周和月的统计是将多天的key按位或(or)合并存到一个key中在通过bitcount统计即可;
Redis为什么这么快?redis采用多线程会有哪些问题?
答:redis快:1)数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);2)数据结构简单,对数据操作也简单;3)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU;4)使用多路I/O复用模型,非阻塞IO;5)使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制;redis线程:Redis在多线程高并发下出现数据错乱,也就是A的数据给了B,B的数据给到了C。
Redis中的Lua有没有使用过?可以用来做什么?
答: 1、减少网络开销:可以将多个请求通过脚本的形式一次发送,减少网络时延和请求次数。2、原子性的操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。 3、代码复用:客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本来完成相同的逻辑。4、速度快:见 与其它语言的性能比较, 还有一个 JIT编译器可以显著地提高多数任务的性能; 对于那些仍然对性能不满意的人, 可以把关键部分使用C实现, 然后与其集成, 这样还可以享受其它方面的好处。5、可以移植:只要是有ANSI C 编译器的平台都可以编译,你可以看到它可以在几乎所有的平台上运行:从 Windows 到Linux, 同样Mac平台也没问题, 再到移动平台、游戏主机,甚至浏览器也可以完美使用 (翻译成JavaScript);6、源码小巧:20000行C代码,可以编译进182K的可执行文件,加载快,运行快。
Redis的线程模型,是怎么工作的?
答:redis在6.0版本以前针对客户端是单线程的,当有unlink和慢IO时会创建子进程处理,在6.0版本以后提供了多线程默认是关闭的,而且只是对read和write是多线程,其command(处理客户端命令)是单线程的,另外客户端是通过TCP连接服务的,单个TCP连接内是有序的,多个TCP连接时不能保证有序;
单线程的Redis如何能够高并发?
答:Redis通过主从架构,实现读写分离,主节点负责写,并将数据同步给其他从节点,从节点负责读,从而实现高并发;
Redis的key
Reids热key问题怎么解决?
答:1)本地缓存,适合提前已知的情况;2)请求分摊:将热key拆分成多个子key,将读请求分摊到多个key上;3)限流:防止过多的请求进入;4)监控和报警:适合未知的热key场景;
Redis中Key过期了一定会立即删除吗?
答:不一定立即删除,有两种删除策略:1)惰性删除:过期后不会立即删除,而是等着下次访问时才会删除; 2)定期删除:reids后台会有一个定时任务,大约每隔100毫秒扫描一次删除;
Redis的key和value的设计原则有那些?
答:key:1)短小精炼;2)使用命名空间;3)避免热key;4)选择唯一和通用的标识;
value:1)选择合适的数据结构;2)限制单个value的大小;3)利用压缩;4)TTL设置;
Redis如何高效安全的遍历所有Key?
答:1)使用scan命令,就是增量式的,可以指定每次遍历一小部分的key;
Redis的key过期了为什么内存没释放?
答:修改过期的key时没有携带过期时间,那么这个key就变成永不过期了;redis的删除策略使用:惰性和定时删除,当一个key过期了,并不会立马删除;
Redis淘汰key的算法LRU与LFU区别?
答:LRU(最近最少使用):淘汰很久没被访问过的数据,以最近一次访问的时间作为参考;LFU(最不经常使用):淘汰最近一段时间被访问次数最少得数据;
删除key的命令会阻塞Redis吗?
答:删除单个字符串的key,事件复杂度是o(1),删除单个列表、集合、有序集合、哈希的key,事件复杂度是o(M);
Redis中的key和value的类型分别是什么?
答:key都是String类型,value有String、Set、List、Hash、Zset;
Redis中大key(bigkey)解决办法?
答:存在的问题:1)读写bigkey会导致超时严重,甚至阻塞服务;2)大key相关的删除或者自动过期时,会出现qps突降或者突升的情况,极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求;3)占用资源;解决办法:1)将大key分拆成多个key,value用multiGet获取值,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;2)将分拆的key,value用hash存储,用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性;3)按照存储元素进行规则分类,分散存储到多个redis实例中;4)可以利用pipeline管道,一次发送多个命令,无需等待服务端返回;
Redis的存储
Redis底层数据是如何用跳表来存储的?
答:zset结构,对跳表做了优化,就是将有序链表改造为支持近乎“折半查找”算法,可以快速的插入、删除、查询等;
Redis默认的DB(数据库)有多少个?
答:一共16个, 都是redisDb存储的, redisDb的数据结构共有9个 :1)dict(字典):主要用于Key的索引; 2)expires:存储过期时间; 3)blocking_keys(阻塞):存储被阻塞的key; 4)ready_keys:存储的是可以解除阻塞的键, key通过该方式与客户端建立关系;5)watched_keys:存储的是正在被 watch 命令监控的键;6)id:记录的是当前数据库的一个编号;7)avg_ttl:收集了所有键剩余存活时间的一个平均值;8)expires_cursor;9)defrag_later;其中RedisDB数据结构整体流向:
Redis的key在底层是怎么存储的?
答:主要用redisObject对象,该对象中有type(数据类型:string、list、hash、set)、encoding(数据编码,内存的利用率极高)、iru:LRU_BITS(内存淘汰策略)、refcount(内存计数器)、 *ptr(len、free、buf[])指向数据编码对象也就是真实的数据;int类型存储逻辑:首先判断数据的长度是否在20以内,其次尝试转成int,如果是int的话ptr将不在创建内存地址,直接存储在redisObject对象上;embstr类型存储逻辑: 是SDS(Simple Dynamic String 简单动态字符串),其中cpu获取数据的缓存行是64byte, 如果业务数据少于44个字节,只需分配一次内存空间即可,而不在通过指针引用; raw类类型存储逻辑:存储大于 44 个字节的字符串,需要分配两次内存空间;
Redis如何实现持久化?
答:有三种:1)RDB(redis DataBase):保存某一个时间点之前的快照数据,通知配置方式或者手动执行save命令,优点是a)服务启动数据恢复比较快;、b)持久化使用子进程处理主进程可以继续处理客户端请求 ;缺点是:a)持久化有时间间隔;b)写入进程多的话会有大量的分页错误,造成性能耗费;2)AOF(Append-Only File):所有的命令行记录以redis命令请求协议的格式完全持久化存储保存为aof文件,优点是:数据安全,配置appendfsync属性,每执行一次命令就记录到aof文件中;缺点是:数据大的时候,比rdb启动效率低;3)混合持久化(4.0版本以后):进行aof重写时子进程将当前时间点的数据快照保存为rdb文件格式,而后将父进程命令保存为aof格式,优点是:兼顾了rdb的恢复速度和aof的安全性;
Redis是如何处理过期数据的?
答:有两种:1)惰性删除:当访问时才判断是否过期,是就删除返回null,否就返回数据;2)定期删除:通过serverCron(定时任务)每一秒执行10次;
了解Redis事务的CAS操作吗?
答:cas(check-and-set 乐观锁):Redis的事务:redis事务用的命令:MULTI、SET、HSET、EXEC。Redis会将所有EXEC命令之前的命令放入一个QUEUE中,当遇到EXEC时批量执行QUEUE中的命令,但是 Redis的事务是不支持回滚的,它只是顺序的执行命令,并批量返回结果,但是对于极端情况下,事务在没有完全执行完时宕机,导致事务日志只写入部分,这样在重启时会产生错误,用aof的修复工具修复后可以进行启动;Watch命令可以监控Redis中的一个key,当Key发生变化时终止事务的提交;如果watch一个不稳定(有生命周期)的key并且此key自然过期,exec仍然会执行事务队列的指令;
当内存不够用时redis是如何处理的?
答:当内存不足时影响最大的是写请求会返回错误,通过两个算法:1)LRU(The Least Recently Used)最近少使用:当数据在最近一段时间没有被访问,将被认定为访问的可能性很小,当内存满时将被淘汰,通过链表实现;2)LFU(Least Frequently Used)最不请经常使用:当数据在最近一段时间很少被访问,将被认定为访问的可能性很小,当内存满时将被淘汰也是用redisObject中的lru在存储lfu数据,将该lru分为两部分1)高16位记录访问时间(分钟);2)低八位记录频率,简称counter;
Redis的LRU过期策略的具体实现?
答:Redis中的键与值都是redisObject对象,unsigned的低24 bits的lru记录了redisObj的LRU time, LRU_CLOCK_RESOLUTION代表了LRU算法的精度,即一个LRU的单位是多长。server.hz代表服务器刷新的频率, 如果服务器的时间更新精度值比LRU的精度值要小,LRU_CLOCK()直接使用服务器的时间,减小开销。
Redis宕机之后如何恢复数据?
答:有三种:1)RDB(redis DataBase):保存某一个时间点之前的快照数据,通知配置方式或者手动执行save命令,优点是1)服务启动数据恢复比较快;2)持久化使用子进程处理主进程可以继续处理客户端请求 ;缺点是:1)持久化有时间间隔;2)写入进程多的话会有大量的分页错误,造成性能耗费;2)AOF(Append-Only File):所有的命令行记录以redis命令请求协议的格式完全持久化存储保存为aof文件,优点是:数据安全,配置appendfsync属性,每执行一次命令就记录到aof文件中;缺点是:数据大的时候,比rdb启动效率低; 3)混合持久化(4.0版本以后):进行aof重写时子进程将当前时间点的数据快照保存为rdb文件格式,而后将父进程命令保存为aof格式,优点是:兼顾了rdb的恢复速度和aof的安全性;
Redis持久化的几种方式,优缺点是什么,怎么实现的?
答:1)RDB:是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化;优点:a)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中 redis 的数据,这种多个数据文件的方式,非常适合做冷备。b)可以让 redis 保持高性能,因为 redis主进程只需要 fork 一个子进程,让子进程执行磁盘 IO 操作来进行RDB 持久化即可。c)对于灾难恢复,可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。d)如果数据集很大,RDB的启动效率会更高。缺点:a)RDB 数据快照文件,都是每隔 5 分钟,或者更长时间生成一次,这个时候就得接受一旦 redis 进程宕机,那么会丢失最近 5 分钟的数据。b)RDB是通过fork子进程来协助完成数据持久化工作的,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。实现方式:a)通过配置自动进行的持久化: save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。b)通过SAVE与BGSAVE命令进行持久化。c)通过执行FLUSHALL命令,会清空内存中的数据。d)执行复制的时候; 2)AOF:将Reids的操作日志以追加的方式写入文件;优点:a)每隔 1 秒,通过一个后台线程执行一次fsync操作,最多丢失 1 秒钟的数据。b)日志文件以 append-only 模式写入,没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损。c)如果日志过大,Redis可以自动启用rewrite机制。
d)日志文件的命令通过非常可读的方式进行记录,格式清晰、易于理解。 缺点:a)相同数量的数据集而言,AOF文件通常要大于RDB文件。c)根据同步策略的不同,AOF在运行效率上往往会慢于RDB。
Redis的缓存失效策略?
答:1)FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。 2)LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。 3)LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
redis的数据淘汰(过期)策略?
答:1)定时删除: 在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。 2)惰性删除:放任过期键不管,每次从键空间读写操作时,都检查键是否过期,如果过期,删除该键,如果没有过期,返回该键。 3)定期删除:每隔一段时间执行一次定时删除,并通过限制删除操作执行的总时长和总频率来限制删除操作对CPU占用时间的影响。 通过定期删除过期键,有效减少了因为过期键而带来的内存浪费。4)主动清理:当前已用内存超过maxmemory限定时,触发主动清理策略。清理时会根据用户配置的maxmemory-policy来做适当的清理。
redis数据类型存储的场景?
答:1)string :一个 key 对应一个 value。value其实不仅是String,也可以是数字。string 类型是二进制安全的,使用场景:常规key-value缓存应用。常规计数: 微博数, 粉丝数。2)hash: 是一个键值(key => value)对集合,hash 是一个 string 类型的 field 和 value 的映射表,使用场景:存储部分变更数据,如用户信息等。Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口;3)list: 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),使用场景:比如微博ID等;4)set是string类型的无序集合。集合是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等;使用场景:存储全班同学成绩;
什么是缓存穿透?
答:每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源;解决办法:1)采用布隆算法过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉;2)设置缓存的过期时间(短);
什么是缓存击穿?
答:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期就会从DB获取数据并回设到缓存;解决办法:1)使用互斥锁(mutex key) ,就是在缓存失效的时候,不是立即去load db,而是先用Redis的SETNX去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法;2)用二级缓存也就是在一层redis;
什么是缓存雪崩?
答:在流量洪峰达到时,大量的请求导致缓存服务宕机,所有请求访问db造成不可用称为雪崩;解决办法:1)采用集群架构实现;2)对服务接口降级;3)对缓存监控,达到阈值时通过自动故障转移和不重要的接口;4)将比较常用的key缓存在本地,减少redis访问;
Redis缓存怎么和数据库保持一致性?
答:我们一般保证数据的最终一致性,可以通过Canal框架监听mysql的binlog日志,把删除数据的动作放到客户端去做,如果删除失败就重试。
Redis数据结构
String类型的底层数据结构及实现原理?
答:redis自定义了一个数据类型sds(simple dynamic string)简单的动态字符串,通过动态扩容机制减少内存浪费,也就是用存储的业务数据长度判断用什么方法存储;Stirng是由多个sdshdr5、sdshdr8、sdshdr16、sdshdr32等方法组成,每个方法中有len(长度)、char[]、flags组成,其中flags是由type(数据范围)和len(数据长度 )组成,flags是在真实数据往前偏移1个byte的位置;
List类型在redis中的实现?
答:list是有序的数据结构,按照插入顺序排序,通过quicklist(双向链表)和ziplist实现的;ziplist是紧凑的结构有:zibytes(当前list的占用空间)、zitail(定位结尾数据的偏移量)、zllen(当前list中存储的个数)、zlend(当前list的结尾)、entry(prerawlen表示前面第一个元素,为0、len表示前面数据长度、data)主要存储数据;
其中quicklist(双向链表)是ziplist和linkedList的优化,通过head指向头部,通过tail指向尾部,每个quicklist(双向链表)中用quicklistNode包含一个ziplist,多个ziplist用双向指针串联起来;
通过内存优化提供存取效率,在redis.conf文件中:1)list-max-ziplist-size -2:设置ziplist最大容量; 2)list-compress-depth 0:压缩范围;
Hash类型在redis中的实现?
答:hash的数据结构其实是dict(字典)是无序的,用key和value存储,当数据小时用ziplist存储,数据的大小和元素阈值可通过参数设置;
Redis怎么解决哈希冲突?
答:首先hash会根据数组的长度求模,这时key会拿到数组的索引位置,hash有两个特点:1)相同的输入一定能得到相同的输出;2)不同的输入有可能得到相同的输出,也就是哈希冲突;redis通过链表法解决冲突,通过next指针指向原有的key,如果没有就是null;
Set和hset的区别?
答:首先set和String中的命令,hset是hash中的命令,set可以通过expire设置过期时间而hset在单个filed不行,set每执行一次就会多一个key,造成内存消耗过高,而hset以hash散列表的形式存储比较节省内存;
Set类型在redis中的实现?
答:set是无序的自动去重的集合类型,底层数据结构value是为null的dict(字典),当数据是整形时用intset存储(有序),否则用hashtable存储(无序);
Zset类型在redis中的实现?
答:zset是有序的,优先根据score排序,score相同用元素字典排序,会自动去重,底层数据结构是用dict(字典)+skiplist(跳表)其中跳表的底层使用链表存的,数据少时用ziplist结构存储;
Redis支持的数据类型到跳跃表?
答:zskiplist就是一个跳表,其中header 和 tail 指针分别指向表头和表尾节点,length 记录了节点数量,level 记录了所有节点中层级最高的节点的层级,表头节点的层高不计算在内,zskiplistNode是跳表的一个节点,每个节点的层级都是根据幂次定律(power law,越大的树出现的概率越小)随机生成的,它是1~32之间的一个数,作为level数组的大小;
Redis跳跃表?
答:跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。Redis只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构;
Redis的命令
Redis中mset(批量)和set(单次)操作的区别是什么?
答:第一是命令有却别,单次用set插入,用get获取数据,批量用mset插入,mget批量获取;第二是IO,每次操作会产生rasp协议,转成tcp,最后转成IP,如果是单次的话会重复以上操作,造成IO浪费,而批量只会损失一次即可;
redis中的常用的命令有哪些?
答:redisCommand数据结构存储着redis命令,其中负数代表至少有多少个参数,整数代表只能有两个;特殊:flushdb:清空数据库;String类型的命令有:1)type key:查看key的类型都是String;2)object encoding key:查看key在redis底层的实际存储类型;3)Incr key:对key进行递增或递减;4)strlen key:获取val的长度;5)help @string:查看String操作命令; 6)mset:批量插入数据;7)mget:批量查询数据;8)append key:字符串追加值;9)strlen key:查看长度; list类型的命令有:1)help @list:查看操作命令;2)lpush key:从左插入(入队列);3)lrange key 0 -1:从左获取所有数据;4)lpop key:从左查数据(出队列);5)rpush key:从右插入(入队列);6)rpop key:从右查数据(出队列);7)ltrim key 0 3:删除不是0到3的数据; 8)blpop key 秒:阻塞队列; hash类型的命令有: 1)help @hash:查看操作命令;2)hset:插入数据;set类型命令有: 1)help @set:查看操作命令;2)sadd key:插入数据;3)smembers key:查询数据; zset类型命令有:1)help @sorted_set:查看操作命令;
Redis中mset(批量)和set(单次)操作的区别是什么?
答:第一是命令有却别,单次用set插入,用get获取数据,批量用mset插入,mget批量获取;第二是IO,每次操作会产生rasp协议,转成tcp,最后转成IP,如果是单次的话会重复以上 操作,造成IO浪费,而批量只会损失一次即可;
热KEY重建有什么风险,如何优化?
答:设置的缓存过期了,有大量的请求访问同一个key,缓存失效的话可能会有大量的线程重建,造成数据库压力比较大;解决办法:1)通过集群方式分发缓解;2)服务端先将请求本地缓存;3)通过多级请求,层层过滤key缓解;
Redis中大key(bigkey)解决办法?
答:存在的问题:1)读写bigkey会导致超时严重,甚至阻塞服务;2)大key相关的删除或者自动过期时,会出现qps突降或者突升的情况,极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求;3)占用资源;解决办法:1)将大key分拆成多个key,value用multiGet获取值,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;2)将分拆的key,value用hash存储,用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性;3)按照存储元素进行规则分类,分散存储到多个redis实例中;4)可以利用pipeline管道,一次发送多个命令,无需等待服务端返回;