Gevent: 优点,缺点,以及不优美的地方

原始出处:                    In the Milky way

我不想用很多时间去描述Gevent是什么,我想它官网上的一句总结足矣:

“Gevent是一种基于协程的Python网络库,它用到Greenlet提供的,封装了libevent事件循环的高层同步API。”

接下来我将阐述在Mixpanel中一个内部项目使用Gevent的经验。 为了这篇文章我还动手写了几个性能小测试。(Whipped up这里的意思让我迷惑哎- -)

优点

首先Gevent最明显的特征就是它惊人的性能,尤其是当与传统线程解决方案对比的时候。

在这一点上,当负载超过一定程度的时候,异步I/O的性能会大大的优于基于独立线程的同步I/O这几乎是常识了。

同时Gevent提供了看上去非常像传统的基于线程模型编程的接口,但是在隐藏在下面做的是异步I/O。

更妙的是,它使得这一切透明。(此处意思是你可以不用关心其如何实现,Gevent会自动帮你转换)

你可以继续使用这些普通的Python模块,比如用urllib2去处理HTTP请求,它会用Gevent替换那些普通的阻塞的Socket操作。

当然也有一些需要注意的问题,我稍后会阐述。

接下来,见证性能奇迹的时候到了。

从上图看出

忽略其他因素,Gevent性能是线程方案的4倍左右(在这个测试中对比的是Paste,译者注:这是Python另一个基于线程的网络库)

在线程方案中,错误数随着并发连接数的增长线性上升(这些错误都是超时,我完全可以增加超时限制,但是从用户的角度来看漫长的等待和失败其实是一个妈生的)。

Gevent则是直到10,000个并发连接的时候都没有任何错误,或者说能处理至少5,000并发连接。

在这2种情况下,每秒实际完成的请求数都非常的稳定,至少直到Gevent在10,000个并发连接测试崩溃之前是如此。这一点让我感到非常的惊讶。我原本猜想的是RPS(每秒完成请求数)会随着并发的增多而下降。

线程模型在10,000并发连接测试中完全失败。我完全可以让它正常的工作(比如用一些资源优化技巧应该能做到),不过我纯粹是出于玩蛋来做这个测试的,所以没有在这上面花太多功夫。

如果这类东西能勾引起你的兴趣,我们正在招聘,你懂的。(没错,我就在内容里面混点广告宣传下。)

测试方法

这是我用来测试的Python代码:

#!/usr/bin/env python 
 
import sys 
 
def serve_page(env, start_response): 
    paragraph = ‘‘‘
        Lorem ipsum dolor sit amet,
        consectetur adipisicing elit,
        sed do eiusmod tempor incididunt ut labore et
        dolore magna aliqua. Ut enim adminim veniam,
        quis nostrud exercitation ullamco laboris nisi ut aliquip
        ex ea commodo consequat.
        Duis aute irure dolor in reprehenderit in
        voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident,
        sunt in culpa qui officia deserunt mollit anim id est laborum.
    ‘‘‘ 
    page = ‘‘‘
        \<html\>
            \<head\>
                \<title\>Static Page\</title\>
            \</head\>
            \<body\>
                \
<h1\>Static Content\</h1\>
                %s
            \</body\>
        \</html\>
    ‘‘‘ % (paragraph * 10,) 
 
    start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) 
    return [page] 
 
if __name__ == ‘__main__‘: 
    def usage(): 
        print ‘usage:‘, sys.argv[0], ‘gevent|threaded CONCURRENCY‘ 
        sys.exit(1) 
 
    if len(sys.argv) != 3 
        or sys.argv[1] not in [‘gevent‘, ‘threaded‘]: 
        usage() 
 
    try: 
        concurrency = int(sys.argv[2]) 
    except ValueError: 
        usage() 
 
    if sys.argv[1] == ‘gevent‘: 
        from gevent import wsgi 
        wsgi.WSGIServer( 
            (‘127.0.0.1‘, 10001), 
            serve_page, 
            log=None, 
            spawn=concurrency 
        ).serve_forever() 
    else: 
        from paste import httpserver 
        httpserver.serve( 
            serve_page, 
            host=‘127.0.0.1‘, 
            port=‘10001‘, 
            use_threadpool=True, 
            threadpool_workers=concurrency 
        )

在客户端,我在下面这些参数下使用Apache Bench:

  • -c NUM: 这里的NUM是并发连接数。在每一个测试中这个数与服务器命令行中使用的那个数是匹配的。(译者注:这里指脚本运行时需要提供的第二个参数)
  • -n 100000: 所有的测试都需要完成100,000个请求。在上面的图中,错误率并没有统计,而是实际100,000请求中失败的请求数。
  • -r: 如果请求失败,自动重试

所有的测试包括服务端和客户端都是运行在一个低配置并且只有512MB内存的VPS上。

我最初以为我需要用一些方法来限制线程方案到一个CPU上,但事实证明就算这VPS号称是“四核”,你也就只能让一个核心到100%。就是这么蛋疼。

负载测试中所做的Linux优化

  • 当Linux处理超过500连接每秒的时候我遇到了一大堆的问题。
    基本上这些问题都是因为所有连接都是从一个IP到另一个相同的IP(127.0.0.1 <-> 127.0.0.1)。
    换句话说,你可能在生产环境中不会遇到这些问题,但几乎可以肯定的是这些问题一定会出现在测试环境中(除非你在后端跑一个单向代理)。
  • 增加客户端端口范围

    echo -e ’1024\t65535′ | sudo tee /proc/sys/net/ipv4/ip_local_port_range

    这一步将会使得客户端的连接有更多的可用的端口。没有这个的话你会很快的用尽所有端口(然后连接就处于TIME_WAIT状态)。

  • 启用TIME_WAIT复用

    echo 1 | sudo tee /proc/sys/net/ipv4/tcp_tw_recycle

    这也会优化停留在TIME_WAIT的连接,当然这种优化至少需要每秒含有同样IP对连接超过一定数量的时候才会起作用。同时另一个叫做tcp_tw_reuse的参数也能起到同样的作用,但我不需要用到它。

  • 关闭同步标签

    echo 1 | sudo tee /proc/sys/net/ipv4/tcp_syncookies

    当你看到”possible SYN flooding on port 10001. Sending cookies.”这种信息的时候,你可能需要关闭同步标签(tcp_syncookies)。在你生产环境的服务器上不要做这样的事情,这样做会导致连 接重置,只是测试的话还是没问题的。

  • 如果用到了连接追踪,关闭iptables

    你将会很快的填满你netfiler表。当然咯,你可以尝试增加/proc/sys/net/netfilter/nf_conntrack_max中的数值,但是我想最简单的还是在测试的时候关闭防火墙更好吧。

  • 提高文件描述符限制

    至少在Ubuntu上,默认每一个普通用户的文件描述符限制数是4096。所以咯,如果你想测试超过4000并发连接的时候,你需要调高这个数值。最简单 的方法就是你测试之前在/etc/security/limits.conf中增加一行类似于”* hard nofile 16384″的东西,然后运行ulimit -n 16384这条shell命令。

缺点

当然所有的事情不会这么好对吧?没错。事实上,如果有更完整的文档的话,很多我在用Gevent的问题会被解决得更好。(译者对于这类句子毫无抵抗力,凑合着看吧╮(╯_╰)╭)

文档

简单的说,这货一般般。我大概读了比文档更多的Gevent源码(这样很有用!)。事实上最好的文档就是源码目录下的那些示例代码。如果你有问题,认真的瞄瞄看它们先。同时我也花了很多时间用Google去搜索邮件列表的存单。

兼容性

这里我特别想提到eventlet。回想起来,这是有一定道理的,它会导致一些匪夷所思的故障。我们用了一些eventlet在MongoDB客户端(译者注:一种高性能文档型数据库)代码上。当我使用Gevent的时候,它根本不能在服务器上运行。

呃,使用顺序错误

在你导入Gevent或者说至少在你调用Monkey.path_all()之前启动监听进程。我不知道为什么,但这是我从邮件列表中学到的,另一点则是 Gevent修改了Python内部Socket的实现。当你启动一个监听进程,所有已经打开的文件描述符会被关闭,因此在子进程中,Socket会以未 修改过的形式重新创建出来,当然啦,这就会运行异常。Gevent需要处理这类的异常,或者说至少提供一个兼容的守护进程函数。

Monkey Pathing,抽风咩?

这么说吧,当你执行monkey.path_all()的时候,很多操作会被打上补丁修改掉。我不是很好这口,但是这样使得普通Python模块能够很好 的继续运行下去。奇怪的是,这丫的不是所有的东西都打上了这种补丁。我瞄了很久想去找出为毛的Signals模块不能运行,直到我发现是 Gevent.signal的问题。如果你想给函数打补丁,为毛的不全部打上咩?

这问题同样适用于Gevent.queue与标准的Python queue模块。总之,当你需要用到Gevent特定的API去替换标准模块/类/函数的时候,它需要更清晰(就像简单的list一样)。

不优美的地方

Gevent不能支持多进程。这是比其他问题更加蛋疼的部署问题, 这意味着如果你要完全用到多核,你需要在多个端口上运行多个监听进程。然后捏,你可能需要运行类似于Nginx的东西去在这些服务监听进程中分发请求(如果你服务需要处理HTTP请求的话)。

说真的,多进程能力的缺乏意味着为了使用中可用你又要在服务器上多加上一层东西。(译者注:真蛋疼的句子,不就是多一层Nginx或者HA么)

在使用Gevent客户端负载测试中,这真是一个大问题。我最终是实现了一个使用共享内存的多进程负载的客户端去统计以及打印状态。这需花费更多的工作量在上面。(如果有人需要做同样的事情,联系我,我会给你这个客户端脚本程序)

最后

如果你已经看到这里,你会发现我用了2个章节去阐述Gevent的缺点。不要被这些东西蒙蔽了你的眼睛。我相信Gevent对于Python网络编程来说是一种很伟大的解决方案。诚然它有各种各样的问题,但是大多数问题也仅仅是文档的缺失罢了,撑死了多用点时间嘛。

我们内部正在使用Gevent。事实上我们的服务非常的高效,以至于在我们所用的那种规格的VPS上,很容易在用光计算资源(包括CPU和内存)之前用光带宽资源。

# 这是一篇翻译的文章,原文见http://code.mixpanel.com/gevent-the-good-the-bad-the-ugly/

# 原文中由于有大量中英对照,考虑到适合阅读性,去掉了原文部分。

# 作者:In the Milky way

Gevent: 优点,缺点,以及不优美的地方

时间: 2024-10-14 16:22:38

Gevent: 优点,缺点,以及不优美的地方的相关文章

推荐系统中常用算法 以及优点缺点对比

推荐系统中常用算法 以及优点缺点对比 在 推荐系统简介中,我们给出了推荐系统的一般框架.很明显,推荐方法是整个推荐系统中最核心.最关键的部分,很大程度上决定了推荐系统性能的优劣.目前,主要的推荐方法包括:基于内容推荐.协同过滤推荐.基于关联规则推荐.基于效用推荐.基于知识推荐和组合推荐. 一.基于内容推荐 基于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要依据用户对项目的评价意见,更多地需要用机 器

转:数据库索引的作用和优点缺点

为什么要创建索引呢?这是因为,创建索引可以大大提高系统的性能. 第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性. 第二,可以大大加快 数据的检索速度,这也是创建索引的最主要的原因. 第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义. 第四,在使用分组和排序 子句进行数据检索时,同样可以显著减少查询中分组和排序的时间. 第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能. 也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列

LVS三种模式配置及优点缺点比较 转

LVS三种模式配置及优点缺点比较   作者:gzh0222,发布于2012-11-12,来源:CSDN   目录: LVS三种模式配置 LVS 三种工作模式的优缺点比较 LVS三种模式配置 LVS三种(LVS-DR,LVS-NAT,LVS-TUN)模式的简要配置 LVS是什么: http://www.linuxvirtualserver.org/VS-NAT.html http://www.linuxvirtualserver.org/VS-IPTunneling.html http://www

转:【总结】推荐系统中常用算法 以及优点缺点对比

转:http://www.sohu.com/a/108145158_464065 在推荐系统简介中,我们给出了推荐系统的一般框架.很明显,推荐方法是整个推荐系统中最核心.最关键的部分,很大程度上决定了推荐系统性能的优劣.目前,主要的推荐方法包括:基于内容推荐.协同过滤推荐.基于关联规则推荐.基于效用推荐.基于知识推荐和组合推荐. 一.基于内容推荐 基 于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要

作业二 流行的源程序版本管理软件和项目管理软件各自的优点缺点

Microsoft TFS 优点: 在小的团队中,比甘特图更有用集成了项目管理.版本控制.BUG 跟踪,能有效实现 SCRUM能与 VS 无缝接合 缺点: 搭建.维护tfs相对比较复杂,硬件要求同时比较高. GitHub: 优点: 是一个万能的工具.对于任何大小的项目,他都是理想的工具.首 先,他可以作为一个版本控制系统和协作工具,用它来发布工作. 利用GitHub,你可以将项目存档,与其他人分享交流,并让其他开发者帮助你一起完成这个项目.优点在于 ,他支持多人共同完成一个项目,因此你们可以在同

单例模式的优点-缺点

优点: 1,实例控制:单例模式防止其它对象对自己的实例化,确保所有的对象都访问一个实例.     2,伸缩性:因为由类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性. 缺点: 1,系统开销.虽然这个系统开销看起来很小,但是每次引用这个类实例的时候都要进行实例是否存在的检查.这个问题可以通过静态实例来解决.     2,开发混淆.当使用一个单例模式的对象的时候(特别是定义在类库中的),开发人员必须要记住不能使用new关键字来实例化对象.因为开发者看不到在类库中的源代码,所以当他们发现不

群集概述及LVS三种模式优点缺点比较

一.群集技术概述 1.群集的类型 1)负载均衡群集:主要的功能将来自客户机的访问请求分流给多台服务器,从而缓单台服务器的负载压力,例如京东淘宝的购物节的时候,当天的并发量是分常大的,单台服务器是无法承载的. 2)高可用群集:高可用群集和hsrp(热备份路由器协议)原理基本一样,服务器有主从之分,实现故障切换,当一台服务器发生故障的时候,另一台服务器马上提供工作. 3)高性能运算群集:这种群集主要用在"云计算"中,就是将多台服务器的硬件整合到一起,实现高性能运算能力. 2.负载均衡的分层

LVS三种模式配置及优点缺点比较

LVS三种模式配置 LVS 三种工作模式的优缺点比较 LVS三种模式配置 LVS三种(LVS-DR,LVS-NAT,LVS-TUN)模式的简要配置 LVS是什么: http://www.linuxvirtualserver.org/VS-NAT.html http://www.linuxvirtualserver.org/VS-IPTunneling.html http://www.linuxvirtualserver.org/VS-DRouting.html 首先是安装ipvsadm管理程序

git优点缺点(简单介绍)

什么是Git Git是目前世界上最先进的分布式版本控制系统. Git是免费.开源的 最初Git是为辅助 Linux 内核开发的,来替代 BitKeeper 作者 Linux和Git之父李纳斯·托沃兹(Linus Benedic Torvalds)1969.芬兰 优点 适合分布式开发,强调个体. 公共服务器压力和数据量都不会太大. 速度快.灵活. 任意两个开发者之间可以很容易的解决冲突. 离线工作. 缺点 模式上比SVN更加复杂. 不符合常规思维. 代码保密性差,一旦开发者把整个库克隆下来就可以完