DEV Community

Cover image for Go Microservices: A Beginner's Dive Into Modern Architecture
Allan Githaiga
Allan Githaiga

Posted on

Go Microservices: A Beginner's Dive Into Modern Architecture

Introduction

When I first started my journey as a backend developer, I was overwhelmed by the complexity of designing systems that could handle growth and changing requirements. I still remember the night I stayed up debugging a monolithic application that crashed due to a minor change in one of its components. That experience taught me a valuable lesson about the importance of scalable and modular architecture.

Microservices became the beacon of hope, offering solutions to the limitations of monolithic systems. This article aims to share my journey and knowledge, helping backend developers like you gain a clear vision of how microservices can transform your projects. Together, we’ll explore the basics, understand the architecture, and implement a real-world example in Go.

what is microservice?

What are Microservices?

Microservices is an architectural approach where a single application is divided into small, independent services. Each service focuses on a specific functionality, communicates with others through APIs, and can be developed, deployed, and scaled independently.

How Microservices Work

Microservices operate by splitting an application into distinct services, such as user authentication, payment processing, or order management. These services interact through:

  1. API Communication: Services communicate using REST, gRPC, or message brokers like RabbitMQ or Kafka.

  2. Decentralized Data: Each service often has its database, allowing autonomy and reducing bottlenecks.

Main Components of a Microservices Architecture

Main components of microservices architecture include:

  1. Microservices: Small, loosely coupled services that handle specific business functions, each focusing on a distinct capability.
  2. API Gateway: Acts as a central entry point for external clients also they manage requests, authentication and route the requests to the appropriate microservice.
  3. Service Registry and Discovery: Keeps track of the locations and addresses of all microservices, enabling them to locate and communicate with each other dynamically.
  4. Load Balancer: Distributes incoming traffic across multiple service instances and prevent any of the microservice from being overwhelmed.
  5. Containerization: Docker encapsulate microservices and their dependencies and orchestration tools like Kubernetes manage their deployment and scaling. 6.** Event Bus/Message Broker:** Facilitates communication between microservices, allowing pub/sub asynchronous interaction of events between components/microservices.
  6. Database per Microservice: Each microservice usually has its own database, promoting data autonomy and allowing for independent management and scaling.
  7. Caching: Cache stores frequently accessed data close to the microservice which improved performance by reducing the repetitive queries.
  8. Fault Tolerance and Resilience Components: Components like circuit breakers and retry mechanisms ensure that the system can handle failures gracefully, maintaining overall functionality.

Microservices vs Monolith

diffrence

Benefits of Microservices

1.Scalability: Scale specific components as needed.

2.Flexibility: Use the right technology for each service.

3.Resilience: Failures in one service don’t impact others.

4.Rapid Development: Teams can work independently.

Challenges

1.Complexity: More components to manage.

2.Data Consistency: Requires additional mechanisms.

3.Latency: Inter-service communication can slow performance.

4.Testing: Requires integration testing.

Real-World Example: A Hotel Booking System

We’ll create a basic hotel booking system using Go, showcasing microservice architecture.

Project structure

hotel-booking/
├── main.go
├── services/
│   ├── booking/
│   │   ├── booking.go
│   │   ├── handler.go
│   │   └── routes.go
│   ├── customer/
│   │   ├── customer.go
│   │   ├── handler.go
│   │   └── routes.go
│   └── room/
│       ├── room.go
│       ├── handler.go
│       └── routes.go
├── api-gateway/
│   └── gateway.go
└── go.mod
Enter fullscreen mode Exit fullscreen mode

Main Application

// main.go
package main

import (
    "log"
    "net/http"
    "micro/services/booking"
    "micro/services/customer"
    "micro/services/room"
)

func main() {
    // Initialize routes for each service
    booking.RegisterRoutes()
    customer.RegisterRoutes()  // Ensure this is implemented like booking
    room.RegisterRoutes()      // Ensure this is implemented like booking

    // Add a root handler for the base path
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Welcome to the Hotel Booking API"))
    })

    log.Println("Starting hotel booking microservices...")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatalf("Failed to start server: %v", err)
    }
}

Enter fullscreen mode Exit fullscreen mode

Booking Service

booking.go

// services/booking/booking.go
package booking

type Booking struct {
    ID       string
    CustomerID string
    RoomID    string
    CheckIn  string
    CheckOut string
}
Enter fullscreen mode Exit fullscreen mode

handler.go

// services/booking/handler.go
package booking

import (
    "encoding/json"
    "net/http"
)

func HandleBooking(w http.ResponseWriter, r *http.Request) {
    booking := Booking{}
    if err := json.NewDecoder(r.Body).Decode(&booking); err != nil {
        http.Error(w, "Welcome Allan Robinson \n Book hotel services", http.StatusBadRequest)
        return
    }
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(booking)
}
Enter fullscreen mode Exit fullscreen mode

routes.go

// services/booking/routes.go
package booking

import "net/http"

func RegisterRoutes() {
    http.HandleFunc("/booking", HandleBooking)
}
Enter fullscreen mode Exit fullscreen mode

Customer service

customer.go

// services/customer/customer.go
package customer

type Customer struct {
    ID   string
    Name string
    Email string
}
Enter fullscreen mode Exit fullscreen mode

handler.go

// services/customer/handler.go
package customer

import (
    "encoding/json"
    "net/http"
)

func HandleCustomer(w http.ResponseWriter, r *http.Request) {
    customer := Customer{}
    if err := json.NewDecoder(r.Body).Decode(&customer); err != nil {
        http.Error(w, "Welcome Allan Robinson to our hotel services", http.StatusBadRequest)
        return
    }
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(customer)
}
Enter fullscreen mode Exit fullscreen mode

routes.go

// services/customer/routes.go
package customer

import "net/http"

func RegisterRoutes() {
    http.HandleFunc("/customer", HandleCustomer)
}
Enter fullscreen mode Exit fullscreen mode

Room Service

room.go

// services/room/room.go
package room

type Room struct {
    ID     string
    Type   string
    Status string
}
Enter fullscreen mode Exit fullscreen mode

handler.go

// services/room/handler.go
package room

import (
    "encoding/json"
    "net/http"
)

func HandleRoom(w http.ResponseWriter, r *http.Request) {
    room := Room{}
    if err := json.NewDecoder(r.Body).Decode(&room); err != nil {
        http.Error(w, "Welcome Allan Robinson \n Book a room", http.StatusBadRequest)
        return
    }
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(room)
}
Enter fullscreen mode Exit fullscreen mode

routes.go

// services/room/routes.go
package room

import "net/http"

func RegisterRoutes() {
    http.HandleFunc("/room", HandleRoom)
}
Enter fullscreen mode Exit fullscreen mode

API Gateway

gateway.go

// api-gateway/gateway.go
package main

import (
    "net/http"
)

func main() {
    // Proxy requests to specific services
    http.HandleFunc("/api/booking", func(w http.ResponseWriter, r *http.Request) {
        resp, _ := http.Get("http://localhost:8080/booking")
        w.WriteHeader(resp.StatusCode)
    })

    http.ListenAndServe(":9000", nil)
}
Enter fullscreen mode Exit fullscreen mode

Github repo for this article

Go-Microservices

Top comments (0)