We migrated one OpenERP v7 instance to Odoo v8 via OpenUpgrade. Before the upgrade the system was fast enough. After the upgrade the system is very slow if more than one user (10-20) accessing the system. Maybe you can help me to increase the performance.
The current setup:
four vservers in the cloud (provider: Strato)
one vserver hosts the PostgreSQL database system
two vservers provide the odoo v8 instances
one vserver is a "loadbalancer" (nginx) which forwards the traffic to the odoo vservers
Nearly all users access the same odoo instance because the loadbalancer is for the fallback if one odoo instance is not reachable (we use the ip hash algorithm).
Stats (in peak times):
vserver | memory usage | Disk I/O utilization | load avg | Network I/O
--------------------------------------------------------------------------------------
loadbalancer | 179 / 512MB | < 2% | < 0.1 | 0.4 MB/s
odoo 1 | 0.6 / 2GB | < 2% | < 0.8 | 0.6 MB/s
odoo 2 | 1 / 2 GB | < 2% | < 0.4 | 0.8 MB/s
postgres | 1.1 / 4 GB | < 6% | < 0.3 | 0.8 MB/s
CPU usage is okay (see load)
Database:
I updated PostgreSQL from 9.1 to 9.4.
I see no difference in the speed (maybe a bit faster).
I increased some parameters like shared_buffers (=1GB).
The cache hits increased but no performance changes (maybe a bit faster).
Some postgresql stats (average in peak times):
Transactions:
yesterday: 250 transactions/s
today: 134 transactions/s
Reads: 3520 tuples/s
Updates: 2 tuples/s
Inserts: 1.6 tuples/s
Deletes: 0.9 tuples/s
Locks:
Access Share: 163
Row Exclusive: 30
Now some information about our tables:
SELECT schemaname || '.' || relname as table, n_live_tup as num_rows FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 10;
table | num_rows
------------------------------------------------+----------
public.mail_message | 290485
public.mail_followers_mail_message_subtype_rel | 99410
public.mail_followers | 83080
public.account_move_line | 70889
public.ir_model_data | 57953
public.res_partner | 51304
public.wkf_workitem | 42916
public.mail_notification | 41701
public.wkf_instance | 40854
public.res_partner_res_partner_category_rel | 29752
(10 rows)
SELECT schemaname || '.' || relname as table, heap_blks_read as disk_reads, heap_blks_hit as cache_reads, heap_blks_read + heap_blks_hit as total_reads FROM pg_statio_user_tables ORDER BY heap_blks_read + heap_blks_hit DESC LIMIT 15;
table | disk_reads | cache_reads | total_reads
-----------------------------+------------+-------------+-------------
public.purchase_order | 4238 | 32316190 | 32320428
public.res_partner | 10170 | 21109387 | 21119557
public.account_invoice | 2594 | 20076555 | 20079149
public.mail_message | 50876 | 19058003 | 19108879
public.account_move_line | 7769 | 3946367 | 3954136
public.mail_notification | 924 | 2652774 | 2653698
public.res_company | 3 | 1573888 | 1573891
public.account_move | 3082 | 1482233 | 1485315
public.res_users | 19 | 1257049 | 1257068
public.sale_order | 690 | 981857 | 982547
public.product_template | 767 | 916337 | 917104
public.account_account | 251 | 857989 | 858240
public.crm_lead | 2316 | 498267 | 500583
public.product_product | 492 | 454269 | 454761
public.res_groups_users_rel | 22 | 408204 | 408226
(15 rows)
SELECT nspname || '.' || relname AS "table", pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND C.relkind <> 'i' and nspname !~ '^pg_toast' ORDER BY pg_total_relation_size(C.oid) DESC LIMIT 10;
table | total_size
------------------------------------------------+------------
public.ir_attachment | 1333 MB
public.mail_message | 225 MB
public.res_partner | 134 MB
public.account_move_line | 46 MB
public.ir_model_data | 26 MB
public.mail_followers | 21 MB
public.purchase_order | 13 MB
public.ir_translation | 12 MB
public.mail_followers_mail_message_subtype_rel | 12 MB
public.mail_notification | 12 MB
(10 rows)
sorted by lines_read_total:
SELECT schemaname || '.' || relname as table, seq_scan, idx_scan, idx_tup_fetch + seq_tup_read as lines_read_total, n_tup_ins as num_insert, n_tup_upd as num_update, n_tup_del as num_delete FROM pg_stat_user_tables ORDER BY lines_read_total DESC LIMIT 10;
table | seq_scan | idx_scan | lines_read_total | num_insert | num_update | num_delete
--------------------------+----------+----------+------------------+------------+------------+------------
public.account_invoice | 39389 | 219049 | 440230366 | 14666 | 6323 | 1
public.res_partner | 4801 | 2716984 | 255995782 | 51312 | 4819 | 1
public.purchase_order | 28235 | 98654 | 178473412 | 6479 | 3919 | 0
public.account_move | 12569 | 97578 | 61072327 | 28558 | 2930 | 0
public.account_move_line | 4472 | 502235 | 51382939 | 71588 | 14476 | 1
public.mail_message | 1704 | 1403914 | 37891051 | 290921 | 286 | 4
public.product_product | 2777 | 123512 | 18006526 | 6634 | 1005 | 0
public.account_account | 8967 | 146644 | 16325954 | 1858 | 5384 | 0
public.payment_line | 5854 | 38098 | 14298565 | 2499 | 204 | 0
public.res_users | 347243 | 11889 | 13258621 | 45 | 238 | 0
(10 rows)
sorted by seq_scan:
SELECT schemaname || '.' || relname as table, seq_scan, idx_scan, idx_tup_fetch + seq_tup_read as lines_read_total, n_tup_ins as num_insert, n_tup_upd as num_update, n_tup_del as num_delete FROM pg_stat_user_tables ORDER BY seq_scan DESC LIMIT 10;
table | seq_scan | idx_scan | lines_read_total | num_insert | num_update | num_delete
------------------------------+----------+----------+------------------+------------+------------+------------
public.res_company | 2016508 | 0 | 1584118 | 1 | 0 | 0
public.res_users | 347049 | 11889 | 13250453 | 45 | 238 | 0
public.res_groups | 114201 | 124449 | 4055919 | 57 | 0 | 0
public.multi_company_default | 83315 | 0 | 0 | 0 | 0 | 0
public.res_currency | 65770 | 0 | 11125874 | 176 | 0 | 0
public.ir_config_parameter | 61542 | 0 | 676896 | 11 | 7 | 0
public.account_tax | 49250 | 2380 | 997255 | 21 | 0 | 0
public.crm_case_section | 44407 | 594 | 170207 | 4 | 0 | 0
public.wkf_activity | 43521 | 42293 | 1692101 | 63 | 0 | 0
public.account_journal | 42337 | 20 | 547950 | 22 | 0 | 1
(10 rows)
I activated the debug_rpc log - here is an extract of the last messages:
015-04-30 10:35:29,497 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: crm.case.section name_search: time:0.025s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:29,958 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice search_read: time:0.224s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:30,302 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: crm.case.categ name_get: time:0.093s mem: 655460k -> 655460k (diff: 0k)
2015-04-30 10:35:30,865 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: res.partner name_get: time:0.658s mem: 655460k -> 655460k (diff: 0k)
2015-04-30 10:35:30,920 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: sale.order.line default_get: time:0.384s mem: 655460k -> 655460k (diff: 0k)
2015-04-30 10:35:31,110 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice.line read: time:0.889s mem: 655460k -> 655460k (diff: 0k)
2015-04-30 10:35:31,391 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.uom name_get: time:0.138s mem: 663656k -> 680048k (diff: 16392k)
2015-04-30 10:35:31,525 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.tax name_get: time:0.131s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:31,700 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.391s mem: 671852k -> 680048k (diff: 8196k)
2015-04-30 10:35:31,801 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice.tax read: time:0.332s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:32,187 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice.line fields_view_get: time:0.764s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:32,309 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice read_followers_data: time:2.091s mem: 655460k -> 680048k (diff: 24588k)
2015-04-30 10:35:32,627 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.228s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:32,671 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.236s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:33,077 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: sale.order.line onchange: time:1.905s mem: 663660k -> 680048k (diff: 16388k)
2015-04-30 10:35:33,135 7225 DEBUG anydatabase openerp.http.rpc.request: search_read: ir.attachment None: time:1.058s mem: 680048k -> 680048k (diff: 0k)
2015-04-30 10:35:33,334 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.206s mem: 680048k -> 671852k (diff: -8196k)
2015-04-30 10:35:33,340 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.invoice message_get_subscription_data: time:0.680s mem: 680048k -> 671852k (diff: -8196k)
2015-04-30 10:35:33,430 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: mail.message message_read: time:3.216s mem: 655460k -> 663656k (diff: 8196k)
2015-04-30 10:35:33,453 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: crm.case.section name_search: time:0.049s mem: 663656k -> 655460k (diff: -8196k)
2015-04-30 10:35:33,694 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: mail.message set_message_read: time:0.010s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:36,189 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.077s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:36,639 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.135s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:37,939 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.088s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:38,330 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.107s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:39,440 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.092s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:40,232 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product name_search: time:0.101s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:41,763 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product fields_view_get: time:0.292s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:42,285 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product default_get: time:0.219s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:42,603 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.category name_get: time:0.097s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:42,730 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.uom name_get: time:0.135s mem: 647264k -> 663656k (diff: 16392k)
2015-04-30 10:35:42,987 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: stock.location.route search: time:0.121s mem: 663656k -> 663660k (diff: 4k)
2015-04-30 10:35:43,017 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.uom name_get: time:0.191s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:43,289 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: res.company name_search: time:0.481s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:43,455 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.tax name_get: time:0.174s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:43,487 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: stock.location name_get: time:0.602s mem: 663656k -> 663660k (diff: 4k)
2015-04-30 10:35:43,644 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: stock.location name_get: time:0.574s mem: 663656k -> 663660k (diff: 4k)
2015-04-30 10:35:43,770 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: account.tax name_get: time:0.182s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:43,825 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product read_followers_data: time:0.071s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:43,883 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: stock.location name_get: time:0.624s mem: 663656k -> 663660k (diff: 4k)
2015-04-30 10:35:44,209 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: stock.location.route name_get: time:0.189s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:44,376 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.supplierinfo fields_view_get: time:0.583s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:44,410 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.packaging fields_view_get: time:0.446s mem: 663656k -> 663656k (diff: 0k)
2015-04-30 10:35:44,461 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.product onchange: time:2.120s mem: 647264k -> 655460k (diff: 8196k)
2015-04-30 10:35:46,837 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.027s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:57,006 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: sale.order fields_view_get: time:0.159s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:58,037 7225 DEBUG anydatabase openerp.http.rpc.request: notify: None None: time:0.145s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:35:58,073 7225 DEBUG anydatabase openerp.http.rpc.request: search_read: sale.order None: time:0.904s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:36:03,363 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.supplierinfo fields_view_get: time:0.051s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:36:03,523 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.supplierinfo default_get: time:0.032s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:36:03,604 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: product.supplierinfo onchange: time:0.012s mem: 647264k -> 647264k (diff: 0k)
2015-04-30 10:36:03,710 7225 DEBUG anydatabase openerp.http.rpc.request: call_kw: res.company name_search: time:0.023s mem: 647264k -> 647264k (diff: 0k)
As you can see some calls are not very slow but others take seconds.
Do you have any hints?
Ty to use pgtune and compare result. See https://www.odoo.com/forum/help-1/question/how-to-tune-postgresql-for-openerp-v7-production-environment-25326
I am considering moving towards a setup like yours for a customer (with a load balancer). Were you able to resolve the issue?