我们的Web开发与部署 -- 一名python党

2012-11-30 17:43:04 +08:00
 hepochen
不知道Markdown格式会变成什么样子,原文地址如下:

http://ued.com.cn/post/tech/web-dev-and-deploy

## 背景

最近做了一个产品,原本估计10来天就足够了;idea虽然简单,但产品化的过程中,时间超了几番。

我们在用Amazon的AWS服务,后台语言是python,Web框架使用了Flask,数据库为Mongodb;前端Web服务器Nginx,Application服务器Gunicorn;驱动Web的数据任务使用的是Gevent。

前端框架?呃,这次没用。以往是Mootools,这次产品返璞归真,就写了十几行的原生javascript。css这次也把设计压缩到尽可能少的地步,直接原生,未用框架。


- - - - - - - - - - - - -


## 开发

### Flask
原来一直都使用Django,但Django有些重,这种“重”可能只有意会了。接触Flask的时候,里面很多设计很漂亮,也有些代码的写法,相信是Flask作者们长期积累的结果。以前常在Django中试图hack的东西,到了Flask中,就native了。当然,pocoo小组出品的东西,不会差。

实际上,Web框架的差异,本质上都不会太大。

因为数据库选择的是Mongodb,在驱动引擎上的选择,用的是原生pymongo。虽然ORM有它的好处,但性能上会降低不少。另外很重要的一点,选择Flask就是为了离开Django中的各种black boxes,自然也不愿去碰ORM中的黑盒。

还有个插曲是,之前跟一个朋友一起测过好几个ORM的性能。所以,心里大概有底。同时,理解NoSQL,就要尽可能避开ORM。

### PyCharm

PyCharm是一个python的IDE,以前用Django的时候,PyCharm提升了不少效率。目前版本同样很好得支持了Flask,同时在DEBUG的模式中,也支持Gevent.

因为这个产品的测试用例,不想写;而且之前被pylint、pep8(都可以认为是python语法、代码的校验器)折腾过之后,做Start Up的时候,会下意识的绕开它。其实之前,跟David之间有比较大的争议,他接触python时间不长,但死忠得执行这些约定,但为了适应Django的写法,很多pylint的规则要重写……(anyway,基本的pythonic语法必须要保证,比如对类的、全局变量等的命名规则;因为,这些不是写给机器看的,是写给人类看的,“约定”是要保证的。)

而PyCharm本身就可以当pylint、pep8来用。更重要的是,它是即时的。

特性还有不少,恰到好处,用“神器”来形容它,并不过分。曾有一段时间,我用它来调试node.js……

PyCharm于我而言,除了Debug方便外,另外最好用的功能是ALT键按住,然后点(代码的)命令名、属性名,就可以直接去看源码。这非常重要!我的技艺提升,多数情况下是靠这个操作。


### TOX

[Tox](http://tox.testrun.org/), vision: merge packaging, testing and release.

其实无须多言。这是一个非常棒的工具。它是基于virtualenv,所以,你还可以把它当普通的virtualenv来使用,但基本上该没有这个必要了。

曾经有个问题,要不要在virtualenv的基础上直接进行开发?实践证明,呃,还是弄自己的开发环境吧,剩下的交给Tox好了。

另外,Tox是在github上逛着发现的,不做土鳖其实好处蛮多的。所以,吐个槽,前段时间,360技术博客有一篇介绍他们的技术实践,看起来用了不少名词,其实是有些弱的。

### Gevent

如果你用python,你非常有必要去实际用用Gevent。

这是一个协程的工具。并发能力很强,在实际涉及第三方API的开发时,还额外增加了一些限制,避免它并发得太多,被API提供方503掉。

使用Gevent最大的感受,就是在python里同时控制同步、异步的逻辑,便捷了很多。在这方面,不知道node.js现在有没有好的解决方案,之前也使用过node一段时间,呃,回调很苦……



### Sentry
[Sentry](https://www.getsentry.com/)是大名鼎鼎的[DISQUS](http://disqus.com)副产的一个工具。

他们有官方的付费服务,但sentry本身是开源(基于django的框架),自己也可以git一份出来,跑在服务器上就好了。

因为我们的大部分数据运作是基于Gevent的,所以,还要做个patch,这样gevent运行的任务也能捕获到错误信息。

import traceback
# patch greenlet._report_error
def print_exception(*exc_info):
sentry_client.captureException(exc_info)
# 这个sentry_client,如果你用了sentry,应该就明了的。
if ON_PRODUCT:
traceback.print_exception = print_exception

- - - - - - - - - - - - -


## 我们使用AMAZON的服务

- 我们的主机是EC2(跑ubuntu),sentry跑在一个micro instance上,因为有一年免费期;主APP目前跑在small instance上。
- 我们的存储,以及js、css等静态资源,放在S3上。
- 我们的Mongodb数据放在EBS上。
- 我们的DNS服务使用的是route53。

目前是数据库与APP跑在一台服务器上,如果流量扩增,随时准备独立数据库服务器,然后多个APP服务器可以并行运作。按照目前的操作来看,这个应对过程的实现时间会很短。


- - - - - - - - - - - - -

## 部署

感觉没有什么好说的,就是nginx在前面扛着,gunicorn(python写的)在后面高速运作着的。另外一方面,gunicorn可以实现更新代码的时候,服务不停。

另外,在代码层次,我们是在settings.py中自动分离了生产环境和开发环境。

然后,我们还做了一个额外的脚本,就是自动同步一些resources(如css/js)到Amazon的S3存储中,如有变动,会修改sync_log;而APP端运行的时候,会去读sync_log的变动时间戳,以处理css/js的缓存问题。

平时的更新与bug修复,直接通过github进行处理并进一步部署。

### Supervisor

但必须要介绍[Supervisor](http://supervisord.org),它相当于一个任务(线程)管理器,python写的。

运行<code>supervisord</code>可以启动这个服务,另外,可以开一个web可浏览的管理后台,也可以直接使用命令来操控自己的任务。

如果只是普通的Web服务器,则没有必要使用supervisor,如果有附加的脚本在执行的,它就显得非常便利了。

- - - - - - - - - - - - -

## 写在最后

我是商(文)科毕业,没有技术基础,也从未靠代码谋生。

如果有朋友对写代码有兴趣,**用python吧,人生苦短**。

本想再吐槽一些,技术(码农)界内所见的一些恶况。

但不浪费笔墨了。另外一方面,身份也很奇特,因为是一名产品设计师,就是很多人口中的产品经理。
9499 次点击
所在节点    程序员
21 条回复
yetone
2012-11-30 17:57:06 +08:00
不错,谢谢分享
feilaoda
2012-11-30 18:13:57 +08:00
写的很详细。赞。
tedd
2012-11-30 18:20:21 +08:00
lz能写写你的学习之路吗
lewisc402
2012-11-30 18:20:27 +08:00
收藏了,慢慢看。。。
viperasi
2012-11-30 18:26:00 +08:00
不错,感谢分享,正在学习flask,能谈下flask与web.py的之间的优劣吗?多谢
liuxurong
2012-11-30 19:38:54 +08:00
不错,可以做个一键包吗?
cloudbeyond
2012-11-30 21:01:22 +08:00
写的很详细,很需要这样的文章,已感谢楼主
linuxer
2012-11-30 21:26:53 +08:00
嗯,不错。
hepochen
2012-11-30 21:53:34 +08:00
@liuxurong 为什么需要一键?在linux下面不是很方便么?你遇到了什么问题。
hepochen
2012-11-30 21:58:16 +08:00
@viperasi web.py也在一个非常小的项目中使用过,并没有深入了解过,不好评价。我自己本身对技术有守旧的态势,django原来用得就很顺了,等真正去了解flask的时候,真的觉得它漂亮的很,就直接扔了django。毕竟,pocoo出品的,品质有保证的。

但话说回来,作为micro frame的,差异也不会太大。关键的问题在于自己想做什么了,因为,到最后,不论web.py还是flask,肯定会整出不少自己的utils来……
ipconfiger
2012-11-30 22:02:07 +08:00
gunicorn实现更新代码的时候不停服务是如何搞的?
ps aux | grep gunicorn | grep master
然后kill -HUP pid
?
xiaojay
2012-11-30 22:50:40 +08:00
感谢分享,能透露下是什么产品么? :)
hepochen
2012-12-02 04:50:39 +08:00
@tedd 在我完全从0开始去学python的时候,经常在这个时候睡觉。我想学好一样东西的路肯定都是一样的……

当然啦,等时间再充裕点的时候,可以分享一些经验,或许能帮到别人。
hepochen
2012-12-02 04:51:28 +08:00
@xiaojay bug不少,还在修复的过程中。但还是蛮酷的,下周应该能稳定了。
hepochen
2012-12-02 04:54:49 +08:00
@ipconfiger gunicorn本身就是支持这种机制的。它会分几个进程去承接request,当你重启的时候,那些进程其实还活着,然后就不会停机。进程接受了一定数量的request后,会自动被杀掉。

另外,重启的时候,也可以要求一个timeout的时间,默认是30秒,把所有旧进程都杀掉。

一般不是太老的web server都能实现这种机制的,倒不是gunicorn独有的。
viperasi
2012-12-03 11:20:19 +08:00
@hepochen 去研究下flask,多谢。
zeeler
2012-12-03 11:29:18 +08:00
为啥要选mongodb,基于什么考虑的?另外,我更喜欢tornado做app server,不知道你们比较过性能没有。
anew
2012-12-03 13:16:47 +08:00
@hepochen 看了过后收益还是很多的,结合我自己的经历,感觉要根据自己的需要来选择适合的框架。
flask是一个不错的框架,清晰,优美。但我自己么有用过,还没有什么发言权。我自己还是选择了django来开发,理由很简单,开发速度快。我自己用ORM过的很好,只要数据库设计的时候,少用关联,多做缓存,性能上没有什么问题。数据库我也还是用mysql,理由很简单,稳定,方便。

mongodb很好,速度是mysql的好几倍,但我用不上,因为我现在mysql还不是性能瓶颈。我写的应用,一天pv只有几百万,服务器也很烂,只有2G的内存。但还是跑的很欢乐。前端用nginx做了反向代理,性能还不错。 而且还是用 fastcgi 做的,也没有用 gunicorn,主要是感觉 gunicorn 没有fastgi稳定,所以在 fastcgi 不是性能瓶颈以前,还是不准备换其他的。

我现在写应用,主要还是考虑开发速度,“人生苦短,咱就不浪费那个时间了”,接下来考虑的就是稳定性,比较半夜服务器来个崩溃什么的,还是很然你沮丧的。但如果服务器过载了,我还是很欢乐的,毕竟有人用还是好的嘛。服务器过载也容易解决,加台服务器就可以解决了。

NOSQL我是不怎么建议用的,理由很简单,开发时间长。其实NOSQL就是用编程复杂度来换效率。低于500万的应用,mysql还是可以的。NOSQL没有说起来的那么美。一般开发的站点,也就是几万,几十万的PV,所以大可不必在NOSQL上浪费生命。当有需要了再换,也正好。

以上只是我个人的一些体会
jser
2012-12-03 13:54:40 +08:00
楼主经验很赞,文章mark一下慢慢看

建议楼主试用一下http://mahua.jser.me/
buru
2013-06-05 09:35:14 +08:00
@hepochen 请问lz的项目有开源吗,求github地址

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/53744

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX