← Home

Notes on how production grade cloud architectures look

Queues, Kubernetes, Grafana, CI/CD, and Kafka in a Wise-scale system.

Learning how a production grade Wise application cloud architecture looks like.

We have a queue like structure creating events for consumers, a cluster holding groups of pods serving different purposes, Grafana that monitors all these pods and CI/CD pipelines that handle deployments to these pods after testing and reviewing logs.

Microservices

A pod is the smallest subset of an app that can be deployed. Pods are deployed via kubernetes and are iterations of the same app — however they're never the entire app but versions of microservices. For instance, the most common microservice distribution for a enterprise grade fintech app looks like this:

MicroserviceWhat it doesExample pods
API Gateway / IngressEntry point, routing requests to microservices2–3 pods for load balancing
User ServiceHandles customer accounts, KYC, authentication2–5 pods
Ledger ServiceCore ledger, balances, debits/credits3–10 pods (depends on transaction load)
Transaction ServiceHandles sending/receiving money, reconciliations3–5 pods
Payment Gateway ServiceIntegrates with banks, card networks2–3 pods
Notification ServiceEmail/SMS/push notifications1–3 pods
Analytics / Reporting ServiceTracks activity, metrics, reporting2 pods
Database PodsPostgres, Redis, or other storesUsually stateful sets, 1–3 replicas depending on HA
Cache PodsRedis or Memcached for fast lookups2–3 pods
Monitoring / LoggingPrometheus, Grafana, Loki, ELK stack1–2 pods each

Containers and pods

Kubernetes pods run containers, so everything Helm or YAML deploys is ultimately a container. Each microservice is packaged as a Docker image.

A pod is typically one container. Think of those terms as interchangeable although they might have differences. Containers are easy, deployed through docker, like one virtual machine that is isolated from your computer and holds all the info that's needed.

Each pod holds a container and kubernetes allows you to create multiple pods and can also increase and decrease their numbers as need arises. This is useful because we don't want to run a huge app that's always running because requests might decrease or increase. So we want to be able to adjust as the need arises to save costs.

Multiple replicas of the same app

Even within a single microservice, companies run multiple pods (replicas):

Service and Ingress

Water tower analogy: A water pump is necessary to pump water to a society. The average water requirement for a town might be 400 gallons. But we can't design a water pump based on average needs, rather we need to account for the ceiling, the highest water requirement. Say it's morning and everyone needs water right now and water needs hit 600 gallons. So the total water need is 600 gallons.

Creating a water tower allows you to draw from a set resource instead of having to create one big pump. That's equivalent to a kubernetes cluster. The cluster reduces the number of pods and increases them to serve the upper limit of needs as the need arises.

Service

Ingress

Helm Charts

Helm is a package manager for Kubernetes. Helm is useful in simplifying complex deployments into reusable "charts," enabling versioning, rollbacks, and consistent management across environments.

charts/
├── ledger/
│   ├── templates/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── configmap.yaml
│   └── values.yaml

You write YAML templates describing:

You can deploy all services at once (helm install ledger ./charts/ledger).

CI/CD pipeline for a service like Wise

[Code push]
    ↓
[CI Stage] → Build → Lint → Unit Tests → Integration Tests
    ↓
[Docker Stage] → Build Docker images → Push to registry
    ↓
[CD Stage] → Deploy to cluster via Helm → Run smoke tests / integration tests
    ↓
[Monitoring Stage] → Alert if deployment fails, metrics report

Kafka Queues

Kafka is a distributed event streaming platform:

How Kafka works

  1. Producer publishes an event to a topic

    Producer → Topic: transactions Event: {id: 123, from: A, to: B, amount: 100}

  2. Kafka stores the event in partitions of the topic

    • Partitions are ordered logs (append-only)
    • Each partition is replicated for durability
  3. Consumers subscribe to the topic

    • Each consumer tracks its offset: "I have read up to event #45 in partition 1"
    • Consumers read asynchronously at their own pace
  4. Kafka does NOT delete events immediately

    • The event remains in the log until it expires (retention policy)
    • Multiple consumers can independently read the same event

Async consumption model

Diagram

Topic: transactions Partition 0: [e1, e2, e3, e4, e5, ...]  <-- ordered log

Consumer Group 1 (Ledger Service) offset = 3 → reads e4 next

Consumer Group 2 (Notification Service) offset = 1 → reads e2 next

Why Kafka is preferred in large systems like Wise

  1. Decoupling of services

    • Transaction service doesn't need to call all downstream services directly
  2. Durable, persistent events

    • If notification service is down, it can catch up later
  3. Multiple consumers

    • Ledger service, notification service, analytics service can all read the same events
  4. Audit & replay

    • Financial services need to replay transactions in case of errors
  5. Scalability under load

    • Webhooks might fail under spikes; Kafka buffers and distributes events