meow: Migration auf Redis
Das Monitoring-System meow
erlaubt
es, eigens konfigurierte Endpunkte mit einer Liveness Probe zu monitoren.
Grundsätzlich ist meow
als verteiltes System konzipiert, verfügt über eine
HTTP-Schnittstelle und liesse sich so nicht nur auf einer virtuellen Maschine
(IaaS) sondern auch als Cloud Function (PaaS) ausführen.
Einige Aspekte von meow
stehen dem aber im Wege: So wird die Konfiguration
über das Dateisystem in einer CSV-Datei verwaltet. Eine elegantere Lösung wäre
es beispielsweise, die Konfiguration in Redis zu verwalten.
Die Voraussetzung für den folgenden Arbeitsauftrag ist, dass Sie mit Redis arbeiten können sowie meow in Betrieb genommen und konfiguriert haben. Hierzu gibt es folgende Hilfestellungen:
- Die Übungen zu HTTP und
curl
:meow
-Konfiguration, die Sie hoffentlich gelöst haben. - Die YouTube-Playlist zu
meow
, welche die Inbetriebnahme, Konfiguration und Erweiterung des Monitoring-Systems demonstriert.
Arbeiten Sie auf Ihrem persönlichen Fork vom
meow
-Repository. Sichern Sie Ihren
Code regelmässig in Ihrem persönlichen Repository. Für eine Rückmeldung zu Ihrem
Code können Sie einen Pull Request einreichen.
Endpunkt-Konfiguration mit Redis
Als Repetition können Sie noch einmal die Redis-Playlist betrachten, insbesondere das Video zu den Endpunkten als Hashes.
Client-Library installieren
Wenn Sie die Endpunkte in Redis konfiguriert haben, soll als nächstes der
Zugriff auf die Redis-Datenbank vom Go-Code aus bewerkstelligt werden. Redis
bietet verschiedene Client-Libraries für
Go. Der populärste ist Go
Redis. Diese kann im
meow
-Arbeitsverzeichnis in einem Terminal folgendermassen installiert werden:
go get github.com/redis/go-redis/v9
Die Version v9
passt zur lokal vorinstallierten Redis-Version 7. (Für
Redis-Version 6 müssten Sie v8
statt v9
verwenden.)
Redis-URL konfigurierbar machen
Damit eine Verbindung zu Redis aufgenommen werden kann, muss zuerst eine URL
definiert werden. Lokal lautet diese jeweils localhost:6379
. In einer
produktiven Umgebung soll die URL jedoch konfigurierbar sein, etwa über eine
Umgebungsvariable. (So ähnlich funktioniert das bereits mit der
Umgebungsvariable CONFIG_URL
in der probe
-Komponente; siehe
probeCmd/probe.go
ganz oben in der main
-Funktion.)
Implementieren Sie den Zugriff auf die Umgebungsvariable REDIS_URL
entsprechend in configCmd/config.go
.
Verbindung zu Redis aufnehmen
Eine Verbindung zu Redis kann folgendermassen erstellt werden:
rdb := redis.NewClient(&redis.Options{
Addr: [Redis URL from environment variable],
Password: "", // no password set
DB: 0, // use default DB
})
Sie können den Code direkt in der main
-Funktion von configCmd/config.go
einfügen. Die Variable rdb
vom Typ *redis.Client
bietet Ihnen nun die
bekannten Redis-Befehle als Methoden an,
beispielsweise:
rdb.Set("key", "value", 0) // 0 as expiration value (never expires)
value := rdb.Get("key")
fmt.Println(value) // prints "value"
Funktionssignaturen anpassen
Die Funktionen getEndpoint
, postEndpoint
und getEndpoints
‒ sowie
deleteEndpoint
, sofern Sie die Zusatzaufgabe gemacht haben ‒ benötigen die
Redis-Verbindung als zusätzlichen Parameter. Ergänzen Sie die Parameterlisten
entsprechend (Parametername: beispielsweise rdb
, Datentyp: *redis.Client
).
Vorher (Beispiel):
func getEndpoints(w http.ResponseWriter, r *http.Request)
Nachher (Beispiel):
func getEndpoints(w http.ResponseWriter, r *http.Request, rdb *redis.Client)
Sie können nun innerhalb dieser Funktionen auf die Redis-Datenbank zugreifen.
Führen Sie im Terminal noch den Befehl go mod tidy
aus, damit alle
Abhängigkeiten korrekt aufgelöst werden.
Datenzugriffe implementieren
Mithilfe des KEYS
-Befehls erhalten Sie eine Liste aller Schlüssel anhand eines
gegebenen Musters. In der
Musterlösung
habe ich das Präfix endpoint:
verwendet; Sie können sich somit alle Endpunkte
mit dem Redis-Befehl KEYS endpoint:*
auflisten lassen.
Funktion getEndpoints
anpassen
Im Go-Code können Sie hierzu die Methode rdb.Keys
verwenden
(getEndpoints
-Funktion):
keys, err := rdb.Keys("endpoint:*").Result()
if err != nil {
log.Printf("fetch keys by pattern endpoint:*: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
for _, key := range keys {
fmt.Println(key) // TODO: replace with calls to rdb.HGet
}
In der unteren Schleife können Sie nun mittels rdb.HGet
auf die einzelnen
Felder zugreifen, beispielsweise:
identifier, err := rdb.HGet(key, "identifier").Result()
Wobei identifier
der gesuchte Wert und err
ein möglicherweise auftretender
Fehler ist.
Alternativ können Sie sich mittels rdb.HGetAll
eine Map zurückgeben lassen.
(H
steht bekanntlich als Präfix für “Hash”, was nichts anderes als eine Map
ist.):
fields, err := rdb.HGetAll(key).Result()
In beiden Fällen müssen Sie den Fehler err
angemessen behandeln. Den payload
erstellen Sie anschliessend anhand der Informationen aus Redis, wobei Sie den
bestehenden Code anpassen müssen.
Weitere Funktionen
Für die weiteren Funktionen getEndpoint
(Singular) und postEndpoint
(schreibender Zugriff) benötigen Sie neben den bereits bekannten
Redis-Funktionen noch HSET
, um einen Hash zu erstellen (rdb.HSet
). Als Key
können Sie das Präfix endpoint:
mit dem Identifier kombinieren.
Änderungen testen
Testen Sie Ihre Anpassungen, indem Sie die config
-Komponente folgendermassen
starten:
REDIS_URL=localhost:6379 go run configCmd/config.go
Falls Sie die kostenlose Redis-Instanz aus der Cloud verwenden, müssen Sie die URL entsprechend anpassen.
Zum Testen können Sie die curl
-Befehle verwenden, die Sie im entsprechenden
Aufgabenblock umgesetzt haben
bzw. dem entsprechenden
Video entnehmen können.
Code bereinigen
Wenn alles funktioniert, können Sie den bestehenden Code bereinigen, indem Sie
Dateizugriffe, das Flag -file
usw. entfernen. Testen Sie das Programm nach den
Änderungen, damit Sie nicht versehentlich zu viel Code entfernen.