八股

Python

python-内置函数

内置函数是python预先定义的函数,这些函数可以提高我们的编码效率。常用的比如map,他可以传两个参数,分别是函数和指定的序列,会根据你提供的函数对指定的序列做映射,还比如zip,我们也叫拉链,就是把两个可迭代的对象打包成一个个元组。还有像hash,是获取一个对象的hash值,enumerate,可以把可迭代对象同时列出数据和索引,一般用在for循环里。

python-匿名函数

正常情况我们使用的都是有名函数,就是def关键字定义的函数,匿名函数表示没有名字的函数,用lambda关键字定义,没有名字就意味着这个函数只能使用一次,匿名函数和有名函数一样,也有参数和返回值作用域这些。一般来说匿名函数语法是比较简单的。

python-反射

反射是指在程序运行过程中,对于任意一个对象我们可以调用他的属性和方法。这种动态获取对象属性和调用方法的功能称为反射。

python-单例模式

单例模式是指保证该类只有一个实例化对象,并且提供访问这个对象的方式。单例是一种设计模式,当我们想控制实例对象只有一个来节省资源的时候可以使用。

比如说我们服务器有个配置信息的文件,我们客户端通过一个类来读取内容,如果程序运行的时候很多地方都要用到这个配置文件,就可以用单例。

单例模式还是比较简单的,主要思路都是在内部维护一个属性,用来确定是否已经生成了单例,如果已经生成了就直接返回。python的模块导入是天然的单例,一般够用,还有就是使用类方法实现单例的话,多线程情况下会不安全,单例失效,需要在生成单例的地方加线程锁。

优点:

1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间;
2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;
3、单例可长驻内存,减少系统开销。

缺点:

1、单例模式的扩展是比较困难的;
3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试;
4、单例模式在某种情况下会导致“资源瓶颈”。

python-装饰器模式

装饰器模式是指动态地给一个对象添加一些额外的职责。当我们需要给很多地方添加同一个功能的时候,我们可以编写一个装饰器,实现不改动原代码,而增加上了新功能。装饰器也是应该比较多的高级方法,比如django框架中zuth组件的login_required,这个装饰器装饰在视图函数之后,若未登录,那么就会进我们的指定页面,登录之后又会自动重定向到之前的页面。还有drf里面自动生成路由之后的action装饰器,可以根据我们填入的参数,根据不同请求方式来查找我们自己写的视图函数。还有一些python的第三方库也是用装饰器的模式,比如调试用的pysnooper。

多个叠加装饰器,加载顺序自下向上,执行顺序从上到下。

优点:

1、装饰器能在不改变调用方式的情况下增加新功能,方便了开发

2、是实现aop的一个方式

缺点:

多层装饰器的调试和维护有比较大的困难。

python-魔术方法-new和init

new和init这两个都是创建对象的魔术方法,new魔术方法触发在init之前,如果自己重写new魔术方法,一般需要返回一个对象,然后叫给init初始化,如果是返回其他类的对象,那么init不会触发,在django的drf模块里的序列化器中,有关于这两个魔术方法我比较深刻的影响,序列化器有many参数,默认情况是False,在他的源码里,BaseSerializer类的new魔术方法里,先把many给pop出来,如果有many参数的话,就走类的实例化,在这个实例化里,返回的就是list_serializer的对象,如果没有many参数,就是正常返回对象,然后在init里初始化。

python-魔术方法-xxxitem

__xxxitem__:使用 ['']的方式操作属性时被调用
    
__setitem__:每当属性被赋值的时候都会调用该方法,因此不能再该方法内赋值 self.name = value 会死循环
__getitem__:当访问不存在的属性时会调用该方法
__delitem__:当删除属性时调用该方法

python-aop

aop全称是面向切面编程,简单来说就是我们在编程的时候,实现当程序运行到某个阶段时,触发我们的方法,就像刀切进去一样。类似装饰器函数,想django中的中间件,form组件里的钩子函数这些都是aop编程的应用,还有比如全局异常捕获等等。在Python中,AOP通过装饰器模式实现更为简洁和方便。

python-GIL

GIL锁是cpython解释器特有的,加在python解释器上的一把互斥锁,每个python线程要运行,都需要获取这个锁,且在python进程中,GIL锁只有一个,所以在cpython中,同一时间只有一个线程在运行,这导致python不能利用多核优势,是大家诟病python慢的主要原因。所以为了解决这个问题,龟叔设计了多进程,在计算密集型任务时,开多进程利用多个cpu。

python-死锁

举个例子来说就是进程或线程1拿到了A锁,等B锁,进程或线程2拿到B锁等A锁,现在就会导致两者都在等。python设计了可重入锁,因为刚才出现的问题是当一个锁被释放之后立刻被人拿走,导致双方都被卡住,那么只要我们设置只有一把锁,且这把锁能被多次获取,在它完全被释放前,谁都不能再获取这把锁。

python-元类

在python里一切皆对象,包括类也是对象,类的类就叫元类,原来继承type。对于一个类来说,组成部分有三个,类名,基类,类体代码。python内置了class,来用创建类,其实就是把这三个部分取出来,然后运行类体代码,然后利用type函数,实例化出来一个类。我们其实也可以不通过class关键字自己实现一个类,就是利用exec和type这两个函数。不过一般来说我们没必要自找麻烦,如果要自定义元类的话,这个自定义元类必须要继承type这个类,在这个自定义元类里我们书写逻辑,控制类的生成,比如说让类的对象一生成时,属性都是私有,或者类必须有注释等等。当我们要使用的时候,在metaclass参数里写上我们自定义的元类即可。

网络编程

socket

socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用来实现 进程在网络中通信。

csrf攻击是什么,怎么预防

csrf攻击指的是用户在打开某个受信任网站登录后,未关闭浏览器情况下,打开了攻击者的网站,其返回的数据中,包含攻击代码,携带着该用户的数据访问了受信任网站。

预防方案可以是,我们网站的post请求都要带一个csrf的key,其对应一个value是随机字符串的隐藏标签,如果有这个标签才能提交。django框架的预防就是这种方案。

xss攻击,怎么处理

xss攻击是利用网页的漏洞,将一些攻击性代码放入网页中,当用户执行网页的时候,攻击性代码也随之运行,从而达到攻击效果。通常情况,这些恶意程序是js,java,VBScript等等。Django框架已经帮我们处理了xss攻击,django利用escape转义来处理。就是把代码转成实体,让他不具有代码的功能,比如

<div>是html的关键字,那两个箭头可以转成特殊符号&lt;和&gt;

arp协议

根据接收到的ip地址,查找对应的mac地址的协议,他是一个和网络层,数据链路层关联的协议。arp协议会通过广播,在自己的局域网内,获取到ip地址的mac地址。在linux下使用tcpdump抓包,可以看到arp协议广播只有两句:

21:36:56:844580 ARP,Request who-has 192.168.150.2 tell 192.168.150.11 length 28
21:36:56:844580 ARP,Reply 192.168.150.2 is-at 00:50:56:f7:53:2b length 46

tcp-三次握手四次挥手

三次握手:握手过程中使用了 TCP 的两个标志 :SYN和ACK

若在握手过程中某个阶段莫名中断, TCP 协议会再次以相同的顺序发送相同的数据包。

  • 第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
  • 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
  • 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,完成三次握手。

四次挥手:由于TCP连接是可靠安全的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。先进行关闭的一方将执行主动关闭,而另一方被动关闭。

  • 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
  • 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。
  • 服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
  • 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。

tcp协议

是位于传输层的,面向连接的(这里一定要聊三次握手四次挥手),可靠的传输协议。

tcp-为什么三次握手而不是两次

我认为,第三次握手时为了防止已失效的连接请求报文段有传送到B,因而产生错误。

所谓“防止已失效的连接请求报文”是这样产生的。考虑一种正常情况。A发出连接请求,但因连接请求报文丢失而未收到确认。于是A再重传一次请求连接。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。A共发送了两个连接请求报文段。其中第一个丢失,第二个到达了B。没有“已失效的请求连接报文段”。

现假定出现一种异常情况,即A发出的第一个请求连接报文段并没有丢失,而是在某些网络结点长时间滞留了,以至到连接释放以后的某个时间才到达B。本来这是一个已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次新的连接请求。于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了。

由于现在A并没有发出建立请求的连接,因此不会理睬B的确认,也不会向B发送数据,但B却以为新的运输连接已经建立了,并一直等待A发来的数据。B的许多资源就这样白白浪费了。

io模型

BI/O(阻塞IO)

在等待数据的时候,一直在等待,如果已经有数据,就等着从内核缓冲区复制到用户缓冲区,如果没数据,就等着cpu先去把数据获取到内核缓冲区,再等着数据从内核缓冲区复制到用户缓冲区。

NI/O(非阻塞IO)

在等待数据的时候,可以切到其他地方运行。即如果此时没数据,就管自己做事情,且每隔一定时间发送询问是否有了数据,也就是轮询。当多次询问后,数据已经到了内核缓冲区。那么就等着数据从内核缓冲区复制到用户缓冲区(此个过程就不能去做其他事情了)

Multiplexing - I/O(IO多路复用)

类似BIO,只不过找了一个代理,来挂起等待,并能同时监听多个请求。数据从内存缓冲区复制到应用缓冲区期间进程阻塞。

多路复用主要有三种模式

1.select---主要通过轮询的方式线性扫描非常慢,监听数量有限,而且并不是线程安全的,把一个

sock加入到select中后,如果另一个线程发现sock不用

2.pool--本质上和select没有区别将传入的数组拷贝到内核空间,然后查询每个fd(文件描述符)对应的状态,就绪态就在等待队列中加入一项继续遍历没有就绪态就再次遍历一下fd,重复多次无意义的遍历,poll还有一个特点是"水平触发" , 如果报告了fd后 , 没有被处理 , 那么下次poll时会再次报告该fd

3.epool--更加灵活支持水平触发和边缘触发,最大的特点在于边缘触发,只告诉进程哪些fd刚刚变为就绪态,只通知一次,还有一个特点是通过epoll注册fd,一旦该fd就绪,就会采取回调机制来激活fd,epoll_wait便受到了通知epoll的优点是没有连接限制,效率提升,不是轮询方式,只有活跃的fd才会调用callback函数,利用mmap()文件映射内存与内核空间的消息传递,减少复制开销并且是线程安全的

AI/O(异步IO)

发起请求立刻得到回复,不用挂起等待; 数据会由内核进程主动完成拷贝

同步异步、阻塞非阻塞

同步异步阻塞非阻塞都是在io操作时才有的概念

同步:
指代码调用io操作时,必须等待io操作完成才返回的调用方式

异步
异步是指代码调用io操作时,不必等待io操作完成就返回调用方式
我们的多线程,就是典型的异步调用方式

阻塞
指调用函数时候,当前线程被挂起,就是线程被暂停,cpu去执行其他线程

非阻塞
指调用函数时候,当前线程不会被挂起,而是立即返回

同步和异步是消息通讯的机制
阻塞和非阻塞是函数调用机制

Redis

redis-pipeline机制

pipeline是Redis的一个提高吞吐量的机制,适用于多key读写场景,比如同时读取多个key的value,或者更新多个key的value。因为redis本身是基于Request/Response协议的,在正常情况下,客户端发送一个命令,等待Redis返回结果,Redis接收到命令,处理后响应。如果进行多次的读和写数据到redis,每次都建立一个链接,这样是比较消耗资源的,而且也比较忙,于是想到了管道机制,只建立一个连接,然后批量执行读或写。

pipeline每次只作用在一个redis节点上,所以如果做了集群,也就没办法使用pipeline了,因为开了集群之后就不是一个节点,他就不知道该放到哪个上面了。
如果需要在集群上使用Redis Pipeline机制,需要注意一些细节。

在Redis集群中,数据会被分布在多个节点上。传统的Redis Pipeline机制只能作用于单个节点,无法跨节点执行命令。因此,在使用Redis集群时,如果将多个命令打包成一个Pipeline发送到不同的节点,是无法保证命令的执行顺序的。

为了解决这个问题,Redis提供了Cluster Pipeline机制。它可以在Redis集群中使用Pipeline,保证跨节点的命令执行顺序。Cluster Pipeline会根据命令所涉及的键(key)来将命令分配到正确的节点上执行,并按照发送的顺序返回结果。

需要注意的是,Redis Cluster Pipeline并不是将所有命令打包成一个批处理一次性发送,而是将每个命令发送到对应的节点上执行,并按照发送顺序返回结果。这样可以在保证命令执行顺序的同时,减少网络通信的开销。

所以,虽然传统的Redis Pipeline在集群中无法保证命令的执行顺序,但Redis Cluster Pipeline可以解决这个问题,保证命令的执行顺序,并提高集群中的性能。

redis-事务

redis可以用pipeline来实现事务,但是redis的事务和mysql的事务不一样,不保证数据安全。对于redis来说,单条命令是保证原子性的,但是整个事务是不保证的,且没有回滚,如果前面的语句失败,后面的照样执行。

multi 开启事务
exec  执行事务
discard  放弃事务

redis-乐观锁

redis没有悲观锁,只能实现乐观锁,因为加锁有可能会造成长时间的等待,所以Redis为了尽可能地减少客户端的等待时间,并不会在执行WATCH命令时对数据进行加锁。要实现乐观锁也很简单,在事务开始前,先watch要修改的key,如果在事务执行过程中,整个key被修改了,那么这个事务就会执行失败,实现了乐观锁。

redis-缓存更新策略

LRU -Least Recently Used,没有被使用时间最长的

LFU -Least Frequenty User,一定时间段内使用次数最少的

FIFO -First In First Out,先进先出

redis-你项目缓存怎么更新

就是我们使用redis的时候,缓存和数据库之间的数据一致性。

常见的更新策略:

  1. 先删缓存,再更新数据库
  2. 先更新数据库,再删缓存(目前常用)
  3. 先更新数据库,再更新缓存
  4. read/write through
  5. 写回。在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库

redis-持久化策略

redis因为是基于内存的,如果redis重启数据就没了,所以他配置了持久化策略。redis提供了两种方式,RDB和AOF,两中的开启方式一般是在配合文件中配置,也可以通过redis的命令。

RDB

RDB有三种触发方式,save,bgsave,还有配置文件自动化。

save:这个命令会阻塞当前的redis服务器,在RDB完成过程中,redis不能处理其他命令,这个方式不可取。

bgsave:是一个异步执行,redis会在后台异步进行快照,把所有数据完成一个备份,然后父进程fork一个子进程来保存这个文件,这期间只有fork子进程的时候会阻塞,时间基本很短。

配置文件:在配置文件配置好RDB的持久化规则,然后redis会按照配置文件执行。默认的我记得是900 1,300 10这样的。

RDB的优势:文件紧凑,是全部备份,且RDB的恢复大数据集的速度比AOF快

RDB缺点:如果系统在持久化的时候宕机,那么没来得及写入磁盘的数据回丢失

AOF

每写入一条命令,都记录一条日志,放到日志文件中,如果出现宕机,可以将数据完全恢复。aof有两种触发方式

配置文件自动化:配置文件有三种策略,

always每次数据修改都写入aof,是同步持久化,不会丢失数据,但是效率低

everysec异步操作,每秒同步一次,会丢失一秒数据

no不同步

AOF优点:数据比RDB安全,当日志文件过大的时候,会

AOF缺点:AOF文件体积比RDB大,根据选择的持久化策略,AOF的速度可能慢与RDB

redis-AOF重写

当aof文件过大的时候,我们可以通过AOF重写来优化持久化文件,本质就是把一些无用的,重复的命令优化一下。比如rpush list1 1,rpush list1 2,rpush list1 3,经过aof重写就可以变成有一句,rpush list1 1,2,3。

aof重写两种方式:

1、当我们在客户端使用bgrewriteaof命令时,服务端就会起一个子进程,完成aof重写。

2、在配置文件设置,有几个参数配置一下,我记得大概是文件增长率,还有大小等。

redis-规避缓存风险

正常情况下我们的业务请求进来时,先查询Redis,如果Redis中存在的话,直接返回Redis中结果;如果Redis中不存在的话,访问数据库。

在高并发的场景下,缓存会出现一些风险。比如缓存雪崩,缓存击穿,缓存穿透。

缓存雪崩:在某个时刻,缓存大面积失效,导致所有请求都打到数据库。

缓存击穿:在某个时刻,单个热点key过期,导致许多请求打到数据库查询。

缓存穿透:指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案:

雪崩:

1、缓存数据的过期时间随机设置

2、热点数据设置永不过期

3、如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。

击穿:

1、设置数据永不过期

2、基于redis实现互斥锁,第一个进来的线程拿着锁去数据库查,查出来之后缓存下来,后面的请求判断有缓存了就直接走缓存

穿透:

1、使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap(位图)中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

2、将该ip拉黑,这个方案一般是没用的,因为既然是恶意攻击,肯定可以换ip

3、对于不存在的数据,缓存到redis中,设置key,value值为null,并设置一个短期过期时间,避免时间过长影响正常用户。说白了就是将击透的key缓存起来,但是时间不能太长,下次进来是直接返回不存在,但是这种情况无法过滤掉动态的key,就是说每次请求进来都是不同的key,这样还是会造成这个问题

4、对参数进行校验,不法参数直接拦截

redis-主从复制

redis-哨兵

redis-分布式集群

redis-基础类型和应用场景

str:做缓存,计数器

list:做消息队列

hash:存用户数据,模拟关系型数据库

set:做共同好友,做用户标签

zset:排行榜,限流

redis-高级类型和应用场景

Geospatial:地理位置,可以做定位,做附近的人,打车

Hyperloglog:基数统计,访问量统计,去重

Bitmap:操作二进制来进行记录,打卡,活跃与不活跃用户,登录与未登录

redis-跳跃表

Redis使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员是比较长的字符串时, Redis就会使用跳跃表来作为有序集合健的底层实现。

redis-布隆过滤器

redis-主从同步原理

  1. 副本库通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库
  2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
  3. 副本库接收后会应用RDB快照
  4. 主库会陆续将中间产生的新的操作,保存并发送给副本库
  5. 到此,我们主复制集就正常工作了
  6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库.
  7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在.
  8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库
  9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的

MySQL

mysql-悲观锁

使用select...for update,就实现了。zhelyao注意,mysql的select...for update语句,会把所有扫描的行都锁上,所以在mysql中使用悲观锁,我们必须要确定走了索引,不然可能会全表扫描,锁住整个表。

mysql-乐观锁

在我们要修改前,先查询一个这个值和一个自己维护的版本号,记录下来之后,处理完数据,最后要修改的时候,在where中加入判断,只有值没变且版本号不变才修改。

mysql-索引

索引的分类有五种主键索引、唯一索引、普通索引、全文索引、组合索引

索引可以帮助我们加快查询的速度,减少了扫描的数据类,把随机io变成了顺序io。

对于mysql索引底层的数据结构,就大部分的存储引擎,比如Innodb,MyISAM,都是利用B+树,官方文档里写的是B树,但是实际上使用是B+树,它是B树的一种延伸.还有一种memory存储引擎他使用的数据结构是哈希表。

当然索引也有缺点,创建索引和维护索引要耗费时间,并且当对表中的数据进⾏增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执⾏效率。

mysql-为什么用b+树不用b树

我们希望查数据尽量的快,那么对于树来说,肯定深度要尽量低。所以我们采用有序多叉树而不是有序二叉树。

B树是在每个节点都存放所有数据,所以节点上存储的索引数变少了,而b+树只在叶子节点存储数据,同样一个数据页b+树可能存更多的索引,也就使得树的深度变低了

mysql-聚簇索引

叶子节点存放数据,就是聚簇索引,叶子节点存放主键的id,那么是非聚簇索引。也就意味着,聚簇索引将数据存储与索引放到了⼀块,找到索引也就找到了数据

在innodb中,由主键创建的索引是聚簇索引,其他索引都是非聚簇索引,在myisam中,都是非聚簇索引。

mysql-严格模式

简单来说就是MySQL自身对数据进行严格的校验(格式、长度、类型等),比如一个整型字段我们写入一个字符串类型的数据,在非严格模式下MySQL不会报错。

mysql-读写分离

主从复制、读写分离一般是一起使用的。目的很简单,就是为了提高数据库的并发性能。

原理:

①当Master节点进行insert、update、delete操作时,会按顺序写入到binlog中。

②salve从库连接master主库,Master有多少个slave就会创建多少个binlog dump线程。

③当Master节点的binlog发生变化时,binlog dump 线程会通知所有的salve节点,并将相应的binlog内容推送给slave节点。

④I/O线程接收到 binlog 内容后,将内容写入到本地的 relay-log。

⑤SQL线程读取I/O线程写入的relay-log,并且根据 relay-log 的内容对从数据库做对应的操作。

优点:

数据分布:随意开始或停⽌复制,并在不同地理位置分布数据备份

负载均衡:降低单个服务器的压⼒ ⾼可⽤和故障切换:

帮助应⽤程序避免单点失败

实现:

以一主二从为例子

1、首先创建两个用户,给从机用。找到主机的mysql配置文件,写入一些配置,然后重启mysql

2、找到从机的配置文件,写入配置

3、从机用刚才的用户账号密码登录主机,输入一些命令

4、重启从机服务,我们可以用show slave status \G命令查看是否配置成功

mysql-分库分表

当使用分库分表的时候,说明我们的数据库应该面临很高的并发访问了,且单表数据量到达了百万级。

分库的话,就是把库拆的更细一点。

分表有分为水平分表和垂直分表

水平分表: 解决单表记录太大问题,我们可以某个字段分,或者如果是日志类,统计类的表,按照日期分表。

垂直分表:解决列过多的问题,把常用查询的列放到一个表,其余的字段单独再放一个表。常用查询的表我们可以考虑用memory

我记得Apache旗下有个顶级项目,还是专门来分库分表的一个软件,叫ShardingSphere。

mysql-innodb和myisam区别

innodb直接表锁和行锁,myisam只支持表锁

innodb支持事务,myisam不支持

innodb支持聚簇索引

innodb支持外检,myisam不支持

mysql-存储引擎是什么

不同的数据文件在磁盘的不同组织形式,比如说innodb在文件上存储的是两个文件分别是frm,ibd,myisam在文件上存储的是frm,myi,myd

mysql-mvcc

mysql-读写分离数据一致性问题

mysql-主从搭建

简单搭建原理:

1、两个主机上都安装好MySQL服务

2、配置主机的MySQL配置文件、配置从机的MySQL配置文件 使得他们相关的配置文件信息能够在链接的时候对接上;

3、确保主机ip和从机ip在同一网段,即在局域网内;

4、在从机上执行链接信息命令,让从机主动连接主机,由于配置文件的信息校验通过,主机允许从机访问主机MySQL服务从而实现主从结构;

mysql-大数据量分页查询优化

在mysql中,使用limit分页,随着页码增大,效率变低,查询时间和起始记录的位置成正比。

优化1:利用表的索引覆盖加速分页。我们知道,利用索引查询的语句中如果只包含了索引列,那查询会很快。

select id from collect order by id limit 90000,10; 

mysql-redis作为缓存导致的双写一致性问题

看博客。

Django

django-框架模式

django采用的MTV的框架。

  • M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
  • T 代表模板 (Template):负责如何把页面展示给用户(html)。
  • V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。

除了上面的三层之外,还有一个url分发器。

django-请求生命周期

1、uWSGI服务器通过wsgi协议,将HttpRequest交给web框架 (Flask、Django)

2、首先到达request中间件,对请求对象进行校验或添加数据,例如:csrf、request.session,如果验证不通过直接跳转到response中间件

3、通过URL配置文件找到urls.py文件

4、根据浏览器发送的URL,通过视图中间件去匹配不同的视图函数或视图类,如果没有找到相对应的视图函数,就直接跳转到response中间件

5、在视图函数或视图类中进行业务逻辑处理,处理完返回到response中间件

6、模型类通过ORM获取数据库数据,并返回序列化json或渲染好的Template到response中间件

7、所有最后离开的响应都会到达response中间件,对响应的数据进行处理,返回HttpResponse给wsgi

8、wsgi经过uWSGI服务器,将响应的内容发送给浏览器。

django-中间件

中间件是一个处于uWSGI服务器和django视图之间的框架级的钩子函数,用来处理request和response。在全局上改变django的输入和输出,django内置了一些中间件,比如处理csrf攻击的,判断session的。

比较常用的中间件方法。

1 process_request(request对象) ,处理请求进来的时候,可以做限频,登录认证,访问日志等等

2 process_response(request对象,response对象) ,统一给出去的某些请求加上cookies或者响应头

3 process_view ,路由匹配成功且视图函数执行前,在这可以实现改变视图函数的触发时机,且可以在视图执行前后加代码,实现装饰器的功能

4 process_exception,全局异常捕获。

django-读写分离

django框架支持连接多个数据库,在配置文件里,我们可以配置多个数据库的连接。比如db1,db2,db3,分别连上三台机器的数据库。然后我们在使用的时候,可以手动读写分离或者自动。

如果是手动的话,就是在写orm的时候多加一个using,指定使用哪个库。

models.User.objects.using('default').create(name='张三', pwd='123', phone=1234)

如果是自动的话,在项目的app中创建db_router.py文件,并在该文件中定义一个数据库路由类名字随意,用来进行读写分离,这个类最多提供四个方法,分别是:db_for_read、db_for_write、allow_relation、allow_migrate。

class Router1:
		def db_for_read(self, model, **hints):
				return 'db1'

		def db_for_write(self, model, **hints):
				return 'db2'

然后在配置文件里配置上DATABASE_ROUTERS = [我们写的类的路径,]

django-路由分发

当我们的应用过多的时候,把所有的路径都写在一个文件里不方便管理,路由分发,可以让相同应用的请求,由一个专门的urls文件转发。

首先我们导入urls包下的include函数,然后在url把转发的app的urls文件作为参数传给include即可。

django-反向解析

说白了,就是通过路由的别名,拿到路由的地址。这样可以动态根据路由别名获得路径,一旦路径改变,不需要改其他代码。使用方法很简单,导入reverse,直接把路由别名作为参数传入即可。

django-RBAC

rbac就是做不同的角色的不同权限控制,这种控制基本在每个项目中都有作用。因为这了这样的控制之后,对于后续使用的时候,直接给某个用户加入这个角色,他就拥有了一些功能。

dajngo-反向生成数据类

格式:python manage.py inspectdb 数据库中表名)> 到哪个app下的models.py

python manage.py inspectdb home > ajk/models.py

django-F和Q查询

F查询:取出字段值,可以参与比较或运算

Q查询:创建与或非条件

django-only与defer查询

only是只查该字段 直接将结果封装到返回给你的对象中
点该字段 不需要再走数据库
但如果你点了不是括号内的字段 就会频繁的去走数据库查询

defer是查除了该字段的 所有字段 直接将结果封装到返回给你的对象中
点该其他字段 不需要再走数据库
但如果你点了不是括号内的字段 就会频繁的去走数据库查询

django-反向查询

在我们创建表字段的时候,指定related_name取个别名,另外要指定这个字段要关联哪个表。

class level(models.Model):
 l_name = models.CharField(max_length=50,verbose_name="等级名称")
 def __str__(self):
  return self.l_name
  
class userinfo(models.Model):
 u_name = models.CharField(max_length=50,verbose_name="用户名称")
 u_level = models.ForeignKey(level,related_name="lev")

正向查询
userinfo.object.get(pk=1).u_level
反向查询
level.objects.get(pk=1).lev.all()

django-orm

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

DRF

drf-序列化器

我们现在的数据交互一般都是用json格式,所以drf帮助我们做了一部分工作,可以帮助我们转换json格式,并且能够帮助我们检验一些字段,一般我们使用drf,都是序列化器加视图一起使用,当视图配置好了之后,我们的大部分逻辑会写在序列化器里面。序列化器和forms组件的使用差不多,写一个序列化类,然后在里面定义检验字段,然后也有局部钩子,全局钩子。

这里面有一些高级用法,比如source,可以修改返回前端的字段名,并且如果我还有自己的字段检验规则,可以配置source里,他会加括号执行,还有就是我们可以利用souce跨表操作。大致实现思路是,先按照点切割,然后看切割出来的字符串是不是可调用(即有没有call魔术方法),如果不可调用,直接去表模型里把字段反射出来,如果可调用,那就加括号执行,如果是多个字符串,比如publish.author.name,那么就for循环一层一层的重复上述过程

drf-jwt

jwt的本质是token,token是服务端生成的一串字符串,在用户第一次登陆后生成,后续用户的请求只要携带token就行了,不用带用户名和密码,减轻服务器的查询压力。

jwt有三部分组成,header(头部),payload(荷载),signature(签证),前两部分base64编码,是可以反解的,最后一部分是由前两步base64编码后,再加密组成,通常用SHA256,不可反解。

头部里面,存放两部分信息,声明类型和加密算法。

荷载里存在一些有效信息,一些公共声明和私有声明,都是一些键值对,因为是可以反解的,所以一般不放什么敏感信息。

第三部分签证,就是把前两部分base64编码后,再加密,在这个过程中,可以加一些盐,组合加密,更安全一点。

drf使用jwt还需要另外安装一个包。

drf-视图组件

视图组件一般和序列化器一起使用,说白了就是原生的django的视图函数,都是竭诚的django的view,drf继承了这个view之后,还派生了许多自己的方法。让我们开发更快。首先是基础的两个视图类,APIView和GenericAPIView,一般,如果我们的视图和数据库无关的话,使用APIView。

APIView是继承了原生Django的View,需要我们自己写对应请求方法的代码。具体使用和原生django的view使用基本相同。

GenericAPIView继承了APIView,考虑到使用APIView时,当我们写多个类,变化的代码只有调用的myserializers类和自己的表模型,所以将变量提取了出来。就是那些model表和序列化器,现在直接在类里定义

queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer

后续使用的话,就是直接调用方法来使用

在两个视图基类后面,有五个扩展类,对应的是常用的五个方法,还有九个子类,就是这五个扩展类的组合。最后还有视图集,我们常用的ViewSetMixin,他重写了as_view(),这里我们现在应该传一个字典,key和value是请求方法,对应的视图函数。并且我们就可以使用router自动生成路由。ViewSet,继承了ViewSetMixin和APIView,GenericViewSet继承了ViewSetMixin和GenericAPIView

drf-xadmin

是一个后台管理的模板框架。django自己有内置一个后台管理,是admin,不过样式和功能偏少。xadmin安装很简单,pip安装之后,配置文件的app里注册一下,然后路由里写上路径,之后在admin文件里注册一下,就可以使用。

drf-自动生成接口文档

使用coreapi自动生成接口文档,pip安装后我们管自己书写接口,然后项目运行之后就可以看到自动生成的文档。

数据结构

项目

工业互联网那个项目,推荐系统,用redis来做的,给每个用户,商品添加上标签,然后根据这个用户的购买记录,来给他推差不多同标签的商品或者供应商

我们那个微应用平台订单成功之后会给用户绑定的邮箱发一个订单的邮件,那个是用多线程发的。

项目中遇到的问题

celery,work开多了会内存溢出

有什么要问我们的吗

咋们数据库设计字段有专门的命名规范吗

为了胜任这份工作,请问我还需要提升哪些部分的技术

团队大概有多少人

目前团队的核心工作是什么

posted @ 2023-08-24 10:50  王寄鱼  阅读(32)  评论(0编辑  收藏  举报