1. python 的内存管理
引用计数,变量的赋值只是对对象的引用,删除一个变量就减少了一个引用。 垃圾回收,当对象的引用计数为0时,对象会被垃圾回收,释放内存。自动的垃圾回收是需要一定的阈值条件,垃圾对象达到一定的数量,才会触发;主动触发gc.collect() 内存池机制,python申请的1-256k的小块内存,由malloc进行分配,垃圾回收后,内存不会释放,而是由内存池进行管理,便于下次使用。
2. 类方法与实例方法、静态方法
类方法
-
使用@classmethod装饰的方法,第一个参数为当前类cls, 可以被类对象、实例对象引用
实例方法
-
在类中定义的普通方法,第一个参数为当前实例对象self, 可以被类对象、实例对象引用
静态方法
-
使用@staticmethod装饰的方法,参数不需要传cls或者self,可以自行决定传递的参数,就相当于将一个普通的方法放入类中。 可以被类对象、实例对象引用
3. python的闭包与装饰器
闭包,定义函数时,在其内部又定义了一个函数,内部函数的内部作用域引用了外部函数的局部变量,外部函数返回内部函数,这种函数嵌套的方式就是闭包。
装饰器,它是闭包的一种应用形式,可以在不改变源码的情况下扩展函数的功能。使用\@高阶函数去装饰另一个函数,进行功能扩展。
4. 什么是git? 有什么作用? 如何初始化一个本地仓库
git, 分布式版本控制工具 可以实现软件的版本控制,在多个版本之间切换; 可以实现多分支开发,提高开发效率; 可以实现历史记录,历史状态的恢复; 团队内部实现权限管理等。
初始化本地仓库: git init
5. 什么是并行?什么是并发? Python的多线程属于哪种,为什么?
并发,两个或两个以上的程序,在同一时间内执行。 并行,同时执行,异步独立 python的多线程属于并发,在python解释器内部有一个GIL,所有线程必须申请到该锁才可以解释执行。
-
python 是弱类型的语言,由python解释器边解释边执行。 源码---解释 为01001--交给CPU执行
-
Java C 强类型语言, 源代码需要编译,得到字节码文件 ---CPU执行
-
python解释器 ----开一个进程, 在这个进程里有一个GIL(Global Interpreter Lock)全局解释器锁
-
在一个进程里开的所有的线程,必须申请这个GIL, 然后才可以执行。其他线程必须等待。
-
所以python的多线程是属于并发。
6. Django对请求的处理流程
处理请求的中间件,在进入路由匹配之前对请求做一些预处理或者直接返回响应
主路由及分布式路由的匹配
处理视图的中间件,在请求进入视图之前,做一些预处理
在视图中接收请求、处理请求、返回响应;视图中发生异常时,还可以使用异常处理中间件进行处理。
处理响应的中间件,对响应做一些预处理
7. 开发模式有哪些?
前后端不分离,页面结构和数据由后端服务器渲染,然后返回给浏览器,由浏览器展示即可。缺点是既要做后端接口,又要做模板页面;服务器计算压力大。 前后端分离,将页面结构、数据分离开,前端服务器返回页面结构,后端服务器返回数据。 由客户端浏览器最终渲染整体页面。可以实现并行开发、充分利用客户端的资源,降低服务器的压力。
8. 什么是静态页面? 动态页面?
静态页面, html/css/js等资源均已准备就绪,由浏览器展示页面即可,不用再动态渲染。 动态页面,浏览器拿到页面后,需要执行js,经过多次与服务端交互,渲染最终的页面。
9. JWT 会话保持的流程
浏览器发起请求登陆,服务端验证身份,根据算法,将用户标识信息编码生成 token, 并且返回给浏览器做本地存储;下次请求时,把本地的 token 一起发送给服务器,服务器通过解码token,完成用户的身份认证。
10. JWT token的生成过程?
对header {'typ':"JWT", 'alg':"HS256"}进行base64编码,然后将结果中的’=‘替换为“”, 得到第一部分; 对payload {’username‘:"laufing", .....}进行base64编码,然后将结果中的’=‘替换为’‘,得到第二部分; 第一部分通过“.” 拼接第二部分,然后使用HS256算法进行哈希加密,然后base64编码,最后将结果中的’=‘替换为’‘,得到第三部分。 以上三部分通过’.‘ 拼接为一个整体,即得到jwt token。
11. JWT 如何做身份验证的?(JWT的验证过程)
首先,JWT 的 Token 相当是明文,是可以解码的,服务端,拿到 token 后进行解码,解码成功就可拿到用户的信息,即认证成功。 解码流程:将token字符串从右边开始以“.”进行一次分割,得到签名输入部分(header编码+payload编码)、签名部分, 对签名输入部分进行哈希加密(使用header中的alg算法),然后base64编码,将编码结果中的'='替换为“”,然后与签名部分对比,两者一致则验证成功,否则失败。
12. JWT 如何防止 token 被串改?
jwt第三部分signature是关键且无法解密,能被解密出明文的,只有header和payload,假如中间串改了payload,在服务端在执行一次 signature = 哈希加密(header + “.” + payload, 密钥),然后与token中的signature对比,肯定不一致,因为哈希加密是单向不可逆的过程,只要header、payload有任何的改变,计算出的签名一定改变,从而与原来的签名不一致。
13. tcp三次握手的过程:
-
第一次握手:客户端发送syn包(syn=i)到服务器,并进入SYN_SEND状态,等待服务器确认; SYN:同步序列编号(Synchronize Sequence Numbers)
-
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=i+1),同时自己也发送一个SYN包(syn=j),即SYN+ACK包,此时服务器进入SYN_RECV状态;
-
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=j+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
14. 类属性和实例属性的区别?
-
实例属性:在init方法中定义的属性称为实例属性,属于某个实例,不同实例之间互不影响。
-
类属性:在类里面和方法外面定义的属性称为类属性,属于当前类,可以被所有实例共享。
-
对象可以访问类属性,但是不能够修改类属性。
-
如果对象想要修改类属性怎么做?
-
定义类方法,通过类方法修改。
-
15. django中csrf的实现机制?
CSRF即跨站伪造请求攻击,是利用用户登录后保存在浏览器中的认证信息(cookie),进行一些恶意操作的过程。 Django预防CSRF攻击的方法:
配置文件中开启CSRF中间件,然后在模板页面中加入{% csrf_token %}
Django渲染该模板时,就会在页面中生成一个csrftoken口令,同时存入cookie一份
用户提交POST表单时,将页面中的csrftoken 和cookie中的csrftoken一起发给服务端,django验证两者是否相等,相等则认为是合法请求,否则报403
16. 什么是wsgi, uwsgi, uWSGI
WSGI: web 服务器网关接口, 是一套协议。用于接收请求并进行初次封装,然后将请求交给web框架
uwsgi: 和WSGI一样是一种通讯协议,是uWSGI的独占协议,用于定义传输信息类型
uWSGI:一个web服务器,实现了WSGI协议 uWSGI协议 http协议
17. Redis有哪些优缺点
优点
-
数据存储在内存, 读写速度快,性能优异
-
支持数据持久化,便于数据备份、恢复
-
支持简单的事务,操作满足原子性
-
支持String、List、Hash、Set、Zset五种数据类型,满足多场景需求
-
支持主从复制,实现读写分离,分担读的压力
-
支持哨兵机制,实现自动故障转移
缺点
-
数据存储在内存,主机断电则数据丢失
-
存储容量受到物理内存的限制,只能用于小数据量的高性能操作
-
在线扩容比较困难,系统上线时必须确保有足够的空间
-
用于缓存时,易出现’缓存雪崩‘,’缓存击穿‘等问题
18. 为什么要用 Redis 做缓存?
web系统中的缓存是一种降低数据库的查询压力,提高服务性能的一种数据存储方案。它需要更快的数据读写操作,满足多场景的数据类型,更健全的数据安全、数据可用机制等,而redis恰好具有以上这些优点,所以常用Redis作为缓存。
19. Redis为什么这么快
-
完全基于内存,内存操作,非常快速。而且数据结构类似于 HashMap,查找和操作的时间复杂度都是O(1);
-
采用单线程,避免了不必要的上下文切换和竞争条件,不用考虑各种锁的问题,不存在加锁释放锁操作
-
使用 I/O 多路复用,非阻塞 IO模型
20. Redis的应用场景
-
计数器 可以对 String 进行自增自减运算,从而实现计数器功能。
-
缓存 将热点数据放到内存中进行缓存,降低数据库的查询压力
-
会话缓存(session) 可以使用 Redis 来统一存储多台应用服务器的会话信息,解决session不能共享的问题。
-
全页缓存(FPC) 缓存整个页面,加快页面的响应速度
-
查找表 查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
-
消息队列 List 是一个双向链表,可以作为生产者、消费者之间的中间队列。不过最好使用 Kafka、RabbitMQ 等消息中间件。
-
分布式锁实现 在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
-
其它 Set 可以实现交集、并集等操作,从而实现共同好友等功能。ZSet 可以实现有序性操作,从而实现排行榜等功能。
21. 什么是Redis持久化
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。 有RDB、AOF两种方式
RDB,将内存数据以二进制形式存入磁盘; AOF,将操作指令写入日志文件。
22. Redis 的持久化机制是什么?各自的优缺点?
方式一:RDB
RDB:是Redis DataBase缩写快照 RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。
优点:
-
只有一个文件 dump.rdb,方便持久化。
-
容灾性好,一个文件可以保存到安全的磁盘。
-
性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。
-
相对于数据集大时,比 AOF 的启动效率更高。
缺点:
-
据安全性低。
RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
方式二 :AOF
AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
优点:
-
数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。
-
通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
-
AOF 机制的 rewrite 模式。文件过大时会对命令 进行合并重写, 可以删除其中的某些命令
缺点:
-
AOF 文件比 RDB 文件大,且恢复速度慢。
-
数据集大的时候,比 rdb 启动效率低。
两种持久化的对比?
-
AOF文件比RDB更新频率高,优先使用AOF还原数据。
-
AOF比RDB更安全也更大
-
RDB性能比AOF好
-
如果两个都配了优先加载AOF
23. Redis持久化数据和缓存怎么做扩容
-
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
-
如果Redis被当做一个持久化存储使用,搭建集群实现扩容。
24. 过期键的删除策略
-
定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
-
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
-
定期扫描:每隔一定的时间,会扫描expires字典中key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
25. Redis key的过期时间和永久有效分别怎么设置?对过期的数据怎么处理呢?
EXPIRE设置过期时间和PERSIST设置永久有效。
常见的策略有两种:
-
定时去清理过期的缓存;
-
当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就删除。
26. Redis的内存淘汰策略有哪些?
Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
-
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
-
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
-
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
-
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
-
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
-
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
总结
Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。
27. 数据库事务的四大特性
原子性(Atomicity);指事务是一个不可分割的单元,事务中的操作要么全部执行,要么全部不执行。 一致性(Consistency);事务执行前后数据的完整性必须保持一致。这里的完整性包括实体完整性、参照完整性、用户定义的完整性。 隔离性(Isolation);多个用户并发访问数据库时,数据库为每一个用户开启一个事务,多个事务并发执行时,相互之间是隔离开的,互不影响。 持久性(Durability);事务一旦被提交,对数据库中数据的改变是永久性性的。
28. 事务的隔离级别
读未提交
事务A更新了数据,但是还没提交;事务B就读取到A更新的数据,事务A回滚后,B就看不到更新的数据。这种现象就是读未提交,即脏读
读已提交
事务A更新数据并完成提交;事务B内部就可以读取到A更新的数据。
如:开始时,事务A、B读取的库存量都是100; 事务A更新库存为80,并进行了提交。由于事务B处理比较耗时,还没执行结束,B再次读取库存时,已经变成了80;最后B在更新库存时就要在80的基础上进行更新。
可重复读
事务A更新数据并完成提交;在事务B提交之前,其内部无法读取到A更新的数据,只能读取到之前的旧数据。(普通查询,即快照读) 缺点:容易出现幻读:
什么是幻读?
对于innodb存储引擎,可重复读的隔离级别,使用当前读(加共享锁)时容易出现幻读,即一个事务进行两次相同条件的查询时,后一次查询看到了上一次没有看到的行。
串行(xing)化
所有事务串行执行,一个执行完成,再执行另一个。
29. 什么是悲观锁、乐观锁?如何选择
悲观锁:在查询语句上加锁,保证多事务写入时串行执行。
例如,在多个用户同时进行订单提交时,哪个事务先执行到该语句则获取锁,等事务结束后才会释放,其他事务阻塞等待获取锁,保证了同一时刻只有一个事务在写入;
乐观锁:查询时不加锁,在变更时对比原数据与当前重新查询的数据是否一致,若不一致则本次变更失败(即乐观的认为当前没有其他事务在同时进行此过程)
在冲突较少时,如订单并发量较少,使用乐观锁(省去加锁、释放锁的开销,提高性能),在冲突较多时,如订单并发量大,使用悲观锁。一般将整个事务的过程都放置于try中。