この文書はPostgreSQL11.7とpgpool4.1.1の話題です。

なんらかの理由でテーブルをロックしたままのPostgreSQLのSQLをキャンセルしてロックを開放したい場合以下の関数を使います。


この関数は成功するとtrueを返すのですが、trueが返ってきたからといって、キャンセルできる(プロセスを終了できる)わけではありません。
以下に例を示します。
ap2=# select l.pid , a.backend_start from (select pid from pg_locks group by pid) l,pg_stat_activity a where l.pid=a.pid order by query_start;
  pid  |         backend_start
-------+-------------------------------
 10673 | 2020-05-06 14:06:57.721961+09
 18222 | 2020-05-06 15:52:12.091632+09
 28546 | 2020-05-06 16:30:04.77062+09
(3 rows)

ap2=# SELECT pg_cancel_backend(10673);
 pg_cancel_backend
-------------------
 t
(1 row)

ap2=# SELECT pg_cancel_backend(18222);
 pg_cancel_backend
-------------------
 t
(1 row)

ap2=# select l.pid , a.backend_start from (select pid from pg_locks group by pid) l,pg_stat_activity a where l.pid=a.pid order by query_start;
  pid  |         backend_start
-------+-------------------------------
 10673 | 2020-05-06 14:06:57.721961+09
 18222 | 2020-05-06 15:52:12.091632+09
 28546 | 2020-05-06 16:30:04.77062+09
(3 rows)
10673と18222のプロセスを終了したいのですが、終了できません。
pg_terminate_backend(pid int)を使うと終了できるのですが、pgpoolを使っている場合、pg_terminate_backendを使うとpgpoolがPostgreSQLを切り離すので、サービスが中断します。

ErogameScapeにおいて、上記のようにpg_cancel_backendがきかないのは以下のような状況のときのようでした。

Apacheにアクセス
php-fpmがpgpoolにクエリを発行
pgpoolがPostgreSQLにクエリを発行
クエリの実行に時間がかかる
一定時間たってもphp-fpmから応答がないのでApacheがtimeoutとしてユーザーに504を返す
このあとpsコマンドで確認すると
pgpoolはidleもしくはidle in transaction
PostgreSQLはSELECTだったりUPDATEだったりpgpoolが発行したSQLを実行している状態

以下、例を示します。
[root@sakura ap2]# cat /var/log/httpd/access_log | grep update
127.0.0.1 - - [08/May/2020:04:40:01 +0900] "GET /~ap2/ero/toukei_kaiseki/update_userreview_display_log.php HTTP/1.1" 504 247 "-" "Wget/1.19.5 (linux-gnu)" 60027802
127.0.0.1 - - [08/May/2020:04:41:02 +0900] "GET /~ap2/ero/toukei_kaiseki/update_userreview_display_log.php HTTP/1.1" 504 247 "-" "Wget/1.19.5 (linux-gnu)" 60060326
127.0.0.1 - - [08/May/2020:04:42:04 +0900] "GET /~ap2/ero/toukei_kaiseki/update_userreview_display_log.php HTTP/1.1" 200 462 "-" "Wget/1.19.5 (linux-gnu)" 6428
[root@sakura ap2]# cat /var/lib/pgsql/11/log/postgresql-Fri.log
2020-05-08 04:41:10.718 JST [28908] [ap2] LOG:  duration: 8271.792 ms  execute : UPDATE userreview SET display_unique_count = coalesce( display_unique_count , 0 ) + $1 WHERE uid = $2 AND game = $3 ;
ap2=# select * from (select pid from pg_locks group by pid) l,pg_stat_activity a where l.pid=a.pid order by query_start;
  pid  |  datid   | datname |  pid  | usesysid | usename | application_name | client_addr | client_hostname | client_port |
        backend_start         |          xact_start           |          query_start          |         state_change
  | wait_event_type | wait_event | state  | backend_xid | backend_xmin |
     query                                                         |  backend_type
-------+----------+---------+-------+----------+---------+------------------+-------------+-----------------+-------------+-
------------------------------+-------------------------------+-------------------------------+-----------------------------
--+-----------------+------------+--------+-------------+--------------+----------------------------------------------------
-------------------------------------------------------------------+----------------
 28908 | 10934808 | ap2     | 28908 |    16385 | ap2     |                  | 127.0.0.1   |                 |       55878 |
2020-05-08 04:41:01.103872+09 | 2020-05-08 04:41:02.407331+09 | 2020-05-08 04:41:02.446477+09 | 2020-05-08 04:41:02.446478+0
9 | Client          | ClientRead | active |    17877103 |              | UPDATE userreview SET display_unique_count = coales
ce( display_unique_count , 0 ) + $1 WHERE uid = $2 AND game = $3 ; | client backend
この状態で
SELECT pg_cancel_backend(28908);
しても、28908を終了させることができません。

28908を使っているpgpoolのプロセスを殺したところ、28908を終了させることができました。
pcp_proc_infoコマンドで28908を使っているpgpoolのプロセスIDを確認します。
[ap2@sakura ~]$ pcp_proc_info -h /var/run/postgresql/ -U pgpool | grep 28908
Password:
ap2 ap2 2020-05-08 04:36:00 2020-05-08 04:41:01 3 0 2 28908 1 27546 0
28908と27546のプロセスを確認します。
[ap2@sakura ~]$ ps ax | grep 27546
 8121 pts/0    S+     0:00 grep --color=auto 27546
27546 ?        S      0:00 pgpool: ap2 ap2 127.0.0.1(58634) idle in transaction
[ap2@sakura ~]$ ps ax | grep 28908
 8134 pts/0    S+     0:00 grep --color=auto 28908
28908 ?        Ss     0:00 postgres: ap2 ap2 127.0.0.1(55878) UPDATE
27546をkillします。
※確か、kill 27546では殺せなくて、kill -KILL 27546で殺しました。
これで、28908のプロセスも開放されて、ロックされていたテーブルもロックが解除されました。

※そもそも、なぜpostgresがSELECTやUPDATEのまま止まってしまうのかの原因は未だ分かりません…