جزء من سلسلة Performance & Scalability
اقرأ الدليل الكاملضبط أداء Odoo: تحسين PostgreSQL والخادم
مثيل Odoo البطيء يكلف أموالاً بسبب فقدان الإنتاجية وإحباط المستخدمين. الخبر السار: معظم مشكلات أداء Odoo قابلة للحل دون الحاجة إلى ترقية الأجهزة. الأخبار السيئة: تشخيص السبب الجذري يتطلب فهم المكدس بأكمله - Python، وPostgreSQL، وNginx، وRedis، وطبقة الشبكة.
يغطي هذا الدليل دورة الحياة الكاملة لتحسين الأداء لـ Odoo 19 Enterprise: تحديد الاختناقات، وضبط PostgreSQL، وتحسين إعدادات خادم Odoo، وتكوين التخزين المؤقت لـ Nginx، وضبط حجم البنية التحتية لديك بما يتناسب مع عدد المستخدمين وحجم المعاملات.
الوجبات الرئيسية
- يوفر ضبط PostgreSQL أكبر مكاسب في الأداء (50-300% في عمليات التثبيت النموذجية)
- يجب تعيين المخازن المؤقتة المشتركة على 25% من ذاكرة الوصول العشوائي المتوفرة كنقطة بداية
- يقوم ORM بإنشاء استعلامات N+1 التي يمكن اكتشافها باستخدام pg_stat_statements
- تعد الفهارس الموجودة في الحقول التي تتم تصفيتها بشكل متكرر (معرف_الشركة، والحالة، والتاريخ) إلزامية
- يخدم التخزين المؤقت لوكيل Nginx الأصول الثابتة دون الوصول إلى خادم Odoo
- يؤثر تكوين العامل بشكل مباشر على سعة المستخدم المتزامنة
- يقلل التخزين المؤقت لجلسة Redis من تحميل قاعدة البيانات للمصادقة
- يجب ضبط جداول التفريغ والتحليل لأحمال عمل Odoo عالية الكتابة
تشخيص اختناقات الأداء
قبل ضبط أي شيء، حدد المكان الذي يتم فيه قضاء الوقت فعليًا. التحسين الأعمى يهدر الجهد.
تمكين تسجيل استعلام Odoo:
# odoo.conf
[options]
log_level = info
logfile = /var/log/odoo/odoo.log
# For SQL query logging (development/staging only):
log_handler = odoo.sql_db:DEBUG
** تمكين التسجيل البطيء للاستعلام PostgreSQL: **
# /etc/postgresql/15/main/postgresql.conf
log_min_duration_statement = 1000 # Log queries taking > 1 second
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_lock_waits = on
تثبيت pg_stat_statements (امتداد PostgreSQL الأكثر قيمة):
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Find the top 20 slowest queries
SELECT
round(total_exec_time::numeric, 2) AS total_ms,
calls,
round(mean_exec_time::numeric, 2) AS mean_ms,
round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS pct,
left(query, 100) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
-- Reset statistics after tuning to measure improvement
SELECT pg_stat_statements_reset();
تحديد استعلامات N+1 في Odoo:
تحدث استعلامات N+1 عندما يقوم Odoo بتحميل قائمة السجلات ثم يقوم بإجراء استعلام واحد لكل سجل لجلب البيانات ذات الصلة. ابحث عن أنماط مثل هذه في pg_stat_statements:
-- This query appearing 500 times in a single page load = N+1 problem
SELECT * FROM res_partner WHERE id = $1
الحل هو استخدام آلية prefetch_ids الخاصة بـ Odoo أو إضافة select إلى استعلام ORM الخاص بك:
# Bad: triggers N+1 for partner on each order
for order in orders:
print(order.partner_id.name) # One query per order
# Good: prefetch partner data in one query
orders = self.env['sale.order'].search([...])
orders.mapped('partner_id') # Forces prefetch
for order in orders:
print(order.partner_id.name) # No additional queries
ضبط تكوين PostgreSQL
يأتي PostgreSQL مع إعدادات افتراضية محافظة مصممة للتشغيل على أي جهاز. بالنسبة لخادم إنتاج Odoo، يجب ضبط هذه الإعدادات الافتراضية.
إعدادات الذاكرة (لخادم ذاكرة الوصول العشوائي سعة 32 جيجابايت):
# /etc/postgresql/15/main/postgresql.conf
# Shared buffers: 25% of RAM
shared_buffers = 8GB
# Work memory: per-operation memory for sorts/joins
# Start conservative, increase if you see disk sorts
work_mem = 64MB
# Maintenance work memory: for VACUUM, CREATE INDEX
maintenance_work_mem = 2GB
# Effective cache size: tells planner how much OS cache is available
# Set to 75% of total RAM
effective_cache_size = 24GB
# WAL settings for better write performance
wal_buffers = 256MB
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 4GB
min_wal_size = 1GB
إعدادات الاتصال:
# Maximum connections (Odoo workers × 2 + headroom)
max_connections = 200
# For connection pooling with PgBouncer
# If using PgBouncer, reduce to 50-100
إعدادات مخطط الاستعلام:
# Enable parallel query execution
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_worker_processes = 16
# SSD storage: random_page_cost should equal seq_page_cost
random_page_cost = 1.1 # Default is 4.0 (for spinning disk)
seq_page_cost = 1.0
# Increase statistics target for better query plans on Odoo's large tables
default_statistics_target = 200
ضبط الفراغ التلقائي لأحمال العمل عالية الكتابة:
تولد وحدات المخزون والمحاسبة والمراسلة في Odoo حركة مرور كثيفة للإدخال/التحديث. إعدادات الفراغ التلقائي الافتراضية غير كافية:
autovacuum = on
autovacuum_max_workers = 5
autovacuum_naptime = 30s
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.01 # Vacuum when 1% of rows are dead
autovacuum_analyze_scale_factor = 0.005 # Analyze when 0.5% of rows change
autovacuum_vacuum_cost_delay = 2ms # Reduce I/O throttling
فهارس قاعدة البيانات الهامة
تعد الفهارس المفقودة هي السبب الثاني الأكثر شيوعًا لمشكلات أداء Odoo بعد التكوين السيئ. يقوم Odoo بإنشاء فهارس للمفاتيح الأساسية وبعض المفاتيح الخارجية، لكن العديد من الحقول التي تمت تصفيتها بشكل شائع تفتقر إلى الفهارس.
تحقق من الفهارس المفقودة باستخدام عرض pg_missing_fk_indexes:
-- Find foreign keys without indexes
SELECT
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
pg_relation_size(tc.table_name::regclass) AS table_size
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND NOT EXISTS (
SELECT 1 FROM pg_indexes pi
WHERE pi.tablename = tc.table_name
AND pi.indexdef LIKE '%' || kcu.column_name || '%'
)
ORDER BY table_size DESC;
** الفهارس الأساسية لـ Odoo 19:**
-- Sale orders (most queried table)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_state
ON sale_order(state);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_company_date
ON sale_order(company_id, date_order DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_partner
ON sale_order(partner_id) WHERE state != 'cancel';
-- Account moves (invoicing)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_state_type
ON account_move(state, move_type);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_company_date
ON account_move(company_id, invoice_date DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_partner
ON account_move(partner_id) WHERE state = 'posted';
-- Account move lines (most queried for reconciliation)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_account_reconcile
ON account_move_line(account_id, reconciled, date);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_move_date
ON account_move_line(move_id, date);
-- Stock moves (inventory)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_move_state_product
ON stock_move(state, product_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_quant_product_location
ON stock_quant(product_id, location_id);
-- Mail messages (can grow very large)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_res_model_id
ON mail_message(res_model, res_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_date
ON mail_message(date DESC);
-- IR rule performance (access control)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_ir_rule_model_groups
ON ir_rule(model_id);
تكوين عامل Odoo
يحدد عدد العاملين في Odoo عدد الطلبات المتزامنة التي يمكن للخادم التعامل معها.
صيغة عدد العمال:
Workers = (CPU_cores × 2) + 1
Memory per worker: 256MB - 512MB depending on workload
Example for 8 CPU cores, 32GB RAM:
Workers = (8 × 2) + 1 = 17
Memory check: 17 × 512MB = 8.5GB (well within 32GB)
إعدادات عامل odoo.conf:
[options]
# Worker processes
workers = 17
# Limits to prevent runaway workers
limit_memory_hard = 2684354560 # 2.5GB hard limit (kills worker)
limit_memory_soft = 2147483648 # 2GB soft limit (triggers gc)
limit_time_cpu = 600 # CPU seconds per request
limit_time_real = 1200 # Wall clock seconds per request
limit_request = 8192 # Requests before worker restart
# Long polling (for live notifications)
longpolling_port = 8072
فهم أنواع العمال:
يستخدم Odoo نوعين من العمال:
- عمال HTTP (
workersconfig): التعامل مع جميع طلبات الويب - عمال Cron (1 محجوز): تشغيل الإجراءات المجدولة في الخلفية
يعمل عامل cron دائمًا ولكنه لا يتم احتسابه ضمن سعة HTTP الخاصة بك. تأكد من توفر عامل كرون واحد على الأقل حتى عند ذروة التحميل.
تكوين Nginx للأداء
يقع Nginx أمام Odoo ويتعامل مع إنهاء TLS وخدمة الملفات الثابتة والتخزين المؤقت اختياريًا.
تكوين Nginx عالي الأداء:
upstream odoo {
server 127.0.0.1:8069 weight=1 fail_timeout=0;
}
upstream odoochat {
server 127.0.0.1:8072 weight=1 fail_timeout=0;
}
# Cache zone for static assets
proxy_cache_path /var/cache/nginx/odoo
levels=1:2
keys_zone=odoo_cache:100m
max_size=1g
inactive=60m
use_temp_path=off;
server {
listen 443 ssl http2;
server_name your-odoo.com;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
gzip_comp_level 6;
# Static file caching
location /web/static/ {
proxy_cache odoo_cache;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating
http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
expires 7d;
proxy_pass http://odoo;
}
# Long polling for live chat/notifications
location /web/longpolling {
proxy_pass http://odoochat;
proxy_read_timeout 3600s;
proxy_connect_timeout 300s;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Main application
location / {
proxy_pass http://odoo;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 720s;
proxy_connect_timeout 300s;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy strict-origin-when-cross-origin;
}
}
Redis للجلسة وذاكرة التخزين المؤقت
يقلل Redis بشكل كبير من تحميل قاعدة البيانات لإدارة الجلسة وذاكرة التخزين المؤقت ORM الخاصة بـ Odoo.
** تثبيت وتكوين Redis: **
# Install Redis
sudo apt install redis-server
# Configure Redis for Odoo (max 4GB memory, LRU eviction)
sudo nano /etc/redis/redis.conf
# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru
save "" # Disable persistence for pure cache
tcp-keepalive 300
تكوين Odoo لاستخدام Redis:
# odoo.conf
[options]
# Redis for session storage
session_redis_host = 127.0.0.1
session_redis_port = 6379
session_redis_prefix = odoo_session_
# Redis for IR rules and ORM cache
cache_redis_host = 127.0.0.1
cache_redis_port = 6379
المراقبة وإدارة الأداء المستمر
إعداد pgBadger لتحليل سجل PostgreSQL:
# Install pgBadger
sudo apt install pgbadger
# Generate report from PostgreSQL logs
pgbadger /var/log/postgresql/postgresql-15-main.log \
-o /var/www/html/pgbadger/index.html \
--format html \
--top 20
المقاييس الرئيسية التي يجب مراقبتها:
| متري | عتبة التحذير | العتبة الحرجة |
|---|---|---|
| وقت تحميل الصفحة | > 2 ثانية | > 5 ثواني |
| وقت استعلام قاعدة البيانات | > متوسط 100 مللي ثانية | > متوسط 500 مللي ثانية |
| الذاكرة العاملة | > 80% من الحد | > 95% من الحد |
| اتصالات PostgreSQL | > 70% من الحد الأقصى | > 90% من الحد الأقصى |
| القرص IOPS | > 80% من المخصص | > 95% من المخصص |
| نسبة إصابة ذاكرة التخزين المؤقت | < 95% | < 90% |
الأسئلة المتداولة
ما هو الحد الأدنى لمواصفات الخادم لـ 50 مستخدمًا متزامنًا لـ Odoo؟
لـ 50 مستخدمًا متزامنًا مع حجم معاملات متوسط: 8 وحدات معالجة مركزية افتراضية، وذاكرة وصول عشوائي سعة 32 جيجابايت، ومحرك أقراص SSD سعة 500 جيجابايت (يفضل NVMe). تعد قاعدة بيانات PostgreSQL الخاصة بـ Odoo بمثابة عنق الزجاجة الأساسي للإدخال/الإخراج، لذا فإن التخزين السريع مهم أكثر من سرعة وحدة المعالجة المركزية الأولية. قم بتكوين 13 عاملًا (8×2-3 للإرتفاع)، ومخازن تخزين مؤقتة مشتركة بسعة 8 جيجابايت، وتأكد من وجود قاعدة البيانات الخاصة بك على وحدة تخزين SSD.
كيف يمكنني تشخيص ما إذا كان بطء Odoo الخاص بي هو Python أم PostgreSQL؟
استخدم ملف التعريف المدمج في Odoo (الإعدادات → التقنية → الأداء → ملف التعريف في وضع المطور) لتسجيل عملية بطيئة. سيُظهر مخطط اللهب ما إذا كان الوقت قد تم قضاؤه في كود Python أو في انتظار نتائج SQL. إذا كانت استعلامات SQL هي المهيمنة، فركز على ضبط PostgreSQL وفهرستها. إذا كانت لغة Python هي المهيمنة، فابحث عن التخزين المؤقت المفقود لـ @api.depends أو عدم كفاءة التعليمات البرمجية المخصصة.
هل يجب أن أستخدم PgBouncer لتجميع الاتصالات؟
نعم، لعمليات النشر التي تحتوي على أكثر من 30 عاملًا في Odoo أو حركة مرور كثيفة لواجهة برمجة التطبيقات (API). يسمح PgBouncer في تجميع وضع المعاملة للعديد من العاملين في Odoo بمشاركة مجموعة أصغر من اتصالات PostgreSQL الفعلية، مما يقلل من الحمل الزائد لكل اتصال. قم بتكوين الحد الأقصى للاتصالات في PostgreSQL إلى 50-100 عند استخدام PgBouncer، ثم قم بتعيين حجم تجمع PgBouncer ليتوافق مع عدد العاملين في Odoo.
كم مرة يجب أن أقوم بتشغيل VACUUM ANALYZE على قاعدة بيانات Odoo؟
يقوم Autovacuum بمعالجة هذا تلقائيًا إذا تم تكوينه بشكل صحيح. بعد الضبط أعلاه (عوامل القياس العدوانية، المزيد من العمال)، يجب أن يعمل الفراغ التلقائي بشكل مستمر على الجداول النشطة. قم بتشغيل SELECT schemaname, tablename, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; للتحقق من تنظيف الجداول بالمكنسة الكهربائية بشكل متكرر.
ما هو تأثير وجود عدد كبير جدًا من العاملين في Odoo؟
يستهلك كل عامل في Odoo ما يتراوح بين 256 إلى 512 ميجابايت من ذاكرة الوصول العشوائي (RAM) كحد أدنى. يؤدي عدد كبير جدًا من العمال إلى استنفاد الذاكرة، مما يتسبب في تعطل العمال (limit_memory_hard)، مما يؤدي إلى حدوث أخطاء HTTP 500 للمستخدمين. بالإضافة إلى ذلك، يمكن لعدد كبير جدًا من اتصالات PostgreSQL (العمال × max_db_connections) أن تطغى على قاعدة البيانات. ابدأ بالصيغة (CPU×2+1)، وراقب الذاكرة تحت الحمل، واضبطها إذا لزم الأمر.
الخطوات التالية
يعد ضبط أداء Odoo عملية متكررة. توفر جلسة ضبط واحدة مكاسب كبيرة، ولكن الأداء المستدام يتطلب مراقبة مستمرة وتحليل دوري للمؤشر وتعديلات التكوين مع نمو حجم البيانات لديك.
يوفر ECOSIRE عمليات تدقيق أداء Odoo لعمليات نشر المؤسسات، وتحديد التحسينات ذات التأثير الأعلى لأعباء العمل المحددة وأنماط المعاملات والبنية التحتية. لقد قام مهندسونا بضبط عمليات تثبيت Odoo من الشركات الصغيرة والمتوسطة التي تضم 10 مستخدمين إلى عمليات النشر المؤسسية التي تضم 500 مستخدم.
اطلب تدقيق أداء Odoo من ECOSIRE →
قم بمشاركة مواصفات خادمك الحالي وعدد المستخدمين والأعراض التي تواجهها، وسيقوم فريقنا بتحديد الأسباب الجذرية وتقديم خطة تحسين ذات أولوية.
بقلم
ECOSIRE Research and Development Team
بناء منتجات رقمية بمستوى المؤسسات في ECOSIRE. مشاركة رؤى حول تكاملات Odoo وأتمتة التجارة الإلكترونية وحلول الأعمال المدعومة بالذكاء الاصطناعي.
مقالات ذات صلة
Odoo Accounting vs QuickBooks: Detailed Comparison 2026
In-depth 2026 comparison of Odoo Accounting vs QuickBooks covering features, pricing, integrations, scalability, and which platform fits your business needs.
Case Study: eCommerce Migration to Shopify with Odoo Backend
How a fashion retailer migrated from WooCommerce to Shopify and connected it to Odoo ERP, cutting order fulfillment time by 71% and growing revenue 43%.
Case Study: Manufacturing ERP Implementation with Odoo 19
How a Pakistani auto-parts manufacturer cut order processing time by 68% and reduced inventory variance to under 2% with ECOSIRE's Odoo 19 implementation.
المزيد من Performance & Scalability
k6 Load Testing: Stress-Test Your APIs Before Launch
Master k6 load testing for Node.js APIs. Covers virtual user ramp-ups, thresholds, scenarios, HTTP/2, WebSocket testing, Grafana dashboards, and CI integration patterns.
Nginx Production Configuration: SSL, Caching, and Security
Nginx production configuration guide: SSL termination, HTTP/2, caching headers, security headers, rate limiting, reverse proxy setup, and Cloudflare integration patterns.
Odoo vs Acumatica: Cloud ERP for Growing Businesses
Odoo vs Acumatica compared for 2026: unique pricing models, scalability, manufacturing depth, and which cloud ERP fits your growth trajectory.
Testing and Monitoring AI Agents in Production
A complete guide to testing and monitoring AI agents in production environments. Covers evaluation frameworks, observability, drift detection, and incident response for OpenClaw deployments.
Compliance Monitoring Agents with OpenClaw
Deploy OpenClaw AI agents for continuous compliance monitoring. Automate regulatory checks, policy enforcement, audit trail generation, and compliance reporting.
Optimizing AI Agent Costs: Token Usage and Caching
Practical strategies for reducing AI agent operational costs through token optimization, caching, model routing, and usage monitoring. Real savings from production OpenClaw deployments.