zoukankan      html  css  js  c++  java
  • swift bug 调试记(wsgi.input)

    第一次指定纠删码策略,修改了一部分swift代码后,执行PUT object,就被一个bug拦住。产生bug代码段如下:

    try:
        with ChunkReadTimeout(self.client_timeout):
            mime_documents_iter = iter_mime_headers_and_bodies(
                    request.environ['wsgi.input'],
                    mime_boundary, self.network_chunk_size)
            _junk_hdrs, obj_input = next(mime_documents_iter)
    except ChunkReadTimeout:
        return HTTPRequestTimeout(request=request)
    

    在执行第三行iter_mime_headers_and_bodies()过程中出错,代码会最终定位至eventlet.wsgi的Input类中_chunked_read()函数,抛出一个ValueError异常。异常全文如下:

    ValueError: invalid literal for int() with base 16: ''
    

    而Input类中_chunked_read()函数相关代码如下:

    def _chunked_read(self, rfile, length=None, use_readline=False):
            ......
                while self.chunk_length != 0:
                    ......
                    if maxreadlen > 0:
                        ......
                    else:
                        self.chunk_length = int(rfile.readline().split(b";", 1)[0], 16)
                        self.position = 0
                        if self.chunk_length == 0:
                            rfile.readline()
            except greenio.SSL.ZeroReturnError:
                pass
            return b''.join(response)
    

    Google了一阵后,大致了解这个问题,一步步尝试解决。

    eventlet版本原因导致?

    首先利用apt-cache命令查看了本机上安装的eventlet版本信息。apt-cache用于查看相应软件包确切名称及详细信息。

    apt-cache show python-eventlet
    

    果然,显示Version: 0.9.7-0ubunutu1,而在swift项目中requirement.txt内容如下:

    dnspython>=1.9.4
    eventlet>=0.16.1,!=0.17.0
    greenlet>=0.3.1
    netifaces>=0.5,!=0.10.0,!=0.10.1
    pastedeploy>=1.3.3
    simplejson>=2.0.9
    six>=1.9.0
    xattr>=0.4
    PyECLib==1.0.7    
    

    明确规定eventlet版本为0.16.1以上。马上通过源码安装eventlet 0.16.1版本,重新运行swift服务。结果……依旧抛出异常!
    人为比较了一下两个版本eventlet.wsgi,发现Input类具体实现确实有区别,但没能解决我的问题。我甚至尝试直接修改eventlet相应库文件,但依旧无效。两版本eventlet最大区别字符串前加b,具体解释可见字符串知识

    配置错误?

    这个猜想主要根据List Openstack上关于此错误的一些回答
    然而当我尝试调整object-server.conf中间eventlet_debug后,异常依旧。

    回归错误本身

    多方尝试无果,重新回来思考这个错误。
    其实错误行代码本身提示,便是在读取某个类似文件的对象一行后,尝试用“;”进行切分,取切分后生成列表的第一个元素,但问题是切分后列表的第一个元素为空,根本无法以16进制形式转换为整数。
    这个readline()为空的问题究竟如何产生?难道是six模块版本太老?或是真的是配置错误?还是我删掉了一些必要的代码?抑或是我用dd命令生成的测试文件有问题?
    多方尝试,耗费整整一天,依然无果。第二天升级编译python-six模块,并利用其它大文件做PUT object测试,问题依旧。在耗费两天毫无进展,自己都快发疯时,注意到了一个问题,那便是proxy server会返回状态码503然后输出如下信息:

    Object PUT returning 503, 1/5 required connections
    

    在源码中查询搜索了这条错误信息,发现只有在_check_min_conn()函数使用默认msg参数时,会输出这样的错误信息。而这样的调用仅在_check_failure_put_connections()函数的最末发生过一次!!!
    到这里,总算发现解决问题的曙光。根本问题就出在纠删码策略PUT object过程中_store_object()调用_check_failure_put_connections()函数时(line. 2200)。我重读了这部分代码,发现_check_min_conn()函数中检查链接过程,实际上是将纠删码策略存取成功所需最新链接数min_conns和成功建立的链接conns数量相比较,后者要大于等于前者。即:
    len(conns) >= min_conns
    其中min_conns = policy.quroum_size,与选用的存储策略相关,quorum_size在相应的存储策略中均有定义(NRW策略)。比如我选用(4,2)RS码进行编码,即有:quorum_size = 4 + 2/2 = 5。而所有连接建立成功情况下,len(conns)值应为选定存放数据的结点数,应为6,其中nodes初始值由object_ring给出。但在我修改后的代码中,仅成功创建了一个链接,即len(conns) == 1

    追根溯源

    我终于明白是怎么回事。最初我看到了标示不同数据段的boundary,便理所当然认为proxy obj controller 和 object server之间仅会建立起一个链接,然后将所有的数据段传输上去,在我修改后的代码中,所有的数据放在一个http链接上进行传输,自始至终只成功建立了一个http链接。所有的一切,源于我对swift纠删码策略的一个错误认知:将boundary进行分区的在网络上进行传输的数据段(fragments)和要放置在一个具体结点上的相应数据块(由许多fragments组成)混淆了,boundary是用来区分不同网络数据段,并不是用来区分传输至不同object-server的多个数据块!!!
    要保证纠删码策略正常,proxy和每个object-server间必须建立起相应的链接,而我只建立成功了一个链接,object-server端仍旧在等待真正的对象数据传输过去,而proxy obj controller这边确因为_check_min_conn()不合格而返回503,接下来的数据传输过程自然无从谈起,object-server苦等良久,却得不到需要的数据,这也就解释了为何对request.environ['wsgi.input']中数据处理到后来因为空而报错!也就是:

    ValueError: invalid literal for int() with base 16: ''
    

    后尝试注释掉obj controller中_check_min_conn(),代码果真一路向下正常运行,顿感心情舒畅。
    关于最初在网络上搜索到的同类问题,我亦怀疑问题并不是出在接收数据方,而是数据发送方。没有具体研究过,仅写出我的经验,供参考。

    参考:

    [1]List Openstack上关于此问题的回答
    [2]launchpad上关于此问题的研究
    [3]nova中出现的类似错误
    [4]ssync-reciver中类似问题

  • 相关阅读:
    MSClass (Class Of Marquee Scroll通用不间断滚动JS封装类)
    IE和FF下javascript获取网页宽高及窗口大小
    JSON View – JSON格式化查看工具
    查询功能所属的菜单
    会计科目API CCID
    应付的帐龄分析SQL
    采购到入库所经历的表
    金额大小写转换(2)
    oracle行列转换总结
    金额大小写转换(1)
  • 原文地址:https://www.cnblogs.com/qiyukun/p/4816676.html
Copyright © 2011-2022 走看看