Python后端开发工程师面试

面试主要流程:

第一步:自我介绍

第二步:公司介绍

第三步:技术基础

第四步:项目介绍

第五步:待遇

自我介绍

自我介绍,简单直接,姓名,籍贯,大学,工作经历

示例如下:

你好,面试官,我叫XX,来自XX,本科毕业于XX,主修XX专业,有X年工作经验,在上一家公司担任python后端开发工程师的职位。

公司介绍

公司名称是XX、公司主要做外包软件、都有软件定制/商城定制、前端2个后端2个运维1个

技术基础

主要是根据你简历中填写的技术,根据我的简历中所写的,总结几点如下:

一、python语言

  1. 数据类型有几种、有什么区别

    列表:列表是一个可以存放任意数据类型的可变有序序列。

    元祖:元组是一个可以存放任意数据类型的不可变有序序列。

    list和tuple在c实现上是很相似的,对于元素数量大的时候, 都是一个数组指针,指针指向相应的对象,找不到tuple比list快的理由。 但对于小对象来说,tuple会有一个对象池,所以小的、重复的使用tuple还有益处的。

    • immutable的重要性

      • 性能优化:指出元素全部为immutable的tuple会作为常量在编译时确定,因此产生了显著的速度差异

      • 线程安全

      • 可以当做dict的key:因为不可变,所以可以hash,只有可hash的数据类型才可以作为dict的key

      • 拆包特性

    • 类比c语言:

      • tuple对应strut,list对应array

    字典:字典是一个可以存放任意数据类型的可变无序的映射集合,key只能是可hash数据类型。字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组的每个单元叫做 bucket。每个 bucket 有两部分:一个是键对象的引用,一个是值对象的引用。所有 bucket 结构和大小一致,我们可以通过偏移量来读取指定 bucket。dict内部实现是哈希表(散列表),将dict的key通过哈希函数转换成一个哈希值作为偏移量,(所以key必须是可哈希的数据结构),和7做&运算,得到运算值作为存储地址。

  • dict查找的性能要远高于list

  • 在list中随着list数据的增大查找时间会增加

  • 在dict中查找不会随着dict的体量增大而增大

字典的查询流程:

  • 计算key的哈希值

  • 使用哈希值的一部分来定位散列表中的一个表元

    • 表元为空,抛出keyerror

    • 表元不为空,可能是为了解决哈希冲突占据了这个表元,判断key是否相等

      • 不相等,使用散列值的另一部分定位散列表中的另一个表元

      • 相等,返回表元中的值

不可变对象可哈希,strfronzensettuple,自己实现的类,要重载__hash__方法。

dict内存花销大,但是查询速度快,自定义的对象或者python内部的对象都是dict包装的。

dict的存储顺序和元素添加顺序有关,添加顺序可能改变已有数据的顺序。

集合:是一个可以存放任意数据类型的可变无序的映射集合。

set和dict类似,set的核心也是散列表,但是表元只包含值的引用。 由于散列表的特性,set的元素不能重复,且无序。 内部由哈希实现,查找的时间复杂度为O(1),所以性能很高,实现了魔法函数__contains__可以使用in来查找。 set的去重是通过两个函数__hash____eq__实现的。

  1. 进程、线程、协程(这个很少问),定义及区别

    (1)进程

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

    (2)线程

    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

    (3)协程

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

    (4)进程多与线程比较

    线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:

    • 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间

    • 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源

    • 线程是处理器调度的基本单位,但进程不是

    • 二者均可并发执行

    • 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

    (5)协程多与线程进行比较

    • 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。

    • 线程进程都是同步机制,而协程则是异步

    • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

  2. 深浅拷贝的实现和区别

(1)浅拷贝

定义:浅拷贝只是对另外一个变量的内存地址的拷贝,这两个变量指向同一个内存地址的变量值。

浅拷贝的特点:

  • 公用一个值;

  • 这两个变量的内存地址一样;

  • 对其中一个变量的值改变,另外一个变量的值也会改变;

(2)深拷贝:

定义:一个变量对另外一个变量的值拷贝。

深拷贝的特点:

  • 两个变量的内存地址不同;

  • 两个变量各有自己的值,且互不影响;

  • 对其任意一个变量的值的改变不会影响另外一个;

  1. new() 与 init()的区别
  • __new__是一个静态方法,而__init__是一个实例方法.

  • __new__方法会返回一个创建的实例,而__init__什么都不返回.

  • 只有在__new__返回一个cls的实例时后面的__init__才能被调用.

  • 当创建一个新实例时调用__new__,初始化一个实例时用__init__.

  1. 常用开发模式
  • 单例模式

    • 重写new方法

    • 闭包定义装饰器

  • 工厂模式

    • 简单工厂

    • 工厂方法

    • 抽象工厂

  • 构建者模式

  • 代理模式

  • 观察者模式

  1. 函数式编程、对象式编程

    • 函数式编程,顾名思义,这种编程是以函数思维做为核心,在这种思维的角度去思考问题。 这种编程最重要的基础是λ演算,接受函数当作输入和输出。

    • 面向对象编程,这种编程是把问题看作由对象的属性与对象所进行的行为组成。基于对象的概念, 以类作为对象的模板,把类和继承作为构造机制,以对象为中心,来思考并解决问题。

    优点:

    • 函数式编程:

      支持闭包和高阶函数,闭包是一种可以起函数的作用并可以如对象般操作的对象;

      而高阶函数是可以以另一个函数作为输入值来进行编程。支持惰性计算,这就可以在求值需要表达式的值得时候进行计算 ,而不是固定在变量时计算。还有就是可以用递归作为控制流程。函数式编程所编程出来的代码相对而言少很多,而且更加简洁明了。

    • 面向对象编程:

      面向对象有三个主要特征,分别是封装性、继承性和多态性。类的说明展现了封装性,类作为对象的模板, 含有私有数据和公有数据,封装性能使数据更加安全依赖的就是类的特性,使得用户只能看到对象的外在特性, 不能看到对象的内在属性,用户只能访问公有数据不能直接访问到私有数据。 类的派生功能展现了继承性,继承性是子类共享父类的机制,但是由于封装性,继承性也只限于公有数据的继承(还有保护数据的继承)

    缺点:

    • 函数式编程:

      所有的数据都是不可以改变的,严重占据运行资源,导致运行速度也不够快。

    • 面向对象编程:

      为了编写可以重用的代码导致许多无用代码的产生,并且许多人为了面向对象而面向对象导致代码给后期维护带来很多麻烦。

  2. 闭包、装饰器

    闭包:

    如果一个外函数中定义了一个内函数,且内函数体内引用到了体外的变量,这时外函数通过return返回内函数的引用时,会把定义时涉及到的外部引用变量和内函数打包成一个整体(闭包)返回。

    装饰器:

    本质上是一个嵌套函数,它接受被装饰的函数(func)作为参数,并返回一个包装过的函数。这样我们可以在不改变被装饰函数的代码的情况下给被装饰函数或程序添加新的功能。Python的装饰器广泛应用于缓存、权限校验(如django中的@login_required和@permission_required装饰器)、性能测试(比如统计一段程序的运行时间)和插入日志等应用场景。有了装饰器,我们就可以抽离出大量与函数功能本身无关的代码,增加一个函数的重用性。

  3. python中的类可以多继承么,多继承的继承方式?

    可以。

    经典算法,按照定义从左到右,深度优先策略2.2版本之前用;新式类算法,深度优先,重复的只保留最后一个2.2版本也难过;

    C3算法,在类创建出来的时候,就计算出一个MRO有序表2.2之后支持,Python3唯一支持的算法。

  4. 类的特性

    封装:根据职责将属性和方法封装到一个抽象的类中。

    继承:实现代码的重用,不需要重复编写代码。子类拥有父类所有的属性和方法。也可以重写父类方法。

    多态:不同的对象调用相同的代码,产生不同的效果,提高代码的灵活性。

  5. 魔法方法,举例并说明

  • 构造和初始化

    init

    new

    del

  • 属性访问控制

    getattr

    setatrr

    delattr

  • 描述器对象

    get

    set

    delete

  • 构造自定义容器

    len(self)

    getitem(self, key)

    setitem(self, key,value)

    delitem(self,key)

    iter(self)

    reversed(self)

    contains(sel,item)

    missing(self, key)

  • 上下文管理

    enter(self)

    exit(self)

  • 对象的序列化

    getinitargs(self)

    getnewargs(self)

    getstate(self)

    setstate(self)

    reduce(self)

  • 运算符相关的魔法方法

    • 比较运算符

      cmp(self,other)

      eq(self,other)

      ne(self,other)

      lt(self,other)

      gt(self,other)

      le(self,other)

      ge(self,other)

    • 一元运算符和函数

      pos(self)

      neg(self)

      invert(self)

      abs(self)

      round(self)

      floor(self)

      ceil(self)

      trunc(self)

    • 算术运算符

      add(self,other)

      sub(self,other)

      mul(self,other)

      floordiv(self,other)

      div(self,other)

      truediv(self,other)

      mod(self,other)

      divmod(self,other)

      pow(self,other)

      lshift(self,other)

      rshift(self,other)

      and(self,other)

      or(self,other)

      xor(self,other)

    • 反算术运算符

      radd(self,other)

      rsub(self,other)

      rmul(self,other)

      rfloordiv(self,other)

      rdiv(self,other)

      rtruediv(self,other)

      rmod(self,other)

      rdivmod(self,other)

      rpow(self,other)

      rlshift(self,other)

      rrshift(self,other)

      rand(self,other)

      ror(self,other)

      rxor(self,other)

    • 增量赋值

      iadd(self,other)

      isub(self,other)

      imul(self,other)

      ifloordiv(self,other)

      idiv(self,other)

      itruediv(self,other)

      imod(self,other)

      idivmod(self,other)

      ipow(self,other)

      ilshift(self,other)

      irshift(self,other)

      iand(self,other)

      ior(self,other)

      ixor(self,other)

    • 类型转化

      int(self)

      long(self)

      float(self)

      complex(self)

      oct(self)

      hex(self)

      index(self)

  • 其他魔术方法

    str(self)

    repr(self)

    unicode(self)

    format(self)

    hash(self)

    nonzero(self)

    dir(self)

    sizeof(self)

    instancecheck(self, instance)

    subclasscheck(self,subclass)

    copy(self)

    deepcopy(self,memodict={})

    call(self,[args...])

  • Python3中,str与unicode的区别被废除了,因而__unicode__没有了,取而代之地出现了__bytes__.

  • Python3中,division默认就是true division, 因而__div__废弃.

  • __coerce__因存在冗余而废弃.

  • __cmp__因存在冗余而废弃.

  • __nonzero__改名为__bool__.

  1. 生成器、迭代器、可迭代对象的定义及区别
  • 容器是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。

  • 可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

  • 迭代器持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next____iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。

  • 生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield

  1. 垃圾回收机制

Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collectio n)以空间换时间的方法提高垃圾回收效率。

  • 引用计数

    PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。

    优点:

    简单 实时性 缺点:

    维护引用计数消耗资源 循环引用

  • 标记-清除机制

    基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。

  • 分代技术

    分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。

    Python默认定义了三代对象集合,索引数越大,对象存活时间越长。

  1. 线程安全、死锁、GIL

GIL全称 Global Interpreter Lock ,中文解释为全局解释器锁。它并不是Python的特性,而是在实现python的主流Cpython解释器时所引入的一个概念,GIL本质上就是一把互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,从而保证数据的安全性。

GIL保护的是解释器级别的数据,但是用户自己的数据需要自己加锁处理。

既然有了GIL的存在,一个进程中同一时刻只有一个线程能够被执行,无法利用cpu的多核机制,导致多线程用于I/O密集型,多进程用于计算密集型,如金融分析等。

死锁:两个或两个以上的进程或者线程在执行过程中,因为争夺资源而造成的互相等待现象,若无外力的作用,都将一直处于阻塞状态,这些互相等待的进程或者线程就被称为死锁。

解决方法,使用递归锁(RLock)

这个RLock内部有一个Lock和一个counter变量,counter记录着acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁

  1. 解决线程不安全的办法
  • 锁(lock)对象对于同步受保护的共享资源的访问很有用的,以及与其类似的RLock对象。

  • 条件(condition)对象,它对线程在等待任何条件时进行同步很有用的。

  • 事件(event)对象,它在线程之间提供了基本的信号机制。

  • 信号量(semaphore)对象,它允许对有限资源的同步访问。

  • 界线(barrier)对象,它允许一组固定的线程相互等待,同步到一特定的状态,接着继续往下执行。

  1. linux常用命令,举例说明
ls(ls -al)查看文件信息

cd 切换到

pwd 查看当前工作目录

mkdr (mkdir -p)创建文件夹

rm (rm -rf)删除文件夹

rmdir (rmdir -p)删除文件夹

mv 移动文件或修改文件名

cp (cp -r)复制目录和目录内所有内容

cat 显示整个文件

more 一页一页显示(只能向后)

less 和more类似,可以随意浏览文件

head (head 文件 -n 行数)显示前几行

tail (tail 文件 -n 行数)显示末尾几行

which 查找某个文件位置

whereis 搜索程序名

locate 通过搜寻系统内奸文档数据库达到快速找到档案

find 查找文件

chmod 更改文件或目录访问权限

tar 压缩解压文件

chown 更改文件的拥有者

df 显示磁盘空间使用情况

du对文件和目录磁盘使用的空间的查看

ln 创建链接

date 显示或设定系统的日期和时间

cal 显示日历

grep 文本搜索命令

wc 统计制定的文件中字行数

ps (ps -ef)(ps -aux)查看当前运行的进程状态

top 显示当前系统正在执行的进程的相关信息

kill (kill -9)(kill -p)终止程序

free 显示系统内存使用情况
  1. http状态码
2XX Success(成功状态码)

200 表示从客户端发来的请求在服务器端被正常处理

204 该状态码表示服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分

206 该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求

3XX Redirection(重定向状态码)

301 永久性重定向

302 临时性重定向

4XX Client Error(客户端错误状态码)

400 该状态码表示请求报文中存在语法错误

401 该状态码表示发送的请求需要有通过HTTP认证的认证信息

403 该状态码表明对请求资源的访问被服务器拒绝了

404 该状态码表明对服务器上无法找到请求的资源

5XX Server Error(服务器错误状态码)

500 该状态码表明服务器端在执行请求时发生了错误

503 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
  1. http和https的区别
    http协议和https协议的区别:传输信息安全性不同、连接方式不同、端口不同、证书申请方式不同
  • 传输信息安全性不同

    • http协议:是超文本传输协议,信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。

    • https协议:是具有安全性的ssl加密传输协议,为浏览器和服务器之间的通信加密,确保数据传输的安全。

  • 连接方式不同

    • http协议:http的连接很简单,是无状态的。

    • https协议:是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。

  • 端口不同

    • http协议:使用的端口是80。

    • https协议:使用的端口是443。

  • 证书申请方式不同

    • http协议:免费申请。

    • https协议:需要到ca申请证书,一般免费证书很少,需要交费。

  1. 简述OSI七层协议
*   物理层。为数据链路层提供物理连接,实现比特流的透明传输,所传输数据的单位是比特,该层定义了通信设备与传输线接口硬件的电气、机械以及功能和过程的特性。

*   数据链路层。在通信的实体之间建立数据链路连接,传送以帧为单位的数据,通过检查发生在连接通信系统间传送路上的比特错误并进行恢复,确保比特序列组成为数据流准确无误地传送给对方的系统。数据链路层在相邻的节点之间实现透明的高可靠性传输。

*   网络层。解决多节点传送时的路由选择、拥挤控制及网络互连等,控制分组传送系统的操作,它的特性对高层是透明的,同时,根据传输层的要求选择服务质量,并向传输层报告未恢复的差错。

*   传输层。为两个端系统(源站和目标站)的会话层之间建立一条传输连接,可靠、透明地传送报文,执行端一端差错控制、顺序和流量控制、管理多路复用等。本层提供建立、维护和拆除传送连接的功能,并保证网络连接的质量。它向高层屏蔽了下层数据通信的细节,因而是OSI网络参考模型中最需要的一层。

*   会话层。不参与具体的数据传输,但对数据传输的同步进行管理。它主要负责提供两个进程之间建立、维护和结束会话连接功能,同时要对进程中必要的信息传送方式、进程间的同步以及重新同步进行管理。

*   表示层。解决在两个通信系统中交换信息时不同数据格式的编码之间的转换,语法选择,数据加密与解密及文本压缩等。

*   应用层。负责向用户提供各种网络应用服务,如文件传输、电子邮件、远程访问等。把进程中于对方进程通信的部分放入应用实体中,同时,对各种业务内容的通信功能进行管理。
  1. 简述TCP/IP四层协议
*   应用层:应用层决定这次通信的应用类型,比如说FTP、DNS、SMTP等等,同时HTTP协议也属于应用层的范围。通俗来讲,应用层决定这一次通信要干嘛。

*   传输层:传输层提供两台计算机之间的数据传输,传输层中包含着两个很叼的协议,分别是TCP和UDP协议。面试中经常提及的三次握手,四次挥手就是TCP协议的部分内容

*   网络层:网络层则是用来处理这些流动的数据包,也就是如果把相应的数据包路由到指定的地点,为通信时的网络传输选择传输路线

*   数据链路层:数据链路层包含了软件与硬件的接口部分,以及各种网络设备的硬件,也就是整个网络通信过程中最底层的基础设施
  1. TCP和UDP的区别是什么
TCP UDP
可靠性 可靠 不可靠
连接性 面向连接 无连接
报文 面向字节流 面向报文
效率 传输效率低 传输效率高
双工性 全双工 一对一、一对多、多对一、多对多
流量控制 有(滑动窗口)
拥塞控制 有(慢开始、拥塞避免、快重传、快恢复)
  1. 三次握手
    (1)第一步:源主机A的TCP向主机B发出连接请求报文段,其首部中的SYN(同步)标志位应置为1,表示想与目标主机B进行通信,并发送一个同步序列号X(例:SEQ=100)进行同步,表明在后面传送数据时的第一个数据字节的序号是X+1(即101)。SYN同步报文会指明客户端使用的端口以及TCP连接的初始序号。
    (2)第二步:目标主机B的TCP收到连接请求报文段后,如同意,则发回确认。在确认报中应将ACK位和SYN位置1,表示客户端的请求被接受。确认号应为X+1(图中为101),同时也为自己选择一个序号Y。
    (3)第三步:源主机A的TCP收到目标主机B的确认后要向目标主机B给出确认,其ACK置1,确认号为Y+1,而自己的序号为X+1。TCP的标准规定,SYN置1的报文段要消耗掉一个序号。

  2. 四次回收
    1)第一步:源主机A的应用进程先向其TCP发出连接释放请求,并且不再发送数据。TCP通知对方要释放从A到B这个方向的连接,将发往主机B的TCP报文段首部的终止比特FIN置1,其序号X等于前面已传送过的数据的最后一个字节的序号加1。
    2)第二步:目标主机B的TCP收到释放连接通知后即发出确认,其序号为Y,确认号为X+1,同时通知高层应用进程,这样,从A到B的连接就释放了,连接处于半关闭状态,相当于主机A向主机B说:“我已经没有数据要发送了。但如果还发送数据,我仍接收。”此后,主机B不再接收主机A发来的数据。但若主机B还有一些数据要发送主机A,则可以继续发送。主机A只要正确收到数据,仍应向主机B发送确认。
    3)第三步:若主机B不再向主机A发送数据,其应用进程就通知TCP释放连接。主机B发出的连接释放报文段必须将终止比特FIN和确认比特ACK置1,并使其序号仍为Y,但还必须重复上次已发送过的ACK=X+1
    4 第四步:主机A必须对此发出确认,将ACK置1,ACK=Y+1,而自己的序号是X+1。这样才把从B到A的反方向的连接释放掉。主机A的TCP再向其应用进程报告,整个连接已经全部释放。

  3. 什么是 socket?简述基于 tcp 协议的套接字通信流程。
    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。 服务端:创建socket对象,绑定ip端口bind(), 设置最大链接数listen(), accept()与客户端的connect()创建双向管道, send(), recv(),close() 客户端:创建socket对象,connect()与服务端accept()创建双向管道 , send(), recv(),close()

  4. 简述基于UDP协议的套接字通信流程
    1、创建一个socket,用函数socket();
    2、绑定IP地址、端口等信息到socket上,用函数bind();
    3、设置对方的IP地址和端口等属性;
    4、发送数据,用函数sendto();
    5、关闭网络连接;

  5. TCP 为什么不是两次连接?而是三次握手?
    先假设是两次吧。我们知道, tcp的连接过程中有一个超时重传算法(karn算法是比较典型的), 如果client发出syn包后, 由于网络原因, 没有立即收到ack/syn包, 那么client会再次发起syn包, 这一点, 我们已经多次实验过。 如果第二次syn包正常达到且与server端建立了tcp连接, server端维护了一个连接, 一次貌似OK, 但别忘了, 第一次那个syn包可能就在此时达到server端了, 于是server端又要维护一个连接, 而这个连接是无效的, 可以认为是死连接。 而一个进程打开的socket是有限度的, 维护这些死连接非常耗费资源。 所以, 二次握手, 服务端有较大隐患, 容易因为资源耗尽而崩溃。而三次握手, 可以避免如上问题

  6. http中get 和 post的区别

  • 在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次

  • get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的

  • get请求因为浏览器对url长度有限制(不同浏览器长度限制不一样)对传参数量有限制,而post请求因为参数存放在request body内所以参数数量没有限制(事实上get请求也能在request body内携带参数,只不过不符合规定,有的浏览器能够获取到数据,而有的不能)

  • 因为get请求参数暴露在url上,所以安全方面post比get更加安全

  • get请求浏览器会主动cache,post并不会,除非主动设置

  • get请求参数会保存在浏览器历史记录内,post请求并不会

  • get请求只能进行url编码,而post请求可以支持多种编码方式

  • get请求产生1个tcp数据包,post请求产生2个tcp数据包

  • 浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK

  1. session、cookie的区别
session与cookie的区别有如下四个方面:

1.存放的位置

cookie保存在客户端,session一般保存在服务器端的文件系统或数据库或mamcache

2.安全性

由于session存放在服务器端,而客户端可以集中采用软、硬件技术保证安全性,所以cookie的安全性较session弱

3.网络传输量

cookie需通过网络实现客户端与服务器端之间的传输,而session保存在服务器端,无需传输

4.生存时间(以设置24分钟为例)

(1)cookie的生命周期是累计的。从创建的时候就开始计时,24分钟后cookie生命周期结束,cookie自动失效

(2)session的生命周期是间隔的,从创建时开始计时,比如在24分钟内(php.ini默认session的失效时间就是1440s,即24m)没有访问过session(指没有执行含session的文件),那么session信息就自动无效,但如果在24分钟之内,比如第23分钟访问过session,那么它的生命周期将重新开始计算。
  1. mysql

  2. redis

  3. django、中间件原理、钩子、drf

    django中间件作用及应用场景:
    process_request : 请求进来时,权限认证
    process_view : 路由匹配之后,能够得到视图函数
    process_exception : 异常时执行
    process_template_responseprocess : 模板渲染时执行
    process_response : 请求有响应时执行

  4. 谈谈Django中的中间件

  • django.middleware.security.SecurityMiddleware’ 一些安全设置,比如XSS脚本过滤。

  • django.contrib.sessions.middleware.SessionMiddleware session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。

  • django.middleware.common.CommonMiddleware 通用中间件,会处理一些URL,比如http://baidu.com会自动的处理成http://www.baidu.com。比如/blog/111会处理 成/blog/111/自动加上反斜杠

  • django.middleware.csrf.CsrfViewMiddleware 跨域请求伪造中间件。加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一 个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击

  • django.contrib.auth.middleware.AuthenticationMiddleware 用户授权中间件。他会在每个HttpRequest对象到达view之前添加当前登录用户的user属性,也就是你可 以在view中通过request访问user

  • django.contrib.messages.middleware.MessageMiddleware 消息中间件。展示一些后台信息给前端页面。如果需要用到消息,还需要在INSTALLED_APPS中添加 django.contrib.message才能有效。如果不需要,可以把这两个都删除

  • django.middleware.clickjacking.XFrameOptionsMiddleware 防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。

  1. 谈谈CSRF原理
    CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/ sessionriding,缩写为:CSRF/XSRF。 你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包 括:个人隐私泄露以及财产安全。 要完成一次CSRF攻击,受害者必须依次完成两个步骤: 1.登录受信任网站A,并在本地生成Cookie。 2.在不登出A的情况下,访问危险网站B。

  2. 谈谈RESTful规范
    Representational State Transfer "表现层状态转化" restful其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值、状态码等信息。 restful: 给用户一个url,根据method不同在后端做不同的处理,比如:post 创建数据、get获取数据、put 和patch修改数据、delete删除数据。 (1)每一个URI代表一种资源; (2)客户端和服务器之间,传递这种资源的某种表现层; (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。 我们常用的状态码: 200 请求成功 301 永久重定向 302 临时重定向 403 权限问题 404 找不到页面 500 服务器问题

  3. 谈谈Django REST framework
    自动生成符合 RESTful 规范的 API 支持 OPTION、HEAD、POST、GET、PATCH、PUT、DELETE 根据 Content-Type 来动态的返回数据类型(如 text、json) Django Rest framework 的流程大概是这样的 1.建立 Models 2.依靠 Serialiers 将数据库取出的数据 Parse 为 API 的数据(可用于返回给客户端,也可用于浏览器 显示) 3.ViewSet 是一个 views 的集合,根据客户端的请求(GET、POST等),返回 Serialiers 处理的数据 权限 Premissions 也在这一步做处理 4.ViewSet 可在 Routers 进行注册,注册后会显示在 Api Root 页上 5.在 urls 里注册 ViewSet 生成的 view,指定监听的 url

  4. 什么是MVC ?什么是MTV?
    MVC(Model View Controller 模型-视图-控制器) Model: 代表数据存取层, View 代表的是系统中选择显示什么和怎么显示的部分, Controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。 MTV(Model Templates View 模型-模板-视图) Models:数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效,是一个抽象层,用来构建和操作你的web应用中的数据,模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。 模板(templates):即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。模板层提供了设计友好的语法来展示信息给用户。使用模板方法可以动态地生成HTML。模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。 视图(views):业务逻辑层,该层包含存取模型及调取恰当模板的相关逻辑。用于封装负责处理用户请求及返回响应的逻辑。视图可以看作是前端与数据库的中间人,他会将前端想要的数据从数据库中读出来给前端。他也会将用户要想保存的数据写到数据库。

  5. django网站执行流程
    Django网站执行流程图.jpg

    一个 HTTP 请求,首先被转化成一个 HttpRequest 对象,然后该对象被传递给 Request 中间件处理,如果该中间件返回了Response,则直接传递给 Response 中间件做收尾处理。否则的话 Request 中间件将访问 URL 配置,确定哪个 view 来处理,在确定了哪个 view 要执行,但是还没有执行该 view 的时候,系统会把 request 传递给 View 中间件处理器进行处理,如果该中间件返回了Response,那么该Response 直接被传递给 Response 中间件进行后续处理,否则将执行确定的 View 函数处理并返回 Response,在这个过程中如果引发了异常并抛出,会被 Exception 中间件处理器进行处理。

  6. Django请求的生命周期
    a. wsgi, 创建socket服务端,用于接收用户请求并对请求进行初次封装。
    b. 中间件,对所有请求到来之前,响应之前定制一些操作。
    c. 路由匹配,在url和视图函数对应关系中,根据当前请求url找到相应的函数。
    d. 执行视图函数,业务处理【通过ORM去数据库中获取数据,再去拿到模板,然后将数据和模板进行渲染】
    e. 再经过所有中间件。
    f. 通过wsgi将响应返回给用户。

  7. 简述Django的orm
    ORM,全拼Object-Relation Mapping,意为对象-关系映射 实现了数据模型与数据库的解耦,通过简单的配置就可以轻松更换数据库,而不需要修改代码只需要面 向对象编程,orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句,所有使用Django开发的项 目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据 库引擎即可

  8. 列举常见的http请求方法及作用?
    GET 请求指定的页面信息,并返回实体主体。
    HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
    POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
    POST请求可能会导致新的资源的建立和/或已有资源的修改。
    PUT 从客户端向服务器传送的数据取代指定的文档的内容。
    DELETE 请求服务器删除指定的页面。
    CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
    OPTIONS 允许客户端查看服务器的性能。
    TRACE 回显服务器收到的请求,主要用于测试或诊断

  9. Web开发中有哪些技术手段防止SQL注入?

  • 使用预编译绑定变量的SQL语句

  • 严格加密处理用户的机密信息

  • 不要随意开启生产环境中Webserver的错误显示

  • 使用正则表达式过滤传入的参数

  • 字符串过滤

  • 检查是否包函非法字符

  1. 正则邮箱地址
    正则表达式为:
    ^[A-Za-z0-9-._]+@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,6})$

  2. 进程通信的方式有几种

  3. 介绍下协程,为何比线程还快

    • 协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
      协程在子程序内部是可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行
    • 协程的特点在于是一个线程执行
    • 极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显;
    • 不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

二、操作系统

可以直接认为是linux,毕竟搞后端的多数是和linux打交道。

  1. tcp/udp的区别?tcp粘包是怎么回事,如何处理?udp有粘包吗?
    TCP粘包问题
    1. 首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包;
    2. 在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段;
    3. 站在传输层的角度, TCP是一个一个报文过来的,按照序号排好序放在缓冲区中;
    4. 站在应用层的角度, 看到的只是一串连续的字节数据. 那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分是一个完整的应用层数据包。

那么如何避免粘包问题呢? 归根结底就是一句话, 明确两个包之间的边界.

  1. 对于定长的包, 保证每次都按固定大小读取即可;
  2. 对于变长的包, 可以在报头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;
  3. 对于变长的包, 还可以在包和包之间使用明确的分隔符。
  4. TLV格式的数据传输

UDP不存在粘包问题,是由于UDP发送的时候,没有经过Negal算法优化,不会将多个小包合并一次发送出去。另外,在UDP协议的接收端,采用了链式结构来记录每一个到达的UDP包,这样接收端应用程序一次recv只能从socket接收缓冲区中读出一个数据包。也就是说,发送端send了几次,接收端必须recv几次(无论recv时指定了多大的缓冲区)。

  1. time_wait是什么情况?出现过多的close_wait可能是什么原因?

  2. epoll,select的区别?边缘触发,水平触发区别?

  3. 如何查看剩余内存

  4. 如何查看端口是否被占用

  5. 如何查看一个程序的PID以及它的所有子进程

  6. 如何为一个目录下的所有文件添加权限

  7. 如果你对一个目录具有写权限,那么你是否具有对这个目录下的所有文件具有删除权限?

  8. 对Linux多路复用的理解

  9. 修改IP地址的方法

三、存储

存储可能包含rdbms,nosql以及缓存等,我以mysql,redis举例**

  • mysql相关
    1. 谈谈mysql字符集和排序规则
    2. varchar与char的区别是什么?大小限制?utf8字符集下varchar最多能存多少个字符
    char char是定长的,也就是当你输入的字符小于你指定的数目时,char(8),你输入的字符小于8时,它会再后面补空值。当你输入的字符大于指定的数时,它会截取超出的字符。
    varchar(n) 长度为 n 个字节的可变长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大小为输入数据的字节的实际长度,而不是 n 个字节。所输入的数据字符长度可以为零。
    3. primary key和unique的区别
    primary key与unique的区别
    1. primary key = unique + not null 主键不能为空每个字段值都不重复,unique可以为空,非空字段不重复
    2. unique 一个或者多个字段定义,primary key 单字段主键或多字段联合主键
    3. primary key一个表只能有一个,unique一个表可以有多个
    4. 逻辑设计上primary key用来作记录标识,unique用来保证唯一性,但是在他们创建时都会去相应创建一个unique index,可以用来做sql优化。
    4. 外键有什么用,是否该用外键?外键一定需要索引
    MySQL外键的作用:
    保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。使两张表形成关联,外键只能引用外表中列的值!
    只要是外键,就一定得有索引
    5. myisam与innodb的区别?innodb的两阶段锁定协议是什么情况
    事务的加锁和解锁严格分为两个阶段,第一阶段加锁,第二阶段解锁.
    在事务中只有提交(commit)或者回滚(rollback)时才是解锁阶段,
    其余时间为加锁阶段。
    6. MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?
    MyISAM特点

    • 不支持行锁(MyISAM只有表锁),读取时对需要读到的所有表加锁,写入时则对表加排他锁;

    • 不支持事务

    • 不支持外键

    • 不支持崩溃后的安全恢复

    • 在表有读取查询的同时,支持往表中插入新纪录

    • 支持BLOB和TEXT的前500个字符索引,支持全文索引

    • 支持延迟更新索引,极大地提升了写入性能

    • 对于不会进行修改的表,支持 压缩表 ,极大地减少了磁盘空间的占用

    InnoDB特点

    • 支持行锁,采用MVCC来支持高并发,有可能死锁

    • 支持事务

    • 支持外键

    • 支持崩溃后的安全恢复

    • 不支持全文索引

    MyISAM和InnoDB两者的应用场景:

    1. MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
    2. InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能.
    1. 索引有什么用,大致原理是什么?设计索引有什么注意点
      索引设计原则
      (1)MySQL 表主键设计
      INNODB 以主键排序存储;聚集索引只能是主键;存储所有数据;二级索引包含主键键值。
      如果表没有定义主键,会选择第一个唯一索引(非空)作为聚集索引主键。如果唯一索引也没有,MySQL后台会自动生成RowID。
      字符类型字段最好不要做主键;常见的主键有两种:自增列和UUID。
      自增: 顺序存储,索引维护成本低,索引效率高;
      UUID:非顺序增长,随机IO严重。
      (2)索引并不是越多越好,要根据查询,有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是使用了索引还是全表扫描;
      (3)应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描;
      (4)值分布很稀少的字段不适合建索引,例如“性别”这种只有两三个值的字段;
      (5)不用外键,由程序保证约束;
      (6)尽量不用UNIQUE,由程序保证约束;
      (7)使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引。
      (8)排序时,排序字段需要注意index, 尤其是关联查询排序时,尽可能使用小表的字段进行排序
      SQL 优化 原则
      (1)避免属性隐试转换 , 如定义Moblie varchar where Moblie =198989888会导致全表扫描;
      (2)Where子句中条件字段本身避免使用函数;
      (3)使用获取的必要字段代替SELECT *;
      (4)批量插入,使用INSERT INTO table (col1,col2,...) VALUES (value1, value2,...),(value1, value2,...); 插入多条数据只有一次提交;
      (5)避免使用长事务;
      (6)禁止负向查询: NOT、!=、<>、!<、!>、NOT IN、NOT LIKE,会导致全表扫描;
      (7)大表之间的join,尽量缩小结果集之后再join,否则会消耗较多的内存和CPU;
      (8)搜索严禁左模糊或者全模糊(like %XX, 或like %XX%),会导致全表扫描。
      1. 什么字段选择什么类型,类型字节大小,限制条件
        数据库类型的选择对数据库的性能影响很大
        1 . 数据类型会影响存储空间的开销
        2 . 数据类型会影响数据查询性能
        所以当一个数据类型可以有多种选择多种类型的时候,应该优先考虑数字类型,其次是日期或二进制类型,最后应该是字符类型。对于相同级别的数据类型,应该优先选择占用空间小的数据类型。 原理:在对数据进行比较(查询条件,JOIN条件及排序)操作时:同样的数据,字符处理往往比数字处理慢,而且在数据库中,数据的处理是以页为单位,列的长度越小,数据类型占用的空间越小,利于性能的提升。

        下面是字段类型所占的字节大小

        这里写图片描述

        Tinyint,SmallInt,Mediumint,Int,Bingint该如何选择

        1 .从 0 到 255 的整型数据。存储大小为 1 字节。适合使用Tinyint
        2.从 -2^15 (-32,768) 到 2^15 - 1 (32,767) 的整型数据。存储大小为 2 个字节。适合使用smallint
        3.从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据(所有数字)。存储大小为 4 个字节。int 的 SQL-92 同义字为 integer。适合使用int
        4.从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字)。存储大小为 8 个字节。适合使用bigint

        char与varchar如何选择

        1.如果列中要存储的数据的长度差不多是一致的,则应该考虑char,否则应该考虑用varchar.
        2.如果列中最大数据的长度小于50Byte,则一般也考虑使用char(当然,如果这个列很少用,则基于节省空加你和减少I/O的考虑,还是可以使用varchar)
        3.一般不宜定义大雨50Byte的char类型列。 注意:utf8每一个字符时3Byte

        decimal和float如何选择

        1.decimal用于存储精确数据,而float只能用于存储非精确数据,故精确数据最好使用decimal类型
        2.由于float的存储空间的开销一般比decimal小(精确到7为小数只需要4个字节,而精确到15位小数只需要8个字节)故非精确数据类型建议使用float

        时间类型如何存储

        1.使用int来存储时间字段的优缺点 优点:字段的长度比datetime小 缺点:使用不方便,需要函数进行转换 限制:只能存储到2038-1-19 11:14:07 即2^32为2147483648
        2.需要考虑需要存储时间的粒度 年 月 日 小时 分钟 秒 周

      2. mysql索引种类?
        主键,唯一索引,普通索引。索引类别,BTree索引,hash索引。索引的优缺点,mysql的索引查找原理,join原理(大部分都是nested loop),以及一些特殊的情况,比如mysql子查询慢等

      3. 读写分离,集群管理,甚至一些参数调优

      4. ACID说一下
        原子性
        根据定义,原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。即要么转账成功,要么转账失败,是不存在中间的状态!
        一致性
        根据定义,一致性是指事务执行前后,数据处于一种合法的状态,这种状态是语义上的而不是语法上的。
        隔离性
        根据定义,隔离性是指多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
        持久性
        根据定义,持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

      5. 事务隔离的级别,默认是啥,幻读是啥意思
        1.脏读
        脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
        当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。
        举个例子,A在一个转账事务中,转了100块钱给B,此时B读到了这个转账的数据,然后做了一些操作(发货给A,或者其他的),可是这时候A的事务并没有提交,如果A回滚了事务,那就GG了。这就是脏读了。
        2.不可重复读
        不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
        例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
        不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
        在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
        3.幻读
        幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
        幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
        现在来看看MySQL数据库为我们提供的四种隔离级别:
        ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
        ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
        ③ Read committed (读已提交):可避免脏读的发生。
        ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
        以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
        在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

      6. 如何优化?涉及到分库分表,慢查询如何看,explain哪个字段能看是否用索引;最左前缀优先匹配;建索引的原则

      7. CPU高应该怎么办

      8. B+树和B树区别,MySQL为何用B+;主键查询和非主键索引查询有何区别

      9. 哈希索引

      10. 什么是聚簇索引

      11. B树有何优点,什么场景会用B树?(memcache)

      12. 扇区、节点大小的概念,为何树的高度要低

      13. innodb和myisam的区别,存储方面

      14. 你如何看待外键,优劣

    • redis相关

      1. 什么场景用redis,为什么mysql不适合?

      2. 谈谈redis的事务?用事务模拟原子+1操作?原子操作还有其它解决方案吗?

      3. redis内存满了会怎么样?

      4. 常见使用场景有哪些?

      5. 为啥快?单线程到底是因还是果;

      6. 发布订阅功能,和MQ,比如rabbitMQ有何区别?

      7. 排行榜、关注的人用什么实现;如果我想范围取值,你推荐用什么方式;

      8. dict底层实现,rehash讲一下;触发条件;

      9. zset底层实现,跳跃表讲一下;

      10. sds的特点,为何这么设计;

      11. 淘汰机制,近似LRU,为何这么设计;

      12. 两种持久化应用场景,RDB有何缺点,默认会用什么;

      13. aof文件太大怎么办;

      14. 集群:你知道几种方式,cluster特点,主从之间是如何同步的,哈希槽概念讲一下,是如何动态扩容的;

      15. 异常情况考虑过吗,比如master断网后,选举出新master,原master又恢复了。。

      16. 分布式锁如何设计

      17. redis双写,是先写数据库还是先缓存?各有什么问题,怎么解决?

      18. 强一致性要求,是否要用缓存?

四、安全

web安全相关
1. sql注入是怎么产生的,如何防止?
所谓SQL注入,就是通过把SQL命令bai插入到Web表单提du交或输入域名或页面请求的查询字符串,最zhi终达到欺骗服务器执行恶意的daoSQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.
防护 :
归纳一下,主要有以下几点:
1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和 双"-"进行转换等。
2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
6.sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。MDCSOFT SCAN等。采用MDCSOFT-IPS可以有效的防御SQL注入,XSS攻击等。
2. xss如何预防?htmlescape后能否避免xss?
XSS 攻击:即跨站脚本攻击,它是 Web 程序中常见的漏洞。原理是攻击者往 Web 页面里插入恶意的脚本代码(css 代码、Javascript 代码等),当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的,如盗取用户 cookie、破坏页面结构、重定向到其他网站等。 预防 XSS 的核心是必须对输入的数据做过滤处理
HtmlEncode和JavaScriptEncode才能预防XSS),javascript escape不能防xss
3. csrf是什么?django是如何防范的?
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
CSRF预防机制
CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。
token防御的整体思路是:

  • 第一步:后端随机产生一个token,把这个token保存在SESSION状态中;同时,后端把这个token交给前端页面;

  • 第二步:下次前端需要发起请求(比如发帖)的时候把这个token加入到请求数据或者头信息中,一起传给后端;

  • 第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;
    Django下的CSRF预防机制:
    django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在 cookie 里。然后每次 POST 请求都会带上这个 token,
    这样就能避免被 CSRF 攻击。
    在 templete 中, 为每个 POST form 增加一个 {% csrf_token %} tag. 如下:

  1. 在返回的 HTTP 响应的 cookie 里,django 会为你添加一个 csrftoken 字段,其值为一个自动生成的 token
  2. 在所有的 POST 表单模板中,加一个{% csrf_token %} 标签,它的功能其实是给form增加一个隐藏的input标签,如下
    <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">,而这个csrf_token = cookie.csrftoken,在渲染模板时context中有context['csrf_token'] = request.COOKIES['csrftoken']
  3. 在通过表单发送POST到服务器时,表单中包含了上面隐藏了crsrmiddlewaretoken这个input项,服务端收到后,django 会验证这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值是否一样。如果一样,则表明这是一个合法的请求,否则,这个请求可能是来自于别人的 csrf 攻击,返回 403 Forbidden.
  4. 在通过 ajax 发送POST请求到服务器时,要求增加一个x-csrftoken header,其值为 cookie 里的 csrftoken 的值,服务湍收到后,django会验证这个请求的cookie里的csrftoken字段与ajax post消息头中的x-csrftoken header是否相同,如果相同,则表明是一个合法的请求

五、网络基础

  1. TCP\IP\UDP

  2. get和post的区别,你还了解其他的方式么;

  3. restful

  4. 状态码

  5. 三次握手

  6. 四次挥手

  7. time_wait

  8. HTTP版本,常见header

  9. HTTPS介绍

  10. Nginx介绍,有几个进程,为何这么快;

  11. uwsgi介绍, 是干嘛的;

  12. socket方面,epoll为何快,底层用了什么?顺带说下红黑树,比如左旋右旋,变色,和AVL区别,为啥大家都会用这个;

六、django项目部分

  1. 你在项目中遇到最难的部分是什么,你是怎么解决的;

  2. 你看过django的admin源码么;看过flask的源码么;你如何理解开源;

  3. MVC / MTV;

  4. 缓存怎么用;

  5. 中间件是干嘛的;

  6. CSRF是什么,django是如何避免的;XSS呢;

  7. 如果你来设计login,简单的说一下思路;

  8. session和cookie的联系与区别;session为什么说是安全的

  9. uWSGI和Nginx的作用;
    ps:上面的这些问题,都是面试比较常问的,能答出的说明技术没问题,每个问题至少答三点,看面试官的反应,不感兴趣的少说,感兴趣的多说,基本上平均一个问题能说3-5分钟,问的问题可以的话基本是15个左右,所以一趟面试基本在一小时以上,一小时一下的面试成功希望很小,所以,基础部分一定要准备充分。

项目介绍

  1. 说一下一个请求过来到返回response的过程

  2. 如何实现单点登录

  3. JWT token是如何进行生成和校验的

  4. 了解过哪些后端框架?Tornado了解吗?

  5. 了解过webapp2吗

  6. Django如何实现csrf攻击保护

  7. 说说你项目中遇到的困难以及如何解决

  8. 说说你认为自己最有成就感或最深刻的项目

  9. 对KAFKA了解吗?用过哪些消息队列?使用过RabbitMQ吗?

  10. 项目团队几个人?开发多长时间

  11. 大家都说Nginx快?快的原因是什么?

  12. 对RPC了解吗?

  13. 如何在服务器上设置业务进程数?

  14. 说说正向代理和反向代理

项目是简历上所写的,要熟练掌握项目的内容、技术点、你负责的模块,这方面可能会问,怎么做的,特别是前端和后端是怎么配合的。(ps:如果是前后端分离,就说是后端写好接口给前端,前后端不分离需要前端写好的页面)面试官常问的是这个项目是几个人做的,说一下这个项目的架构,上线了么?(ps:这里是一个坑,如果上线了可能让你访问一下,这里机智回答),说一下你负责的这个模块主要的逻辑,主要技术点是什么,开发中遇到了哪些问题,是怎么解决的
这里问的很详细,面试之前一定要把项目过几遍,问的时候能说多详细就说多详细,主要是看你的工作经验是不是真实度
待遇
如果顺利走过了前面几关,应该聊的时间在一个半小时左右,这里是最后一关,不能掉以轻心,会问你上一家公司的待遇,你的目标薪资,如果是人事和你谈,基本面试就成了,如果是技术面试的时候,最后问了一句,一定要注意。公司的技术面试官都在公司待过,可以通过你的薪资了解到你的能力多少,和之前聊的情况进行一个匹配。