はじめに
Oracle CloudのARM インスタンス(Ampere A1)でSymbolノードをセットアップしたところ、300万ブロックを超えたあたりでノードがダウンし、同期が進まなくなる問題に遭遇しました。
本記事では、この問題の調査過程と暫定的な対処法を共有します。なお、根本的な解決には至っておらず、現時点では未解決の問題として記録しています。
結論: エラー原因については未解決。でもfast-syncしたらOK
先に結論をお伝えすると、エラーの解決方法はまだわかってないです。
しかし、他の同期済みのノードから以下の2つのディレクトリを持ってくることである程度同期を済ませておくと問題なく動作します。
半年ぐらい回してみましたが、特にx86_64版のサーバーで動かす場合と差異はなく動いています。
回避策: 持ってくるディレクトリ
-
data/- ブロックデータや状態情報 -
databases/- MongoDBのデータ
結論はここまでで、以下は調査・試した内容のまとめです。
発生した事象
環境
| 項目 | 詳細 |
|---|---|
| サーバー | Oracle Ampere A1 Compute(ARM64) |
| OS | Ubuntu Server 24.04 |
| CPU | 4 OCPU |
| RAM | 24GB |
| Storage | 250GB Block Storage |
| Node.js | v24.11.1 |
| symbol-bootstrap | v1.1.12 linux-arm64 |
| Docker | v29.0.1 |
| Docker Compose | v2.40.3 |
エラーログ
同期処理中、320万ブロックあたりまで同期したタイミングで以下のエラーが発生しました:
$ docker compose logs -f node
node | 2025-11-24 08:38:10.671622 <error> failed when connecting to 'node.example.com': Too many open files (cancelled? false)
node | 2025-11-24 08:38:10.671671 <warning> unable to resolve and connect to static node node.example.com @ node.example.com:7900
node | 2025-11-24 08:38:10.672102 <fatal>
node | thread: server catapult
node | unhandled exception while running local node!
node | Dynamic exception type: boost::wrapexcept<boost::filesystem::filesystem_error>
node | std::exception::what: Failed to open file for writing: Input/output error [generic:5]: "/symbol-workdir/logs/catapult_server0000.log"
node |
node | Shutting down server
重要なのは1行目のここ: Too many open files
ログから読み取れる流れは以下の通りです:
- 同期処理中にpeerへの接続が増加
- ファイルディスクリプタ(FD)が枯渇
- ログファイルへの書き込みすら失敗
- ノードがクラッシュ
調査内容
試したこと1: コンテナ内プロセスのFD数を確認
まず、コンテナ内でどれだけのFDが使用されているかを確認しました。
PID=$(docker inspect -f '{{.State.Pid}}' node)
echo "FD Count:"; ls /proc/$PID/fd | wc -l
echo "FD Limit:"; grep FDSize /proc/$PID/status
echo "RSS:"; grep VmRSS /proc/$PID/status
結果:
FD Count: 4
FDSize: 256
VmRSS: 約3MB
FDの上限が256しかありません。これは流石に不足してるかも?
試したこと2: OS全体のFD上限を確認
次に、OS側の制限を確認しました。
$ cat /proc/sys/fs/file-max
9223372036854775807
64bit整数の最大値が設定されており、OS側の制限ではないことがわかりました。
試したこと3: docker-compose.ymlの修正
OS側は問題なかったため、Docker Compose側でFD上限を引き上げることにしました。
target/docker/docker-compose.ymlのrest-gateway外のサービスにulimitsを追加:
# 抜粋
services:
db:
ulimits: #追加
nofile:
soft: 8192
hard: 16384
node:
ulimits: #追加
nofile:
soft: 8192
hard: 16384
broker:
ulimits: #追加
nofile:
soft: 8192
hard: 16384
設定が反映されたか確認:
# node起動後に以下のコマンドをdocker-compose.ymlと同じディレクトリで実行
$ docker exec -it node bash -c "ulimit -n"
8192 # OK
一見すると、8192に上がっており問題なさそうに見えます。
しかし、問題は解決しなかった
FD上限を引き上げたにもかかわらず、同期は依然として途中で停止してしまいました。
調査を進めると、以下の状況が判明しました:
-
ulimit -nでは8192と表示される - しかし同期途中(今回は60万block程度)でなぜかblockが0にしまって以後起動しなくなる
どうやら、docker-composeのulimits設定がコンテナ全体に一貫して適用されないという挙動があるようです。これはcgroup v2 + systemd + Dockerの組み合わせで発生する既知の問題のようです。(これはAIによる推測で未確認)
現時点でのまとめ
わかったこと
- ARMサーバー自体のスペックは十分(4 OCPU、24GB RAM)
- OSの
file-maxは正常に設定されている - 問題はDocker側のFD管理にある
- docker-composeの
ulimits指定がサービス単位で整合性が取れない - Symbolノードは複数プロセスが協調動作するため、この差異が致命的になる
未解決の課題
- Docker daemonレベルでFDを強く制限している可能性
- cgroup v2環境でのulimits設定の挙動
- ARM + Docker + Symbolという組み合わせ特有の問題かどうか
根本的な解決には至っていませんが、原因の方向性は「DockerのFD管理まわり」が濃厚です。
アドベントカレンダーの日までに解決したら良かったのですが残念ながら間に合わなかったので今回はここまでです。