字节跳动测试面试准备
- 1、将一个文件夹下面小于100KB的文件复制到另一个文件夹下
files = 'find /root/logs/tuia/ -size -100k'
for file in ${files}
do
cp ${file} /root/logs/tuia2/
done
-
2、网络状态码
2开头的 请求已经被服务器处理
3开头的 请求方式有问题
4开头的 请求失败 (可能是因为网络问题 )
5开头的 服务器问题 -
3、网络七层模型
应用层:定义了用户在网络中进行通信和传输数据的接口,一般情况下应用都是直接和应用层进行交互的。
表示层:定义不同系统中数据的传输格式,编码和解码规范等,用于多系统下的传输。
会话层:管理者用户的会话,控制用户间的逻辑连接的建立和中断;
传输层:管理者网络中设备间如何传数据。
网络层:定义网络设备间如何传输数据
链路层:将上面的网络层的数据封装成帧,便于物理层进行传输。
物理层:这一层主要就是传输这些二进制数据。
HTTP是基于应用层的,RPC是基于传输层的。
RPC主要用于公司内部的服务调用,性能消耗低,传输效率高,服务治理方便。HTTP主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。
RPC使用自定义的TCP协议,可以减少保温体积提高传输效率,基于thrift实现高效的二进制传输自带了负载均衡策略而且能做到自动通知不影响上游
HTTP的请求中会自带json来实现会有很多无用的内容,负载均衡以及服务治理都需要修改Nginx/HAPoxy配置来实现 但比RPC好的一点在于方便使用没有RPC那么复杂接口多。
- 4、Python问题
dict的底层实现原理
字典是Python的一种可变、无序容器数据结构,它的元素以键值对的形式存在,键值唯一,它的特点搜索速度很快:数据量增加10000倍,搜索时间增加不到2倍;当数据量很大的时候,字典的搜索速度要比列表快成百上千倍
Python字典的底层实现是哈希表。什么是哈希表,简单来说就是一张带索引和存储空间的表,对于任意可哈希对象,通过哈希索引的计算公式:hash(hashable)%k(对可哈希对象进行哈希计算,然后对结果进行取余运算),可将该对象映射为0到k-1之间的某个表
有时候对于不同的键,经过哈希取余运算之后,得到的索引值一样,这时候怎么办?这时采用公开寻址的方式,运用固定的模式将键值对插入到其它的地址空间,比如线性寻址:如果第i个位置已经被使用,我们就看看第i+1个,第i+2个,第i+3个有没有被使用…直到找到一个空间或者对空间进行扩容。
比如:我们想存储 {’小小‘:18}这个键值对,经过哈希和取余运算之后,我们发现,其对应的索引值是0,但是0所指向的空间已经被’小王‘占用了,这就是碰撞。怎么办呢?我们看看0+1对应的所以有没有被占用,如果没有,我们就把’小小‘放在索引1所对应的地址空间中。取的时候,也按照同样的规则,进行探查。索引,然后在该索引所对应的空间进行变量的存储/读取等操。
python的dict和java的map一样,底层还是数组,每个键值对都是通过key的哈希值对dict的长度取余然后存放在对应的index里面,这是理想的情况,一般可能会产生哈希冲突,为了解决哈希冲突,每个index会变成链表,最新的是链表长度小于7还是链表,大于7以上会转成红黑树。这样最优的情况下能提高一半的访问速度。
引入了红黑树结构,若桶中链表元素个数大于等于8时,链表转换成树结构;若桶中链表元素个数小于等于6时,树结构还原成链表。因为红黑树的平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,这才有转换为树的必要。链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。
深拷贝浅拷贝
浅拷贝:类似于C语言中的指针只是把变量的指指向拷贝对象的堆栈,所有操作还是跟着原来拷贝对象的变化而变化
深拷贝:在内存中新建一个堆栈,把拷贝对象所在的整个复制一份过来
- 5、Java问题
Java代码的编译和执行的整个过程大概是:开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件),再然后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。
Java代码编译是由Java源码编译器来完成,也就是Java代码到JVM字节码(.class文件)的过程。Java字节码的执行是由JVM执行引擎来完成
Java 源码编译由以下三个过程组成:
①分析和输入到符号表
②注解处理
③语义分析和生成class文件
最后生成的class文件由以下部分组成:
①结构信息:包括class文件格式版本号及各部分的数量与大小的信息
②元数据:对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池
③方法信息:对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息
JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。
JVM执行class字节码,线程创建后,都会产生程序计数器(PC)和栈(Stack),程序计数器存放下一条要执行的指令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应着每个方法的每次调用,而栈帧又是有局部变量区和操作数栈两部分组成,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果。
6、数据库问题
- 7、TCP\IP
第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
- 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
过程:浏览器输入域名->浏览器查询dns是否有缓存->DNS查询到域名->TCP/IP链接(三次握手)->建立连接->浏览器发出请求->服务器响应(1.2.3.4)->浏览器会先获得响应头然后在获得相应体(因为响应体有时候会很大).