異常に高いCPU使用率

これで最後の情報を提供します。その後は数時間離脱すると思います。

root@discourse_app:/# ps aux --sort=-%mem | head -20
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
postgres    4398 17.0 22.0 8216352 6797764 ?     Ss   11:14   9:53 postgres: 15/main: discourse discourse [local] UPDATE
postgres    2729 15.3 21.1 8123888 6517308 ?     Ss   11:13   9:03 postgres: 15/main: discourse discourse [local] UPDATE
postgres    2501 15.9 19.9 8079700 6148812 ?     Ds   11:13   9:25 postgres: 15/main: discourse discourse [local] UPDATE
postgres   22777 16.9 19.5 8084888 6012052 ?     Ds   11:42   4:58 postgres: 15/main: discourse discourse [local] UPDATE
postgres    2753 28.5 11.3 8055000 3482260 ?     Ss   11:13  16:50 postgres: 15/main: discourse discourse [local] idle
postgres   25715  2.9  6.9 7884064 2135536 ?     Ss   11:47   0:44 postgres: 15/main: discourse discourse [local] idle
postgres   20487  2.9  6.6 7885300 2061088 ?     Ss   11:39   0:59 postgres: 15/main: discourse discourse [local] idle
postgres   22055  3.3  6.5 7887336 2012504 ?     Ss   11:41   1:02 postgres: 15/main: discourse discourse [local] idle
postgres   25883  2.5  6.0 7884096 1848424 ?     Ss   11:47   0:38 postgres: 15/main: discourse discourse [local] idle
postgres   28126  2.4  5.6 7883848 1744912 ?     Ss   11:50   0:31 postgres: 15/main: discourse discourse [local] idle
postgres   29365  1.0  4.5 7883084 1386544 ?     Ss   11:52   0:12 postgres: 15/main: discourse discourse [local] idle
postgres   27172  1.6  4.4 7884288 1384664 ?     Ss   11:49   0:22 postgres: 15/main: discourse discourse [local] idle
postgres   25896  2.1  4.4 8034236 1357264 ?     Ss   11:47   0:31 postgres: 15/main: discourse discourse [local] idle
postgres      89  1.7  4.3 7864156 1342760 ?     Ss   11:11   1:04 postgres: 15/main: checkpointer
postgres   28505  1.0  4.2 7884360 1315360 ?     Ss   11:51   0:13 postgres: 15/main: discourse discourse [local] idle
postgres   27175  1.6  4.1 7882780 1277612 ?     Ss   11:49   0:23 postgres: 15/main: discourse discourse [local] idle
postgres   28553  0.9  3.4 7883976 1064964 ?     Ss   11:51   0:11 postgres: 15/main: discourse discourse [local] idle
postgres   30409  1.0  3.3 7882892 1034860 ?     Ss   11:54   0:10 postgres: 15/main: discourse discourse [local] idle
postgres   40651  4.6  1.9 7872036 592152 ?      Ss   12:11   0:03 postgres: 15/main: discourse discourse [local] idle
root@discourse_app:/# redis-cli info memory
# Memory
used_memory:179899224
used_memory_human:171.57M
used_memory_rss:47591424
used_memory_rss_human:45.39M
used_memory_peak:184509776
used_memory_peak_human:175.96M
used_memory_peak_perc:97.50%
used_memory_overhead:3681093
used_memory_startup:948600
used_memory_dataset:176218131
used_memory_dataset_perc:98.47%
allocator_allocated:181437808
allocator_active:182353920
allocator_resident:188317696
allocator_muzzy:0
total_system_memory:31537295360
total_system_memory_human:29.37G
used_memory_lua:58368
used_memory_vm_eval:58368
used_memory_lua_human:57.00K
used_memory_scripts_eval:10304
number_of_cached_scripts:13
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:33792
used_memory_vm_total:92160
used_memory_vm_total_human:90.00K
used_memory_functions:192
used_memory_scripts:10496
used_memory_scripts_human:10.25K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.00
allocator_frag_bytes:700208
allocator_rss_ratio:1.03
allocator_rss_bytes:5963776
rss_overhead_ratio:0.25
rss_overhead_bytes:-140726272
mem_fragmentation_ratio:0.26
mem_fragmentation_bytes:-132268896
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_total_replication_buffers:0
mem_clients_slaves:0
mem_clients_normal:498197
mem_cluster_links:0
mem_aof_buffer:0
mem_allocator:jemalloc-5.3.0
mem_overhead_db_hashtable_rehashing:0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
root@discourse_app:/# cat /etc/postgresql/15/main/postgresql.conf | grep shared_buffers
shared_buffers = 7424MB
#wal_buffers = -1                       # min 32kB, -1 sets based on shared_buffers
root@discourse_app:/# su - postgres -c "psql discourse -c \"SELECT pid, query_start, state, wait_event_type, wait_event, left(query, 100) as query FROM pg_stat_activity WHERE state != 'idle' ORDER BY query_start;\""
  pid  |          query_start          | state  | wait_event_type |  wait_event  |                                                query
-------+-------------------------------+--------+-----------------+--------------+------------------------------------------------------------------------------------------------------
  2501 | 2026-02-07 11:25:01.028892+00 | active | IO              | DataFileRead | UPDATE posts                                                                                        +
       |                               |        |                 |              | SET percent_rank = X.percent_rank                                                                   +
       |                               |        |                 |              | FROM (                                                                                              +
       |                               |        |                 |              |   SELECT posts.id, Y.percent_rank                                                                   +
       |                               |        |                 |              |   FROM posts
  4398 | 2026-02-07 11:52:53.108942+00 | active | IPC             | BufferIO     | WITH eligible_users AS (                                                                            +
       |                               |        |                 |              |   SELECT id                                                                                         +
       |                               |        |                 |              |   FROM users                                                                                        +
       |                               |        |                 |              |   WHERE id > 0 AND active AND silenced_till IS NUL
  2729 | 2026-02-07 11:54:27.666129+00 | active | IPC             | BufferIO     | UPDATE topics AS topics                                                                             +
       |                               |        |                 |              | SET has_summary = (topics.like_count >= 1 AND                                                       +
       |                               |        |                 |              |                    topics.post
 22777 | 2026-02-07 11:59:27.040575+00 | active | IO              | DataFileRead | UPDATE posts                                                                                        +
       |                               |        |                 |              | SET percent_rank = X.percent_rank                                                                   +
       |                               |        |                 |              | FROM (                                                                                              +
       |                               |        |                 |              |   SELECT posts.id, Y.percent_rank                                                                   +
       |                               |        |                 |              |   FROM posts
 27172 | 2026-02-07 12:15:42.50553+00  | active | IO              | DataFileRead | SELECT "posts"."id" FROM "posts" WHERE "posts"."deleted_at" IS NULL AND "posts"."topic_id" = 792311
 25883 | 2026-02-07 12:15:52.665883+00 | active |                 |              | SELECT "posts"."id" FROM "posts" WHERE "posts"."deleted_at" IS NULL AND "posts"."topic_id" = 829626
 20487 | 2026-02-07 12:16:09.733384+00 | active | IO              | DataFileRead | SELECT "posts"."id" FROM "posts" WHERE "posts"."deleted_at" IS NULL AND "posts"."topic_id" = 653216
 42185 | 2026-02-07 12:16:21.053706+00 | active | IO              | DataFileRead | SELECT "posts"."id", "posts"."user_id", "posts"."topic_id", "posts"."post_number", "posts"."raw", "p
 43940 | 2026-02-07 12:16:21.925505+00 | active |                 |              | SELECT pid, query_start, state, wait_event_type, wait_event, left(query, 100) as query FROM pg_stat_
 28126 | 2026-02-07 12:16:21.96218+00  | active | IO              | DataFileRead | SELECT "posts"."id" FROM "posts" WHERE "posts"."deleted_at" IS NULL AND "posts"."topic_id" = 818063
 42323 | 2026-02-07 12:16:21.966689+00 | active | Client          | ClientRead   | SELECT "discourse_post_event_events"."id", "discourse_post_event_events"."status", "discourse_post_e
(11 rows)

質問は、基本的に「9時間もハングアップするUPDATEクエリは何が原因か?」ということです。
メモリ不足が原因で、クエリがスワップに送られるのではないかと推測しています。
40GBのpostsテーブルがあることは問題になり得るでしょうか?


root@discourse_app:/# su - postgres -c "psql discourse -c \"SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size FROM pg_tables WHERE schemaname = 'public' ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC LIMIT 10;\""
 schemaname |     tablename     |  size
------------+-------------------+---------
 public     | posts             | 40 GB
 public     | post_search_data  | 4326 MB
 public     | topic_users       | 1306 MB
 public     | topics            | 837 MB
 public     | topic_search_data | 702 MB
 public     | post_replies      | 567 MB
 public     | top_topics        | 512 MB
 public     | user_actions      | 417 MB
 public     | topic_links       | 285 MB
 public     | directory_items   | 243 MB

postgresのメモリ設定を調整してみましたか?

新しい仮想マシンへの移行で何かが解決するのであれば、大したことではなく、ダウンタイムなしで、わずかな読み取り専用時間で実行できます。

「いいね!」 1

はい、以前にも似たような問題があったため、一度やりました。それは明らかにPostgresのメモリ不足が原因でした。

今回、症状は異なります。ただし、同様の問題の可能性を排除しているわけではありません。

現在、多くの手がかりが、Discourseの内部タスクに対してスレッド構造が重すぎること(このインストールはvbbフォーラムからのDIY変換によるものです)を指し示しています。そして、2年間はほとんど問題なく、昨年Postgresの設定を調整する必要があり、その後は順調でしたが、約10日前に再び、そして前回のバージョンアップから数日後に再び問題が発生したことを再度述べなければなりません。

要点は、Discourseが5000投稿のチャンクに分割していない古いスレッドが多数あり、数千のアカウントがあり、インポートされた過去の投稿履歴と通常の利用が、ハードウェアとDiscourseのアーキテクチャが通常の操作を処理するのに苦労する閾値に達したのではないかと考えていることです。

そのため、現在抱いている疑問の1つは、Discourseが巨大な商用ソリューション(例:Activision Blizzard)で広く使用されているフォーラムソフトウェアであることに長い間気づいていました。これらは有料のインストールであり、Discourseチームは適切なサポートを提供するために報酬を得ており、問題にお金を投じるという選択肢があることは理解していますが、彼らの投稿テーブルがどれほど大きいのか不思議でなりません。そして、私たちのものより小さいとは思えません。それでも、私たちが持っているアクティブな利用状況(アクティブユーザー約150人、1日あたり新規投稿約2,000件、多かれ少なかれ)でセルフホストされたソリューションが問題を抱えるとは驚きです。

また、フォーラムを読み取り専用モードにした夜、フォーラムは非常に高速でした。明らかに、投稿を含むユーザーアクティビティが、私たちが抱える状況を引き起こしています。

したがって、例えばトピックをロックしたり、非アクティブなユーザーにトラストレベル0を割り当てたりするなど、Discourseで頻繁に読み取られるデータ(トピック?)や更新されるデータ(ユーザー統計?)の一部を除外する方法があるのか疑問に思っています。

これは良い質問の方向性だと思います。大量のRAMを搭載していても、PostgreSQLがそれを特定の目的で使うように設定されており、自ら窮地に陥っている可能性があります。

2つのUPDATEクエリが同一に見えるのは気に入らない点です。これは、スケジュールされたタスクが完了するのに時間がかかりすぎたため、2番目のタスクがその後スケジュールされたことを示している可能性があります。状況がすでに悪化しているときに、さらに負荷をかけることになります。

しかし、それらの調整方法についてはわかりません。

「いいね!」 1

前回、Postgresに十分なスペースを与えることで問題を解決しました。それは、状況に対してプロセスが少なすぎ、ワーキングメモリが少なすぎました。

今回は限界に達したと思います。プロセスの数を減らしてワーキングメモリを増やすか、その逆を行ってどうなるかを見る必要があります。数時間前に最初の解決策を試しましたが、それが良い効果をもたらしているかどうかの結果を待っています。

「いいね!」 1

何を見つけるか興味があります。私はLinux管理者でしたが、データベース管理者の経験はありません。両方の側面について学ぶべきことが膨大にあります。

PostgreSQLのドキュメントで、以下を見つけました。

および

Discourseの設定がRAMサイズに応じていくつかのPostgreSQLパラメータを設定していることに気づきました。サーバーをスケールアップしても、それらのパラメータはより大きなRAMに合わせて調整されないことに注意してください。

多くの伝承や慣行は、2Gが大きなサーバーだった時代に遡る可能性があると感じています。今日のハードウェアには、より大きな数値が適切である可能性は十分にあります。

編集:私の(4G)サーバーでは、huge pagesを無効にしています。透過的な(自動的な)huge pagesは、カーネルがマージと分割に時間を費やす原因となる可能性があると考えています。しかし、PostgreSQLのドキュメントでは、huge pagesが特定の状況で有益である可能性があることが示されています。

私のシステムでは:

root@ubuntu-4gb-hel1-1:~# egrep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
root@ubuntu-4gb-hel1-1:~# egrep huge /proc/filesystems
nodev	hugetlbfs
root@ubuntu-4gb-hel1-1:~# 
root@ubuntu-4gb-hel1-1:~# head -v /proc/sys/vm/nr_hugepages /proc/sys/vm/nr_overcommit_hugepages
==> /proc/sys/vm/nr_hugepages <==
0


==> /proc/sys/vm/nr_overcommit_hugepages <==
0
root@ubuntu-4gb-hel1-1:~# egrep huge /sys/devices/system/node/node*/meminfo
root@ubuntu-4gb-hel1-1:~# 

状況が変わっていなければ、./discourse-setup を実行すると数値は調整されますが、すでに実行中のインストールであることを検出するはずです。記憶が正しければ、変更を加える前に app.yml ファイルをバックアップもします。

最後に実行したのは 3〜4 年前なので、最近変更があったかどうかはわかりません。

記憶が正しければ、共有メモリ(最大メモリの 25%)やユニコーンの Web ワーカーなどの設定を変更するだけだったと思います。何か忘れているかもしれません。

(スワップではなく、ディスクから読み取っている)

これは私の以前の観測と一致します:

これはリレーションとインデックスのサイズであることに注意してください。pg_relation_sizeと比較してください。

これはPeriodicalUpdatesの一部であるScoreCalculatorからのものです。

これは解決すべきあなたの発見です。比較のために、ここではメタ(meta)ではJobs::EnsureDbConsistencyが2分未満、Jobs::TopRefreshOlderが10秒未満で実行されます。

Postgresはより多くのメモリを必要とします。可能な限り多く割り当ててください。

また、VACUUM ANALYZEまたはVACUUM ANALYZE FULLから利益を得る可能性があります。最初のものは実行しても害はありません。

私はおそらく次の順序で実行します。

  • vacuum analyze
  • sidekiqを一時停止してからvacuum analyze full(これによりテーブルがフリーズされ、完全に書き直されます。実行中はいくつかの失敗が発生する可能性があります)
  • postgresにより多くのメモリを割り当てる
「いいね!」 1

移行中に、数GBの空き容量があるにもかかわらず、スペース不足のためにリストア/アップグレードが数回失敗しました(Restore fails due to disk space on migration のような)。

バックアップの前にバキューム(vacuum)を実行すると、その問題が解決するのに役立つでしょうか?

また

それは

 discourse=# VACUUM FULL ANALYZE;

こちらで良いアドバイスがあります:https://stackoverflow.com/a/69206920