Home Backend Development Golang How do Kubernetes Operators Handle Concurrency?

How do Kubernetes Operators Handle Concurrency?

Oct 10, 2024 am 06:07 AM

Publié à l'origine sur mon blog

Par défaut, les opérateurs créés à l'aide de Kubebuilder et du contrôleur d'exécution traitent une seule demande de réconciliation à la fois. Il s'agit d'un paramètre judicieux, car il est plus facile pour les développeurs d'opérateurs de raisonner et de déboguer la logique de leurs applications. Cela limite également le débit du contrôleur vers les ressources principales de Kubernetes telles que ectd et le serveur API.

Mais que se passe-t-il si votre file d'attente de travail commence à être sauvegardée et que les délais moyens de rapprochement augmentent en raison de demandes laissées dans la file d'attente, en attente d'être traitées ? Heureusement pour nous, une structure Controller d'exécution de contrôleur inclut un champ MaxConcurrentReconciles (comme je l'ai mentionné précédemment dans mon article Kubebuilder Tips). Cette option vous permet de définir le nombre de boucles de réconciliation simultanées exécutées dans un seul contrôleur. Ainsi, avec une valeur supérieure à 1, vous pouvez réconcilier plusieurs ressources Kubernetes simultanément.

Au début de mon parcours d'opérateur, une question que je me posais était de savoir comment pouvons-nous garantir que la même ressource n'est pas rapprochée en même temps par 2 goroutines ou plus ? Avec MaxConcurrentReconciles défini au-dessus de 1, cela pourrait conduire à toutes sortes de conditions de concurrence et de comportements indésirables, car l'état d'un objet à l'intérieur d'une boucle de réconciliation pourrait changer via un effet secondaire provenant d'une source externe (une boucle de réconciliation s'exécutant dans un thread différent). .

J'y ai réfléchi pendant un moment et j'ai même implémenté une approche basée sur sync.Map qui permettrait à une goroutine d'acquérir un verrou pour une ressource donnée (en fonction de son espace de noms/nom).

Il s'avère que tous ces efforts ont été vains, puisque j'ai récemment appris (dans un canal Slack de K8s) que la file d'attente du contrôleur inclut déjà cette fonctionnalité ! Mais avec une mise en œuvre plus simple.

Voici une brève histoire sur la façon dont la file d'attente de travail d'un contrôleur K8s garantit que les ressources uniques sont réconciliées séquentiellement. Ainsi, même si MaxConcurrentReconciles est défini au-dessus de 1, vous pouvez être sûr qu'une seule fonction de réconciliation agit sur une ressource donnée à la fois.

client-go/util

Controller-runtime utilise la bibliothèque client-go/util/workqueue pour implémenter sa file d'attente de réconciliation sous-jacente. Dans le fichier doc.go du package, un commentaire indique que la file d'attente prend en charge ces propriétés :

  • Équitable : éléments traités dans l'ordre dans lequel ils sont ajoutés.
  • Avare : un seul élément ne sera pas traité plusieurs fois simultanément, et si un élément est ajouté plusieurs fois avant de pouvoir être traité, il ne sera traité qu'une seule fois.
  • Plusieurs consommateurs et producteurs. En particulier, il est permis qu'un élément soit remis en file d'attente pendant son traitement.
  • Notifications d'arrêt.

Attendez une seconde... Ma réponse est ici, dans le deuxième point, la propriété "Stingy" ! Selon ces documents, la file d'attente gérera automatiquement ce problème de concurrence pour moi, sans avoir à écrire une seule ligne de code. Passons en revue la mise en œuvre.

Comment fonctionne la file d'attente ?

La structure workqueue comporte 3 méthodes principales : Add, Get et Done. À l'intérieur d'un contrôleur, un informateur ajouterait des demandes de réconciliation (noms d'espace de noms des ressources k8s génériques) à la file d'attente de travail. Une boucle de réconciliation exécutée dans une goroutine distincte obtiendrait alors la requête suivante de la file d'attente (bloquante si elle est vide). La boucle exécuterait toute la logique personnalisée écrite dans le contrôleur, puis le contrôleur appellerait Done dans la file d'attente, en transmettant la demande de réconciliation comme argument. Cela recommencerait le processus et la boucle de réconciliation appellerait Get pour récupérer l'élément de travail suivant.

Cela est similaire au traitement des messages dans RabbitMQ, où un travailleur retire un élément de la file d'attente, le traite, puis renvoie un « Ack » au courtier de messages indiquant que le traitement est terminé et qu'il est possible de supprimer l'élément en toute sécurité. la file d'attente.

Pourtant, j'ai un opérateur en production qui alimente l'infrastructure de QuestDB Cloud, et je voulais être sûr que la file d'attente de travail fonctionne comme annoncé. J'ai donc écrit un test rapide pour valider son comportement.

Un petit test

Voici un test simple qui valide la propriété "Stingy" :

package main_test

import (
    "testing"

    "github.com/stretchr/testify/assert"

    "k8s.io/client-go/util/workqueue"
)

func TestWorkqueueStingyProperty(t *testing.T) {

    type Request int

    // Create a new workqueue and add a request
    wq := workqueue.New()
    wq.Add(Request(1))
    assert.Equal(t, wq.Len(), 1)

    // Subsequent adds of an identical object
    // should still result in a single queued one
    wq.Add(Request(1))
    wq.Add(Request(1))
    assert.Equal(t, wq.Len(), 1)

    // Getting the object should remove it from the queue
    // At this point, the controller is processing the request
    obj, _ := wq.Get()
    req := obj.(Request)
    assert.Equal(t, wq.Len(), 0)

    // But re-adding an identical request before it is marked as "Done"
    // should be a no-op, since we don't want to process it simultaneously
    // with the first one
    wq.Add(Request(1))
    assert.Equal(t, wq.Len(), 0)

    // Once the original request is marked as Done, the second
    // instance of the object will be now available for processing
    wq.Done(req)
    assert.Equal(t, wq.Len(), 1)

    // And since it is available for processing, it will be
    // returned by a Get call
    wq.Get()
    assert.Equal(t, wq.Len(), 0)
}
Copy after login

Étant donné que la file d'attente utilise un mutex sous le capot, ce comportement est threadsafe. Ainsi, même si j'écrivais plus de tests utilisant plusieurs goroutines lisant et écrivant simultanément à partir de la file d'attente à grande vitesse pour tenter de la rompre, le comportement réel de la file d'attente serait le même que celui de notre test monothread.

Tout n'est pas perdu

How do Kubernetes Operators Handle Concurrency?

There are a lot of little gems like this hiding in the Kubernetes standard libraries, some of which are in not-so-obvious places (like a controller-runtime workqueue found in the go client package). Despite this discovery, and others like it that I've made in the past, I still feel that my previous attempts at solving these issues are not complete time-wasters. They force you to think critically about fundamental problems in distributed systems computing, and help you to understand more of what is going on under the hood. So that by the time I've discovered that "Kubernetes did it", I'm relieved that I can simplify my codebase and perhaps remove some unnecessary unit tests.

The above is the detailed content of How do Kubernetes Operators Handle Concurrency?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What are the vulnerabilities of Debian OpenSSL What are the vulnerabilities of Debian OpenSSL Apr 02, 2025 am 07:30 AM

OpenSSL, as an open source library widely used in secure communications, provides encryption algorithms, keys and certificate management functions. However, there are some known security vulnerabilities in its historical version, some of which are extremely harmful. This article will focus on common vulnerabilities and response measures for OpenSSL in Debian systems. DebianOpenSSL known vulnerabilities: OpenSSL has experienced several serious vulnerabilities, such as: Heart Bleeding Vulnerability (CVE-2014-0160): This vulnerability affects OpenSSL 1.0.1 to 1.0.1f and 1.0.2 to 1.0.2 beta versions. An attacker can use this vulnerability to unauthorized read sensitive information on the server, including encryption keys, etc.

What is the problem with Queue thread in Go's crawler Colly? What is the problem with Queue thread in Go's crawler Colly? Apr 02, 2025 pm 02:09 PM

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

What libraries are used for floating point number operations in Go? What libraries are used for floating point number operations in Go? Apr 02, 2025 pm 02:06 PM

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Apr 02, 2025 am 09:12 AM

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

PostgreSQL monitoring method under Debian PostgreSQL monitoring method under Debian Apr 02, 2025 am 07:27 AM

This article introduces a variety of methods and tools to monitor PostgreSQL databases under the Debian system, helping you to fully grasp database performance monitoring. 1. Use PostgreSQL to build-in monitoring view PostgreSQL itself provides multiple views for monitoring database activities: pg_stat_activity: displays database activities in real time, including connections, queries, transactions and other information. pg_stat_replication: Monitors replication status, especially suitable for stream replication clusters. pg_stat_database: Provides database statistics, such as database size, transaction commit/rollback times and other key indicators. 2. Use log analysis tool pgBadg

In Go, why does printing strings with Println and string() functions have different effects? In Go, why does printing strings with Println and string() functions have different effects? Apr 02, 2025 pm 02:03 PM

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

How to specify the database associated with the model in Beego ORM? How to specify the database associated with the model in Beego ORM? Apr 02, 2025 pm 03:54 PM

Under the BeegoORM framework, how to specify the database associated with the model? Many Beego projects require multiple databases to be operated simultaneously. When using Beego...

How to solve the user_id type conversion problem when using Redis Stream to implement message queues in Go language? How to solve the user_id type conversion problem when using Redis Stream to implement message queues in Go language? Apr 02, 2025 pm 04:54 PM

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...

See all articles