蔚来感觉更多是tob...面试问的也是偏业务

更多内容可关注微信公众号/B站:小生凡一

一面

先聊项目,再谈八股

1. channel 缓冲与非缓冲

读操作的协程将不会阻塞直到缓冲区为空。

非缓冲可以实现读写同步

2. mysql引擎

InnoDB、MyISAM
MyISAMInnoDB
事务不支持支持
外键不支持支持
表锁行锁
索引类型非聚集索引聚集索引
全文索引支持 FULLTEXT 类型的全文索引不支持 FULLTEXT 类型的全文索引,但是 innodb 可以使用 sphinx 插件支持全文索引,并且效果更好
优势大量的SELECT读操作大量的 INSERT or UPDATE 操作

3. 索引如何建立?

TEXT和BLOG类型的字段,进行全文检索会很浪费时间。

4. linux 如何看进程

  1. ps aux :ps命令用于报告当前系统的进程状态。
  2. ps -elf :-e:显示系统内的所有进程信息,-l:使用长(long)格式显示进程信息,-f:使用完整的(full)格式显示进程信息。
  3. top
  4. pstree -aup

5. redis 字符串的底层

简单动态字符串(simple dynamic string,SDS)
sds.h/sdshdr

SDS 示例

SDS示例


  • free 属性的值为0,表示这个SDS没有分配任何未使用空间
  • len 属性的值为7,表示这个SDS保存了一个七字节长的字符串
  • buf 属性是一个char类型的数组,数组的前七个字节分别保存了FANONEA中的这几个字符,最后一个字节则保留了空字符 '\0' 。

SDS 遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计 算再SDS的 len 属性里面并且为空字符分配额外的1字节空间,以及添加空字符串末尾等操作,都是SDS函数自动完成的。

6. 线程池理解

任务队列和工作线程组成重用线程来避免线程创建的开销

7. 线程池的拒绝策略

我们一般有两种使用拒绝策略的方式:

默认的拒绝策略AbortPolicy自定义拒绝策略 

8.悲观锁,乐观锁

乐观锁与悲观锁只是一种思想。

本线程操作特定数据时不会有其它线程执行操作
在操作特定数据的过程中一定有其它线程去操作这条数据

9. HTTP 各个版本的区别

HTTP 1.0 :

  • 请求方式新增了POST,DELETE,PUT,HEADER等方式
  • 扩充了传输内容格式,图片、音视频资源、二进制等都可以进行传输

HTTP 1.1:

基于上面长连接的基础,管道化可以不等第一个请求响应继续发送后面的请求,但响应的顺序还是按照请求的顺序返回

HTTP2.0:

在共享TCP链接的基础上同时发送请求和响应

10. HTTP2.0之前怎么实现服务器推送机制?

HTTP 1.1 默认保持长连接,数据传输完成保持tcp连接不断开,继续用这个通道传输数据。

11. websocket有了解过吗?

是一个基于TCP的长链接,常用于进行IM即时通讯。

12. 什么时候可能产生内存泄漏?

如果发送内存逃逸,就有可能内存泄漏,比如分配在栈上的内存逃逸到了堆上。又或者垃圾回收没回收到这个内存。

13. 页面置换算法有哪些?

先进先出(FIFO)页面置换算法、最近最久未使用(LRU)置换算法、最佳置换算法(OPT)、时钟(CLOCK)置换算法

14. 内存映射?

在虚拟内存实现和内存管理单元中,内存映射是指页面表,这些页面表存储特定进程的虚拟记忆的布局与该空间与物理内存地址的关系之间的映射。 可以用虚拟内存来映射到到真实的内存管理单元中。

算法:最长公共子串

2. 二面

还是聊项目,再谈八股

1. 讲讲AES加密

作为DES的替代算法,AES (Advanced Encryption Standard) 在设计上满足以下标准:

  • 和DES一样,能有效抵御所有已知攻击;
  • 加密算法易于现有软硬件平台的实现,且加解密过程效率优于DES;
  • 具有典型的对称分组加密算法特性,以快速混淆和扩散为设计原则,本质是轮函数过程的循环。

AES的数据分组长度统一为128位,而密钥空间可根据需要采用128位、192位和256位三种不同长度。和大多数分组加密算法不一样AES的轮函数并没有采用Feistel结构设计,而是使用了3个不同的可逆均匀变换。

AES 对称加密主要步骤包括:

密钥扩展(Key Expansion)初始轮(Init Round)重复轮(Rounds)最终轮(Final Round)

接下来就具体讲讲这个加密的过程: 密钥扩展:目的是将一个128位的密钥扩展10次变成11个128位的秘钥来用于接下来的轮密钥加操作。

密钥扩展


字节替换:将被替换的字节按照高4位做x坐标,低4位做y坐标在sBox中找到替换到的字节表示。sBox是通过一种特定的(求有限域内各元素的乘法逆元和仿射变换的)方式得到的16*16的矩阵,就比如是4f这个字节在sBox中就是第4行第15列的字节0x84代替0X4f。

字节替换


行移位:接下来是行移位,第一行不变,第二行左移1个字节,第三行左移2个字节,第四行左移3个字节。解密时的行移就是相反的,第一行还是不变,第二行左移3个字节,第三行左移2个字节,第四行左移1个字节。

行移位

列混合: AES算法中最复杂的部分,它混合了输入的每一列,使得输入的每个字节都会影响到输出的四个字节。分别将当前组中的每一列乘一个固定矩阵,这里的矩阵乘法和一般的矩阵乘法不同,就像下面这张图一样,乘的结果在相加时用的是异或运算,最后用结果取代原字节序列。

列混合

轮密钥加:就是将列混合得到的结果中的每一列分别与密钥中的每一列做异或,然后取代原字节序列,实现也很简单,就是一个异或操作。

轮密钥加


完整加/解密流程:

完整加/解密流程

2. 那RSA有了解过吗

非对称加密算法有RSA、DSA和ECDSA
公钥和私钥,公钥公开,私钥保留;公钥加密密文发送给接收方私钥进行解密
对称加密密钥传输

下图就是生成公私钥的具体流程

生成公私钥
需要特别注意转换后的数字X需要小于密钥组中的N,如果字符串转换后的数字大于N则需要进行拆分,这也是在数据量大时我们使用对称加密算法来尽心加密内容,用非对称加密来加密密钥的原因。

加密过程满足:

解密过程:我们获得密文Y后哦,开始解密,过程如下


上述过程涉及到了欧拉定理和费尔马小定理在这里就不过多描述。接下来我们讨论一下这个RSA算法的安全性,这个算法是否安全可靠?

φ(N)P和QN=pq,只有将N进行因数分解

所以,如果大数N可以被因数分解,私钥D就可以算出,从而破解密文。 大整数的因数分解是极其困难的,属于NPC问题,除了暴力破解没有很好的解决方案,目前人类分解的最大长度的二进制数为768位,1024位的长度目前尚未破解,因此1024长度的二进制密钥是安全的。所以RSA算法的安全性取决于大整数分解的难度,目前RSA算法可以支持4096位密钥长度,分解难度超乎想象,即使借助于量子计算机难

3. 怎么理解公私钥,以及签名

公钥相等于是公开的钥匙,私钥相当于是自己的钥匙。公钥和私钥是成对的,它们互相解密。

除了保证数据的安全传输之外,公钥体系的另一个用途就是对数据进行签名。通常 “数字签名”是用来验证发送方的身份并帮助保护数据的完整性。

例如:一个发送者 A 想要传些资料给大家,用自己的私钥对资料加密,即签名。这样一来,所有收到资料的人都可以用发送者的公钥进行验证,便可确认资料是由 A 发出来的了。(因为只有A使用私钥签名得到的信息,才能用这个公钥来解) 采用数字签名,可以确认两点:

签名者自己签名发送的,签名者不能否认或难以否认自签发后到收到为止未曾作过任何修改
私钥只有签名者持有

总结就是: 公钥加密,私钥解密。 私钥数字签名,公钥验证。

4. 我看你用到了MQ,那这个rabbitmq消息会丢失吗?

会,但是我们可以保证消息不丢失。

发送方确认模式

confirm模式(发送方确认模式)

如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack消息。

发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。

当确认消息到达生产者应用程序,生产者应用的回调方法就会被触发来处理确认消息。

接收方确认机制

消费者接受每一条消息后都必须进行确认,只要有消费者确认了消息,MQ才能安全的把消息从队列中删除。

这里并没有用到超时机制,MQ仅通过 Consumer 的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证了数据的最终一致性。

还有几种情况:

  • 如果消费者接受到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消费重复的隐患,需要去重)
  • 如果消费者接受到消息却没有确认消息,连接也未断开,则 RabbitMQ 认为该消费者繁忙。则不会给该消费者分发更多的消息。

5. MYSQL 乱序insert和有序insert区别?补充 针对innoDB引擎。

首先来看顺序插入的情况。如果主键是顺序的,所以InnoDB会把每插入的记录存储在上一条记录的后面。当达到页的最大填充因子时(InnoDB默认的最大填充因子是15/16,流出不封空间用于以后可能产生的修改),下一条记录就会写入新的页中。 一旦数据按照这种顺序的的方式插入,主键就会近似于被顺序的记录填满。这是正常的情况。

可能比上一个插入的主键值大,也可能小说插入的位置很有可能是在现有数据的中间

这种随机插入方式可能会有以下缺点:

内存缓存区磁盘页是已经加载到内存不断的的做页分裂操作移动大量的数据数据碎片

所以,当把随机值载入到聚簇索引后,最好做一次optimize table来重建表并优化页的填充。很费性能....

间隙锁竞争

6. 哈夫曼树有了解吗?

带权路径长度最短的二叉树

7. 讲讲用户态和内核态?

用户空间中的代码被限制了只能使用一个局部的内存空间,我们说这些程序在用户态(User Mode) 执行。 内核空间中的代码可以访问所有内存,我们称这些程序在内核态(Kernal Mode) 执行。
用户态程序权限不足,因此会中断执行,也就是 Trap(Trap 是一种中断)。
内核程序开始执行,也就是开始处理系统调用。

8. 用户态和内核态切换都做了什么?

当发生用户态到内核态的切换时,会发生如下过程 (本质上是从“用户程序”切换到“内核程序”)

  1. 设置处理器至内核态。
  2. 保存当前寄存器(栈指针、程序计数器、通用寄存器)。
  3. 将栈指针设置指向内核栈地址。
  4. 将程序计数器设置为一个事先约定的地址上,该地址上存放的是系统调用处理程序的起始地址。

而之后从内核态返回用户态时,又会进行类似的工作。

9. 如何避免频繁的用户态和内核态的切换?

  1. 减少线程切换,比如锁的并发编程,有锁的话,不断地释放和加锁会引起较多地上下文切换
  2. CAS算法,避免阻塞现场。
  3. 使用协程,在单线程中实现多任务地调度,并在单线程里维持多喝任务间地切换。

10. 为什么频繁加锁会引起较多的上下文切换?

Synchronized 是通过对象内部的一个叫做监视器锁(monitor)来实现的。

Mutex Lock需要将当前线程挂起并从用户态切换到内核态来执行,这种切换的代价是非常昂贵的因此重量级锁

算法:滑动窗口最大值

参考链接