今天面试了百度系统部的后天开发,在面试时自己有几个问题回答不上来,或者说回答的不够好,今天总结下来以便自己查漏补缺。
一、纲领:
1、对自己简历上写的任意一个知识点至少掌握100%,然后可以根据自身需要进行拓展。
2、对于HR的问题一定要听清楚,有时候HR会对你的解答进行补充和改正,一定要记住。
3、对于自己学习过的知识一定要定期复习,不能到面试时忘记了。
4、对于网络基础知识,例如TCP/IP、三次握手、四次分手、socket通信,一定要熟记(基本每家公司面试都会问的)。
5、必须熟练掌握一个数据库
6、必须精通基本的数据结构与算法
二、问题:
(一)什么是数据库的sql注入,如何去防止?。
当应用程序使用输入的内容来构造动态的sql语句去访问数据库时;或者当代码使用存储过程,而这些存储过程作为包含为筛选的用户的输入的字符串来传递时,都会发生sql注入。因此总的来讲:SQL注入就是攻击者利用现有程序,将恶意的SQL命令注入到后台数据库执行的一些恶意操作。其根本原因是程序没有有效的去过滤用户的输入。
解决方式(信条准则):
1、永远不要信任任何用户的输入,对用户的输入进行校验,可以通过正则、或者限制长度、以及非法字符规定、对单引号和“-”进行转换。
2、永远不要进行动态拼接sql,可以使用参数话的sql(Flask的SqlAlChemy)或者直接通过使用存储过程进行数据库查询存取。
3、对机密信息在数据库存储时使用hash加密。
4、应用的异常提示应尽可能的少,尽量使用自定义的异常信息(sql注入通过异常信息可以看到数据库的名称以及所有的表名)
5、使用专业的SQL注入检测工具进行检测(sqlmap,SQLninja),以及时修补被发现的SQL注入漏洞。
(二)如何解决Flask中出现的高并发问题,或者说如何解决Python中的高并发问题。
首先解决这个问题我们先要从源头上说说高并发是怎么一回事,只有明白这些我们才可以从关键点去回答切入这个问题。
1、什么是高并发?
高并发是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。
2、怎样减少高并发的几个最简单的方法:
(1)、垂直拓展:增强硬件性能、使用缓存来减少IO次数,使用异步增加服务吞吐量,使用无锁的数据结构来减少响应时间。
(2)、水平拓展:反向代理层的水平扩展、站点层的水平扩展、服务层的水平扩展、数据层的水平扩展。
推荐文章:什么是高并发 ,详细讲解
3、因为我们做服务的不免会牵扯到数据库,那么当高并发遇到数据库会怎样?
原因:由于mysql是一个链接给一个线程,当高并发时,每秒需要几百个甚至更多个的线程,其中创建和销毁线程还比较好说,最多对内存的耗费比较多,导致性能下降的最主要的原因是:mysql底层瞬间处理这几百个线程提交的sql,但是cpu一次只能处理一条sql,这个中间会有cpu的上下文切换(线程的cpu上下文切换,是需要保存堆栈,相关寄存器、计数器的状态的,需要相对较多的时间),因此数据库访问的性能会下降。
解决数据库高并发带来的性能下降问题:
(1)在web与db之间加一层cache层,主要是为了:减少数据库的访问负担,提高数据读取速度。cache存取的媒介是内存,因此可已考虑,采用分布式的cache层,这样更容
(2)使用MySql数据库的异步查询机制。
(3)使MySql数据库实现读写分离
我们使用cache层只能减小数据库的读压力,但是当写压力增大时cache层几乎没有任何作用,因此我们需要使用主从复制技术(master-slave模式)来达到读写分离,以提高读写性能和读库的可扩展性。读写分离:在主服务器上写,只在从服务器上读。基本原理是让主数据库进行实物性查询(增删改),而从数据库处理select查询。
(4)分表分库。
推荐文章:解决数据库高并发访问瓶颈问题
(三)如何使用两个栈去实现一个队列的模型?
解决这个问题,首先需要对两种数据结构模型的特点非常清楚:栈,先进后出模型;队列,先进先出模型。
明白了两个数据结构的基本模型之后,来就是去实现队列的操作了,队列有下面几种操作:
(1)入队:使用栈去实现的本质,也就是入栈A;
(2)出队:使用栈实现的本质:(1)栈B出栈、若栈B空不能出栈则进行下一步(2)将栈A的数据依次出栈,再依次压入栈B
(3)队列是否为空:本质是两个栈A,B是否为空。
(4)队列是否为满:本质是两个队列是否为满。
类比:如何使用两个队列实现一个栈的模型?
两个队列去实现一个栈的模型,同样如上面一个问题,根据栈和队列的数据模型先进行假设,假如,在正常的栈,我们将数字1,2,3,4,5一次入栈,那么我们的出栈顺序应该是5,4,3,2,1;但是使用队列的话,我们先将所有的数组入队之后,怎样才能将队列的尾部的数字5拿出来呢?我们将5拿出来时,前面的四个数字,是不是也要依次在另一个队里上保存起来呢?
因此:要拿到队列中最后压入的数据,只能每次将队列A中数据pop到只剩一个,并将POP出来的数据全部依次入队B,再将队A中仅有的一个原数POP,循环执行此步骤。
(四)什么是三次握手、为什么要三次握手、什么是四次挥手,为什么要四次?
(1)三次握手
三次握手,即建立TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。
第一次握手:建立链接时,客户端发送syn(同步序列编号)到服务器,并进入等待服务器确认确认状态。
第二次握手:服务端收到了客户端发送的syn,向客户端进行确认(ack)同时也要发送一个自己的syn包,即发送一个syn+ack包,服务器进入等待状态。
第三次握手:客户端收到服务端的SYN+ack包,再向服务器发送一个确认包ACK,此包发送完毕,服务端与客户端确认连接。
(2)为什么三次握手
三次握手的目的:为了防止已经失效的连接请求报文段突然又传到了服务端,而产生错误。
先来说下为什么不能小于三次,比如:客户端A发出去的第一个链接请求报文因为网络上的滞留问题,导致延迟到客户端已经把该请求连接释放掉了以后才到达服务端。这本是一个已经失效的报文,但是服务端接收到此报文后,会误认为是客户端新发出的连接建立请求,于是服务端向客户单发出确认报文,表示同意建立链接。如果服务端不采用“三次握手”,那么服务端发出确认报文后就会认为有新的连接建立了,但是客户端并没有发出建立链接请求,因此不会向服务端发送数据,而此时服务端会一直等待,白白浪费资源。如果采用“三次握手”,服务端收到一个已经失效的请求建立链接的报文后,会向客户端发送确认报文(ack)和自己的syn(同步序列编号)来确认,但是此时客户端并没有要求建立链接,因此客户端不会向服务端发送确认信息(ack+1),因此服务端也会知道链接并没建立。
大于三次:因为两边已经可以通过前三次的确认去建立一个可靠的通信链接,如果再进行确认的话就会有资源浪费了。而且,信道是不可靠的,但是要建立可靠的连接发送可靠的数据,这个时候三次握手是一个理论上的最小值,并不是TCP协议要求的,是为了满足在不可靠的信道上传输可靠的数据所要求的。
(3)4次挥手
4次挥手,别名连接终止协议,是指通过TCP建立链接的服务端与客户端进行进行断开连接时,相互发4个包进行确认的过程。
第一次:TCP客户端向服务端发送一个FIN,用来关闭客户端到服务端的数据传送。
第二次:服务端收到这个FIN后,返回一个确认报文(ACK),确认序号为收到的序号加1,和SYN一样,一个FIN占用一个序号。
第三次:服务端关闭客户端的连接,发送一个FIN给客户端。
第四次:客户端向服务端发回ACK报文确认,并将确认序号设置为收到的序号加1。
(4)为什么是四次挥手
本质的原因是tcp是全双工的,要实现可靠的关闭连接,需要双方都要将需要发送的数据发送完(因为TCP是稳定的,不会出现数据传输的不完整)。而一个FIN报文只能表示自己已经将需要发送的数据发送完了,但是还允许对方把继续把没发完的数据发过来。