1/10/2018 解決:SymantecEndpointProtectionのバグによりゾンビプロセスが発生していたことがRHELとSymantecのサポート解析により判明しました。現在は対象サーバー上でSEPのサービスを停止した所、ゾンビプロセスが0となりました、現在SEPのパッチ適用調整中です。修正したPythonスクリプトはゾンビプロセスも生成せずに完璧にメモリ開放してくれる事を確認しました。nmyu様改めてありがとうございました!
nmyu様の以下ご教授により、Pythonスクリプト自体の問題点が修正され、スクリプト実行により生成されていた、ゾンビプロセス発生は抑える事ができてたと考えております。スクリプト実行されていない状況で一晩モニターした結果、200から300程度のゾンビプロセスが発生していたので、
現在はRHELのサポートにもサポートケースを作成し、他の要因も調査しております。
------------
子プロセスがSSH接続のために生成したソケットを適切にクローズできていないのではないかと考えています。スクリプトの定期実行を自動化した場合、いずれメモリを食いつぶしてしまうため対策を調べております。
ゾンビプロセス発生を防ぐ、または発生した場合に削除するなど、Pythonスクリプト内で対処する方法をご存知の方、ご教授頂けますと幸いです。
Pythonスクリプトの実行環境:
RHEL Linux7.2 Python Version 3.6
Pythonスクリプト仕様:
約200台ある対象LinuxサーバーIPを外部ファイル"systems.txt"から一行ずつ読み取ってSSH接続し、接続先のサーバーで実行するコマンドを外部ファイル"commands.txt"から一行読み取り実行(実行するコマンドは1つのみ)。
接続先のLinuxサーバーで実行されるコマンドの内容は、あるファイルに対して絶対パスでcatコマンドを実行、実行元のサーバーの標準出力に結果を表示します。
問題:
Pythonスクリプト実行毎に、ゾンビプロセスが100程度増え、メモリを圧迫しております。
強引ではありますが、下記MainProcedureに呼び出した変数に対するdelコマンドとガベージコレクションを実行するようにもしてみましたが、変わらずゾンビプロセスが発生します。
for h in reader.hosts: for c in reader.commands: executer = CommandExecuter(h, c) results = executer.execute() print("IP: {0} :({1}):".format(h, c) + '\n') if results != None: for i in results: print(i + '\n') del c del h gc.collect()
オリジナルフルコード:
#Modules import paramiko from contextlib import suppress from paramiko import SSHException #Variables USER = 'UserID' PSWD = 'password' #Classes and Functions class InputReader: def __init__(self, commands_path, hosts_path): self.commands_path = commands_path self.hosts_path = hosts_path def read(self): self.commands = self.__readlines(self.commands_path) self.hosts = self.__readlines(self.hosts_path) def __readlines(self, path): with open(path) as f: return [v.strip() for v in f.readlines()] class CommandExecuter: def __init__(self, host, command): self.host = host self.command = command def execute(self): with suppress(TimeoutError): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(self.host, username=USER, password=PSWD) stdin, stdout, stderr = ssh.exec_command(self.command) errors = stderr.readlines() lines = [v.strip() for v in stdout.readlines()] return lines #ここで変数hの循環参照を起こしていた print('## SSH connection failed for %s ##' % h + '\n') #Main Procedure if __name__ == '__main__': reader = InputReader("commands.txt", "systems.txt") reader.read() for h in reader.hosts: for c in reader.commands: executer = CommandExecuter(h, c) results = executer.execute() print("IP:{0}({1}):".format(h, c) + '\n') if results != None: for i in results: print(i + '\n')
コード修正箇所:
from contextlib import suppress, closing ~~~~途中省略 #Classes and Functions class InputReader: def __init__(self, commands_path, hosts_path): self.commands_path = commands_path self.hosts_path = hosts_path def read(self): self.commands = self.__readlines(self.commands_path) self.hosts = self.__readlines(self.hosts_path) def __readlines(self, path): with open(path) as f: return [v.strip() for v in f.readlines()] #List comprehension class CommandExecuter: def __init__(self, host, command): self.host = host self.command = command def execute(self): with suppress(Exception): with closing(paramiko.SSHClient()) as ssh: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(self.host, username=USER, password=PSWD) stdin, stdout, stderr = ssh.exec_command(self.command) errors = stderr.readlines() lines = [v.strip() for v in stdout.readlines()] return lines print('## %s SSH connection failed ##' % self.host + '\n') def __del__(self): self.host = None self.command = None self.commands_path = None self.hosts_path = None self.exec_command = None del self def main(): reader = InputReader("/root/CR/commands.txt", "/root/CR/systems.txt") reader.read() for h in reader.hosts: for c in reader.commands: executer = CommandExecuter(h, c) results = executer.execute() print("IP: {0} :({1}):".format(h, c) + '\n') if results != None: for i in results: print(i + '\n') del executer del results gc.collect() #Main Procedure if __name__ == '__main__': main()
回答1件
あなたの回答
tips
プレビュー