简单介绍

  1. gevent 基本概念:
       调度器: hub
              上下文切换管理: switch
              主循环: loop
       协程: greenlet
  2. gevent 特性:
        优点:
                高效,实现简单,易维护
        缺点:
                和go不一样,并不是python原生支持的功能,所以使用起来难免会踩一些坑,但是由于并不是实现方式有问题,所以存在着点弊病并没有什么问题。

开始使用

  1. 什么情况下可以使用:
        足够了解自己服务所使用的io,  写的代码足够规范,否则会出现出了问题都不知道那里有问题。
        需要并行化的代码不能阻塞时间过长,否则没有意义。
        存在大量的io, 前提是可以变成非阻塞的,否则不能满足条件2。
  2. 由于发现api的代码满足以上三条,所以开始进行优化:
    第一版代码如下:

    class ParallelTask(object):
        def __init__(self, timeout=5):
            # 覆盖python原生的socket
            gevent.monkey.patch_socket()
            self.timeout = timeout
            self.task = []
     
        def taskAppend(self, task, *args):
            self.task.append(gevent.spawn(task, *args))
     
        def run(self):
            errno, err_msg = get_error(AwemeStatus.SUCCESS)
            try:
                gevent.joinall(self.task, timeout=self.timeout)
                return errno, err_msg
            except Exception, ex:
                logger.exception("[ParallelTask] run task fail error=%s" % ex)
                errno, err_msg = get_error(AwemeStatus.REE_PARALLEL_TASK)
                return errno, err_msg
    # handler
    def __getAwemeList(self, category_id, req_type):
        pass
      
    # 创建一个并行处理的任务
    paralle_obj = ParallelTask()
    paralle_obj.taskAppend(self.__getAwemeList, category_id, req_type)
    errno, err_msg = paralle_obj.run()

    代码看似没有问题,自测也没发现什么问题。

  3. 上线观察:
    果不其然,出问题了。。。

    错误发生在 challengeDetail 接口, 也是奇怪,上的明明是category 接口。
    不过看错误知道应该是掉RPC没有成功, 查看RPC的日志可以看到全是fail。
  4. 分析问题:
     首先RPC失败肯定是由于使用gevent 引起的。但是我在这category使用gevent 为啥会影响challengeDetail 呢。
     观察最上面的 ParallelTask 代码,里面使用了monkey patch , 没错就是这个东西,重写了python原生socket ,使其支持了非阻塞io。
     所以在没有并行化的代码里使用RPC调用,里面使用的socket变成了非阻塞的,而这些调用不受hup控制,所以肯定会出现调用失败的情况。
  5. 解决:
    解决办法很简单,在用完monkey patch 之后恢复原生的socket不久好了。 gevent 没有提供接口恢复,所以自己实现了下。

    def repatching(item):
        try:
            # 需要重新写回的module
            module = __import__(item)
            # 需要重写的属性
            saved = gevent.monkey.saved
            mapper = saved.get(item, {})
            for attr in mapper:
                old_value = mapper.get(attr)
                if not old_value:
                    continue
                setattr(module, attr, old_value)
        except Exception, ex:
            logger.exception("[gevent] repatching fail error=%s" % ex)
     
    class ParallelTask(object):
        def __init__(self, timeout=5):
            # 覆盖python原生的socket, 使用完记得repatching 不然会有未知错误
            gevent.monkey.patch_socket()
            self.timeout = timeout
            self.task = []
     
        def taskAppend(self, task, *args):
            self.task.append(gevent.spawn(task, *args))
     
        def run(self):
            errno, err_msg = get_error(AwemeStatus.SUCCESS)
            try:
                gevent.joinall(self.task, timeout=self.timeout)
                return errno, err_msg
            except Exception, ex:
                logger.exception("[ParallelTask] run task fail error=%s" % ex)
                errno, err_msg = get_error(AwemeStatus.REE_PARALLEL_TASK)
                return errno, err_msg
            finally:
                # 使用完非阻塞的网络io之后一定要改回来
                repatching('socket')
  6. 线上观察:
    bug 修复之后线上没有新的问题爆出来,至今稳定运行着, 本来打算用go优化的接口看样子也不需要了, 并行化之后接口的时延由3s 降低到了300ms, 降低的幅度也符合预期 (30个rpc并行)

gevent 使用踩坑的更多相关文章

  1. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  2. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  3. 【踩坑速记】二次依赖?android studio编译运行各种踩坑解决方案,杜绝弯路,总有你想要的~

    这篇博客,只是把自己在开发中经常遇到的打包编译问题以及解决方案给大家稍微分享一下,不求吸睛,但求有用. 1.大家都知道我们常常会遇到dex超出方法数的问题,所以很多人都会采用android.suppo ...

  4. NPOI导出Excel (C#) 踩坑 之--The maximum column width for an individual cell is 255 charaters

    /******************************************************************* * 版权所有: * 类 名 称:ExcelHelper * 作 ...

  5. 我的微信小程序入门踩坑之旅

    前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...

  6. router路由去掉#!的踩坑记

    项目中在研究去掉router#!的过程中的踩坑过程.

  7. vue+ vue-router + webpack 踩坑之旅

    说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案   老司机可以忽略下面的内容了 1)起因  考虑到数据分离的问题  因为server是express搭的   自然少 ...

  8. 记jQuery.fn.show的一次踩坑和问题排查

    最近很少已经很少用jQuery,因为主攻移动端,常用Zepto,其实很多细节和jQuery并不一样.最近又无意中接触到了PC的需求和IE6, 使用了jQuery,刚好踩坑了,特意记录一下. 本文内容如 ...

  9. WebForm路由踩坑 ajax请求多次

    WebForm路由踩坑 再次接触Asp.Net WebForm已是4年后的今天,源起新入职的公司,一个老的项目. Web接触的少,那就多动手写写. WebForm1.aspx <body> ...

随机推荐

  1. Java中枚举类型Enum的一种使用方式

    枚举类定义如下: public enum Status { SCUUESS("1", "成功"), FAILED("2", "失败 ...

  2. UVA10917 A walk trough the Forest (最短路,dp)

    求出家到其他点的最短路径,题目的条件变成了u->v不是回头路等价于d[u]>d[v]. 然后根据这个条件建DAG图,跑dp统计方案数,dp[u] = sum(dp[v]). #includ ...

  3. Paxos算法与Zookeeper分析,zab (zk)raft协议(etcd) 8. 与Galera及MySQL Group replication的比较

    mit 分布式论文集 https://github.com/feixiao/Distributed-Systems wiki上描述的几种都明白了就出师了 raft 和 zab 是类似的,都是1.先选举 ...

  4. Oracle数据库同步方案

    Oracle数据库同步方案 1. 利用数据泵导出每表前2000行数据 expdp tvpay2/tvpay directory=dmp dumpfile=20170508.dmp include=ta ...

  5. 【技巧:字符串同构】Avendesora

    判断字符串“同构”的技巧 题目大意 给定A,B两个序列,要求B在A中出现的次数以及位置.定义字符变换:把所有相同的字符变为另一种字符:两个字符串相等:当且仅当一个字符串可以在若干次字符变换之后变为另一 ...

  6. 【计算机网络】Session机制

    1. Http请求中Session机制 先简单说一下HTTP请求中的Session机制:Session数据保存在服务器端,SessionID保存在客户端的Cookies中(关闭浏览器时过期).当客户端 ...

  7. 【Java基础】java中的反射机制与动态代理

    一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...

  8. 计算机完全卸载mysql

    编写时间:15:07:02(2018年9月23日) 1.停止mysql服务. “运行”——>“cmd”——>输入“net stop mysql;” 看链接: https://blog.cs ...

  9. react 列表渲染

    https://reactjs.org/docs/lists-and-keys.html#keys 以下代码运行会报错:Warning: Each child in an array or itera ...

  10. Python运算符总结

    一.简介 Python中运算符分为: 算术运算符:主要用于两个对象算数计算(加减乘除等运算) 比较(关系)运算符:用于两个对象比较(判断是否相等.大于等运算) 赋值运算符:用于对象的赋值,将运算符右边 ...