Think Deep,Work Lean

知识梳理

Posted on By zack

HTTP

什么是 HTTP?超文本传输协议(HTTP)的设计目的是保证客户机与服务器之间的通信。举例:客户端(浏览器)向服务器提交 HTTP 请求;服务器向客户端返回响应。响应包含关于请求的状态信息以及可能被请求的内容。

关于http tcp ip请参考这个

关于常用的协议有 grpc http thrift

HTTP的方法GET及POST

  • GET 方法 请注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的
    /test/demo_form.asp?name1=value1&name2=value2
    
  • GET 请求可被缓存
  • GET 请求可被收藏为书签
  • GET 请求不应在处理敏感数据时使用
  • GET 请求有长度限制
  • GET 请求只应当用于取回数据

  • POST 方法

请注意,查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的

POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2

其他 HTTP 请求方法

  • HEAD 与 GET 相同,但只返回 HTTP 报头,不返回文档主体。
  • PUT 上传指定的 URI 表示。
  • DELETE 删除指定资源。
  • OPTIONS 返回服务器支持的 HTTP 方法。
  • CONNECT 把请求连接转换到透明的 TCP/IP 通道。

参考

HTTP响应码

1xx: 信息

  • 100 Continue 服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求
  • 101 Switching Protocols 服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。

2xx: 成功

  • 200 OK 请求成功(其后是对GET和POST请求的应答文档。)
  • 201 Created 请求被创建完成,同时新的资源被创建。
  • 202 Accepted 供处理的请求已被接受,但是处理未完成。
  • 203 Non-authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝。
  • 204 No Content 没有新文档。浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。
  • 205 Reset Content 没有新文档。但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容。
  • 206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它。

3xx: 重定向

  • 300 Multiple Choices 多重选择。链接列表。用户可以选择某链接到达目的地。最多允许五个地址。
  • 301 Moved Permanently 所请求的页面已经转移至新的url。
  • 302 Found 所请求的页面已经临时转移至新的url。
  • 303 See Other 所请求的页面可在别的url下被找到。
  • 304 Not Modified 未按预期修改文档。客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
  • 305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取。
  • 306 Unused 此代码被用于前一版本。目前已不再使用,但是代码依然被保留。
  • 307 Temporary Redirect 被请求的页面已经临时移至新的url。

4xx: 客户端错误

  • 400 Bad Request 服务器未能理解请求。
  • 401 Unauthorized 被请求的页面需要用户名和密码。
  • 402 Payment Required 此代码尚无法使用。
  • 403 Forbidden 对被请求页面的访问被禁止。
  • 404 Not Found 服务器无法找到被请求的页面。
  • 405 Method Not Allowed 请求中指定的方法不被允许。
  • 406 Not Acceptable 服务器生成的响应无法被客户端所接受。
  • 407 Proxy Authentication Required 用户必须首先使用代理服务器进行验证,这样请求才会被处理。
  • 408 Request Timeout 请求超出了服务器的等待时间。
  • 409 Conflict 由于冲突,请求无法被完成。
  • 410 Gone 被请求的页面不可用。
  • 411 Length Required “Content-Length” 未被定义。如果无此内容,服务器不会接受请求。
  • 412 Precondition Failed 请求中的前提条件被服务器评估为失败。
  • 413 Request Entity Too Large 由于所请求的实体的太大,服务器不会接受请求。
  • 414 Request-url Too Long 由于url太长,服务器不会接受请求。当post请求被转换为带有很长的查询信息的get请求时,就会发生这种情况。
  • 415 Unsupported Media Type 由于媒介类型不被支持,服务器不会接受请求。
  • 416 服务器不能满足客户在请求中指定的Range头。
  • 417 Expectation Failed

5xx: 服务器错误

  • 500 Internal Server Error 请求未完成。服务器遇到不可预知的情况。
  • 501 Not Implemented 请求未完成。服务器不支持所请求的功能。
  • 502 Bad Gateway 请求未完成。服务器从上游服务器收到一个无效的响应。
  • 503 Service Unavailable 请求未完成。服务器临时过载或当机。
  • 504 Gateway Timeout 网关超时。
  • 505 HTTP Version Not Supported 服务器不支持请求中指明的HTTP协议版本。

HTTP缓存

参考

HTTP1.0 HTTP 1.1主要区别

  • 长连接

HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。

HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用个长连接来发多个请求

  • 节约带宽

HTTP 1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接受到100,才开始把请求body发送到服务器。

这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。

另外HTTP还支持传送内容的一部分。这样当客户端已经有一部分的资源后,只需要跟服务器请求另外的部分资源即可。这是支持文件断点续传的基础。

  • HOST域 现在可以web server例如tomat,设置虚拟站点是非常常见的,也即是说,web server上的多个虚拟站点可以共享同一个ip和端口。

HTTP1.0是没有host域的,HTTP1.1才支持这个参数

HTTP1.1 HTTP 2.0主要区别

  • 多路复用 HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。

当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。

TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立好的连接,并且这个连接可以支持瞬时并发的请求。

关于多路复用,可以参看学习NIO 。

  • 数据压缩 HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

  • 服务器推送 意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。

服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。

缓存

 关系型数据库遵循ACID规则(原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)),而Nosql数据库遵循BASE原则(基本可用(Basically Availble)、软/柔性事务(Soft-state )、最终一致性(Eventual Consistency))。由于关系型数据库的数据强一致性,所以对事务的支持很好。关系型数据库支持对事务原子性细粒度控制,并且易于回滚事务。而Nosql数据库是在CAP(一致性、可用性、分区容忍度)中任选两项,因为基于节点的分布式系统中,很难全部满足,所以对事务的支持不是很好,虽然也可以使用事务,但是并不是Nosql的闪光点。

memcache

redis

mongoDB

数据库

mysql

oracle

postgresql

PostgreSQL是一个功能强大的开源对象关系数据库管理系统(ORDBMS)。它是开源的,其源代码是免费提供的。

sqlite

SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。就像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite 直接访问其存储文件。

中间件

MQ

zookeeper/consul

kafka

进程线程协程

线程

多任务可以由多进程完成,也可以由一个进程内的多线程完成。

我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程。

由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程。

Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行: 参考

  • threading
import time, threading

# 新线程执行的代码:
def loop():
    print 'thread %s is running...' % threading.current_thread().name
    n = 0
    while n < 5:
        n = n + 1
        print 'thread %s >>> %s' % (threading.current_thread().name, n)
        time.sleep(1)
    print 'thread %s ended.' % threading.current_thread().name

print 'thread %s is running...' % threading.current_thread().name
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print 'thread %s ended.' % threading.current_thread().name

进程

参考1 参考2

  • multiprocessing
  • subprocess

很多时候,子进程并不是自身,而是一个外部进程。我们创建了子进程后,还需要控制子进程的输入和输出。

subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。

下面的例子演示了如何在Python代码中运行命令nslookup www.python.org,这和命令行直接运行的效果是一样的:

import subprocess
print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)

运行结果:

$ nslookup www.python.org
Server:        192.168.19.4
Address:    192.168.19.4#53

Non-authoritative answer:
www.python.org    canonical name = python.map.fastly.net.
Name:    python.map.fastly.net
Address: 199.27.79.223

Exit code: 0

如果子进程还需要输入,则可以通过communicate()方法输入:

import subprocess
print('$ nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('utf-8'))
print('Exit code:', p.returncode)

上面的代码相当于在命令行执行命令nslookup,然后手动输入:

set q=mx
python.org
exit

运行结果如下:

$ nslookup
Server:        192.168.19.4
Address:    192.168.19.4#53

Non-authoritative answer:
python.org    mail exchanger = 50 mail.python.org.

Authoritative answers can be found from:
mail.python.org    internet address = 82.94.164.166
mail.python.org    has AAAA address 2001:888:2000:d::a6


Exit code: 0

1 p.start():启动进程,并调用该子进程中的p.run() 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
3 4 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 5 p.is_alive():如果p仍然运行,返回True 6 7 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
复制代码

进程间通信

Python的multiprocessing提供了Queue、Pipes等多种方式来交换数据,说白了就是调用消息队列

from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

multiprocessing本身的Queue方法封装了类似于unix的fork()功能

大数据

spark