Maison  >  Article  >  base de données  >  Explication détaillée des fonctionnalités du moteur MySQL et de la récupération après crash d'InnoDB

Explication détaillée des fonctionnalités du moteur MySQL et de la récupération après crash d'InnoDB

黄舟
黄舟original
2017-07-24 13:11:161482parcourir

Avant-propos

La plus grande différence entre un système de base de données et un système de fichiers est que la base de données peut garantir l'atomicité des opérations. Une opération n'est pas effectuée ou est effectuée même si la base de données est en panne. Cela ne se produira pas. Dans la moitié des cas, cela nécessite des journaux de base de données et un mécanisme complet de récupération après incident pour garantir cela. Cet article analyse soigneusement le processus de récupération après crash d'InnoDB et le code est basé sur la branche 5.6.

Connaissances de base

lsn : Cela peut être compris comme la quantité de journaux redo générés depuis la création de la base de données. Plus la valeur est grande, plus la mise à jour de la base de données est importante. Plus peut aussi être compris comme un moment de renouveau. De plus, chaque page de données possède également un lsn, qui représente le lsn lors de sa dernière modification. Plus la valeur est grande, plus elle a été modifiée tardivement. Par exemple, le lsn de la page de données A est de 100, le lsn de la page de données B est de 200, le lsn du point de contrôle est de 150 et le lsn du système est de 300, ce qui signifie que le système actuel a été mis à jour à 300 et que les pages de données sont plus petites. plus de 150 ont été vidées sur le disque, donc les données Les dernières données de la page A doivent être sur le disque, mais la page de données B ne l'est pas nécessairement, elle peut toujours être dans la mémoire.
redo log : Les bases de données modernes doivent écrire des redo logs. Par exemple, pour modifier une donnée, écrivez d'abord le redo log, puis écrivez les données. Après avoir écrit le journal redo, le succès est renvoyé directement au client. De cette façon, même s'il semble que le disque soit à nouveau écrit, les performances sont grandement améliorées car les écritures aléatoires sur le disque (écriture de données) sont converties en écritures séquentielles (écriture de journaux redo). Lorsque la base de données se bloque, en analysant le journal redo, vous pouvez découvrir les pages de données qui n'ont pas été vidées (avant le crash, les pages de données peuvent avoir uniquement été modifiées dans la mémoire, mais n'ont pas eu le temps d'écrire sur le disque ) pour garantir que les données ne soient pas perdues.
Annuler le journal : La base de données fournit également des fonctions similaires à l'annulation. Lorsque vous constatez que vous avez modifié des données erronées, vous pouvez utiliser la commande rollback pour annuler l'opération précédente. . Cette fonctionnalité nécessite la prise en charge des journaux d'annulation. De plus, afin d'améliorer la concurrence (le même enregistrement, la lecture par différents threads n'entre pas en conflit, la lecture et l'écriture n'entrent pas en conflit avec l'écriture et la lecture, seule l'écriture simultanée entre en conflit), tous implémentent un mécanisme similaire à MVCC. Cela repose également sur les journaux d'annulation. Afin d'obtenir une gestion unifiée, contrairement aux redo logs, les undo logs ont des pages de données correspondantes dans le Buffer Pool, qui sont gérées avec les pages de données ordinaires. Elles seront également éliminées de la mémoire selon les règles LRU et seront lues à partir du disque. plus tard. Comme les pages de données ordinaires, les modifications apportées aux pages d'annulation nécessitent également d'abord d'écrire des journaux de rétablissement.
Checkpoint : Le nom anglais est checkpoint. Afin d'améliorer les performances de la base de données, la page de données n'est pas vidée sur le disque à chaque fois que la mémoire est modifiée. Les pages de données avant le point de contrôle sont garanties d'être vidées sur le disque, de sorte que les journaux précédents seront inutiles (en raison du recyclage des journaux de redolog InnoDB, cette partie du journal peut être écrasée à ce moment-là. Les pages de données après le point de contrôle peuvent). être vidé sur le disque, ou il se peut qu'il n'y ait pas d'écriture sur le disque, donc les journaux après le point de contrôle doivent toujours être utilisés pendant la récupération après incident. InnoDB avancera régulièrement les points de contrôle en fonction de l'état d'actualisation des pages sales, réduisant ainsi le temps de récupération après incident de la base de données. Les informations sur le point de contrôle se trouvent en tête du premier fichier journal.
Récupération après incident : L'utilisateur a modifié les données et a reçu un message de réussite. Cependant, pour la base de données, les données modifiées n'ont peut-être pas été placées à ce moment-là. la base de données se bloque. Après le redémarrage, la base de données doit récupérer les données modifiées du journal et les réécrire sur le disque pour garantir que les données de l'utilisateur ne sont pas perdues. Ce processus de récupération des données du journal est la tâche principale de la récupération après incident et peut également devenir une restauration de la base de données. Bien entendu, lors d'une reprise après incident, il est également nécessaire d'annuler les transactions non validées et de soumettre les transactions ayant échoué. Étant donné que l'opération de restauration nécessite la prise en charge des journaux d'annulation et que l'intégrité et la fiabilité des journaux d'annulation nécessitent des journaux de rétablissement, la récupération après incident effectue d'abord une restauration en avant, puis effectue une restauration en arrière.

Analysons attentivement le processus de récupération après incident de la base de données du point de vue du code source. L'ensemble du processus est terminé dans la phase d'initialisation du moteur (innobase_init), dont la fonction la plus importante est innobase_start_or_create_for_mysql, grâce à laquelle innodb termine la création et l'initialisation, y compris la récupération en cas de crash. Commençons par présenter le rollforward de la base de données.

Base de données de restauration du journal

La base de données de restauration est principalement divisée en deux étapes. La première est l'étape d'analyse du journal. L'étape d'analyse distribue le journal de restauration à la table de hachage en fonction du space_id et du page_no du. page de données pour garantir que les mêmes données sont distribuées dans le même compartiment de hachage et triées en fonction de la taille du LSN, de petite à grande. Une fois l'analyse terminée, la table de hachage entière est parcourue et les journaux de chaque page de données sont appliqués en séquence. Après l'application, l'état de la page de données est au moins restauré à l'état avant le crash. Analysons le code en détail.
Tout d'abord, ouvrez tous les fichiers ibdata (open_or_create_data_files) (il peut y avoir plusieurs ibdata). Chaque fichier ibdata a un flush_lsn dans l'en-tête. Calculez le max_flush_lsn et le min_flush_lsn dans ces fichiers, car ibdata peut également contenir des données. n'est pas complet et doit être restauré. Le suivi (recv_recovery_from_checkpoint_start_func) détermine si l'ibdata doit être restauré en comparant checkpont_lsn et ces deux valeurs.
Ensuite, ouvrez tous les fichiers dans l'espace table système et enregistrez l'espace table (fil_open_log_and_system_tablespace_files) pour éviter des descripteurs de fichiers insuffisants et vider le pool de tampons (buf_pool_invalidate). Ensuite, entrez la fonction la plus essentielle : recv_recovery_from_checkpoint_start_func. Notez que même si la base de données est fermée normalement, elle sera saisie.
Bien que recv_recovery_from_checkpoint_start_func semble verbeux dans le passé, beaucoup de code est écrit pour la fonctionnalité LOG_ARCHIVE, et il n'y a pas beaucoup de code pour une véritable récupération de données après incident.
Tout d'abord, initialisez certaines variables et vérifiez la variable srv_force_recovery Si l'utilisateur décide de sauter la phase de roll forward, la fonction revient directement.
Ensuite, initialisez la structure recv_sys, allouez la taille de hash_table et initialisez la liste de vidage rbtree. recv_sysLa structure est principalement utilisée dans la phase de reprise après incident. hash_table est la table de hachage utilisée pour stocker les journaux de différentes pages de données comme mentionné précédemment. La taille de la table de hachage est initialisée à buffer_size_in_bytes/512. Il s'agit de la longueur maximale de la table de hachage. Si elle dépasse la longueur, elle ne peut pas être enregistrée. Heureusement, il doit être restauré. Le nombre de pages de données ne dépassera pas cette valeur, car le sondage du tampon (pages sales en ligne avant le crash de la base de données) ne peut stocker que des pages de données buffer_size_in_bytes/16 Ko, même si les pages compressées sont prises en compte. ne sont que buffer_size_in_bytes/1KB au maximum. De plus, environ Pour la taille de l'allocation de mémoire de cette table de hachage, veuillez vous référer au bug n° 53122. flush list rbtree est principalement utilisé pour ajouter la liste de pages sales insérée. La liste de flush d'InnoDB doit être triée de petite à grande en fonction de la modification la plus ancienne lsn (oldest_modifcation) de la page de données. Lorsque la base de données fonctionne normalement, vous pouvez utiliser log_sys-. >mutex et log_sys->log_flush_order_mutex garantissent l'ordre. Il n'y a aucune garantie de ce type en cas de récupération après incident. Lors de l'application des données, la table de hachage est parcourue à partir du premier élément. Il n'y a aucune garantie que les pages de données soient triées du plus petit au plus grand. selon la modification la plus ancienne lsn (oldest_modifcation), il est donc nécessaire de parcourir linéairement la flush_list pour trouver la position d'insertion, ce qui est trop inefficace. Par conséquent, un arbre rouge-noir est introduit pour accélérer la recherche de la position d'insertion.
Ensuite, lisez les informations sur le point de contrôle dans l'en-tête de ib_logfile0, comprenant principalement checkpoint_lsn et checkpoint_no. Étant donné que les journaux InnoDB sont utilisés de manière cyclique et qu'il doit y en avoir au moins 2, ib_logfile0 doit exister. Il est sûr d'y stocker les informations de point de contrôle et il n'y a pas lieu de s'inquiéter d'être supprimé. Les informations du point de contrôle seront en fait écrites à deux endroits dans l'en-tête du fichier, et les deux champs de point de contrôle sont écrits tour à tour. Pourquoi devons-nous écrire à deux endroits tour à tour ? Supposons qu'il n'y ait qu'un seul champ de point de contrôle, et que ce champ est mis à jour tout le temps, et que le champ de point de contrôle contient 512 octets (OS_FILE_LOG_BLOCK_SIZE Si juste au moment de l'écriture de ces 512 octets, la base de données raccroche et le serveur raccroche également (). sans tenir compte de l'atomicité du matériel) Fonction d'écriture (les premiers matériels ne disposent pas de cette fonctionnalité), seule la moitié des 512 octets peut être écrite, ce qui rend l'ensemble du domaine de point de contrôle indisponible. De cette façon, la base de données ne pourra pas effectuer de récupération après incident et ne pourra donc pas démarrer. S'il existe deux domaines de point de contrôle, même si l'un est endommagé, vous pouvez toujours utiliser l'autre pour tenter de récupérer. Même si le journal peut avoir été écrasé à ce moment-là, cela augmente au moins la probabilité de réussite de la récupération. Les deux domaines de point de contrôle sont écrits tour à tour, ce qui peut également réduire l'impact des pannes de secteur de disque. Les pages de données précédant checkpoint_lsn ont été placées sur le disque et n'ont pas besoin d'être restaurées. Les pages de données suivantes n'ont peut-être pas encore été placées sur le disque et doivent être restaurées, même si elles y ont été placées. le disque car le redo log est idempotent, appliqué une fois et appliqué deux fois. Tout de même (implémentation sous-jacente : Si le lsn sur la page de données est supérieur ou égal au lsn du redo log actuel, il ne sera pas appliqué, sinon il sera appliqué. checkpoint_no peut être compris comme le nombre de fois que le domaine de point de contrôle est écrit sur le disque. Chaque fois que le disque est vidé, il est incrémenté de 1, et cette valeur modulo 2 peut être utilisée pour implémenter une écriture alternative de. le champ checkpoint_no. Dans une logique normale, la valeur de checkpoint_no est sélectionnée comme information de point de contrôle finale, qui est utilisée comme point de départ pour les analyses de récupération après incident ultérieures.Ensuite, après avoir utilisé les informations du champ du point de contrôle pour initialiser certaines informations dans la structure recv_sys, nous entrons dans la fonction principale d'analyse des journaux recv_group_scan_log_recs Nous analyserons cette fonction plus tard. Sa fonction principale est d'analyser les journaux de rétablissement. ne suffit pas, l'application est appelée directement (recv_apply_hashed_log_recs) log, puis continue l'analyse. S'il y a très peu de journaux à appliquer, analysez simplement le journal de distribution et appliquez le journal dans la fonction recv_recovery_from_checkpoint_finish.
Ensuite, effectuez un point de contrôle basé sur l'état actuel de la page de données vidées, car certains journaux peuvent avoir été appliqués dans recv_group_scan_log_recs. À ce stade, la fonction recv_recovery_from_checkpoint_start_func se termine.
Dans la fonction recv_recovery_from_checkpoint_finish, si le paramètre srv_force_recovery est correct, commencez à appeler la fonction recv_apply_hashed_log_recs pour appliquer le journal, puis attendez que le thread sale se termine (le thread est temporairement démarré lors d'une récupération après crash), et enfin Libérez les ressources associées de recv_sys et la mémoire occupée par hash_table.
À ce stade, la restauration de la base de données est terminée. Ensuite, nous analysons en détail les détails d'implémentation de la fonction d'analyse de journalisation redo et de la fonction d'application de journalisation redo.

Fonction d'analyse de journalisation

Le niveau supérieur de la fonction d'analyse est recv_group_scan_log_recs Cette fonction appelle la fonction sous-jacente (log_group_read_log_seg) et lit par lots en fonction de la taille de RECV_SCAN_SIZE (. 64 Ko). Après la lecture, jugez d'abord si la fin du journal a été lue grâce à la relation entre block_no et lsn et la somme de contrôle du journal (on peut donc voir qu'il n'y a aucune marque dans l'en-tête du journal pour marquer la position effective du journal, et il est complètement jugé selon les deux conditions ci-dessus (il a atteint la fin du journal) et revient s'il lit jusqu'à la fin (comme mentionné précédemment, même si la base de données est fermée normalement, la logique de récupération après incident doit être suivie, donc il est renvoyé ici, car la valeur du point de contrôle de l'arrêt normal doit pointer vers la fin du journal), sinon, supprimez le début et la fin du journal et placez-le dans un recv_sys->buf. Certaines informations de contrôle et valeurs de somme de contrôle. ​​sont stockés dans l'en-tête du journal, qui ne sont utilisés qu'à des fins de vérification et de positionnement, et sont inutiles dans les applications réelles. Avant de le placer dans recv_sys->buf, vous devez vérifier si recv_sys->buf est plein (RECV_PARSING_BUF_SIZE, 2M) S'il est plein, une erreur sera signalée (si le lot d'analyse précédent contient des journaux incomplets). , la fonction d'analyse des journaux ne sera pas distribuée, mais laissera ces journaux incomplets dans recv_sys->buf jusqu'à ce que le journal complet soit analysé). La prochaine étape consiste à analyser le journal de recv_sys->buf (recv_parse_log_recs). Il existe deux types de journaux : single_rec et multi_rec. Le premier signifie qu'une seule opération est effectuée sur une page de données, et le second signifie que plusieurs opérations sont effectuées sur une ou plusieurs pages de données. Le journal comprend également le space_id, le page_no de la page de données correspondante, le type d'opération et le contenu de l'opération (recv_parse_log_rec). Après avoir analysé le journal correspondant, hachez-le selon space_id et page_no (si l'espace table correspondant n'existe pas dans la mémoire, cela signifie que la table a été supprimée), et placez-le dans hash_table (l'emplacement de stockage réel du journal est toujours dans le pool tampon) Voilà, en attente des applications ultérieures. Il y a quelques points à noter ici :

  • S'il s'agit d'un type multi_rec, ce n'est que lorsque la marque MLOG_MULTI_REC_END est rencontrée que le journal sera considéré comme complet et sera distribué à la hash_table. En regardant le code, nous pouvons constater que le journal de type multi_rec est analysé deux fois, une fois pour vérifier l'intégrité (à la recherche de MLOG_MULTI_REC_END), et la deuxième fois pour distribuer le journal. Je pense que c'est un point qui peut être optimisé.

  • Il existe actuellement plus de 50 types d'opérations de journalisation. Le contenu derrière chaque opération est différent, donc la longueur est également différente. La logique actuelle d'analyse des journaux doit analyser tous les journaux. dans l'ordre, puis déterminez la longueur pour localiser la position de départ du journal suivant. Cette méthode est légèrement inefficace. En fait, vous pouvez ajouter un champ à l'en-tête de chaque opération pour stocker la longueur du contenu suivant. De cette façon, vous n'avez pas besoin d'analyser trop de contenu, améliorant ainsi la vitesse d'analyse et améliorant encore le contenu. vitesse de récupération après crash. D'après les résultats, la vitesse peut être doublée (de 38 secondes à 14 secondes, voir le bug n° 82937 pour plus de détails).

  • Si vous constatez qu'il y a encore des journaux après le point de contrôle, cela signifie que la base de données n'a pas été arrêtée correctement auparavant et qu'une récupération après incident doit être effectuée, vous devez donc effectuer quelques opérations supplémentaires ( recv_init_crash_recovery), comme l'impression de nos erreurs courantes dans le journal des erreurs "La base de données ne s'est pas arrêtée normalement !" et "Démarrage de la récupération après incident.", vous devez également vérifier si la page de données est à moitié écrite à partir du tampon d'écriture double. Si une récupération est nécessaire (buf_dblwr_process), vous devez également démarrer un fil de discussion pour vider les pages sales générées par le journal de l'application (car buf_flush_page_cleaner_thread n'a pas été démarré pour le moment). Enfin, tous les espaces table doivent être ouverts. . Notez qu'il s'agit de tous les tableaux. . . Lors du fonctionnement et de la maintenance d'Alibaba Cloud RDS MySQL, nous constatons souvent que la base de données se bloque lors de la phase de récupération après incident, et il y a des mots similaires à "Lecture des informations sur l'espace table à partir des fichiers .ibd..." dans le journal des erreurs, ce qui signifie que la base de données ouvre toutes les tables, puis en regardant le nombre de tables, j'ai découvert qu'il y avait des dizaines, voire des millions de tables. . . La raison pour laquelle la base de données doit ouvrir toutes les tables est que lors de la distribution des journaux, il est nécessaire de déterminer à quel fichier ibd correspond le space_id. Ceci est déterminé en ouvrant toutes les tables et en lisant les informations space_id. Une autre raison est de faciliter la double écriture. tampon pour vérifier les données à moitié écrites. Afin de résoudre le problème d'un trop grand nombre de tables entraînant une récupération trop lente, MySQL 5.7 a été optimisé, WL#7142. L'idée principale est d'écrire un nouveau journal mlog_file_name (incluant le mappage de space_id et du nom de fichier) pour indiquer que les opérations ont été effectuées. sur cette table. Les opérations ultérieures sur cette table n'ont pas besoin d'écrire ce nouveau journal. Lorsqu'une récupération après incident est requise, une analyse supplémentaire est effectuée pour déterminer quelles tables ont été modifiées en collectant mlog_file_name , il n'est donc pas nécessaire d'ouvrir toutes les tables. pour déterminer space_id.

  • La dernière chose à noter est la mémoire. Comme mentionné précédemment, si trop de journaux ont été distribués et occupent trop de mémoire, la fonction d'analyse des journaux appliquera les journaux au moment approprié au lieu d'attendre la fin pour les appliquer tous ensemble. La question est donc de savoir quelle quantité de mémoire utilisée déclenchera l’application de la logique de journalisation. La réponse est : buffer_pool_size_in_bytes - 512 * buffer_pool_instance_num * 16 Ko. Étant donné que buffer_pool_instance_num n'est généralement pas trop grand, cela peut fonctionner. La majeure partie de la mémoire du pool de mémoire tampon est utilisée pour stocker les journaux. Les pages de données restantes sont principalement réservées aux pages de données lues lors de l'application du journal, car actuellement l'application de journalisation est monothread. La lecture d'un journal, l'application de tous les journaux, puis son renvoi sur le disque ne nécessitent pas beaucoup de travail. mémoire.

Fonction d'application de journalisation

La fonction supérieure du journal d'application est recv_apply_hashed_log_recs (le journal d'application peut également être effectué dans la fonction io_helper). traversez hash_table, à partir des lectures de disque, appliquez tour à tour les journaux dans les compartiments de hachage à chaque page de données. Après avoir appliqué tous les journaux, videz toutes les pages buffer_pool si nécessaire. Après tout, l'espace est limité. Les points suivants méritent d'être notés :

  • Les journaux sur la même page de données doivent être appliqués de petit à grand selon lsn, sinon les données seront écrasées. N'appliquez que les journaux de rétablissement dont lsn est supérieur à page_lsn. Seuls ces journaux doivent être refaits et les autres sont ignorés. Après avoir appliqué le journal, ajoutez la page sale à la liste des pages sales étant triée selon la modification la plus ancienne lsn (oldest_modification), une arborescence rouge-noir est introduite ici pour accélérer la recherche de la position d'insertion. La complexité temporelle a augmenté par rapport à avant. La recherche linéaire est réduite au niveau logarithmique.

  • Lorsqu'une certaine page de données est nécessaire, s'il s'avère qu'elle ne se trouve pas dans le pool de tampons, les 32 pages de données entourant cette page de données seront vérifiées pour voir si la récupération est également requis. Si c'est le cas, ils peuvent alors être lus ensemble, ce qui équivaut à effectuer une fusion d'E/S et à réduire les opérations d'E/S (recv_read_in_area). Puisqu'il s'agit d'une lecture asynchrone, le travail final du journal d'application est effectué par le thread io_helper (buf_page_io_complete) De plus, afin d'éviter que trop d'ios ne soient lancés en peu de temps, une logique de contrôle de flux est ajoutée au code. (buf_read_recv_pages). Si une page de données est trouvée en mémoire, le journal d'application recv_recover_page est appelé directement. De cela, nous pouvons voir que le journal d'application InnoDB n'est pas réellement un journal d'application à thread unique. En plus du thread principal pour la récupération après incident, le thread io_helper participera également à la récupération. Le nombre de threads simultanés dépend du nombre de threads de lecture dans io_helper.

Une fois la base de données de rétablissement de restauration exécutée, toutes les pages de données de la base de données sont déjà dans un état cohérent et la base de données d'annulation de restauration peut être exécutée en toute sécurité. Lorsque la base de données tombe en panne, il peut y avoir des transactions non validées ou des transactions validées. À ce stade, vous devez décider si vous souhaitez valider. Elle est principalement divisée en trois étapes : Tout d'abord, analyser le journal d'annulation et rétablir la liste chaînée du journal d'annulation. Ensuite, sur la base de la liste chaînée établie à l'étape précédente, reconstruire la transaction avant le crash, c'est-à-dire restaurer l'état. de la transaction à ce moment-là. Enfin, la restauration ou la validation est effectuée en fonction des différents statuts de la transaction.

annuler la base de données d'annulation du journal

est appelée après recv_recovery_from_checkpoint_start_func et avant recv_recovery_from_checkpoint_finish. Cette fonction effectue les deux premières des trois étapes ci-dessus. trx_sys_init_at_db_startLa première étape est traitée dans la fonction
, qui parcourt tout l'espace du journal d'annulation (jusqu'à TRX_SYS_N_RSEGS (128) segments). Si un segment d'annulation s'avère non vide, il est initialisé (trx_rseg_array_init). ). Pour chaque segment d'annulation, si l'emplacement d'annulation s'avère non vide (jusqu'à TRX_RSEG_N_SLOTS (1024) emplacements), il sera initialisé (trx_rseg_create_instance). Après avoir initialisé l'emplacement d'annulation, placez différents types de journaux d'annulation dans différentes listes chaînées (trx_undo_lists_init). Il existe deux principaux types de journaux d'annulation : TRX_UNDO_INSERT et TRX_UNDO_UPDATE. Le premier est principalement utilisé pour les opérations d’insertion, et le second est utilisé pour les opérations de mise à jour et de suppression. Comme mentionné précédemment, le journal d'annulation a deux fonctions, utilisées lors de l'annulation de transactions et lors de la lecture d'instantanés MVCC. Étant donné que les données d'insertion n'ont pas besoin d'être fournies à d'autres threads, le journal d'annulation de type TRX_UNDO_INSERT peut être supprimé tant que la transaction est validée. TRX_UNDO_UPDATE ne peut pas être supprimé une fois la transaction validée. Il faut s'assurer qu'aucun instantané ne l'utilise avant de pouvoir le nettoyer via le thread de purge en arrière-plan. trx_undo_mem_create_at_db_startLa deuxième étape est effectuée dans la fonction
Puisque dans la première étape, undo_insert_list et undo_update_list ont été établis dans la mémoire (chaque segment d'annulation de la liste chaînée est indépendant), cette étape n'a donc besoin que de parcourir. toutes les listes chaînées et les reconstruire. Le statut de la transaction (trx_lists_init_at_db_start et trx_resurrect_insert). En termes simples, si l'état du journal d'annulation est TRX_UNDO_ACTIVE, l'état de la transaction est TRX_ACTIVE. Si l'état du journal d'annulation est TRX_UNDO_PREPARED, l'état de la transaction est TRX_PREPARED. Le paramétrage de la variable srv_force_recovery doit également être pris en compte ici. Si la valeur de cette variable est différente de 0, toutes les transactions seront annulées (c'est-à-dire que la transaction est définie sur TRX_ACTIVE), même si le statut de la transaction doit être TRX_STATE_PREPARED. Une fois la transaction reconstruite, elle est ajoutée à la liste chaînée trx_sys->trx_list en fonction de l'ID de transaction. Enfin, dans la fonction trx_resurrect_update, elle comptera le nombre de lignes de données qui doivent être annulées pour toutes les transactions qui doivent être annulées (le statut de la transaction est TRX_ACTIVE) et l'affichera dans le journal des erreurs, de la même manière : 5 transaction(s) qui doivent être annulées ou nettoyées. InnoDB : au total 342 232 opérations sur les lignes à annuler. trx_sys_init_at_db_startLa troisième étape est appelée à deux endroits. L’un est à la fin de
et l’autre est en recv_recovery_from_checkpoint_finish. Le premier consiste principalement à annuler le fonctionnement du dictionnaire de données, c'est-à-dire l'opération d'annulation de l'instruction DDL, et le second consiste à annuler l'instruction DML. Le premier doit être terminé avant que la base de données puisse fournir des services, tandis que le second peut être poursuivi une fois que la base de données a fourni des services (c'est-à-dire que la récupération après crash est terminée) (traitée en ouvrant un nouveau thread en arrière-plan recv_recovery_rollback_active). Parce qu'InnoDB estime que le dictionnaire de données est le plus important, il doit être restauré à un état cohérent. Les données de la table utilisateur peuvent être légèrement plus lentes et peuvent être restaurées lentement après avoir fourni des services externes. Par conséquent, nous constatons souvent que la base de données a été démarrée, puis le journal des erreurs imprime toujours les informations sur la transaction d'annulation. La fonction principale de l'annulation de transaction est trx_rollback_or_clean_all_recovered. La logique est très simple. Il vous suffit de parcourir trx_sys->trx_list et d'annuler ou de soumettre en fonction des différents statuts de la transaction (trx_rollback_or_clean_recovered). Ce qu'il convient de noter ici, c'est que si la transaction est dans l'état TRX_STATE_PREPARED, aucun traitement n'est effectué au niveau de la couche InnoDB. La couche serveur doit décider si elle doit annuler la transaction en fonction de la situation du journal binaire. , la transaction sera soumise car le journal binaire a été écrit. Il peut être transféré vers la base de données de secours. Si la base de données principale est restaurée, les données primaires et de secours seront incohérentes. Si le journal binaire n'est pas écrit, la transaction sera soumise. reculé. trx_rollback_resurrected

Analyse des paramètres liés à la récupération après incident

innodb_fast_shutdown : innodb_fast_shutdown = 0. Cela signifie que lorsque MySQL est arrêté, un arrêt lent est effectué, ce qui inclut non seulement le vidage du journal et le vidage des pages de données, mais inclut également le nettoyage des données (purge), la fusion ibuf, le vidage du pool de tampons et les opérations de suppression de table paresseuse (si le table Il y a des opérations inachevées Même si la suppression de la table est exécutée et que le retour réussit, la table peut ne pas être supprimée immédiatement).
innodb_fast_shutdown = 1. Il s'agit de la valeur par défaut, ce qui signifie que lorsque MySQL est arrêté, seuls les journaux et les données seront vidés.
innodb_fast_shutdown = 2. Cela signifie que lorsqu'il est fermé, seuls les journaux sont vidés et rien d'autre n'est fait, comme si MySQL plantait.
Plus la valeur de ce paramètre est grande, plus MySQL s'arrêtera rapidement, mais plus la vitesse de démarrage sera lente, ce qui équivaut à déplacer le travail qui doit être effectué pendant l'arrêt vers la récupération après crash. De plus, si MySQL doit être mis à niveau, il est recommandé d'utiliser la première méthode pour effectuer un arrêt propre.

innodb_force_recovery :
Ce paramètre est principalement utilisé pour contrôler le travail effectué par InnoDB au démarrage. Plus la valeur est grande, moins de travail est effectué et le démarrage est plus facile. , mais les données Le risque d'incohérence est également plus grand. Lorsque MySQL ne peut pas démarrer pour des raisons incontrôlables, vous pouvez définir ce paramètre et l'augmenter progressivement de 1 jusqu'au démarrage de MySQL, puis utiliser SELECT INTO OUTFILE pour exporter les données et faire de votre mieux pour réduire la perte de données.
innodb_force_recovery = 0. Il s'agit du paramètre par défaut. Il fera tout au démarrage, y compris l'application de journalisation, l'annulation de l'annulation du journal, le démarrage du maître d'arrière-plan et des threads de purge, ainsi que la fusion ibuf. Il est détecté que la page de données est endommagée. Si elle se trouve dans l'espace table système, elle plantera. Si elle se trouve dans l'espace table utilisateur, un journal des erreurs sera enregistré.
innodb_force_recovery = 1. S'il est détecté que la page de données est endommagée, il n'y aura ni crash ni erreur (buf_page_io_complete), et l'exactitude de la première page de données de l'espace table ne sera pas vérifiée au démarrage (fil_check_first_page), et le L'espace table sera inaccessible. Continuez à effectuer une récupération après incident (fil_open_single_table_tablespace, fil_load_single_table_tablespace), les opérations ddl ne peuvent pas être effectuées (check_if_supported_inplace_alter) et la base de données est également incapable d'effectuer des opérations d'écriture (row_insert_for_mysql, row_update_for_mysql). , etc.), et toutes les transactions préparées seront également annulées (trx_resurrect_insert, trx_resurrect_update_in_prepared_state). Cette option est encore très couramment utilisée. La page de données peut être endommagée en raison d'un disque défectueux. La définir sur 1 peut garantir que la base de données démarre normalement.
innodb_force_recovery = 2. De plus, les opérations après le paramètre 1 ne s'exécuteront pas, les threads maître et de purge en arrière-plan ne démarreront pas (srv_master_thread, srv_purge_coordinator_thread, etc. Lorsque vous constatez que la base de données ne peut pas démarrer à cause de ces deux threads, vous pouvez). ensemble .
innodb_force_recovery = 3. Sauf que les opérations après le paramètre 2 ne seront pas exécutées, l'annulation de la restauration de la base de données ne sera pas effectuée, mais le segment de restauration sera toujours analysé et la liste chaînée d'annulation sera toujours créée (trx_sys_init_at_db_start). srv_read_only_mode sera activé.
innodb_force_recovery = 4. De plus, les opérations après le réglage 3 ne s'exécuteront pas, l'opération ibuf ne s'exécutera pas (ibuf_merge_or_delete_for_page) et le thread pour les statistiques d'informations sur la table ne s'exécutera pas (car une mauvaise page d'index entraînera le crash de la base de données) (info_low, dict_stats_updateetc.). À partir de cette option, toutes les options suivantes endommageront les données, alors utilisez-les avec prudence.
innodb_force_recovery = 5. De plus, les opérations après le paramètre 4 ne s'exécuteront pas, le segment d'annulation ne sera pas analysé (recv_recovery_rollback_active) et la liste chaînée d'annulation ne sera pas créée. Ceci est principalement utilisé lorsque le journal d'annulation est mal écrit.
innodb_force_recovery = 6. En plus des opérations après le paramètre 5, les opérations de restauration de la base de données ne seront pas effectuées, y compris l'analyse et l'application (recv_recovery_from_checkpoint_start_func).

Résumé

InnoDB a implémenté un mécanisme complet de récupération après incident pour garantir que la base de données peut être restaurée normalement si elle se bloque dans n'importe quel état (y compris l'état de récupération après incident). Ceci est lié au fichier Le). la plus grande différence dans le système. De plus, la récupération après incident utilise des journaux physiques tels que les journaux redo pour appliquer les pages de données, ce qui apporte de nouvelles idées à la réplication MySQL. La base de données de secours peut-elle synchroniser les données de la même manière que l'application des journaux redo ? L'équipe MySQL d'Alibaba Cloud RDS vous apportera des fonctionnalités similaires dans les produits ultérieurs, alors restez à l'écoute.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn