我为何从 Python 转向 Erlang,python转向erlang,如果你不是一个使用pyt


在本文中,我将讲述我是如何从使用python转换到使用Erlang的。如果你不是一个使用python的开发者(很可能对基于python的网页服务具有深入的了解),或者你不需要将一些事物大规模化,那么你将不会觉得本文很实用。如果你不用开发一个基础的框架,或者你只需要开发一些小的博客、小的资源管理平台、简单的导航指南类网页,那么本文也将对你没有什么帮助。还有,如果你正想着选择一门语言入门,那么请不要让我的观点影响到你的决定。我所要讲述的,是我在使用python过程遇到的问题,然后Erlang又是如何帮我解决这些问题的。

下面我将从一个简短的发展史开始,然后以我自己的推论结尾。如果你不同意我的观点,那么十分欢迎一起来讨论!这是我分享我的体验的初衷。

我开始写代码的时候,使用的是MEL(maya嵌入式语言)。然后我找到一份工作,收到我人生中第一份薪水。很快因为越来越多的紧急开发因素,我开始使用python并且阅读了K&R,学习到了如何使用C语言来开发python语言的各种功能。随着一年一年过去,我对网页开发越来越感兴趣。因为个人兴趣,我从动画行业辞职出来,然后被德黑兰一家非常有名的科技公司雇佣。

最近我开发了Appido.IR,这是一个用python写的视频和音乐流服务。

下面我将开始讲述我所遇到的问题。

每个人都喜欢Django。但是我讨厌它!可能是因为我帮助马西莫开发了Web2py,也可能是简单的因为Web2py让我无法选择其他的框架。但是我最终还是在一个无聊的项目中尝试过使用Django。

那么,Django甚至是Web2py到底有什么问题呢?没有!直到你开始通过一些模块引擎和数据库管理系统来使用Bottle和Falcon,然后你就会发现,这些企业级的框架运行起来很慢。对一个简单的RESTful 风格的API 服务,你不得不因此浪费部分你cpu的性能。对于复杂的API服务,你必须越狱,然后将一个全新的架构合并到你所谓的全栈架构中。这里举个例子:

在Appido.ir 流技术中,我们通过FFMPEG和其他n多开源工具才把Dash协议加入其中。Appido有它自己的OAuth2 服务端,它有认证系统、工作流引擎、调度器、监视器、日志系统、调试系统、报表系统以及审计系统,只要你能想到的都有。当然,这是经过反复调试修改,痛苦煎熬使用Web2py和Django好几个星期才完成的,显然这个系统不可能在一个简单的框架下工作。创建一些文件夹然后试着使用MVC模式或者是在大框架中拥有一个非常赞的数据库管理界面也将无法让你将整个系统组合起来。然后最终一些用不上的功能也会让你无语。迟早的事。虽然确实全栈的python框架有一些优点,但是仍然存在一些问题。所以我开发了我自己的基于Falcon的框架。

因此你开始使用Bottle框架、Falcon框架或Flask框架…并且你会发现自己需要安装任务队列和调度模块(例如, CeleryRQ )。为什么需要呢?因为,在web2.0中超过500ms的每一次请求都必须是有状态的(stateful)!这是一个不成文的规定。你需要给用户提供一些长时间等待请求的状态。而不能让客户在计算过程中一直等待。你需要把发送邮件、转换图片一类的沉重负担放置在Celery框架中(或者自己定制开发的多进程队列)。又有什么问题呢?我们来看看:

假设你有一个流媒体服务。客户要上传20Gb的4K raw视频文件,你把文件转换成10个不同的分辨率并给他(她)发邮件说结果已准备好。

你使用有40个工作者(workers)的celery框架。视频开始转换,服务器变得超载,越来越慢。这时你会找到一个巧妙的解决办法!安装另一个带有流媒体代码和工具的服务器,使用Celery作为一个工作者。好了,问题得以解决!不!没有那么快!到了半夜,你会发现其中有5个或6个服务器的CPU利用率为0,而第6个却达到100%。为什么呢?事实证明Redis和Celery一起使用时有时序的问题,目的是防止工作者挑拣工作。(有一个很显然的解决方案:欢迎来到扇出模式和能见度超时的世界),安装  RabbitMQ可以解决问题(还会产生另外一些新的奇怪的问题)。(如果你开发了这样一个系统,它不存在任何所提及的问题,那么恭喜你!你是世界上最幸运的家伙!)。你找到了蜂蜜却没有被蜜蜂叮咬。

服务运行得很棒,所以现在需要做的是提高WEB服务的RPS(每秒请求数量),要么通过增加WSGI的工人数量,要么通过使用Tornado/Gevent,最后借助于Varnish的缓存,使用HAProxy或Nginx实现负载均衡。哈哈,简直就是完美的解决方案!同时你会注意到使用SQLAlchemy会降低你的查询速度(除非SQLAlchemy的极其复杂实现),而使用原始的SQL语句可以解决这个问题。让我看如下使用Postgres数据库的案例,这个案列有数万行记录:

Python
def 
                                                                    pure_python():
    max_per_task 
                                                                        = db.DBSession.query(
        Version.task_id, func.max(Version.version_number).label(
                                                                            'max'))\
        .join(Task)\
        .filter(Task.project_id 
                                                                                == proj_id)\
        .group_by(Version.task_id)\
        .subquery()
     
                                                                                    return Version.query\
        .join(max_per_task,
              tuple_(max_per_task.c.task_id, max_per_task.c.max) 
                                                                                        ==
              tuple_(Version.task_id, Version.version_number))\
        .all()

Python
def  simple_sql():
   sql =  """
    select
        max("Versions".id) as id
    from "Versions"
        join "Tasks" on "Versions".task_id = "Tasks".id
        join "Projects" on "Tasks".project_id = "Projects".id
        where "Projects".id = %s
        group by "Versions".task_id, "Versions".take_name
    """   %  proj_id
   conn =  db.DBSession.connection()
   result =  conn.execute(sql)
    return  result.fetchall()

结果

Python
pure_python: 3.284  sec
simple_sql: 0.228 sec

这真人让印象深刻!希望你能明白其中的道理!

真的是全部解决了吗?好吧,你只是使用Python写了一些Erlang特性的代码,因为Erlang并不会出现这些分布式/可拓展性问题。可拓展性问题经常是Python需要解决的。对于扩展性,你需要分布式,需要完善的架构用于面向服务的内部调用,你需要故障切换(failover)、容错性(fault tolerant),我不得不接受所有这些都是Python亟待解决的,但这么多技术的使用往往会付出代价。你需要规避Python的问题。你需要正确的原生SQL语句,需要创建自定义的索引(亦或物化视图)。Python的全局解释器锁使用起来并不复杂,对于快速启动,共享状态通常是有用的,但这样有时候会以灾难式的结果集退出。除此之外,对于实际生活中的每个计算,你都需要为Python写扩展(原生C API/Swig/Cython亦或pypy)。

Erlang 没有比 C 快,但是它的分布式模式能让它易于编写程序来利用数据中心里的每一个核心。(如果你知道NIF, 那么你就会觉得有价值)。在 Erlang 中连接数据库也需要 SQL 知识。(这与Python一致)

如果你需要创建一个云服务,或者为系统扩展上千的用户,就需要使用 USE RIGHT TOOLS 。Python 是伟大的快速测试和模拟工具。它非常适合你取得合同!你使用 python 过一夜,就可以实现复杂的东西。它很好地适应了许多上百人用户的大工程。但是当它遇到需要巨大的系统伸缩时,我希望我停止在商业上的自我烦恼,因为我正试图用错误的工具去解决一个错误的问题。

简而言之,使用 Python 来赢得合同,使用 erlang 来完成工作

评论关闭