缓存雪崩:缓存挂点了,所有的请求全部跑到数据库上面去了,它采用的是惰性删除和定期删除两种策略对过期键进行删除。所以两种情况导致缓存雪崩:redis挂掉了,一个是对缓存设置了相同的过期时间,导致某一个时间缓存全部失效。解决办法:第一个当然是给缓存设置时间为随机值。第二个首先事发前准备好redis的主从防止挂掉,然后如果挂了就设置本地缓存和限流不让数据路挂掉。后面的话redis持久化,重启后从磁盘上加载数据,恢复缓存。
缓存穿透:是指查询一个一定不存在的数据,由于缓存不命中,数据库查不到的数据不存在缓存,那么每次这个查询都会去数据库查询。解决方案:由于请求不合法,可以用布隆过滤器或者压缩filter提前拦截。还有一个方法是把查询到的空对象也放进缓存,只是设置一个很短的过期时间。
布隆过滤器:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。
a.sort()与sorted(a)的不同在于,sort是在原位重新排列列表,而sorted()是产生一个新的列表。
list.reverse()和reversed(list)都是反向排序,但是reversed() 的返回值类型 并不是list,因此如果需要,要再套上一个list()
最早只有ASCII,只包含了大小写英文,数字和符号,对于中文肯定不够,所以有了unicode,把所有语言统一一套编码,UTF8隶属于Unicode
可变数据类型:list、dict、set
不可变数据类型:int/float、str、tuple
ilter 函数用于过滤序列,它接收一个函数和一个序列,把函数作用在序列的每个元素上,然后根据返回值是True还是False决定保留还是丢弃该元素。
list(filter(lambda x: x%2 == 1, mylist))
map 函数传入一个函数和一个序列,并把函数作用到序列的每个元素上,返回一个可迭代对象
list(map(lambda x: x*2, mylist))
reduce 函数用于递归计算,同样需要传入一个函数和一个序列,并把函数和序列元素的计算结果与下一个元素进行计算
reduce(lambda x, y: x+y, range(101))
zip 函数用法:
list1 = ['zhangfei', 'guanyu', 'liubei', 'zhaoyun']
list2 = [0, 3, 2, 4]
list(zip(list1, list2))
生成一个里面是元组的list
所以可以合并两个元组成字典:dict(zip(a,b))
range生成一个序列,xrange生成一个生成器,节省很大的内存
read 读取整个文件
readline 读取下一行,使用生成器方法
readlines 读取整个文件到一个迭代器以供我们遍历
# 按照key进行排序
print sorted(dict1.items(), key=lambda d: d[0])
# 按照value进行排序
print sorted(dict1.items(), key=lambda d: d[1])
都是先取一个列表,然后指定key为列表中每一项的某个元素
def add(x:int, y:int) -> int:
return x + y
必须有一个内嵌函数
内嵌函数必须引用外部函数中的变量
外部函数的返回值必须是内嵌函数
def func_timer(function):
'''
用装饰器实现函数计时
:param function: 需要计时的函数
:return: None
'''
@wraps(function)
def function_timer(*args, **kwargs):
print '[Function: {name} start...]'.format(name = function.__name__)
t0 = time.time()
result = function(*args, **kwargs)
t1 = time.time()
print '[Function: {name} finished, spent time: {time:.2f}s]'.format(name = function.__name__,time = t1 - t0)
return result
return function_timer
猴子补丁在程序运行时动态修改类和模块:
在运行时替换方法和属性
在不修改第三方代码的情况下,增加原来不支持的功能
在运行时为内存中的对象增加patch而不是在磁盘中的源代码中增加
Python 的断言就是检测一个条件,如果条件为真,它什么都不做;反之它触发一个带可选错误信息的 AssertionError。
def testassert(n):
assert n == 2, "n is not 2"
print('n is 2')
testassert(1)
七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
五层划分为:应用层、传输层、网络层、数据链路层、物理层。
arp 协议:ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标 IP 对应的 MAC 地址。
socket 是对 TCP/IP 协议的封装,它的出现只是使得程序员更方便地使用 TCP/IP 协议栈而已。
RPC 是指远程过程调用,也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
在关系数据库中,一个事务可以是一条 SQL 语句、一组 SQL 语句或整个程序。
四个属性:原子性,一致性,隔离性和持久性。
都是将数据库放在内存中,不过memcached还能储存图片视频
redis支持更多的数据类型,dic,hash,set,string,list
redis可以将数据持久化到硬盘
持久化策略:
RDB持久化,将redis在内存中的数据库记录定时dump到磁盘上持久化
AOF持久化,将redis 的操作日志以追加的方式写入文件
redis默认有16个数据库,每个数据库都是隔离的,所以在存储数据库的时候可以指定不同的数据存储到不同的数据库中。
redis的过期策略是惰性删除和定期删除,也就是key过期的时候不删除,每次获取key的时候去检查过期没,过期了就删除;定期删除也就是每隔一段时间执行一次删除key的操作
保证redis都是热点数据:限定redis占用的内存,然后就会触发数据淘汰策略。
redis是单进程单线程的,但是利用队列技术将并发访问变成串行访问
支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
优点:
方便使用面向对象,有效的防治SQL注入,方便动态构造语句,方便设置钩子函数
缺点:
不容易处理复杂的查询语句,性能差
如果发送方发送数据太快,接受者来不及接受,那么就会有分组丢失,所以控制发送方的发送速度,让接受者来得及接受,那就是流量控制,如何实现?滑动窗口协议实现,主要就是接收方返回的ack中会包含自己接收窗口的大小
????
开放地址法:就是从发生冲突的哪个单元开始,按照一定次序,从哈希表中找到一个空闲的单元,然后把发生冲突的元素存入到该单元。缺点是删除元素不能真的删除,否则会引起查找错误,只能做一个标记,下次插入的时候再删除
拉链法:适用于经常插入删除,将哈希值相同的元素构成一个同义词的单链表。
再哈希法:再哈希,直到不产生冲突
建立公共溢出区: 将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。
查找某进程,但是过滤grep进程本身:
ps -ef | grep nginx
find命令:
find . -name "*.c"
find . -ctime -20
将目录下面所有最近20天内更新过的文件列出
gunicorn的pre-fork worker模型中有一个管理进程和多个工作进程,管理进程master工作进程是worker。
在worker.init_process()
函数中,worker中的gunicorn的app对象会去import我们的wsgi app,也就是说,每个worker子进程都会单独的实例化我们的app对象,所以每个worker里面的app对象是相互独立,互不干扰的。
master的事件循环就是接受信号,管理worker进程,而worker进程的事件循环就是监听网络事件并且处理,比如新建连接,断开连接,处理请求发送响应
gevent:
gevent worker启动的时候回启动多个server对象,worker首先为每个listener创建一个server对象,每个server对象都由运行在一个单独的gevent pool对象中,真正等待链接和处理链接的操作是在server对象中进行的。
这个server就是一个gevent的WSGI server子类,构造的时候,有很多参数,s是server里面用来监听链接的套接字,spawn是gevent的协程池,application也就是flask App,所以我们的app就是这样交给gunicorn去跑的。
server对象创建成功后,worker会定时通知manager,不然挂了都不知道。这个notify的机制是去操作一下,tmp file,然后更新一下时间戳,然后manager就会检查时间戳来判断谁挂了。
实际上,WSGIserver是创建一个协程去处理套接字,也就是说,一个协程单独处理一个http链接
总结: gunicorn会启动一组worker进程,所有worker进程公用一组listener,每个worker中为每个listener简历一个wsgi server,每当有http链接到来是时,wsgi server创建一个协程来处理该链接,协程会先初始化一个WSGI环境,然后调用用户提供的app去处理http请求。