Python面试宝典(终极版)

一、Linux与python语法

1. 大数据的文件的读取

2. 迭代器和生成器区别 ?

3. 线程、进程、协程

4. 装饰器

5. 谈谈你对同步异步阻塞非阻塞理解

6. GIL对多线程的影响?

7. python中的反射?

8. python2和python3的区别?

9. 什么是pep8?

10. 什么是线程安全?

11. 十个常用的linux命令?

12. find和grep?

13. 什么是面向对象编程?

14. 面向对象有那些技术?

15. 静态方法和类方法?

16. 类属性、实例属性?

17. 如果你需要执行一个定时任务,你会怎么做?

18. 线上服务可能因为种种原因导致挂掉怎么办?

19. python的多进程与多线程的运行机制是什么?有什么区别?分别在什么情况下用?

20. 如何提高Python的运行效率,请说出不少于2种提高运行效率的方法。

21. 介绍下“消费者”和“生产者”模型。

22. 简述Python的is和==的区别

23. python 的魔法方法

24. 字典取值的方式有哪些?请举例说明

25. python中的True 和 False

26. and 和 or

27. 请至少用两种方法下面字符串的反转

28. 请用至少两种方法删除下面list里面的重复元素

29. 请简述值传递和引用传递的区别

30. 下面代码会输出什么?

31. 匿名函数 lambda

32. Python深拷贝deepcopy与浅拷贝copy

33. 下面代码会输出什么?

34. 补充缺失的代码

35. 介绍一下python的异常处理机制

36. 单例模式

二、数据库

1. 说一下MySQL数据库存储的原理?

2. 事务的特性

3. readis和mysql的区别

4. redis 受攻击怎么办?

5. MongoDB

6. Mysql和redis高可用性

7. 数据库索引

8. 数据库怎么优化查询效率

9. 数据库优化方案

10. Redis mongodb优缺点

11. 数据库负载均衡

12. Mysql集群操作步骤

13. 怎样解决海量数据的存储和访问造成系统设计瓶颈的问题?

14. 你用的mysql是哪个引擎,各引擎间有什么区别

15. redis基本类型、相关方法

16. redis的事务?

17. redis的使用场景有哪些?

18. 怎样解决数据库高并发的问题?

19. redis默认端口,默认过期时间,Value最多可以容纳的数据长度?

20. sqlserver,MySQL ,Oracle  http,redis,https默认端口号?

21. redis有多少个库?

三、网络

1. 网络传输层?

2. 什么是 2MSL?

3. 创建一个简单 tcp 服务器需要的流程?

4. TTL,MSL,RTT?

5. 关于 HTTP/HTTPS 的区别,分别应该在什么场合下。

6. HTTPS 有什么优点和缺点

7.  HTTPS 是如何实现安全传输数据的。

8. get 和 post 请求有什么区别,分别应该在什么场合下。

9. HTTP 请求会有哪些信息发送到后台服务器。

10. 为什么要三次握手和四次挥手?

11. 什么是 URL?

12. 从输入URL到浏览器显示页面发生了什么

四、Django框架

1.你对Django的认识?

2.请解释或描述一下Django的架构

3.Django 的 queryset 什么时候用 Q

答:Q 对象可以使用&(and)、|(or)操作符组合起来,需要进行 or 查询,使

4.django对数据查询结果排序怎么做,降序怎么做,查询大于某个字段怎么做

5.谈谈你对Django事务的理解?

6.AJAX是什么?

7.cookie 和session 的区别?

8.Django整个执行流程?

9.Django 的模板渲染 render 可否增加自定义控制,如何实现

10.跨域请求伪造问题django怎么解决的(原理)

11.Django 如何解决防止暴力破解用户密码

12.说一下Django,MIDDLEWARES中间件的作用?

13.django 文件上传原理

14.django 中当一个用户登录 A 应用服务器(进入登录状态),然后下次请求被 nginx 代理到 B 应用服务器会出现什么影响?

15.ngnix的正向代理与反向代理?

16.Django 本身提供了 runserver,为什么不能用来部署?

17.常见的HTTP状态码有哪些?

18.Post和get区别?

19.uWSGI是什么?

五、爬虫

1. python 爬虫有哪些常用技术?

2. 说一下爬虫程序执行的流程?(框架和三方库均可)?

3. 多线程有哪些模块?

4. 写爬虫是用多进程好?还是多线程好? 为什么?

5. 动态加载又对及时性要求很高怎么处理

6. 谈一谈你对 Selenium 和 PhantomJS 了解

7. 实现模拟登录的方式有哪些?

8. 简单说一下你对 scrapy 的了解?

9. 描述下 scrapy 框架运行的机制?

10. Scrapy 的优缺点?

11. 简单介绍下 scrapy 的异步处理。

12. scrapy 和 request?

13. 爬取下来的数据如何去重,说一下具体的算法依据?

14. scrapy 去重

15. 爬虫在向数据库存数据开始和结束都会发一条消息,是 scrapy 哪个模块实现的?

16. 验证码如何处理

17. 微信公众号数据如何抓取?

18. 动态的股票信息如何抓取

19. 常见的反爬虫和应对方法?

20. 常用的反爬虫措施?

21. 分布式爬虫主要解决什么问题?

22.分布式有哪些方案,哪一种最好?

23. scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?

六、数据结构与算法

1. 桶排序(最快最简单的排序)

2. 斐波那契数列

3. 排序算法的分析

4. 冒泡

5. 快排

一、Linux与python语法

1. 大数据的文件的读取

1. 读取大几G的大文件,可以利用生成器 generator

2. 对可迭代对象 file,进行迭代遍历:for line in file,会自动地使用缓冲IO(buffered IO)以及内存管理,而不必担心任何大文件的问题。

with open('filename') as file:

    for line in file:

        do_things(line)

2. 迭代器和生成器区别 ?

答:(1)迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身 。对于 strings、list、dict、tuple等这类容器对象,使用 for循环遍历是很方便的。在后台 for语句对容器象调用 iter()函数, iter()是 python的内置函数。 iter()会返回一个定义了 next()方法的迭代器对象,它在容器中逐个访问容器内元素, next()也是 python的内置函数。在没有后续元素时调用next()会抛出一个 StopIteration异常

(2)生成器( Generator)是创建迭代器的简单而强大工具。它们写起来就像是正规的函数,只在需要返回据时候使用 yield语句。每次 next()被调用时,生成器会返回它脱离的位置(记忆语句最后一次执行和所有数据 ,生成器会返回它脱离的位置)。

(3)区别:生成器能做到迭代器的所有事,而且因为自动创建了 __iter__()和 next()方法 ,生成器显得特别简洁 ,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省 cup和内存。除了自动创建方法和保存程序状态之外,当发生器终结时,还会自动抛出 StopIteration异常。Yield的用法有点像return,但是它返回的是一个生成器。

3. 线程、进程、协程

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

4. 装饰器

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能

装饰器(decorator)里引入通用功能处理:

引入日志

函数执行时间统计

执行函数前预备处理

执行函数后清理功能

权限校验等场景

缓存

from time import ctime, sleep

def timefun(func):

    def wrappedfunc():

        print("%s called at %s"%(func.__name__, ctime()))

        return func()

    return wrappedfunc

@timefun

def foo():

    print("I am foo")

foo()

>>> foo called at Mon Oct 30 14:58:37 2017

5. 谈谈你对同步异步阻塞非阻塞理解

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的 LRESULT值返回给调用者。

异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsycSocket类为例(注意,CSocket从CAsyncSocket派生,但是起功能已经由异步转化为同步),当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在CSocket中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。socket接收数据的另外一个函数recv则是一个阻塞调用的例子。当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

对象的阻塞模式和阻塞函数调用。对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。

6. GIL对多线程的影响?

GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。)

在Python多线程下,每个线程的执行方式:

1、获取GIL

2、执行代码直到sleep或者是python虚拟机将其挂起。

3、释放GIL        

可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。

在Python2.x里,GIL的释放逻辑是当前线程遇见IO操作或者ticks计数达到100(ticks可以看作是Python自身的一个计数器,专门做用于GIL,每次释放后归零,这个计数可以通过 sys.setcheckinterval 来调整),进行释放。而每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行)。

 IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率),所以多线程对IO密集型代码比较友好。

7. python中的反射?

python中反射的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动。

8. python2和python3的区别?

1.性能 

Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可

以取得很好的优化结果。 

Py3.1性能比Py2.5慢15%,还有很大的提升空间。 

2.编码 

Py3.X源码文件默认使用utf-8编码,这就使得以下代码是合法的: 

    >>> 中国 = 'china' 

    >>>print(中国) 

    china 

3. 语法 

1)去除了<>,全部改用!= 

2)去除``,全部改用repr() 

3)关键词加入as 和with,还有True,False,None 

4)整型除法返回浮点数,要得到整型结果,请使用// 

5)加入nonlocal语句。使用noclocal x可以直接指派外围(非全局)变量 

6)去除print语句,加入print()函数实现相同的功能。同样的还有 exec语句,已经改为exec()函数 

7)改变了顺序操作符的行为,例如x,当x和y类型不匹配时抛出TypeError而不是返回随即的 bool值  

8)输入函数改变了,删除了raw_input,用input代替: 

   2.X:guess = int(raw_input('Enter an integer : ')) # 读取键盘输入的方法 

   3.X:guess = int(input('Enter an integer : '))

9)去除元组参数解包。不能def(a, (b, c)):pass这样定义函数了 

10)新式的8进制字变量,相应地修改了oct()函数。 

11)增加了 2进制字面量和bin()函数 

12)扩展的可迭代解包。在Py3.X 里,a, b, *rest = seq和 *rest, a = seq都是合法的,只要求两点:rest是list 

对象和seq是可迭代的。 

13)新的super(),可以不再给super()传参数, 

14)新的metaclass语法: 

    class Foo(*bases, **kwds): 

      pass 

15)支持class decorator。用法与函数decorator一样: 

4. 字符串和字节串 

1)现在字符串只有str一种类型,但它跟2.x版本的unicode几乎一样。

2)关于字节串,请参阅“数据类型”的第2条目 

5.数据类型 

1)Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long 

2)新增了bytes类型,对应于2.X版本的八位串,定义一个bytes字面量的方法如下: 

   str对象和bytes对象可以使用.encode() (str -> bytes) or .decode() (bytes -> str)方法相互转化。

 3)dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有 

dict.has_key(),用 in替代它吧 

6.面向对象 

1)引入抽象基类(Abstraact Base Classes,ABCs)。 

2)容器类和迭代器类被ABCs化,所以cellections模块里的类型比Py2.5多了很多。 

    >>> import collections 

    >>> print('\n'.join(dir(collections))) 

    Callable     Container     Hashable    ItemsView     Iterable     Iterator     KeysView     Mapping     MappingView     MutableMapping     MutableSequence     MutableSet     NamedTuple    Sequence     Set     Sized     ValuesView     __all__     __builtins__    __doc__     __file__     __name__    _abcoll     _itemgetter     _sys    defaultdict     deque 另外,数值类型也被ABCs化。关于这两点,请参阅 PEP 3119和PEP 3141。 

3)迭代器的next()方法改名为__next__(),并增加内置函数next(),用以调用迭代器的__next__()方法 

4)增加了@abstractmethod和 @abstractproperty两个 decorator,编写抽象方法(属性)更加方便。 

7.异常 

1)所以异常都从 BaseException继承,并删除了StardardError 

2)去除了异常类的序列行为和.message属性 

4)捕获异常的语法改变,引入了as关键字来标识异常实例 

5)异常链,因为__context__在3.0a1版本中没有实现 

8.模块变动 

1)移除了cPickle模块,可以使用pickle模块代替。最终我们将会有一个透明高效的模块。 

2)移除了imageop模块 

3)移除了 audiodev, Bastion, bsddb185, exceptions, linuxaudiodev, md5, MimeWriter, mimify, popen2,  

rexec, sets, sha, stringold, strop, sunaudiodev, timing和xmllib模块 

4)移除了bsddb模块(单独发布,可以从Python "bindings" for Oracle Berkeley DB获取) 

5)移除了new模块 

6)os.tmpnam()和os.tmpfile()函数被移动到tmpfile模块下 

7)tokenize模块现在使用bytes工作。主要的入口点不再是generate_tokens,而是 tokenize.tokenize() 

9.其它 

1)xrange() 改名为range(),要想使用range()获得一个list,必须显式调用: 

    >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

2)bytes对象不能hash,也不支持 b.lower()、b.strip()和b.split()方法,但对于后两者可以使用 b.strip(b’  \n\t\r \f’)和b.split(b’ ‘)来达到相同目的 

3)zip()、map()和filter()都返回迭代器。而apply()、 callable()、coerce()、 execfile()、reduce()和reload ()函数都被去除了现在可以使用hasattr()来替换 callable(). hasattr()的语法如:hasattr(string, '__name__')

4)string.letters和相关的.lowercase和.uppercase被去除,请改用string.ascii_letters 等 

5)如果x < y的不能比较,抛出TypeError异常。2.x版本是返回伪随机布尔值的 

6)__getslice__系列成员被废弃。a[i:j]根据上下文转换为a.__getitem__(slice(I, j))或 __setitem__和 __delitem__调用 

7)file类被废弃

9. 什么是pep8?

9. 什么是pep8?

1变量

常量:大写加下划线 USER_CONSTANT

私有变量 : 小写和一个前导下划线 _private_value

Python 中不存在私有变量一说,若是遇到需要保护的变量,使用小写和一个前导下划线。但这只是程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。但实际上,外部类还是可以访问到这个变量。

内置变量 : 小写,两个前导下划线和两个后置下划线 __class__

两个前导下划线会导致变量在解释期间被更名。这是为了避免内置变量和其他变量产生冲突。用户定义的变量要严格避免这种风格。以免导致混乱。

2 函数和方法

总体而言应该使用,小写和下划线。但有些比较老的库使用的是混合大小写,即首单词小写,之后每个单词第一个字母大写,其余小写。但现在,小写和下划线已成为规范。

私有方法 :小写和一个前导下划线

def _secrete(self):

0

     print "don't test me."

这里和私有变量一样,并不是真正的私有访问权限。同时也应该注意一般函数不要使用两个前导下划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。

特殊方法 :小写和两个前导下划线,两个后置下划线

0

 def __add__(self, other):

0

  

0

   return int.__add__(other)

这种风格只应用于特殊函数,比如操作符重载等。

函数参数 : 小写和下划线,缺省值等号两边无空格

3 类

类总是使用驼峰格式命名,即所有单词首字母大写其余字母小写。类名应该简明,精确,并足以从中理解类所完成的工作。常见的一个方法是使用表示其类型或者特性的后缀,例如:

SQLEngine,MimeTypes对于基类而言,可以使用一个 Base 或者 Abstract 前缀BaseCookie,AbstractGroup

4 模块和包

除特殊模块 __init__ 之外,模块名称都使用不带下划线的小写字母。

若是它们实现一个协议,那么通常使用lib为后缀,例如:

import smtplib

5 关于参数

5.1 不要用断言来实现静态类型检测。断言可以用于检查参数,但不应仅仅是进行静态类型检测。 Python 是动态类型语言,静态类型检测违背了其设计思想。断言应该用于避免函数不被毫无意义的调用。

5.2 不要滥用 *args 和 **kwargs。*args 和 **kwargs 参数可能会破坏函数的健壮性。它们使签名变得模糊,而且代码常常开始在不应该的地方构建小的参数解析器。

6 其他

6.1 使用 has 或 is 前缀命名布尔元素

is_connect = True

0

has_member = False

6.2 用复数形式命名序列

0

members = ['user_1', 'user_2']

6.3 用显式名称命名字典

0

person_address = {'user_1':'10 road WD', 'user_2' : '20 street huafu'}

6.4 避免通用名称

诸如 list, dict, sequence 或者 element 这样的名称应该避免。

6.5 避免现有名称

诸如 os, sys 这种系统已经存在的名称应该避免。

7 一些数字

一行列数 : PEP 8 规定为 79 列。根据自己的情况,比如不要超过满屏时编辑器的显示列数。

一个函数 : 不要超过 30 行代码, 即可显示在一个屏幕类,可以不使用垂直游标即可看到整个函数。

一个类 : 不要超过 200 行代码,不要有超过 10 个方法。一个模块 不要超过 500 行。

8 验证脚本

可以安装一个 pep8 脚本用于验证你的代码风格是否符合 PEP8。

10. 什么是线程安全?

线程安全是在多线程的环境下,能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据可以由多个线程存取,但是同一时刻只能有一个线程进行存取。多线程环境下解决资源竞争问题的办法是加锁来保证存取操作的唯一性。

11. 十个常用的linux命令?

ls,help,cd ,more,clear,mkdir,pwd,rm,grep,find,mv,su,touch,echo,

cat,cp,tree,rmdir,ln,who,top,ps,ifconfig,ping,man,kill 

12. find和grep?

grep命令是一种强大的文本搜索工具,grep搜索内容串可以是正则表达式,允许对文本文件进行模式查找。如果找到匹配模式, grep打印包含模式的所有行。

find通常用来在特定的目录下搜索符合条件的文件,也可以用来搜索特定用户属主的文件。

13. 什么是面向对象编程?

面向对象编程是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

14. 面向对象有那些技术?

类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

实例变量:定义在方法中的变量,只作用于当前实例的类。

继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。

实例化:创建一个类的实例,类的具体对象。

方法:类中定义的函数。

对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

15. 静态方法和类方法?

静态方法:需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数。

类方法:类方法是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(也可以用其他名称的变量作为其第一个参数),能够通过实例对象和类对象去访问。

16. 类属性、实例属性?

类属性:定义在类里面但在函数外面的变量,是静态的。类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本。对于公有的类属性,在类外可以通过类对象和实例对象访问。

实例属性:定义在__init__()方法里的变量就是实例属性,这些属性只有被创建时才会被创建。 

当类属性与实例属性同名时,一个实例访问这个属性时实例属性会覆盖类属性

17. 如果你需要执行一个定时任务,你会怎么做?

Linux的Crontab 执行命令: sudo crontab -e

例:0 */1 * * * /usr/local/etc/rc.d/lighttpd restart  每一小时重启apache

18. 线上服务可能因为种种原因导致挂掉怎么办?

Linux下的后台进程管理利器 supervisor

每次文件修改后在linux执行:service supervisord restart

19. python的多进程与多线程的运行机制是什么?有什么区别?分别在什么情况下用?

运行机制:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

区别:

多进程稳定性好,一个子进程崩溃了,不会影响主进程以及其余进程。但是缺点是创建进程的代价非常大,因为操作系统要给每个进程分配固定的资源,并且,操作系统对进程的总数会有一定的限制,若进程过多,操作系统调度都会存在问题,会造成假死状态。

多线程效率较高一些,但是致命的缺点是任何一个线程崩溃都可能造成整个进程的崩溃,因为它们共享了进程的内存资源池。

使用情况:

如果代码是IO密集型的,多线程。

如果代码是CPU密集型的,多进程是更好的选择——特别是所使用的机器是多核或多CPU的。

20. 如何提高Python的运行效率,请说出不少于2种提高运行效率的方法。

使用生成器

关键代码使用外部功能包:Cython、Pylnlne、PyPy、Pyrex

针对循环的优化——尽量避免在循环中访问变量的属性

21. 介绍下“消费者”和“生产者”模型。

生产者-消费者模型是多线程同步的经典案例。此模型中生产者向缓冲区push数据,消费者从缓冲区中pull数据。

这个Demo中缓冲区用python实现的Queue来做,这个模块是线程安全的使开发者不用再为队列增加额外的互斥锁.

信号处理的实现是这样的:

1)主线程接到一个SIGTERM的信号后先通知Consumer停止向缓冲区push数据并退出

2)Produer将缓冲区中的数据消费完全后在退出

3)主线程退出

生产者消费者模型的优点:

1、解耦

假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化, 可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

2、支持并发

由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。

3、支持忙闲不均

如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。

22. 简述Python的is和==的区别

==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等

is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。

23. python 的魔法方法

魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 __init__,__new__),Python 的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!

__init__ 构造器,当一个实例被创建的时候初始化的方法。但是它并不是实例化调用的第一个方法。

__new__才是实例化对象调用的第一个方法,它只取下 cls 参数,并把其他参数传给 __init__。 __new__很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。

__call__ 允许一个类的实例像函数一样被调用

__getitem__ 定义获取容器中指定元素的行为,相当于 self[key] __getattr__ 定义当用户试图访问一个不存在属性的时候的行为

__setattr__ 定义当一个属性被设置的时候的行为

__getattribute__ 定义当一个属性被访问的时候的行为

24. 字典取值的方式有哪些?请举例说明

A = {'b':1,'c':2}

print a.get('b')

print a['b']

25. python中的True 和 False

1. 在python中,任何对象都可以判断其真假值:True,False

2. 布尔值True被索引求值为1,而False就等于0

3. 比较运算符< > == 等返回的类型就是bool类型

4. False:

l None

l False

l 0

l ()、[ ] 、{ }

5. True:

l 除以上的,其他表达式均会被判定位True

6. 注意布尔运算的优先级低于表达式

7. not a == b 相当于 not (a == b), 若 a == not b 就会有语法错误

26. and 和 or

python中逻辑运算符 and、 or:

and(与): x and y 返回的结果是决定表达式的结果的值。

​ 当x为真时,决定表达式的真假由y的值决定,所有返回y的值

​ 当x为假,则不进行y的判断,返回x

or(与): x or y

​ 当x为假、y为真时返回y的值;

​ 当x为假、y为假时返回y的值;

​ 当x为真,直接返回x的值

27. 请至少用两种方法下面字符串的反转

A=“abcdefg”

1) .A[::-1]

2).交换前后字母的位置

t = list(A)

l = len(t)

for i, j in zip(range(l - 1, 0, -1), range(l // 2)):

        t[i], t[j] = t[j], t[i]

return "".join(t)

3). 递归的方式, 每次输出一个字符

def string_reverse3(string):  

    if len(string)

        return string  

    return string_reverse3(string[1:]) + string[0]

28. 请用至少两种方法删除下面list里面的重复元素

1) .A=list(set(A))

2).A = [1,2,3,4,5,1,5]

List = []

for i in A:

    if I not in List:

     List.append(i)

print List

29. 请简述值传递和引用传递的区别

在一个函数中传递参数,python会根据你传入的数据对象,

自动识别是 值传递 还是 引用传递

若 传入的参数对象是

     可变对象:列表,字典

此时就是 引用传递。如果参数在函数体内被修改,那么源对象也会被修改。

若 传入的参数对象是

     不可变对象:数字,元祖,字符串

此时就是 值传递。源对象是不会被改变的。

值传递仅仅传递的是值

引用传递,传递的是内存地址,修改后会改变内存地址对应储存的值。

30. 下面代码会输出什么?

def f(x,l=[]):

    for i in range(x):

        l.append(i*i)

    print l

f(2)

f(3,[3,2,1])

f(3)

[0, 1]

[3, 2, 1, 0, 1, 4]

[0, 1, 0, 1, 4]

31. 匿名函数 lambda

l Python中对匿名函数提供有限支持

l 只能有一个表达式,不用写return,返回值就是表达式的结果

l 也是一个函数对象,可以赋值给一个变量,用变量来调用

Sum = lambda a,b:a+b

print(Sum(1,2))

>>> 3

32. Python深拷贝deepcopy与浅拷贝copy

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块。 

1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。 

2. copy.deepcopy 深拷贝 拷贝对象及其子对象 

33. 下面代码会输出什么?

import copy  

a = [1, 2, 3, 4, ['a', 'b']]

b = a

c = copy.copy(a)

d = copy.deepcopy(a)

a.append(5)

a[4].append('c')

print a  

print b  

print c  

print d

1. import copy  

2. a = [1, 2, 3, 4, ['a', 'b']] #原始对象  

3.   

4. b = a #赋值,传对象的引用  

5. c = copy.copy(a) #对象拷贝,浅拷贝  

6. d = copy.deepcopy(a) #对象拷贝,深拷贝  

7.   

8. a.append(5) #修改对象a  

9. a[4].append('c') #修改对象a中的['a', 'b']数组对象  

输出结果: 

a = [1, 2, 3, 4, ['a', 'b', 'c'], 5] 

b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] 

c = [1, 2, 3, 4, ['a', 'b', 'c']] 

d = [1, 2, 3, 4, ['a', 'b']]

34. 补充缺失的代码

def print_directory_contents(sPath):

    """    这个函数接受文件夹的名称作为输入参数,    返回该文件夹中文件的路径,    以及其包含文件夹中文件的路径。

    """    

def print_directory_contents(sPath):

    import os                                       

    for sChild in os.listdir(sPath):                

        sChildPath = os.path.join(sPath,sChild)

        if os.path.isdir(sChildPath):

            print_directory_contents(sChildPath)

        else:

            print sChildPath

35. 介绍一下python的异常处理机制

Try:尝试抛出异常

Raise:引发异常

Except:处理异常

Finally:是否发生异常都要做的事

36. 单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

在 Python 中,我们可以用多种方法来实现单例模式:

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

# mysingleton.py

class My_Singleton(object):

    def foo(self):

        pass

my_singleton = My_Singleton()

将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

from mysingleton import my_singleton

my_singleton.foo()

使用__new__

为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

class Singleton(object):

    _instance = None

    def __new__(cls, *args, **kw):

        if not cls._instance:

            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  

        return cls._instance  

class MyClass(Singleton):  

    a = 1

在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance。

执行情况如下:

>>> one = MyClass()

>>> two = MyClass()

>>> one == two

True

>>> one is two

True

>>> id(one), id(two)

(4303862608, 4303862608)

使用装饰器

我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

from functools import wraps

def singleton(cls):

    instances = {}

    @wraps(cls)

    def getinstance(*args, **kw):

        if cls not in instances:

            instances[cls] = cls(*args, **kw)

        return instances[cls]

    return getinstance

@singleton

class MyClass(object):

    a = 1

在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]。

二、数据库

1. 说一下MySQL数据库存储的原理?

答:储存过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式。存储过程通常有以下优点:

1)存储过程能实现较快的执行速度。

2)存储过程允许标准组件是编程。

3)存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

4)存储过程可被作为一种安全机制来充分利用。

5)存储过程能过减少网络流量。

2. 事务的特性

答:

1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。

2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。

3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。

4、持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障

3. readis和mysql的区别

readis是内存数据库,数据保存在内存中,速度快。

mysql是关系型数据库,持久化存储,存放在磁盘里面,功能强大。检索的话,会涉及到一定的IO,数据访问也就慢。

4. redis 受攻击怎么办?

主从

持久化存储

Redis不以root账户启动

设置复杂密码

不允许key方式登录

5. MongoDB

MongoDB是一个面向文档的数据库系统。使用C++编写,不支持SQL,但有自己功能强大的查询语法。

MongoDB使用BSON作为数据存储和传输的格式。BSON是一种类似JSON的二进制序列化文档,支持嵌套对象和数组。

MongoDB很像MySQL,document对应MySQL的row,collection对应MySQL的table

应用场景:

1.网站数据:mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。

  2.缓存:由于性能很高,mongo也适合作为信息基础设施的缓存层。在系统重启之后,由mongo搭建的持久化缓存可以避免下层的数据源过载。

  3.大尺寸、低价值的数据:使用传统的关系数据库存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。

  4.高伸缩性的场景:mongo非常适合由数十或者数百台服务器组成的数据库。

  5.用于对象及JSON数据的存储:mongo的BSON数据格式非常适合文档格式化的存储及查询。

  6.重要数据:mysql,一般数据:mongodb,临时数据:memcache

  7.对于关系数据表而言,mongodb是提供了一个更快速的视图view;而对于PHP程序而言,mongodb可以作为一个持久化的数组来使用,并且这个持久化的数组还可以支持排序、条件、限制等功能。

 8.将mongodb代替mysql的部分功能,主要一个思考点就是:把mongodb当作mysql的一个view(视图),view是将表数据整合成业务数据的关键。比如说对原始数据进行报表,那么就要先把原始数据统计后生成view,在对view进行查询和报表。

不适合的场景:

  a.高度事物性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。

  b.传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。

  c.需要SQL的问题

  d.重要数据,关系数据

优点:弱一致性(最终一致),更能保证用户的访问速度

文档结构的存储方式,能够更便捷的获取数

内置GridFS,高效存储二进制大对象 (比如照片和视频)

支持复制集、主备、互为主备、自动分片等特性

动态查询

全索引支持,扩展到内部对象和内嵌数组

缺点:不支持事务

MongoDB占用空间过大

维护工具不够成熟

6. Mysql和redis高可用性

MySQL Replication是MySQL官方提供的主从同步方案,用于将一个MySQL实例的数据,同步到另一个实例中。Replication为保证数据安全做了重要的保证,也是现在运用最广的MySQL容灾方案。Replication用两个或以上的实例搭建了MySQL主从复制集群,提供单点写入,多点读取的服务,实现了读的scale out.

Sentinel是Redis官方为集群提供的高可用解决方案。 在实际项目中可以使用sentinel去做redis自动故障转移,减少人工介入的工作量。另外sentinel也给客户端提供了监控消息的通知,这样客户端就可根据消息类型去判断服务器的状态,去做对应的适配操作。

下面是Sentinel主要功能列表:

Monitoring:Sentinel持续检查集群中的master、slave状态,判断是否存活。

Notification:在发现某个redis实例死的情况下,Sentinel能通过API通知系统管理员或其他程序脚本。

Automatic failover:如果一个master挂掉后,sentinel立马启动故障转移,把某个slave提升为master。其他的slave重新配置指向新master。

Configuration provider:对于客户端来说sentinel通知是有效可信赖的。客户端会连接sentinel去请求当前master的地址,一旦发生故障sentinel会提供新地址给客户端。

7. 数据库索引

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B_TREE。B_TREE索引加速了数据访问,因为存储引擎不会再去扫描整张表得到需要的数据;相反,它从根节点开始,根节点保存了子节点的指针,存储引擎会根据指针快速寻找数据。

8. 数据库怎么优化查询效率

1.储存引擎选择:如果数据表需要事务处理,应该考虑使用InnoDB,因为它完全符合ACID特性。如果不需要事务处理,使用默认存储引擎MyISAM是比较明智的

2.分表分库,主从,

3.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引

4.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

5.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描

6.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描

7.Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志

8.对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。

9. 数据库优化方案

1. 优化索引、SQL 语句、分析慢查询;

2. 设计表的时候严格根据数据库的设计范式来设计数据库;

3. 使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能

节约磁盘IO;

4. 优化硬件;采用SSD,使用磁盘队列技术(RAID0,RAID1,RDID5)等;

5. 采用MySQL 内部自带的表分区技术,把数据分层不同的文件,能够提高磁

盘的读取效率;

6. 垂直分表;把一些不经常读的数据放在一张表里,节约磁盘I/O;

7. 主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来;

8. 分库分表分机器(数据量特别大),主要的的原理就是数据路由;

9. 选择合适的表引擎,参数上的优化;

10. 进行架构级别的缓存,静态化和分布式;

11. 不采用全文索引;

12. 采用更快的存储方式,例如 NoSQL存储经常访问的数

10. Redis mongodb优缺点

MongoDB和Redis都是NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于二者在内存映射的处理过程,持久化的处理方法不同。MongoDB建议集群部署,更多的考虑到集群方案,Redis更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式.

Redis优点:

1 读写性能优异

2 支持数据持久化,支持AOF和RDB两种持久化方式

3 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

4 数据结构丰富:除了支持string类型的value外还支持string、hash、set、sortedset、list等数据结构。

缺点:

1 Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

2 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。

3 Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。

4 Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。

优点:弱一致性(最终一致),更能保证用户的访问速度

文档结构的存储方式,能够更便捷的获取数

内置GridFS,高效存储二进制大对象 (比如照片和视频)

支持复制集、主备、互为主备、自动分片等特性

动态查询

全索引支持,扩展到内部对象和内嵌数组

缺点:不支持事务

MongoDB占用空间过大

维护工具不够成熟

11. 数据库负载均衡

负载均衡集群是由一组相互独立的计算机系统构成,通过常规网络或专用网络进行连接,由路由器衔接在一起,各节点相互协作、共同负载、均衡压力,对客户端来说,整个群集可以视为一台具有超高性能的独立服务器。

1、实现原理

实现数据库的负载均衡技术,首先要有一个可以控制连接数据库的控制端。在这里,它截断了数据库和程序的直接连接,由所有的程序来访问这个中间层,然后再由中间层来访问数据库。这样,我们就可以具体控制访问某个数据库了,然后还可以根据数据库的当前负载采取有效的均衡策略,来调整每次连接到哪个数据库。

2、实现多据库数据同步

对于负载均衡,最重要的就是所有服务器的数据都是实时同步的。这是一个集群所必需的,因为,如果数不据实时、不同步,那么用户从一台服务器读出的数据,就有别于从另一台服务器读出的数据,这是不能允许的。所以必须实现数据库的数据同步。这样,在查询的时候就可以有多个资源,实现均衡。比较常用的方法是Moebius for SQL Server集群,Moebius for SQL Server集群采用将核心程序驻留在每个机器的数据库中的办法,这个核心程序称为Moebius for SQL Server 中间件,主要作用是监测数据库内数据的变化并将变化的数据同步到其他数据库中。数据同步完成后客户端才会得到响应,同步过程是并发完成的,所以同步到多个数据库和同步到一个数据库的时间基本相等;另外同步的过程是在事务的环境下完成的,保证了多份数据在任何时刻数据的一致性。正因为Moebius 中间件宿主在数据库中的创新,让中间件不但能知道数据的变化,而且知道引起数据变化的SQL语句,根据SQL语句的类型智能的采取不同的数据同步的策略以保证数据同步成本的最小化。

数据条数很少,数据内容也不大,则直接同步数据

数据条数很少,但是里面包含大数据类型,比如文本,二进制数据等,则先对数据进行压缩然后再同步,从而减少网络带宽的占用和传输所用的时间。

数据条数很多,此时中间件会拿到造成数据变化的SQL语句, 然后对SQL语句进行解析,分析其执行计划和执行成本,并选择是同步数据还是同步SQL语句到其他的数据库中。此种情况应用在对表结构进行调整或者批量更改数据的时候非常有用。

3、优缺点

优点:

(1) 扩展性强:当系统要更高数据库处理速度时,只要简单地增加数据库服务器就 可以得到扩展。

(2) 可维护性:当某节点发生故障时,系统会自动检测故障并转移故障节点的应用,保证数据库的持续工作。

(3) 安全性:因为数据会同步的多台服务器上,可以实现数据集的冗余,通过多份数据来保证安全性。另外它成功地将数据库放到了内网之中,更好地保护了数据库的安全性。

(4) 易用性:对应用来说完全透明,集群暴露出来的就是一个IP

缺点:

(1) 不能够按照Web服务器的处理能力分配负载。

(2) 负载均衡器(控制端)故障,会导致整个数据库系统瘫痪。

12. Mysql集群操作步骤

原博客地址

Mysql群集(Cluster)简介

MySQL群集需要有一组计算机,每台计算机的角色可能是不一样的。MySQL群集中有三种节点:管理节点、数据节点和SQL节点。群集中的某计算机可能是某一种节点,也可能是两种或三种节点的集合。这三种节点只是在逻辑上的划分,所以它们不一定和物理计算机是一一对应的关系。

管理节点(也可以称管理服务器)主要负责管理数据节点和SQL节点,还有群集配置文件和群集日志文件。它监控其他节点的工作状态,能够启动、关闭或重启某个节点。其他节点从管理节点检索配置数据,当数据节点有新事件时就把事件信息发送给管理节点并写入群集日志。

数据节点用于存储数据。

    SQL节点跟一般的MySQL服务器是一样的,我们可以通过它进行SQL操作。

用的MysqlServer已经不能满足群集的要求,配置群集需要使用MySQLCluster。

MySQLCluster的配置

    首先找三台电脑,或者是开三个虚拟机,管理节点部署在一台机子上,其他两台每台都部署一个数据节点和一个SQL节点。这里以两台机子举例,其中一台机器A(IP为192.168.193.90)部署管理节点、数据节点和SQL节点,另一台机器B(IP为192.168.193.50)部署数据节点和SQL节点。

     其实最好不要将管理节点跟数据节点部署到一台机子上,因为如果数据节点宕机会导致管理节点也不可用,整个MySQL群集就都不可用了。所以一个MySQL群集理想情况下至少有三台服务器,将管理节点单独放到一台服务器上。暂以两台举例,只是为了说明三种节点的配置启动方法。

将上面下载的安装包解压,并改文件夹名为mysql,因为需要多次在命令行中操作,所以名字改短后更容易输入。

配置管理节点,配置数据节点,配置SQL节点

启动管理节点,启动数据节点,启动SQL节点

测试MySQLCluster:我们需要测试三种情况:

1.在任一SQL节点对数据节点进行操作后,各数据节点是否能够实现数据同步。例如,我们在机器A上新创建一个数据库myDB,然后再建一个表student(新建表如下命令:createtable student (id int(2)) engine=ndbcluster),插入若干数据,接着我们到机器B上查看是否能看到新的数据库myDB和新的表student以及插入数据。

  2.当关闭任一数据节点后,在所有SQL节点中进行操作是否不受其影响。例如,我们关闭机器A上的数据节点服务,在两台主机上应该能够继续对数据库进行各种操作。

3.关闭某数据节点进行了数据库操作,然后重新启动,所有SQL节点的操作是否正常。

13. 怎样解决海量数据的存储和访问造成系统设计瓶颈的问题?

水平切分数据库:可以降低单台机器的负载,同时最大限度的降低了宕机造成的损失;分库降低了单点机器的负载;分表,提高了数据操作的效率,

负载均衡策略:可以降低单台机器的访问负载,降低宕机的可能性;

集群方案:解决了数据库宕机带来的单点数据库不能访问的问题;

读写分离策略:最大限度了提高了应用中读取数据的速度和并发量;

MySQL集群的优缺点

优点:

a)  99.999%的高可用性

b)快速的自动失效切换

c)灵活的分布式体系结构,没有单点故障

d)高吞吐量和低延迟

e)可扩展性强,支持在线扩容

缺点:

a)存在很多限制,比如:不支持外键

b)部署、管理、配置很复杂

c)占用磁盘空间大,内存大

d)备份和恢复不方便

e)重启的时候,数据节点将数据load到内存需要很长时间

14. 你用的mysql是哪个引擎,各引擎间有什么区别

主要 MyISAM 与 InnoDB 两个引擎,其主要区别如下:

一、InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高

级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM

就不可以了;

二、MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到

安全性较高的应用;

三、InnoDB 支持外键,MyISAM 不支持;

四、MyISAM 是默认引擎,InnoDB 需要指定;

五、InnoDB 不支持 FULLTEXT 类型的索引;

六、InnoDB 中不保存表的行数,如 select count(*) from table 时,InnoDB;需要

扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即

可。注意的是,当 count(*)语句包含 where 条件时 MyISAM 也需要扫描整个表;

七、对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM

表中可以和其他字段一起建立联合索引;

八、清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重

建表;

九、InnoDB 支持行锁(某些情况下还是锁整表,如 update table set a=1 where

user like '%lee%'

15. redis基本类型、相关方法

答:Redis支持五种数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)及zset(sorted set:有序集合)。

一、String

String是Redis最为常用的一种数据类型,String的数据结构为key/value类型,String可以包含任何数据。

常用命令:  set,get,decr,incr,mget 等

二、Hash

Hash类型可以看成是一个key/value都是String的Map容器。

常用命令:hget,hset,hgetall 等。

三、List

List用于存储一个有序的字符串列表,常用的操作是向队列两端添加元素或者获得列表的某一片段。

常用命令:lpush,rpush,lpop,rpop,lrange等

四、Set

Set可以理解为一组无序的字符集合,Set中相同的元素是不会重复出现的,相同的元素只保留一个。

常用命令:sadd,spop,smembers,sunion等

五、Sorted Set(有序集合)

有序集合是在集合的基础上为每一个元素关联一个分数,Redis通过分数为集合中的成员进行排序。

常用命令:zadd,zrange,zrem,zcard等

16. redis的事务?

Redis事务允许一组命令在单一步骤中执行。事务有两个属性,说明如下:

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

Redis事务是原子的。原子意味着要么所有的命令都执行,要么都不执行;

一个事务从开始到执行会经历以下三个阶段:

开始事务

命令入队

执行事务

17. redis的使用场景有哪些?

1.取最新N个数据的操作

2.排行榜应用,取TOP N操作

3.需要精准设定过期时间的应用

4.计数器应用

5.uniq操作,获取某段时间所有数据排重值

6.Pub/Sub构建实时消息系统

7.构建队列系统

8.缓存

18. 怎样解决数据库高并发的问题?

解决数据库高并发:

分表分库

数据库索引

redis缓存数据库

读写分离

负载均衡集群:将大量的并发请求分担到多个处理节点。由于单个处理节点的故障不影响整个服务,负载均衡集群同时也实现了高可用性。

19. redis默认端口,默认过期时间,Value最多可以容纳的数据长度?

默认端口:6379

默认过期时间:可以说永不过期,一般情况下,当配置中开启了超出最大内存限制就写磁盘的话,那么没有设置过期时间的key可能会被写到磁盘上。假如没设置,那么REDIS将使用LRU机制,将内存中的老数据删除,并写入新数据。

Value最多可以容纳的数据长度是:512M。

20. sqlserver,MySQL ,Oracle  http,redis,https默认端口号?

sqlserver:1433

MySQL:3306

Oracle :1521

http:40

https:443

redis:6379

21. redis有多少个库?

Redis一个实例下有16个库

三、网络

1. 网络传输层?

应用层—http ftp dns nfs

传输层—tcp --udp

网络层—ip icmp igmp

链路层—data link

物理层—media

2. 什么是 2MSL?

2MSL 即两倍的 MSL,TCP 的 TIME_WAIT 状态也称为 2MSL 等待状态,当 TCP 的一端发起主动关闭,在发出最后一个 ACK 包后,即第 3 次握手完成后发送了第四次握手的 ACK 包后就进入了 TIME_WAIT 状态,必须在此状态上停留两倍的 MSL 时间,等待 2MSL 时间主要目的是怕最后一个 ACK 包对方没收到,那么对方在超时后将重发第三次握手的 FIN 包,主动关闭端接到重发的 FIN 包后可以再发一个 ACK 应答包。在 TIME_WAIT 状态时两端的端口不能使用,要等到 2MSL 时间结束才可继续使用。当连接处于 2MSL 等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置 SO_REUSEADDR 选项达到不必等待 2MSL时间结束再使用此端口。

3. 创建一个简单 tcp 服务器需要的流程?

1.socket 创建一个套接字

2.bind 绑定 ip 和 port

3.listen 使套接字变为可以被动链接

4.accept 等待客户端的链接

5.recv/send 接收发送数据

4. TTL,MSL,RTT?

MSL:报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

TTL:TTL 是 time to live 的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个 ip 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。RFC 793 中规定 MSL 为 2 分钟,实际应用中常用的是 30 秒,1 分钟和 2 分钟等。TTL 与 MSL 是有关系的但不是简单的相等的关系,MSL 要大于等于 TTL。

RTT: RTT 是客户到服务器往返所花时间(round-trip time,简称 RTT),TCP 含有动态估算RTT 的算法。TCP 还持续估算一个给定连接的 RTT,这是因为 RTT 受网络传输拥塞程序的变化而变化。

5. 关于 HTTP/HTTPS 的区别,分别应该在什么场合下。

HTTPS 和 HTTP 的区别:

https 协议需要到 ca 申请证书,一般免费证书很少,需要交费。

http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议

http 和 https 使用的是完全不同的连接方式用的端口也不一样,前者是 80,后者是 443。

http 的连接很简单,是无状态的

HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议 要比 http 协议安全

应用场合:

http:适合于对传输速度,安全性要求不是很高,且需要快速开发的应用。如 web 应用,小的手机游戏等等.

https:https 应该用于任何场景!

6. HTTPS 有什么优点和缺点

优点:

1、使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;

2、HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比

http 协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。

3、HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本

缺点:

1.HTTPS 协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用

2.HTTPS 协议还会影响缓存,增加数据开销和功耗,甚至已有安全措施也会受到影响也会因此而受到影响。

3.SSL 证书需要钱。功能越强大的证书费用越高。个人网站、小网站没有必要一般不会用。

4.HTTPS 连接服务器端资源占用高很多,握手阶段比较费时对网站的相应速度有负面影响。

HTTPS 连接缓存不如 HTTP 高效。

7.  HTTPS 是如何实现安全传输数据的。

HTTPS 其实就是在 HTTP 跟 TCP 中间加多了一层加密层 TLS/SSL。SSL 是个加密套件,负责

对 HTTP 的数据进行加密。TLS 是 SSL 的升级版。现在提到 HTTPS,加密套件基本指的是

TLS。原先是应用层将数据直接给到 TCP 进行传输,现在改成应用层将数据给到 TLS/SSL,

将数据加密后,再给到 TCP 进行传输。

8. get 和 post 请求有什么区别,分别应该在什么场合下。

区别:

get:从指定的服务器中获取数据。

GET 请求能够被缓存

GET 请求会保存在浏览器的浏览记录中

以 GET 请求的 URL 能够保存为浏览器书签

GET 请求有长度限制

GET 请求主要用以获取数据

post:

POST 请求不能被缓存下来

POST 请求不会保存在浏览器浏览记录中

以 POST 请求的 URL 无法保存为浏览器书签

POST 请求没有长度限制

POST 请求会把请求的数据放置在 HTTP 请求包的包体中,POST 的安全性比 GET的高.可能修改变服务器上的资源的请求.

应用场合:

post:请求的结果有持续性的副作用(数据库内添加新的数据行)

若使用 GET 方法,则表单上收集的数据可能让 URL 过长。

要传送的数据不是采用 7 位的 ASCII 编码。

get:请求是为了查找资源,HTML 表单数据仅用来帮助搜索。

请求结果无持续性的副作用。

收集的数据及 HTML 表单内的输入字段名称的总长不超过 1024 个字符

9. HTTP 请求会有哪些信息发送到后台服务器。

请求行 (请求方式、资源路径和 HTTP 协议版本)POST /demo/login HTTP/1.1

请求消息头

消息正文(也叫实体内容) username=xxxx&password=1234

10. 为什么要三次握手和四次挥手?

建立连接的过程是利用客户服务器模式,假设主机 A 为客户端,主机 B 为服务器端。

(1)TCP 的三次握手过程:主机 A 向 B 发送连接请求;主机 B 对收到的主机 A 的报文段进行确认;主机 A 再次对主机 B 的确认进行确认。

(2)采用三次握手是为了防止失效的连接请求报文段突然又传送到主机 B,因而产生错误。失效的连接请求报文段是指:主机 A 发出的连接请求没有收到主机 B 的确认,于是经过一段时间后,主机 A 又重新向主机 B 发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机 A 第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机 B,主机 B 以为是主机 A 又发起的新连接,于是主机 B 同意连接,并向主机A 发回确认,但是此时主机 A 根本不会理会,主机 B 就一直在等待主机 A 发送数据,导致主机 B 的资源浪费。

(3)采用两次握手不行,原因就是上面说的失效的连接请求的特殊情况,因此采用三次握手刚刚好,两次可能出现失效,四次甚至更多次则没必要,反而复杂了

四次挥手:

先由客户端向服务器端发送一个 FIN,请求关闭数据传输。

当服务器接收到客户端的 FIN 时,向客户端发送一个 ACK,其中 ack 的值等于 FIN+SEQ

然后服务器向客户端发送一个 FIN,告诉客户端应用程序关闭。

当客户端收到服务器端的 FIN 是,回复一个 ACK 给服务器端。其中 ack 的值等于 FIN+SEQ

为什么要 4 次挥手?

确保数据能够完成传输

11. 什么是 URL?

URL,即统一资源定位符,也就是我们说的网址,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

12. 从输入URL到浏览器显示页面发生了什么

一、网络通信

互联网内各网络设备间的通信都遵循TCP/IP协议,利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。分层由高到低分别为:应用层、传输层、网络层、数据链路层。发送端从应用层往下走,接收端从数据链路层网上走。如图所示:

0

1. 在浏览器中输入url

    用户输入url,例如http://www.baidu.com。其中http为协议,www.baidu.com为网络地址,及指出需要的资源在那台计算机上。一般网络地址可以为域名或IP地址,此处为域名。使用域名是为了方便记忆,但是为了让计算机理解这个地址还需要把它解析为IP地址。

2.应用层DNS解析域名

   客户端先检查本地是否有对应的IP地址,若找到则返回响应的IP地址。若没找到则请求上级DNS服务器,直至找到或到根节点。

3.应用层客户端发送HTTP请求

HTTP请求包括请求报头和请求主体两个部分,其中请求报头包含了至关重要的信息,包括请求的方法(GET / POST)、目标url、遵循的协议(http / https / ftp…),返回的信息是否需要缓存,以及客户端是否发送cookie等。

4.传输层TCP传输报文

   位于传输层的TCP协议为传输报文提供可靠的字节流服务。它为了方便传输,将大块的数据分割成以报文段为单位的数据包进行管理,并为它们编号,方便服务器接收时能准确地还原报文信息。TCP协议通过“三次握手”等方法保证传输的安全可靠。

  “三次握手”的过程是,发送端先发送一个带有SYN(synchronize)标志的数据包给接收端,在一定的延迟时间内等待接收的回复。接收端收到数据包后,传回一个带有SYN/ACK标志的数据包以示传达确认信息。接收方收到后再发送一个带有ACK标志的数据包给接收端以示握手成功。在这个过程中,如果发送端在规定延迟时间内没有收到回复则默认接收方没有收到请求,而再次发送,直到收到回复为止。

0

5.网络层IP协议查询MAC地址

   IP协议的作用是把TCP分割好的各种数据包传送给接收方。而要保证确实能传到接收方还需要接收方的MAC地址,也就是物理地址。IP地址和MAC地址是一一对应的关系,一个网络设备的IP地址可以更换,但是MAC地址一般是固定不变的。ARP协议可以将IP地址解析成对应的MAC地址。当通信的双方不在同一个局域网时,需要多次中转才能到达最终的目标,在中转的过程中需要通过下一个中转站的MAC地址来搜索下一个中转目标。

6.数据到达数据链路层

   在找到对方的MAC地址后,就将数据发送到数据链路层传输。这时,客户端发送请求的阶段结束

7.服务器接收数据

   接收端的服务器在链路层接收到数据包,再层层向上直到应用层。这过程中包括在运输层通过TCP协议讲分段的数据包重新组成原来的HTTP请求报文。

8.服务器响应请求

   服务接收到客户端发送的HTTP请求后,查找客户端请求的资源,并返回响应报文,响应报文中包括一个重要的信息——状态码。状态码由三位数字组成,其中比较常见的是200 OK表示请求成功。301表示永久重定向,即请求的资源已经永久转移到新的位置。在返回301状态码的同时,响应报文也会附带重定向的url,客户端接收到后将http请求的url做相应的改变再重新发送。404 not found 表示客户端请求的资源找不到。

9. 服务器返回相应文件

   请求成功后,服务器会返回相应的HTML文件。接下来就到了页面的渲染阶段了。

二、页面渲染   

现代浏览器渲染页面的过程是这样的:jiexiHTML以构建DOM树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树。

   DOM树是由HTML文件中的标签排列组成,渲染树是在DOM树中加入CSS或HTML中的style样式而形成。渲染树只包含需要显示在页面中的DOM元素,像

元素或display属性值为none的元素都不在渲染树中。

   在浏览器还没接收到完整的HTML文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送HTTP请求重复上述的步骤。在收到CSS文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。

四、Django框架

1.你对Django的认识?

Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

Django内置的ORM跟框架内的其他模块耦合程度高。

应用程序必须使用Django内置的ORM,否则就不能享受到框架内提供的种种基于其ORM的便利;理论上可以切换掉其ORM模块,但这就相当于要把装修完毕的房子拆除重新装修,倒不如一开始就去毛胚房做全新的装修。

Django的卖点是超高的开发效率,其性能扩展有限;采用Django的项目,在流量达到一定规模后,都需要对其进行重构,才能满足性能的要求。

Django适用的是中小型的网站,或者是作为大型网站快速实现产品雏形的工具。

Django模板的设计哲学是彻底的将代码、样式分离; Django从根本上杜绝在模板中进行编码、处理数据的可能。

2.请解释或描述一下Django的架构

对于Django框架遵循MVC设计,并且有一个专有名词:MVT

M全拼为Model,与MVC中的M功能相同,负责数据处理,内嵌了ORM框架

V全拼为View,与MVC中的C功能相同,接收HttpRequest,业务处理,返回HttpResponse

T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html,内嵌了模板引擎

3.Django 的 queryset 什么时候用 Q 

答:Q 对象可以使用&(and)、|(or)操作符组合起来,需要进行 or 查询,使

用 Q()对象

4.django对数据查询结果排序怎么做,降序怎么做,查询大于某个字段怎么做

排序使用order_by()

降序需要在排序字段名前加-

查询字段大于某个值:使用filter(字段名_gt=值)

5.谈谈你对Django事务的理解?

对于Web请求,Django官方推荐使用中件间TransactionMiddleware来处理请求和响应中的事务。它的工作原理是这样的:当一个请求到来时,Django开始一个事务,如果响应没有出错,Django提交这期间所有的事务,如果view中的函数抛出异常,那么Django会回滚这之间的事务。

如果想在更细粒度的条件下(例如在一个view函数中)控制事务,我们可以使用django.db.transaction。

操作步骤:

1. 在视图上添加装饰器(from django.db import transaction):@transaction.atomic

2. 创建还原点:sid=transaction.savepoint()

3. 失败了回顾到还原点:transaction.savepoint_rollback(sid)

4. 成功了提交:transaction.savepoint_commit(sid)

6.AJAX是什么?

  AJAX的全称是Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

  ajax不是新的编程语言,而是一种使用现有标准的新方法。ajax是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。

  ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

  ajax是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换。ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。而传统的网页(不使用ajax)如果需要更新内容,必须重载整个网页面。

  ajax的应用使用支持以上技术的web浏览器作为运行平台。这些浏览器目前包括:Mozilla、Firefox、Internet Explorer、Opera、Konqueror及Safari。但是Opera不支持XSL格式对象,也不支持XSLT。

  ajax前景非常乐观,可以提高系统性能,优化用户界面。AJAX现有直接框架AjaxPro,可以引入AjaxPro.2.dll文件,可以直接在前台页面JS调用后台页面的方法。但此框架与FORM验证有冲突。另微软也引入了AJAX组建,需要添加AjaxControlToolkit.dll文件,可以在控件列表中出现相关控件。

  ajax的优点:

  1、最大的一点是页面无刷新,用户的体验非常好。

  2、使用异步方式与服务器通信,具有更加迅速的响应能力。。

  3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。

  4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。

  5、ajax可使因特网应用程序更小、更快,更友好。

  ajax的缺点:

  1、ajax不支持浏览器back按钮。

  2、安全问题 AJAX暴露了与服务器交互的细节。

  3、对搜索引擎的支持比较弱。

  4、破坏了程序的异常机制。

  5、不容易调试。

7.cookie 和session 的区别?

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、建议:

   将登陆信息等重要信息存放为SESSION

   其他信息如果需要保留,可以放在COOKIE中

8.Django整个执行流程?

1.url匹配,匹配对应的url

2.调用url匹配成功的view视图

3.运行视图中所编写的逻辑

4.定义上下文

5.将定义的上下文传给对应的模板

6.渲染模板页面

9.Django 的模板渲染 render 可否增加自定义控制,如何实现

通过创建 RequestContext 和 context 处理器来解决这个问题,Conetxt 管理器允许你设置一些变量,它们会在每个 context 中自动被设置好,二不必每次调用 render 时候指定。

10.跨域请求伪造问题django怎么解决的(原理)

启用中间件

post请求

验证码

表单中添加{%csrf_token%}标签

11.Django 如何解决防止暴力破解用户密码

1.用户登录失败,将登录失败次数记录到 cache 中:比如 redis

2.在 5 分钟内连续登录失败 3 次,为了防止暴力破解用户密码行为,此时可在登

录页面提供验证码输入框验证码输入失败,不需要验证账号密码是否正确

如果验证码正确,但是 5 分钟内已经输错了 10 此账号密码,则可以冻结该用户,设置该用户的 is_active 属性为 False;冻结 24 小时,可在 cache 中写一个 TTL 为 24 小时的 Flag,比如以 username 为 key

用户登录时,首先检查是否存在 key 为 username 的 Flag,如果有表明该用户在冻结状态中,因为设置了 is_active 为 False,登录自然会失败

如果 flag 不存在于 cache 中,在检查该密码是否正确,如果正确可设置 is_active

为 True,以恢复期冻结状态

12.说一下Django,MIDDLEWARES中间件的作用?

答:中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。

13.django 文件上传原理

1)当 Django 在处理文件上传的时候,文件数据被保存在 request. FILES,当用户上传一个文件的时候,Django 会把文件数据传递给上传处理器 – 一个小型的类,会在文件数据上传时处理它。上传处理器在 FILE_UPLOAD_HANDLERS 中定义,默认为:

("django.core.files.uploadhandler.MemoryFileUploadHandler",

 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)

MemoryFileUploadHandler 和 TemporaryFileUploadHandler 一 起 提 供 了

Django 的默认文件上传行为,将小文件读取到内存中,大文件放置在磁盘中。你可以编写自定义的处理器,来定制 Django 如何处理文件。例如,你可以使用自定义处理器来限制用户级别的配额,在运行中压缩数据,渲染进度条,甚至是向另一个储存位置直接发送数据,而不把它存到本地。关于如何自定义或者完全替换处理器的行为,详见编写自定义的上传处理器。

2)上传数据在哪里储存在你保存上传文件之前,数据需要储存在某个地方。

通常,如果上传文件小于 2.5MB,Django 会把整个内容存到内存。这意味着,文件的保存仅仅涉及到从内存读取和写到磁盘,所以非常快。

但是,如果上传的文件很大,Django 会把它写入一个临时文件,储存在你系统的临时目录中。在类 Unix 的平台下,你可以认为 Django 生成了一个文件,名称类似于/tmp/tmpzfp6I6.upload。如果上传的文件足够大,你可以观察到文件大小的增长,由于 Django 向磁盘写入数据。

这些特定值 – 2.5 MB,/tmp,以及其它 -- 都仅仅是"合理的默认值",它们可以自定义

14.django 中当一个用户登录 A 应用服务器(进入登录状态),然后下次请求被 nginx 代理到 B 应用服务器会出现什么影响?

如果用户在A应用服务器登陆的session数据没有共享到B应用服务器,那么之前的登录状态就没有了。

15.ngnix的正向代理与反向代理?

答:正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

反向代理正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。

16.Django 本身提供了 runserver,为什么不能用来部署?

runserver 方法是调试 Django 时经常用到的运行方式,它使用 Django 自带的

WSGI Server 运行,主要在测试和开发中使用,并且 runserver 开启的方式也是单进程 。

 uWSGI 是一个 Web 服务器,它实现了 WSGI 协议、uwsgi、http 等协议。注意 uwsgi 是一种通信协议,而 uWSGI 是实现 uwsgi 协议和 WSGI 协议的 Web 服务器。uWSGI 具有超快的性能、低内存占用和多 app 管理等优点,并且搭配着 Nginx

就是一个生产环境了,能够将用户访问请求与应用 app 隔离开,实现真正的部署 。相比来讲,支持的并发量更高,方便管理多进程,发挥多核的优势,提升性能。

17.常见的HTTP状态码有哪些?

17.常见的HTTP状态码有哪些?

200 OK

301 Moved Permanently

302 Found

304 Not Modified

307 Temporary Redirect

400 Bad Request

401 Unauthorized

403 Forbidden

404 Not Found

410 Gone

500 Internal Server Error

501 Not Implemented

18.Post和get区别?

1、GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是unicode,即是说所有的非ASCII字符都要编码之后再传输。

POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。

GET请求的数据会暴露在地址栏中,而POST请求则不会。

2、传输数据的大小

在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。

对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

3、安全性

POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击。

19.uWSGI是什么?

19.uWSGI是什么?

答:uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。uwsgi协议是一个uWSGI服务器自有的协议,它用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型描述,它与WSGI相比是两样东西。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。为什么有了uWSGI为什么还需要nginx?因为nginx具备优秀的静态内容处理能力,然后将动态内容转发给uWSGI服务器,这样可以达到很好的客户端响应。

五、爬虫

1. python 爬虫有哪些常用技术?

Requests,Scrapy,Beautiful Soup,urllib,urllib2

2. 说一下爬虫程序执行的流程?(框架和三方库均可)?

获取想要的页面

根据规则进行解析

解析数据入库

3. 多线程有哪些模块?

在 Python 中可使用的多线程模块主要有两个,thread 和 threading 模块。

Queue。

4. 写爬虫是用多进程好?还是多线程好? 为什么?

IO 密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有 IO 操作会进行 IO 等待,造成不必要的时间浪费,而开启多线程能在线程 A 等待时,自动切换到线程 B,可以不浪费 CPU 的资源,从而能提升程序执行效率)。在实际的数据采集过程中,既考虑网速和响应的问题,也需要考虑自身机器的硬件情况,来设置多进程或多线程。

5. 动态加载又对及时性要求很高怎么处理

Selenium+Phantomjs

尽量不使用 sleep 而使用 WebDriverWait

6. 谈一谈你对 Selenium 和 PhantomJS 了解

Selenium 是一个 Web 的自动化测试工具,可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器。Selenium 库里有个叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以像 BeautifulSoup 或者其他 Selector 对象一样用来查找页面元素,与页面上的元素进行交互 (发送文本、点击等),以及执行其他动作来运行网络爬虫。

PhantomJS 是一个基于 Webkit 的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。

如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。

7. 实现模拟登录的方式有哪些?

1) 使用一个具有登录状态的 cookie,结合请求报头一起发送,可以直接发送 get 请求,访问登录后才能访问的页面。

2) 先发送登录界面的 get 请求,在登录页面 HTML 里获取登录需要的数据(如果需要的话),然后结合账户密码,再发送 post 请求,即可登录成功。然后根据获取的 cookie 信息,继续访问之后的页面。

8. 简单说一下你对 scrapy 的了解?

scrapy 是一个快速(fast)、高层次(high-level)的基于 python 的 web 爬虫构架。用来下载、并解析 web 页面, 其 parse->yield item->pipeline 流程是所有爬虫的固有模式。构造形式主要分 spider.pypipeline.py item.py decorator.py middlewares.py setting.py。

9. 描述下 scrapy 框架运行的机制?

答:从 start_urls 里获取第一批 url 并发送请求,请求由引擎交给调度器入请求队列,获取完毕后,调度器将请求队列里的请求交给下载器去获取请求对应的响应资源,并将响应交给自己编写的解析方法做提取处理:

1. 如果提取出需要的数据,则交给管道文件处理;

2. 如果提取出 url,则继续执行之前的步骤(发送 url 请求,并由引擎将请求交给调度器入队列...),直到请求队列里没有请求,程序结束。

10. Scrapy 的优缺点?

优点:scrapy 是异步的

采取可读性更强的 xpath 代替正则

强大的统计和 log 系统

同时在不同的 url 上爬行

支持 shell 方式,方便独立调试

写 middleware,方便写一些统一的过滤器

通过管道的方式存入数据库

缺点:基于 python 的爬虫框架,扩展性比较差

基于 twisted 框架,运行中的 exception 是不会干掉 reactor,并且异步框架出错后是不会停掉其他任务的,数据出错后难以察觉。

11. 简单介绍下 scrapy 的异步处理。

scrapy 框架的异步机制是基于 twisted 异步网络框架处理的,在 settings.py 文件里可以设置具体的并发量数值(默认是并发量 16)。

12. scrapy 和 request?

scrapy 是封装起来的框架,他包含了下载器,解析器,日志及异常处理,基于多线程, twisted的方式处理,对于固定单个网站的爬取开发,有优势,但是对于多网站爬取 100 个网站,并发及分布式处理方面,不够灵活,不便调整与括展。

request 是一个 HTTP 库, 它只是用来,进行请求,对于 HTTP 请求,他是一个强大的库,下载,解析全部自己处理,灵活性更高,高并发与分布式部署也非常灵活,对于功能可以更好实现.

13. 爬取下来的数据如何去重,说一下具体的算法依据?

1.通过 MD5 生成电子指纹来判断页面是否改变

2.nutch 去重。nutch 中 digest 是对采集的每一个网页内容的 32 位哈希值,如果两个网页内容完全一样,它们的 digest 值肯定会一样。

14. scrapy 去重

数据量不大时,可以直接放在内存里面进行去重,python 可以使用 set()进行去重。

当去重数据需要持久化时可以使用 redis 的 set 数据结构。

当数据量再大一点时,可以用不同的加密算法先将长字符串压缩成 16/32/40 个字符,再使用上面两种方法去重;

当数据量达到亿(甚至十亿、百亿)数量级时,内存有限,必须用“位”来去重,才能够满足需求。Bloomfilter 就是将去重对象映射到几个内存“位”,通过几个位的 0/1 值来判断一个对象是否已经存在。

然而 Bloomfilter 运行在一台机器的内存上,不方便持久化(机器 down 掉就什么都没啦),也不方便分布式爬虫的统一去重。如果可以在 Redis 上申请内存进行 Bloomfilter,以上两个问题就都能解决了。

simhash 最牛逼的一点就是将一个文档,最后转换成一个 64 位的字节,暂且称之为特征字,然后判断重复只需要判断他们的特征字的距离是不是(根据经验这个 n 一般取值为3),就可以判断两个文档是否相似。

15. 爬虫在向数据库存数据开始和结束都会发一条消息,是 scrapy 哪个模块实现的?

答:Item Pipeline scrapy 的信号处理使用的是 dispatch 模块

16. 验证码如何处理

1、Scrapy 自带处理验证码

2、获取到验证码图片的 url,调用第三方付费借口破解验证码

17. 微信公众号数据如何抓取?

sogou 微信搜索数据

18. 动态的股票信息如何抓取

股票数据的获取目前有如下两种方法可以获取:

1.http/JavaScript 接口取数据

2.web-service 接口

Sina 股票数据接口

以大秦铁路(股票代码:601006)为例,如果要获取它的最新行情,只需访问新浪的股票数据

接口:http://hq.sinajs.cn/list=sh601006 这个 url 会返回一串文本,例如 var hq_str_sh601006="

大秦铁路, 27.55, 27.25, 26.91, 27.55, 26.20, 26.91, 26.92,

22114263, 589824680, 4695, 26.91, 57590, 26.90, 14700, 26.89, 14300,

26.88, 15100, 26.87, 3100, 26.92, 8900, 26.93, 14230, 26.94, 25150, 26.95, 15220, 26.96, 2008-

01-11, 15:05:32";

19. 常见的反爬虫和应对方法?

1).通过 Headers 反爬虫

从用户请求的 Headers 反爬虫是最常见的反爬虫策略。很多网站都会对 Headers 的 User-Agent 进行检测,还有一部分网站会对 Referer 进行检测(一些资源网站的防盗链就是检测Referer)。如果遇到了这类反爬虫机制,可以直接在爬虫中添加 Headers,将浏览器的 User-Agent 复制到爬虫的 Headers 中;或者将 Referer 值修改为目标网站域名。对于检测 Headers的反爬虫,在爬虫中修改或者添加 Headers 就能很好的绕过。

2).基于用户行为反爬虫

还有一部分网站是通过检测用户行为,例如同一 IP 短时间内多次访问同一页面,或者同一账户短时间内多次进行相同操作。大多数网站都是前一种情况,对于这种情况,使用 IP 代理就可以解决。可以专门写一个爬虫,爬取网上公开的代理 ip,检测后全部保存起来。这样的代理 ip 爬虫经常会用到,最好自己准备一个。有了大量代理 ip 后可以每请求几次更换一个 ip,这在 requests 或者 urllib2中很容易做到,这样就能很容易的绕过第一种反爬虫。

对于第二种情况,可以在每次请求后随机间隔几秒再进行下一次请求。有些有逻辑漏洞的网站,可以通过请求几次,退出登录,重新登录,继续请求来绕过同一账号短时间内不能多次进行相同请求的限制。

3).动态页面的反爬虫

上述的几种情况大多都是出现在静态页面,还有一部分网站,我们需要爬取的数据是通过ajax 请求得到,或者通过 JavaScript 生成的。首先用 Fiddler 对网络请求进行分析。如果能够找到 ajax 请求,也能分析出具体的参数和响应的具体含义,我们就能采用上面的方法,直接利用 requests 或者 urllib2 模拟 ajax 请求,对响应的 json 进行分析得到需要的数据。

能够直接模拟 ajax 请求获取数据固然是极好的,但是有些网站把 ajax 请求的所有参数全部 加密 了。 我们根 本没 办法 构造 自己所 需要 的数 据的 请求。 这种 情况 下就 用selenium+phantomJS,调用浏览器内核,并利用 phantomJS 执行 js 来模拟人为操作以及触发页面中的 js 脚本。从填写表单到点击按钮再到滚动页面,全部都可以模拟,不考虑具体的请求和响应过程,只是完完整整的把人浏览页面获取数据的过程模拟一遍。

用这套框架几乎能绕过大多数的反爬虫,因为它不是在伪装成浏览器来获取数据(上述的通过添加 Headers 一定程度上就是为了伪装成浏览器),它本身就是浏览器,phantomJS就是一个没有界面的浏览器,只是操控这个浏览器的不是人。利 selenium+phantomJS 能干很多事情,例如识别点触式(12306)或者滑动式的验证码,对页面表单进行暴力破解等。

20. 常用的反爬虫措施?

1.添加代理

2.降低访问频率

3.User-Agent

4.动态 HTML 数据加载

5.验证码处理

6. Cookie

21. 分布式爬虫主要解决什么问题?

1)ip

2)带宽

3)cpu

4)io

22.分布式有哪些方案,哪一种最好?

celery、beanstalk,gearman

个人认为 gearman 比较好。原因主要有以下几点:

1).技术类型简单,维护成本低。

2).简单至上。能满足当前的技术需求即可 (分布式任务处理、异步同步任务同时支持、任务队列的持久化、维护部署简单)。

3).有成熟的使用案例。instagram 就是使用的 gearman 来完成图片的处理的相关任务,

有成功的经验,我们当然应该借鉴。

23. scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?

1) scrapy 是一个 Python 爬虫框架,爬取效率极高,具有高度定制性,但是不支持分布式。而 scrapy-redis 一套基于 redis 数据库、运行在 scrapy 框架之上的组件,可以让 scrapy 支持分布式策略,Slaver 端共享 Master 端 redis 数据库里的 item 队列、请求队列和请求指纹集合。

2) 为什么选择 redis 数据库,因为 redis 支持主从同步,而且数据都是缓存在内存中的,所以基于 redis 的分布式爬虫,对请求和数据的高频读取效率非常高。

六、数据结构与算法

1. 桶排序(最快最简单的排序)

桶排序的基本思想是将一个数据表分割成许多buckets,然后每个bucket各自排序,或用不同的排序算法,或者递归的使用bucket sort算法。也是典型的divide-and-conquer分而治之的策略。它是一个分布式的排序,介于MSD基数排序和LSD基数排序之间

def bucketSort(nums):

    # 选择一个最大的数

    max_num = max(nums)

    # 创建一个元素全是0的列表, 当做桶

    bucket = [0]*(max_num+1)

    # 把所有元素放入桶中, 即把对应元素个数加一

    for i in nums:

        bucket[i] += 1

    # 存储排序好的元素

    sort_nums = []

    # 取出桶中的元素

    for j in range(len(bucket)):

        if bucket[j] != 0:

            for y in range(bucket[j]):

                sort_nums.append(j)

    return sort_nums

nums = [5,6,3,2,1,65,2,0,8,0]

print bucketSort(nums)

1、桶排序是稳定的

2、桶排序是常见排序里最快的一种, 大多数情况下比快排还要快

3、桶排序非常快,但是同时也非常耗空间,基本上是最耗空间的一种排序算法

2. 斐波那契数列

斐波那契数列:简单地说,起始两项为0和1,此后的项分别为它的前两项之和。

def fibo(num):

    numList = [0,1]

    for i in range(num - 2):

        numList.append(numList[-2] + numList[-1])

    return numList

3. 排序算法的分析

排序算法的稳定性:如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

时间开销:排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。

算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销:算法执行时所需的附加存储。

4. 冒泡

冒泡排序的思想: 每次比较两个相邻的元素, 如果他们的顺序错误就把他们交换位置。

def bubble_improve(l):  

    print l  

    flag = 1  

    for index in range(len(l) - 1, 0 , -1):  

        if flag:  

            flag = 0  

            for two_index in range(index):  

                if l[two_index] > l[two_index + 1]:  

                    l[two_index], l[two_index + 1] = l[two_index + 1], l[two_index]  

                    flag = 1  

        else:  

            break  

    print l  

l = [10, 20, 40, 50, 30, 60]  

bubble_improve(l)

5. 快排

快速排序使用分治法策略来把一个序列分为两个子序列。

步骤:

从数列中挑出一个元素,称为 "基准"(pivot),

重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作。

递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

def quickSort(alist,first,last):

   if first

       splitpoint = findpos(alist,first,last)

       quickSort(alist,first,splitpoint-1)

       quickSort(alist,splitpoint+1,last)

def findpos(lists, low, high):

    key = lists[low]

    while low < high:

       while low < high and lists[high] >= key:

           high -= 1

       lists[low] = lists[high]

       while low < high and lists[low]

           low += 1

       lists[high] = lists[low]

    lists[low] = key

    return low

alist = [54,26,93,17,77,31,44,55,20]

quickSort(alist,0,8)

print(alist)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学习的小初雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值