模糊:^(\d{1, 3}.){3}{\d}{1, 3}$
精确:^(( 25[0-5] | 24[0-9] | [01]?[0-9] [0-9]? ) .) {3}( 25[0-5] | 24[0-9] | [01]?[0-9] [0-9]? )$
画图(一定要自己画图才能理解!!!);关键词:全双工,握手/挥手建立通信都需要双方确认对方收到自己发送的报文;两次不足以建立双端通信,三次足够,中间一次握手同时包含 syn 和 ack 因此不需要四次;但是 挥手的时候必须四次,因此 fin 和 ack 一般不能同时发送,ack是立即发送的,而fin需要等服务端当前报文发送完毕才能发送,因此挥手是四次。
1.导入 selenium(web自动化工具)包 的 webdriver 模块(from … import …)
2.将chrome 的启动文件作为webdriver参数,使用webdiiver模拟chrome
进程:资源分配最小单位; 多进程 切换和进程通信消耗大。
线程:系统调度的最小单位;线程之间的切换系统调度,会有损耗;(基于cpython解释器)python的多线程为伪多线程,
一旦处理任何一个计算密集型任务,都会导致性能极低。
协程:用户态的轻量级线程,协程切换的控制权在用户手中;使用多进程+协程发挥多核CPU的性能优势
概念:多个网络IO复用1路或者多路线程来处理TCP连接
1984 select: 1.1024连接上限 2.使用轮询的方式 3.会修改传入的参数 4.非线程安全;
1997 poll:修改了 1024上限;不会修改传入的参数;仍然采用 轮询方式 并且 非线程安全;
2002 epoll:线程安全,并且 改用事件触发的方式,节省了系统资源;
TCP:面向连接,安全,数据不丢失;基于字节流的传输,消息无边界;传输速率较慢(类比于打电话,发电报)
UDP:非连接,不安全,数据可能丢失;基于消息传输,有边界;传输速率较快;(类比于直播)
(1)
get: 用来发起请求,获取数据;幂等性(无论操作多少次结果都一样),安全;
post: 提交数据(表单形式),一般是没有的,重新创建
put: 更新数据;幂等性;
delete:删除操作;幂等性;
(2)
get 和 post 具体区别:
get post
url参数可见性: 可见 不可见
数据传输: 拼接url进行传递参数 通过body传输参数
缓存性: 可缓存 不能缓存
传输数据大小: 一般2-4K 根据配置而定,理论上无限大
安全性: 暴露url参数 ,原则上不安全 安全
单例模式
(1)
应用层 访问网络服务的接口 (http,ftp,telnet,snmp,dns)
表示层 数据格式转换服务
会话层 建立端连接,提供访问验证,会话管理(session)
传输层 提供应用进程之间的逻辑通信 (tcp,udp,socket)
网络层 数据在结点之间传输创建逻辑链路,并分组转发数据 (ip,32位。路由器,交换机)
链路层 通信的实体间建立数据链路连接 (mac,48位,arp)
物理层 为数据端设备提供原始比特流的传输的通路 (传输介质,如 网线,RJ45)
(2)
ARP协议是地址解析协议,工作在数据链路层,根据IP地址来获取物理地址的一个协议。
(1)http是一种传输协议,全名是超文本传输协议;用于从万维网传输超文本到本地浏览器的协议。
https相当于http的安全版,加入了安全加密传输协议ssl,相比http他更安全;两者连接方式完全不一样,用的端口也不一样,http是80,https是443;https需要用到ca申请证书,一般免费证书较少,需要一定费用;并且每次消息的加密十分耗时,消耗系统资源。
(2) 对称性加密:服务器和客户端使用同一个秘钥,即加密和解密都使用一个秘钥;
优:算法公开,计算量小;加密速度快,加密效率高;
缺点:使用前需要双方协商好秘钥,并且保存好不能泄露;每对用户要使用其他用户不知道的秘钥。会使得秘钥管理成为负担。
非对称性解密:加密和解密使用一对秘钥,公钥和秘钥,互为加锁和解锁。公钥能够公开(给对方),秘钥自己保管,不能外泄。(服务端和客户端都有自己的公钥和秘钥)。客户端在发送消息前,先用服务器的公钥进行加密,服务器收到后再用自己的私钥进行解密。
优:安全 缺点:慢
原理:https使用非对称加密进行证书验证,使用对称加密进行数据传输。
详解:1.证书验证阶段: 浏览器发起 https 请求;服务端返回 https 证书;客户端验证证书是否合法,如果不合法则报警。 2.数据传输阶段:证书合法后,客户端本地生成随机数;通过(服务端)公钥加密随机数,并把加密后的随机数传输到服务端;服务端通过私钥对随机数进行解密获得客户端传入的随机数;服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输,客户端根据本地随机数进行解密。
数据传输使用对称加密的目的:非对称加密效率低;大量数据的传送使用非对称加密效率无法接受;另外非对称加密,一对公钥,私钥用于加密,解密,是单向的,而数据传输是双向,这也是为什么效率低的原因。
使用ca证书的目的:需要一个认证机构,防止伪造,防止任何人都可以制造证书而造成中间人攻击。(相当于一个资格认证)。
如果有人伪造证书呢:即使伪造证书,因为非对称加密存在,无法通过公钥生成私钥,所以伪造人无法拿到客户端生成的随机数。
ca包含:颁发机构信息,公钥,公司相关信息,域名,有效期,指纹等;
ssl(secure socket layer 安全套接层):融合 对称加密,非对称加密,数字证书来达到性能与安全与最大化的整合技术。
略
(1) 状态码格式
1xx:临时响应 2xx:成功 3xx:重定向(需要进一步操作) 4xx:请求错误 5xx:服务器错误
(2)常用http状态码
200 OK 服务器成功返回网页
301 永久跳转 请求的网页跳转到新的位置
302 临时移动 服务端临时从不同位置响应,但是请求者应继续使用原有位置进行请求
400 服务器不理解的请求语法(字段不合法之类的)
401 未授权 请求要求身份验证
403 服务器拒绝请求
404 服务器找不到请求的页面
500 内部服务器错误
502 坏的网关(后端没有按照http协议正确返回)
503 服务不可用 (可能是超载或者停机维护)
504 网关超时(后端没有在特定时间内完服务)
(1)TCP是一种面向连接的,可靠的,基于字节流的传输层协议;基于不可靠的网路实现可靠的传输。
TCP丢包可能的原因:
1.程序发送过程或者接受过程出现问题。
2.多线程同步问题
3.缓冲区溢出
TCP丢包解决办法:数据分片(接收到重组),到达确认,超时重发,数据校验,失序处理,重复处理
(1)ARP:地址解析协议 链路层 根据ip地址获取物理地址
(2)免费ARP:
免费ARP是一个Sender IP和Target IP字段相同的广播请求报文,相当于请求自己IP地址的mac地址,大部分时候发送者不希望收到ARP回复。
作用:1.验证IP是否冲突 2.双击热备 3.网关定时刷新
(1)请求报文:请求行,请求头部,空行,请求数据
响应报文:响应行,响应头,空行,响应体
请求报文头:Accept (客户端
告诉服务器接受的响应类型);cookie;Refer(请求的URL来源);cache_control 缓存控制;
响应报文头:Cache-Control 缓存控制;Etag 代表响应的服务端资源版本;Location 重定向作用;
(2)略
略
1.DNS解析,由域名获得真实IP地址;
2.客户端向IP指向的服务器发起TCP三次握手,建立同步;
3.客户端发送http请求,请求数据包
4.服务端根据请求进行响应,返回数据
5.客户端收到HTTP响应
6.客户端读取页面内容,浏览器渲染,解析html原码,css样式,js交互
1.确认和重传机制
建立连接时三次握手同步双方的“序列号+确认号+窗口大小信息”,是确认重传,流控的基础。传输过程中,如果checksum校验失败,丢包或者延时,发送端重传
2 流量控制(滑动窗口)
窗口和计时器的使用。TCP窗口中会指明双方能够发送的最大数据量。
3 拥塞控制
拥塞控制相对于流量控制来说考虑的是整个网络的控制。
拥塞控制有四个核心算法组成:慢启动,拥塞避免,快速重传,快速恢复。
拥塞控制相对于流量控制来说考虑的是整个网络的控制。
拥塞控制有四个核心算法组成:慢启动,拥塞避免,快速重传,快速恢复
(已建立TCP三次握手连接情况下) 客户端:http请求,ajax轮询 服务端:http响应
备注:多个HTTP请求并不代表有多个TCP连接,当然这个场景肯定会有多个TCP连接
http2.0 可以通过多路复用计数,允许通过单一的http请求连接发起多重请求-响应消息,即同一次传输中发送多个css,js,图片等资源
1.accept():从处于established 状态的队列中取出完成的连接,当队列中没有完成连接时候,会形成阻塞,直到取出队列中已完成连接的用户连接为止。(Accept默认阻塞进程,直到有一个客户建立连接为止。)。established阶段。
2.客户端调用connect来发送syn报文。默认阻塞进程,直到连接成功。同步发送阶段。
3.服务器调用listen进行监听。非阻塞函数。建立三次握手之前。closed阶段。
不能;
如果服务器还没发送FIN就关闭;会导致导致此时响应给客户端的报文不完整;
如果还没收到客户端对服务端关闭报文的响应就关闭:客户端没有办法确认服务端是否关闭,造成非正常关闭。
原因:服务器处理高并发短连接,严重影响服务器的处理能力,甚至耗尽可用的socket。(占用大量端口,短连接本身时间很短)
解决:调整参数,缩短Time_wait的时间。
1次socket连接成功之后,无论是否使用socket连接,不断开socket连接(进行多次HTTP事务)。
域名解析:DNS协议(应用层)
TCP三次握手:TCP协议
建立TCP连接时需要发送数据:IP协议
OSPF:IP数据包在路由器之间,路由选择使用OSPF协议
ARP:路由器在于服务器通信时,需要将IP地址转换为MAC地址,需要使用ARP协议
HTTP:TCP建立连接完成后,使用HTTP协议访问网页
略
(1)核心区别: 编码方式,字符串类型,类的区别,缩进,import方式(2相对,3绝对)
(2)废弃类区别:
raw_input函数弃用,统一使用input函数;
print语句弃用,统一使用print函数;
xrange弃用,统一使用range(同python2中的xrange);(保留生成器功能)
exec,execfile语句被弃用,使用exec函数;(将字符串转化为执行代码)
long整数类型被废弃,统一使用Int
file函数被废弃,统一使用open来处理文件
字典has_key函数被废弃,统一使用in关键字
keys(),values(),items();zip(),map(),filter(),不在返回list对象,而是iterable对象,但可以通过list方法转化为list
(3)修改类区别:
/ 修改: 2中有浮点数参与结果为浮点数,全整为整数;3中根据实际结果而定类型。
for循环: 2会改变同名外部相同名称变量的值;3不会;
round函数; 2返回float类型,而3返回int类型。
比较操作符:2不同类型对象可以比较(ASCII码的比较),3只有统一数据类型可以比较。
def trans_int(strvar)
intvar = 0
for i in strvar:
temp1 = len(strvar) - strvar.index(i) - 1
temp2 = int(i) * pow(10, temp1)
intvar += temp2
return intvar
引用计数,分代回收;
解决循环引用:手动回收,弱引用;
import time
def wraper(func):
t1 = time.time()
func()
t2 = time.time()
print(“耗时:{:.8f}s”).format(t2- t1))
@wraper
def func():
pass
1 + : 适用于拼接的字符串较小,数量较少 空间复杂度O(n);如果数据量很大,效率较低;
2 .join(): 缺点:只适用于拼接列表对象; 优点:数据量很大时效率较高,只申请一次内存,节省空间;
3 格式化拼接 % : 不适合数据量较大,可读性一般;
4 格式化拼接 .format: 可用于代替% 功能更强大(设置下标,控制填补),可读性较强;格式要求高:{} 与 字符串数量一致;(python3.6之后的)
5 空格号: 可读性较差,不适于数据量较大;
6 *操作符: 只能用于同一字符串的多次拼接,原理同+,不适合于数据量较大;
7 f-strings: 速度很快;仅限于 python3.6 版本以上;
class father():
__name = 'haha'
class son(father):
__name = 'miemie'
查:len() count() index() startswith() endswith() isupper() islower() isalpha() isdigit()
改:centre() strip() replace()
拼接: +;*;f-strings;%;{} .format;.join(); ’ ’ , ;
转化:split()
略
sort() 普通内置函数,对列表排序,直接在原列表进行修改;
sorted() python中的高级函数;sorted(iterable, reverse=True, func) 返回排序后的结果;排序对象为可迭代对象,并可按照函数进行排序,生成新的列表。
略
略
键值对都是存储在哈希表中,键,值通过哈希算法存储在内存中,字典又称为哈希数组
(1)手动回收: gc.collect
(2)采用弱引用
替代还没确定好的逻辑代码,防止程序报错;
items() keys() values()
文件操作(即使语句异常,也能正常关闭,解决 try except finally)
用于简化资源操作的后续清除操作,是 try/finally 的替代方法,原理建立在上下文管理器之上。此外,python还提供了一个 contextmanager 装饰器。进一步简化了管理器的实现方式。
使用 global 声明该变量。
集合:可变数据类型,默认无序(也有有序集合),去重性,不可获取
列表:可变数据类型,有序,可获取
元组:不可变数据类型,有序,可获取
转换为集合,再转换过来,或者先排序在遍历去重
略
单下划线:表面私有,类外部可以访问,但是不建议访问,只是不能在其他模块中被导入;(保护变量)
双下划线:真正的私有,类外部无法访问。(私有变量)
(双下划线,实际名称为 _类.__属性 可以通过真实名字访问)
(私有属性和方法,子类能继承但无法覆盖,因为已经无法改名 _父类.__属性/方法)
python里面特殊方法专用的标识。比如类的魔术方法。
类是一类特征的抽象概念;对象是类的实例化。
无论实例化多少次,都只有一个对象存在。
# 手写代码
class singleton(object):
__instance = None
def __new__(cls):
if not cls.__instance:
return object.__new__(cls)
return __instance
程序设计中最常用的设计模式之一。这种类型的设计模式属于创建型模式。该模式在创建对象时不会对客户端暴露创建逻辑,所谓创建逻辑是指我必须要知道创建函数的构造函数的逻辑组成,才能创建对象。通俗点,工厂模式就是提供一个工厂类去创建对象,我只需要告诉这个工厂我需要什么,他们就会返回给我一个相对应的对象。专门创建类型的实例的工厂(类)。
class 类名():
pass
类名使用驼峰命名法。
类的成员变量归、类所有,能被类和所有实例化对象访问,声明周期跟类一致;
成员变量归各自对象所有,只能被各自对象调用,声明周期跟绑定的对象一致;
@ 将下面的函数作为参数传入上面的函数,使下面的函数具有上面函数赋予的功能。即包装的作用: 例如: 装饰器 类方法修饰器,静态方法修饰器,特殊属性修饰器
类,对象
with open(“1.txt”, r) as fp
listvar = fp.readlines()
for i in listvar:
print(i)
read(n):读取指定字节内容;无参数则读取全部
readlines:将文件按行读入列表
readline:每次读取一行,返回字符串对象
pass
数据量较大时,造成内存空间的浪费;使用 f-strings 代替,或者 格式化,.join()
python是一门解释型的语言。python代码经历两个阶段:.pyc是 编译的python文件,实际上是一个字节码,然后使用解释器解释此 .pyc文件。
这是python一种节省运行时间的操作,一种缓存操作,python会记录 .pyc 的时间戳来自动使其无效或者重新加载。
迭代器: 成员方法含有 (iter, next)
可迭代对象: 成员方法含有 (iter)
生成器是一种特殊的能被用户定义的迭代器。
定义:使用括号包裹的推导式;使用yiled语句的函数。
作用:自定义的可迭代对象,节省内存空间。特点:变循环边计算。生成器保存的是算法。
场景: 比如 range();需要遍历较大的数据时,可以选择生成器。
略。
先设计一个节点类:对象含两个成员遍历: 数据域,指针。默认指针为空。
在设计一个链表类:
初始化:传入节点则头节点接收,没传入则头结点默认为空。
判断为空:判断头结点是不是为空。
链表长度:设置一个cur游标遍历指向后面的节点来获取链表长度。
遍历链表节点:通过cur游标指针遍历结点。
头部插入:将新结点下一结点设置为头结点。
尾部插入:cur游标找到最后一个结点在后面插入。
指定位置插入:通过游标计数,找到指定位置。
查找结点:游标遍历。
删除结点:游标遍历。
select() 方法直接调用操作系统的IO接口。对应 select。
selectors 模块,对应epoll。
相当于是c语言中的long类型的数值的扩展。
python使用了小数据池缓存了[-5, 257]之间的整数,该范围内的整数在Python中是共享的。
对于超出这个范围的整数python也分配了一块内存空间叫做 PyIntBlock,减少 molloc 分配内存带来的损耗。这个内存块通过一个单链表组织在一起。PyIntObject会把销毁的对象内存用给下一个创建的整数。整数对象回收并不会归还系统。该空间相比于小数据池整数不是共享的。
上下文管理器:就是规定对象的使用范围,如果超出范围就采取处理。
常见上下文管理器: with操作符。
上下文管理器原理:含有 enter() 方法,exit()方法的对象就是上下文管理器。
实现:基于类的上下文管理器,基于生成器的上下文管理器;
对比:功能一致,基于类的上下文管理器更加灵活,适用于大型系统的开发;基于生成器的上下文管理器更加方便,简洁,使用中小型程序。
右加方法;
python在执行加法a + b的过程中,首先是查找a是否有左加法方法__add__(self, other),如果有就直接调用,如果没有,就查找b是否有右加法__radd__(self, other),如果有就调用此方法,如果没有就引发类型异常。
type;type是所有实例关系的顶端;object是父子继承的顶端;object也是type的一个实例。
通过c3算法,生成mro列表,根据列表中元素顺序查询调用父类;
新式类为广度优先;旧式类为深度优先。
python中一切皆对象。类也是一种对象。而元类就是类的类。
python中使用class创建类;当你使用class关键字的时候,python解释器自动创建这个对象,底层就是使用的type()函数(type函数也可以查看实例所属类型)来创建类的。我们可以直接使用type()函数来手动实现动态创建类。
type()就是python背后创建所有类的元类。
要有继承,要有函数重写,父类指针指向子类对象。
pass
处理IO密集型任务,相比多线程效率更高。多进程的进程之间的通信以及进程切换的高消耗带来效率的降低。
time_sort: 结合 merge_sort 和 select_sort
最坏时间复杂度: nlogN 空间复杂度 n
pass
(1)锁机制:主要有 Lock 和 Rlock 模块;acquire/release 都是对应的,并且数量需要一致。
Rlock 相比可以解决多次 acqiure 造成死锁的问题
(2) event 事件。通过 is_set 来判断是否阻塞。默认为false,添加阻塞。
e.wait 动态加阻塞;e.set e.clear 改变属性值。
(3) semaphore 用法同lock,但是可以允许多把锁。acqiure 计数-1,release 计数+1
(4)condition 条件变量;设定条件,满足则通知释放锁。
管道;消息队列;共享内存;信号量(semaphore);socket
(1)堆:一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。存储数据由程序员分配。
(2)栈:由操作系统自动分配释放,存放函数的参数值,局部变量等。操作方式和数据结构中的栈相类似。 函数之间相互调用需要传递参数,就是将参数放到栈里面通过压栈和出栈的操作来完成的。
子程序(函数)的调用是通过栈实现的。
操作系统栈区;操作系统堆区。
注意分操作系统和数据结构来却比。
os.fork() 用于进程创建子进程。这个方法在主进程返回值是子进程的pid,在子进程返回的是0。
os.getpid() 获取当前进程的pid;os.getppid() 获取当前进程父进程的pid。
关于子进程和父进程:
1.子进程相当于在当前主进程之外申请了一块额外内存,把主进程所有代码和资源复制一份自己来用。主进程和子进程不共享全局变量。
2.子进程死掉后,内存等资源都由父进程进行管理回收和释放。父进程使用os.wait()可以进行资源回收。
3.os.fork() 连续执行的话,会产生 2^n 个进程,子进程也会fork出子进程
可以谈谈 cow 技术。
(1)创建 多线程主要有两种方式:
threading.Thread 函数 (参数1:执行函数 参数2:需要传递的参数) ;
继承 threading 类
(2) 节省线程需要创建和销毁的成本,方便安排指定数量的线程数。
concurrent.futures模块提供 ThreadPoolExecutor 和 ProcessPoolExcutor 类。
submit 函数提交线程需要执行的任务。submit不是阻塞的,而是立即执行。
cancel() 方法可以取消提交的任务。
result() 方法可以获取任务的返回值。
python多线程处理IO适合,一个任务获得GIL发送消息,然后等待返回消息(阻塞),此时释放GIL,其他线程获得GIL发送消息,然后同样等待返回消息(阻塞)。这样保证了IO传输过程的合理利用,提高IO传输效率。
python对协程的支持是通过生成器来说实现的。
生成器中,可以使用for 循环迭代,还可以不断调用next()函数获取yield语句返回的下一个值。同时yield还可以接收调用者发出的参数。
举个例子:
# 生产者与消费者模型
def consumer():
r = ''
while True:
n = yiled r
if not n: # 控制consumer开启和关闭
return
print('[c] consuming %s' % n)
r = '200 ok'
def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[p] producing %s' % n)
r = c.send(n)
print('[p] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
传统生产-消费这模型都是通过一个线程写,一个线程取,通过锁机制控制队列和等待,但一不小心就看死锁。
可使用 produce 和 consumer 通过 生成器的方式协作完成任务,所以该方式可以称为协程。全程无锁。执行过程受用户控制。
(1) 重复消费根本原因:已经消费了数据,但是offset没有提交。
(2) consumer group 下可以有一个或多个consumer 实例。
在一个kafka集群中,Group ID标识唯一的一个 Consumer Group;
cp下所有实例定于的主题的单个分区,只能分配给组内的某个consumer实例消费。
不会
一个搭建云平台的解决方案。可以搭建公有云,私有云,企业云。
7个核心组件:Compute(计算), Object Storage(对象存储),Identity(身份认证),Dashboard(仪表盘), Block Storage(块存储), Network(网络) 和 Image Service(镜像服务) 。
略
使用 alter table 为mysql添加索引:
主键索引:alter table ‘table_name’ add primary key (‘column’)
唯一索引:alter table ‘table_name’ add unique (‘column’)
普通索引: alter table ‘table_name’ add index index_name(‘column’)
多列索引: alter table ‘table_name’ add index index_name(‘c1’, ‘c2’, ‘c3’)
全文索引:alter table ‘table_name’ add fulltext (‘column’)
略
conn = pymysql.connect(host= , user= , password= , daatbase= ) #创建连接对象
cursor = conn.cursor() #创建游标对象
inner join 有效的连接;跟据on条件将两张表的数据都显示出来
left join 左全选,后看on;没有就补null
right join 右全选,后看on;没有就补null
(1)读锁:也叫共享锁。使用: select * from table_name where … lock in share mode
详解:事务A使用共享锁获取某条记录,事务B可以使用共享锁继续读取这些记录,但是事务B对这些数据修改或删除时会进入阻塞状态,直到锁等待超时或者事务A提交。
应用:读取结果集的最新版本,同时防止其他事务更新该结果集。
注意情况:如果两个事务都拿到了读锁并且都有update操作,则两个事务互相等待造成死锁。
(2)写锁:排他锁。使用:select * from table_name where … for update
详解:一个写锁会阻塞其他的读锁和写锁;事务A对某些记录添加写锁,事务B无法对这些记录添加写锁或者读锁(不添加锁的读取是可以的),事务B也无法对锁住的数据 update delete
应用:读取结果集的最新版本,同时防止其他事务产生读取或者更新该结果集。
例如:并发下对商品库存的操作。
总结:以上都是行级锁。事务1对商品A获取写锁,事务2对商品B获取写锁是互相不阻塞的。SQL全表扫描的时候,行级锁会变成表锁。
(3)乐观锁:逻辑锁。通过数据的版本机制实现,极大降低了数据库的性能开销。
要进行更新时,先将版本号拿出,更新后对比版本号,如果大于数据库版本,则更新,否则认为是过期数据。
索引:索引对于数据的存在就是相当于目录对于书籍的存在,提升数据检索的性能。
索引建立在表的列上;在where 后面的列建立索引才会加快查询速度。
略。
事务:维护sql语句完整的一种机制。要么全部执行,要么全部不执行。
隔离等级:RU RC RR(默认级别) SE
1.避免全表扫描,首先应考虑在where和order by涉及到的列建立索引。
2.where 语句:
a.通配符不要放后面
b.where 字句使用 or 连接条件,否则mysql将放弃索引来进行全表查询。
c.放弃where字句中使用字段表达式,否则mysql将放弃索引来进行扫描。
d.谨慎使用 in 和 not in,可能造成全盘扫描。
e.放弃对where字句中对字段进行函数化操作。
f.禁止在where语句中 = 左边进行函数,算术运算或其他表达式运算,容易导致系统无法使用索引。
3.使用 索引字段作为条件,联合索引,必须用到该索引的第一个字段作为条件。
4.索引不是越多越好,索引一方面提高了 select的效率,但是过多会降低 update 和 insert 的效率。一个表的索引最好不要超过6个。
5.尽量使用数字型字段,除非该字段必须设计成字符串字段。
6.字符串尽量使用 char 代替 varchar
7.使用join代替子查询。
8.定长字段放前面,变长字段放后面(尽可能小的改变树状结构高度)。
9.尽量使用组合索引代替单个索引。
10 重复的,字段少的字段值不适合做索引。如性别。
1.索引优化规则:
联合索引最左前缀规则:从最左边列开始,不跳过索引中的列并且不能使用范围查询;
模糊查询不能利用%在索引前面;
不要过多创建索引;
索引长度尽量短,节省索引空间;
索引更新不能频繁;
索引列不能参与计算,会导致索引失效;
2.查询优化规则:
小表驱动大表(建议使用 left join 小串大 ;join 的第一张表必须全扫描的,以少关联多就可以减少这个扫描次数。)
避免全表扫描(!= < >)的时候无法使用索引而导致全盘扫描。
使用覆盖索引,尤其是组合索引,mysql将会直接在索引上取值,并且返回值不包含不是索引的字段。
少用select *
order by 排序应该遵循最佳左前缀查询,如果是使用多个索引字段进行排序,那么排序的规则必须相同(同时升序,降序),否则索引同样会是失效。
其他优化:
开启慢查询:(查询一下)
开启慢查询,可以让MySQL记录下查询超过指定时间的语句,通过分析能的瓶颈,更好的优化数据库系统的性能。
实时获取有性能的SQL:实时查看执行时间过长的线程,定时需要优化的SQL。
垂直分割:把一种数据库中的表,切换变成几张表的方法。
拆分时间长的DELETE或INSERT语句。
undo log: 为了实现事务原子性,要么全部完成commit, 要么全部回滚rollback,Innodb用于实现MVCC(多版本并发控制)。例如:将user = ‘A’ 改成 user = ‘B’, 则 undo log中会记录下 user = ‘A’ 和事务版本信息。一旦事务完成,所有修改必须被记录下,保证数据一致性。
redo log: 如果使用 undo log 作为持久化数据,意味着修改数据和undo log必须同时写入磁盘持久化,这必定带来巨大的磁盘IO,解决方案为了平衡io和一致性,引入 redo log。数据和undo log可定时从缓冲刷至磁盘。但是 redo log必须实时写入磁盘,当系统崩溃时,可依据 redo log来进行数据重做。
binlog: redo log可以实现数据重做,那么为什么要使用 binlog 呢? 因为 redo log是Innodb实现的物理日志,一旦涉及到多种存储引擎,无法进行重做。binlog 记录下所有数据的或更改,可用于本机数据恢复和主从同步。刷入磁盘的方式:每个 1s 刷入磁盘 | 每次事务提交撒刷入磁盘 | 同时使用
relaylog:中继log。mysql 主从同步当中用于实现主从同步。讲一下主从同步:
1.主库产生数据写入,更新;2. binlog 会记录所有数据更改(二进制文件) 3.从库会有一个IO线程一直开启,将 binlog 读出 并且写入到 从库relaylog上。 4. 从库sql线程将 delay log 记录信息转化为 sql语句 对从库数据进行更新操作。实现主从同步。
(1)应用场景:订单超过30分钟未支付,则自动取消。订单超过30分钟未接单,则自动取消。
(2)解决:轻量级可以实现轮询去实现。但是数据量过大时,高频轮询会消耗大量资源。此时用延迟队列来应对这类场景比较好。
(3)需求:1.消息存储 2.过期延时消息实时获取 3.高可用性
(4)redis延迟队列特点:1.消息持久化,消息至少被消费一次 2.实时性:存在一定的时间误差
3.支持指定消息 remove 4.高可用 5.redis的特殊数据结构 zset 满足延迟的特性。
(5)实现方法:
原理:
1.使用zset,为每个成员绑定一个分数score(集合的成员是唯一的,但是分数却可以重复);(zadd key value1 score1 value2 score2 );消费消息通过按分数排序从0位置开始每次消费一条(zrangebyscore key min max withscores limit 0 1: ) 消费最早的消息;
2.ACK机制:队列最重要的就是保证消息被成功消费;
维护一个消息记录表,贮存消息的消费记录,用于失败时回滚消息。表中记录消息ID,消息内容,消息时间,消息状态。定时轮询该消息表,处理消费记录表中消费状态未成功的记录,重新放入等待队列。
3.锁机制。从延迟队列中获取消息前,先lock下,以防止分布式环境下,多个实例拿到相同消息处理。消息消费后从队列删除,释放锁。(分布式锁如何获取?拓展内容,直接说不会)
slave先pull,master再响应。
master并不会主动去"push"(推送)日志的内容,而是由slave去主动从master去“pull”(拉取)日志;
每一个slave都是完全独立的个体,所以slave完全依据自己的节奏去处理同步,和master,其他的slave没有一点关系;
(1)略
(2)主从同步加入新从机实现过程(不停机):
非线上环境:主服务器执行加只读锁(fulsh tables with read lock),再拷贝主库数据到新的从库服务器上,然后执行主从同步(更改 主库配置文件 vim /etc/my.conf binlog-do-db = 库名),主库释放锁。
1.从服务器向主服务器发送SYNC命令。
2.接到SYNC命令的主服务器会调用BGSAVE命令,创建一个RDB文件,并使用缓冲区记录接下来执行的所有写命令。
3.当主服务器执行完BGSAVE命令时,它会向从服务器发送RDB文件,而从服务器会接收并载入这个文件。
4.主服务器将缓冲区存储的所有写命令发送给从服务器执行。
补充:
1.开启主从复制的时候,使用的是RDB的方式,同步主从数据的。
2.同步开始之后,通过主库命令传播的方式,主从的复制方式实现。
3.2.8以后实现的PSYNC机制,实现断线重连。
有序数组:方便查询,支持和此二分查找(O(logn)),范围查找,但并适合插入删除,导致相关行之后的数据行都要移动
哈希表:查找最快O(1),只能索引等值查询,无法范围查询
二叉树:查找O(logn),有序,支持范围查找。缺点:每次查询都要读取树的节点,而二叉树的节点是在文件中随机存在的。所以可能读取一个节点就需要一次磁盘IO,二叉树搜索树比较高,造成IO次数较多。(改善高度,减少IO- 升级到B树)
B树:每个节点都是一个页,可以存放多个数据节点,每页中的节点都是有序的,左子树的节点小于当前节点,右子树的节点大于当前节点。B树的高度降低,且每页使用二分查找,故查找效率很快。(innodb中规定一页16k,按1天 100bytes,一页160条,三层6亿条,因此B树一般 3-5 层。而根结点一般都是 在内存中的,所以一般只需要2-4次磁盘IO就可以查询到指定数据。)
B+树:与B树的区别: 1.非节点只存放索引key,不存放数据,数据只存在于叶子节点。
叶子节点页之间使用链表连接。带来的好处:
1.磁盘读写IO次数更低。非叶子节点只放索引,不放数据,每个节点可以存放的索引更多,一次查取的关键字更多,树的高度更低。
2.B+树的查询效率更加稳定,因为只有叶子节点存在数据,所以每次查询的路径长度都是相同的。
3.B+树更适合范围查询,因为B树的非叶子节点存放数据,所以需要中序遍历来查询,而B+树只有节点有数据,叶子节点之间使用链表连接,所以只要顺序扫描进行,更加方便。
1.哨兵机制:可以管理多个redis服务器,他提供了监控,提醒以及自动的故障转移的功能。
(哨兵机制本身也是高可用,多个哨兵(进程)节点共同监控,且互相通信)
(每隔1s每个哨兵会向整个集群(master slave 其他哨兵)发送一次ping做一次心跳检测。)
(哨兵判断节点是否正常的重要依据,涉及两个重要依据,涉及两个新的概念:
主观下线:一个哨兵节点判断主节点down掉是主观下线。
客观下线:半数哨兵主观判定主节点down掉,此时多个哨兵节点交换主观判断结果,才会判定主节点客观下线。
投票机制:基本上先哪个哨兵节点最先判断这个主节点客观下线,就会在各个哨兵节点中发起投票机制(rat 算法),最终被投为领导者的哨兵节点完成主从自动化切换的过程。)
2.复制:负责让一个redis服务器可以配备多个备份的服务器。
3.以下几个概念的区别:
主从模式:读写模式,备份,一个Master可以有多个slaves。
哨兵sentinel:监控,自动转移,哨兵发现主服务器挂了后,就会从slave中重新选举一个主服务器。
集群:为了解决单机redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/qps不受限于单机,可受益于分布式集群高扩展性。
Mysql:
redis:
不会!!
解决:
未解决:
幻读:多次执行 select 语句,读到的数据行发生了改变,这是因为数据行发生了新增或者减少。
略。
略。
(1)
概念:跳跃表是一种有序数据结构,他通过在每个节点维持多个指向其他的几点指针,从而达到快速访问队尾目的。跳跃表的效率可以和平衡树相媲美,且它的代码实现更简单。
跳跃表本质上是一个链表,但他是有序的。意味着我们可以冗余节点,来达到快速查询的效率。
level层级完全是随机的,一般来说,层级越多,访问节点的速度越快。
使用场景:1.实现有序集合键,2.集群节点中用作内部数据结构
层级:使用层级-使用抛硬币;每个层级最末端节点指向都是Null,表示该层级到达末尾,可以往下一级跳。
(2) RDB AOF
略
1.数据结构角度
redis采用简单动态字符串(sds)。
sdshdr 包含 free len buf
len 记录长度,计算长度为O(1)
sds增加未使用空间 ,记录free属性中,实现空间预分配和惰性空间释放策略。
sds空间预分配策略:sds不超过1M时,程序将分配和len相同长度的未使用空间。
sds超过1M时,程序将分配1M的使用空间。
sds的惰性空间释放:当SDS减少时,程序并不立即使用内存重新分配来回收多出的长度,而是将他们记录在free中,以此减少修改字符串长度时所需的内存重分配次数。
sds会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对数据有任何限制,过滤或者假设,数据写入是什么样的,读出就是什么样的
总结:SDS优点
1.常数复杂度获得字符串长度。
2.杜绝缓冲区溢出。
3.减少修改字符串长度
2.多路复用模型,非阻塞IO
3.运行在内存中,自然很快
4.采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为死锁而导致的性能消耗。
‘数据库并发控制’
数据库和操作系统一样,一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发存储不正确的数据,破坏数据库的一致性。加锁是实现数据库并发控制的一个非常重要的技术。当两个事务需要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁,严重影响应用的正常执行。
数据库有两种基本的锁:排他锁(exclusive 即x锁)和共享锁(share locks) 当数据对象被加上排他锁是,其他的事务不能对他读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。
一级索引(聚簇索引)
二级索引(辅助索引)
略
都是Mysql中字符串类型:
char 定长字符串;即每条数据占用等长字节空间;适合用在身份证号码、手机号码等。
varchar 变长字符串,可以设置最大长度;适合用在长度可变的属性。
text 长文本数据 ,不设置长度,当不知道属性的最大长度时,适合用text。
分表,分区的原因:当表过于庞大的时候,比如有百万级乃至千万级别记录的表。导致数据库在查询和插入的时候耗时太长,如果涉及联合查询,性能更加糟糕。分表和分区的目的就是减少数据库的负担,提高数据库的效率 ,通俗说,就是提高表的增删改查效率。
分表:将一个大表按一定规则分解成多张具有独立存储空间的实体表,我们可以称为子表。每个表都对应三个文件 .MYD数据文件, .MYI索引文件 .frm表结构文件,这些表可以分布在同一块磁盘上,也可以在不同的机器上。app读写的时候跟据实现定义好的规则去得到对应的子表名,然后去操作它。
分区:分区跟分表相似,按照规则分解表。不同的是,分区是将数据划分在多个位置存放,可以是同一块磁盘也可以在不同的机器。分区后,还是一张表,但是数据散列在不同的位置。app读写的时候操作的还是大表名字,db自动去组织分区的数据。
分表方式:
1.mysql集群:不算严格意义上的分表。但可以分担数据库的操作次数,将任务分担到多台数据上。
2.自定义分表(range, hash, key, list, composite)
3.利用merge引擎存储分表。主表类似于一个壳子,逻辑上封装了子表,实际上数据都是存储在子表中。可以通过主表插入和查询数据,如果清除分表规律,也可以直接操作子表。
分区:range; list; hash; key;
------
查询某个产品的所有订单。
查询某一天的所有订单。
查询有个产品最近一个月的所有订单。
略。
分 Innodb 和 mysiam:
innodb: 数据和主键索引都在叶子节点中,直接按ID进行搜索这颗B+树。
myisam:也只节点中只存放主键和指向数据存储的地址。先按ID主键索引拿到地址之后回表查询。
url请求 -> 分配路由到不同的视图类(函数) -> 视图处理请求 -> DB操作 -> 返回 template 给到用户。
本质上就是一个 socket 服务端,用户的浏览器其实就是一个 socket 客户端。本质上就是 服务端与 客户端 scoket 通信的过程。
pass
中间件执行顺序:
视图处理前: 中间件从前到后执行
视图执行后: 中间件从后到前执行
中间件实际上是装饰器,是一种无侵入式的开发方式,保证了 django的健壮性。
(装饰器本身是个闭包)
django对请求的执行顺序:
pass
概念:介于 request 和 response 处理之间的一道处理过程。相对来说比较轻量级。并且在全局上改变 django 的输入输出。因为改变的是全局,所以谨慎实用,用不好会影响性能。
中间件位于 web 服务端和url路由层之间。
支持自定义中间价:
process_request,process_view,process_template_reaponse,process_exception,process_response。 以上方法的返回值可以是None 或 一个HttpResponse,如果是 None,按照django定义的规则向后执行。如果是 HttpResponse 对象,则直接将该对象返回给用户。
中间件作用:
1.做IP访问频率限制;2. URL 访问过滤
略
rest 表述性状态迁移 ;
– 本质: 一种软件架构风格;
– 核心:面向资源设计的API;
依托于 HTTP协议,但是本质上与 http 协议无关。
解决问题:1.降低开发的复杂性;2.提高系统的可伸缩性
设计概念和准则:
网络上的所有事物都可以被抽象为资源
每一个资源都有唯一的资源标识,对资源的操作不会改变这些标识;
所有的操作都是无状态的(本次操作,下次操作,上次操作之间无关系。)
设计方法:
没看过;
MVC: 通用后端工作模式 M
MTV:django后端工作模式 Model: db联系文件,执行db创建,更新,查找等。Template: 模板文件:即前端展示页面 view: 视图文件 联系model 和 template的文件,执行业务逻辑。
url: 分配视图
使用redis作为缓存;(根据业务场景作答)
缓存用途:高性能、高并发。
高性能:对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么结果直接放在缓存,后面直接读缓存就好。
高并发:mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql 单机支撑到 2000QPS 也开始容易报警了。
再讲讲 缓存的不良后果: 缓存雪崩,缓存穿透,缓存击穿
pass;
csrf: 跨站请求伪造。直白点:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的。
xss利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
完成一次 csrf 攻击,受害者必须完成两个步骤:
1.登陆受信任网站,并在本地生成 cookie
2.在不登出A的情况下,访问危险网站B
防范csrf的三种策略:
验证 http referer字段:HTTP头中的referer字段是记录请求的来源地址。特点:
简单易行,只需要增加一个简单的拦截器。缺点是:依赖第三方浏览器的保护,不太安全;referer记录用户访问来源,有些用户认为这可能侵犯隐私。
在请求地址中添加 token 并验证。(必须是黑客不能伪造的信息,存在于cookie之外)
将 token 以参数的形式置于HTTP头中自定义的属性里。通过 xmlHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个HTTP头属性。
使用示例:
1.form表单:
{% csrf_token %}
2.ajax 放在 data 里面:
‘csrfmiddlewaretoken’: $(’[name=“csrfmiddlewaretoken”]’).val()
直接说资讯的登陆注册模块;
cookies 是浏览器为 Web 服务器存的一小段信息。 每次浏览器从某个服务器请求页面 时,都会自动带上以前收到的cookie。cookie保存在客户端,安全性较差,注意不要保存敏感信息(登录;购物车)
用户的数据保存在服务端,在客户端cookie里加一个sessionID(随机字符串)。其工作流程:
(1)、当用户来访问服务端时,服务端会生成一个随机字符串;
(2)、当用户登录成功后 服务端把 {sessionID :随机字符串} 组织成键值对加到cookie里发送给用户;
(3)、服务器以发送给客户端 cookie中的随机字符串做键,用户信息做值,保存用户信息;
(4)、再访问服务时客户端会带上sessionid,服务器根据sessionid来确认用户是否访问过网站
区别:session将数据存储与服务器端 cookie存储在客户端
cookie 存储在客户端,不安全,sess存储在服务器端,客户端只存sesseionid,安全
cookie在客户端存储值有大小的限制,大约几kb。session没有限制
联系
联系:session 基于cookie
nginx: 负载均衡;反向代理;静态文件;
uwsgi:全功能 http 服务器,将http请求转换为 语言可以识别的协议。
top
netstat
blog;书籍;交流;公众号;
推荐STAR模型。
S——situation,项目是什么背景下产生的
T——task,你的任务是什么
A——action,你怎么做的
R——result,结果如何
我相信每一个真实做过自己的项目的人,肯定会对自己的项目有所思考。总结一下自己在这个项目里最难的地方,以及最精彩的地方,也可以使用上面的STAR模型。
有的面试官会要求你在白纸上把项目的框架图或者设计图画出来,这个也可以提前准备下,做到条理清晰,临场画的话很容易乱。
一:登录怎么做的?分布式session?
订单表怎么区分买家端和卖家端?你怎么设计订单表的?数据库表数据膨胀怎么办(我说了水平拆分和垂直拆分)?那拆分维度呢?我balabala说怎么拆分。那么你这么拆分有什么问题吗?我如果要做排序呢?我balabala。那如果我就要取某个商家或者某个用户的订单呢?我balabala。那我就取中间10条呢?就问到你答不上来为止。
项目Redis怎么用?怎么保证Redis高可用?怎么解决缓存和db一致性?热点key?缓存雪崩?逮着一个点一直问
微博出现热搜服务挂了,你觉得是什么原因?你会怎么解决?我balabala。这里也一直追问
就大概记得这些了。
问的点不多,就是根据你项目问你难点,然后你给思路,然后又根据你的思路继续追问,直到你答不上来。
二:
如果你去设计一个网站后台的缓存,你会怎么做。
如果用户访问了你的网站感觉很卡,是什么原因,如何解决?