1. django是如何实现websocket的

1.1 什么是websocket

websocket是一种在单个TCP连接上实现的全双工通信的协议。websocket允许服务端主动向客户端发送信息。在websocket协议中,只要客户端和服务端完成一次TCP握手,就可以持久化的建立连接,并在客户端和服务器之间相互通信。

1.2 websocket的作用

websocket区别于http协议的最为显著的特点就是,websocket协议允许服务器主动向客户端发送信息,对于浏览器需要及时接收数据的场景非常适合。

2. restful规范

  1. restful提倡面向资源编程,在url接口中尽量使用名词,不要使用动词
  2. 在url中使用https协议,让网络接口更安全

例如:https://www.baidu.com/?page=3

  1. 在url中可以体现版本号

例如:https://v1.www.baidu.com/

  1. url中可以体现是否是API接口

例如:https://www.baidu.com/api/

  1. url中可以添加条件去筛选匹配

例如:https://www.baidu.com/v1/rooms/?page=3

  1. 可以根据http的不同method,进行不同的请求
  2. 响应式应该设置状态码
  3. 有返回值,而且格式为统一的json格式
  4. 返回错误信息
  5. 返回结果中要提供帮助链接,API最好使用hypermedia

3. 接口的幂等性是什么意思

幂等性:原本是数学里面的概念,用在接口上理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。调用接口发生异常并且重复尝试时,总是造成系统所无法承受的损失,所以必须阻止这种事情发生。

3.1 为什么会产生接口幂等性问题

  1. 网络波动,可能会引起重复的请求
  2. 用户重复操作,用户在操作时可能会无意中触发多次下单交易,甚至没有响应而多次有意触发多次交易造成损失
  3. 页面重复刷新

    3.2 如何保证幂等性

    一个是在客户端防止重复调用,一个是在服务端进行校验。客户端实现比较简单,但不可靠。

  4. 按钮只可提交一次

一般是提交后把提交按钮变灰,防止用户多次点击提交

  1. token机制

功能上允许重复提交,但要保证重复提交不会产生副作用,比如点击n次只会产生一条数据。具体实现就是客户端进入页面时,申请一个token,然后后面所有的请求都带上这个token,后端根据token来避免重复请求。

  1. 使用post/redirect/get模式

在提交后执行页面重定向,这就是所谓的post/redirect/get模式,就是当用户提交表单后,跳转到一个重定向的信息页面,这样就避免用户F5刷新导致的重复提交。

  1. 使用唯一索引防止新增脏数据

利用数据库唯一索引机制,当数据重复时,插入数据会抛出异常,保证不会出现脏数据。

3.3 HTTP方法中的幂等性

幂等性:指的是作用于结果而非资源本身。

  1. HTTP GET方法,用户获取资源,不管调用多少次接口,结果都是不会改变的,所以是幂等的,
  • 当我们有一个接口是获取当前时间,我们应该设计成

GET/service_time #获取当前服务器的时间
它本身不会对资源本身产生影,因此满足是幂等的。

  1. HTTP POST方法,是一个非幂等方法,因此多次调用,都会产生新的资源
  2. HTTP PUT方法,因为它直接把实体部分的数据替换到服务器的资源,我们多次调用它,只会产生一次影响,但是有相同的HTTP方法,所以满足幂等性。
  3. HTTP PATCH方法,只是更新部分资源,是非幂等的。因为PATCH提供的实体需要根据程序或其他协议的定义,解析后在服务器上运行,以此来修改服务器上的资源。换句话说:PATCH请求是会执行某个程序的,如果重复提交,程序可能执行多次,对服务器上的资源可能会造成额外的影响,这样可以解释它为什么是非幂等的了。
  4. HTTP DELETE方法用于删除资源,会将资源删除。调用一次或多次对资源产生的影响是相同的,所以是幂等的。

    4. 什么是RPC

    RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。
    RPC协议:做到不同服务间调用方法就像同一服务间调用本地方法一样。

5.HTTP和HTTPS的区别

  1. 安全性不同
    1. https://前缀表明是SSL(安全套接字)或TSL加密的。你的浏览器与服务器之间的通信也将会变得安全。如果你访问的是HTTP协议的网站,浏览器会提醒你不安全的信息。
  2. 网站申请流程不同
    1. https需要到CA申请证书,需要缴费。Web服务器启动SSL需要获得一个服务器证书并将该证书与要使用的SSL服务器绑定在一起。
  3. 默认端口号不同
    1. http和https使用的是完全不同的连接方式,同时使用的端口也不同
    2. http使用的是80端口,https使用的是443端口
    3. 在网络模型中,http工作于应用程,https工作于传输层
  4. 对搜索排名的提升
    1. https比http网站的搜索排名更有优势
    2. http终将被https淘汰

      6. 简述rabbitmq

      rabbitmq(Advanced Message Queuing Protocol,高级消息队列协议)是一个消息代理和队列服务器,用来通过普通的应用在完全不同的应用之间共享数据。

何为消息队列,也就是“生产者-消费者”模型,一端向消息队列中不断写入数据,而另一端可以读取或者订阅队列中的消息。

在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步操作,而这种异步处理的方式大大的节省了服务器的请求时间,从而提高了整个系统的吞吐量。而且不影响服务器做其他的响应,不独占服务器资源。

6.1 几个重要概念:

  1. broker:消息队列服务器实体
  2. exchange:消息交换机,它指定消息按什么规则,路由到哪个队列
  3. queue:消息队列载体,每个消息都会被投入到一个或多个队列
  4. binding:绑定,把exchange和queue按照某种路由规则绑定起来
  5. routing key:路由关键字,exchange根据这个关键字进行消息投递
  6. vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限隔离
  7. producer:消息生产者,就是投递消息的程序
  8. consumer:消息消费者,就是处理消息的程序
  9. channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

    6.2 消息队列的使用过程

  10. 客户端连接到消息队列服务器,打开一个channel

  11. 客户端声明一个exchange,并设置相关属性
  12. 客户端声明一个queue,并设置相关属性
  13. 客户端使用routing key,在exchange和queue之间建立好绑定关系
  14. 客户端投递消息到exchange

6.3 rabbitmq支持消息队列的持久化

持久化的机制就是把数据写在磁盘上,当rabbitmq服务器宕机重启后,从磁盘中读取存入的持久化数据。消息队列持久化包括三个部分:

  1. exchange持久化,在声明时指定durable =>1
  2. queue持久化,在声明时指定durable =>1
  3. 消息持久化,在投递时指定delivery_mode =>2(1是非持久化)

7. B树和B+树的区别

7.1 B树

B树是一种多路自平衡搜索树,它类似于普通的二叉树,但是B树允许每个节点有更多的子节点。
特点:

  1. 所有键值分布在整个树种
  2. 任何关键字出现且只出现在一个节点中
  3. 性能稍逊二分查找

    7.2 B+树

    特点:

  4. 所有关键都存储在叶子节点,非叶子节点不存储真正的data

  5. 为所有的叶子节点增加了一个链指针

    8. SSH的原理及应用

    8.1 SSH简介

    SSH是Secure Shell的缩写,也叫做安全外壳协议。主要目的用于安全远程登录。

    8.2 SSH工作原理

    SSH对数据加密的方式有两种:对称加密(密钥加密)和非对称加密(公钥加密)。

  6. 对称加密:加密解密使用的是同一套密钥。客户端把密钥加密后发送个服务端,服务端用同一套密钥解密。对称加密的强度非常高,很难破解。但是,客户端的数量庞大,很难保证密钥不泄露出去。如果有一个客户端的密钥泄露,那么整个系统的安全性就存在严重的漏洞。

  7. 非对称加密:为了解决对称加密的问题,于是就出现了非对称加密。非对称加密有两个密钥:“公钥”和“私钥”。公钥加密后的密文,只能通过对应的私钥解密。反之亦然。
  8. SSH的加密原理中,使用了RSA非对称加密算法。过程如下:
    1. 远程主机收到用户的登录请求,把自己的公钥发给用户
    2. 用户使用这个公钥,将登录密码加密后,发送回来
    3. 远程主机用自己的私钥,解密登录密码,如果密码正确,就同一用户登录
  9. 中间人攻击
    1. SSH之所以能够保证安全,原因就在于使用了公钥加密,这个过程本身是安全的,但是实际上使用时会存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发送个用户,那么用户就很难辨真伪。SSH 协议的公钥是没有证书中心(CA)公证的,是自己签发的。
    2. 如果攻击人插在用户与远程主机之间(比如公共wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就不存在了。这就是“中间人攻击”。

      9. I/O多路复用

      I/O多路复用:是用于提升效率,单个进程可以同时监听多个网络连接IO
      举例:通过一种机制,可以监视多个文件描述符,一旦描述符就绪(读就绪或写就绪),就能通知程序进行相应的读写操作,I/O多路复用避免阻塞在IO上,原本为多线程或多进程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理。

9.1 没有I/O多路复用时,有BIO和NIO两种方式

  1. BIO(同步阻塞)
    1. 服务端采用单线程,当accept一个请求后,在recv或send调用阻塞时,将无法accept其他请求(必须等上一个请求处理完recv或send),无法处理并发
    2. 服务端采用多线程,当accept一个请求后,开启线程进行recv,可以完成并发处理,但随着请求数量增加需要增加系统线程。(大量的线程占用很大的内存空间,并且线程切换也会带来很大的开销)
  2. NIO(同步非阻塞)

    1. 服务器端当接收一个accept请求后,加入fds集合,每次轮询一遍fds集合recv(非阻塞)数据,没有数据则立即返回错误,(每次轮询所有fd(包括没有读写操作的fd)会很浪费CPU)

      9.2 I/O多路复用的三种实现方式

  3. select是通过系统调用来监视一组由多个文件描述符组成的数组,通过调用select()返回结果,数组中的就绪文件描述符会被内核标记出来,然后进程就可以获得这些文件描述符,然会进行相应的读写操作。

    1. 每次调用select,都需要把fd集合由用户态拷贝到内核态,在fd多的时候开销会很大,每次select都是线性遍历整个列表,当fd很大的时候,遍历的开销也很大。
  4. poll本质上与select基本相同,只不过监控的最大连接数上相比于select没有了限制,因为poll使用的数据结构是链表,而select使用的是数组,数组是要初始化长度大小的,且不能改变。
  5. epoll:解决select和poll本身的缺陷。

    1. 数组长度限制解决方案:fd上限是最大可以打开文件的数目,具体数目可以查看/proc/sys/fs/file-max。一般和内存有关,
    2. 需要每次轮询将数组全部拷贝到内核态解决方案:每次注册事件时,会把fd拷贝到内核态,而不是每次poll的时候拷贝,这样就保证每个fd只需要拷贝一次。
    3. 每次遍历都需要列表线性遍历解决方案:不再采用线性遍历,给每个fd指定一个回调函数,fd就绪时,这个回调函数会把fd加入到就绪的fd列表中,所以epoll只需要遍历就绪的list即可。

      10. GIL和线程锁

  6. GIL:限制的是一个进程中只有一个线程进入Python解释器。

  7. 线程锁:由于在线程进行数据操作时保证数据操作的安全性(同一个进程中线程之间可以共用信息,如果同时对数据操作,则会出现公共数据有误)
  8. 其实线程锁可以完全取代GIL,但是Python后续的模块都是加在GIL 基础上的,所以无法更改或去掉GIL,这就是Python最大的Bug,只能用多进程或协程改善。

    11. 进程间的通信方式

    11.1 进程间为什么要通信?

  9. 进行数据传输

    1. 一个进程需要将它的数据传递给另一个进程
  10. 资源共享
    1. 多个进程之间共享同样的资源
  11. 通知事件
    1. 一个进程需要向另一个或一组进程发送信息,通知它们发生了某种事件
  12. 进程控制

    1. 有些进程希望完全控制另外一个进程的执行(Debug进程),该控制进程希望能够拦截另一个进程的所有操作,并能够及时直到它的状态改变。

      11.2 进程间通信的原理

      每个进程都有各自不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到内核缓冲区,进程2再去内核缓冲区把数据读走。

      11.3 进程间通信的几种方式

  13. 管道(pipe)

    1. 管道又称匿名管道,这是一种最基本的IPC机制
  14. 命名管道
  15. 消息队列(msg)
  16. 信号量(sem)

12. Python线程锁和进程锁

在Python的多进程和多线程中,当我们需要对多线程和多进程的共享资源或对象进行修改操作时,往往会出现因CPU随机调度而导致结果和我们预期的不一致的问题,这时就需要对线程或者进程加锁,以保证一个进程或线程在对共享对象进行修改时,其他的进程或线程无法访问这个对象,直到获取锁的这个进程或线程执行完这个操作释放掉锁。