Tiempos de carga largos para la página de resumen de usuario con base de datos lenta

Hola,

Estamos experimentando tiempos de carga enormes al acceder a la página de resumen de un usuario. Parece que la carga del resumen tarda más cuanto más activo es un usuario en nuestro sitio. Lo cual, sí, parece bastante obvio, pero la diferencia en los tiempos de carga en nuestro sitio es inmensa.
Así, cargar la página de resumen de un usuario “nuevo” (con algunas semanas de actividad) toma ~1 segundo, pero cargar la página de un usuario que ha tenido actividad diaria durante años toma hasta 30-40 segundos.

Por lo tanto, hemos revisado la base de datos y quedamos bastante impresionados por el tamaño de la tabla (incluyendo índices) de topic_views, que es de 62 GB.

Aquí están nuestras 7 tablas más grandes:

relación tamaño_total tamaño_tabla tamaño_indice reltuples
topic_views 62 GB 17 GB 45 GB 399215000
posts 27 GB 22 GB 5022 MB 9123860
top_topics 15 GB 708 MB 15 GB 1602180
post_search_data 15 GB 12 GB 2849 MB 8181010
incoming_links 12 GB 5330 MB 6647 MB 90008900
user_actions 3184 MB 877 MB 2307 MB 11872800
topics 2117 MB 1035 MB 1082 MB 1613070

Para probar esto, seleccionamos el ID de un usuario del que sabemos que tiene un tiempo de carga enorme en los resúmenes y realizamos un conteo con ese ID en la tabla topic_views. Esta consulta tomó casi el mismo tiempo que el resumen del usuario tardó en cargar. Por lo tanto, la parte de temas vistos es responsable de este retraso.

Como se explicó en temas anteriores, hemos actualizado un sitio antiguo basado en Discourse (v1.2.4 + modificaciones) a la v2.4.0-beta.2 y ahora estamos ejecutando Discourse v2.4.0-beta6. Por lo tanto, podría haber quedado algún dato residual. Pero no sabemos qué se puede eliminar.

En este punto, estamos bastante inseguros sobre qué hacer o ajustar a continuación. Nuestra instalación se ejecuta completamente en Azure utilizando una instancia externa de Azure Database for PostgreSQL y hemos aplicado la configuración descrita en su postgres.10.template.yml. Ni siquiera sabemos si el tamaño de la tabla topic_views (especialmente el índice) es “demasiado grande” en relación con las otras tablas o si es bastante normal.

Agradecemos cualquier pista, reflexión o idea.

Saludos cordiales,
Sascha Hofmann

P.D.
Olvidé mencionar que, debido a esto, tenemos varios errores 502 (mostrados en el sitio mismo, por lo que no es una página de error de nginx ni de la puerta de enlace de la aplicación) al cargar /u/<username>/summary.json.

¿Lo estás viendo como administrador / personal o como anónimo? La vista del personal es mucho más costosa.

No hay diferencia si veo /u/<username>/summary como administrador/personal o con mi cuenta de usuario normal. También tenemos habilitada la opción ‘ocultar perfiles de usuario al público’, por lo que los perfiles no son visibles para los anónimos (la desactivé para pruebas, pero no hay diferencia, ya que temas vistos también aparece en el resumen).

¿Has migrado, modificado o reconstruido la misma base de datos una y otra vez? Es posible que tu base de datos necesite un VACUUM para actualizar las estadísticas. Las consultas de 30 segundos están muy fuera del rango normal que observamos en las instalaciones de Discourse (aunque, admitámoslo, tu base de datos es grande).

VACUUM FULL vale la pena probarlo si puedes aceptar cierto tiempo de inactividad.

¿También está tu base de datos en almacenamiento SSD rápido con MUCHA RAM? Eso es crítico.

Para saber exactamente cuál es el problema:

  1. Edita el archivo app.yml y agrega tu correo de usuario administrador a DISCOURSE_DEVELOPER_EMAILS.

  2. Reconstruye

  3. Carga la página lenta mientras inicias sesión como el usuario configurado en el paso 1.

  4. Comparte el resultado del mini-profiler

Comparte el contenido de esto y de la ventana expandida:

Lo hemos probado varias veces, pero siempre con una copia fresca del conjunto de datos antiguo. Después de unas pocas semanas, y tan pronto como estuvimos seguros de haber revertido con éxito los cambios del propietario anterior, ejecutamos la actualización y la migración una sola vez.

Definitivamente vale la pena intentarlo, pero no estoy muy seguro de cuánto tiempo tomará. Pero sí, deberíamos considerar un VACUUM completo. Especialmente porque ya tuvimos algunos problemas con la base de datos anterior ya.

Sí. Todos los datos se almacenan en un SSD del servidor y están respaldados por 40 GB de RAM (de los cuales se utiliza aproximadamente el 60% en general, sin alcanzar el 100% en cargas más altas).

Gracias por este consejo, lo probaré. Como utilizamos nuestra propia imagen de Docker, donde falta app.yml, deberíamos lograr el mismo comportamiento añadiendo la(s) dirección(es) de correo a developer_emails en discourse.conf.

Puedes entrar en la consola de Rails y usar Developers.create!(user_id: 123), donde 123 es tu ID de usuario.

Desafortunadamente, no funciona (sí, ya reemplacé el 123 antes :slight_smile:) :

discourse@2d5c3bf04550:~$ rails console --environment=production
Cargando entorno de producción (Rails 6.0.0)
irb(main):001:0> Developers.create!(user_id: 123)
Traceback (most recent call last):
        1: from (irb):1
NameError (constant Developers no inicializado)

Otro enfoque:

discourse@2d5c3bf04550:~$ rails runner --environment=production make_me_dev.rb
Traceback (most recent call last):
/var/www/discourse/bin/rails: Bootsnap::LoadPathCache::FallbackScan
	19: from /var/www/discourse/bin/rails:17:in `<main>'
	18: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
	17: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
	16: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
	15: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	14: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
	13: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	12: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
	11: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
	10: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>'
	 9: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke'
	 8: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform'
	 7: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch'
	 6: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'
	 5: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run'
	 4: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/runner/runner_command.rb:42:in `perform'
	 3: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:52:in `load'
	 2: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:69:in `rescue in load'
	 1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:69:in `load'
make_me_dev.rb:1:in `<main>': constant Developers no inicializado (NameError)
discourse@2d5c3bf04550:~$ cat make_me_dev.rb
Developers.create!(user_id: 123)

Intentaré el método de discourse.conf y proporcionaré los datos solicitados lo antes posible.

¡Gracias por tus consejos hasta ahora!

Bueno, por eso siempre le decimos a la gente que utilice el método oficial y compatible para instalar Discourse, de modo que, cuando se necesite ayuda, podamos asistir utilizando herramientas estándar.

Sí, puede ser porque estamos usando supervisord para iniciar todos los procesos.

De todos modos, aquí está la salida que solicitaste (contenido HTML comprimido):
_u_x_strom_summary.json-13498.2ms-ProfilingResults.zip (94.5 KB)

Esta solicitud tardó 13 segundos, pero tuve que cargar el sitio dos veces. Nuevamente, el primer intento tardó demasiado, lo que resultó en un error 502. Así que quizás algunos elementos ya estaban en caché.

Se tardó más de 13 segundos en ejecutar 51 consultas SQL. Tu base de datos está seriamente mal configurada o carece de potencia.

Los principales responsables
SELECT "posts"."id" AS t0_r0, "posts"."user_id" AS t0_r1, "posts"."topic_id" AS t0_r2, "posts"."post_number" AS t0_r3, "posts"."raw" AS t0_r4, "posts"."cooked" AS t0_r5, "posts"."created_at" AS t0_r6, "posts"."updated_at" AS t0_r7, "posts"."reply_to_post_number" AS t0_r8, "posts"."reply_count" AS t0_r9, "posts"."quote_count" AS t0_r10, "posts"."deleted_at" AS t0_r11, "posts"."off_topic_count" AS t0_r12, "posts"."like_count" AS t0_r13, "posts"."incoming_link_count" AS t0_r14, "posts"."bookmark_count" AS t0_r15, "posts"."avg_time" AS t0_r16, "posts"."score" AS t0_r17, "posts"."reads" AS t0_r18, "posts"."post_type" AS t0_r19, "posts"."sort_order" AS t0_r20, "posts"."last_editor_id" AS t0_r21, "posts"."hidden" AS t0_r22, "posts"."hidden_reason_id" AS t0_r23, "posts"."notify_moderators_count" AS t0_r24, "posts"."spam_count" AS t0_r25, "posts"."illegal_count" AS t0_r26, "posts"."inappropriate_count" AS t0_r27, "posts"."last_version_at" AS t0_r28, "posts"."user_deleted" AS t0_r29, "posts"."reply_to_user_id" AS t0_r30, "posts"."percent_rank" AS t0_r31, "posts"."notify_user_count" AS t0_r32, "posts"."like_score" AS t0_r33, "posts"."deleted_by_id" AS t0_r34, "posts"."edit_reason" AS t0_r35, "posts"."word_count" AS t0_r36, "posts"."version" AS t0_r37, "posts"."cook_method" AS t0_r38, "posts"."wiki" AS t0_r39, "posts"."baked_at" AS t0_r40, "posts"."baked_version" AS t0_r41, "posts"."hidden_at" AS t0_r42, "posts"."self_edits" AS t0_r43, "posts"."reply_quoted" AS t0_r44, "posts"."via_email" AS t0_r45, "posts"."raw_email" AS t0_r46, "posts"."public_version" AS t0_r47, "posts"."action_code" AS t0_r48, "posts"."image_url" AS t0_r49, "posts"."locked_by_id" AS t0_r50, "topics"."id" AS t1_r0, "topics"."title" AS t1_r1, "topics"."last_posted_at" AS t1_r2, "topics"."created_at" AS t1_r3, "topics"."updated_at" AS t1_r4, "topics"."views" AS t1_r5, "topics"."posts_count" AS t1_r6, "topics"."user_id" AS t1_r7, "topics"."last_post_user_id" AS t1_r8, "topics"."reply_count" AS t1_r9, "topics"."featured_user1_id" AS t1_r10, "topics"."featured_user2_id" AS t1_r11, "topics"."featured_user3_id" AS t1_r12, "topics"."avg_time" AS t1_r13, "topics"."deleted_at" AS t1_r14, "topics"."highest_post_number" AS t1_r15, "topics"."image_url" AS t1_r16, "topics"."like_count" AS t1_r17, "topics"."incoming_link_count" AS t1_r18, "topics"."category_id" AS t1_r19, "topics"."visible" AS t1_r20, "topics"."moderator_posts_count" AS t1_r21, "topics"."closed" AS t1_r22, "topics"."archived" AS t1_r23, "topics"."bumped_at" AS t1_r24, "topics"."has_summary" AS t1_r25, "topics"."archetype" AS t1_r26, "topics"."featured_user4_id" AS t1_r27, "topics"."notify_moderators_count" AS t1_r28, "topics"."spam_count" AS t1_r29, "topics"."pinned_at" AS t1_r30, "topics"."score" AS t1_r31, "topics"."percent_rank" AS t1_r32, "topics"."subtype" AS t1_r33, "topics"."slug" AS t1_r34, "topics"."deleted_by_id" AS t1_r35, "topics"."participant_count" AS t1_r36, "topics"."word_count" AS t1_r37, "topics"."excerpt" AS t1_r38, "topics"."pinned_globally" AS t1_r39, "topics"."pinned_until" AS t1_r40, "topics"."fancy_title" AS t1_r41, "topics"."highest_staff_post_number" AS t1_r42, "topics"."featured_link" AS t1_r43, "topics"."reviewable_score" AS t1_r44 FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (post_number > 1) ORDER BY posts.like_count DESC, posts.created_at DESC LIMIT 6; 

Tardó 6248.3 ms

SELECT "topic_links"."id" AS t0_r0, "topic_links"."topic_id" AS t0_r1, "topic_links"."post_id" AS t0_r2, "topic_links"."user_id" AS t0_r3, "topic_links"."url" AS t0_r4, "topic_links"."domain" AS t0_r5, "topic_links"."internal" AS t0_r6, "topic_links"."link_topic_id" AS t0_r7, "topic_links"."created_at" AS t0_r8, "topic_links"."updated_at" AS t0_r9, "topic_links"."reflection" AS t0_r10, "topic_links"."clicks" AS t0_r11, "topic_links"."link_post_id" AS t0_r12, "topic_links"."title" AS t0_r13, "topic_links"."crawled_at" AS t0_r14, "topic_links"."quote" AS t0_r15, "topic_links"."extension" AS t0_r16, "topics"."id" AS t1_r0, "topics"."title" AS t1_r1, "topics"."last_posted_at" AS t1_r2, "topics"."created_at" AS t1_r3, "topics"."updated_at" AS t1_r4, "topics"."views" AS t1_r5, "topics"."posts_count" AS t1_r6, "topics"."user_id" AS t1_r7, "topics"."last_post_user_id" AS t1_r8, "topics"."reply_count" AS t1_r9, "topics"."featured_user1_id" AS t1_r10, "topics"."featured_user2_id" AS t1_r11, "topics"."featured_user3_id" AS t1_r12, "topics"."avg_time" AS t1_r13, "topics"."deleted_at" AS t1_r14, "topics"."highest_post_number" AS t1_r15, "topics"."image_url" AS t1_r16, "topics"."like_count" AS t1_r17, "topics"."incoming_link_count" AS t1_r18, "topics"."category_id" AS t1_r19, "topics"."visible" AS t1_r20, "topics"."moderator_posts_count" AS t1_r21, "topics"."closed" AS t1_r22, "topics"."archived" AS t1_r23, "topics"."bumped_at" AS t1_r24, "topics"."has_summary" AS t1_r25, "topics"."archetype" AS t1_r26, "topics"."featured_user4_id" AS t1_r27, "topics"."notify_moderators_count" AS t1_r28, "topics"."spam_count" AS t1_r29, "topics"."pinned_at" AS t1_r30, "topics"."score" AS t1_r31, "topics"."percent_rank" AS t1_r32, "topics"."subtype" AS t1_r33, "topics"."slug" AS t1_r34, "topics"."deleted_by_id" AS t1_r35, "topics"."participant_count" AS t1_r36, "topics"."word_count" AS t1_r37, "topics"."excerpt" AS t1_r38, "topics"."pinned_globally" AS t1_r39, "topics"."pinned_until" AS t1_r40, "topics"."fancy_title" AS t1_r41, "topics"."highest_staff_post_number" AS t1_r42, "topics"."featured_link" AS t1_r43, "topics"."reviewable_score" AS t1_r44, "posts"."id" AS t2_r0, "posts"."user_id" AS t2_r1, "posts"."topic_id" AS t2_r2, "posts"."post_number" AS t2_r3, "posts"."raw" AS t2_r4, "posts"."cooked" AS t2_r5, "posts"."created_at" AS t2_r6, "posts"."updated_at" AS t2_r7, "posts"."reply_to_post_number" AS t2_r8, "posts"."reply_count" AS t2_r9, "posts"."quote_count" AS t2_r10, "posts"."deleted_at" AS t2_r11, "posts"."off_topic_count" AS t2_r12, "posts"."like_count" AS t2_r13, "posts"."incoming_link_count" AS t2_r14, "posts"."bookmark_count" AS t2_r15, "posts"."avg_time" AS t2_r16, "posts"."score" AS t2_r17, "posts"."reads" AS t2_r18, "posts"."post_type" AS t2_r19, "posts"."sort_order" AS t2_r20, "posts"."last_editor_id" AS t2_r21, "posts"."hidden" AS t2_r22, "posts"."hidden_reason_id" AS t2_r23, "posts"."notify_moderators_count" AS t2_r24, "posts"."spam_count" AS t2_r25, "posts"."illegal_count" AS t2_r26, "posts"."inappropriate_count" AS t2_r27, "posts"."last_version_at" AS t2_r28, "posts"."user_deleted" AS t2_r29, "posts"."reply_to_user_id" AS t2_r30, "posts"."percent_rank" AS t2_r31, "posts"."notify_user_count" AS t2_r32, "posts"."like_score" AS t2_r33, "posts"."deleted_by_id" AS t2_r34, "posts"."edit_reason" AS t2_r35, "posts"."word_count" AS t2_r36, "posts"."version" AS t2_r37, "posts"."cook_method" AS t2_r38, "posts"."wiki" AS t2_r39, "posts"."baked_at" AS t2_r40, "posts"."baked_version" AS t2_r41, "posts"."hidden_at" AS t2_r42, "posts"."self_edits" AS t2_r43, "posts"."reply_quoted" AS t2_r44, "posts"."via_email" AS t2_r45, "posts"."raw_email" AS t2_r46, "posts"."public_version" AS t2_r47, "posts"."action_code" AS t2_r48, "posts"."image_url" AS t2_r49, "posts"."locked_by_id" AS t2_r50 FROM "topic_links" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "topic_links"."topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "topic_links"."post_id" WHERE (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "topic_links"."user_id" = 643476 AND "topic_links"."internal" = FALSE AND "topic_links"."reflection" = FALSE AND "topic_links"."quote" = FALSE ORDER BY clicks DESC, topic_links.created_at DESC LIMIT 6; 

Tardó 258.3 ms

SELECT acting_user_id, COUNT(*) FROM "user_actions" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "user_actions"."target_topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "user_actions"."target_post_id" WHERE ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "user_actions"."user_id" = 643476 AND "user_actions"."action_type" = 2 GROUP BY "user_actions"."acting_user_id" ORDER BY COUNT(*) DESC LIMIT 6; 

Tardó 245.5 ms

SELECT user_actions.user_id, COUNT(*) FROM "user_actions" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "user_actions"."target_topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "user_actions"."target_post_id" WHERE ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "user_actions"."action_type" = 2 AND "user_actions"."acting_user_id" = 643476 GROUP BY "user_actions"."user_id" ORDER BY COUNT(*) DESC LIMIT 6; 

Tardó 277.2 ms

SELECT replies.user_id, COUNT(*) FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (replies.user_id <> 643476) GROUP BY replies.user_id ORDER BY COUNT(*) DESC LIMIT 6; 

Tardó 3064.6 ms

SELECT category_id FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 GROUP BY topics.category_id ORDER BY COUNT(*) DESC LIMIT 6; 

Tardó 2283.3 ms

SELECT category_id, COUNT(*) FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (post_number > 1) AND (topics.category_id in (64,13,59,124,327,122)) GROUP BY topics.category_id ORDER BY COUNT(*) DESC; 

Tardó 811.5 ms

Supongo que Azure tiene algún tipo de estadísticas de base de datos para el servicio alojado; debes revisarlas y evaluar qué cambios son necesarios.

Además, verifica la URL /sidekiq en tu instalación para ver si no hay contención en la cola que mantenga la base de datos ocupada.

Eso es lo primero que verificamos. Nuestra instancia tiene:

  • 8 núcleos (~16,18% de utilización, con picos hasta el 60%)
  • 40 GB de RAM (~60% usado, sin picos)
  • 2244 IOPS disponibles (~2,5% de utilización, con picos hasta el 24%)

Como se mencionó, hemos utilizado la configuración descrita en tu postgres.10.template.yml . Todo lo demás está en su valor predeterminado. Parece que deberíamos volver a revisarlo.

Sidekiq se ve bien en este momento. 0 ocupados, 0 en cola, 0 reintentos, 1 programado, 0 muertos. La lista de trabajos está actualmente vacía.

Por lo tanto, para llegar a una primera conclusión: primero revisaremos la configuración de PostgreSQL, ya que hay algunas optimizaciones que podríamos aplicar. Si no funciona, deberíamos considerar actualizar la instancia de PostgreSQL y/o realizar un vaciado completo.

Gracias por tu tiempo hasta ahora y que tengas un buen fin de semana.
Saludos cordiales,
Sascha

Si tu máquina tiene 40 GB de RAM, los valores predeterminados en postgres.10.template.yml ya no son adecuados, como se señala en samples/standalone.yml:

Hola,

gracias por tu respuesta. Existen algunas limitaciones al utilizar una instancia de PostgreSQL en Azure. No se pueden configurar ciertos parámetros como effective_cache_size, max_connections, maintenance_worker_mem o shared_buffers.

Al momento de redactar esta solicitud de soporte, estábamos utilizando el nivel “General Purpose”, que nos proporcionaba 40 GB de RAM, pero solo 1 GB de shared_buffers y 2,5 GB de effective_cache_size.

Desde ayer, hemos cambiado al nivel “Memory Optimized”, lo que duplicó la RAM a 80 GB, con 2 GB de shared_buffers y 5 GB de effective_cache_size.

work_mem, un parámetro que sí podemos ajustar, está actualmente configurado en 128 MB, ya que no hay entradas de temporary file en nuestros registros.

Lo interesante fue que, tan pronto como cambiamos de nivel, el uso de CPU y IOPS disminuyó sin aumentar los vCores ni el almacenamiento. Esto confirma que teníamos un problema causado por cachés y búferes demasiado pequeños.

Aún tenemos tiempos de carga prolongados al mostrar páginas de resumen de algunos usuarios (especialmente usuarios del personal o usuarios de larga data) o la página about, pero es mucho mejor que antes (aproximadamente el 50% de los tiempos de carga anteriores).

Saludos cordiales,

P.D.
Para quienes enfrenten problemas similares y tengan mayor control sobre su instalación de PostgreSQL, estas guías podrían ser útiles:

Me alegra saberlo. Los siguientes pasos serían ver si puedes conformarte con usar una instancia de 4 vCPU optimizada para memoria como optimización de precios, o pasar a ejecutarla tú mismo.

Ah, estamos ejecutando 8 vCores, lo que resulta en 80 GB de RAM. shared_buffers está configurado en 2 GB, pero debería estar en 16 GB para este nivel y número de vCores. Sin embargo, estamos en contacto con el Soporte de Azure para solucionar esto.

P.D.
Ya estamos configurados con 16 GB de shared_buffers. Malinterpreté la salida de SELECT * FROM pg_settings WHERE name = 'shared_buffers';. La unidad es 8 KB.

Así que creo que este tema puede cerrarse. Les agradezco a todos su esfuerzo y espero que podamos lograr un mejor rendimiento en los próximos días junto con el soporte de Azure.

P.P.D.
Lo siento, @riking, te entendí mal. Creo que estamos bien con 8 vCores en lugar de reducirlo a 4. ¿Podríamos intentarlo tan pronto como logremos el rendimiento que buscamos?