面试的一些答案
HTTP和HTTPS
http是超文本传输协议,基于socket作用于应用层之上的协议,基于请求相应,无状态,无连接。
https信息是明文传输,而https则是具有安全性的ssl加密传输协议,比http更安全。
TCP与UDP协议优缺点
UDP是用户用户数据报协议,不可靠,差错控制开销较小,传输大小限制在 64 KB以下,不需要建立连接。
TCP可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。
Linux常用命令
pwd、cd、history、vim、ls、cp
线程、协程
线程:拥有自己的堆和共享的栈 共享栈 但不共享堆 线程也是由操作系统调度
协程:协程和线程一样有自己的堆和共享的栈 共享栈但不共享堆 协程由开发人员在适当情况调用
线程池:提前创建若干个线程,如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。要注意线程池大小、并发错误、线程泄漏
互斥锁
一个线程获得资源的使用权后就会将该资源加锁,使用完后会将其解锁,如果在使用过程中有其他线程想要获取该资源的锁,那么它就会被阻塞陷入睡眠状态,直到该资源被解锁才会被唤醒,如果被阻塞的资源不止一个,那么它们都会被唤醒,但是获得资源使用权的是第一个被唤醒的线程,其它线程又陷入沉睡.
GIL锁
全局解释器锁。当我们用多线程的时候,每一个进程中只有一个GIL锁,那么这多个线程中谁拿到GIL锁,谁即可以用cpu(ps:多个进程有多个Gil锁,但每个进程中只有一个GIL)
同步和异步
同步异步关注的是消息通信机制
同步:就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值。换句话说,就是由调用者主动等待这个调用结果。
异步:调用在出发之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用出发后,调用者不会立刻得到结果。而是在调用出发后,被调用者通过状态、来通知调用者或通过回调函数处理这个调用。
阻塞和非阻塞
指的是程序的运行状态
阻塞:程序运行过程中遇到IO操作 无法继续
非阻塞:程序正在运行中,并且没有遇到IO,即使遇到IO也不会阻塞,CPU不会切走
垃圾回收机制
栈(先进先出、临时存储、局部)| 堆(先进后出、持久化存储、全局)
引用计数(优点:一旦没有引用,内存就直接释放,缺点:维护引用计数消耗资源、循环引用)、标记清除、分代回收
MySQL事务
- 原子性:最小的工作单元,不可再分。事务中的所有操作必须全部成功或全部失败,成功后写入底层数据,失败后回滚rollback到事务开启的状态。
- 一致性:事务在完成时,必须使所有的数据都保持一致状态,保持数据库的完整性。
- 隔离性:并发事务之间存在隔离,互不干扰。
- 持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一致保持。
MySQL查询优化
- 储存引擎选择:如果数据表需要事务处理,应该考虑使用InnoDB,因为它完全符合ACID特性。如果不需要事务处理,使用默认存储引擎MyISAM是比较明智的
- 分表分表,主从
- 对查询进行优化,要尽量避免全表扫,首先应考虑在where及order by涉及的列上建立索引
- 应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫
- 应尽量避免在where子句中使用!=或< >操作符,否则将引擎放弃使用索引而进行全表扫
- 应尽量避免在where子句中使用or来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫
- Update语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志
MySQL索引优化
-
前导模糊查询
-
union、in、or都能够命中索引,建议使用in
-
负向条件查询不能使用索引,可以优化为in查询
-
联合索引最左前缀原则(又叫最左侧查询)
-
范围列可以用到索引(联合索引最左前缀原则)
-
把计算放到业务层而不是数据层
-
强制类型转换会全表扫描
-
更新十分频繁、数据区分度不高的字段上不宜建立索引
-
利用覆盖索引来进行查询操作,避免回表
-
如果有order by、group by的场景,请注意利用索引的有序性
-
使用短索引(又叫前缀索引)来优化索引
-
建立索引的列,不允许使用null
-
利用延迟关联或者子查询优化超多分页场景
-
业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引
-
超过三个表最好不要用join
-
如果明确知道只有一条结果返回,limit1能够提高效率
-
SQL性能优化expalin中的type:至少要达到range级别,要求是ref级别,如果可以是consts最好
-
单表索引建议控制在5个以内
-
单索引字段数不允许超过5个
-
创建索引时避免以下错误观念
索引越多越好,认为一个查询就需要建一个索引
宁缺勿滥,认为索引会消耗空间、严重拖慢更新和新增速度
抵制唯一索引,认为业务的唯一性一律需要在应用层通过“先查后插”方式解决
过早优化,在不了解系统的情况下就开始优化
MySQL主从复制
- 从库开启主从同步之后,开启了两个线程:IO线程(从主库同步数据即bin-log)、SQL线程(负责将同步过来的sql语句进行执行)
- 同步主库也会开启一个dump线程,等待着从库过来请求数据
- io线程带着从本地‘master.info’中的pos标记,去主库中查询有没有比这个标记更新的数据,如果有的话,主库会将标记到的最新的pos标记之间的数据进行返回
- 等io线程接收到数据之后,将数据存放在tcp/ip缓存中,不用等待,从库的sql进程执行整个过程是异步的,在tcp/ip接收到数据之后返回一个ack给主库代表着成功接收到数据
- 然后将数据放到‘relay-log’交由sql线程执行当前已经执行的标志位‘relay-log.info’中获得,拿着标签去‘relay-log’中获得数据进行同步。
MongoDB
MongoDB是一个面向文档的数据库系统,使用C++编程,不支持SQL,但有自己功能强大的查询语法。
MongoDB使用BSON作为数据存储和传输的格式,BSON是一种类似JSON的、二进制序列化文档,支持嵌套对象和数组。
MongoDB很像MySQL占用空间过大,维护工具不够成熟。
MongoDB应用场景
- 网站数据:mongodb非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
- 缓存:由于性能很高,mongodb也适合作为信息基础设施的缓存层。在系统重启之后,由mongodb搭建的持久化缓存可以避免下层的数据源过载。
- 大尺寸、低价值的数据:使用传统的关系型数据酷存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。
- 高伸缩性的场景:mongodb非常适合由数十或者数百台服务器组成的数据库
- 用于对象及JSON数据的存储:mongodb的BSON数据格式非常适合文档格式化的存储与查询
- 重要数据:mysql,一般数据:mongodb,临时数据:memcache
Django request请求流程
浏览器发送http请求通过后台的web服务网关接口里面的wsgiref解析和封装了http数据(WSGI是协议:wsgiref、uwsgi、werkzeug都是基于该协议),之后通过Django的中间件(默认是7个中间件,五个是可自定义方法,全局访问频率限制、权限限制等process_request:请求刚进来时、process_view:经过url执行视图函数之前、process_template_response:视图函数中return render时触发、process_exception:视图函数报错执行、process_response:返回相应响应时)中间件执行顺序请求来从上向下、请求走从下往上,之后经过路由层(可以是有名分组和无名分组,可以通过include实现路由分发,反向解析前端通过{ % url ''%} 后端通过reverse),之后通过视图函数层(FBV和FBV)通过获取models进行渲染前端页面然后返回给浏览器。
Django as_view的执行过程
当urls中as_view()方法它实际是一个必包,它的作用就是做一些检查工作,在返回view方法
view方法的作用是给请求对象补充三个参数,并调用dispatch方法进行处理
dispatch方法查找到指定的请求方法,并执行相应的代码
(比如一个get请求过来,首先匹配路由,匹配到后执行后面的视图函数,比如匹配的是index函数 执行他的as_view,index中没有as_view回去找它继承的APIView执行APIView中的as_view方法,其实这个as_view就是执行的Django原来的view方法,但是执行self.dispatch的时候,执行的就不是原来view中的dispatch,而是APIView中的dispatch方法,这个dispatch就是在原来的dispatch方法上添加了initialize_request方法,对requext进行了封装,包含了原来的request,然后执行initial认证、权限、频率组件执行原来的流程,执行视图函数,返回response)
cookie、session、token
cookie:cookie是浏览器中永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。由服务器产生发送给浏览器,浏览器把cookie以key,value键值对形式保存到某个文件下,下次访问同一网站再发送给服务器。
session:服务器把session临时保存在服务器上,用户离开网站后session就会被销毁。
token:是无状态可扩展的,支持移动设备,跨程序调用,安全
RESTful规范
url连接设计:采用https方式,有api关键字,有版本需要明确版本,请求链接用名词来表示资源,具体的操作方式采用请求方式来确定
url响应数据设计:需要明确状态码、错误信息、成功结果,子资源一般用子资源接口来标注
缓存雪崩,缓存击穿,缓存穿透
缓存雪崩:缓存中的数据大批量到过期时间,查询数据量巨大,引起数据库压力过大而宕机(缓存数据的过期时间设为随机,防止同一时间大量数据过期、如果缓存数据库是分布式部署,那就把热点数据均匀分布在不同缓存数据库中、设置热点数据永不过期)
缓存击穿:指在缓存中没有但是在数据库中有的数据(一般是缓存数据过期),很多用户同时访问,缓存数据库中没有,就直接去访问数据库,造成数据库压力过大(设置热点数据永不过期,加互斥锁)
缓存穿透:指缓存中和数据库中都没有的数据,很多用户同时访问,如果找的是id为"-1"或id特别大不存在的数据,会造成用户变成攻击者,导致数据库压力过大。(可以加频率限制或者接口校验id校验)
六大设计原理
- 单一职责原则
- 里氏替换原则
- 依赖倒装原则
- 接口隔离原则
- 迪米特法则
- 开闭原则
冒泡排序
# 时间复杂度:O(n^2) 空间复杂度:O(1)
def bubble_sort(li):
for i in range(len(li) - 1):
flag = False
for j in range(len(li) - 1 - i):
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
flag = True
if not flag:
return
快速排序
时间复杂度:O(n log n)
def partition(li, left, right):
tmp = li[left]
while left < right:
while left < right and li[right] >= tmp:
right = right - 1
li[left] = li[right]
while left < right and li[left] <= tmp:
left = left + 1
li[right] = li[left]
li[left] = tmp
return left
def quick_sort(li, left, right):
if left < right:
middle = partition(li, left, right) # O(n)
quick_sort(li, left, middle - 1) # O(log n)
quick_sort(li, middle + 1, right) # O(log n)
设计模式
单例模式
工厂模式
代理模式


浙公网安备 33010602011771号