mcpField
F
frappe-ops-performance

frappe-ops-performance

github.com/impertio-studioクラウド・DevOps198114 回インストール30 週間前に更新
リポジトリ

frappe-ops-performance について

Frappe/ERPNext の運用担当者向けのパフォーマンス調整リファレンスです。MariaDB、Redis、Gunicorn、RQ の診断、監視、スケーリングを扱います。

主な機能

  1. 01データベース設定とスロークエリ分析
  2. 02Redis のメモリとキャッシュ設定
  3. 03Gunicorn ワーカーの調整
  4. 04RQ キューとバックグラウンドジョブの診断
  5. 05ログとシステム状態の監視
  6. 06垂直・水平スケーリングの指針

活用シーン

  1. 01ページ表示の遅延調査
  2. 02バックグラウンドジョブ滞留の診断
  3. 03メモリ負荷とタイムアウトの軽減
  4. 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/
.gitkeep
anti-patterns.md
examples.md
workflows.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-cache13000ドキュメントキャッシュ、セッションデータ256MB-1GB
redis-queue11000RQ ジョブキュー128MB-512MB
redis-socketio12000リアルタイムイベント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.logHTTP リクエスト、エラー
ワーカーログ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

バージョンによる違い

機能v14v15v16
サイトレベルのログ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 とクエリのパターン

コメント