Vous n'êtes pas identifié(e).
Pages : 1
Aucun désagrément tant que c'est constructif donc je prends. Désolé si l'urgence ma facette prod ressort parfois ^^
Les instances ont été redémarrées avec pg_ctl -D et aucune autre option particulière. Il n'y a eu aucun problème pour le rejeu des WAL ou la réouverture de l'instance. Les seules erreurs dans les logs concernent les tentatives d'accès à la table en question - une fois la base déjà up - lorsque la requête tente de remonter la ligne défectueuse. Je n'ai aucun WAL perdu ou problème d'archivage (qui se fait sur un serveur tiers). Et ma "restore_command" est également bien configuré. Mon master et mes slaves ont bien retrouvés leurs petits. Consistent recovery state reached.
Je crois qu'il y a confusion pour le backup. Je voulais dire que j'ai envisagé de restore un backup full sur un serveur tiers puis de lui faire rejouer les WAL un par un jusqu'à ce que ce fichier pg_clog manquant resurgisse pour ensuite aller le copier sur la vraie prod où il est marqué comme not found. Je n'ai pas pour autant fait de restore de ma base de prod, j'ai juste redémarré les instances et grep les erreurs (il n'y en a pas eu au démarrage).
J'ai remarqué que les fichiers dans pg_clog s'incrémentent dans le temps, manque de bol, mon dernier backup (datant d'avant l'incident) ne possède déjà plus ce fichier avant même de commencer à rejouer les WAL. Cela semble donc rejoindre la piste d'un problème latent depuis un moment et effectivement peut-être pas lié à l'incident réseau.
Le fichier était vraiment physiquement absent.
Du coup, la méthode du dumpall pour détecter la corruption est-elle suffisante ?
Faudrait-il (dans l'idéal) reboot l'ensemble de nos noeuds avant de refaire un dumpall pour mettre en évidence une corruption ?
Faire un script pour check chaque transaction vs le courant et son datfrozenxid me parait un peu compliqué (sauf si une extension fait déjà cela) ?
Egalement, nous avions essayé de delete / update la ligne, mais peut-être que la forcer/marquer comme frozen pourrait suffir (si cela est possible manuellement) ?
@rjuju:
pardon, j'ai corrigé pour le vacuum full. Non, il n'a été fait que sur le master. La replication est du streaming.
nous sommes sur du full ssd + serveurs physiques + lien 10G + iscsi + rhel6 côté infra.
@ioguix:
fsync à on.
le lien que je fais est que les pg_clog contiennent les historiques de commits/transactions qui permet ensuite à la map de visibilité de savoir quelles sont les lignes à afficher ou non, or, s'il lui manque un fichier clog, il n'est plus capable d'assurer l'intégrité de sa map de visibilité (ou si j'ai mal compris, je veux bien qu'on me corrige svp ). J'aurais bien rejoué WAL par WAL depuis mon dernier backup jusqu'à l'apparition de ce fichier pour le réintégrer, mais avec 2T de wal par jour, ce n'est pas la 1ère option qui a été envisagée.
Pour le pg_truncate_visibility_map, il me semble que cela permet effectivement que la ligne s'affiche à nouveau mais au risque/prix d'en voir d'autres qui étaient freeze ou delete réapparaitre également. Or, comme on avait la ligne sur le slave, on n'a pas choisi cette option.
Oups.
J'ai tout traduit, merci d'avoir précisé.
Bonjour à tous
Je suis perplexe face au comportement de Postgres.
Nous avons eu récemment une corruption de 2 de nos databases (PG9.6.21) suite à un incident réseau et une coupure électrique de nos noeuds sur les 3 DC que nous possédons.
La corruption semblait être du même type sur les 2:
ERROR: could not access status of transaction xxxxxx
DETAIL: Could not open file "pg_clog/yyyy": file not found
Sur notre 1er cluster:
La corruption a pu être réduite à un unique enregistrement, plus particulièrement à 2 colonnes de cette ligne.
1.
select * from mytable
=> ERROR sur master, OK sur slave
2.
select * from mytable where id<>corrupted_record_id
=> ok sur master et slave
3.
select * from mytable where id=corrupted_record_id
=> ERROR sur master, OK sur slave
4.
select all_but_2_columns from mytable where id=corrupted_record_id
=> ok sur master et slave
5.
select identified_2_colums from mytable where id=corrupted_record_id
=> ERROR sur master, OK sur slave
6.
vacuum full mytable
=> ERROR
7.
pg_dump -t mytable
=> ERROR sur master, OK sur slave
8.
pg_dumpall
=> ERROR sur master, OK sur slave
9.
delete from mytable where id=corrupted_record_id
=> ERROR
10.
update mytable set corrupted_col_1=<its_value_on_slave>, corrupted_col_2=<its_value_on_slave> where id=corrupted_record_id
=> ERROR
Nous en avons conclu qu'il n'y avait pas de perte de données mais uniquement un problème d'accès aux données de cette ligne.
Nous avons donc décidé de promote le slave en master.
Cela dit, une fois fait, le problème est apparu / persiste sur le nouveau master et a disparu sur l'ancien master devenu slave.
1ère question : pourquoi ? En quoi le rôle du noeud peut-il impacter la map de visibilité ? Ou qu'avons-nous raté ici ?
Le fix appliqué (pour ceux qui auraient la même situation):
. stop applications on that database only (1 db = 1 customer, multiple db per instance in our case, live 24/7 critical db)
. check slave is 100% sync
. dump data from table on slave
. truncate table on master
. restore data into that table on master
. reindexdb + vacuum analyze
. restart apps
Sur la 2e cluster:
Après la 1ère corruption (apparue immédiatement suite à l'incident), nous avons décidé de faire un dumpall sur l'ensemble de nos clusters et avons identifié un 2e avec le même message d'erreur.
Contrairement au 1er cluster, pas de plainte client ou de blocage fonctionnel à ce moment.
Du coup, nous n'avons pas fixé, nous avons relancé un dumpall 4 fois.
Pour 4 ? parce qu'un dumpall sur ce cluster dure entre 3 et 4h, et que le résultat a varié d'une exécution à l'autre :
1st iteration: corruption detected, error on database X, objID Y
2nd iteration: corruption detected, error on database U, objID V
3rd iteration: ok
4th iteration: ok
5th iteration: ok
Comment une telle évolution est-elle possible ?
Ma théorie:
* je comprends qu'une page est marqué comme obsolète à partir du moment ou toutes les lignes auxquelles elle fait référence sont également marquées comme obsolètes
* la page était marquée obsolète mais l'une de ses lignes ne l'était pas => corruption de la page. Vérifié avec l'extension pg_visibility et la requête suivante:
SELECT oid::regclass AS relname FROM pg_class WHERE relkind IN ('r', 'm') AND (EXISTS (SELECT * FROM pg_check_visible(oid)) OR EXISTS (SELECT * FROM pg_check_frozen(oid)));
* à un moment, qqch se passe et la ligne en question devient marquée comme obsolète => la page n'est plus corrompue puisque toutes ses lignes sont effectivement obsolètes
Mais:
Je suis vraiment perplexe sur cette étape "qqch se passe" (en assumant que ma théorie soit techniquement correcte). Comment Postgres parvient-il a marqué une ligne obsolète alors qu'il n'arrive pas à y accéder et que manuellement, nous n'avons pas réussi non plus à l'altérer ?
Surtout, si une corruption peut disparaitre de la sorte, peut-elle également (re)apparaître de la même sorte ?
Finallement:
==> comment détecter avec fiabilité une telle corruption (en cours ou à venir) ?
==> comment prévenir qu'elle ne se reproduise sur une DB où elle s'est déjà produite ? (un restore est-il vraiment fiable ou peut-il embarquer le problème)
Bonjour
Effectivement, vous avez raison. Il semblerait que Jasper ne fasse que des transactions read_only par défaut et qu'il faille passer en JNDI pour pouvoir modifier son comportement.
Je vais donc passer sous le forum de Jasper du coup ^^
Merci pour votre aide
ps: pour ceux qui seraient intéressés par la suite, voici le fil du discussion sur Jasper : http://jasperforge.org/plugins/espforum … icid=95700
Déjà testé la requête sans passer par Jasper : cela fonctionne très bien.
Maintenant, cela n'explique pas pourquoi le SET TRANSACTION READ WRITE n'a pas d'effet, ni encore moins pourquoi elle entraîne une erreur.
J'ai vérifié le rôle de l'user en charge de l'exécution des requêtes par Jasper, j'ai testé avec :
GRANT ALL PRIVILEGES ON FUNCTION func_update_date() TO my_role;
ALTER ROLE my_role SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE;
Sans effet non plus...
Enfin, sous Oracle, il n'y a pas ce problème, donc selon moi, le soucis vient bien de la configuration de postgres quelque part...
Bonjour,
J'utilise JasperServer pour afficher des rapports.
Ces rapports sont développés sous iReport et ne peuvent se baser que sur une seule requête de type SELECT.
J'ai besoin de faire une mise à jour avant le SELECT (ex: last_consultation_date).
Pour tricher donc, j'ai la requête suivante :
SELECT * FROM func_update_report()
Jusque là, tout va bien.
Voici maintenant la procédure stockée :
CREATE OR REPLACE FUNCTION func_update_report() RETURNS SETOF data_report AS
$BODY$
DECLARE
record data_report;
BEGIN
UPDATE my_table SET last_consultation_date = now();
FOR record IN SELECT * FROM my_table
LOOP
RETURN NEXT record;
END;
RETURN;
END;
$BODY$
LANGUAGE 'plpgsql';
Le problème est le message d'erreur suivant lorsque la procédure stockée est appelée :
org.postgresql.util.PSQLException: ERREUR: ne peut pas exécuter UPDATE dans une transaction en lecture seule Où : instruction SQL « UPDATE my_table SET last_consultation_date = now() » PL/pgSQL function "func_update_report" line 5 at instruction SQL
C'est déjà bizarre en soit puisque par défaut, le mode de transaction devrait être à READ WRITE (j'ai vérifié le postgresql.conf également)...
M'enfin, admettons. Mais là encore, si jamais j'essaie de corriger en ajoutant un SET TRANSACTION READ WRITE; entre BEGIN et UPDATE, j'ai le message d'erreur suivant :
org.postgresql.util.PSQLException: ERREUR: le mode de transaction lecture/écriture doit être configuré avant d'exécuter la première requête Où : instruction SQL « SET TRANSACTION READ WRITE » PL/pgSQL function "func_update_report" line 5 at instruction SQL
que du coup, je ne cerne pas vraiment.
Auriez-vous une idée / explication / solution?
Merci d'avance.
Pages : 1