Maison  >  Article  >  développement back-end  >  Écrire un système de messagerie efficace en utilisant le langage Go

Écrire un système de messagerie efficace en utilisant le langage Go

PHPz
PHPzoriginal
2023-06-15 12:36:121410parcourir

Avec le développement d'Internet, les systèmes de messagerie sont de plus en plus utilisés dans divers domaines. Le système de messagerie peut mettre en œuvre une communication asynchrone pour améliorer les performances et la fiabilité du système, et peut également réaliser un découplage pour faciliter l'expansion et la maintenance du système. Le langage Go possède les caractéristiques des coroutines et des canaux, ce qui le rend très efficace et flexible dans la mise en œuvre de systèmes de messagerie. Cet article explique comment utiliser le langage Go pour écrire un système de messagerie efficace.

1. Comprendre l'architecture de base du système de messagerie

L'architecture de base du système de messagerie se compose de trois parties : l'éditeur de messages, le consommateur de messages et la file d'attente de messages. L'éditeur du message envoie le message à la file d'attente des messages pour le stockage, et le consommateur du message obtient le message de la file d'attente des messages pour le consommer. La file d'attente de messages joue le rôle de mise en mémoire tampon et de découplage, ce qui peut rendre incohérentes les capacités de traitement des éditeurs de messages et des consommateurs de messages, mettre en cache les messages pendant les périodes de pointe et garantir la fiabilité et la séquence des messages.

2. Utilisez le langage Go pour créer un système de messagerie

  1. Installez la file d'attente de messages RabbitMQ

Étant donné que RabbitMQ est un courtier de messages open source, fiable, efficace et évolutif, nous choisissons d'utiliser cette file d'attente de messages pour implémenter notre système de messagerie. . Vous pouvez télécharger RabbitMQ depuis le site officiel https://www.rabbitmq.com/.

  1. Créer des producteurs de messages et des consommateurs de messages

Il est très simple d'écrire des producteurs de messages et des consommateurs de messages en langage Go. Voici un exemple de code pour un simple producteur de message :

package main

import (
    "log"
    "github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
    }
}

func main() {
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    q, err := ch.QueueDeclare(
        "hello", // queue name
        false,   // durable
        false,   // delete when unused
        false,   // exclusive
        false,   // no-wait
        nil,     // arguments
    )
    failOnError(err, "Failed to declare a queue")

    body := "Hello World!"
    err = ch.Publish(
        "",     // exchange
        q.Name, // routing key
        false,  // mandatory
        false,  // immediate
        amqp.Publishing {
            ContentType: "text/plain",
            Body:        []byte(body),
        })
    failOnError(err, "Failed to publish a message")
}

Le code ci-dessus se connecte au serveur RabbitMQ, crée une file d'attente nommée "hello" et envoie un message "Hello World!"

Ce qui suit est un exemple de code pour un simple consommateur de messages :

package main

import (
    "log"
    "github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
    }
}

func main() {
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    q, err := ch.QueueDeclare(
        "hello", // queue name
        false,   // durable
        false,   // delete when unused
        false,   // exclusive
        false,   // no-wait
        nil,     // arguments
    )
    failOnError(err, "Failed to declare a queue")

    msgs, err := ch.Consume(
        q.Name, // queue
        "",     // consumer
        true,   // auto-ack
        false,  // exclusive
        false,  // no-local
        false,  // no-wait
        nil,    // arguments
    )
    failOnError(err, "Failed to register a consumer")

    forever := make(chan bool)

    go func() {
        for d := range msgs {
            log.Printf("Received a message: %s", d.Body)
        }
    }()

    log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
    <-forever
}

Le code ci-dessus se connecte au serveur RabbitMQ, crée une file d'attente nommée "hello" et obtient les messages de la file d'attente pour consommation. Tant qu'il y a un message dans la file d'attente, le consommateur du message peut le consommer immédiatement.

  1. Utilisez des coroutines et des canaux pour implémenter un traitement simultané

Les fonctionnalités des coroutines et des canaux dans le langage Go peuvent nous aider à implémenter un traitement simultané dans le système de messagerie. Une coroutine est comme un thread léger qui peut réaliser un traitement simultané élevé. Les canaux peuvent servir de ponts de communication entre les coroutines pour réaliser une transmission simultanée de données.

Ce qui suit est un exemple de code pour utiliser des coroutines et des canaux pour implémenter un traitement simultané :

package main

import (
    "log"
    "math/rand"
    "time"
    "github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
    }
}

func publish(i int) {
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    q, err := ch.QueueDeclare(
        "hello", // queue name
        false,   // durable
        false,   // delete when unused
        false,   // exclusive
        false,   // no-wait
        nil,     // arguments
    )
    failOnError(err, "Failed to declare a queue")

    body := "Hello World " + strconv.Itoa(i) + "!"
    err = ch.Publish(
        "",     // exchange
        q.Name, // routing key
        false,  // mandatory
        false,  // immediate
        amqp.Publishing {
            ContentType: "text/plain",
            Body:        []byte(body),
        })
    failOnError(err, "Failed to publish a message")
}

func consume() {
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    q, err := ch.QueueDeclare(
        "hello", // queue name
        false,   // durable
        false,   // delete when unused
        false,   // exclusive
        false,   // no-wait
        nil,     // arguments
    )
    failOnError(err, "Failed to declare a queue")

    msgs, err := ch.Consume(
        q.Name, // queue
        "",     // consumer
        true,   // auto-ack
        false,  // exclusive
        false,  // no-local
        false,  // no-wait
        nil,    // arguments
    )
    failOnError(err, "Failed to register a consumer")

    forever := make(chan bool)

    go func() {
        for d := range msgs {
            log.Printf("Received a message: %s", d.Body)
        }
    }()

    log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
    <-forever
}

func main() {
    rand.Seed(time.Now().UnixNano())
    
    for i := 0; i < 10; i++ {
        go publish(i)
    }

    go consume()

    forever := make(chan bool)
    <-forever
}

Dans le code ci-dessus, nous avons créé 10 coroutines pour envoyer des messages à la file d'attente des messages en même temps, et créé une autre coroutine pour obtenir des messages pour consommation. Cela améliore considérablement la capacité de traitement simultané du système de messagerie.

3. Résumé

Dans cet article, nous avons présenté comment utiliser le langage Go pour écrire un système de messagerie efficace. En utilisant les fonctionnalités des courtiers de messages, des coroutines et des canaux RabbitMQ, nous pouvons facilement implémenter un système de messagerie à haute concurrence et haute fiabilité. Si vous devez implémenter une communication de messages asynchrone dans votre projet actuel, le langage Go est un bon choix.

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