1.https的具体握手流程,是先非对称加密还是先对称加密???
HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段
非对称加密的加解密效率是非常低的,而 http 的应用场景中通常端与端之间存在大量的交互,非对称加密的效率是无法接受的。
另外:在 HTTPS 的场景中只有服务端保存了私钥,一对公私钥只能实现单向的加密和解密,所以 HTTPS 中内容传输加密采取的是对称加密,而不是非对称加密。
2.CA证书具体是怎么验证的???
1)验证域名、有效期等信息是否正确:证书上都有包含这些信息,比较容易完成验证;
2)判断证书来源是否合法:每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证
3)判断证书是否被篡改:需要与 CA 服务器进行校验;
4)判断证书是否已吊销:通过CRL(Certificate Revocation List 证书注销列表)和 OCSP(Online Certificate Status Protocol 在线证书状态协议)实现,其中 OCSP 可用于第3步中以减少与 CA 服务器的交互,提高验证效率。
以上任意一步都满足的情况下浏览器才认为证书是合法的。
3.HTTP的请求指令(GET,POST)这些在请求头还是请求行还是请求体???简单
4.除了GET和POST还有哪些请求指令???简单
5.Radis的String底层是怎么实现的??简单
6.Radis的持久化方式?? 简单
做题:1.手撕单例模式
2.二叉树的Z字型遍历
字节三面:8月5号(45min)
1.自我介绍途中直接打断,不让说完直接开始问
1.1.项目和研究方向全是CV,为什么不去做CV算法要做后端(。。。菜但不想承认)
2.项目每个模块具体功能,详细说
3.Innodb引擎特点有啥,底层是怎么存储的?简单
4.还有别的什么数据库引擎?简单Hash
5.为什么索引要用B+树不用B树???简单
6.有这样一张表,学生和学号,学号已经可以保证唯一性的情况下,是否还需要再加一列自增id???需要
7. select id,name,age From students Where age between(18,21) and city = 'Beijing' 针对这条语句,怎么建立索引
8.如果再加上order by name 怎么建立索引(???)简单
***是那一层的协议(???)
10.DNS是基于什么协议的???如何解析DNS????
1.区域传输时,一个区中主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息,传输协议是tcp。
2.域名解析时一般返回的内容都不超过512字节,首选的通讯协议是udp。使用udp传输,不用经过TCP三次握手,这样DNS服务器负载更低,响应更快
解析DNS域名
1.浏览器查找自己的DNS缓存,如果有直接返回,如果没有进行步骤二
2.操作系统查找自己的DNS缓存,如果有直接返回给浏览器,如果没有进行步骤三
3.操作系统查找自己的本地host文件,如果有返回给浏览器,如果没有则进行步骤四
4.操作系统向本地域名服务器发起请求,查找本地DNS缓存,如果有,返回给操作系统, 然后操作系统返回给浏览器,如果没有进行步骤五
5.操作系统向根域名服务器发起请求得到顶级域名服务器的IP,然后根域名服务器向顶级域名服务器发起请求得到权限域名服务器的IP,顶级域名服务器再向权限域名服务器发起请求得到IP,本地域名服务器返回给操作系统IP,同时将IP缓存起来,操作系统将IP返回给浏览器,同时将IP缓存起来。
11.浏览器输入一个URL后的全过程????
1.根据域名到DNS中找到IP 【如第10问】
2.根据IP建立TCP连接(三次握手)
3.连接建立成功发起http请求
4.服务器响应http请求
5.浏览器解析HTML代码并请求html中的静态资源(js,css)
6.关闭TCP连接(四次挥手)
7.浏览器渲染页面
做题:1.二叉树的右视图
三、字节Java开发实习面经
4月28日 字节一面
1. 先问了问项目
2. 操作系统:虚拟内存??Kafka零拷贝技术???
所有现代操作系统都使用虚拟内存,使用虚拟的地址取代物理地址,虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间)。这样做的好处是:
1)一个以上的虚拟地址可以指向同一个物理内存地址,
2)虚拟内存空间可大于实际可用的物理地址;
在 Linux 中零拷贝技术主要有 3 个实现思路
用户态直接 I/O:应用程序可以直接访问硬件存储,操作系统内核只是辅助数据传输。
这种方式依旧存在用户空间和内核空间的上下文切换,硬件上的数据直接拷贝至了用户空间,不经过内核空间。因此,直接 I/O 不存在内核空间缓冲区和用户空间缓冲区之间的数据拷贝。
减少数据拷贝次数:在数据传输过程中,避免数据在用户空间缓冲区和系统内核空间缓冲区之间的 CPU 拷贝,以及数据在系统内核空间内的 CPU 拷贝,这也是当前主流零拷贝技术的实现思路。
写时复制技术:写时复制指的是当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么将其拷贝到自己的进程地址空间中,如果只是数据读取操作则不需要进行拷贝操作。
缓冲区共享 方式完全改写了传统的 I/O 操作,因为传统 I/O 接口都是基于数据拷贝进行的,要避免拷贝就得去掉原先的那套接口并重新改写。
所以这种方法是比较全面的零拷贝技术,目前比较成熟的一个方案是在 Solaris 上实现的 fbuf(Fast Buffer,快速缓冲区)。
fbuf 的思想是每个进程都维护着一个缓冲区池,这个缓冲区池能被同时映射到用户空间(user space)和内核态(kernel space),内核和用户共享这个缓冲区池,这样就避免了一系列的拷贝操作。
RocketMQ 和 Kafka 对比
RocketMQ 选择了 mmap+write 这种零拷贝方式,适用于业务级消息这种小块文件的数据持久化和传输。
Kafka 采用的是 Sendfile 这种零拷贝方式,适用于系统日志消息这种高吞吐量的大块文件的数据持久化和传输。
但是值得注意的一点是,Kafka 的索引文件使用的是 mmap+write 方式,数据文件使用的是 Sendfile 方式
3. 计算机网络:三次握手,HTTP状态码??简单
4. 数据库:索引的了解,事务的隔离级别,脏读是什么???简单
5. 两个考察算法场景:有一个忘了,还有一个是一亿个数里判断是否出现某个数
6. 刷题:一个数组中找出最短的连续子数组使得除了这个子数组外其他部分已经排好序。我首先说了一下双指针,但是好像有点问题,然后为了保证正确先给了个暴力解法,然后问我还有其他思路嘛?我又往另一个方向去,后来面试官终于提示我,给了我思路,最后还好做出来了.
5月6号 字节二面
1.简单自我介绍,没问项目可能觉得项目太简单啦,问我大概学了多久
2.Java 垃圾回收算法??简单
3.Spring IOC容器初始化的过程有了解嘛?简单
4.Java线程池大概有哪几种?AQS有了解过嘛?
5.四次挥手的过程,Time-Wait的意义是?简单
6.Redis有了解过嘛?分布式事务有了解嘛?简单
7.Linux 如何查询进程占用,top 和ps, top的参数有哪些?
top命令经常用来监控linux的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。
-d:number代表秒数,表示top命令显示的页面更新一次的间隔。默认是5秒。 -b:以批次的方式执行top。 -n:与-b配合使用,表示需要进行几次top命令的输出结果。 -p:指定特定的pid进程号进行观察。 P:以CPU的使用资源排序显示 M:以内存的使用资源排序显示 N:以pid排序显示 T:由进程使用的时间累计排序显示 k:给某一个pid一个信号。可以用来杀死进程 r:给某个pid重新定制一个nice值(即优先级) q:退出top(用ctrl+c也可以退出top)。
ps(process status)进程查看命令。查看正在运行的进程、进程运行状态、进程资源占用等。
1)ps -ef | grep '进程名' e 显示所有进程 f 全格式 2)ps -aux | grep '进程名' a 显示所有程序 u 以用户为主的格式来显示程序状况 x 显示无控制终端的程序
8.概率题:从20双手套中拿3只,其中任意左右手都可以组成一双手套,那么恰好有一双手套的概率
9.场景题:日志文件几个G,希望根据时间戳以最小时间复杂度查找到某个事件段的日志信息。
借助二分法能够快速匹配时间戳,根据时间戳来找出需要查找的日志内容。
查找前提条件:
1 因为是二分法特性,所以日志的时间必须是按从小到大或者从大到小的顺序排列。
2 根据查找需要,修改匹配时间戳。
3 根据不同的时间戳格式,修改对应的代码。
10.最后问你觉得你相比于别人有什么优点?
四、字节跳动 后端开发工程师-商业化技术 一面面经
1.UDP 有什么特点?简单
2.TCP/IP 协议说一下?简单
3.OSI 七层模型与 TCP/IP 五层模型,为什么会有两种模型?这个?
4.从 TCP/IP 五层的角度,分析每一层都做了什么?
简单:没有了会话层 和表示层,分工明确,干活牛
5.epoll 知道吗,有什么优点?知道
6.select、epoll 的区别是什么?文件描述符的限制
一、select的缺点
1、编写难度大
2、同时处理的文件描述符是有上限的
3、每次需要重新设定fd集合
4、性能会随用户的增多而效率降低
二、poll的缺点
poll是对select的一种改良,最突出的改良有两点:
1、文件描述符数量没有上限
2、将输入输出参数进行分离,不用每次设定
那么poll的缺点是
poll中监听的文件描述符数目增多时:
1、和select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
2、每次调用poll都需要大把大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
三、epoll的优点
1、文件描述符数目没有上限 通过epoll_ctl()来注册一个文件描述符,内核中使用红黑树的数据结构来管理所有需要监控的文件描述符。
2、基于事件就绪通知方式 一旦被监听的某个文件描述符就绪,内核会采用类似于callback的回调机制,迅速激活这个文件描述符,这样随着文件描述符数量的增加,也不会影响判定就绪的性能。
3、维护就绪队列 当文件描述符就绪,就会被放到内核中的一个就绪队列中,这样调用epoll_weit获取就绪文件描述符的时候,只要取队列中的元素即可,操作的时间复杂度恒为O(1)。
4、关于有些地方说:epoll还有内存映射机制,即内核将就绪队列通过mmap的方式映射到用户态,避免了拷贝内存这样的额外性能开销。
7.epoll 底层怎么实现事件驱动的,还有 select 底层怎么实现事件驱动的?
8.基于 epoll 主从反应堆怎么设计,有什么优势,换成 select 呢?
9.服务端怎么发送,缓冲区有内容?
10.select 在哪些场景下,更具优势(联系CPU 与磁盘刷新频率,及业务场景),不然为什么没有被时代淹没
11.Linux 内核态与用户态知道吗,为什么区分内核态与用户态?
用户空间:指的就是用户可以操作和访问的空间,这个空间通常存放我们用户自己写的数据等。
内核空间:是系统内核来操作的一块空间,这块空间里面存放系统内核的函数、接口等。
用户态切换到内核态的3种方式:a.系统调用 b.异常 c.外围设备的中断
a.系统调用 :这是用户进程主动要求切换到内核态的一种方式,用户进程通过系统调用申请操作系统提供的服务程序完成工作。
b.异常:当CPU在执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理此
异常的内核相关程序中,也就到了内核态,比如缺页异常(硬中断)。
c.外围设备的中断:当外围设备完成用户请求的操作之后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条将要执行的指令
转而去执行中断信号的处理程序,如果先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了有
用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
12.进程空间说一下?
13.虚拟内存知道吗,虚拟地址?
当一个进程开始执行时,系统就为它开辟了一个虚拟内存空间,这个虚拟内存空间与真正的物理地址映射。
进程开始要访问一个地址,它可能会经历下面的过程
1.每次我要访问地址空间上的某一个地址,都需要把地址翻译为实际物理内存地址
所有进程共享这整一块物理内存,每个进程只把自己目前需要的虚拟地址空间映射到物理内存上
2.进程需要知道哪些地址空间上的数据在物理内存上,哪些不在(可能这部分存储在磁盘上),还有在物理内存上的哪里,这就需要通过页表来记录
页表的每一个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(如果在的话)
3.当进程访问某个虚拟地址的时候,就会先去看页表,如果发现对应的数据不在物理内存上,就会发生缺页异常
4.缺页异常的处理过程,操作系统立即阻塞该进程,并将硬盘里对应的页换入内存,然后使该进程就绪,如果内存已经满了,没有空地方了,那就找一个页覆盖,至于具体覆盖的哪个页,就需要看操作系统的页面置换算法是怎么设计的了。
5.进程运行过程中,要通过malloc来动态分配内存时,也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。
利用虚拟内存机制的优点
1.既然每个进程的内存空间都是一致而且固定的(32位平台下都是4G),所以链接器在链接可执行文件时,可以设定内存地址,而不用去管这些数据最终实际内存地址,这交给内核来完成映射关系
2.当不同的进程使用同一段代码时,比如库文件的代码,在物理内存中可以只存储一份这样的代码,不同进程只要将自己的虚拟内存映射过去就好了,这样可以节省物理内存
3.在程序需要分配连续空间的时候,只需要在虚拟内存分配连续空间,而不需要物理内存时连续的,实际上,往往物理内存都是断断续续的内存碎片。这样就可以有效地利用我们的物理内存
14.虚拟地址底层是怎么实现的,为什么表现得连续,而在物理磁盘上不连续(面试官很耐心,无论从哪个问题,他都能抛出新的点,并且会耐心地讲,然后我慢慢地理解,再复述)
15.扇区、磁盘块?
16.写个题,MySQL 三个表,学生表(id, name),课程表(id,name,credit),id 关联表(stu_id,course_id),题目 a 查询学生 id 所选的总学分,题目 b 查询学生 id 没选的总学分
17.聚簇索引和非聚簇索引的区别?简单
18.聚簇索引有什么优缺点?简单
19.页是什么?
20.写个题,单调栈实现接雨水?
题目描述
LeetCode 42. 接雨水(难度:困难)
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
// 注意:由于栈中存放的是数组的下标,所以需要用到柱子的高度时,记得转换过来 public class 接雨水 { public int trap(int[] height) { // 创建一个单调栈,为了便于后面计算,栈中存放的是数组的下标 LinkedList<Integer> stack = new LinkedList<>(); // 第一个元素先直接入栈 stack.push(0); // 保存雨水的数量 int sum = 0; for (int i = 1; i < height.length; i++) { while (!stack.isEmpty() && height[i] >= height[stack.peek()]) { // 出栈的元素需要保存起来,作为底部参考值 int temp = height[stack.pop()]; // 判断栈是否为空,为空,接不到雨水,直接break if (stack.isEmpty()) { break; } // 不为空,计算雨水 int w = i - stack.peek() - 1; // 宽度 int h = Math.min(height[i], height[stack.peek()]) - temp; // 高度 sum += w * h; } stack.push(i); } return sum; } }
五、2021 年抖音直播秋招提前批面经-后端开发工程师
自我介绍
原来在字节实习过,为什么来深圳
1.介绍进程、线程、协程(golang)
协程其实可以认为是比线程更小的执行单元。为啥说他是一个执行单元,因为他自带CPU上下文。这样只要在合适的时机,我们可以把一个协程 切换到 另一个协程。只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
1.一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
2.线程进程都是同步机制,而协程则是异步
3.协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
2.自旋锁和互斥锁有什么区别?
一、互斥锁
互斥锁是一种独占锁,当线程A加锁成功后,此时互斥锁已经被线程A独占了,只要线程A没有释放手中的锁,线程B就会失败,就会释放掉CPU给其他线程,线程B加锁的代码就会被阻塞。
性能开销成本:两次线程上下文切换的成本。
1、当线程加锁失败时,内核将线程的状态从【运行】切换到睡眠状态,然后把CPU切换给其他线程运行;
2、当锁被释放时,之前睡眠状态的线程会变成就绪状态,然后内核就会在合适的时间把CPU切换给该线程运行;
二、自旋锁
自旋锁通过CPU提供的CAS,在用户态完成加锁和解锁操作,不会主动产生线程上下文切换,所以相比互斥锁来说,会快一些开销小一些。
当两个线程属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
上下切换的耗时大概在几十纳秒到几微秒之间,如果锁住的代码执行时间比较短,可能上下文切换的时间比锁住的代码执行时间还要长。
若是能确定被锁住的代码执行时间很短,就不应该使用互斥锁,而应该选择自旋锁。
自旋锁利用CPU周期一直自旋直到锁可用。由于一个自选的线程永远不会放弃CPU,因此在单核CPU上,需要抢占式的调度器(不断通过时钟中断一个线程,运行其他线程)。
自旋的时间和被锁住的代码执行的时间成正比关系。
3.介绍TCP和UDP??简单
4.TCP实现可靠传输依赖哪些机制??简单
5.浏览器转到百度网址,涉及到哪些协议??简单
6.编程语言熟悉哪个?简单
7.容器、迭代器和算法的关系???C++内容
8.STL的sort函数是怎么实现的?C++内容
9.快速排序的最坏时间复杂度???
快速排序的时间复杂度最好是O(nlogn),平均也是O(nlogn),这种情况是轴枢恰好能把两侧的分开。
时间复杂度最差是O(N 2),最差的情况选择的轴枢在数组最左侧或是最右侧
10.如何改进快速排序避免陷入最坏时间复杂度的情况?
11.Redis数据结构了解多少?简单
12.MySQL的索引结构了解多少?简单
13.设计题:千万级、亿级整数数据,拥有4GB不连续的内存,设计一个双端队列结构,首尾都可以入出队,存入这些数据??
14.反问,问了下小组做的事情还有技术栈??
15.后面半个小时都在思考如何设计这样一个数据结构,提出几种方案面试官都否决了
16.主要是不连续那个条件,当时想到用链表将不连续的内存块串联起来,在这个基础上实现一个双端队列
17.面试官最后说只沾了一点点边,让我回去好好想想
8月4日 二面 50分钟
因为一面结束紧接着二面,二面面试官(主管)和一面面试官简单沟通了一下
自我介绍
讲讲你擅长的技术(瞎聊天)
< 第一次牛客网断连 >
1.MySQL的隔离性和原子性怎么实现的?不清楚MySQL的实现,但是了解过一些数据库的做法
2.介绍一下MySQL的脏读和幻想读??
3.B+树相比B树什么优点?简单
4.说一下最左前缀原理?
5.介绍下MySQL查询语句的执行过程?
1.DML语句首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树。
2.语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用户是否具有操作权限等
3.视图转换:将语法分析树转换成关系代数表达式,称为逻辑查询计划;
4.查询优化:在选择逻辑查询计划时,会有多个不同的表达式,选择最佳的逻辑查询计划;
5.代码生成:必须将逻辑查询计划转换成物理查询计划,物理查询计划不仅能指明要执行的操作,也给出了这些操作的执行顺序,每步所用的算法,存储数据的方式以及从一个操作传递给另一个操作的方式。
6.将DML转换成一串可执行的存取操作的过程称为束缚过程,