怎么测django并发量(django并发量过大出现异常)

请教下,怎么测django并发量(django并发量过大出现异常)
最新回答
罂语

2024-12-02 06:13:33

导读:本篇文章首席CTO笔记来给大家介绍有关怎么测django并发量的相关内容,希望对大家有所帮助,一起来看看吧。

如何有效的遍历django的QuerySet

最近做了一个小的需求,在django模型中通过前台页面的表单的提交

(post),后台对post的参数进行解析,通过models模型查询MySQL,将数据结构进行加工,返回到前台页面进行展示。由于对django中

QuerySet特性的不熟悉,所以测试过程中发现了很多问题。

开始的阶段没有遇到什么问题,我们举例,在models有一张员工表

employee,对应的表结构中,postion列表示员工职位,前台post过来的参数赋给position,加上入职时间、离职时间,查询操作通过

models.filter(position=params)完成,获取的员工信息内容由QuerySet和当前展示页与每页展示的记录数进行简单的计

算,返回给前台页面进行渲染展示。编码如下:

1defget_employees(position,start,end):

2returnemployee.objects.filter(alert_time__lt=end,alert_time__gt=start).filter(position__in=position)

3

4

5@login_required

6defshow(request):

7ifnotvalidate(request):

8returnrender_to_response('none.html',

9context_instance=RequestContext(request,'msg':'paramserror')

10)

11

12position=request.REQUEST.get('position')

13time_range=request.REQUEST.get('time')

14start,end=time_range[0],time_range[1]

15

16num_per_page,page_num=get_num(request)

17all_employees=get_employees(position,start,end)

18#根据当前页与每页展示的记录数,取到正确的记录

19employees=employees_events[(page_num-1)*num_per_page:page_num*num_per_page]

20

21returnrender_to_response('show_employees.html',

22context_instance=RequestContext(

23request,

24'employees':employees,

25'num_per_page':num_per_page,

26'page_num':page_num,

27'page_options':[50,100,200]

28)

29)

运行之后可以正确的对所查询的员工信息进行展示,并且查询速度很快。

employee表中存放着不同职位的员工信息,不同类型的详细内容也不相同,假设employees有一列名为infomation,存储的是员工的详

细信息,infomation={'age':33,'gender':'male','nationality':'German',

'degree':'doctor','motto':'justdo

it'},现在的需求是要展示出分类更细的员工信息,前台页面除了post职位、入职离职时间外,还会对infomation中的内容进行筛选,这里以查

询中国籍的设计师为例,在之前的代码基础上,需要做一些修改。员工信息表employee存放于MySQL中,而MySQL为ORM数据库,它并未提供类

似mongodb一样更为强大的聚合函数,所以这里不能通过objects提供的方法进行filter,一次性将所需的数据获取出来,那么需要对type

进行过滤后的数据,进行二次遍历,通过information来确定当前记录是否需要返回展示,在展示过程中,需要根据num_per_page和

page_num计算出需要展示数据起始以及终止位置。

1defget_employees(position,start,end):

2returnemployee.objects.filter(alert_time__lt=end,alert_time__gt=start).filter(position__in=position)

3

4

5deffilter_with_nation(all_employees,nationality,num_per_page,page_num):

6result=[]

7

8pos=(page_num-1)*num_per_page

9cnt=0

10start=False

11foremployeeinall_employees:

12info=json.loads(employee.information)

13ifinfo.nationality!=nationality:

14continue

15

16#获取的数据可能并不是首页,所以需要先跳过前n-1页

17ifcnt==pos:

18ifstart:

19break

20cnt=0

21pos=num_per_page

22start=True

23

24ifstart:

25result.append(employee)

26

27returnemployee

28

29

30@login_required

31defshow(request):

32ifnotvalidate(request):

33returnrender_to_response('none.html',

34context_instance=RequestContext(request,'msg':'paramserror')

35)

36

37position=request.REQUEST.get('position')

38time_range=request.REQUEST.get('time')

39start,end=time_range[0],time_range[1]

40

41num_per_page,page_num=get_num(request)

42all_employees=get_employees(position,start,end)

43

44nationality=request.REQUEST.get('nationality')

45

46employees=filter_with_nation(all_employees,num_per_page,page_num)

47

48returnrender_to_response('show_employees.html',

49context_instance=RequestContext(

50request,

51'employees':employees,

52'num_per_page':num_per_page,

53'page_num':page_num,

54'page_options':[50,100,200]

55)

56)

当编码完成之后,在数据employee表数据很小的情况下测试并未发现问

题,而当数据量非常大,并且查询的数据很少时,代码运行非常耗时。我们设想,这是一家规模很大的跨国公司,同时人员的流动量也很大,所以employee

表的数据量很庞大,而这里一些来自于小国家的员工并不多,比如需要查询国籍为梵蒂冈的员工时,前台页面进入了无尽的等待状态。同时,监控进程的内存信息,

发现进程的内存一直在增长。毫无疑问,问题出现在filter_with_nation这个函数中,这里逐条遍历了employee中的数据,并且对每条

数据进行了解析,这并不是高效的做法。

在网上查阅了相关资料,了解到:

1Django的queryset是惰性的,使用filter语句进行查询,实际上并没有运行任何的要真正从数据库获得数据

2只要你查询的时候才真正的操作数据库。会导致执行查询的操作有:对QuerySet进行遍历queryset,切片,序列化,对QuerySet应用list()、len()方法,还有if语句

3当第一次进入循环并且对QuerySet进行遍历时,Django从数据库中获取数据,在它返回任何可遍历的数据之前,会在内存中为每一条数据创建实例,而这有可能会导致内存溢出。

上面的原来很好的解释了代码所造成的现象。那么如何进行优化是个问题,网上有

说到当QuerySet非常巨大时,为避免将它们一次装入内存,可以使用迭代器iterator()来处理,但对上面的代码进行修改,遍历时使用

employee.iterator(),而结果和之前一样,内存持续增长,前台页面等待,对此的解释是:usingiterator()

willsaveyousomememorybynotstoringtheresultofthecache

internally(thoughnotnecessarilyonPostgreSQL!);butwillstill

retrievethewholeobjectsfromthedatabase。

这里我们知道不能一次性对QuerySet中所有的记录进行遍历,那么只能对

QuerySet进行切片,每次取一个chunk_size的大小,遍历这部分数据,然后进行累加,当达到需要的数目时,返回满足的对象列表,这里修改下

filter_with_nation函数:

1deffilter_with_nation(all_employees,nationality,num_per_page,page_num):

2result=[]

3

4pos=(page_num-1)*num_per_page

5cnt=0

6start_pos=0

7start=False

8whileTrue:

9employees=all_employees[start_pos:start_pos+num_per_page]

10start_pos+=num_per_page

11

12foremployeeinemployees:

13info=json.loads(employee.infomation)

14ifinfo.nationality!=nationality:

15continue

16

17ifcnt==pos:

18ifstart:

19break

20cnt=0

21pos=num_per_page

22start=True

23

24ifstart:

25result.append(opt)

26

27cnt+=1

28

29ifcnt==num_per_pageornotevents:

30break

31

32returnresult

运行上述代码时,查询的速度更快,内存也没有明显的增长,得到效果不错的优

化。这篇文章初衷在于记录自己对django中queryset的理解和使用,而对于文中的例子,其实正常业务中,如果需要记录员工详细的信息,最好对

employee表进行扩充,或者建立一个字表,存放详细信息,而不是将所有信息存放入一个字段中,避免在查询时的二次解析。

python中django的问题--------请高人指点尽量详细点哦初学django

django的模块一般都不能单独执行,如果是用的命令行,要使用pythonmanage.pyshell,而不要直接使用python

如何用nginx关联django应用

通过Nginx部署Django(基于ubuntu)

Django的部署可以有很多方式,采用nginx+uwsgi的方式是其中比较常见的一种方式。

在这种方式中,我们的通常做法是,将nginx作为服务器最前端,它将接收WEB的所有请求,统一管理请求。nginx把所有静态请求自己来处理(这是NGINX的强项)。然后,NGINX将所有非静态请求通过uwsgi传递给Django,由Django来进行处理,从而完成一次WEB请求。

可见,uwsgi的作用就类似一个桥接器。起到桥梁的作用。

Linux的强项是用来做服务器,所以,下面的整个部署过程我们选择在Ubuntu下完成。

一、安装Nginx

Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好。

Nginx同样为当前非常流行的web服务器。利用其部署Django,我们在此也做简单的介绍。

Nginx官网:

打开ubuntu控制台(ctrl+alt+t)利用Ubuntu的仓库安装。

fnngj@ubuntu:~$sudoapt-getinstallnginx#安装

启动Nginx:

fnngj@ubuntu:~$/etc/init.d/nginxstart#启动

fnngj@ubuntu:~$/etc/init.d/nginxstop#关闭

fnngj@ubuntu:~$/etc/init.d/nginxrestart#重启

修改Nginx默认端口号,打开/etc/nginx/nginx.conf文件,修改端口号。

复制代码

server{

listen8088;#修改端口号

server_namelocalhost;

#charsetkoi8-r;

#access_loglogs/host.access.logmain;

location/{

roothtml;

indexindex.htmlindex.htm;

}

复制代码

大概在文件36行的位置,将默认的80端口号改成其它端口号,如8088。因为默认的80端口号很容易被其它应用程序占用。

然后,通过上面命令重启nginx。访问:http//127.0.0.1:8088/

如果出现如上图,说明Nginx启动成功。

二、安装uwsgi

通过pip安装uwsgi。

root@ubuntu:/etc#python3-mpipinstalluwsgi

测试uwsgi,创建test.py文件:

defapplication(env,start_response):

start_response('200OK',[('Content-Type','text/html')])

return[b"HelloWorld"]

通过uwsgi运行该文件。

fnngj@ubuntu:~/pydj$uwsgi--http:8001--wsgi-filetest.py

接下来配置Django与uwsgi连接。此处,假定的我的django项目位置为:/home/fnngj/pydj/myweb

fnngj@ubuntu:~/pydj$uwsgi--http:8001--chdir/home/fnngj/pydj/myweb/--wsgi-filemyweb/wsgi.py--master--processes4--threads2--stats127.0.0.1:9191

常用选项:

http:协议类型和端口号

processes:开启的进程数量

workers:开启的进程数量,等同于processes(官网的说法是spawnthespecifiednumberofworkers/processes)

chdir:指定运行目录(chdirtospecifieddirectorybeforeappsloading)

wsgi-file:载入wsgi-file(load.wsgifile)

stats:在指定的地址上,开启状态服务(enablethestatsserveronthespecifiedaddress)

threads:运行线程。由于GIL的存在,我觉得这个真心没啥用。(runeachworkerinprethreadedmodewiththespecifiednumberofthreads)

master:允许主进程存在(enablemasterprocess)

daemonize:使进程在后台运行,并将日志打到指定的日志文件或者udp服务器(daemonizeuWSGI)。实际上最常用的,还是把运行记录输出到一个本地文件上。

pidfile:指定pid文件的位置,记录主进程的pid号。

vacuum:当服务器退出的时候自动清理环境,删除unixsocket文件和pid文件(trytoremoveallofthegeneratedfile/sockets)

三、Nginx+uwsgi+Django

接下来,我们要将三者结合起来。首先罗列一下项目的所需要的文件:

myweb/

├──manage.py

├──myweb/

│├──__init__.py

│├──settings.py

│├──urls.py

│└──wsgi.py

└──myweb_uwsgi.ini

在我们通过Django创建myweb项目时,在子目录myweb下已经帮我们生成的wsgi.py文件。所以,我们只需要再创建myweb_uwsgi.ini配置文件即可,当然,uwsgi支持多种类型的配置文件,如xml,ini等。此处,使用ini类型的配置。

复制代码

#myweb_uwsgi.inifile

[uwsgi]

#Django-relatedsettings

socket=:8000

#thebasedirectory(fullpath)

chdir=/home/fnngj/pydj/myweb

#Djangoswsgifile

module=myweb.wsgi

#process-relatedsettings

#master

master=true

#maximumnumberofworkerprocesses

processes=4

#...withappropriatepermissions-maybeneeded

#chmod-socket=664

#clearenvironmentonexit

vacuum=true

复制代码

这个配置,其实就相当于在上一小节中通过wsgi命令,后面跟一堆参数的方式,给文件化了。

socket指定项目执行的端口号。

chdir指定项目的目录。

modulemyweb.wsgi,可以这么来理解,对于myweb_uwsgi.ini文件来说,与它的平级的有一个myweb目录,这个目录下有一个wsgi.py文件。

其它几个参数,可以参考上一小节中参数的介绍。

接下来,切换到myweb项目目录下,通过uwsgi命令读取myweb_uwsgi.ini文件启动项目。

复制代码

fnngj@ubuntu:~$cd/home/fnngj/pydj/myweb/

fnngj@ubuntu:~/pydj/myweb$uwsgi--inimyweb_uwsgi.ini

[uWSGI]gettingINIconfigurationfrommyweb_uwsgi.ini

***StartinguWSGI2.0.12(32bit)on[SatMar1213:05:062016]***

compiledwithversion:4.8.4on26January201606:14:41

os:Linux-3.19.0-25-generic#26~14.04.1-UbuntuSMPFriJul2421:18:00UTC2015

nodename:ubuntu

machine:i686

clocksource:unix

detectednumberofCPUcores:2

currentworkingdirectory:/home/fnngj/pydj/myweb

detectedbinarypath:/usr/local/bin/uwsgi

!!!nointernalroutingsupport,rebuildwithpcresuppor