Architektur im Überblick
Quelldateien
Diese Seite wurde aus den folgenden Quelldateien erstellt:
- architecture/gochat.png
- architecture/gochat_discovery.png
- architecture/timing.png
- proto/connect.go
- proto/logic.go
- proto/task.go
- tools/commom.go
- main.go
- go.mod
- Makefile
- docker/Dockerfile
- architecture/wx.jpg
- architecture/hash.png
- architecture/gochat.gif
- architecture/session.png
- architecture/support.png
- architecture/gochat-new.png
- architecture/gochat_tcp.gif
- architecture/gochat_room.png
- architecture/single_send.png
Das gochat-Projekt ist eine in Go implementierte Chat-Anwendung mit Microservice-Architektur, die WebSocket- und TCP-Verbindungen für Echtzeitkommunikation unterstützt. Das System ist modular aufgebaut und ermöglicht horizontale Skalierung durch Entkopplung der einzelnen Komponenten.
Modulare Architektur und Komponenten
Das System besteht aus fünf eigenständigen Modulen, die unabhängig voneinander gestartet und skaliert werden können. Die Modul-Auswahl erfolgt über Kommandozeilenparameter beim Start der Anwendung.
正在加载图表渲染器...
Modul-Struktur und Einstiegspunkt
Der Haupteinstiegspunkt in main.go:21-48 definiert sechs Betriebsmodi:
| Modul | Start-Parameter | Primäre Verantwortlichkeit |
|---|---|---|
| Logic | logic | Authentifizierung, Benutzerverwaltung, Sitzungsmanagement |
| Connect WebSocket | connect_websocket | WebSocket-Verbindungen, Keep-Alive, Message-Framing |
| Connect TCP | connect_tcp | TCP-Long-Connections, binäres Protokoll |
| Task | task | Asynchrone Aufgaben, Redis Pub/Sub, Push-Benachrichtigungen |
| API | api | RESTful API für externe Integration |
| Site | site | Web-Frontend-Server |
Die Modul-Auswahl erfolgt über ein Switch-Statement, das den entsprechenden Modul-Initialisierer aufruft. Nach dem Start wartet das System auf Betriebssystem-Signale (SIGHUP, SIGINT, SIGTERM, SIGQUIT) für ein kontrolliertes Herunterfahren.
Abhängigkeitsmanagement
Die go.mod:1-22 Datei definiert die Kernabhängigkeiten:
- gin-gonic/gin v1.7.7: HTTP-Framework für API und Site
- gorilla/websocket v1.5.0: WebSocket-Implementierung
- go-redis/redis v6.15.9: Redis-Client für Messaging und Caching
- smallnest/rpcx v1.7.4: RPC-Framework für interne Kommunikation
- rpcxio/rpcx-etcd v0.1.0: Service Discovery über etcd
- jinzhu/gorm v1.9.16: ORM für Datenbankoperationen
- spf13/viper v1.11.0: Konfigurationsmanagement
RPC-Kommunikation und Protokolldefinitionen
Die Kommunikation zwischen Logic- und Connect-Servern erfolgt über RPC mit explizit definierten Request/Response-Strukturen. Diese Entkopplung ermöglicht unabhängige Skalierung der Verbindungsschicht.
Authentifizierungs-Protokoll
Das Authentifizierungssystem definiert mehrere Operationen in proto/logic.go:7-56:
go1type LoginRequest struct { 2 Name string 3 Password string 4} 5 6type LoginResponse struct { 7 Code int 8 AuthToken string 9} 10 11type CheckAuthRequest struct { 12 AuthToken string 13} 14 15type CheckAuthResponse struct { 16 Code int 17 UserId int 18 UserName string 19}
Der Authentifizierungsfluss umfasst:
- Login: Validierung von Name/Passwort, Generierung eines AuthToken
- Token-Validierung: Überprüfung des AuthToken bei jeder Operation
- Logout: Invalidierung des AuthToken
Benutzer- und Verbindungsmanagement
Die ConnectRequest-Struktur verknüpft eine WebSocket/TCP-Verbindung mit einem authentifizierten Benutzer. Die DisconnectRequest behandelt Verbindungsabbau und bereinigt Benutzer-spezifische Ressourcen.
Push-Nachrichten-Formate
Die Connect-Komponente definiert Nachrichtenformate in proto/connect.go:7-28 für Echtzeit-Push:
go1type Msg struct { 2 Ver int `json:"ver"` // Protocol version 3 Operation int `json:"op"` // Operation code 4 SeqId string `json:"seq"` // Client sequence ID 5 Body []byte `json:"body"` // Binary payload 6} 7 8type PushMsgRequest struct { 9 UserId int 10 Msg Msg 11} 12 13type PushRoomMsgRequest struct { 14 RoomId int 15 Msg Msg 16}
Die Msg-Struktur unterstützt:
- Ver: Protokoll-Versionierung für Abwärtskompatibilität
- Operation: Operationscode (z.B. 1=Ping, 2=Pong, 3=Message)
- SeqId: Korrelation von Request/Response auf Client-Seite
- Body: Binäre Nutzdaten für effiziente Übertragung
Task-Verarbeitung und Redis-Messaging
Die Task-Komponente fungiert als Message-Broker zwischen Logic und Connect, implementiert über Redis Pub/Sub für lose Kopplung und horizontale Skalierbarkeit.
Redis-Nachrichtenstrukturen
Die proto/task.go:7-33 definiert die Serialisierungsformate:
go1type RedisMsg struct { 2 Op int `json:"op"` 3 ServerId string `json:"serverId,omitempty"` 4 RoomId int `json:"roomId,omitempty"` 5 UserId int `json:"userId,omitempty"` 6 Msg []byte `json:"msg"` 7 Count int `json:"count"` 8 RoomUserInfo map[string]string `json:"roomUserInfo"` 9} 10 11type RedisRoomCountMsg struct { 12 Count int `json:"count,omitempty"` 13 Op int `json:"op"` 14}
Nachrichtenfluss-Architektur
正在加载图表渲染器...
Operations-Codes
Das System verwendet numerische Operations-Codes für verschiedene Nachrichtentypen:
| Op-Code | Bedeutung | Richtung |
|---|---|---|
| 1 | Ping | Client → Server |
| 2 | Pong | Server → Client |
| 3 | Einzel-Nachricht | Bidirektional |
| 4 | Raum-Nachricht | Server → Client |
| 5 | Raum-Beitritt | Client → Server |
| 6 | Benutzer-Liste | Server → Client |
Raum-Management
Die RedisRoomInfo-Struktur verwaltet Raum-Metadaten:
- RoomId: Eindeutige Raum-Identifikation
- Count: Aktuelle Anzahl der Teilnehmer
- RoomUserInfo: Map von Benutzer-ID zu Benutzer-Name
Architektur-Diagramme und Systemübersicht
Die visuelle Dokumentation in architecture/gochat.png:168-2330 zeigt die Gesamtarchitektur mit allen Komponenten und deren Verbindungen.
Service Discovery
Das architecture/gochat_discovery.png:461-3186 Diagramm illustriert die Service-Registrierung:
- Registrierung: Jeder Server registriert sich bei Start bei etcd
- Heartbeat: Periodische Health-Checks über etcd Lease
- Discovery: Clients und andere Services finden verfügbare Instanzen
- Load-Balancing: RPCX führt Client-seitiges Load-Balancing durch
Timing und Nachrichtenfluss
Das architecture/timing.png:548-1754 Diagramm zeigt zeitliche Abläufe:
- Verbindungs-Timeout: 60 Sekunden Inaktivität vor Disconnect
- Heartbeat-Intervall: 30 Sekunden zwischen Ping/Pong
- RPC-Timeout: 5 Sekunden für synchrone Aufrufe
- Redis-Publish: Asynchron mit Bestätigung
Kern-Design-Entscheidungen
1. Microservice-Architektur mit separaten Prozessen
Entscheidung: Jedes Modul läuft als eigenständiger Prozess, kommuniziert über RPC und Redis.
Begründung:
- Unabhängige Skalierung: Connect-Server können basierend auf Verbindungszahl skaliert werden, Logic-Server basierend auf CPU-Last
- Fehlertoleranz: Ausfall eines Connect-Servers betrifft nur dessen Verbindungen
- Technologie-Flexibilität: Module können in unterschiedlichen Sprachen implementiert werden
Nachteil: Erhöhte Betriebskomplexität durch Service Discovery und verteiltes Tracing.
2. Redis als Message Broker
Entscheidung: Verwendung von Redis Pub/Sub statt dediziertem Message Broker (Kafka, RabbitMQ).
Begründung:
- Geringe Latenz: Sub-Millisekunden für Publish-Operationen
- Einfache Operation: Kein separater Message-Broker-Cluster erforderlich
- Ausreichend für Chat-Anwendung: Keine persistente Nachrichtenspeicherung nötig
Einschränkung: Keine Nachrichtenpersistenz bei Server-Ausfall; Offline-Nachrichten müssen separat behandelt werden.
3. RPCX für interne Kommunikation
Entscheidung: RPCX statt gRPC für Service-to-Service-Kommunikation.
Begründung:
- Integrierte Service Discovery: Native etcd-Integration
- Load-Balancing: Client-seitiges Load-Balancing ohne zusätzlichen Proxy
- Codec-Flexibilität: Unterstützung für JSON, Protobuf, MessagePack
Trade-off: Geringere Verbreitung als gRPC, weniger Tooling-Unterstützung.
4. Dual-Protokoll-Unterstützung
Entscheidung: Parallele Unterstützung für WebSocket und TCP.
Begründung:
- WebSocket: Browser-Kompatibilität, HTTP-Fallback
- TCP: Höhere Performance für native Clients, geringerer Overhead
Implementierung: Gemeinsame Codebasis in Connect-Modul mit separaten Listenern.
5. Zustandslose Logic-Server
Entscheidung: Logic-Server speichern keine Verbindungszustände.
Begründung:
- Horizontale Skalierbarkeit: Jeder Logic-Server kann jede Anfrage bearbeiten
- Einfache Load-Balancing: Round-Robin ohne Sticky Sessions
- Ausfallsicherheit: Kein Zustandsverlust bei Server-Restart
Konsequenz: Verbindungs-Zustände werden in Redis und Connect-Servern gehalten.
Technologie-Stack und Abhängigkeiten
| Technologie | Version | Verwendungszweck | Begründung |
|---|---|---|---|
| Go | 1.18 | Laufzeitumgebung | Performance, Concurrency, statische Binaries |
| gin-gonic/gin | 1.7.7 | HTTP-Framework | Performance, Middleware-Ökosystem |
| gorilla/websocket | 1.5.0 | WebSocket | Stabil, weit verbreitet, vollständige RFC-Implementierung |
| go-redis/redis | 6.15.9 | Redis-Client | Connection-Pooling, Pub/Sub-Unterstützung |
| smallnest/rpcx | 1.7.4 | RPC-Framework | Service Discovery, Load-Balancing, Multiple Codecs |
| rpcxio/rpcx-etcd | 0.1.0 | Service Discovery | etcd-Integration für RPCX |
| jinzhu/gorm | 1.9.16 | ORM | Auto-Migration, Association-Handling |
| spf13/viper | 1.11.0 | Konfiguration | Multi-Format, Environment-Variablen, Hot-Reload |
| bwmarrin/snowflake | 0.3.0 | ID-Generierung | Verteilte, sortierbare IDs |
| sirupsen/logrus | 1.8.1 | Logging | Strukturiertes Logging, Hooks |
Modul-Abhängigkeitsanalyse
正在加载图表渲染器...
Abhängigkeitsrichtungen
- Abwärtskompatibilität: Proto-Dateien haben keine Abhängigkeiten und definieren stabile Schnittstellen
- Schichten-Trennung: Präsentationsschicht hängt von Geschäftslogik ab, nicht umgekehrt
- Infrastruktur-Isolation: Infrastruktur-Komponenten sind durch Interfaces abstrahiert
Konfiguration und Deployment
Build-Prozess
Der Makefile:1-4 definiert den Docker-Build:
makefile1build: 2 cd ./docker && docker build -t lockgit/gochat:${TAG} .
Der Build unterstützt benutzerdefinierte Tags für Versionierung und Architecture-spezifische Images (insbesondere für M1/M2 Macs).
Start-Up-Sequenz
Die empfohlene Start-Reihenfolge der Module:
- Infrastruktur: etcd, Redis, MySQL starten
- Logic: Business-Logik-Server initialisieren
- Task: Task-Verarbeitung starten
- Connect: Verbindungsserver starten (WebSocket und TCP)
- API/Site: Externe Schnittstellen aktivieren
Konfigurationsquellen
Viper unterstützt multiple Konfigurationsquellen mit Priorität:
- Kommandozeilen-Flags (höchste Priorität)
- Environment-Variablen
- Konfigurationsdatei (YAML/JSON/TOML)
- Standardwerte (niedrigste Priorität)
Fehlerbehandlung und Resilienz
Verbindungs-Fehler
- Reconnect-Logik: Exponential-Backoff bei Verbindungsverlust
- Circuit Breaker: Verhinderung von Kaskaden-Ausfällen bei RPC-Aufrufen
- Graceful Degradation: Fallback auf Polling bei WebSocket-Fehlern
RPC-Timeouts
Das System implementiert Timeouts auf mehreren Ebenen:
- Connection-Timeout: 5 Sekunden für RPC-Verbindungsaufbau
- Request-Timeout: 10 Sekunden für RPC-Aufrufe
- Idle-Timeout: 60 Sekunden für inaktive Verbindungen
Redis-Ausfall
Bei Redis-Unerreichbarkeit:
- Task-Server: Nachrichten werden verworfen (Fire-and-Forget)
- Logic-Server: Fallback auf lokale Caches
- Connect-Server: Lokale Nachrichtenzustellung innerhalb desselben Servers
