環境
- ホスト: Raspberry Pi 4 (4GB)
GrafanaはDockerHubに公開されているイメージを使用して動かしています。 (以下のdocker-compose.yml参照)
version: "2"
services:
prometheus:
# 省略
grafana:
image: grafana/grafana-arm64v8-linux
links:
- prometheus
volumes:
- grafana-data:/var/lib/grafana
volumes:
grafana-data:
現象
例えばRaspberryPiのカーネルのtar.gz1を展開しているときの状態をiostatで確認すると、%iowaitの値が50近い値になります。これ自体はRaspberryPiのSDカード読み書き性能はそこまで高くないので、しょうがないことだと思います2。
ただ、その負荷が高くなったタイミングでGrafanaのダッシュボードの自動更新が走ると、以下のような現象が発生しました。
- Grafana上にUnauthorizedのメッセージが表示される
- Unauthorizedのメッセージが表示された後、勝手にログアウトされたり、Server Errorの画面が表示される
-
docker-compose logs grafana
に以下のようなログが記録される
grafana_1 | t=2020-09-06T04:34:56+0000 lvl=eror msg="Failed to look up user based on cookie" logger=context error="database is locked"
分析
ログに記載されている通り、データベースがロックされていてユーザの情報が取得できず、ログアウトしてしまっているようです。
DockerHubに公開されているGrafanaは、何も設定しなければSQLite3をデータベースに使用するようになっています。SQLite3のロックはデータベース単位でしかかけられないため、IO負荷が高いときロックからロック解除までの時間がかかり、その間にユーザ情報の読み取りが発生したために上記エラーが発生したと考えました。
対処
ロックが問題であれば、PostgreSQLなど他のRDBMSであれば行レベルでのロックに対応しているため、ロックにより行のデータが取得できない可能性は減るだろうと言うことで、PostgreSQLを使用するようにGrafanaを設定することにしました。
GrafanaのDockerイメージはGF_
で始まる環境変数を設定すると、grafana.iniの設定をオーバーライドできます。そのため、docker-compose.ymlを以下のように設定してPostgreSQLを使用するように設定しました。
services:
grafana:
image: grafana/grafana-arm64v8-linux
ports:
- 3111:3000
links:
- prometheus
- postgres
environment:
- GF_DATABASE_TYPE=postgres
- GF_DATABASE_HOST=postgres
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana_user
- GF_DATABASE_PASSWORD=aoZ62dMb
postgres:
image: postgres:12.4
environment:
- POSTGRES_USER=grafana_user
- POSTGRES_PASSWORD=aoZ62dMb
- POSTGRES_DB=grafana
この設定でgrafana.iniに以下の設定を行ったことになります。
[database]
type=postgres
host=postgres
name=grafana
user=grafana_user
password=aoZ62dMb
以上の設定で、これまで勝手にログアウトされていた時と同じ状況を再現しても、勝手にログアウトされることがなくなりました。
ただ、先述の通りRaspberryPiのSDカードの読み書き性能は高くないので、もしかするとこれでもシステムの負荷によってはログアウトしてしまうかもしれないです。とはいえ、その確率は大幅に減ると思っています。
参考ページ
- https://grafana.com/docs/grafana/latest/installation/configure-docker/
- https://grafana.com/docs/grafana/latest/administration/configuration/
-
raspberrypi/linuxで配布されているものです ↩
-
ioniceでも対処できるかもしれないですが、使っているIOスケジューラがbfqなので使えないのと、今回はSQLiteのロック範囲が広すぎることが原因みたいだったのでioniceは使いません ↩