SoFunction
Updated on 2025-03-05

Write a simple distributed system in Go language

distributed

  • Registration Service:RegistryService
  • Log Service:LogService
  • Other services:GradingServiceportal

RegistryService

RegistryServiceServices provided:

  • supply/servicesInterface, used to inform other services when they are started or stopped
    • POST:TellRegistryService, I started a service and calledaddmethod
    • DELETE:TellRegistryService, I stopped a service and calledremovemethod
  • passaddFunctions add services toregistrationsIn the list
    • = append(, reg)
  • passremoveThe function will serve fromregistrationsRemove from the list
    • = append([:i], [i+1:]...)
  • What needs to be noted here is: to ensure thread safety, that is,appendWhen using the lock
()
append(xxx, xxx)
()
  • Service Discovery:

    For exampleGradingServicerelyLogService,SoGradingServiceYou need to knowLogServiceAddress

    At this timeRegistryServiceYou can passregistrationsList to notifyGradingServiceLogServiceAddress

    RegistryServiceIt is throughServiceUpdateURLTo notify,GradingServiceLogServiceAddress

  • Service discovery needs to be carried out in two steps

    ifGradingServiceWhen starting, ifLogServiceIt's already started, thenRegistryServiceYou can notify directlyGradingServiceLogServiceAddress ((reg)method)

    ifGradingServiceWhen starting, ifLogServiceNot started yet, thenRegistryServiceWill not be notifiedGradingServiceLogServiceThe address, waitLogServiceAfter startup,RegistryServiceWill notifyGradingServiceLogServiceAddress (notifymethod)

RegistryServiceOnly need to provideRegisterServiceMethod, other services can obtainRegistryServiceServices provided

  • CallRegisterServiceThe interface provided/services, register the service toRegistryServicemiddle
  • Add a route to the registered service:ServiceUpdateURL
  • Add to registered servicesServeHTTPMethod for processingServiceUpdateURLThe request, this request is in the methodsendRequiredServicesWhen calling, updateprovidersIn-houseservice
  • Provide health checks for each registered service

Finally, provide oneShutdownServiceUsed for like/servicesInterface sendingdeleteRequest, informRegistryService, I stopped a service

LogService

LogServiceServices manage logs, collect, store logs of other services, and provide them./logInterface for other services to send logs toLogService

GradingService and Portal

These two are business services

  • Calling methods when starting the serviceRegistryService, register yourself inRegistryServicemiddle
  • Calling a method when stopping the serviceShutdownService, take yourself fromRegistryServiceRemoved in

api

Used to specify the mode to open the file and return the pointer to the file

func OpenFile(name string, flag int, perm FileMode) (*File, error)

flagparameter:

  • os.O_RDONLY: Open the file with read-only mode
  • os.O_WRONLY: Open the file by writing only mode
  • os.O_RDWR: Read and write mode to open the file
  • os.O_APPEND: Append mode, append data to the end of the file when writing content
  • os.O_CREATE: If the file does not exist, create a new file

permparameter:

- 0: No permission
- 1: Execution permissions
- 2: Write permission
- 3: Write and execute permissions
- 4: Read permission
- 5: Read and execute permissions
- 6: Read and write permissions
- 7: Read, write and execute permissions

  • 0644: means that the owner of the file can read and write files, and the group to which the file belongs and other users can only read files. This is a common setting
  • 0600: means that the owner of the file can read and write the file, but the file belongs to the group and other users cannot access the file. This permission is more secure

The entire file content can be read into memory, and the content of the request body can be read into memory.

ps: Read the entire file content or request body into memory at one time. For very large files or request body, the memory usage is too high.

It blocks the execution of the program until the user enters a line in the terminal and presses Enter. Then it stores the value entered by the user into the passed parameters.

It is mainly used to read and parse simple basic type data

func main(){
  var name string
	var age int
	("Enter your name: ")
	(&name)
	("Enter your age: ")
	(&age)
	("Hello, %s! You are %d years old.\n", name, age)
}

http

  • ListenAndServe: Start the service and listen for the specified address and port, which will block
  • Shutdown: Elegantly shutting down the service, ensuring that the service being processed will not be interrupted
var srv 
go func(){
  ()
}()
go func(){
  ()
}()

ServeHTTP

When a structure is implementedServeHTTPAfter the method, this structure is implementedinterface

ImplementedThe structure of the interface can be used asThe second parameter of the method

Then callThe method can start a service and will be called automaticallyServeHTTPMethod to handle requests

func main() {
	("/ping", &MyHandler{})
	(":8080", nil)
}
type MyHandler struct{}
func (mh MyHandler) ServeHTTP(w , r *) {
	switch  {
	case :
		()
		([]byte("pong"))
	default:
		()
	}
}

Serialize the structure

  • buf := new()Created a newObject, used to store encodedJSONdata
  • enc := (buf)Created a newJSONEncoderencand associate it tobufObject. This means that the codedJSONThe data will be written tobufmiddle
  • err := (r)useJSONEncoderencPut the structurerEncoded asJSONdata and write the result tobufmiddle.EncodeMethod returns a possible errorerr
type Registration struct {
	ServiceName string
	ServiceURL  string
}
r := Registration{
  ServiceName: "LogService",
  ServiceURL:  "http://localhost:3000/services",
}
buf := new()
enc := (buf)
err := (r)
res, err := (ServicesURL, "application/json", buf)

Use http default request

  • It is the default provided in the standard libraryHTTPask. It has pre-configured some default settings, such as timeout time, retry mechanism, etc.
  • Do(req)yesA method of type, used to execute aHTTPRequest and return a response
    • It accepts aObject as a parameter, indicating the request to be sent
req, _ := (, "http://localhost:3000/services", ([]byte("http://localhost:4000/log")))
("Content-Type", "text/plain")
res, err := (req)

log

Used to create a new logger instance to write log messages to the specified output location and optionally add prefix strings

  • Log in the form of a file, usingCreate a newlogInstance, then callMethod to write logs to file

It receivesParameters of type,Returned file pointer type*Implementedinterface, so you can pass file pointers intoIn the method

The code reference is as follows:

import (
	"fmt"
	stlog "log"
	"os"
)
func main() {
	file, err := ("./logs", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		(err)
	}
	defer ()
	log := (file, "[go] -  ", )
	("hello world")
}
  • RewritelogofWriteMethod, can also implement logs to files

RewritingWriteWhen a method, you need to define a type alias and then implement it on the type alias.WriteMethod, then this type alias can be passed inIn the method

The code reference is as follows:

import (
	stlog "log"
	"os"
)
type filelog string
func (fl filelog) Write(data []byte) (int, error) {
	file, err := (string(fl), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		return 0, err
	}
	defer ()
	(data)
	return len(data), nil
}
func main() {
	log := (filelog("./logs"), "[go] -  ", )
	("hello world")
}

The above is the detailed content of writing a simple distributed system in Go language. For more information about the distributed system in Go language, please pay attention to my other related articles!