1
Help us understand the problem. What are the problem?

posted at

updated at

Organization

ラズパイのプロセス監視を slee-Pi3 のウォッチドッグタイマで【異常動作検知ー実装編】

今回は slee-Pi3 のウォッチドッグタイマを利用したプロセス監視を行います。
前回【異常動作検知による監視】は動作確認でしたが、今回はより実用性を求めて service ファイルでNice 等は設定しません
※作業環境と事前準備は こちら をご覧ください。

[関連ブログ]

slee-Pi3 のウォッチドッグタイマを利用したプロセス監視
OOM 状態からの即時復帰
正常動作検知による監視
異常動作検知による監視
【異常動作検知-実装編】← 本ブログ

[目的と方法]

目的:停止したくないプログラムが停止した場合に、クリーンな状態で再開させたい。
方法:プログラム内にハートビートを組込んでおき、ウォッチドッグタイマが異常検知した際に再起動させる。

[手順1]service ファイル作成

なるべくシンプルなものを作成します。

/etc/systemd/system/test-heartbeat.service
[Unit]
Description=sleepi3 test heartbeat
DefaultDependencies=no 
After=sysinit.target

[Service]
Type=simple
ExecStart=/opt/mtx/test-heartbeat.py ← 実行ファイルのフルパス

[Install]
WantedBy=sysinit.target

[手順2]実行プログラム+ハートビートを作成

素数計算中にハートビートを発生させます。
RaspberryPiでよく使うpythonを用います。

#!/bin/python3

import os
import time
import math
from datetime import datetime
from datetime import timedelta

LED_PATH = '/sys/class/leds/sleepi:led0/brightness'
PRIME_PATH = '/var/log/prime-num.log'

class LedBlink():
    def __init__(self,num,dt):
        self.num = num
        self.dt = dt

    def blink(self):
        now = datetime.now()
        if now - self.dt > timedelta(seconds=1):
            with open(LED_PATH,mode="w") as f:
                f.write(self.num)
            self.dt = now
            if self.num == "0":
                self.num = "1"
            else:
                self.num = "0"

def check_files():
    #calculation continue
    if os.path.isfile(PRIME_PATH):
        with open(PRIME_PATH) as f:
            saved_num = f.readline()
    #path lost
    else:
        with open(PRIME_PATH,mode="w") as f:
            f.write("3")
        print("new prime-log created")
    return int(saved_num)

def save_num(PATH,i):
    with open(PATH,mode="w") as f:
         f.write(str(i))

def prime_calc(num,Led):
    i = num
    while True:
        Led.blink()
        j = 3
        flag = 0
        r = math.sqrt(i)
        while j<=r:
            if i%j==0:
                flag = 1
                Led.blink()
                break
            j+=2
        if flag==0:
            save_num(PRIME_PATH,i)
        i+=2

def main():
    Led = LedBlink(num="0",dt=datetime.now())
    num = check_files()
    prime_calc(num,Led)

if __name__ == "__main__":
    main()
else:
    print("FILE NAME ERROR")

[手順3]既存の sleepi3-heartbeat.service を停止して自作ハートビートを起動する

sleepi3-heartbeat.service は sleePi3-utils に含まれている service です。

sudo systemctl disable sleepi3-heartbeat.service
sudo systemctl enable test-heartbeat.service
sudo systemctl restart test-heartbeat.service 

test-heartbeat.service の部分は自作ハートビートのファイル名を入れてください。

[手順4]OOMKiller 用プログラム作成と実行

こちら のブログを参考に作成しました。

[手順5]復帰確認

動作確認編と違い、Nice や OOMScoreAdjust を設定していないのでしばらく生き残りつつ、最終的には OOM によりハートビート停止 → ハードウェアリセットが確認できるはずです。

下記コマンド実行で再起動要因がわかります。

sleepi3ctl -g wakeup-flag
watchdog

[まとめ]

今回は slee-Pi3 のウォッチドッグタイマによるプロセス監視機能を利用しました。
監視されているプロセスが OOMKiller に kill された際に、ハードウェアリセットをかける仕組みです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?