3. 为什么要设置两个Survivor区呢?From 和 To?
一、Redis是单线程还是多线程?
redis5.0之前是单线程,指的是它内部的worker线程是单线程。
它的机制是一个人处理例如set name get name两个由两个客户端分别发送的指令。一个worker线程进行读取指令、计算、返回数据的工作。对客户端发送的指令以串行的方式进行执行。
redis6.0以后有了多线程的概念。
假设有两个客户端,客户端1发送set name指令,首先新开辟一个IO子线程用于读取指令,然后由worker线程进行计算,得到的结果由IO子线程返回给客户端1。
二、新生代和老年代。
堆分为新生代和老年代。新生代又可以分为eden区和survivor区。survivor可以分为from区和to区。
![](https://img-blog.csdnimg.cn/img_convert/a68de232f66817e54fe47e36c6d09494.png)
1. 为什么要分新生代和老年代?
如果不分新老代,内存就一整块,垃圾收集器每次都要把那些长期存在的对象,和生命周期很短的对象放在一起回收,一般长生命周期的对象可能跟应用生命周期一致,你基本回收不掉的,比如Spring 框架里面的Bean管理相关的对象(ApplicationContext),整个应用运行期间都存在,这种一般经过几次回收最后都放在老年代,但是如果不区分新老代,每次都一起回收,性能消耗很大。
区分新老代之后,老年代放长期存活的对象,新生代就放生命周期短的对象,老年代对象很稳定,新生代回收不影响老年代,回收效率能大大提高。
2. 为什么新生代还要分Eden、From、To区域呢?
首先大部分对象生命周期是很短的,如果新生代不分多个区域,新生代可能会有二种回收方案
第一种可能:
每次回收都在新生代整块内存上进行,完整的垃圾回收过程分三步:
- 需要先找到需要清理的对象标记;
- 清理这些被标记的对象;
- 移动剩下的对象,对达到老年代晋升年龄的对象移动到老年代。
对象被回收掉后会产生很多内存碎片(被回收的对象很多),如果要解决内存碎片,需要移动剩下的对象(标记整理算法),整个回收流程效率很低。
第二种可能:
如果没有Survivor区(From + To),Minor GC(新生代回收)过程中,存活的对象直接被送到老年代,这样的话老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC),Full GC频繁会影响程序的执行和响应速度。
新生代的回收叫MinorGC 老年代的回收叫MajorGC
3. 为什么要设置两个Survivor区呢?From 和 To?
标记复制算法流程:
- Eden区域+Survivor From区满,进行存活对象标记,标记完,把存活对象复制到Survivor To区域;
- Survivor To区域变成From区域(一个逻辑标识),From区域变成To区域;
- 内存分配,继续步骤1,复制过程中有达到老年代晋升年龄(默认值15),移动到老年代。
三、哨兵机制
- 假设有一个主机 两台从机。此时有三个哨兵,哨兵一发送心跳给主节点,但是主节点可能已经挂掉了,没有给哨兵一响应信息,对于哨兵一,这个称为主观下线。接着哨兵二给主节点也发送心跳但没有响应。三个哨兵中有两个认为它下线(有一半的哨兵认为),那主节点就是真的下线了。这个称为客观下线。
- 哨兵的选举符合奇数原则,即哨兵的总数为奇数。因为哨兵一第一个发现主节点下线,哨兵一申请做leader,由leader决定哪个从节点当老大。但是其他哨兵也可以对自己投票,最后由票数超过一半且超过它配置的quorum票数的哨兵获选。
- 假设哨兵一获选,决定一个从节点升级为主节点,进行故障转移操作。
四、http证书的底层实现原理?
前置知识:
- 公钥用于加密,私钥用于解密,它们是一对存在的,用于对数据进行加密。它们就是xx00一大堆东西的字符串。
- 证书就是一大堆公钥的文件,它放在服务端内。
实际情况:
- 当客户端发起https请求访问服务端,第一次建立连接的时候,它做的是把客户端的证书(公钥)下载下来。
- 客户端生成随机密码串(对称密码)并使用AES(高级加密标准,最常见的加密对称算法。)加密业务数据(随机生成例如123456的密码。假如对zip压缩包进行加密,123456就是打开压缩包的密码)再通过公钥使用RSA(公钥密码算法)对该随机密码串进行加密(即对123456这个密码进行加密),然后把AES密文和RSA密文发送到服务端,服务端使用密钥(私钥)对RSA密文解密得到密码串,再用密码串对AES密文进行解密得到业务数据。
五、零拷贝技术?
文件从本地发送到服务端,其传统传输流程是从硬盘到网卡,经历了四次拷贝。
• 第一次拷贝,把磁盘上的数据拷贝到操作系统内核的缓冲区里,这个拷贝的过程是通过 DMA 搬运的。测试100M大小文件需要时间4毫秒。
• 第二次拷贝,把内核缓冲区的数据拷贝到用户的缓冲区里,于是我们应用程序就可以使用这部分数据了,这个拷贝到过程是由 CPU 完成的。需要时间200毫秒。
• 第三次拷贝,把刚才拷贝到用户的缓冲区里的数据,再拷贝到内核的 socket 的缓冲区里,这个过程依然还是由 CPU 搬运的。需要时间200毫秒。
• 第四次拷贝,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程又是由 DMA 搬运的。需要时间4毫秒。
零拷贝的技术有两种
• mmap + write(RocketMQ)
• sendfile(Kafka)
1. mmap+write
它使用了内存映射技术,在系统启动的时候划分出一块磁盘的区域来跟应用层的内存直接对应。所以磁盘到应用缓冲区由原来的两次变为一次。整体上使用了三次拷贝。
通过使用 mmap() 来代替 read(), 可以减少一次数据拷贝的过程。
2. sendfile
• 第一步,通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;
• 第二步,缓冲区描述符和数据长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里,此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝;
sendfile方法合并了read和write的操作,降低了上下文切换次数。
这就是所谓的零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。
零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运。
参考资料
特别提醒:文章所有知识来自于参考资料和学习后的个人理解。
1. 全网独一家!聊聊Redis是单线程还是多线程?全套流程告诉你
https://www.bilibili.com/video/BV1bZ4y1w77s?share_source=copy_web
2.【阿里二面】面试官问为什么新生代不用标记清除算法
https://blog.csdn.net/zhengwangzw/article/details/116672024?utm_source=app&app_version=4.6.1
3. Redis哨兵机制选举大会?(前阿里架构师老詹举办)
https://www.bilibili.com/video/BV1U44y167vr?share_source=copy_web
4. 互联网安全之HTTP证书的底层实现原理?前阿里架构师亲授
https://www.bilibili.com/video/BV1s84y1F7xd?share_source=copy_web
5.【硬核面试】你搞懂-零拷贝了吗?阿里百万级并发技术!
https://www.bilibili.com/video/BV1J54y187La?share_source=copy_web