🏝️

GoでWebSocketを使用した通知システムを作成する:[Redis連携]

2025/03/10に公開

はじめに

前回の記事では、GoでWebSocketを使った基本的なリアルタイム通信を実装しました。
今回は、さらに応用的なWebSocketの活用方法として、通知システムの作成およびRedisを使ったスケーラブルなWebSocketサーバーの構築を解説します。

対象読者

  • WebSocketを活用して通知システムを実装したい方
  • Redisを使ってWebSocketサーバーをスケールアウトしたい方
  • 複数のWebSocketクライアントを効率的に管理したい方

目次

  1. WebSocketを活用した通知システムの作り方
    • 通知システムの仕組み
    • WebSocketサーバーの実装
    • クライアント側の実装(JavaScript)
  2. Redisを使ったWebSocketサーバーの構築方法
    • Redis Pub/Subの仕組み
    • GoでのRedis連携(go-redis
    • マルチインスタンス対応のWebSocketサーバー

1. WebSocketを活用した通知システムの作り方

1.1 通知システムの仕組み

WebSocketを活用すると、サーバーからリアルタイムでクライアントに通知を送信できます。

例:通知システムの流れ

  1. クライアントがWebSocketに接続する
  2. サーバーが特定のイベント(新しい投稿、メッセージなど)を検知
  3. サーバーが該当ユーザーにリアルタイム通知を送信

1.2 WebSocketサーバーの実装

まず、GoでWebSocketの通知サーバーを実装します。

server.go

package main

import (
    "fmt"
    "net/http"
    "sync"
    "github.com/gorilla/websocket"
)

type Client struct {
    conn *websocket.Conn
}

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true },
}
var clients = make(map[*Client]bool)
var mu sync.Mutex

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("WebSocket connection failed:", err)
        return
    }
    client := &Client{conn: conn}
    mu.Lock()
    clients[client] = true
    mu.Unlock()

    defer func() {
        mu.Lock()
        delete(clients, client)
        mu.Unlock()
        conn.Close()
    }()

    for {
        _, _, err := conn.ReadMessage()
        if err != nil {
            break
        }
    }
}

func sendNotification(message string) {
    mu.Lock()
    defer mu.Unlock()
    for client := range clients {
        client.conn.WriteMessage(websocket.TextMessage, []byte(message))
    }
}

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    fmt.Println("WebSocket server running on ws://localhost:8080/ws")
    http.ListenAndServe(":8080", nil)
}
  • clientsマップでWebSocketに接続しているクライアントを管理
  • sendNotification()で接続中のすべてのクライアントにメッセージを送信

1.3 クライアント側の実装(JavaScript)

index.html

<script>
    const ws = new WebSocket("ws://localhost:8080/ws");

    ws.onmessage = function(event) {
        alert("通知: " + event.data);
    };
</script>
  • WebSocketからのメッセージを受け取るとポップアップ通知を表示

2. Redisを使ったWebSocketサーバーの構築方法

2.1 Redis Pub/Subの仕組み

Redis Pub/Sub(パブリッシュ・サブスクライブ)を使うと、異なるWebSocketサーバー間で通知を共有できます。

2.2 GoでのRedis連携(go-redis

Redisをインストール

docker run --name redis -d -p 6379:6379 redis

Goライブラリをインストール

go get github.com/go-redis/redis/v8

server_redis.go

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
    "net/http"
    "github.com/gorilla/websocket"
)

var ctx = context.Background()
var rdb = redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
})

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, _ := upgrader.Upgrade(w, r, nil)
    defer conn.Close()
    sub := rdb.Subscribe(ctx, "notifications")
    defer sub.Close()
    
    ch := sub.Channel()
    for msg := range ch {
        conn.WriteMessage(websocket.TextMessage, []byte(msg.Payload))
    }
}

func sendNotification(message string) {
    rdb.Publish(ctx, "notifications", message)
}

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    fmt.Println("WebSocket server with Redis running on ws://localhost:8080/ws")
    http.ListenAndServe(":8080", nil)
}
  • rdb.Publish()を使って通知をRedisに送信
  • rdb.Subscribe() でRedisから通知を受信し、WebSocketでクライアントに配信

まとめ

項目 説明
WebSocket 通知システム Goでリアルタイム通知を実装する方法
Redis Pub/Sub 異なるWebSocketサーバー間で通知を共有する方法
Redis によるスケールアウト 複数サーバーでも統一的に通知を送信

本記事では、WebSocketを活用した通知システムと、Redisを用いたWebSocketサーバーの構築方法を解説しました。
次も発展系を勉強していこうと思います!

Discussion