DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Database Zone»Lecture du code source de l’opérateur TiDB (partie 4) : mise en œuvre d’une boucle de contrôle de composant
    Database Zone

    Lecture du code source de l’opérateur TiDB (partie 4) : mise en œuvre d’une boucle de contrôle de composant

    novembre 21, 2021
    Lecture du code source de l'opérateur TiDB (partie 4) : mise en œuvre d'une boucle de contrôle de composant
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Dans notre dernier article, nous avons présenté comment TiDB Operator orchestre les événements de boucle de contrôle pour gérer les cycles de vie des composants TiDB. Les TidbCluster Le contrôleur gère les cycles de vie des composants TiDB, et le gestionnaire membre de chaque composant TiDB encapsule la logique de gestion spécifique de ce composant.

    Dans cet article, je vais vous expliquer en détail comment nous implémentons une boucle de contrôle de composant en prenant PD comme exemple. Vous découvrirez le gestionnaire de membres PD et ses opérations de gestion du cycle de vie. Je comparerai également d’autres composants avec PD et montrerai leurs différences.

    La boucle de contrôle PD

    Le pilote de placement (PD) gère un cluster TiDB et planifie les régions dans le cluster. Le gestionnaire de membres PD maintient la logique de gestion du cycle de vie PD. La plupart de son code réside dans pkg/manager/member/pd_member_manager.go, et d’autres codes liés à la mise à l’échelle, à la mise à niveau et au basculement se trouvent dans pd_scaler.go, pd_upgrader.go, et pd_failover.go respectivement.

    Comme illustré dans la partie III, la gestion du cycle de vie d’un composant nécessite les tâches suivantes :

    • Service de synchronisation
    • Démarrer la synchronisation StatefulSet
    • État de la synchronisation
    • Synchroniser ConfigMap
    • Mise à jour continue
    • Mise à l’échelle et mise à l’échelle
    • Basculement
    • Terminer la synchronisation StatefulSet

    La synchronisation StatefulSet est la logique principale. D’autres tâches, telles que la synchronisation de l’état et la synchronisation de ConfigMap, sont définies comme des sous-fonctions et appelées par le gestionnaire de membres PD lorsqu’il synchronise StatefulSet.

    Sync StatefulSet

    Pour synchroniser StatefulSet, le gestionnaire de membres PD :

    1. Obtient le PD actuel StatefulSet en utilisant StatefulSetLister.

      oldPDSetTmp, err := m.deps.StatefulSetLister.StatefulSets(ns).Get(controller.PDMemberName(tcName))
      if err != nil && !errors.IsNotFound(err) {
          return fmt.Errorf("syncPDStatefulSetForTidbCluster: fail to get sts %s for cluster %s/%s, error: %s", controller.PDMemberName(tcName), ns, tcName, err)
      }
      setNotExist := errors.IsNotFound(err)
      
      oldPDSet := oldPDSetTmp.DeepCopy()

    2. Obtient le dernier statut en utilisant m.syncTidbClusterStatus(tc, oldPDSet).

      if err := m.syncTidbClusterStatus(tc, oldPDSet); err != nil {
          klog.Errorf("failed to sync TidbCluster: [%s/%s]'s status, error: %v", ns, tcName, err)
      }

    3. Vérifie si le cluster TiDB suspend la synchronisation. Si c’est le cas, terminez le rapprochement suivant.

      if tc.Spec.Paused {
          klog.V(4).Infof("tidb cluster %s/%s is paused, skip syncing for pd statefulset", tc.GetNamespace(), tc.GetName())
          return nil
      }

    4. Synchronise ConfigMap selon la dernière tc.Spec.

      cm, err := m.syncPDConfigMap(tc, oldPDSet)

    5. Génère le dernier modèle StatefulSet en fonction de la dernière tc.Spec, tc.Status, et ConfigMap obtenu à la dernière étape.

      newPDSet, err := getNewPDSetForTidbCluster(tc, cm)

    6. Si le nouveau StatefulSet PD n’a pas encore été créé, créez d’abord le StatefulSet.

      if setNotExist {
          if err := SetStatefulSetLastAppliedConfigAnnotation(newPDSet); err != nil {
              return err
          }
          if err := m.deps.StatefulSetControl.CreateStatefulSet(tc, newPDSet); err != nil {
              return err
          }
          tc.Status.PD.StatefulSet = &apps.StatefulSetStatus{}
          return controller.RequeueErrorf("TidbCluster: [%s/%s], waiting for PD cluster running", ns, tcName)
      }

    7. Si un utilisateur configure une mise à niveau forcée à l’aide d’annotations, cette étape configure le StatefulSet pour effectuer directement une mise à niveau propagée. Ceci afin d’éviter un échec de mise à niveau si la boucle de réconciliation est bloquée.

      if !tc.Status.PD.Synced && NeedForceUpgrade(tc.Annotations) {
          tc.Status.PD.Phase = v1alpha1.UpgradePhase
          setUpgradePartition(newPDSet, 0)
          errSTS := UpdateStatefulSet(m.deps.StatefulSetControl, tc, newPDSet, oldPDSet)
          return controller.RequeueErrorf("tidbcluster: [%s/%s]'s pd needs force upgrade, %v", ns, tcName, errSTS)
      }

    8. Appelle la logique de mise à l’échelle implémentée dans pd_scaler.go.

      if err := m.scaler.Scale(tc, oldPDSet, newPDSet); err != nil {
          return err
      }

    9. Appelle la logique de basculement implémentée dans pd_failover.go. La fonction vérifie d’abord si le cluster doit être restauré, puis vérifie si tous les pods sont démarrés et si tous les membres sont sains, et détermine enfin s’il doit commencer le basculement.

      if m.deps.CLIConfig.AutoFailover {
          if m.shouldRecover(tc) {
              m.failover.Recover(tc)
          } else if tc.PDAllPodsStarted() && !tc.PDAllMembersReady() || tc.PDAutoFailovering() {
              if err := m.failover.Failover(tc); err != nil {
                  return err
              }
          }
      }

    10. Appelle la logique de mise à niveau implémentée dans pd_upgrader.go. Lorsque le StatefulSet PD nouvellement généré est incohérent avec celui existant ou lorsque les deux StatefulSets sont cohérents mais tc.Status.PD.Phase est upgrade, le gestionnaire des membres PD saisit upgrader pour traiter la logique de mise à niveau progressive.

      if !templateEqual(newPDSet, oldPDSet) || tc.Status.PD.Phase == v1alpha1.UpgradePhase {
          if err := m.upgrader.Upgrade(tc, oldPDSet, newPDSet); err != nil {
              return err
          }
      }

    11. Le StatefulSet PD est synchronisé et le nouveau StatefulSet est mis à jour vers le cluster Kubernetes.

    Service de synchronisation

    PD utilise à la fois des Services et des Services headless, gérés par syncPDServiceForTidbCluster et syncPDHeadlessServiceForTidbCluster.

    L’adresse de service est utilisée dans TiDB, TiKV et TiFlash pour configurer le point de terminaison PD. Par exemple, TiDB utilise --path=${CLUSTER_NAME}-pd:2379 comme son adresse de service PD dans le paramètre de démarrage :

    ARGS="--store=tikv 
    --advertise-address=${POD_NAME}.${HEADLESS_SERVICE_NAME}.${NAMESPACE}.svc 
    --path=${CLUSTER_NAME}-pd:2379 

    Le service sans tête fournit un identifiant unique pour chaque pod. Lorsque PD démarre, le PD Pod enregistre son point de terminaison dans les membres PD comme "${POD_NAME}.${PEER_SERVICE_NAME}.${NAMESPACE}.svc":

    domain="${POD_NAME}.${PEER_SERVICE_NAME}.${NAMESPACE}.svc"
    ARGS="--data-dir=/var/lib/pd 
    --name=${POD_NAME} 
    --peer-urls=http://0.0.0.0:2380 
    --advertise-peer-urls=http://${domain}:2380 
    --client-urls=http://0.0.0.0:2379 
    --advertise-client-urls=http://${domain}:2379 
    --config=/etc/pd/pd.toml 
    "

    Synchroniser ConfigMap

    PD utilise ConfigMap pour gérer les configurations et le script de démarrage. Les syncPDConfigMap appels de fonction getPDConfigMap pour obtenir la dernière ConfigMap et l’appliquer au cluster Kubernetes. ConfigMap gère les tâches suivantes :

    1. Avoir PD.Config pour la synchronisation de suivi. Pour rester compatible avec les versions antérieures qui utilisent Helm, lorsque l’objet de configuration est vide, ConfigMap n’est pas synchronisé.

      config := tc.Spec.PD.Config
      if config == nil {
          return nil, nil
      }

    2. Modifier la configuration liée à TLS. Étant donné que TiDB 4.0 et les versions antérieures ne prennent pas en charge le tableau de bord TiDB, le gestionnaire de membres PD ignore la configuration des certificats de tableau de bord pour PD dans les versions antérieures.

      // override CA if tls enabled
      if tc.IsTLSClusterEnabled() {
          config.Set("security.cacert-path", path.Join(pdClusterCertPath, tlsSecretRootCAKey))
          config.Set("security.cert-path", path.Join(pdClusterCertPath, corev1.TLSCertKey))
          config.Set("security.key-path", path.Join(pdClusterCertPath, corev1.TLSPrivateKeyKey))
      }
      // Versions below v4.0 do not support Dashboard
      if tc.Spec.TiDB != nil && tc.Spec.TiDB.IsTLSClientEnabled() && !tc.SkipTLSWhenConnectTiDB() && clusterVersionGE4 {
          config.Set("dashboard.tidb-cacert-path", path.Join(tidbClientCertPath, tlsSecretRootCAKey))
          config.Set("dashboard.tidb-cert-path", path.Join(tidbClientCertPath, corev1.TLSCertKey))
          config.Set("dashboard.tidb-key-path", path.Join(tidbClientCertPath, corev1.TLSPrivateKeyKey))
      }

    3. Transformez la configuration au format TOML afin que PD puisse la lire.

      confText, err := config.MarshalTOML()

    4. Générez le script de démarrage PD en utilisant RenderPDStartScript. Le modèle de script est stocké dans le pdStartScriptTpl variable dans pkg/manager/member/template.go. Le script de démarrage PD est un script Bash. RenderPDStartScript insère des variables et des annotations configurées par le TidbCluster objet dans le script de démarrage. Ces variables et annotations sont utilisées pour le démarrage et le débogage de PD.

    5. Assemblez les configurations PD et le script de démarrage en tant qu’objet Kubernetes ConfigMap, et renvoyez le ConfigMap au syncPDConfigMap fonction.

      cm := &corev1.ConfigMap{
          ObjectMeta: metav1.ObjectMeta{
              Name:            controller.PDMemberName(tc.Name),
              Namespace:       tc.Namespace,
              Labels:          pdLabel,
              OwnerReferences: []metav1.OwnerReference{controller.GetOwnerRef(tc)},
          },
          Data: map[string]string{
              "config-file":    string(confText),
              "startup-script": startScript,
          },
      }

    Mise à l’échelle

    La logique de mise à l’échelle est implémentée in pkg/manager/member/pd_scaler.go. Le StatefulSet appelle le Scale fonction de mise à l’échelle ou de mise à l’échelle dans le cluster PD.

    Avant la mise à l’échelle, l’opérateur TiDB doit effectuer certaines opérations préliminaires. Par exemple, pour évoluer dans le cluster PD, l’opérateur TiDB doit transférer les leaders, mettre les membres hors ligne et ajouter des annotations à PersistentVolumeClaims (PVC) pour une suppression différée. Pour faire évoluer le cluster, l’opérateur TiDB doit supprimer les PVC précédemment conservés.

    Une fois les opérations préliminaires terminées, l’opérateur TiDB ajuste le nombre de répliques StatefulSet et commence le processus de mise à l’échelle. Les opérations préliminaires minimisent l’impact de l’opération de mise à l’échelle.

    Les Scale fonction agit comme un routeur. En fonction de la direction, du pas et de la longueur de mise à l’échelle, il détermine le plan de mise à l’échelle à utiliser. Si la scaling variable est un nombre positif, PD est mis à l’échelle ; sinon, PD est mis à l’échelle. Dans chaque opération de mise à l’échelle, PD n’est mis à l’échelle que d’une étape. Le plan spécifique est mis en œuvre par le ScaleIn et ScaleOut les fonctions.

    func (s *pdScaler) Scale(meta metav1.Object, oldSet *apps.StatefulSet, newSet *apps.StatefulSet) error {
        scaling, _, _, _ := scaleOne(oldSet, newSet)
        if scaling > 0 {
            return s.ScaleOut(meta, oldSet, newSet)
        } else if scaling < 0 {
            return s.ScaleIn(meta, oldSet, newSet)
        }
        return s.SyncAutoScalerAnn(meta, oldSet)
    }

    Mise à l’échelle

    Avant que TiDB Operator mette un membre PD hors ligne, il doit transférer le chef. Sinon, lorsque le membre Leader est mis hors ligne, les autres membres PD sont contraints à une élection de Leader, ce qui affecte les performances du cluster. Par conséquent, l’opérateur TiDB doit transférer le leader au membre PD avec le plus petit ID. Cela garantit que le PD Leader n’est transféré qu’une seule fois.

    Pour transférer le PD Leader, obtenez d’abord le PD Client et le PD Leader :

    pdClient := controller.GetPDClient(s.deps.PDControl, tc)
    leader, err := pdClient.GetPDLeader()

    Lorsque le nom du leader est égal au nom du membre, l’opérateur TiDB transfère le leader. S’il ne reste qu’un membre, aucun autre membre n’est disponible pour le transfert, donc l’opérateur TiDB ignore le transfert du leader.

    Après le transfert du chef, le ScaleIn la fonction appelle les PD DeleteMember API et supprime le membre des membres PD. Le membre PD est alors mis hors ligne. Enfin, la fonction appelle setReplicasAndDeleteSlots pour ajuster le nombre de réplicas StatefulSet, et le processus de mise à l’échelle est terminé.

    Mise à l’échelle

    Avant que l’opérateur TiDB ne fasse évoluer le cluster PD, il doit supprimer les PVC différés en appelant deleteDeferDeletingPVC. Lorsque l’opérateur TiDB a précédemment mis à l’échelle en PD, ces PVC ont été conservés pour une suppression différée afin d’assurer la fiabilité des données ; maintenant, l’opérateur TiDB doit les supprimer pour éviter que le cluster n’utilise d’anciennes données. Une fois ces PVC supprimés, l’opérateur TiDB n’a qu’à ajuster le nombre de répliques StatefulSet et à faire évoluer le cluster PD.

    Que vous augmentiez ou augmentiez le cluster PD, l’opération est effectuée en configurant le nombre de réplicas StatefulSet….

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.