Inhaltsverzeichnis
Szenario für eine einzelne Redis-Instanz
Entsperrungsbeispiel hinzufügen
Zusammenfassung
Wenn die Sperrung erfolgreich ist, erfolgt im nächsten Schritt die Geschäftsabwicklung.
Heim Datenbank Redis So implementieren Sie verteilte Sperren in Go in Kombination mit Redis

So implementieren Sie verteilte Sperren in Go in Kombination mit Redis

May 27, 2023 pm 09:55 PM
redis go

    Szenario für eine einzelne Redis-Instanz

    Wenn Sie mit Redis-Befehlen vertraut sind, denken Sie möglicherweise sofort daran, die Set-If-Not-Existenz-Operation von Redis zu verwenden, um sie zu implementieren. Die aktuelle Standardimplementierungsmethode ist SET resources_name my_random_value NX PX 30000 Befehlsreihen, wobei:

    • Ressourcenname die zu sperrende Ressource bedeutet

    • NX bedeutet, sie festzulegen, wenn sie nicht vorhanden ist

    • PX 30000 bedeutet, dass die Ablaufzeit 30000 Millisekunden beträgt, also 30 Sekunden

    • my_random_value Dieser Wert wird von allen Kunden verwendet. Das Ende muss eindeutig sein und alle Erwerber (Konkurrenten) desselben Schlüssels können nicht denselben Wert haben.

    Der Wert von value muss eine Zufallszahl sein, hauptsächlich um die Sperre sicherer aufzuheben. Verwenden Sie beim Aufheben der Sperre ein Skript, um Redis Folgendes mitzuteilen: Nur wenn der Schlüssel vorhanden ist und der gespeicherte Wert mit dem von mir angegebenen Wert übereinstimmt Kann mir mitgeteilt werden, dass die Löschung erfolgreich war? Dies kann durch das folgende Lua-Skript erreicht werden:

    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end
    Nach dem Login kopieren

    Beispiel: Client A erhält eine Ressourcensperre, wird aber sofort durch einen anderen Vorgang blockiert. Wenn Client A die Sperre nach der Ausführung anderer Vorgänge aufheben möchte, ist die ursprüngliche Sperre bereits festgelegt Und es wurde automatisch von Redis freigegeben, und während dieser Zeit wurde die Ressourcensperre erneut von Client B erworben.

    Lua-Skript wird verwendet, da Beurteilung und Löschung zwei Vorgänge sind. Daher ist es möglich, dass A die Sperre automatisch aufhebt, nachdem sie abgelaufen ist, sobald sie beurteilt hat, und B dann die Sperre erworben hat und A dann Del aufruft. Dadurch wird die Sperre von B aufgehoben.

    Entsperrungsbeispiel hinzufügen

    package main
    
    import (
       "context"
       "errors"
       "fmt"
       "github.com/brianvoe/gofakeit/v6"
       "github.com/go-redis/redis/v8"
       "sync"
       "time"
    )
    
    var client *redis.Client
    
    const unlockScript = `
    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end`
    
    func lottery(ctx context.Context) error {
       // 加锁
       myRandomValue := gofakeit.UUID()
       resourceName := "resource_name"
       ok, err := client.SetNX(ctx, resourceName, myRandomValue, time.Second*30).Result()
       if err != nil {
          return err
       }
       if !ok {
          return errors.New("系统繁忙,请重试")
       }
       // 解锁
       defer func() {
          script := redis.NewScript(unlockScript)
          script.Run(ctx, client, []string{resourceName}, myRandomValue)
       }()
    
       // 业务处理
       time.Sleep(time.Second)
       return nil
    }
    
    func main() {
       client = redis.NewClient(&redis.Options{
          Addr: "127.0.0.1:6379",
       })
       var wg sync.WaitGroup
       wg.Add(2)
       go func() {
          defer wg.Done()
          ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
          err := lottery(ctx)
          if err != nil {
             fmt.Println(err)
          }
       }()
       go func() {
          defer wg.Done()
          ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
          err := lottery(ctx)
          if err != nil {
             fmt.Println(err)
          }
       }()
       wg.Wait()
    }
    Nach dem Login kopieren

    Sehen wir uns zunächst die Funktion lottery() an. Bei der Eingabe der Funktion wird zunächst SET resources_name my_random_value NX PX 30000 zum Sperren verwendet Wenn der Vorgang fehlschlägt, kehren Sie direkt zurück und lassen Sie den Benutzer es erneut versuchen. Wenn die Entsperrlogik erfolgreich ausgeführt wird, besteht die Entsperrlogik darin, das oben erwähnte Lua-Skript auszuführen und dann die Geschäftsverarbeitung durchzuführen.

    Wir haben zwei Goroutinen in der Funktion main() ausgeführt, um gleichzeitig die Funktion lottery() aufzurufen. Eine der Operationen schlägt direkt fehl, da die Sperre nicht erhalten werden kann.

    Zusammenfassung

    • Zufälligen Wert generieren

    • Verwenden Sie SET resources_name my_random_value NX PX 30000 zum Sperren

    • Wenn die Sperre fehlschlägt, kehren Sie direkt zurück

    • Verzögern Sie, um die Entsperrlogik hinzuzufügen um sicherzustellen, dass es entsperrt wird Wenn die Funktion beendet wird, führen Sie die Geschäftslogik aus Redis-Instanzen sind auf verschiedenen Rechnern verteilt und die meisten Knoten können erfolgreich gesperrt werden. Dies ist der RedLock-Algorithmus. Wir müssen Sperren für mehrere Redis-Instanzen gleichzeitig erwerben, aber dies basiert tatsächlich auf einem einzelnen Instanzalgorithmus.

    • Entsperrungsbeispiel hinzugefügt
    • package main
      
      import (
         "context"
         "errors"
         "fmt"
         "github.com/brianvoe/gofakeit/v6"
         "github.com/go-redis/redis/v8"
         "sync"
         "time"
      )
      
      var clients []*redis.Client
      
      const unlockScript = `
      if redis.call("get",KEYS[1]) == ARGV[1] then
          return redis.call("del",KEYS[1])
      else
          return 0
      end`
      
      func lottery(ctx context.Context) error {
         // 加锁
         myRandomValue := gofakeit.UUID()
         resourceName := "resource_name"
         var wg sync.WaitGroup
         wg.Add(len(clients))
         // 这里主要是确保不要加锁太久,这样会导致业务处理的时间变少
         lockCtx, _ := context.WithTimeout(ctx, time.Millisecond*5)
         // 成功获得锁的Redis实例的客户端
         successClients := make(chan *redis.Client, len(clients))
         for _, client := range clients {
            go func(client *redis.Client) {
               defer wg.Done()
               ok, err := client.SetNX(lockCtx, resourceName, myRandomValue, time.Second*30).Result()
               if err != nil {
                  return
               }
               if !ok {
                  return
               }
               successClients <- client
            }(client)
         }
         wg.Wait() // 等待所有获取锁操作完成
         close(successClients)
         // 解锁,不管加锁是否成功,最后都要把已经获得的锁给释放掉
         defer func() {
            script := redis.NewScript(unlockScript)
            for client := range successClients {
               go func(client *redis.Client) {
                  script.Run(ctx, client, []string{resourceName}, myRandomValue)
               }(client)
            }
         }()
         // 如果成功加锁得客户端少于客户端数量的一半+1,表示加锁失败
         if len(successClients) < len(clients)/2+1 {
            return errors.New("系统繁忙,请重试")
         }
      
         // 业务处理
         time.Sleep(time.Second)
         return nil
      }
      
      func main() {
         clients = append(clients, redis.NewClient(&redis.Options{
            Addr: "127.0.0.1:6379",
            DB:   0,
         }), redis.NewClient(&redis.Options{
            Addr: "127.0.0.1:6379",
            DB:   1,
         }), redis.NewClient(&redis.Options{
            Addr: "127.0.0.1:6379",
            DB:   2,
         }), redis.NewClient(&redis.Options{
            Addr: "127.0.0.1:6379",
            DB:   3,
         }), redis.NewClient(&redis.Options{
            Addr: "127.0.0.1:6379",
            DB:   4,
         }))
         var wg sync.WaitGroup
         wg.Add(2)
         go func() {
            defer wg.Done()
            ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
            err := lottery(ctx)
            if err != nil {
               fmt.Println(err)
            }
         }()
         go func() {
            defer wg.Done()
            ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
            err := lottery(ctx)
            if err != nil {
               fmt.Println(err)
            }
         }()
         wg.Wait()
         time.Sleep(time.Second) 
      }
      Nach dem Login kopieren

      Im obigen Code verwenden wir die Multi-Datenbank von Redis, um mehrere Redis-Masterinstanzen zu simulieren. In der realen Umgebung sollten diese Instanzen vermieden werden gleichzeitige Ausfälle.

      In der Sperrlogik führen wir hauptsächlich SET resources_name my_random_value NX PX 30000 auf jeder Redis-Instanz aus, um die Sperre zu erhalten, und stellen dann den Client, der die Sperre erfolgreich erhalten hat, in einen Kanal (die Verwendung von Slice kann hier Probleme mit der Parallelität haben) und verwenden die Synchronisierung .WaitGroup wartet auf das Ende des Sperrenerfassungsvorgangs. Dann fügen Sie „defer“ hinzu, um die Sperrlogik freizugeben. Die Sperrfreigabelogik ist sehr einfach. Geben Sie einfach die erfolgreich erhaltene Sperre frei. Beurteilen Sie abschließend, ob die Anzahl der erfolgreich erworbenen Sperren mehr als die Hälfte beträgt. Wenn mehr als die Hälfte der Sperren nicht erworben wurden, bedeutet dies, dass die Sperrung fehlgeschlagen ist.

      Wenn die Sperrung erfolgreich ist, erfolgt im nächsten Schritt die Geschäftsabwicklung.

      Zusammenfassung

      Generieren Sie einen Zufallswert



      und senden Sie ihn zur Verwendung an jede Redis-Instanz.

      Sperren

      • Warten Sie, bis alle Sperrenerfassungsvorgänge abgeschlossen sind Es wird entsperrt, wenn die Funktion die Ausführung verlässt. Hier wird es zuerst verzögert und dann beurteilt, da es möglich ist, die Sperre eines Teils der Redis-Instanz zu erhalten. Da es jedoch nicht mehr als die Hälfte beträgt, wird es dennoch als Sperrfehler beurteilt

      • Beurteilen Sie, ob die Sperre von mehr als der Hälfte der Redis-Instanz erhalten wurde. Wenn keine Erklärung vorliegt. Wenn die Sperre fehlschlägt, kehren Sie direkt zu
      • SET resource_name my_random_value NX PX 30000

        zurück, um die Geschäftslogik auszuführen

      Das obige ist der detaillierte Inhalt vonSo implementieren Sie verteilte Sperren in Go in Kombination mit Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

    Heiße KI -Werkzeuge

    Undresser.AI Undress

    Undresser.AI Undress

    KI-gestützte App zum Erstellen realistischer Aktfotos

    AI Clothes Remover

    AI Clothes Remover

    Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

    Undress AI Tool

    Undress AI Tool

    Ausziehbilder kostenlos

    Clothoff.io

    Clothoff.io

    KI-Kleiderentferner

    AI Hentai Generator

    AI Hentai Generator

    Erstellen Sie kostenlos Ai Hentai.

    Heißer Artikel

    R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
    2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
    Repo: Wie man Teamkollegen wiederbelebt
    4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
    Hello Kitty Island Abenteuer: Wie man riesige Samen bekommt
    3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

    Heiße Werkzeuge

    Notepad++7.3.1

    Notepad++7.3.1

    Einfach zu bedienender und kostenloser Code-Editor

    SublimeText3 chinesische Version

    SublimeText3 chinesische Version

    Chinesische Version, sehr einfach zu bedienen

    Senden Sie Studio 13.0.1

    Senden Sie Studio 13.0.1

    Leistungsstarke integrierte PHP-Entwicklungsumgebung

    Dreamweaver CS6

    Dreamweaver CS6

    Visuelle Webentwicklungstools

    SublimeText3 Mac-Version

    SublimeText3 Mac-Version

    Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

    Lösung für den Fehler 0x80242008 bei der Installation von Windows 11 10.0.22000.100 Lösung für den Fehler 0x80242008 bei der Installation von Windows 11 10.0.22000.100 May 08, 2024 pm 03:50 PM

    1. Starten Sie das Menü [Start], geben Sie [cmd] ein, klicken Sie mit der rechten Maustaste auf [Eingabeaufforderung] und wählen Sie Als [Administrator] ausführen. 2. Geben Sie nacheinander die folgenden Befehle ein (kopieren und fügen Sie sie sorgfältig ein): SCconfigwuauservstart=auto, drücken Sie die Eingabetaste. SCconfigbitsstart=auto, drücken Sie die Eingabetaste. SCconfigcryptsvcstart=auto, drücken Sie die Eingabetaste. SCconfigtrustedinstallerstart=auto, drücken Sie die Eingabetaste. SCconfigwuauservtype=share, drücken Sie die Eingabetaste. netstopwuauserv, drücken Sie die Eingabetaste für netstopcryptS

    Wie sende ich Go WebSocket-Nachrichten? Wie sende ich Go WebSocket-Nachrichten? Jun 03, 2024 pm 04:53 PM

    In Go können WebSocket-Nachrichten mit dem Paket gorilla/websocket gesendet werden. Konkrete Schritte: Stellen Sie eine WebSocket-Verbindung her. Senden Sie eine Textnachricht: Rufen Sie WriteMessage(websocket.TextMessage,[]byte("message")) auf. Senden Sie eine binäre Nachricht: Rufen Sie WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) auf.

    Wie vermeidet man Speicherlecks bei der technischen Leistungsoptimierung von Golang? Wie vermeidet man Speicherlecks bei der technischen Leistungsoptimierung von Golang? Jun 04, 2024 pm 12:27 PM

    Speicherlecks können dazu führen, dass der Speicher des Go-Programms kontinuierlich zunimmt, indem: Ressourcen geschlossen werden, die nicht mehr verwendet werden, wie z. B. Dateien, Netzwerkverbindungen und Datenbankverbindungen. Verwenden Sie schwache Referenzen, um Speicherlecks zu verhindern, und zielen Sie auf Objekte für die Garbage Collection ab, wenn sie nicht mehr stark referenziert sind. Bei Verwendung von Go-Coroutine wird der Speicher des Coroutine-Stapels beim Beenden automatisch freigegeben, um Speicherverluste zu vermeiden.

    Caching-Mechanismus und Anwendungspraxis in der PHP-Entwicklung Caching-Mechanismus und Anwendungspraxis in der PHP-Entwicklung May 09, 2024 pm 01:30 PM

    In der PHP-Entwicklung verbessert der Caching-Mechanismus die Leistung, indem er häufig aufgerufene Daten vorübergehend im Speicher oder auf der Festplatte speichert und so die Anzahl der Datenbankzugriffe reduziert. Zu den Cache-Typen gehören hauptsächlich Speicher-, Datei- und Datenbank-Cache. In PHP können Sie integrierte Funktionen oder Bibliotheken von Drittanbietern verwenden, um Caching zu implementieren, wie zum Beispiel Cache_get() und Memcache. Zu den gängigen praktischen Anwendungen gehören das Zwischenspeichern von Datenbankabfrageergebnissen zur Optimierung der Abfrageleistung und das Zwischenspeichern von Seitenausgaben zur Beschleunigung des Renderings. Der Caching-Mechanismus verbessert effektiv die Reaktionsgeschwindigkeit der Website, verbessert das Benutzererlebnis und reduziert die Serverlast.

    Wie kann ich Zeitstempel mithilfe regulärer Ausdrücke in Go abgleichen? Wie kann ich Zeitstempel mithilfe regulärer Ausdrücke in Go abgleichen? Jun 02, 2024 am 09:00 AM

    In Go können Sie reguläre Ausdrücke verwenden, um Zeitstempel abzugleichen: Kompilieren Sie eine Zeichenfolge mit regulären Ausdrücken, z. B. die, die zum Abgleich von ISO8601-Zeitstempeln verwendet wird: ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ . Verwenden Sie die Funktion regexp.MatchString, um zu überprüfen, ob eine Zeichenfolge mit einem regulären Ausdruck übereinstimmt.

    So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000_So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000 So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000_So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000 May 08, 2024 pm 05:10 PM

    Zuerst müssen Sie die Systemsprache auf die Anzeige in vereinfachtem Chinesisch einstellen und neu starten. Wenn Sie die Anzeigesprache zuvor auf vereinfachtes Chinesisch geändert haben, können Sie diesen Schritt natürlich einfach überspringen. Beginnen Sie als Nächstes mit dem Betrieb der Registrierung regedit.exe, navigieren Sie direkt zu HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNlsLanguage in der linken Navigationsleiste oder der oberen Adressleiste und ändern Sie dann den InstallLanguage-Schlüsselwert und den Standardschlüsselwert auf 0804 (wenn Sie ihn in Englisch ändern möchten). us, Sie müssen zunächst die Anzeigesprache des Systems auf en-us einstellen, das System neu starten und dann alles auf 0409 ändern) Sie müssen das System an dieser Stelle neu starten.

    Der Unterschied zwischen Golang und Go-Sprache Der Unterschied zwischen Golang und Go-Sprache May 31, 2024 pm 08:10 PM

    Go und die Go-Sprache sind unterschiedliche Einheiten mit unterschiedlichen Eigenschaften. Go (auch bekannt als Golang) ist bekannt für seine Parallelität, schnelle Kompilierungsgeschwindigkeit, Speicherverwaltung und plattformübergreifende Vorteile. Zu den Nachteilen der Go-Sprache gehören ein weniger umfangreiches Ökosystem als andere Sprachen, eine strengere Syntax und das Fehlen dynamischer Typisierung.

    Best Practices für die Dokumentation des Golang-Frameworks Best Practices für die Dokumentation des Golang-Frameworks Jun 04, 2024 pm 05:00 PM

    Das Verfassen einer klaren und umfassenden Dokumentation ist für das Golang-Framework von entscheidender Bedeutung. Zu den Best Practices gehört die Befolgung eines etablierten Dokumentationsstils, beispielsweise des Go Coding Style Guide von Google. Verwenden Sie eine klare Organisationsstruktur, einschließlich Überschriften, Unterüberschriften und Listen, und sorgen Sie für eine Navigation. Bietet umfassende und genaue Informationen, einschließlich Leitfäden für den Einstieg, API-Referenzen und Konzepte. Verwenden Sie Codebeispiele, um Konzepte und Verwendung zu veranschaulichen. Halten Sie die Dokumentation auf dem neuesten Stand, verfolgen Sie Änderungen und dokumentieren Sie neue Funktionen. Stellen Sie Support und Community-Ressourcen wie GitHub-Probleme und Foren bereit. Erstellen Sie praktische Beispiele, beispielsweise eine API-Dokumentation.

    See all articles