指引:html
1、面试题:redis中zset的score值同样,那它是按什么排序的:按字典值排序
java
在score相同的状况下,redis使用字典排序,而所谓的字典排序其实就是“ABCDEFG”这样的排序,在首字母相同的状况下,redis会再比较后面的字母,仍是按照字典排序。
node
二、假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,若是将它们所有找出来?mysql
使用keys指令能够扫出指定模式的key列表。可是redis的单线程的,keys指令会致使线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。面试
这个时候可以使用scan指令,scan指令能够无阻塞的提取出指定模式的key列表,可是会有必定的重复几率,在客户端作一次去重就能够了,可是总体所花费的时间会比直接用keys指令长。redis
Redis有5个基本数据结构,string、list、hash、set和zset。
算法
Redis列表是简单的字符串列表,按照插入顺序排序。可添加一个元素到列表头部或尾部
List为一个双向的链表,便可用做栈,也能够用做队列。List同时支持头和尾的操做
sql
Redis 列表命令
Redis Lpush 命令将一个或多个值插入到列表头部。
Redis Rpop 命令用于移除并返回列表的最后一个元素。
Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。
应用:
一、消息队列
二、文章列表或者数据分页展现的应用
三、例如新闻列表页面最新的新闻列表
zset应用:排行榜zset:字典与跳跃表数据库
其中,字典(也称为hashtable或散列表)api
Strings类型:一个String类型的value最大能够存储512M
Lists类型:list的元素个数最多为2^32-1个,也就是4294967295个。
Sets类型:元素个数最多为2^32-1个,也就是4294967295个。
Hashes类型:键值对个数最多为2^32-1个,也就是4294967295个。
Sorted sets类型:跟Sets类型类似。
一、缓存穿透,是指查询一个必定不存在的数据,因为缓存是不命中时被动写( 被动写,指的是从 DB 查询到数据,则更新到缓存中 )的,而且处于容错考虑,若是从 DB 查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到 DB 去查询,失去了缓存的意义。 在流量大时,可能 DB 就挂掉了,要是有人利用不存在的 key 频繁攻击咱们的应用,这就是漏洞。
解决方法:
方案一,缓存空对象:当从 DB 查询数据为空,咱们仍然将这个空结果进行缓存,具体的值须要使用特殊的标识,能和真正缓存的数据区分开。另外,须要设置较短的过时时间,通常建议不要超过 5 分钟。
方案二,BloomFilter 布隆过滤器:在缓存服务的基础上,构建 BloomFilter 数据结构,在 BloomFilter 中存储对应的 KEY 是否存在,若是存在,说明该 KEY 对应的值为空。
- 简介:布隆过滤器其实是一个很长的二进制向量和一系列随机映射函数。布隆过滤器能够用于检索一个元素是否在一个集合中。它的优势是空间效率和查询时间都远远超过通常的算法,缺点是有必定的误识别率和删除困难。
- 原理:当一个元素被加入集合时,经过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,咱们只要看看这些点是否是都是1就(大约)知道集合中有没有它了:若是这些点有任何一个0,则被检元素必定不在;若是都是1,则被检元素极可能在。
- 思想步骤:
1. 位数组:初始状态时,BloomFilter是一个长度为m的位数组,每一位都置为0。
2. 添加元素(k个独立的hash函数)
添加元素时,对x使用k个哈希函数获得k个哈希值,对m取余,对应的bit位设置为1。
3. 判断元素是否存在
判断y是否属于这个集合,对y使用k个哈希函数获得k个哈希值,对m取余,全部对应的位置都是1,则认为y属于该集合(哈希冲突,可能存在误判),不然就认为y不属于该集合。原文连接:https://blog.csdn.net/qq_18495465/article/details/78500472
二、缓存雪崩,是指缓存因为某些缘由没法提供服务( 例如,缓存挂掉了 ),全部请求所有达到 DB 中,致使 DB 负荷大增,最终挂掉的状况。
解决方法:
1)缓存高可用
2)本地缓存
3)请求 DB 限流
4)服务降级
5)提早演练
一、纯内存操做。 Redis 为了达到最快的读写速度,将数据都读到内存中,并经过异步的方式将数据写入磁盘。因此 Redis 具备快速和数据持久化的特征。 若是不将数据放在内存中,磁盘 I/O 速度为严重影响 Redis 的性能。
二、核心是基于非阻塞的 IO 多路复用机制。
三、单线程反而避免了多线程的频繁上下文切换问题。 Redis 利用队列技术,将并发访问变为串行访问,消除了传统数据库串行控制的开销
四、Redis 全程使用 hash 结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
学习:IO多路复用的三种机制Select,Poll,Epoll 从新学习
redis 采用网络IO多路复用技术来保证在多链接的时候, 系统的高吞吐量。
多路-指的是多个socket链接,复用-指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll是最新的也是目前最好的多路复用技术。
这里“多路”指的是多个网络链接,“复用”指的是复用同一个线程。采用多路I/O复用技术可让单个线程高效的处理多个链接请求(尽可能减小网络IO的时间消耗),且Redis在内存中操做数据的速度很是快(内存内的操做不会成为这里的性能瓶颈),主要以上两点造就了Redis具备很高的吞吐量。
1.在写库先后都进行redis.del(key)操做,而且设定合理的超时时间。
2.具体的步骤就是:
1)先删除缓存
2)再写数据库
3)休眠500毫秒:须要评估本身的项目的读数据业务逻辑的耗时
4)再次删除缓存
3.设置缓存过时时间
从理论上来讲,给缓存设置过时时间,是保证最终一致性的解决方案。全部的写操做以数据库为准,只要到达缓存过时时间,则后面的读请求天然会从数据库中读取新值而后回填缓存。
4.该方案的弊端
结合双删策略+缓存超时设置,这样最差的状况就是在超时时间内数据存在不一致,并且又增长了写请求的耗时。
1.技术总体思路:
MySQL binlog增量订阅消费+消息队列+增量数据更新到redis
1)读Redis:热数据基本都在Redis
2)写MySQL:增删改都是操做MySQL
3)更新Redis数据:MySQ的数据操做binlog,来更新到Redis
2.Redis更新
1)数据操做主要分为两大块:
这里说的是增量,指的是mysql的update、insert、delate变动数据。
2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
这样一旦MySQL中产生了新的写入、更新、删除等操做,就能够把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
其实这种机制,很相似MySQL的主从备份机制,由于MySQL的主备也是经过binlog来实现的数据一致性。
这里能够结合使用canal(阿里的一款开源框架),经过该框架能够对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。
固然,这里的消息推送工具你也能够采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。
以上就是Redis和MySQL数据一致性详解
摘自:零壹技术栈
在 Redis 中,实现 高可用 的技术主要包括 持久化、复制、哨兵 和 集群,下面简单说明它们的做用,以及解决了什么样的问题:
主:写,从:读
Redis 主从复制可将主节点数据同步给从节点,从节点此时有两个做用:
主从复制同时存在如下几个问题:
- 一旦主节点宕机,从节点晋升成主节点,同时须要修改应用方的主节点地址,还须要命令全部 从节点去复制新的主节点,整个过程须要人工干预。
- 主节点的写能力受到单机的限制。
- 主节点的存储能力受到单机的限制。
- 原生复制 的弊端在早期的版本中也会比较突出,好比:Redis 复制中断 后,从节点 会发起 psync。此时若是 同步不成功,则会进行 全量同步,主库 执行 全量备份 的同时,可能会形成毫秒或秒级的卡顿。
哨兵模式就是不时地监控redis是否按照预期良好地运行(至少是保证主节点是存在的),若一台主机出现问题时,哨兵会自动将该主机下的某一个从机设置为新的主机,并让其余从机和新主机创建主从关系。
哨兵模式也存在单点故障问题,若是哨兵机器挂了,那么就没法进行监控了,解决办法是哨兵也创建集群,Redis哨兵模式是支持集群的。
Sentinel 的主要功能包括 主节点存活检测、主从运行状况检测、自动故障转移 、主从切换。Redis 的 Sentinel 最小配置是 一主一从。
Redis 的 Sentinel 系统能够用来管理多个 Redis 服务器,该系统能够执行如下四个任务:
Sentinel 会不断的检查 主服务器 和 从服务器 是否正常运行。
当被监控的某个 Redis 服务器出现问题,Sentinel 经过 API 脚本 向 管理员 或者其余的 应用程序 发送通知。
当主节点不能正常工做时,Sentinel 会开始一次自动的故障转移操做,它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,而且将其余从节点指向新的主节点
在 Redis Sentinel 模式下,客户端应用 在初始化时链接的是 Sentinel 节点集合,从中获取主节点的信息。
redis集群核心原理:gossip通讯、jedis Smart定位、主备切换
可能会懵逼,又是 Redis 主从复制,又是 Redis 分区,又是 Redis 集群。傻傻分不清啊!
客户端就已经决定数据会被存储到哪一个 redis 节点或者从哪一个 redis 节点 读取数据。其主要思想是采用 哈希算法 将 Redis 数据的 key 进行散列,经过 hash 函数,特定的 key会 映射 到特定的 Redis 节点上。
优势:不使用第三方中间件,分区逻辑可控,配置简单,节点之间无关联,容易线性扩展,灵活性强。
缺点:客户端没法动态增删服务节点,客户端须要自行维护分发逻辑,客户端之间无链接共享,会形成链接浪费。
代理分区,意味着客户端将请求发送给代理,而后代理决定去哪一个节点写数据或者读数据。代理根据分区规则决定请求哪些 Redis 实例,而后根据 Redis 的响应结果返回给客户端。
优势:简化客户端的分布式逻辑,客户端透明接入,切换成本低,代理的转发和存储分离
缺点:多了一层代理层,加剧了 架构部署复杂度和性能损耗。
代理分区主流实现的有方案有 Twemproxy 和 Codis。
01. Twemproxy
Twemproxy 也叫 nutcraker,是 twitter 开源的一个 redis 和 memcache 的 中间代理服务器 程序。Twemproxy 做为 代理,可接受来自多个程序的访问,按照 路由规则,转发给后台的各个 Redis 服务器,再原路返回。Twemproxy 存在单点故障问题,须要结合 Lvs 和 Keepalived 作 高可用方案。
02. Codis
Codis 是一个 分布式 Redis 解决方案,对于上层应用来讲,链接 Codis-Proxy 和直接链接 原生的 Redis-Server 没有的区别。Codis 底层会 处理请求的转发,不停机的进行 数据迁移 等工做。Codis 采用了无状态的 代理层,对于 客户端 来讲,一切都是透明的。
客户端随机地 请求任意一个 Redis 实例,而后由 Redis 将请求 转发 给 正确 的 Redis 节点。Redis Cluster 实现了一种 混合形式 的 查询路由,但并非 直接 将请求从一个 Redis 节点 转发 到另外一个 Redis 节点,而是在 客户端 的帮助下直接 重定向( redirected)到正确的 Redis 节点。
开源方案 Redis-cluster
Hash slot。集群内的每一个redis实例监听两个tcp端口,6379(默认)用于服务客户端查询,16379(默认服务端口 + 10000)用于集群内部通讯。
- key的空间被分到16384个hash slot里;
- 计算key属于哪一个slot,CRC16(key) & 16384。
- 用hash tag能够手动指定key对应的slot,同一个hash tag下的key,都会在一个hash slot中,好比set mykey1:{100}和set mykey2:{100};
- 节点间状态同步:gossip协议,最终一致性。节点间通讯使用轻量的二进制协议,减小带宽占用。
- 16379 端口号是用来进行节点间通讯的,也就是 cluster bus 的东西,cluster bus 的通讯,用来进行故障检测、配置更新、故障转移受权。cluster bus 用了另一种二进制的协议,
gossip
协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
Redis-Cluster借助客户端实现了混合形式的路由查询
查询路由并不是直接从一个redis节点到另一个redis,而是借助客户端转发到正确的节点。根据客户端的实现方式,能够分为如下两种:包括Jedis在内的许多redis client,已经实现了对Redis Cluster的支持。
Redis cluster采用这种架构的考虑:
具体路由过程
- 减小redis实现的复杂度
- 下降客户端等待的时间。Smart client能够在客户端缓存 slot 与 redis节点的映射关系,当接收到 MOVED 响应时,会修改缓存中的映射关系。请求时会直接发送到正确的节点上,减小一次交互。
Redis Cluster 的客户端相比单机Redis 须要具有路由语义的识别能力,且具有必定的路由缓存能力。当Client 访问的key 不在当前Redis 节点的 slots 中,Redis 会返回给Client 一个moved命令。并告知其正确的路由信息,以下所示:
当Client 接收到moved 后,再次请求新的Redis时,此时Cluster 的结构又可能发生了变化(slot 迁移)。此时有可能再次返回moved 。Client 会根据 moved响应,更新其内部的路由缓存信息,以便后续的操做直接找到正确的节点,减小交互次数。
基于重定向的客户端,很消耗网络io,由于大部分状况下,可能都会出现一次请求重定向,才能找到正确的节点; 因此大部分的客户端好比java redis客户端,都是jedis,都是smart的,
本地维护一份hashslot -> node的映射表在缓存里,大部分状况下直接走本地缓存就能够找到hashslot -> node,不须要经过节点进行moved重定向;
redis-cluster群集高可用架构:参考
若是一个节点认为另一个节点宕机,name就是pfail,主观宕机;
若是多个节点都认为另一个节点宕机了,那么就是fail,客观宕机,跟哨兵的原理几乎同样,sdown,odown;
在cluster-node-timeout内,某个节点一直没有返回pong,那么就被认为pfail;
若是一个节点认为某个节点pfail了,那么会在gossip ping消息中,ping给其余节点,若是超过半数的节点都认为pfail了,那么就会变成fail;
对宕机的master node,从其全部的slave node中,选择一个切换成master node;
检查每一个slave node与master node断开链接的时间,若是超过了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资格切换成master;
哨兵:对全部从节点进行排序,slave priority,offset,run id;
每一个从节点,都根据本身对master复制数据的offset,来设置一个选举时间,offset越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举;
全部的master node开始slave选举投票,给要进行选举的slave进行投票,若是大部分master node(N/2 + 1)都投票给了某个从节点,那么选举经过,那个从节点能够切换成master;
从节点执行主备切换,从节点切换为主节点;
整个流程跟哨兵相比,很是相似,因此说,redis cluster功能强大,直接集成了replication和sentinal的功能;
redis集群核心原理: 转载自 https://blog.csdn.net/qq_33814629/article/details/79904158
来了一个 key,首先计算 hash 值,而后对节点数取模。使用公式:hash(key)% N
计算出 哈希值,用来决定数据 映射 到哪个节点上。 而后打在不一样的 master 节点上。
一旦某一个 master 节点宕机,全部请求过来,都会基于最新的剩余 master 节点数去取模,尝试去取数据。这会致使大部分的请求过来,所有没法拿到有效的缓存,致使大量的流量涌入数据库。
一致性 hash 算法将整个 hash 值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个 master 节点(使用服务器的 ip 或主机名)进行 hash。这样就能肯定每一个节点在其哈希环上的位置。
来了一个 key,首先计算 hash 值,并肯定此数据在环上的位置,今后位置沿环顺时针“行走”,遇到的第一个 master 节点就是 key 所在位置。
在一致性哈希算法中,若是一个节点挂了,受影响的数据仅仅是此节点到环空间前一个节点(沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不受影响。增长一个节点也同理。
燃鹅,一致性哈希算法在节点太少时,容易由于节点分布不均匀而形成缓存热点的问题。为了解决这种热点问题,一致性 hash 算法引入了虚拟节点机制,即对每个节点计算多个 hash,每一个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
redis cluster 有固定的 16384
个 hash slot,对每一个 key
计算 CRC16
值,而后对 16384
取模,能够获取 key 对应的 hash slot。
redis cluster 中每一个 master 都会持有部分 slot,好比有 3 个 master,那么可能每一个 master 持有 5000 多个 hash slot。hash slot 让 node 的增长和移除很简单,增长一个 master,就将其余 master 的 hash slot 移动部分过去,减小一个 master,就将它的 hash slot 移动到其余 master 上去。移动 hash slot 的成本是很是低的。客户端的 api,能够对指定的数据,让他们走同一个 hash slot,经过 hash tag
来实现。
任何一台机器宕机,另外两个节点,不影响的。由于 key 找的是 hash slot,不是机器。
Redis 提供 RDB 和 AOF 两种数据的持久化存储方案,解决内存数据库最担忧的万一 Redis 挂掉,数据会消失。
Redis 提供了两种方式来将数据持久化到硬盘。
如何选择
Redis 支持同时开启开启两种持久化方式,咱们能够综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,做为数据恢复的第一选择; 用 RDB 来作不一样程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可使用 RDB 来进行快速的数据恢复。
默认 Redis 是会以快照 “RDB” 的形式将数据持久化到磁盘的,一个二进 制文件,dump.rdb
工做原理简单介绍一下:当 Redis 须要作持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处就是能够 copy-on-write。
Redis默认状况下,是快照 RDB 的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是 dump.rdb 。固然咱们也能够手动执行 save 或者 bgsave(异步)作快照。
使用 AOF 作持久化,每个写命令都经过write函数追加到 appendonly.aof 中,配置方式:启动 AOF 持久化的方式
Redis.conf配置
appendfsync yes
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。复制代码
若是你很是关心你的数据,但仍然能够承受数分钟之内的数据丢失, 那么你能够只使用 RDB 持久。 AOF 将 Redis 执行的每一条命令追加到磁盘中,处理巨大的写入会下降 Redis 的性能,不知道你是否能够接受。 数据库备份和灾难恢复:定时生成 RDB 快照(snapshot)很是便于进行数据库备份, 而且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。
Redis 支持同时开启 RDB 和 AOF,系统重启后,Redis 会优先使用 AOF 来恢复数据,这样丢失的数据会最少。
参考:https://juejin.im/post/5bb02c42e51d450e92524b6f
参考:在面试pdd的时候有问到相关的问题:
1. 全部的过时指令最终都变成了PEXPIREAT指令
2. redis保存一份过时字典,键是一个指针,指向某个键对象,值是过时时间,一个毫秒精度的时间戳。过时字典与键空间中的键指向的是一个地址,不存在空间浪费。
redis采用的是惰性删除跟按期删除。
参考:
连接:https://juejin.im/post/5bb02c42e51d450e92524b6f
http://youzhixueyuan.com/reasons-for-redis-fast.html
http://youzhixueyuan.com/redis-cache-and-mysql-data-consistency.html
http://svip.iocoder.cn/Redis/Interview/#Redis-