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