选择Google App Engine框架:慎用Django
2009 10 18 09:30 PM 5757次查看
分类:Google App Engine 标签:Google App Engine, 性能
对用户而言,0.5秒以内的响应时间(含网络延迟)比较完美,1秒以内尚可接受,2秒以上就会觉得很慢了。
而我使用的cpedialog,初次访问首页将花费1.9秒的CPU时间和0.7秒的API CPU时间(约1.6秒响应时间,不含网络延迟),紧接着的访问只需0.35秒的CPU时间和0.17秒的API CPU时间(约0.2秒响应时间),隔几分钟后访问则需要1.1秒的CPU时间和0.17秒的API CPU时间(约0.8~1.2秒响应时间)。
由于这个blog我基本不使用,所以只有约5%的概率可以让用户感觉不错,这个性能确实很糟糕。
实际上这和GAE的构架有关。当服务器接到访问时,会去执行该url对应的handler,并将其全局变量缓存起来。再次访问时,如果缓存还存在,那么就使用该缓存,无需重做所有初始化工作。这就大大节省了CPU时间。
而这个缓存的存在时间是不确定的,大约为1分钟。也就是说,假如访问者都不是同时访问的,那么如果网站每天的访问量不到1440,则每个人初次访问的感受都会很慢。
而Django这个庞大的东西就更夸张了,它的启动时间约为1~4秒。如果不是一个访问量很大的网站的话,那么带给用户的感受会是极差的。
如果不介意占用过多的CPU时间(实际上就是你的money),用计划任务每几十秒访问一个小页面,可以让Django实例停留在缓存中。
目前仍无其他办法解决该问题,所以小站还是慎用Django比较好。
话说回来,我这网站的访问量(目前约800页/天)估计是维持不了Django的,所以可能得自己从头设计,或者找个性能不错的小框架算了…
顺便做了个测试,比较了7种方案实现hello world所需的CPU时间(单位:毫秒)。
其中CGI是指直接用print输出。
WSGI是指构造一个WSGI的hello world函数。
Django 1.1使用了app-engine-patch 1.1RC的例子,稍微修改了一下,删去了一些用不到的模块和设置,且直接用HttpResponse()方法输出字符串(未使用模板)。
web.py则使用web.application对象的cgirun()方法,并也缓存了web.application对象。
uliweb则只是缓存了application对象。但uliweb和pytz都包含很多文件,我也没研究出zipimport的方法,应该会很影响速度。
Tornado未经过修改,template模块实际上用不到,但我不知道咋去掉,所以也会影响些性能。
未缓存 | 已缓存 | |
---|---|---|
CGI | 96 | 3 |
WSGI | 96 | 4 |
webapp | 96 | 4 |
Django 1.1 | 1340 | 10 |
web.py 0.32 | 155 | 6 |
uliweb 0.0.1a1 | 427 | 4 |
Tornado 0.2 | 233 | 5 |
而web.py这种小型的框架启动时间也达到了233毫秒,再加上数据库操作和渲染模板,几乎不可能保证0.2秒的响应时间了。不过删掉db、debugerror、template、form、session、browser、test和webopenid的话(注意在application.py里也得去除template),启动时间可以降低到155毫秒,较为接近webapp了,而且还支持惰性加载。
但如果访问量较大的话(保证每分钟至少1次页面访问),使用Django也不错。因为在都已缓存的情况下,各种方案的差距都不大,重点则在自己的代码和数据库操作等时间了,框架则不太影响性能。
值得一提的是,Tornado是唯一会根据内容生成Etag头的(查看源码发现是使用SHA-1):如果第2次访问该网址使用的If-None-Match与将要生成的Etag相同,服务器就会直接返回304状态码,这就减少了传输时间,对于较为静态的页面能节省很多传输时间和流量。经我测试,IE 7、Firefox和Chrome都会接收到304,而IE 6不会去缓存。
综合看起来,似乎没有一个完美的,如果能把webapp改成惰性加载,我应该会选它的。
考虑到Django在已缓存的情况下还算快(约0.01秒),如果用计划任务每30秒访问一个hello world页面,一天也就2880次访问,不到30秒的CPU时间(约合0.0008美元),似乎很划算。但目前计划任务的最短时间间隔是1分钟,可能会在缓存刚过期时才访问。
尚不清楚使用sleep()函数能否延长缓存时间,实在不行的话,只好用任务队列了,这个的速率可以到每秒10次。
另外,对于特别小型的额外页面(我经常会做些小测试和小服务之类的),似乎也没必要放在Django框架下,直接用app.yaml分配,再用webapp处理比较好。对于xmpp和incoming email来说更是如此。
不过对于框架我还有些特殊的要求,希望能把对appspot.com的域名的HTTP访问重定向到apps域名上去,此外还能对部分url自动进行unquote操作(就是为了解析中文网址),而且还要能重用main()函数。
对于前者,webapp可以通过创建多个全局WSGIApplication对象,或者封装WSGIApplication对象来做到,后者则用Decorator封装handler即可。
web.py的处理应该和webapp类似,uliweb似乎很麻烦,而Django我还得研究研究。
向下滚动可载入更多评论,或者点这里禁止自动加载。