redis面试问题(二)
1.redis和其他缓存相比有哪些优点呢
见上一篇
2. 你刚刚提到了持久化,能重点介绍一下么
见上一篇
3.Redis中对于IO的控制做过什么优化?
pipeline?
4 有没有尝试进行多机redis 的部署?如何保证数据一致的?
主从复制,读写分离
1、redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
2、通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。
1:当一个从数据库启动时,会向主数据库发送sync命令,
2:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来
3:当快照完成后,redis会将快照文件和所有缓存的命令发送给从数据库。
4:从数据库收到后,会载入快照文件并执行收到的缓存的命令。
5. 我们把数存到redis的一个节点,在另一个节点却能查询到,这是怎么实现的呢
主从复制?
6. 说一下强一致性和最终一致性
一致性又可以分为强一致性与弱一致性。
强一致性可以理解为在任意时刻,所有节点中的数据是一样的。同一时间点,你在节点A中获取到key1的值与在节点B中获取到key1的值应该都是一样的。
弱一致性包含很多种不同的实现,目前分布式系统中广泛实现的是最终一致性。
所谓最终一致性,就是不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。也可以简单的理解为在一段时间后,节点间的数据会最终达到一致状态。
对于最终一致性最好的例子就是DNS系统,由于DNS多级缓存的实现,所以修改DNS记录后不会在全球所有DNS服务节点生效,需要等待DNS服务器缓存过期后向源服务器更新新的记录才能实现。
类似的,还有一些其它的弱一致性实现,下面摘自《NoSQL数据库笔谈》https://docs.google.com/View?id=dc23x53c_64db5px4f6
Causal consistency(因果一致性)
7. Redis用的什么协议
Redis从1.2版本开始,设计了一套统一的协议格式,作者讲到自己设计的协议在下面几个方面进行了权衡:
- 实现简单
- 快速通过计算机解析
- 容易让人阅读
如果我们需要自己实现一个Redis客户端程序,有必要了解一下Redis的协议格式。在网络层面,客户端通过TCP连接到Redis服务器(默认端口6379,可以通过配置文件修改),客户端与服务器之间发送的命令以\r\n(CR LF)结尾。
https://blog.csdn.net/hu2010shuai/article/details/52946116
8.对于大量的请求怎么样处理
redis是一个单线程程序,也就说同一时刻它只能处理一个客户端请求;
redis是通过IO多路复用(select,epoll, kqueue,依据不同的平台,采取不同的实现)来处理多个客户端请求的,伪代码:
9.怎么样设计调度算法
10.两个文件,上亿个URL怎么样找出重复的。
题目描述:给A,B两个文件,各存放50亿条URL,每条URL占用64个字节,内存限制为4G,找出A,B中相同的URL。
分析:我们先来看如果要把这些URL全部加载到内存中,需要多大的空间。
1MB = 2^20 = 10^6 = 100W
1GB = 2^30 = 10^9 = 10亿
50亿 = 5G * 64 Byte = 320G
明显是不可能全部加载到内存中的。我们可采用以下方法解决:
方法1:
采用Bloom filter,假设布隆过滤器的错误率为0.01,则位数组大小m约为输入元素个数n的13倍,此时需要的哈希函数k约为8个。
元素个数:n = 5G
位数组大小:m = 5G * 13 = 65G = 650亿 即需要650亿个bit位才能达到错误率0.01
而我们拥有的内存可容纳bit位个数:4G * 8bit = 32G bit = 320亿,按此实现错误率大于0.01。
方法2:
分别扫描A,B两个文件,根据hash(url)%k(k为正整数,比如k = 1000,那么每个小文件只占用300M,内存完全可以放得下)将url划分到不同的k个文件中,比如a0,a1,....a999;b0,b1,...b999;这样处理后相同的url肯定在对应的小文件中(a0 vs b0,a1 vs b1,...a999 vs b999)因为相同的url%1000的值肯定相同,不对应的小文件不可能有相同的url;然后我们只要求出1000对小文件中相同的url即可。比如对于a0 vs b0,我们可以遍历a0,将其中的url存放到hash_map中,然后遍历b0,如果b0中的某个url在hash_map中,则说明此url在a和b中同时存在,保存下来即可。
http://www.360doc.com/content/16/0331/22/16915_546938410.shtml
11.聊聊 Redis 使用场景
见上一篇
以下三个集群的问题完全不懂
12.Redis 集群方案与实现
https://www.cnblogs.com/kerwinC/p/6611634.html
https://www.cnblogs.com/me115/p/9043420.html#h21
https://blog.csdn.net/u010963948/article/details/78963572
13.问我Redis怎么做集群,答了主从哨兵和cluster。
14.redis3.0原生集群和redis读写分离+哨兵机制区别
https://blog.csdn.net/keketrtr/article/details/78802571
15.Redis 为什么是单线程的
官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)
Redis总体快速的原因:
采用队列模式将并发访问变为串行访问(?)
单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),其他模块仍用了多个线程。
总体来说快速的原因如下:
1)绝大部分请求是纯粹的内存操作(非常快速)
2)采用单线程,避免了不必要的上下文切换和竞争条件
3)非阻塞IO
内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间
这3个条件不是相互独立的,特别是第一条,如果请求都是耗时的,采用单线程吞吐量及性能可想而知了。应该说redis为特殊的场景选择了合适的技术方案。
16.缓存崩溃
见上一篇缓存雪崩
17.缓存降级
https://www.cnblogs.com/leeSmall/p/8594542.html
18.使用缓存的合理性问题
热点数据
对于冷数据而言,读取频率低,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。
对于热点数据,读取频率高。如果不做缓存,给数据库造成很大的压力,可能被击穿。
修改频率
数据更新前至少读取两次,缓存才有意义。这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。(读取频率>修改频率)
如果这个读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到Redis缓存,减少数据库压力
缓存更新机制
一般情况下,我们采取缓存双淘汰机制,在更新数据库的时候淘汰缓存。此外,设定超时时间,例如30分钟。极限场景下,即使有脏数据入cache,这个脏数据也最多存在三十分钟。
在高并发的情况下,设计上最好避免查询Mysql,所以在更新数据库的时候更新缓存。
缓存可用性
缓存是提高数据读取性能的,缓存数据丢失和缓存不可用不会影响应用程序的处理。因此,一般的操作手段是,如果Redis出现异常,我们手动捕获这个异常,记录日志,并且去数据库查询数据返回给用户。
服务降级
服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。