运维方面技术点
docker熟悉
docker简单理解: Docker 中包括三个基本的概念: •Image(镜像) •Container(容器) •Repository(仓库) 镜像是 Docker 运行容器的前提,仓库是存放镜像的场所,可见镜像更是 Docker 的核心。 Image镜像是什么? Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。 镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义。 Container (容器)是什么? 容器 (container) 的定义和镜像 (image) 几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。 由于容器的定义并没有提及是否要运行容器,所以实际上,容器 = 镜像 + 读写层。 Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。 而 Linux 容器是 Linux 发展出了另一种虚拟化技术,简单来讲, Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离,相当于是在正常进程的外面套了一个保护层。 对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。 Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker ,就不用担心环境问题。 总体来说, Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。 说说docker的Repository (仓库)? Docker 仓库是集中存放镜像文件的场所。镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务, Docker Registry (仓库注册服务器)就是这样的服务。有时候会把仓库 (Repository) 和仓库注册服务器 (Registry) 混为一谈,并不严格区分。Docker 仓库的概念跟 Git 类似, 注册服务器可以理解为 GitHub 这样的托管服务。实际上,一个 Docker Registry 中可以包含多个仓库 (Repository) ,每个仓库可以包含多个标签 (Tag),每个标签对应着一个镜像。 所以说,镜像仓库是 Docker 用来集中存放镜像文件的地方类似于我们之前常用的代码仓库。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。 如果不给出标签,将以 latest 作为默认标签.。 仓库又可以分为两种形式: •public(公有仓库) •private(私有仓库) 简要阐述一下docker的架构? Docker 使用 C/S 结构,即客户端/服务器体系结构。 Docker 客户端与 Docker 服务器进行交互,Docker服务端负责构建、运行和分发 Docker 镜像。 Docker 客户端和服务端可以运行在一台机器上,也可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。 Docker 客户端、服务端和 Docker 仓库(即 Docker Hub 和 Docker Cloud ),默认情况下Docker 会在 Docker 中央仓库寻找镜像文件, 这种利用仓库管理镜像的设计理念类似于 Git ,当然这个仓库是可以通过修改配置来指定的,甚至我们可以创建我们自己的私有仓库。 Docker 的核心组件包括: 1.Docker Client 2.Docker daemon 3.Docker Image 4.Docker Registry 5.Docker Container Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。 客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信。 说出几条你常用的docker的常用命令? 1,我们需要拉取一个 docker 镜像,我们可以用如下命令:docker pull image_name 2,image_name 为镜像的名称,而如果我们想从 Docker Hub 上去下载某个镜像,我们可以使用以下命令:docker pull centos:latest 3,接着我们如果想查看下主机下存在多少镜像,我们可以用如下命令:docker images 4,我们要想知道当前有哪些容器在运行,我们可以用如下命令:docker ps -a 5,我们该如何去对一个容器进行启动,重启和停止呢?我们可以用如下命令: docker start container_name/container_id docker restart container_name/container_id docker stop container_name/container_id docker优点: docker 启动快速属于秒级别。虚拟机通常需要几分钟去启动 •docker 需要的资源更少, docker 在操作系统级别进行虚拟化, docker 容器和内核交互,几乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化 •docker 更轻量, docker 的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境, Docker 运行的镜像数远多于虚拟机数量,对系统的利用率非常高 •与虚拟机相比, docker 隔离性更弱, docker 属于进程之间的隔离,虚拟机可实现系统级别隔离 •安全性: docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。 虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术, 这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击 •可管理性: docker 的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如 VMware vCenter 提供完备的虚拟机管理能力 •高可用和可恢复性: docker 对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡,高可用,容错,迁移和数据保护等经过生产实践检验的成熟保障机制, VMware 可承诺虚拟机 99.999% 高可用,保证业务连续性 •快速创建、删除:虚拟化创建是分钟级别的, Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间 •交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。 Docker 在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署
5.斐波那契数列,使用python写出来? 斐波那契数列(Fibonacci sequence),又称黄金分割数列 打印正整数n之内的斐波那契数列 # Python特有, 常规写法 def fib(self, n): a = 0 b = 1 while a <= n: print(a, end=" ", flush=True) a, b = b, a + b # python不借助变量交换两数的值
fib(100) # 求n之内的斐波那契数列 时间复杂度:O(n),空间复杂度:O(1) 递归 打印斐波那契数列前10位数字 # 递归 def fibonacci(i): num_list = [0, 1] if i < 2: return num_list[i] elif i >= 2: return (fibonacci(i - 2) + fibonacci(i - 1))
print(fibonacci(10)) 时间复杂度:O(n),空间复杂度:O(n) 类对象 # 迭代的方式 class FibIterator(object): """斐波那契数列迭代器""" def __init__(self, n): """ :param n: int, 指明生成数列的前n个数 """ self.n = n # current用来保存当前生成到数列中的第几个数了 self.current = 0 # num1用来保存前前一个数,初始值为数列中的第一个数0 self.num1 = 0 # num2用来保存前一个数,初始值为数列中的第二个数1 self.num2 = 1
def __next__(self): """被next()函数调用来获取下一个数""" if self.current < self.n: num = self.num1 self.num1, self.num2 = self.num2, self.num1+self.num2 self.current += 1 return num else: raise StopIteration
def __iter__(self): """迭代器的__iter__返回自身即可""" return self
if __name__ == '__main__': fib = FibIterator(10) for num in fib: print(num, end=" ")
6.实现服务器与业务直接的关系表 用ORm 了解orm,先了解以下概念: ORM是基于对象和数据之间映射技术。 什么是“持久化” 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中, 当然也可以存储在磁盘文件中、XML数据文件中等等。
什么是 “持久层” 持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。
什么是ORM 即Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道, 只要像平时操作对象一样操作它就可以了 。 为什么要做持久化和ORM设计(重要)? 在目前的企业应用系统设计中,MVC,即 Model(模型)- View(视图)- Control(控制)为主要的系统架构模式。 MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑,以及数据存取机制(如 JDBC的连接、SQL生成和Statement创建、还有ResultSet结果集的读取等)等。 将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦 合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。 MVC 模式实现了架构上将表现层(即View)和数据处理层(即Model)分离的解耦合,而持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。 而 ORM 作为持久化设计中的最重要也最复杂的技术,也是目前业界热点技术。 简单来说,按通常的系统设计,使用 JDBC 操作数据库,业务处理逻辑和数据存取逻辑是混杂在一起的。
7.如何实现高并发? 简单阐述: 在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。 但是除了这几个方面,还没法根本解决大型网站面临的高负载和高并发问题。 1、前端HTML 其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。 但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道, 甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能, 对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化, 有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息, 这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化, 这样避免了大量的数据库访问请求。 2、图片服务器分离 大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离, 这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力, 并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持, 尽可能少的LoadModule,保证更高的系统消耗和执行效率。 3、数据库集群和库表散列 大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。 在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。 上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。 我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列, 比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离, 然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。 4、缓存 缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。 架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。 网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,PHP有Pear的Cache模块,Java就更多了,.net不是很熟悉,相信也肯定有。 5、镜像 镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异, 比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。在镜像的细节技术方面, 这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。 6、负载均衡 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。 负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,我个人接触过一些解决方法,其中有两个架构可以给大家做参考。
1)硬件四层交换 第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上, 需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。 在硬件四层交换产品领域,有一些知名的产品可以选择,比如Alteon、F5等,这些产品很昂贵,但是物有所值,能够提供非常优秀的性能和很灵活的管理能力。 Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。 2)软件四层交换 大家知道了硬件四层交换机的原理后,基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致,不过性能稍差。但是满足一定量的压力还是游刃有余的, 有人说软件实现方式其实更灵活,处理能力完全看你配置的熟悉能力。
软件四层交换我们可以使用Linux上常用的LVS来解决,LVS就是Linux Virtual Server,他提供了基于心跳线heartbeat的实时灾难应对解决方案,提高系统的鲁棒性, 同时可供了灵活的虚拟VIP配置和管理功能,可以同时满足多种应用需求,这对于分布式的系统来说必不可少。
一个典型的使用负载均衡的策略就是,在软件或者硬件四层交换的基础上搭建squid集群,这种思路在很多大型网站包括搜索引擎上被采用,这样的架构低成本、 高性能还有很强的扩张性,随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。
8.介绍Restframwork及其中组件? 介绍Restframwork: Restframwork是一个框架,主要实现前后端分离,提供接口API, 对API做一些规范,中文名: 表征状态转移 Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。 通常简称为DRF框架 或 REST framework,DRF框架是建立在Django框架基础之上。 特点: 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化; 提供了丰富的类视图、Mixin扩展类,简化视图的编写; 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要; 多种身份认证和权限认证方式的支持; 内置了限流系统; 直观的 API web 界面; 可扩展性,插件丰富 Rest-framwork的基本流程: Django生命周期: 前端发送请求-->Django的wsgi-->中间件-->路由系统-->视图-->ORM数据库操作-->模板-->返回数据给用户。 Rest framework生命周期: 前端发送请求-->Django的wsgi-->中间件-->路由系统_执行CBV的as_view(),就是执行内部的dispath方法-->在执行dispath之前, 有版本分析 和 渲染器-->在dispath内,对request封装-->版本-->认证-->权限-->限流-->视图--> 如果视图用到缓存( request.data or request.query_params )就用到了 解析器-->视图处理数据,用到了序列化(对数据进行序列化或验证) -->视图返回数据可以用到分页 代码实现: in url.py from django.conf.urls import url, include from web.views.s1_api import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ] in views.py from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def dispatch(self, request, *args, **kwargs): """ 请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法 注意:APIView中的dispatch方法有好多好多的功能 """ return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') def options(self, request, *args, **kwargs): # 复杂请求 例如post请求 # 1、先发options请求,服务端进行预检(不带数据) # 2、通过后,在发送post请求 (带数据) #最好交给中间件来设置这些 response['Access-Control-Allow-Origin'] = "*" # 解决CORS同源策略方式之一 response['Access-Control-Allow-Headers'] = 'content-type' # 尽量不要写 * ,请求头有多少这里就写多少,逗号分隔 response['Access-Control-Allow-Methods'] = '*' # 判断可以通过的请求方式 return Response('PUT请求,响应内容')
9.Django-Rest-framwork中有哪些组件? 1.序列化组件:serializers 对queryset序列化以及对请求数据格式校验 2.路由组件routers 进行路由分发 3.视图组件ModelViewSet 帮助开发者提供了一些类,并在类中提供了多个方法 4.认证组件 写一个类并注册到认证类(authentication_classes),在类的的authticate方法中编写认证逻 5.权限组件 写一个类并注册到权限类(permission_classes),在类的的has_permission方法中编写认证逻辑。 6.频率限制 写一个类并注册到频率类(throttle_classes),在类的的allow_request/wait 方法中编写认证逻辑 7.解析器 选择对数据解析的类,在解析器类中注册(parser_classes) 8.渲染器 定义数据如何渲染到到页面上,在渲染器类中注册(renderer_classes) 9.分页 对获取到的数据进行分页处理, pagination_class 10.版本 版本控制用来在不同的客户端使用不同的行为 在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不同 做不同处理 对于认证,我们一般有三种方式,即cookie, session,token, 1.cookie,是将信息存放在客户端(浏览器上),信息不安全; 2.session,把信息放在服务器数据库中,但是要是信息量较大,对服务器的压力就会大大增加; 3.token采用每次用户登陆后为其设置一个随机字符串,即token值,用户登陆之后,每次访问都带着这个token来访问,服务端只需要验证token值是否正确就可以,相对比较方便使用;所以,我们使用token做认证
restframwork组件的使用 换掉之前使用url链接直接对应视图函数的方式,取代之前render 或者redirect渲染页面返回数据的方式,直接返回json字符数据, 通过get,post,put,delete 等请求协议来实现数据传递,要查看传递的数据可以通过postman插件来浏览。 首先需要编写模型类这里已经准备好了,主要是需要user表与token表。 class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) level = ( (1, 'delux'), (2, 'vip'), (3, 'svip') ) user_level = models.IntegerField(choices=level)
class UserToken(models.Model): token = models.CharField(max_length=128) user = models.OneToOneField('User', on_delete=models.CASCADE) 然后需要编写登陆视图 class Loginview(APIView): # parser_classes = [JSONParser, FormParser] def get(self, request): return render(request, 'login.html')
def post(self, request): ''' code: 200:登陆成功 201:用户名或密码错误 202:其他错误 :param request: :return: ''' res = {'code': None, 'user': None, 'message': None} try: username = request.data.get('username') password = request.data.get('password') user_obj = User.objects.filter(username=username, password=password).first() if user_obj: token_str = str(uuid.uuid4()).replace('-', '') UserToken.objects.update_or_create(user=user_obj, defaults={'token': token_str}) res['code'] = '200' res['user'] = username res['message'] = '登陆成功' res['token'] = token_str else: res['code'] = '201' res['message'] = '用户名或密码错误' except Exception as e: res['code'] = '202' res['message'] = e # print(request.data) # print(self.parser_classes) # res['succsess'] = request.data # res = json.dumps(res) return Response(res) 准备工作做好之后我们来编写认证类,在编写之前需要导入相关的包与模型类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from app01.models import UserToken # model中的模型类 开始编写认证类 class UserAuth(BaseAuthentication): def authenticate(self, request): # 我们模仿get请求页面 token = request.query_params.get("token") # 同request.GET.get("token") # 在token表中查找有么有这次请求携带的token值 user_token_obj = models.UserToken.objects.filter(token=token).first() if user_token_obj: # 如果有值,说明是 正常用户 return user_token_obj.user, user_token_obj.token # 返回 当前的用户对象,和当前的token值,这样源码就会帮我们赋值给request对象了,我们在后面的request中就可以使用了 else: raise AuthenticationFailed("认证失败!") 视图类中只需要加入一行代码 authentication_classes = [UserAuth] # 认证类 这样我们的认证组件就完成了
10.写冒泡排序 实现思路 : 使用双重for循环,内层变量为i, 外层为j,在内层循环中不断的比较相邻的两个值(i, i+1)的大小, 如果i+1的值大于i的值,交换两者位置,每循环一次,外层的j增加1,等到j等于n-1的时候,结束循环。 三种代码实现方法: 方法一: arr = [7, 4, 3, 67, 34, 1, 8] def bubble_sort(arr): n = len(arr) for j in range(0, n - 1): for i in range(0, n - 1 - j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 总结: 关键点其实在双重for循环变量的配置,我们来分析一下 第一次循环: j = 0, i~n-2 range(0, n-1) 第二次循环: j = 1, i~n-3 range(0, n-1-1) 第三次循环: j = 2, i~n-4 range(0, n-1-1-1) —> range(0, n-1-j) 方法二: def bubble_sort2(arr): for j in range(len(arr) - 1, 0, -1): # [n-1, n-2, ....2, 1] for i in range(0, j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort2(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 方法三: def bubble_sort3(arr): for j in range(len(arr)-1, 0, -1): count = 0 for i in range(0, j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i] count += 1 if count == 0: return
bubble_sort3(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 总结:我们在循环中定义了一个变量count,如果第一次循环后count没有变化,就说明输入的是有序序列,这时我们直接return退出循环,这时候的时间复杂度为O(n)
扩展知识:冒泡排序还是一种稳定性的算法,如果序列中出现两个相同的值的时候,无论选取最大值,还是最小值进行排序,最后两个相同值的前后位置都是不变的。
11.谈谈并发编程与网络编程 详见https://www.cnblogs.com/ls13691357174/p/10450054.html
12.什么是消息队列和缓存机制 什么是消息队列: 消息(Message)是指在应用之间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。 消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取, 消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在。
为什么需要消息队列: 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞, 比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多, 从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。 什么是缓存机制: 据库缓存机制 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。 缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。 mysql缓存机制就是缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要在再去解析、优化、执行sql。
13.分库分表怎么操作 ,介绍下
14.前后端分离会有什么问题 我说的是跨域问题
跨域问题的根本原因:浏览器的同源策略限制默认情况下前端页面和后端服务在不同服务器(域名、端口不一样)时,前端页面js无法请求到后端接口服务,即存在跨域问题。 跨域问题的根本原因:因为浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。 什么叫做同源策略?就是不同的域名, 不同端口, 不同的协议不允许共享资源的,保障浏览器安全。 同源策略是针对浏览器设置的门槛。如果绕过浏览就能实现跨域,所以说早期的跨域都是打着安全路数的擦边球,都可以认为是 hack 处理 这里要注意的是,只有访问类型为xhr(XMLHttpRequest)的才会出现跨域。
跨域问题的解决方案: 修改浏览器的设置 修改请求的方式:jsonp 使用CORS来解决 使用nginx代理解决
15.装饰器在cbv和fbv中怎么使用? FBV中的示例:
在views.py中
# 用户认证的装饰器 def auth(func): def inner(request, *args, **kwargs): v = request.COOKIES.get('username') if not v: return redirect('/login/')
return func(request, *args, **kwargs)
return inner
@auth def index(request): # 获取当前已经登录的用户名
v = request.COOKIES.get('username')
print v
if not v: return redirect('/cookie/login/')
return render(request, 'cookie/index.html', {'current_user':v})
CBV中的示例:
# 方法1 from django.utils.decorators import method_decorator
class Order(views.View):
@method_decorator(auth) def get(self, request): pass @method_decorator(auth) def post(self, request): pass
# 方法2
from django.utils.decorators import method_decorator
class Order(views.View):
@method_decorator(auth) def dispatch(self, request, *args, **kwargs): return super(Order, self).dispatch(request, *args, **kwargs)
def get(self, request): pass def post(self, request): pass
# 方法3
from django.utils.decorators import method_decorator
@method_decorator(auth, name='dispatch') class Order(views.View):
#def dispatch(self, request, *args, **kwargs): # return super(Order, self).dispatch(request, *args, **kwargs)
def get(self, request): pass def post(self, request): pass #在用户认证时的一个应用 装饰器: FBV: def auth(func): def inner(reqeust,*args,**kwargs): v = reqeust.COOKIES.get('user') if not v: return redirect('/login') return func(reqeust, *args,**kwargs) return inner CBV: from django import views from django.utils.decorators import method_decorator @method_decorator(auth, name='dispatch') #也可以写到类上, 这样在get,post请求都可以省略, 也可以写在类里面方法上 class Order(views.View): #@method_decorator(auth) #def dispatch(self, request, *args, **kwargs): #return super(Order, self).dispatch(request, *args, **kwargs) #@method_decorator(auth): #只对get请求有效 def get(self, request): v = request.COOKIE.get('username') return render(request, 'index.html', {'current_user': v }) def post(self, request): v = request.COOKIE.get('username') return render(request, 'index.html', {'current_user': v })
16.具体的认证组件怎么写?
17.解释器怎么用?有什么类型?
18.Restframwork的序列化组件怎么用,具体实现方式,及用途?
19. django 的orm是怎么使用的?怎么用?有什么缺点?
ORM的优缺点: 优点: 1)提高开发效率,降低开发成本 2)使开发更加对象化 3)可移植 4)可以很方便地引入数据缓存之类的附加功能 缺点: 1)自动化进行关系数据库的映射需要消耗系统性能。其实这里的性能消耗还好啦,一般来说都可以忽略之。 2)在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。
------------恢复内容开始------------
分布式:
docker熟悉
docker简单理解: Docker 中包括三个基本的概念: •Image(镜像) •Container(容器) •Repository(仓库) 镜像是 Docker 运行容器的前提,仓库是存放镜像的场所,可见镜像更是 Docker 的核心。 Image镜像是什么? Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。 镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义。 Container (容器)是什么? 容器 (container) 的定义和镜像 (image) 几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。 由于容器的定义并没有提及是否要运行容器,所以实际上,容器 = 镜像 + 读写层。 Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。 而 Linux 容器是 Linux 发展出了另一种虚拟化技术,简单来讲, Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离,相当于是在正常进程的外面套了一个保护层。 对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。 Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker ,就不用担心环境问题。 总体来说, Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。 说说docker的Repository (仓库)? Docker 仓库是集中存放镜像文件的场所。镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务, Docker Registry (仓库注册服务器)就是这样的服务。有时候会把仓库 (Repository) 和仓库注册服务器 (Registry) 混为一谈,并不严格区分。Docker 仓库的概念跟 Git 类似, 注册服务器可以理解为 GitHub 这样的托管服务。实际上,一个 Docker Registry 中可以包含多个仓库 (Repository) ,每个仓库可以包含多个标签 (Tag),每个标签对应着一个镜像。 所以说,镜像仓库是 Docker 用来集中存放镜像文件的地方类似于我们之前常用的代码仓库。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。 如果不给出标签,将以 latest 作为默认标签.。 仓库又可以分为两种形式: •public(公有仓库) •private(私有仓库) 简要阐述一下docker的架构? Docker 使用 C/S 结构,即客户端/服务器体系结构。 Docker 客户端与 Docker 服务器进行交互,Docker服务端负责构建、运行和分发 Docker 镜像。 Docker 客户端和服务端可以运行在一台机器上,也可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。 Docker 客户端、服务端和 Docker 仓库(即 Docker Hub 和 Docker Cloud ),默认情况下Docker 会在 Docker 中央仓库寻找镜像文件, 这种利用仓库管理镜像的设计理念类似于 Git ,当然这个仓库是可以通过修改配置来指定的,甚至我们可以创建我们自己的私有仓库。 Docker 的核心组件包括: 1.Docker Client 2.Docker daemon 3.Docker Image 4.Docker Registry 5.Docker Container Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。 客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信。 说出几条你常用的docker的常用命令? 1,我们需要拉取一个 docker 镜像,我们可以用如下命令:docker pull image_name 2,image_name 为镜像的名称,而如果我们想从 Docker Hub 上去下载某个镜像,我们可以使用以下命令:docker pull centos:latest 3,接着我们如果想查看下主机下存在多少镜像,我们可以用如下命令:docker images 4,我们要想知道当前有哪些容器在运行,我们可以用如下命令:docker ps -a 5,我们该如何去对一个容器进行启动,重启和停止呢?我们可以用如下命令: docker start container_name/container_id docker restart container_name/container_id docker stop container_name/container_id docker优点: docker 启动快速属于秒级别。虚拟机通常需要几分钟去启动 •docker 需要的资源更少, docker 在操作系统级别进行虚拟化, docker 容器和内核交互,几乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化 •docker 更轻量, docker 的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境, Docker 运行的镜像数远多于虚拟机数量,对系统的利用率非常高 •与虚拟机相比, docker 隔离性更弱, docker 属于进程之间的隔离,虚拟机可实现系统级别隔离 •安全性: docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。 虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术, 这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击 •可管理性: docker 的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如 VMware vCenter 提供完备的虚拟机管理能力 •高可用和可恢复性: docker 对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡,高可用,容错,迁移和数据保护等经过生产实践检验的成熟保障机制, VMware 可承诺虚拟机 99.999% 高可用,保证业务连续性 •快速创建、删除:虚拟化创建是分钟级别的, Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间 •交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。 Docker 在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署
5.斐波那契数列,使用python写出来? 斐波那契数列(Fibonacci sequence),又称黄金分割数列 打印正整数n之内的斐波那契数列 # Python特有, 常规写法 def fib(self, n): a = 0 b = 1 while a <= n: print(a, end=" ", flush=True) a, b = b, a + b # python不借助变量交换两数的值
fib(100) # 求n之内的斐波那契数列 时间复杂度:O(n),空间复杂度:O(1) 递归 打印斐波那契数列前10位数字 # 递归 def fibonacci(i): num_list = [0, 1] if i < 2: return num_list[i] elif i >= 2: return (fibonacci(i - 2) + fibonacci(i - 1))
print(fibonacci(10)) 时间复杂度:O(n),空间复杂度:O(n) 类对象 # 迭代的方式 class FibIterator(object): """斐波那契数列迭代器""" def __init__(self, n): """ :param n: int, 指明生成数列的前n个数 """ self.n = n # current用来保存当前生成到数列中的第几个数了 self.current = 0 # num1用来保存前前一个数,初始值为数列中的第一个数0 self.num1 = 0 # num2用来保存前一个数,初始值为数列中的第二个数1 self.num2 = 1
def __next__(self): """被next()函数调用来获取下一个数""" if self.current < self.n: num = self.num1 self.num1, self.num2 = self.num2, self.num1+self.num2 self.current += 1 return num else: raise StopIteration
def __iter__(self): """迭代器的__iter__返回自身即可""" return self
if __name__ == '__main__': fib = FibIterator(10) for num in fib: print(num, end=" ")
6.实现服务器与业务直接的关系表 用ORm 了解orm,先了解以下概念: ORM是基于对象和数据之间映射技术。 什么是“持久化” 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中, 当然也可以存储在磁盘文件中、XML数据文件中等等。
什么是 “持久层” 持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。
什么是ORM 即Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道, 只要像平时操作对象一样操作它就可以了 。 为什么要做持久化和ORM设计(重要)? 在目前的企业应用系统设计中,MVC,即 Model(模型)- View(视图)- Control(控制)为主要的系统架构模式。 MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑,以及数据存取机制(如 JDBC的连接、SQL生成和Statement创建、还有ResultSet结果集的读取等)等。 将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦 合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。 MVC 模式实现了架构上将表现层(即View)和数据处理层(即Model)分离的解耦合,而持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。 而 ORM 作为持久化设计中的最重要也最复杂的技术,也是目前业界热点技术。 简单来说,按通常的系统设计,使用 JDBC 操作数据库,业务处理逻辑和数据存取逻辑是混杂在一起的。
7.如何实现高并发? 简单阐述: 在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。 但是除了这几个方面,还没法根本解决大型网站面临的高负载和高并发问题。 1、前端HTML 其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。 但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道, 甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能, 对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化, 有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息, 这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化, 这样避免了大量的数据库访问请求。 2、图片服务器分离 大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离, 这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力, 并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持, 尽可能少的LoadModule,保证更高的系统消耗和执行效率。 3、数据库集群和库表散列 大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。 在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。 上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。 我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列, 比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离, 然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。 4、缓存 缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。 架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。 网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,PHP有Pear的Cache模块,Java就更多了,.net不是很熟悉,相信也肯定有。 5、镜像 镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异, 比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。在镜像的细节技术方面, 这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。 6、负载均衡 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。 负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,我个人接触过一些解决方法,其中有两个架构可以给大家做参考。
1)硬件四层交换 第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上, 需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。 在硬件四层交换产品领域,有一些知名的产品可以选择,比如Alteon、F5等,这些产品很昂贵,但是物有所值,能够提供非常优秀的性能和很灵活的管理能力。 Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。 2)软件四层交换 大家知道了硬件四层交换机的原理后,基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致,不过性能稍差。但是满足一定量的压力还是游刃有余的, 有人说软件实现方式其实更灵活,处理能力完全看你配置的熟悉能力。
软件四层交换我们可以使用Linux上常用的LVS来解决,LVS就是Linux Virtual Server,他提供了基于心跳线heartbeat的实时灾难应对解决方案,提高系统的鲁棒性, 同时可供了灵活的虚拟VIP配置和管理功能,可以同时满足多种应用需求,这对于分布式的系统来说必不可少。
一个典型的使用负载均衡的策略就是,在软件或者硬件四层交换的基础上搭建squid集群,这种思路在很多大型网站包括搜索引擎上被采用,这样的架构低成本、 高性能还有很强的扩张性,随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。
8.介绍Restframwork及其中组件? 介绍Restframwork: Restframwork是一个框架,主要实现前后端分离,提供接口API, 对API做一些规范,中文名: 表征状态转移 Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。 通常简称为DRF框架 或 REST framework,DRF框架是建立在Django框架基础之上。 特点: 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化; 提供了丰富的类视图、Mixin扩展类,简化视图的编写; 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要; 多种身份认证和权限认证方式的支持; 内置了限流系统; 直观的 API web 界面; 可扩展性,插件丰富 Rest-framwork的基本流程: Django生命周期: 前端发送请求-->Django的wsgi-->中间件-->路由系统-->视图-->ORM数据库操作-->模板-->返回数据给用户。 Rest framework生命周期: 前端发送请求-->Django的wsgi-->中间件-->路由系统_执行CBV的as_view(),就是执行内部的dispath方法-->在执行dispath之前, 有版本分析 和 渲染器-->在dispath内,对request封装-->版本-->认证-->权限-->限流-->视图--> 如果视图用到缓存( request.data or request.query_params )就用到了 解析器-->视图处理数据,用到了序列化(对数据进行序列化或验证) -->视图返回数据可以用到分页 代码实现: in url.py from django.conf.urls import url, include from web.views.s1_api import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ] in views.py from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def dispatch(self, request, *args, **kwargs): """ 请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法 注意:APIView中的dispatch方法有好多好多的功能 """ return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') def options(self, request, *args, **kwargs): # 复杂请求 例如post请求 # 1、先发options请求,服务端进行预检(不带数据) # 2、通过后,在发送post请求 (带数据) #最好交给中间件来设置这些 response['Access-Control-Allow-Origin'] = "*" # 解决CORS同源策略方式之一 response['Access-Control-Allow-Headers'] = 'content-type' # 尽量不要写 * ,请求头有多少这里就写多少,逗号分隔 response['Access-Control-Allow-Methods'] = '*' # 判断可以通过的请求方式 return Response('PUT请求,响应内容')
9.Django-Rest-framwork中有哪些组件? 1.序列化组件:serializers 对queryset序列化以及对请求数据格式校验 2.路由组件routers 进行路由分发 3.视图组件ModelViewSet 帮助开发者提供了一些类,并在类中提供了多个方法 4.认证组件 写一个类并注册到认证类(authentication_classes),在类的的authticate方法中编写认证逻 5.权限组件 写一个类并注册到权限类(permission_classes),在类的的has_permission方法中编写认证逻辑。 6.频率限制 写一个类并注册到频率类(throttle_classes),在类的的allow_request/wait 方法中编写认证逻辑 7.解析器 选择对数据解析的类,在解析器类中注册(parser_classes) 8.渲染器 定义数据如何渲染到到页面上,在渲染器类中注册(renderer_classes) 9.分页 对获取到的数据进行分页处理, pagination_class 10.版本 版本控制用来在不同的客户端使用不同的行为 在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不同 做不同处理 对于认证,我们一般有三种方式,即cookie, session,token, 1.cookie,是将信息存放在客户端(浏览器上),信息不安全; 2.session,把信息放在服务器数据库中,但是要是信息量较大,对服务器的压力就会大大增加; 3.token采用每次用户登陆后为其设置一个随机字符串,即token值,用户登陆之后,每次访问都带着这个token来访问,服务端只需要验证token值是否正确就可以,相对比较方便使用;所以,我们使用token做认证
restframwork组件的使用 换掉之前使用url链接直接对应视图函数的方式,取代之前render 或者redirect渲染页面返回数据的方式,直接返回json字符数据, 通过get,post,put,delete 等请求协议来实现数据传递,要查看传递的数据可以通过postman插件来浏览。 首先需要编写模型类这里已经准备好了,主要是需要user表与token表。 class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) level = ( (1, 'delux'), (2, 'vip'), (3, 'svip') ) user_level = models.IntegerField(choices=level)
class UserToken(models.Model): token = models.CharField(max_length=128) user = models.OneToOneField('User', on_delete=models.CASCADE) 然后需要编写登陆视图 class Loginview(APIView): # parser_classes = [JSONParser, FormParser] def get(self, request): return render(request, 'login.html')
def post(self, request): ''' code: 200:登陆成功 201:用户名或密码错误 202:其他错误 :param request: :return: ''' res = {'code': None, 'user': None, 'message': None} try: username = request.data.get('username') password = request.data.get('password') user_obj = User.objects.filter(username=username, password=password).first() if user_obj: token_str = str(uuid.uuid4()).replace('-', '') UserToken.objects.update_or_create(user=user_obj, defaults={'token': token_str}) res['code'] = '200' res['user'] = username res['message'] = '登陆成功' res['token'] = token_str else: res['code'] = '201' res['message'] = '用户名或密码错误' except Exception as e: res['code'] = '202' res['message'] = e # print(request.data) # print(self.parser_classes) # res['succsess'] = request.data # res = json.dumps(res) return Response(res) 准备工作做好之后我们来编写认证类,在编写之前需要导入相关的包与模型类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from app01.models import UserToken # model中的模型类 开始编写认证类 class UserAuth(BaseAuthentication): def authenticate(self, request): # 我们模仿get请求页面 token = request.query_params.get("token") # 同request.GET.get("token") # 在token表中查找有么有这次请求携带的token值 user_token_obj = models.UserToken.objects.filter(token=token).first() if user_token_obj: # 如果有值,说明是 正常用户 return user_token_obj.user, user_token_obj.token # 返回 当前的用户对象,和当前的token值,这样源码就会帮我们赋值给request对象了,我们在后面的request中就可以使用了 else: raise AuthenticationFailed("认证失败!") 视图类中只需要加入一行代码 authentication_classes = [UserAuth] # 认证类 这样我们的认证组件就完成了
10.写冒泡排序 实现思路 : 使用双重for循环,内层变量为i, 外层为j,在内层循环中不断的比较相邻的两个值(i, i+1)的大小, 如果i+1的值大于i的值,交换两者位置,每循环一次,外层的j增加1,等到j等于n-1的时候,结束循环。 三种代码实现方法: 方法一: arr = [7, 4, 3, 67, 34, 1, 8] def bubble_sort(arr): n = len(arr) for j in range(0, n - 1): for i in range(0, n - 1 - j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 总结: 关键点其实在双重for循环变量的配置,我们来分析一下 第一次循环: j = 0, i~n-2 range(0, n-1) 第二次循环: j = 1, i~n-3 range(0, n-1-1) 第三次循环: j = 2, i~n-4 range(0, n-1-1-1) —> range(0, n-1-j) 方法二: def bubble_sort2(arr): for j in range(len(arr) - 1, 0, -1): # [n-1, n-2, ....2, 1] for i in range(0, j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort2(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 方法三: def bubble_sort3(arr): for j in range(len(arr)-1, 0, -1): count = 0 for i in range(0, j): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i] count += 1 if count == 0: return
bubble_sort3(arr) print(arr) # [1, 3, 4, 7, 8, 34, 67] 总结:我们在循环中定义了一个变量count,如果第一次循环后count没有变化,就说明输入的是有序序列,这时我们直接return退出循环,这时候的时间复杂度为O(n)
扩展知识:冒泡排序还是一种稳定性的算法,如果序列中出现两个相同的值的时候,无论选取最大值,还是最小值进行排序,最后两个相同值的前后位置都是不变的。
11.谈谈并发编程与网络编程 详见https://www.cnblogs.com/ls13691357174/p/10450054.html
12.什么是消息队列和缓存机制 什么是消息队列: 消息(Message)是指在应用之间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。 消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取, 消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在。
为什么需要消息队列: 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞, 比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多, 从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。 什么是缓存机制: 据库缓存机制 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。 缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。 mysql缓存机制就是缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要在再去解析、优化、执行sql。
13.分库分表怎么操作 ,介绍下
14.前后端分离会有什么问题 我说的是跨域问题
跨域问题的根本原因:浏览器的同源策略限制默认情况下前端页面和后端服务在不同服务器(域名、端口不一样)时,前端页面js无法请求到后端接口服务,即存在跨域问题。 跨域问题的根本原因:因为浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。 什么叫做同源策略?就是不同的域名, 不同端口, 不同的协议不允许共享资源的,保障浏览器安全。 同源策略是针对浏览器设置的门槛。如果绕过浏览就能实现跨域,所以说早期的跨域都是打着安全路数的擦边球,都可以认为是 hack 处理 这里要注意的是,只有访问类型为xhr(XMLHttpRequest)的才会出现跨域。
跨域问题的解决方案: 修改浏览器的设置 修改请求的方式:jsonp 使用CORS来解决 使用nginx代理解决
15.装饰器在cbv和fbv中怎么使用? FBV中的示例:
在views.py中
# 用户认证的装饰器 def auth(func): def inner(request, *args, **kwargs): v = request.COOKIES.get('username') if not v: return redirect('/login/')
return func(request, *args, **kwargs)
return inner
@auth def index(request): # 获取当前已经登录的用户名
v = request.COOKIES.get('username')
print v
if not v: return redirect('/cookie/login/')
return render(request, 'cookie/index.html', {'current_user':v})
CBV中的示例:
# 方法1 from django.utils.decorators import method_decorator
class Order(views.View):
@method_decorator(auth) def get(self, request): pass @method_decorator(auth) def post(self, request): pass
# 方法2
from django.utils.decorators import method_decorator
class Order(views.View):
@method_decorator(auth) def dispatch(self, request, *args, **kwargs): return super(Order, self).dispatch(request, *args, **kwargs)
def get(self, request): pass def post(self, request): pass
# 方法3
from django.utils.decorators import method_decorator
@method_decorator(auth, name='dispatch') class Order(views.View):
#def dispatch(self, request, *args, **kwargs): # return super(Order, self).dispatch(request, *args, **kwargs)
def get(self, request): pass def post(self, request): pass #在用户认证时的一个应用 装饰器: FBV: def auth(func): def inner(reqeust,*args,**kwargs): v = reqeust.COOKIES.get('user') if not v: return redirect('/login') return func(reqeust, *args,**kwargs) return inner CBV: from django import views from django.utils.decorators import method_decorator @method_decorator(auth, name='dispatch') #也可以写到类上, 这样在get,post请求都可以省略, 也可以写在类里面方法上 class Order(views.View): #@method_decorator(auth) #def dispatch(self, request, *args, **kwargs): #return super(Order, self).dispatch(request, *args, **kwargs) #@method_decorator(auth): #只对get请求有效 def get(self, request): v = request.COOKIE.get('username') return render(request, 'index.html', {'current_user': v }) def post(self, request): v = request.COOKIE.get('username') return render(request, 'index.html', {'current_user': v })
16.具体的认证组件怎么写?
17.解释器怎么用?有什么类型?
18.Restframwork的序列化组件怎么用,具体实现方式,及用途?
19. django 的orm是怎么使用的?怎么用?有什么缺点?
ORM的优缺点: 优点: 1)提高开发效率,降低开发成本 2)使开发更加对象化 3)可移植 4)可以很方便地引入数据缓存之类的附加功能 缺点: 1)自动化进行关系数据库的映射需要消耗系统性能。其实这里的性能消耗还好啦,一般来说都可以忽略之。 2)在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。