我正在使用nginx和uwsgi运行django应用程序。这是我运行uwsgi的方法:
sudo uwsgi -b 25000 --chdir=/www/python/apps/pyapp --module=wsgi:application --env DJANGO_SETTINGS_MODULE=settings --socket=/tmp/pyapp.socket --cheaper=8 --processes=16 --harakiri=10 --max-requests=5000 --vacuum --master --pidfile=/tmp/pyapp-master.pid --uid=220 --gid=499
&nginx配置:
server {
listen 80;
server_name test.com
root /www/python/apps/pyapp/;
access_log /var/log/nginx/test.com.access.log;
error_log /var/log/nginx/test.com.error.log;
# https://docs.djangoproject.com/en/dev/howto/static-files/#serving-static-files-in-production
location /static/ {
alias /www/python/apps/pyapp/static/;
expires 30d;
}
location /media/ {
alias /www/python/apps/pyapp/media/;
expires 30d;
}
location / {
uwsgi_pass unix:///tmp/pyapp.socket;
include uwsgi_params;
proxy_read_timeout 120;
}
# what to serve if upstream is not available or crashes
#error_page 500 502 503 504 /media/50x.html;
}
问题来了。在服务器上执行“ab”(ApacheBenchmark)时,我得到以下结果:
nginx版本:nginx版本:nginx/1.2.6
uwsgi版本:1.4.5
Server Software: nginx/1.0.15
Server Hostname: pycms.com
Server Port: 80
Document Path: /api/nodes/mostviewed/8/?format=json
Document Length: 8696 bytes
Concurrency Level: 100
Time taken for tests: 41.232 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 8866000 bytes
HTML transferred: 8696000 bytes
Requests per second: 24.25 [#/sec] (mean)
Time per request: 4123.216 [ms] (mean)
Time per request: 41.232 [ms] (mean, across all concurrent requests)
Transfer rate: 209.99 [Kbytes/sec] received
在500并发级别上运行时
oncurrency Level: 500
Time taken for tests: 2.175 seconds
Complete requests: 1000
Failed requests: 50
(Connect: 0, Receive: 0, Length: 50, Exceptions: 0)
Write errors: 0
Non-2xx responses: 950
Total transferred: 629200 bytes
HTML transferred: 476300 bytes
Requests per second: 459.81 [#/sec] (mean)
Time per request: 1087.416 [ms] (mean)
Time per request: 2.175 [ms] (mean, across all concurrent requests)
Transfer rate: 282.53 [Kbytes/sec] received
如您所见...服务器上的所有请求均因超时错误或“客户端过早断开连接”而失败,或:
writev(): Broken pipe [proto/uwsgi.c line 124] during GET /api/nodes/mostviewed/9/?format=json
以下是有关我的应用程序的更多信息:
基本上,它是模型的集合,这些模型反射(reflect)了包含所有内容的MySQL表。在前端,我有django-rest-framework,它将json内容提供给客户端。
我已经安装了django-profiling和django调试工具栏以查看发生了什么。在Django分析中,这是我运行单个请求时得到的结果:
Instance wide RAM usage
Partition of a set of 147315 objects. Total size = 20779408 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 63960 43 5726288 28 5726288 28 str
1 36887 25 3131112 15 8857400 43 tuple
2 2495 2 1500392 7 10357792 50 dict (no owner)
3 615 0 1397160 7 11754952 57 dict of module
4 1371 1 1236432 6 12991384 63 type
5 9974 7 1196880 6 14188264 68 function
6 8974 6 1076880 5 15265144 73 types.CodeType
7 1371 1 1014408 5 16279552 78 dict of type
8 2684 2 340640 2 16620192 80 list
9 382 0 328912 2 16949104 82 dict of class
<607 more rows. Type e.g. '_.more' to view.>
CPU Time for this request
11068 function calls (10158 primitive calls) in 0.064 CPU seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.064 0.064 /usr/lib/python2.6/site-packages/django/views/generic/base.py:44(view)
1 0.000 0.000 0.064 0.064 /usr/lib/python2.6/site-packages/django/views/decorators/csrf.py:76(wrapped_view)
1 0.000 0.000 0.064 0.064 /usr/lib/python2.6/site-packages/rest_framework/views.py:359(dispatch)
1 0.000 0.000 0.064 0.064 /usr/lib/python2.6/site-packages/rest_framework/generics.py:144(get)
1 0.000 0.000 0.064 0.064 /usr/lib/python2.6/site-packages/rest_framework/mixins.py:46(list)
1 0.000 0.000 0.038 0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:348(data)
21/1 0.000 0.000 0.038 0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:273(to_native)
21/1 0.000 0.000 0.038 0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:190(convert_object)
11/1 0.000 0.000 0.036 0.036 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:303(field_to_native)
13/11 0.000 0.000 0.033 0.003 /usr/lib/python2.6/site-packages/django/db/models/query.py:92(__iter__)
3/1 0.000 0.000 0.033 0.033 /usr/lib/python2.6/site-packages/django/db/models/query.py:77(__len__)
4 0.000 0.000 0.030 0.008 /usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py:794(execute_sql)
1 0.000 0.000 0.021 0.021 /usr/lib/python2.6/site-packages/django/views/generic/list.py:33(paginate_queryset)
1 0.000 0.000 0.021 0.021 /usr/lib/python2.6/site-packages/django/core/paginator.py:35(page)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/core/paginator.py:20(validate_number)
3 0.000 0.000 0.020 0.007 /usr/lib/python2.6/site-packages/django/core/paginator.py:57(_get_num_pages)
4 0.000 0.000 0.020 0.005 /usr/lib/python2.6/site-packages/django/core/paginator.py:44(_get_count)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:340(count)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:394(get_count)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:568(_prefetch_related_objects)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:1596(prefetch_related_objects)
4 0.000 0.000 0.020 0.005 /usr/lib/python2.6/site-packages/django/db/backends/util.py:36(execute)
1 0.000 0.000 0.020 0.020 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:340(get_aggregation)
5 0.000 0.000 0.020 0.004 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:136(execute)
2 0.000 0.000 0.020 0.010 /usr/lib/python2.6/site-packages/django/db/models/query.py:1748(prefetch_one_level)
4 0.000 0.000 0.020 0.005 /usr/lib/python2.6/site-packages/django/db/backends/mysql/base.py:112(execute)
5 0.000 0.000 0.019 0.004 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:316(_query)
60 0.000 0.000 0.018 0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:231(iterator)
5 0.012 0.002 0.015 0.003 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:278(_do_query)
60 0.000 0.000 0.013 0.000 /usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py:751(results_iter)
30 0.000 0.000 0.010 0.000 /usr/lib/python2.6/site-packages/django/db/models/manager.py:115(all)
50 0.000 0.000 0.009 0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:870(_clone)
51 0.001 0.000 0.009 0.000 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:235(clone)
4 0.000 0.000 0.009 0.002 /usr/lib/python2.6/site-packages/django/db/backends/__init__.py:302(cursor)
4 0.000 0.000 0.008 0.002 /usr/lib/python2.6/site-packages/django/db/backends/mysql/base.py:361(_cursor)
1 0.000 0.000 0.008 0.008 /usr/lib64/python2.6/site-packages/MySQLdb/__init__.py:78(Connect)
910/208 0.003 0.000 0.008 0.000 /usr/lib64/python2.6/copy.py:144(deepcopy)
22 0.000 0.000 0.007 0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:619(filter)
22 0.000 0.000 0.007 0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:633(_filter_or_exclude)
20 0.000 0.000 0.005 0.000 /usr/lib/python2.6/site-packages/django/db/models/fields/related.py:560(get_query_set)
1 0.000 0.000 0.005 0.005 /usr/lib64/python2.6/site-packages/MySQLdb/connections.py:8()
..等等
但是,django-debug-toolbar显示以下内容:
Resource Usage
Resource Value
User CPU time 149.977 msec
System CPU time 119.982 msec
Total CPU time 269.959 msec
Elapsed time 326.291 msec
Context switches 11 voluntary, 40 involuntary
and 5 queries in 27.1 ms
问题是,“最高”显示平均负载快速上升,而我在本地服务器和网络中的远程计算机上均运行的apache基准表明,我每秒没有处理很多请求。
问题是什么?这是我在分析代码时可以达到的范围,因此如果有人可以指出我在这里所做的工作,将不胜感激。
编辑(23/02/2013):根据安德鲁·阿尔考克的答案添加更多详细信息:
需要我注意/回答的要点是
(3)(3)我在MySQL上执行了“显示全局变量”,发现MySQL配置的max_connections设置为151,足以为我正在为uwsgi启动的工作人员提供服务。
(3)(4)(2)我正在分析的单个请求是最重的请求。它根据django-debug-toolbar执行4个查询。发生的是所有查询都在以下位置运行:
分别为3.71、2.83、0.88、4.84 ms。
(4)这里是指内存分页吗?如果是这样,我怎么知道?
(5)在16个 worker 上,并发率100,1000个请求的平均负载达到〜12
我对不同数量的 worker (并发级别为100)进行了测试:
如您所见,我们拥有的工作人员越多,系统上的负载就越大。我在uwsgi的守护程序日志中看到,当我增加工作人员数量时,响应时间(以毫秒为单位)会增加。
在16个工作线程上,运行500个并发级别请求uwsgi将启动loggin错误:
writev(): Broken pipe [proto/uwsgi.c line 124]
负载也上升到〜10。而且测试不会花费很多时间,因为非2xx响应在1000中占923,这就是为什么这里的响应非常快的原因,因为它几乎是空的。这也是对摘要中第4点的答复。
假设我在这里面临的是基于I/O和网络的OS延迟,建议采取什么行动来扩大规模?新硬件?更大的服务器?
谢谢
最佳答案
编辑1 看到您拥有1个虚拟核心的评论,并在所有相关的点上添加了评论
编辑2 来自Maverick的更多信息,因此,我消除了排除在外的想法,并开发了已确认的问题。
编辑3 填写了有关uwsgi请求队列和扩展选项的更多详细信息。改进语法。
编辑4 来自Maverick的更新和较小的改进
评论太少,因此有一些想法:
因此,总而言之:
发展思路
单核计算机上的平均负载> 10实在令人讨厌,并且(如您所观察到的)导致许多任务切换和一般缓慢的行为。我个人不记得看到一台平均负载为19(一台机器有16个进程)的机器-恭喜,它的性能如此之高;)
数据库性能非常好,所以我现在就给出一个清晰的结论。
分页:要回答有关如何查看分页的问题-您可以通过多种方式检测操作系统分页。例如,在顶部,页眉具有页入和页出(请参阅最后一行):
进程:170个进程,3个运行,4个阻塞,163个睡眠,927个线程15:06:31
平均负载:0.90,1.19,1.94 CPU使用率:1.37%用户,2.97%sys,95.65%空闲SharedLibs:144M常驻,0B数据,24Mlinkedit。
内存区域:总计31726个,居民2541万,私有(private)1.2亿,共享8.17亿。 PhysMem:有线1420M, Activity 3548M,未 Activity 1703M,已使用6671M,空闲1514M。
虚拟机:392G vsize,1286M框架vsize,1534241(0)pageins,0(0)pageout。网络:数据包:789684/288M输入,912863/482M输出。磁盘:读取739807/15G,写入996745/24G。
进程数:在当前配置中,进程数太高了。 将进程数缩放回2 。我们可能稍后再调高该值,具体取决于将更多负载转移到该服务器上。
Apache基准测试的位置:一个进程的平均负载为1.85,这向我暗示您正在与uwsgi一起在同一台计算机上运行负载生成器-是正确的吗?
如果是这样,您确实需要从另一台计算机上运行它,否则测试运行不能代表实际负载-您正在从Web进程中获取内存和CPU,以供负载生成器使用。此外,负载生成器的100或500个线程通常会以一种现实生活中不会发生的方式使服务器承受压力。确实,这可能是整个测试失败的原因。
数据库的位置:一个进程的平均负载还表明您正在与Web进程在同一台计算机上运行数据库-这是正确的吗?
如果我对数据库是正确的,那么开始扩展的第一个也是最好的方法是将数据库移至另一台计算机。我们这样做有两个原因:
500并发,但有异常(exception)上图中的请求队列最多为100-如果在队列已满时uwsgi接收到请求,则该请求将被拒绝,并出现5xx错误。我认为这是在您的500个并发负载测试中发生的-基本上队列中充满了前100个左右线程,然后其他400个线程发出了其余900个请求并立即收到5xx错误。
要每秒处理500个请求,您需要确保两件事:
--listen
参数uwsgi
我认为uwsgi的队列设置为较小的数目,以便更好地处理DDoS攻击。如果负载很大,大多数请求将立即失败,几乎不进行任何处理,从而使整个请求箱仍然可以响应管理员。
扩展系统的一般建议
您最重要的考虑因素可能是最大化吞吐量。另一个可能的需求是使响应时间最小化,但是我这里不再讨论。为了最大化吞吐量,您正在尝试最大化系统,而不是单个组件。局部减少可能会提高整体系统吞吐量(例如,进行更改以增加Web层的延迟以提高DB的性能是一种净 yield )。
详细说明:
top
和您最喜欢的MySQL监视工具,在负载测试期间对数据库进行概要分析。您需要能够进行分析。将数据库移到单独的计算机上会为每个请求引入一些额外的延迟(几毫秒),因此期望稍微增加Web层的进程数以保持相同的吞吐量。 uswgi
请求队列足够大,以使用--listen
参数处理突发流量。这应该是系统可以处理的每秒最大稳态请求的几倍。 top
,以确保您的CPU利用率(每个内核)均高于90%,平均负载略高于1.0。如果平均负载较高,请缩减流程。如果一切顺利,在某些时候您将无法实现此目标,DB现在可能成为瓶颈关于python - 不良的Django/uwsgi性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14962289/