Distributed Applications with GO: Difference between revisions
Line 40: | Line 40: | ||
===Cmd=== | ===Cmd=== | ||
===Client=== | ===Client=== | ||
package log | |||
import ( | |||
"app/registry" | |||
"bytes" | |||
"fmt" | |||
stlog "log" | |||
"net/http" | |||
) | |||
func SetClientLogger(serviceURL string, clientService registry.ServiceName) { | |||
stlog.SetPrefix(fmt.Sprintf("[%v] - ", clientService)) | |||
stlog.SetFlags(0) | |||
stlog.SetOutput(&clientLogger{url: serviceURL}) | |||
} | |||
type clientLogger struct { | |||
url string | |||
} | |||
func (cl clientLogger) Write(data []byte) (int, error) { | |||
b := bytes.NewBuffer([]byte(data)) | |||
res, err := http.Post(cl.url+"/log", "text/plain", b) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if res.StatusCode != http.StatusOK { | |||
return 0, fmt.Errorf("Failed to send log message. Service responded with %v - %v", res.StatusCode, res.Status) | |||
} | |||
return len(data), nil | |||
} | |||
===Server=== | ===Server=== | ||
====Comments for the code==== | ====Comments for the code==== |
Revision as of 11:30, 24 August 2021
Elements of a Distributed System
Characteristic
Four aspects might be
- Service Discovery
- Load Balancing
- Distributed tracing and logging
- Service Monitoring
Type of Distributed System
- Hub and Spoke (Satélite approach)
- Advantages Good for load balancing and logging
- Disadvantages Bad to single point of failure. Hub is complex due to responsibilities
- Peer to Peer where each communicate directly
- Advantages No Single point of failure. Highly decoupled
- Disadvantages Service discovery and Load Balancing hard
- Message Queue System where services get work from the queue
- Advantages Easy to scale, Persistence for disaster
- Disadvantages Single Point of failure (message queue), hard to configure
- Hybrid system (none of the above)
- This might will have advantages and disadvantage of both
Architectural Element
These are the aspect you may want to consider
- Languages
- Frameworks (Recommended Go-Kit and Go-Micro)
- Transports
- Protocol
Sample App
The sample app is a hybrid app using GO
This is the components to build
Introduction
I do not usually go through large portions of code but I thought it might be useful to look at the sample code and comment on the topic and the relationship with GO as a language.
Project Structure
The project structure was basically a root folder with a cmd directory holding the main.go code for each binary. From there there is one folder for each component.
Log
Cmd
Client
package log
import ( "app/registry" "bytes" "fmt" stlog "log" "net/http" )
func SetClientLogger(serviceURL string, clientService registry.ServiceName) { stlog.SetPrefix(fmt.Sprintf("[%v] - ", clientService)) stlog.SetFlags(0) stlog.SetOutput(&clientLogger{url: serviceURL}) }
type clientLogger struct { url string }
func (cl clientLogger) Write(data []byte) (int, error) { b := bytes.NewBuffer([]byte(data)) res, err := http.Post(cl.url+"/log", "text/plain", b) if err != nil { return 0, err } if res.StatusCode != http.StatusOK { return 0, fmt.Errorf("Failed to send log message. Service responded with %v - %v", res.StatusCode, res.Status) } return len(data), nil }
Server
Comments for the code
This creates an instance of a custom log type, a handler and a function to write to the file.
- Run
Creates a custom log file using the standard log package
- Write
Writes data to the stream
- RegisterHandlers
Registers the "/log", reads the data and writes the message
The Code
package log
import (
"io/ioutil"
stlog "log"
"net/http"
"os"
)
var log *stlog.Logger
type fileLog string
func (fl fileLog) Write(data []byte) (int, error) {
f, err := os.OpenFile(string(fl), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return 0, err
}
defer f.Close()
return f.Write(data)
}
func Run(destination string) {
log = stlog.New(fileLog(destination), "", stlog.LstdFlags)
}
func RegisterHandlers() {
http.HandleFunc("/log", func(w http.ResponseWriter, r *http.Request) {
msg, err := ioutil.ReadAll(r.Body)
if err != nil || len(msg) == 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
write(string(msg))
})
}
func write(message string) {
log.Printf("%v\n", message)
}
Cmd
Service Registry
Service Registration
- Create Web Service
- Create Register Service
- Register Web Service
- Deregister Web Service
Service Discovery
- Create Grading Service
- Request Required Service On Startup
- Notify when Service Starts
- Notify when Service Shutdown