面试
Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
通常简称为DRF框架 或 REST framework。
特点:
提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
多种身份认证和权限认证方式的支持;
内置了限流系统;
直观的 API web 界面;
可扩展性,插件丰富
Django的中间件
Django的中间件就是一个类,分别是process_request,process_respone,process_view,process_exception,process_render_template。
中间件的应用场景
做ip限制
放在中间件类的列表中华,阻止了某些ip的访问
2,URL访问过滤
如果用户访问的是login视图
如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省在多个视图函数上写装饰器
3、缓存
客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层执行视图函数
数据库的结构设计,和优化?
第一范式:保证列的原子性,保证列不可在分
第二范式:唯一性;一个表只能说明一个事物,有主键且非主键依赖主键
第三范式:每列都与主键有直接关系,不存在传递依赖
Ps:第二范式要遵循第一范式,第三范式要遵循第二范式
数据库结构优化的目的有哪些?
l 减少数据冗余
l 尽量避免数据维护中出现更新,插入,删除异常。
l 节约数据查询空间
优化mysql数据库的8个方法
l 选取最合适的字段j
l 使用join来代替子查询
l 使用联合来代替手动创建的临时表
l 事务 (1.维护数据库的完整性。2.当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其他用户干扰)
事务的缺点:因为事务的独占性,有时候会影响数据库的性能,在事务执行过程中,数据库被锁定,其他用户请求只能等待该事务结束,当访问量大时,就会产生较严重的响应延迟
l 锁定表 (可以维护数据的完整性,但是不能保证数据的关联性)
l 使用外键
l 使用索引 (索引应该建立在join,where,判断和orderby排序字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。)
l 优化查询语句 (查询的时候尽量不要select * ,尽量使用索引字段查询)
多线程,多进程,celery分布式任务,定时任务和异步任务
l 线程:一个运行的程序就是一个进程
l 进程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,
进程间内存是否是存是共享,如何实现通讯?
进程间内存不共享
1. 可以通过Manage模块加锁
2. 通过队列或通过管道加锁
3. Socket实现通讯
l 协程:是一种用户态的轻 量级线程,协程的调度完全由用户控制
Celery是分布式异步消息任务队列。
优点:
l 简单
l 高可用:当任务执行失败或执行过程中发生连接中断,celery会自动尝试重新执行任务
l 快速:一个单进程的celery每分钟可以处理上百万个任务
l 灵活:几乎celery的各个组件都可以被扩展及定制
Celery支持定时任务,celery启动任务有两种方式:1.在程序中指定2.在配置文件中指定
Celery异步任务,一些耗时较长的操作,比如i/o操作,可以交给celery去异步执行,用户提交后可以做其他事情,让任务完成后将结果返回用户,可以提高用户体验。
互联网通信协议http协议,是一个无状态协议。
客户端用到的手段,只能是http协议,四个表示操作方式的动词:get,post,put,delete。它们分别对应四种操作:get用来获取资源,post用来新建资源(也可以用于更新资源),put用来更新资源,delete用来删除资源
计算机网络传输协议分层
1.osi七层模型
从上到下:应用层 (应用程序的通信服务)
表示层 (定义数据格式及加密)
会话层 ()
传输层 ()
网络层 ()
数据链路层 ()
物理层 ()
2.五层模型
从上到下:
应用层 (应用程序的通信服务)
表示层 (定义数据格式及加密)
网络层 (定义包传输,定义节点的逻辑地址,定义路由实现和学习的方式,定义包的分段方法)
数据链路层(定义单个链路如何传输数据)
物理层(传输介质的标准定制)
http是超文本传输协议,是客户端浏览器或其他程序与web服务器之间的应用层通信协议。
tcp(面向连接)通过序列化应答和必要时重发数据包,tcp为应用程序提供了可靠的传输流和虚拟连接服务。
udp(用户数据报协议)是与tcp相对应的协议,它是面向非连接的协议,它不与对方建立连接,而是直接把数据包发送过去
tcp/udp区别:1、tcp面向连接,udp是无连接,发送数据之前不需要连接
2、安全方面:tcp提供可靠服务,通过tcp连接传送数据,无差错,不丢失,不重复,且按序到达
udp尽最大努力交付,即不保证可靠交付
3、传输效率的区别
TCP传输效率相对较低
udp传输效率高,适用对高传输和实时性有较高的通信或广播
4、连接对象数量的区别
tcp连接只能是点到点,一对一的。
udp支持一对一,一对多,和多对一和多对多的交互通信
Http是应用层协议,tcp是传输层协议!
数据包在网络传输过程中,http被封装在tcp包内
什么是nginx?
nginx 是一个高性能http和反向代理服务器,也是一个(IMAP/POP3)代理服务器 目前使用的最多的web服务器或者是代理服务器。
为什么要用nginx?
优点:1.跨平台,配置简单 2、非阻塞。高并发连接;处理2-3w并发连接数 3、内存消耗小 4、内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,在发送的请求就不会发送到宕机服务器,重新将请求提交到其他节点上 5、节省宽带 6、稳定性高:宕机的概率非常小 7、master/worker结构:一个master进程,生成一个或者多个worker进程 8、接受用户请求的是异步,浏览器将请求发送到nginx服务器,它先将用户请求全部接收下来,在一次性发送给后端web服务器,极大减轻了web服务器的压力 9、一边接收web服务器的返回数据,一边发送给浏览器客户端 10、网络依赖性比较低,只要ping通就可以负载均衡 11、可以有多台nginx服务器 12、事件驱动:通信机制采用epoll模型
为什么nginx性能那么高?
因为他的处理机制:异步非阻塞事件处理机制:运用了epoll模型。提供了一个队列,排队解决
为什么不使用多线程?
因为线程创建上下文的切换非常消耗资源,线程占用内存大,上下文切换占用cpu也很高,采用epoll模型避免了和这个缺点
uwsgi是一个web 服务器,他实现了wsgi协议,uwsgi、http等协议。
wsgi是一种通信协议。 uwsgi是一种线路协议而不是通信协议,在此常用在uwsgi服务器与其他网络服务器的数据通信
uwsgi是实现了uwsgi和wsgi两种协议的web服务器
websocket特点:1.建立在tcp协议之上,服务器端的实现比较容易 2、与http协议有良好的兼容性,默认端口是80和443,通信握手阶段采用了http协议,能通过各种http代理服务器 3、数据格式比较轻量,性能开销小,通信高效 4.可以发送文本,也可以发送二进制数据 5.没有同源策略的限制,客户端(浏览器)可以任意与服务器通信
同步和异步关注的是消息通信机制
同步就是在发出一个调用之后,在没有得到结果之前,该调用就不返回,但是一旦调用返回,就得到了返回值(就是调用者主动等待这个调用结果)
异步刚好相反,调用在发出去之后,这个调用就可以直接返回,所以没有返回结果,当一个异步调用过程调用发出去后,调用者不会立刻得到结果,而是在调用发出去后,被调用着通过状态、通知来通知调用者,或通过回调函数处理这个调用。
Mysql的复制原理及负载均衡
Mysql主从复制工作原理
1. 在主库上把数据更高纪录到二进制日志
2. 从库将主库的日志复制到自己的中继日志
3. 从库读取中继日志的事件,将其重放到从库数据中
Mysql主从复制解决的问题
数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
负载均衡:降低单个服务器的压力
高可用和故障切换:帮助应用程序避免单点失败
升级测试:可以用更高版本的mysql作为从库
设定网站用户数量在千万级,但是活跃用户的数量只有1%,如何通过优化数据库提高活跃用户访问速度?
1. 可以使用Mysql的分区,把活跃用户分在一个区,不活跃用户分在一个区,本身活跃用户区数据量比较少,因此可以提高活跃用户的访问速度
还可以水平分表,把活跃用户分在一张表,不活跃用户分在一张表,可以提高活跃用户访问速度
阻塞/非阻塞和同步异步
阻塞:在进行socket通信中,一个线程发起请求,如果当前请求没有返回结果,则进入sleep状态,期间线程挂起不能做其他操作,直到有返回结果,或者超时(如果设置超时的话)
非阻塞:与阻塞相似,只不过在等待请求结果时,线程并不挂起而是进行其他操作,既在不能立刻得到结果之前,该函数不会阻挂起当前线程,而是会立刻返回。
进程问题
进程间内存是否是共享?如何实现通讯?
进程间内存不共享
1.可以通过Manage模块加锁
2.通过队列或通过管道加锁
3.Socket实现通讯
请聊聊进程队列的特点和实现原理?
1. 先进先出
2. 后进先出
3. 优先级队列
线程本身带锁通过put()和get()数据,同一时间只有一个线程运行修改任务实现数据安全
请画出进程的三状态转换图
就绪====运行
\阻塞/
谈谈python的装饰器,迭代器,yield
装饰器:装饰器的本质是一个闭包函数,他的作用就是让其他函数在不需要任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数对象,我们通常在一些有切面需求的场景,比如:插入日志,性能测试,事物处理,缓存,权限校验等场景,有了装饰器就可以少写很多重复代码,提高效率
迭代器:迭代器是一种访问可迭代对象的方式,通常从第一个元素开始访问,知道所有的元素都被访问完才结束,迭代器只能前进不能后退,使用迭代器可以不用事先准备好迭代过程中的所有元素,仅仅是在迭代到该元素的时候才能计算该元素,而在这之前的元素则是被销毁,因此迭代器适合遍历一些数据量巨大的无限的序列。
迭代器的本质就是调用iter方法,每次调用的时候返回一个元素,当没有下一个元素的时候回排除StopIteration异常
如何解决线程安全?
线程安全是在多线程的环境下,能够保证多个线程同时执行时程序依旧运行正确,而且要保证对于共享的数据可以由多个线程存取,但是同一时刻只能有一个线程进行存取。多线程环境下解决资源竞争问题的办法是加锁来保证存取操作的唯一性。如何加锁?分布式 负载均衡
常用linux命令?
Ls ,cd,more,clear,mkdir,pwd,rm,grep,find,mv,su,date等等
什么是面向对象编程?
回答:面向对象编程是一种软件复用的设计和编程方法。这种方法把软件系统中相近似的操作逻辑和操作应用数据、状态,以类的形式述出来,以对象实例的形式在软件系统中复用,以达到高软件开发效率的作用。封装,继承多态
如何提高python的运行效率,请说出不少于2种提高运行效率的方法?
1. 使用生成器
2. 关键代码使用外部功能包:Cython,Pylnlne、pypy、pyrex
3. 针对循环的优化—尽量避免在循环中访问变量的属性;
说说mysql数据库存储的原理?
存储过程是一个可编程的函数,它在数据库中创建并保存,它可以有sql语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者是封装特定功能时,存储过程是非常有用的,数据库中额度存储过程客户看做是对编程中面向对象方法的模拟,他允许控制数据的访问方式。
说一下事物的特效?
1. 原子性:事物中的全部操作在数据库中是不可分割的,要么全部完成,要么俊不执行
2. 一致性:几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
3. 隔离性:事物的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
持久性:对于任意已交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库
MyISAM不支持事务,InnoDB支持事务。表锁虽然开销小,锁表快,但高并发下性能低。行锁虽然开销大,锁表慢,但高并发下相比之下性能更高。事务和行锁都是在确保数据准确的基础上提高并发的处理能力。
MySQL常用的存储引擎是InnoDB,相对于MyISAM而言。InnoDB更适合高并发场景,同时也支持事务处理。
行锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;
表锁:开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
页锁:开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般
什么时候使用表锁
对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。
第一种情况是:事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
第二种情况是:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
问题一:已登录用户的购物车放在哪里?未登录用户的购物车放在哪里?
已登录用户的购物车可以放在数据库中(可以先在Redis中缓存);未登录用户的购物车可以保存在Cookie、localStorage或sessionStorage中(减少服务器端内存开销)
登录后购物车合并
当跳到购物车页面,查询购物车列表前,需要判断用户登录状态,如果登录:
首先检查用户的localStorage中是否有购物车信息
如果有,则提交后台保存
清空Localstorage
如果未登录,直接查询就好
调用支付宝第三方API接口
创建调用支付宝的对象
在线创建应用时分配的ID
自己应用的私钥
支付宝的公钥
调用获取支付页面操作
生成完整的支付页面URL
通过上面返回的链接可以进入支付页面,支付完成后会自动跳转回上面代码中设定好的项目页面,在该页面中可以获得订单号(out_trade_no)、支付流水号(trade_no)、交易金额(total_amount)和对应的签名(sign)并请求后端验证和保存交易结果,代码如下所示:
创建调用支付宝的对象
创建调用支付宝的对象
自己应用的私钥
支付宝的公钥
请求参数(假设是POST请求)中包括订单号、支付流水号、交易金额和签名
调用验证操作
超卖现象:比如某商品的库存为1,此时用户1和用户2并发购买该商品,用户1提交订单后该商品的库存被修改为0,而此时用户2并不知道的情况下提交订单,该商品的库存再次被修改为-1这就是超卖现象。解决超卖现象有三种常见的思路:
悲观锁控制:查询商品数量的时候就用select ... for update对数据加锁,这样的话用户1查询库存时,用户2因无法读取库存数量被阻塞,直到用户1提交或者回滚了更新库存的操作后才能继续,从而解决了超卖问题。但是这种做法对并发访问量很高的商品来说性能太过糟糕,实际开发中可以在库存小于某个值时才考虑加锁,但是总的来说这种做法不太可取。
乐观锁控制:查询商品数量不用加锁,更新库存的时候设定商品数量必须与之前查询数量相同才能更新,否则说明其他事务已经更新了库存,必须重新发出请求。这种做法要求事务隔离级别为可重复读,否则仍然会产生问题。
尝试减库存:将上面的查询(select)和更新(update)操作合并为一条SQL操作,更新库存的时候,在where筛选条件中加上库存>=购买数量或库存-购买数量>=0的条件。