大数据技术 记一次Apache HUE优化
沉沙 2018-10-11 来源 : 阅读 2092 评论 0

摘要:本篇教程探讨了大数据技术 记一次Apache HUE优化,希望阅读本篇文章以后大家有所收获,帮助大家对大数据技术的理解更加深入。

本篇教程探讨了大数据技术 记一次Apache HUE优化,希望阅读本篇文章以后大家有所收获,帮助大家对大数据技术的理解更加深入。

<


今天在优化 Lib Sentry 的时候,不经意间就出现了一个 Bug. 项目中,有处使用了全局锁的形式,来将 Sentry 的链接存入到全局变量中. 我试着用 Django 缓存的形式将其替换,以提高代码的效率.但是, run 起来的时候,很快就出现了调用栈溢出的现象.为什么会出现这种情况? 难道是导入不合理?先就是一顿 import review. 发现并没有类似的循环导入, 目录结构也还OK啊.那问题出现哪呢? 没办法,借助日志, 发现了一些问题:
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
File "/home/hp/Project/platform/desktop/core/src/desktop/lib/thrift_util.py" in __getattr__
  364.     superclient = _connection_pool.get_client(self.conf,
日志的信息显示,在 thrift_utils.py 文件中,发现一直有个方法在执行,且是同一行.为什么?看源码.
class PooledClient(object):
  """
  A wrapper for a SuperClient
  """
  def __init__(self, conf):
    self.conf = conf

  def __getattr__(self, attr_name):
    if attr_name in self.__dict__:
      return self.__dict__[attr_name]

    # Fetch the thrift client from the pool
    superclient = _connection_pool.get_client(self.conf,
        get_client_timeout=self.conf.timeout_seconds)

    # Fetch the attribute. If it's callable, wrap it in a wrapper that re-gets
    # the client.
    try:
      attr = getattr(superclient, attr_name)

      if callable(attr):
        return self._wrap_callable(attr_name)
      else:
        return attr
    finally:
      self._return_client(superclient)

这是 HUE 源码的片段, 抛错就是从这里出现的. 发现一直在执行 superclient = _connection_pool.get_client(... 这块.WHY? 难道是 conf 没有?试着去加些打印信息,发现果然是没有 conf. 不能啊!为什么会没有 conf 呢?
于是,再看下Django抛出的 error 信息,发现了一些信息:
py2.7.egg/django/core/cache/backends/locmem.py" in get
  48.                     return pickle.loads(pickled)
程序是执行到这之后,才一直在重复执行上面的错误的.为什么 loads 的时候会出错呢? 首先猜想的是, loads 的时候,因为什么原因导致了 PooledClient 的 object 没有 conf 属性. 那就看下 pickle.loads. 看完之后,再借助了 log 信息, 发现其是因为去寻找 __setstate__ 属性的时候才导致了这种错误.好了,至此,问题就得以描述清楚了.
之所以调用 Django core cache 导致了调用栈溢出, 是因为 Django 在 cache get 的方法中将存储的数据反序列化成对象,而这个对象在此时还没有生成,且序列化的时候要去调用 __setstate__ 方法, 但是类中没有定义,只是定义了 __getattr__ 方法.而 __getattr__ 方法中又使用了 conf 方法, 这时候 conf 还没有, 所以,又触发了 __getattr__ 方法的执行.如此反复,导致了最终的调用栈溢出现象.
好了,既然找到问题了,那就解决吧.
我这里是自己实现了 __getstate__, __setstate__ 的魔术方法,这样,就可以解决了找不到 __setstate__ 的问题. 还有一种解决方法,就是将 conf 定位为 类属性. 这样是从找不到 conf 源头解决问题.
问题解决,开始总结下 Python 魔术方法.
__setstate__, __getstate__ 方法在 pickle 序列化和反序列化的时候会触发执行. getattr 是当 object 的某个属性找不到的时候触发执行.
下面是我模拟的测试代码:
# coding=utf8

import pickle
import StringIO


class PeopleObject(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def display(self):
        print 'name:', self.name, 'address:', self.age

    def __getattr__(self, attr_name):
        if attr_name in self.__dict__:
            return self.__dict__[attr_name]
        else:
            print self.name

    def __getstate__(self):
        state = self.__dict__.copy()
        return state

    # def __setstate__(self, state):
    #     print state
    #     self.__dict__.update(state)


hanmeimei = PeopleObject("Han Meimei", 18)
hanmeimei.display()
store_file = StringIO.StringIO()

pickle.dump(hanmeimei, store_file, 0)  # 序列化

# del Person #反序列的时候,必须能找到对应类的定义。否则反序列化操作失败。
store_file.seek(0)
hanmeimei_ins = pickle.load(store_file)  # 反序列化
hanmeimei_ins.display()
store_file.close()

执行会发现,很快就会出现同样的错误.
   

本文由职坐标整理发布,学习更多的大数据技术相关知识,请关注职坐标大技术云计算大技术技术频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved