关于 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)。务必同时调优所有四个层面——只优化其中一层而忽略其他层会造成新的瓶颈。
快速参考
# 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 使用三个 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
常见瓶颈诊断
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 页面加载缓慢,数据库耗时长 | 缺少索引、N+1 查询 | 添加索引,使用带筛选条件的 get_list |
| 工作进程队列不断增长 | 工作进程太少、作业耗时过长 | 增加工作进程,优化作业代码 |
| 内存占用高,发生 OOM 终止 | Gunicorn 工作进程过多、Redis 无上限 | 减少工作进程,设置 maxmemory |
| 间歇性超时 | Gunicorn 超时时间过短 | 增加 --timeout(默认 120s) |
| 清除缓存后变慢 | 缓存未预热 | 部署后预热关键缓存 |
| 静态资源加载缓慢 | 未使用 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