中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python踩坑之旅其一殺不死的Shell子進程

發布時間:2020-08-06 02:35:03 來源:網絡 閱讀:2126 作者:mythmgn 欄目:軟件技術

1.1 踩坑案例

踩坑的程序是個常駐的Agent類管理進程, 包括但不限于如下類型的任務在執行:

  • a. 多線程的網絡通信包處理
    • 和控制Master節點交互
    • 有固定Listen端口
  • b. 定期作業任務, 通過subprocess.Pipe執行shell命令
  • c. etc

發現坑的過程很有意思:

  • a.重啟Agent發現Port被占用了
    • => 立刻想到可能進程沒被殺死, 是不是停止腳本出問題
    • => 排除發現不是, Agent進程確實死亡了
    • => 通過 netstat -tanop|grep port_number 發現端口確實有人占用
    • => 調試環境, 直接殺掉占用進程了之, 錯失首次發現問題的機會
  • b.問題在一段時間后重現, 重啟后Port還是被占用
    • 定位問題出現在一個叫做xxxxxx.sh的腳本, 該腳本占用了Agent使用的端口
    • => 奇了怪了, 一個xxx.sh腳本使用這個奇葩Port干啥(大于60000的Port, 有興趣的磚友可以想下為什么Agent默認使用6W+的端口)
    • => review該腳本并沒有進行端口監聽的代碼
  • 一拍腦袋, c.進程共享了父進程資源
    • => 溯源該腳本,發現確實是Agent啟動的任務中的腳本之一
    • => 問題基本定位, 該腳本屬于Agent調用的腳本
    • => 該Agent繼承了Agent原來的資源FD, 也就是這個port
    • => 雖然該腳本由于超時被動觸發了terminate機制, 但terminate并沒有干掉這個子進程
    • => 該腳本進程的父進程(ppid) 被重置為了1
  • d.問題**出在腳本進程超時kill邏輯**

1.2 填坑解法

通過代碼review, 找到shell具體執行的庫代碼如下:

self._subpro = subprocess.Popen(
    cmd, shell=True, stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    preexec_fn=_signal_handle
)
# 重點是shell=True !

把上述代碼改為:

self._subpro = subprocess.Popen(
    cmd.split(), stdout=subprocess.PIPE,
    stderr=subprocess.PIPE, preexec_fn=_signal_handle
)
# 重點是去掉了shell=True

1.3 坑位分析

Agent會在一個新創建的threading線程中執行這段代碼, 如果線程執行時間超時(xx seconds), 會調用 self._subpro.terminate()終止該腳本.

表面正常:

  • 啟用新線程執行該腳本
  • 如果出現問題,執行超時防止hang住其他任務執行調用terminate殺死進程

深層問題:

  • Python 2.7.x中subprocess.Pipe 如果shell=True, 會默認把相關的pid設置為shell(sh/bash/etc)本身(執行命令的shell父進程), 并非執行cmd任務的那個進程
  • 子進程由于會復制父進程的opened FD表, 導致即使被殺死, 依然保留了擁有這個Listened Port FD

這樣雖然殺死了shell進程(未必死亡, 可能進入defunct狀態), 但實際的執行進程確活著. 于是1.1中的坑就被結實的踩上了.

1.4 坑后擴展

1.4.1 擴展知識

本節擴展知識包括二個部分:

  • Linux系統中, 子進程一般會繼承父進程的哪些信息
  • Agent這種常駐進程選擇>60000端口的意義

擴展知識留到下篇末尾講述, 感興趣的可以自行搜索

1.4.1 技術關鍵字

  • Linux系統進程
  • Linux隨機端口選擇
  • 程序多線程執行
  • Shell執行

1.5 填坑總結

  1. 子進程會繼承父進程的資源信息
  2. 如果只kill某進程的父進程, 集成了父進程資源的子進程會繼續占用父進程的資源不釋放, 包括但不限于

    • listened port
    • opened fd
    • etc
  3. Python Popen使用上, shell的bool狀態決定了進程kill的邏輯, 需要根據場景選擇使用方式

Life is short. We use Python

工號: 程序員的夢囈指南

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

称多县| 连城县| 公安县| 岗巴县| 祁连县| 潼关县| 阳山县| 呼玛县| 阜南县| 平谷区| 会泽县| 宜丰县| 湾仔区| 宁都县| 沙坪坝区| 密云县| 长治县| 桂阳县| 晋宁县| 鸡西市| 沐川县| 惠东县| 洱源县| 罗平县| 玉门市| 宕昌县| 金堂县| 九江市| 乌拉特中旗| 阿克苏市| 晋中市| 新河县| 广元市| 灵璧县| 西乌| 三门峡市| 杭州市| 彭山县| 浑源县| 墨脱县| 望都县|