從CDH Agent錯誤日誌學習Python拆包語法

從CDH Agent錯誤日誌學習Python拆包語法

國慶七天長假回來上班,遲遲沒有進入工作狀態,可能祖國的強大,讓我不自覺的也飄了起來,哈哈,該收拾收拾心情,爲祖國之繁榮而努力加班掙money了。今天通過解決公司開發環境的一個問題,讓我瞬間進入了戰鬥狀態,並且順便學了一下Python拆包的一些語法,還是挺有意思的。

1 CDH Agent錯誤日誌解決

放假回來,同事發現公司開發環境的CDH集羣掛了,好長時間沒關注了,可能早就掛了吧。掛成什麼樣了呢?兩臺節點與Manager失去心跳,所有服務都起不來了,簡直廢了,處於不可用狀態。

當時但看服務狀態以爲沒啥問題,可能是放假期間重啓服務器導致的,於是便心不在焉的重啓了一下集羣,結果可想而知,服務根本起不來。再一看有兩臺節點已經飄紅了,心想問題就出在這了,於是跑到這兩臺節點上,分別重啓了cloudera-scm-agent服務,沒想到還是不行。再去/var/log/cloudera-scm-agent/下查看一下agent的日誌,發現日誌裏報錯了。

當時沒有細看錯誤信息,看了一句unexpected exception in main loop,心想之前沒遇到過這個錯誤啊,先google一下,沒想到還真有類似的問題。https://community.cloudera.com/t5/Support-Questions/ERROR-MESSAGE-This-host-is-not-in-contact-with-the-Host/td-p/52279/page/2

參照網上的說法,在細看一下報錯信息,確實是代碼中一個地方出錯了,原來的寫法是對的,但是可能會出現問題,所以就參考網上說的改了一下,重啓Agent服務,結果主機正常了。

查看vusr/lib64/cmf/agent/build/env/lib/python2.7/site-packages/cmf-5.11.0-py2.7.egg/cmf/client_configs.py代碼446行

def _parse_alternatives(self, name, output):
         """
         Parses output from "update-alternatives --display". Returns a dictionary
         mapping ClientConfigKey to ClientConfigValue.
     
         Alternatives not managed by CM are ignored.
         """
         ret = {}
         for line in output.splitlines():
           if line.startswith("/"):
             path, _, _, priority_str = line.rstrip().split(" ")
     
             # Ignore the alternative if it's not managed by CM.
             if CM_MAGIC_PREFIX not in os.path.basename(path):
               continue
     
             try:
               priority = int(priority_str)
             except ValueError:
               THROTTLED_LOG.info("Failed to parse %s: %s", name, line)
     
             key = ClientConfigKey(name, path)
             value = ClientConfigValue(priority, self._read_generation(path))
             ret[key] = value
     
         return ret

該部分代碼如上所示,報錯行爲 path, _, _, priority_str = line.rstrip().split(" "),錯誤信息是

ValueError: too many values to unpack。我猜測可能是line.rstrip().split(" ")之後的元素個數超過了四個,導致此錯誤。這個語法很有意思,之前遇到過,但是沒有深入研究,先記得這個語法在python裏叫做拆包,後面後詳細介紹。

既然問題出在這裏,那我們簡單暴力的參考網上的改法,修改一下,修改之後如下所示:

             # path, _, _, priority_str = line.rstrip().split(" ")
             thisLine = line.rstrip().split(" ")
             path = thisLine[0]
             priority_str = thisLine[-1]

顯而易見,只是取第一個元素和最後一個元素即可。

通過這種方式,依次將兩臺失聯的主機都修改了,然後重啓了集羣,很ok。

2 Python 拆包語法

上面分析到了錯誤是由於拆包時,元素個數超過預期導致的。但是path, _, _, priority_str = line.rstrip().split(" ")這種代碼寫法,確實值得學習,很裝逼有沒有。於是我來好好學習一下這個寫法。

假設,我有一個數組array_1,裏面有3個元素10,20,30,我想把這三個元素分別賦值給a,b,c,通常寫法是:

array_1 = [10,20,30]
a = array_1[0]
b = array_1[1]
c = array_1[2]

這樣沒毛病,老鐵。但是我們可以通過拆包語法更裝逼的寫一下:

array_1 = [10,20,30]
a,b,c = array_1

很nice有沒有,人家Cloudera團隊就是這樣寫的,但是同樣這樣寫會有一個問題,如果我的數組裏有四個元素的話,你這樣寫是不是會有問題?

>>> array_2 = [10,20,30,40]
>>> a,b,c = array_2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

發現了沒有,這個錯誤有沒有很相似,與CDH Agent日誌裏的錯誤如出一轍。那麼問題來,如果你數組個數不確定,而你又使用這種方式,很容易出錯,那我們就沒法使用該語法裝逼了嗎,答案是可以的。

假如,無論數組多長,我們只想取數組的前三個元素賦值給a,b,c,可以這樣寫:

array_3 = [10,20,30,40,50]
a,b,c,*_ = array_3

那麼問題又來了,如果我們只想取第一個,第二個,以及最後一個元素賦值給a,b,c該怎麼寫呢?

array_3 = [10,20,30,40,50]
a,b,*_,c = array_3

是不是很舒服?我們還可以這樣玩,第一個、第二個元素賦值給a,b,剩下所有的元素以list的形式賦值給c

>>> a,b,*c = array_3
>>> type(c)
<class 'list'>

3 總結

接觸Python有一段時間了,對於這個語法第一次碰到,還是挺新鮮的。類似的語法在不同的編程語言中都有體現,比如scala裏也有類似的寫法,叫做提取器,如下所示:

scala> val array1 = Array(10,20,30,40)
array1: Array[Int] = Array(10, 20, 30, 40)

scala> val Array(a,b,c,_*) = array1
a: Int = 10
b: Int = 20
c: Int = 30

scala> val Array(a,b,c @_*) = array1
a: Int = 10
b: Int = 20
c: Seq[Int] = Vector(30, 40)

總的來說,今天通過與老師一起排查問題,到學習新的語法,沉澱了一下浮躁的心情,今天開始步入正軌,好好學習,天天向上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章