V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hepochen
V2EX  ›  程序员

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

  •  1
     
  •   hepochen · 2012-11-30 17:43:04 +08:00 · 9484 次点击
    这是一个创建于 4164 天前的主题,其中的信息可能已经有所发展或是发生改变。
    不知道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   ·   我们的愿景   ·   实用小工具   ·   4709 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 04:02 · PVG 12:02 · LAX 21:02 · JFK 00:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.