frappe-ops-performance について
Frappe/ERPNext の運用担当者向けのパフォーマンス調整リファレンスです。MariaDB、Redis、Gunicorn、RQ の診断、監視、スケーリングを扱います。
主な機能
- 01データベース設定とスロークエリ分析
- 02Redis のメモリとキャッシュ設定
- 03Gunicorn ワーカーの調整
- 04RQ キューとバックグラウンドジョブの診断
- 05ログとシステム状態の監視
- 06垂直・水平スケーリングの指針
活用シーン
- 01ページ表示の遅延調査
- 02バックグラウンドジョブ滞留の診断
- 03メモリ負荷とタイムアウトの軽減
- 04単一・複数サーバー構成の計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ impertio-studio/ frappe_claude_skill_package --skill frappe-ops-performanceインストール後、Claude Code で/frappe-ops-performanceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/.gitkeepanti-patterns.mdexamples.mdworkflows.md詳細
パフォーマンスのチューニング
Frappe/ERPNext のパフォーマンスは、データベース(MariaDB)、キャッシュ(Redis)、アプリケーションサーバー(Gunicorn)、バックグラウンドワーカー(RQ)の 4 つの層に依存します。必ず 4 つの層をすべてまとめてチューニングしてください。他の層を無視して 1 つだけを最適化すると、新たなボトルネックが発生します。
クイックリファレンス
# Check system health
bench doctor
# Show pending background jobs
bench --site mysite.com show-pending-jobs
# Clear all caches
bench --site mysite.com clear-cache
bench --site mysite.com clear-website-cache
# Purge stuck background jobs
bench purge-jobs
# Enable MariaDB slow query log
# In /etc/mysql/mariadb.conf.d/50-server.cnf:
# slow_query_log = 1
# slow_query_log_file = /var/log/mysql/slow.log
# long_query_time = 1
# Check Gunicorn worker count
# In Procfile or supervisor config: -w [workers]
# Formula: workers = (2 * CPU_CORES) + 1
パフォーマンスの判断ツリー
What is slow?
|
+-- Page loads are slow?
| +-- Check Gunicorn workers (are they saturated?)
| +-- Check MariaDB slow query log
| +-- Check Redis memory (is cache evicting?)
| +-- Enable CDN for static assets
|
+-- Background jobs are delayed?
| +-- bench doctor (check worker count and pending jobs)
| +-- Increase RQ worker count
| +-- Check for long-running jobs blocking queues
|
+-- Database queries are slow?
| +-- Enable slow query log
| +-- Run EXPLAIN on slow queries
| +-- Add indexes on frequently filtered columns
| +-- Use get_cached_value instead of get_value
|
+-- Server runs out of memory?
| +-- Reduce Gunicorn workers
| +-- Set Redis maxmemory
| +-- Check MariaDB innodb_buffer_pool_size
| +-- Look for memory leaks in custom code
|
+-- High CPU usage?
| +-- Profile Python code (cProfile)
| +-- Check for N+1 query patterns
| +-- Review custom scheduled jobs
MariaDB のチューニング
重要な設定
# /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
# InnoDB buffer pool — MOST important setting
# Set to 50-70% of available RAM on dedicated DB server
# Set to 25-40% of RAM on shared server
innodb_buffer_pool_size = 2G
# Buffer pool instances (1 per GB of buffer pool)
innodb_buffer_pool_instances = 2
# Log file size (larger = better write performance, slower recovery)
innodb_log_file_size = 256M
# Flush method — use O_DIRECT to avoid double buffering
innodb_flush_method = O_DIRECT
# Character set (ALWAYS use utf8mb4 for Frappe)
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# Key buffer for MyISAM (Frappe uses InnoDB, keep small)
key_buffer_size = 32M
# Query cache (DISABLE for MariaDB 10.4+ / MySQL 8.0+)
query_cache_type = 0
query_cache_size = 0
# Connection limits
max_connections = 200
wait_timeout = 600
interactive_timeout = 600
# Temp tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Slow query log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
遅いクエリの分析
# Enable slow query log (runtime, no restart needed)
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;
# Analyze slow queries with mysqldumpslow
mysqldumpslow -t 10 -s c /var/log/mysql/slow.log
# -t 10: top 10 queries
# -s c: sort by count (use -s t for total time)
# Use EXPLAIN to analyze specific queries
EXPLAIN SELECT * FROM `tabSales Invoice` WHERE customer = 'ABC';
# Look for: type=ALL (full table scan), rows > 10000, Using filesort
インデックスの最適化
-- Check for missing indexes on frequently filtered columns
SHOW INDEX FROM `tabSales Invoice`;
-- Add index for common filter patterns
ALTER TABLE `tabSales Invoice` ADD INDEX idx_customer_date (customer, posting_date);
-- Frappe way: add index via DocType definition
-- In doctype JSON: set "in_list_view" or "search_index" on fields
-- OR use hooks.py:
-- after_migrate = ["myapp.patches.add_custom_indexes"]
Redis の設定
メモリ管理
# /etc/redis/redis.conf (or bench config/redis_cache.conf)
# Set maximum memory — NEVER let Redis use all available RAM
maxmemory 512mb
# Eviction policy — allkeys-lru is best for cache use
maxmemory-policy allkeys-lru
# Disable persistence for cache Redis (performance boost)
save ""
appendonly no
Frappe の Redis アーキテクチャ
Frappe は 3 つの Redis インスタンスを使用します。
| インスタンス | デフォルトのポート | 用途 | メモリの目安 |
|---|---|---|---|
| redis-cache | 13000 | ドキュメントキャッシュ、セッションデータ | 256MB-1GB |
| redis-queue | 11000 | RQ ジョブキュー | 128MB-512MB |
| redis-socketio | 12000 | リアルタイムイベント | 64MB-256MB |
redis-cache には必ず maxmemory を設定してください。設定しないと Redis が際限なく増加し、OOM Killer が起動する可能性があります。
Frappe のキャッシュ API
import frappe
# Basic Redis cache
frappe.cache.set_value("my_key", {"data": "value"})
result = frappe.cache.get_value("my_key")
# get_cached_value — cached database lookup (ALWAYS prefer over get_value for reads)
value = frappe.db.get_cached_value("Customer", "CUST-001", "customer_name")
# Equivalent to get_value but caches in Redis — dramatically faster for repeated reads
# Hashed cache (group related values)
frappe.cache.hset("settings", "key1", "value1")
frappe.cache.hget("settings", "key1")
# Clear specific cache
frappe.cache.delete_value("my_key")
frappe.cache.delete_keys("prefix*")
# Clear all cache (use sparingly)
# bench --site mysite.com clear-cache
Gunicorn ワーカー
ワーカー数の計算式
workers = (2 * CPU_CORES) + 1
Examples:
2 CPU cores → 5 workers
4 CPU cores → 9 workers
8 CPU cores → 17 workers
設定
# Traditional: edit Procfile or supervisor config
# In supervisor.conf:
command=/home/frappe/frappe-bench/env/bin/gunicorn \
-b 127.0.0.1:8000 \
-w 9 \ # Worker count
--timeout 120 \ # Request timeout (seconds)
--graceful-timeout 30 \ # Graceful shutdown timeout
--max-requests 5000 \ # Restart worker after N requests (prevents memory leaks)
--max-requests-jitter 500 \
frappe.app:application
# Docker: set via environment variable or command override
メモリの計算
Gunicorn の各ワーカーは 150~300MB の RAM を使用します。必ず合計メモリが足りることを確認してください。
Required RAM = workers * 300MB + MariaDB buffer pool + Redis + OS overhead
Example (4 CPU, 8GB RAM server):
9 workers * 300MB = 2.7GB (Gunicorn)
+ 2GB (MariaDB innodb_buffer_pool_size)
+ 1GB (Redis total)
+ 1.5GB (OS + other)
= 7.2GB — fits in 8GB
RAM の許容量を超える数のワーカーを設定しないでください。スワップが発生するとパフォーマンスが低下します。
バックグラウンドワーカー(RQ)
ワーカーキュー
| キュー | 用途 | デフォルトのワーカー数 |
|---|---|---|
| short | 短時間のタスク(5 分未満) | 1 |
| default | 標準的なタスク | 1 |
| long | 負荷の高いタスク(レポート、一括処理) | 1 |
ワーカー数のチューニング
# Supervisor: duplicate worker sections with unique names
# For high-volume sites, increase short/default workers:
[program:frappe-bench-frappe-worker-short-1]
command=bench worker --queue short
...
[program:frappe-bench-frappe-worker-short-2]
command=bench worker --queue short
...
# Docker: scale via docker compose
docker compose up -d --scale queue-short=3 --scale queue-long=2
ジョブの滞留を診断する
# Check overall health
bench doctor
# Expected: Workers online: N, no pending jobs
# Check specific site queues
bench --site mysite.com show-pending-jobs
# Clear stuck jobs (use when jobs are permanently stuck)
bench purge-jobs
静的アセット向け CDN の設定
# site_config.json
{
"cdn_url": "https://cdn.example.com"
}
# All /assets/ URLs will be prefixed with the CDN URL
# ALTERNATIVELY: configure at Nginx level
# location /assets {
# alias /home/frappe/frappe-bench/sites/assets;
# expires 1y;
# add_header Cache-Control "public, immutable";
# }
監視
bench doctor
bench doctor
# Output:
# -----Checking scheduler------
# mysite.com: scheduler is running
# Workers online: 3
# -----None Jobs-----
主要なログの場所
| ログ | パス | 内容 |
|---|---|---|
| Frappe の Web ログ | logs/web.log | HTTP リクエスト、エラー |
| ワーカーログ | logs/worker.log | バックグラウンドジョブの出力 |
| スケジューラーログ | logs/scheduler.log | スケジュールされたジョブの実行 |
| サイトレベルのログ | sites/{site}/logs/ | サイトごとのエラー(v13 以降) |
| スロークエリログ | /var/log/mysql/slow.log | 遅いデータベースクエリ |
スケジュール済みジョブログ(DocType)
ERPNext の UI で Setup > Scheduled Job Log を確認すると、以下を確認できます。
- ジョブの実行時間
- エラーの詳細を含む失敗したジョブ
- 実行頻度の分析
RQ ダッシュボード(任意)
# Install RQ dashboard for web-based job monitoring
pip install rq-dashboard
rq-dashboard --redis-url redis://localhost:11000
# Access at http://localhost:9181
よくあるボトルネックの診断
| 症状 | 考えられる原因 | 解決策 |
|---|---|---|
| ページの読み込みが遅い、DB 処理時間が長い | インデックスの不足、N+1 クエリ | インデックスを追加し、フィルターを指定して get_list を使用する |
| ワーカーキューが増え続ける | ワーカー不足、長時間のジョブ | ワーカーを増やし、ジョブのコードを最適化する |
| メモリ使用量が多い、OOM による強制終了 | Gunicorn ワーカーが多すぎる、Redis が際限なく増加している | ワーカーを減らし、maxmemory を設定する |
| タイムアウトが断続的に発生する | Gunicorn のタイムアウトが短すぎる | --timeout を増やす(デフォルトは 120 秒) |
| キャッシュのクリア後に遅くなる | キャッシュが空、事前のウォームアップがない | デプロイ後に重要なキャッシュを事前にウォームアップする |
| 静的アセットの読み込みが遅い | CDN がない、ブラウザーキャッシュがない | CDN を追加し、expires ヘッダーを設定する |
スケーリングのパターン
Vertical Scaling (single server):
1. Add RAM → increase innodb_buffer_pool_size + Redis maxmemory
2. Add CPU → increase Gunicorn workers + RQ workers
3. Use SSD → dramatic improvement for database I/O
Horizontal Scaling (multiple servers):
1. Separate DB server (MariaDB on dedicated host)
2. Separate Redis server(s)
3. Multiple app servers behind load balancer
4. Read replicas for reporting queries
5. Kubernetes with frappe_docker for auto-scaling
バージョンによる違い
| 機能 | v14 | v15 | v16 |
|---|---|---|---|
| サイトレベルのログ | v13 以降 | あり | あり |
bench doctor | あり | あり | あり |
| Scheduled Job Log | あり | あり | あり |
get_cached_value | あり | あり | あり |
| バックグラウンドワーカー(RQ) | あり | あり | あり |
参考ファイル
| ファイル | 内容 |
|---|---|
| examples.md | チューニング設定とスクリプトの完全な例 |
| anti-patterns.md | よくあるパフォーマンス上の誤り |
| workflows.md | チューニングの手順 |
関連スキル
frappe-ops-deployment— 本番環境へのデプロイ設定frappe-ops-backup— バックアップと災害復旧frappe-ops-bench— Bench CLI リファレンスfrappe-core-database— データベース API とクエリのパターン
コメント
Markdown 対応