本博客整理牛客网上面经的疑难问题
后面会跟着自己的解答,解答包括自己的理解和搜索到的内容
文章目录
- 猫眼面经
- 1、String为什么不可变?
- 2、String是否线程安全
- 3、Https的对称加密和非对称加密
- 4、Linux 如何查看负载;负载一般是多少;
- 5、 git 操作,使用经历;怎么开分支,怎么切换,怎么merge;
- 6、redis的LRU策略的实现;AOF文件写满会如何
- 7、日志的作用;MVCC 的用处;MVCC 解决了幻读吗;
- 8、. 场景题,设计一个排序榜。
- 9、tcp三次握手及四次挥手原因,timewait的原型,icmp属于
- 10、死锁产生的条件,以及如何避免死锁,银行家算法,产生死锁后如何解决
- 11、为什么要实现双亲委派模型
- 12、虚拟机调优参数
- 13、进程间的通信
- 14、innnodb和myisam的区别,各自的b数索引叶子节点分别存储什么
- 15、拆箱装箱的原理
- 16、md5加密的原理
- 17、CMS垃圾收集器
- 18、happen-before
- 19、不用乘法实现乘法
- 20、数组的最大连续子串和
- 21、.http发送的包里面有什么,TCP/IP五层结构,如果网络情况不好,三次握手怎么保证认证
- 22、java的线程和操作系统的线程什么关系
- 23、一个西瓜切九刀最多切多少块
- 24、having和where的区别
- 25、写了个分层打印二叉树,用队列实现
- 有赞面经
- 1、netty的原理,nioEventLoop的作用
- 2、AQS底层,非公平锁怎么实现的,加锁和释放锁怎么实现的?
- 3、Redis的底层是一个大的hashmap,怎么扩容的,底层是单线程的,扩容的时候会阻塞吗?
- 4、Zoo[keep]()er的作用,如果挂了会怎么样,知道XXX注册中心吗?说一下和Nacas的区别?
- 5、怎么统计concurrentHashmap的size?
- 6、说一下Spring IOC的[源码]()吧,说一下三级缓存怎么解决循环依赖,两级缓存可以吗
- 7、知道LongAtomic吗? 在哪里使用知道不?
- 8、MySQL的主从原理
- 9、多机登录问题?分布式session
- 10、 做接口优化的思路是怎么样的?(用阿尔萨斯查看)。阿尔萨斯原理是怎么样的?
- 11、 怎么解决多机任务争抢的?乐观锁
- 12、 数据膨胀怎么办?服务怎么保证高可用?
- 13、 ES怎么用的?倒排索引讲一下?
- 14、100层楼扔两个啤酒瓶,花费最少次数找到临界楼层
- 顺丰面经
- 1、防止提前秒杀怎么实现? 令牌的值为什么设置库存的5倍
- 2、介绍MQ在项目中怎么用, MQ处理失败怎么办
- 3、表跟表怎么关联的。 用户去下单,这个过程中涉及到什么表
- 4、聚簇索引和非聚簇索引的区别
- 5、JVM 的内存模型, 局部变量放在哪里
- 6、多线程锁的引用场景
- 7、服务端分页怎么做的?
- 8、如何查看sql执行计划?
- 9、为什么索引能加快查询速度?
- 10、如果from子句两个表用“,”隔开,解释一下该子句的意思?
- 11、ThreadPoolExecutor的构造函数参数有哪些? 拒绝策略介绍下? 默认的拒绝策略是哪一个?
- 12、synchronized关键字修饰一个类的static方法与普通成员方法,两个线程同时分别调用这两个方***阻塞吗?
- 13、有一条sql语句执行很慢,如何排查问题?
- 14、假设有一个String str = new String("hello world");这条语句创建了几个对象,分别在JVM的哪个区域?
- 15、什么时候会开启核心线程以外的线程?
- 16、什么时候会用到拒绝策略?
- 17、最后问个场景题,现在要查询数据库,数据两位2千万行,使用多线程实现,你有什么思路吗?不能重复读取,数据全部读取完之后才进行数据操作。
- 18、假设有一个线程查询失败如何处理?
- 19、复制[算法]()好处
- 20、新生代内存结构
- 21、spring事务 事务传播机制
- 22、分布式与微服务了解吗
- 美团面经
- 1、redis支持多核吗?
- 2、redis的value支持多大?
- 3、100k的数据适合用memcached还是redis?
- 4、mq有几种?区别了解吗?(rabbitmq,rocketmq,kafka区别)
- 5、TCP/IP五层有哪些?为什么分层?
- 6、交换机,路由器是哪一层?物理层是啥?
- 7、TCP和Http的区别?
- 8、http是基于tcp还是udp?
- 9、tcp的报文头?有报文长度嘛?
- 10、粘包问题怎么解决?(添加报文长度、每个报文结尾加分隔符、报文设置固定长度、发送方关闭nagle算法)
- 11、滑动窗口,拥塞控制说一下,窗口满了怎么办?缓冲了解吗?
- 12、四次挥手状态位?客户端处于finwait1的时候还能给服务端发数据吗?
- 13、定义一个Integer,存在哪?
- 14、多线程解决的问题是什么?有缺点吗?
- 15、调用start和run的区别?sleep和wait区别?
- 16、垃圾回收算法有哪些?在哪里进行?
- 17、微博大V每次发微博,如何设计一个接口,给大V的所有粉丝进行推送消息?
- 18、删除链表中节点值等于target的节点。
- 19、ConcorrentHashMap锁住的是什么(忘了,是锁住关键字对应的红黑树或链表,还是数组的某个区间)
- 20、两个value为-1025的Integer对象是否相等(a = -1025, b=-1025,a==b是否为true)
- 21、两个value为-125的对象是否相等
- 22、线程切换和进程切换的区别
- 23、进程的调度算法
- 24、内核态和用户态的区别
- 25、GET和POST的区别
- 26、TCP确保传输正确的方法
- 27、spring相比servlet开发的优势在哪里
- 28、sql注入是什么,如何防范
- 29、在一个数组中,时间复杂度O(n)找出左边比右边大的最大值,比如a[] = {1,3,7,5,2,9,8},左边选出7,右边选2,他们差值最大,为5。
- 网易面经
- 1、线程池说一下,workQueue有哪些,ListBlockingQueue和SynchronousQueue有什么区别
- 2、CAS,Atomic包
- 3、linux怎么看系统性能
- 4、如果有个java进程cpu占有率特别高,如何排查问题
- 5、redis数据结构及过期清除策略(惰性和定期),为什么不使用redis的队列作为传送秒杀消息的中间件
- 6、rabbitmq与kafka的对比,针对你说的kafka会有较低几率重发消息有验证过吗
- 7、写查询,mysql查找一个表中重复列值的个数,join查询会写吗
- 8、知道mysql中的锁吗,说一下表锁,行锁,如何上锁(for update),举个例子在什么时候事务会进入阻塞状态
- 9、在Java中如何使用事务,回答Spring中使用注解,提示不对,没想出来
- 10、docker是什么,有实际应用过吗(讲了下docker是基于OO思想,仅了解)
- 11、给实例,让设计用例,给一个接口如何测试它的QPS,你的秒杀接口返回的状态码有哪些?
- 12、有没有想过缓存某一刻失效,而此时有大量请求数据库是否会崩,崩了后如何恢复,有试过提升你的数据库瓶颈吗
- 13、为什么JVM年轻代要分区
- 14、动态代理的局限性
- 15、哪些情况不用建立索引
- 16、where b=1 order by a 怎么建立索引 where a=1 or b=2 怎么建立索引
- 17、虚拟内存
- 18、怎么把一个异步操作改成同步
- 19、多线程 对1000张大小不同的图片做模糊处理
- 20、怎么防止dns劫持
- 21、Http2.0的特点 多路复用是怎么实现的 介绍一下Http2.0的帧
- 22、设计一个图片库需要考虑什么(如果图片特别大怎么办)
- 23、讲一下你使用开源库的经历
- 24、对全局变量第一个线程循环10次i++,第二个线程循环10次i--,最后结果是什么?
- 滴滴面经
- 1、你觉得http和https的端口为什么不能一样
- 2、每天有五千万的订单,你会怎么去设计一个数据库
- 3、上述的数据库怎么让我快速的查询到我要的数据
- 4、怎么排除慢查询怎么调优呢
- 5、mysql的回表查询知道吗
- 6、行锁在查询的时候会锁住哪些行
- 7、短作业优先是怎么实现的
- 8、长连接除了解决网络io方面还解决了什么问题
- 9、你认为红黑树一般应用在什么场景
- 10、如果没有spring需要你做个类似spring的程序跟我说下大概的思路
- 11、http2.0有了解吗
- 12、jdk1.8垃圾回收有什么新的变化
- 13、两个文件中有一亿个url 我需要你找到两者重复的
- 14、用java写个限流器
- 15、inner join和left join有什么区别
- 16、inner join会命中索引吗
- 17、慢查询 数据量较大的时候你是怎么查的
- 18、有个单例,来了请求就++操作 如果来了第二个请求 前一个请求的++操作会丢失吗
- 19、IP转物理地址是怎么做到的
- 20、arp协议在哪一层
- 21、arp协议在客户端还是服务端
- 腾讯面经
- 1、布隆过滤器
- 2、如果我网页上QQ,本地登一个QQ,要获取登录状态,用的是哪个通信方式
- 3、线程通信,具体解释一下
- 4、怎么实现验证码功能
- 5、怎么判断验证码
- 6、session底层实现
- 7、输入baidu用的协议 ?是get还是post
- 8、Redis Zset是有序的吗 ,Redis Zset的底层实现 ,跳表的底层实现
- 9、spring是怎么使用AOP的方式配置事务的,什么是静态代理什么是动态代理,动态代理的好处(解耦)
- 10、进程的地址空间 。地址空间包括物理空间以及虚拟空间。每个程序在启动之后都会拥有自己的虚拟地址空间(Virtual Address Space),这个虚拟地址空间的大小由计算机平台决定,具体一点说由操作系统的位数和CPU的地址总线宽度所决定,其中CPU的地址总线宽度决定了地址空间的理论上限
- 11、虚拟地址
- 12、讲项目,做安全方面的考虑了吗?没做,提到会受到XSS攻击,面试官正好是想问这个的,讲讲什么是XSS什么是csrf,如何预防?对于敏感操作要求用户输入验证码;过滤用户的请求;设置cookie为http-only。过滤是指过滤的什么?HTTP-ONLY的作用
- 13、支持的用户登录方式,怎么存的用户密码,md5可逆吗,是在前端就转化为MD5,还是后台,在后台做的目的?
- 14、https建立连接的过程,证书中包含什么
- 15、隆过滤器,数组中存的是什么(01)
- 阿里面经
- 1、如果有一个项目线程数量一直在缓慢增加可能是哪些原因导致的,怎么解决?
- 2、如何辨别出有问题的线程?
- 3、Synchronized的底层实现,从偏向锁到重量锁的升级过程中各阶段的头部是怎么变化的?什么时候会触发各阶段的锁升级?
- 4、g1和cms分别适用于哪些场合?g1有哪些改进?
- 5、垃圾标记算法中的计数法有什么问题
- 6、tcp连接过程中syn_sent连接数过多会是什么原因造成的?
- 7、事务的传播机制有哪些,分别应用于什么场景?
- 8、一个单增数组,将前面一部分挪到末尾,怎么找到最大的那个
- 9、有100块石头,A和B交替拿,每人一次拿1-5块,如果A先拿,第一次拿几块才能保证最后自己一定能赢
- 10、求最大子串数字之和
- 11、对一个大文件的数据进行排序,内存肯定放不下,怎么办?
- 12、堆排的排序思路和过程
- 13、concurrentHashMap的结构,是怎么实现线程安全?get方法要不要加锁,为什么?
- 14、CAS的缺点是什么,怎么解决ABA问题?
- 15、为什么只读场景下Myisam比innoDB快?
- 16、讲解一下你常用的框架功能和原理
猫眼面经
1、String为什么不可变?
答:从底层源码入手分析;
(1)常量与变量
在理解常量和变量之前需要首先理解堆和栈的概念。
- 变量:一般是把内存地址不变,值可以改变的东西称为变量。换句话说,在内存地址不变的前提下,内存的内容是可变的
- 常量:一般把内存地址不变,则值也不可以改变的东西叫做常量。换句话说,对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变,即在栈中的引用不能改变
(2)什么是不可变对象
String变量一旦初始化后就不能更改(指的是内容不能改变,由char【】数组长度不可变,由于数组的性质决定)
如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态指的是不能改变对象内的成员变量
(3)引用和对象
引用代表的是地址
String s=“ABCDEF”;
s=“123456”;
首先会创建一个 String 对象 s (栈中),然后让 s 的值为“ABCabc”(堆内存中分配空间), 然后又让 s 的值为“123456”(堆内存)。从打印结果可以看出,s 的值确实改变了。那么怎么还说String对象是不可变的呢?其实这里存在一个误区:
s 只是一个 String 对象的引用,并不是对象本身。对象在内存中(指堆内存)是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个 4 字节的数据(在栈中,代表指向堆内存的地址),里面存放了它所指向的对象的地址,通过这个地址可以访问对象。也就是说,s 只是一个引用,它指向了一个具体的对象,当 s=“123456”; 这句代码执行过之后,又创建了一个新的对象“123456”, 而引用 s 重新指向了这个新的对象,原来的对象“ABCabc”还在内存中存在,并没有改变。内存结构如下图所示:
图片
Java 和 C++ 的一个不同点是,在 Java 中,引用是访问、操纵对象的唯一方式:我们不可能直接操作对象本身,所有的对象都由一个引用指向,必须通过这个引用才能访问对象本身,包括获取成员变量的值,改变对象的成员变量,调用对象的方法等。而在C++中存在引用,对象和指针三个东西,这三个东西都可以访问对象。其实,Java中的引用和C++中的指针在概念上是相似的,他们都是存放的对象在内存中的地址值,只是在Java中,引用丧失了部分灵活性,比如Java中的引用不能像C++中的指针那样进行加减运算。
(4)String对象不可变
可以看出String类其实就是对字符数组char【】的封装。
那么在 String 中,明明存在一些方法,调用他们可以得到改变后的值。这些方法包括substring(), replace(), replaceAll(), toLowerCase()等。
其实在底层中,比如在调用 a.replace(‘A’, ‘a’) 时, 方法内部创建了一个新的 String对象 ,并把这个心的对象重新赋给了引用 a
(5)String对象一定是不可变的吗?
在我们写的普通代码中做不到,因为我们访问不了这个value引用,更不能通过引用修改数组。
但是用反射可以反射出String对象中的value属性,进而改变通过获得的value引用改变数组的结构。
(6)String对象创建方式
A:字面值形式
String s=“123”;
该种方式先在栈中创建一个对String类的对象引用变量s,然后去查找 “abc”是否被保存在字符串常量池中。若 ”abc” 已经被保存在字符串常量池中,则在字符串常量池中找到值为”abc”的对象,然后将 s 指向这个对象; 否则,在堆中创建char数组 data,然后在堆中创建一个 String 对象 object,它由 data 数组支持,紧接着这个String对象 object 被存放进字符串常量池,最后将 s 指向这个对象。
所以使用这种方式判断两个对象是否相等,那么结果是true
B:通过new创建字符串对象
通过 new 操作产生一个字符串(“abc”)时,会先去常量池中查找是否有“abc”对象,如果没有,则创建一个此字符串对象并放入常量池中。然后,在堆中再创建“abc”对象,并返回该对象的地址。所以,对于 String str = new String(“abc”):如果常量池中原来没有”abc”,则会产生两个对象(一个在常量池中,一个在堆中);否则,产生一个对象。
用 new String() 创建的字符串对象位于堆中,而不是常量池中。它们有自己独立的地址空间
2、String是否线程安全
答:String类通过final修饰,是不可变的,不可变类都是线程安全的。
Java final的用途?
1、final可以修饰类,方法和变量,
2、final修饰的类,不能被继承,即它不能拥有自己的子类,
3、final修饰的方法,不能被重写,
4、final修饰的变量,无论是类属性、对象属性、形参还是局部变量,都需要进行初始化操作。
3、Https的对称加密和非对称加密
HTTPS 的全称是 Hypertext Transfer Protocol Secure,从名称我们可以看出 HTTPS 要比 HTTPS 多了 secure 安全性这个概念,实际上, HTTPS 并不是一个新的应用层协议,它其实就是 HTTP + TLS/SSL 协议组合而成,而安全性的保证正是 TLS/SSL 所做的工作。
也就是说,HTTPS 就是身披了一层 SSL 的 HTTP。
HTTPS 是安全的协议,它通过 密钥交换算法 - 签名算法 - 对称加密算法 - 摘要算法 能够解决上面这些问题。
HTTPS的加解密流程
- 用户在浏览器发起HTTPS请求(如 https://www.mogu.com/),默认使用服务端的443端口进行连接;
- HTTPS需要使用一套CA数字证书,证书内会附带一个公钥Pub,而与之对应的私钥Private保留在服务端不公开;
- 服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
- 客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
- 客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
- 服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
- 服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
- 客户端使用随机Key对称解密密文,得到HTTP数据明文;
- 后续HTTPS请求使用之前交换好的随机Key进行对称加解密。
对称加密与非对称加密
对称加密是指有一个密钥,用它可以对一段明文加密,加密之后也只能用这个密钥来解密得到明文。如果通信双方都持有密钥,且天知地知你知我知,绝对不会有别的人知道,那么通信安全自然是可以得到保证的(在密钥足够强的情况下)。
然而,在HTTPS的传输场景下,服务端事先并不知道客户端是谁,你也不可能在事先不通过互联网和每一个网站的管理员都悄悄商量好一个通信密钥出来,那么必然存在一个密钥在互联网上传输的过程,如果在传输过程中被别人监听到了,那么后续的所有加密都是无用功。
这时,我们就需要另一种神奇的加密类型,非对称加密。
非对称加密有两个密钥,一个是公钥,另一个是私钥。一般来说,公钥用来加密,这时密文只能用私钥才能解开。
那么,当客户端发起连接请求,服务端将公钥传输过去,客户端利用公钥加密好信息,再将密文发送给服务端,服务端里有私钥可以解密。
但是,当服务端要返回数据,如果用公钥加密,那么客户端并没有私钥用来解密,而如果用私钥加密,客户端虽然有公钥可以解密,但这个公钥之前就在互联网上传输过,很有可能已经有人拿到,并不安全,所以这一过程只用非对称加密是不能满足的。
,严格来讲,私钥并不能用来加密,只能用作签名使用,这是由于密码学中生成公钥私钥时对不同变量的数学要求是不同的,因此公钥私钥抵抗攻击的能力也不同,在实际使用中不可互换。签名的功能在HTTPS里也有用到,下文中会说明。
此时,两条传输方向的数据都经过非对称加密,都能保证安全性,那么为什么不采用这种方案呢?
最主要的原因是非对称加解密耗时要远大于对称加解密,对性能有很大损耗,大家的使用体验很差。
所以,我们才最终选用了上文介绍到非对称加密+对称加密的方案,
- 服务端有非对称加密的公钥A1,私钥A2;
- 客户端发起请求,服务端将公钥A1返回给客户端;
- 客户端随机生成一个对称加密的密钥K,用公钥A1加密后发送给服务端;
- 服务端收到密文后用自己的私钥A2解密,得到对称密钥K,此时完成了安全的对称密钥交换,解决了对称加密时密钥传输被人窃取的问题
- 之后双方通信都使用密钥K进行对称加解密。
为了兼顾性能和安全性,使用了非对称加密+对称加密的方案。
为了保证公钥传输中不被篡改,又使用了非对称加密的数字签名功能,借助CA机构和系统根证书的机制保证了HTTPS证书的公信力。
4、Linux 如何查看负载;负载一般是多少;
答:负载(load)是linux机器的一个重要指标,直观了反应了机器当前的状态。如果机器负载过高,那么对机器的操作将难以进行。
Linux的负载高,主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多,都将导致服务器负载的急剧攀升。
- 查看服务器负载有多种命令,w或者uptime都可以直接展示负载,
- cpu的负载情况: 使用top来动态的显示,直接在命令行中输入 top 就能显示如下图所示
load average是显示的是cpu的负载情况,三个数分别是1分钟,5分钟,15分钟的平均负载情况,对于单核来说cpu负载大于1的时候说明负载已经严重了,多核的时候是大于n(n为核数)。这里有点争议,应为单核的时候大于1并不意味着cpu就是已经用尽了,所以这里有的人认为负载可以达到2n的时候才认为负载比较严重。
Tasks行展示了目前的进程总数及所处状态,要注意zombie,表示僵尸进程,不为0则表示有进程出现问题。
Cpu(s)行展示了当前CPU的状态,us表示用户进程占用CPU比例,sy表示内核进程占用CPU比例,id表示空闲CPU百分比,wa表示IO等待所占用的CPU时间的百分比。wa占用超过30%则表示IO压力很大。在top下按1会显示每个cpu的负载情况,注意cpu那行的变化。
Mem行展示了当前内存的状态,total是总的内存大小,userd是已使用的,free是剩余的,buffers是目录缓存。
Swap行同Mem行,cached表示缓存,用户已打开的文件。如果Swap的used很高,则表示系统内存不足。
- 网络io的负载情况ifstat:
ifstat sentos没有自带,需要下载安装
- 磁盘io的负载情况使用的是iostat:
输入iostat -x 1 10命令,表示开始监控输入输出状态,-x表示显示所有参数信息,1表示每隔1秒监控一次,10表示共监控10次
5、 git 操作,使用经历;怎么开分支,怎么切换,怎么merge;
答:
6、redis的LRU策略的实现;AOF文件写满会如何
答:redis内存淘汰机制:
- noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
Redis为什么不使用真实的LRU实现是因为这需要太多的内存。不过近似的LRU算法对于应用而言应该是等价的。
LRU原理
优先删除最远访问时间的
放入和移除都是 O(1) 的
实现LRU
1、利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访问的数据项。
2、继承LInkedHashMap的简单实现
LinkedHashMap底层就是用的HashMap加双链表实现的,而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了一个方法removeEldestEntry用于判断是否需要移除最不常读取的数,方法默认是直接返回false,不会移除元素,所以需要重写该方法。即当缓存满后就移除最不常用的数。
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int CACHE_SIZE;
// 这里就是传递进来最多能缓存多少数据
public LRUCache(int cacheSize) {
// 设置一个hashmap的初始大小,最后一个true指的是让linkedhashmap按照访问顺序来进行排序,最近访问的放在头,最老访问的就在尾
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
// 当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据
return size() > CACHE_SIZE;
}
}
Redis 的LRU实现
如果按照HashMap和双向链表实现,需要额外的存储存放 next 和 prev 指针,牺牲比较大的存储空间,显然是不划算的。所以Redis采用了一个近似的做法,就是随机取出若干个key,然后按照访问时间排序后,淘汰掉最不经常使用的,具体分析如下:
为了支持LRU,Redis 2.8.19中使用了一个全局的LRU时钟,server.lruclock,定义如下,
#define REDIS_LRU_BITS 24
unsigned lruclock:REDIS_LRU_BITS; /* Clock for LRU eviction */
默认的LRU时钟的分辨率是1秒,可以通过改变REDIS_LRU_CLOCK_RESOLUTION宏的值来改变,Redis会在serverCron()中调用updateLRUClock定期的更新LRU时钟,更新的频率和hz参数有关,默认为100ms一次,如下,
#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1) /* Max value of obj->lru /
#define REDIS_LRU_CLOCK_RESOLUTION 1 / LRU clock resolution in seconds */
void updateLRUClock(void) {
server.lruclock = (server.unixtime / REDIS_LRU_CLOCK_RESOLUTION) &
REDIS_LRU_CLOCK_MAX;
}
server.unixtime是系统当前的unix时间戳,当 lruclock 的值超出REDIS_LRU_CLOCK_MAX时,会从头开始计算,所以在计算一个key的最长没有访问时间时,可能key本身保存的lru访问时间会比当前的lrulock还要大,这个时候需要计算额外时间,如下,
/* Given an object returns the min number of seconds the object was never
- requested, using an approximated LRU algorithm. */
unsigned long estimateObjectIdleTime(robj *o) {
if (server.lruclock >= o->lru) {
return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
} else {
return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) *
REDIS_LRU_CLOCK_RESOLUTION;
}
}
Redis支持和LRU相关淘汰策略包括,
volatile-lru 设置了过期时间的key参与近似的lru淘汰策略
allkeys-lru 所有的key均参与近似的lru淘汰策略
当进行LRU淘汰时,Redis按如下方式进行的,
…
/* volatile-lru and allkeys-lru policy */
else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||
server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
{
for (k = 0; k < server.maxmemory_samples; k++) {
sds thiskey;
long thisval;
robj *o;
de = dictGetRandomKey(dict);
thiskey = dictGetKey(de);
/* When policy is volatile-lru we need an additional lookup
* to locate the real key, as dict is set to db->expires. */
if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
de = dictFind(db->dict, thiskey);
o = dictGetVal(de);
thisval = estimateObjectIdleTime(o);
/* Higher idle time is better candidate for deletion */
if (bestkey == NULL || thisval > bestval) {
bestkey = thiskey;
bestval = thisval;
}
}
}
......
Redis会基于server.maxmemory_samples配置选取固定数目的key,然后比较它们的lru访问时间,然后淘汰最近最久没有访问的key,maxmemory_samples的值越大,Redis的近似LRU算法就越接近于严格LRU算法,但是相应消耗也变高,对性能有一定影响,样本值默认为5。
出处:https://www.cnblogs.com/weknow619/p/10730653.html
AOF文件写满怎么办
AOF重写:
(1) 随着AOF文件越来越大,里面会有大部分是重复命令或者可以合并的命令(100次incr = set key 100)
(2) 重写的好处:减少AOF日志尺寸,减少内存占用,加快数据库恢复时间。
执行一个 AOF文件重写操作,重写会创建一个当前 AOF 文件的体积优化版本。
即使 BGREWRITEAOF 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 BGREWRITEAOF 成功之前不会被修改。
从 Redis 2.4 开始,AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。但网上有网友说已经3.2.5版本了,貌似redis还是没有自动触发BGREWRITEAOF
稳妥的方法还写一个脚本每天定时去执行
1,出现问题 :redis集群中某个节点 报错信息如下:
Starting automatic rewriting of AOF on 307% growth
Error opening /setting AOF rewrite IPC pipes: Numerical result out of range
这个错误的意思是redis中aof文件超出存储的最大内容
2,解决方法为:
将aof文件重命名为【文件.aof.(数字)】,如appendonly.aof.1
然后创建原文件
如果问题还没有解决,将出现问题的redis节点进行重启
7、日志的作用;MVCC 的用处;MVCC 解决了幻读吗;
答:
8、. 场景题,设计一个排序榜。
答:
9、tcp三次握手及四次挥手原因,timewait的原型,icmp属于
答:
10、死锁产生的条件,以及如何避免死锁,银行家算法,产生死锁后如何解决
答:
11、为什么要实现双亲委派模型
答:
12、虚拟机调优参数
答: