我们的Web开发与部署 -- 一名python党 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问时复制粘贴 AI 生成的内容
hepochen
V2EX    程序员

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

  •  1
     
  •   hepochen 2012-11-30 17:43:04 +08:00 10143 次点击
    这是一个创建于 4706 天前的主题,其中的信息可能已经有所发展或是发生改变。
    不知道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吧,人生苦短**。

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

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

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

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

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

    一般不是太老的web server都能实现这种机制的,倒不是gunicorn独有的。
    viperasi
        16
    viperasi  
       2012-12-03 11:20:19 +08:00
    @hepochen 去研究下flask,多谢。
    zeeler
        17
    zeeler  
       2012-12-03 11:29:18 +08:00
    为啥要选mongodb,基于什么考虑的?另外,我更喜欢tornado做app server,不知道你们比较过性能没有。
    anew
        18
    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
        19
    jser  
       2012-12-03 13:54:40 +08:00
    楼主经验很赞,文章mark一下慢慢看

    建议楼主试用一下http://mahua.jser.me/
    buru
        20
    buru  
       2013-06-05 09:35:14 +08:00
    @hepochen 请问lz的项目有开源吗,求github地址
    buru
        21
    buru  
       2013-06-05 09:36:29 +08:00
    @hepochen Nginx和gunicorn是怎么配合使用的?Nginx只是用来应对静态文件的请求吗?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2762 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 13:54 PVG 21:54 LAX 06:54 JFK 09:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86