Il y a une table, qui a 200 lignes. Mais le nombre de nuplets vivants montrant qu’il ya plus que cela (environ 60K).
select count(*) from subscriber_offset_manager;
count
-------
200
(1 row)
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 61453 | 5
(1 row)
Mais comme vu de pg_stat_activity et de pg_locks, nous ne sommes pas en mesure de suivre une connexion ouverte.
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity
USING (pid)
WHERE relation::regclass = 'subscriber_offset_manager'::regclass
;
query | state | locktype | mode
-------+-------+----------+------
(0 rows)
J'ai aussi essayé le vide complet sur cette table. Voici les résultats:
Voici la sortie.
vacuum FULL VERBOSE ANALYZE subscriber_offset_manager;
INFO: vacuuming "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": found 0 removable, 67920 nonremovable row versions in 714 pages
DETAIL: 67720 dead row versions cannot be removed yet.
CPU 0.01s/0.06u sec elapsed 0.13 sec.
INFO: analyzing "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": scanned 710 of 710 pages, containing 200 live rows and 67720 dead rows; 200 rows in sample, 200 estimated total rows
VACUUM
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 200 | 67749
et après 10 secondes
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 68325 | 132
Comment notre application demande à cette table.
Notre application sélectionne généralement certaines lignes et, sur la base de certains calculs, met à jour la ligne.
sélection de requête - sélection basée sur un identifiant
select * from subscriber_offset_manager où shard_id = 1;
requête de mise à jour - met à jour une autre colonne pour cet identifiant de fragment sélectionné
environ 20 threads le font en parallèle et un thread ne fonctionne que sur une seule ligne.
Encore une observation intéressante: - Lorsque j'arrête mon application Java et que je fais le vide complet, tout fonctionne correctement (le nombre de lignes et le nombre de lignes deviennent égaux). Il y a donc quelque chose qui ne va pas si nous sélectionnons et mettons à jour continuellement à partir de l'application Java. -
Problème/Problème
Ces tuples vivants vont parfois à des tuples morts et reviennent vivre après quelques fois.
En raison du comportement ci-dessus, sélectionnez dans le tableau le temps et l’augmentation de la charge sur le serveur, car de nombreux live/deadtuples sont présents.
Je connais trois choses qui empêchent VACUUM
de faire son travail:
Longues transactions.
Transactions préparées qui n'ont pas été validées.
Slots de réplication obsolètes.
Voir mon article de blog pour plus de détails.
J'ai eu le problème.
Pour comprendre le problème, considérez le flux suivant:
Fil 1 -
De nombreux threads de type Thread-1 s'exécutant en parallèle.
Fil 2 -
Solution temporaire - Si je ferme toutes les connexions établies par Thread-2 en utilisant pg_cancel_backend, alors l'aspiration commence à fonctionner.
Nous avons également recréé le problème plusieurs fois et avons essayé cette solution et cela a fonctionné.
Maintenant, il y a des doutes suivants auxquels on ne répond toujours pas.
Quelques observations époustouflantes:
@Erwin Brandstetter et @Laurenz Albe, si vous savez qu'il y a un bogue lié à postgres/jdbc.
Après tout, il peut y avoir des verrous, votre requête peut être trompeuse:
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass
pg_locks.pid
peut être NULL, la jointure éliminerait alors les lignes. Le manuel pour Postgres 9.3:
Identificateur de processus du processus serveur détenant ou en attente de ce verrou, ou null si le verrou est conservé par une transaction préparée
Gras accent mien. (Toujours le même à la page 10.)
Avez-vous quelque chose pour la requête simple?
SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;
Cela pourrait expliquer pourquoi VACUUM
se plaint:
DETAIL: 67720 dead row versions cannot be removed yet.
Ceci, à son tour, indiquerait des problèmes dans la logique/les requêtes de votre application, bloquant plus de lignes que nécessaire.
Ma première idée serait longues transactions, où même une simple SELECT
(acquisition d'un verrou ACCESS SHARE
peu élevé) peut empêcher VACUUM
de faire son travail. 20 threads en parallèle pourraient chaîner et verrouiller VACUUM
indéfiniment. Gardez vos transactions (et leurs serrures) aussi brèves que possible. Et assurez-vous que vos requêtes sont optimisées et ne verrouillez pas plus de lignes que nécessaire.
Une dernière chose à noter: l'isolation de transaction les niveaux SERIALIZABLE
ou REPEATABLE READ
rendent beaucoup plus difficile le nettoyage de VACUUM
. Le mode READ COMMITTED
par défaut est moins restrictif, mais VACUUM
peut toujours être bloqué comme indiqué.
En relation: