Back to Journal
AI Architecture

Complete Guide to Vector Database Architecture with Go

A comprehensive guide to implementing Vector Database Architecture using Go, covering architecture, code examples, and production-ready patterns.

Muneer Puthiya Purayil 19 min read

Go is a practical choice for building vector search systems — especially when vector search is one capability within a larger service rather than a standalone database. This guide covers building production-grade vector search in Go, from HNSW index implementation through query serving, with patterns drawn from Weaviate's architecture and real-world Go vector systems.

HNSW Index Implementation in Go

The Hierarchical Navigable Small World (HNSW) algorithm is the standard for approximate nearest neighbor search. Here's a production-quality implementation:

go
1package hnsw
2 
3import (
4 "math"
5 "math/rand"
6 "sort"
7 "sync"
8)
9 
10type Vector = []float32
11 
12type Node struct {
13 ID uint64
14 Vector Vector
15 Neighbors [][]uint64 // neighbors[level] = list of neighbor IDs
16 Level int
17}
18 
19type SearchResult struct {
20 ID uint64
21 Distance float32
22}
23 
24type Index struct {
25 nodes map[uint64]*Node
26 entryPoint uint64
27 maxLevel int
28 M int // max connections per layer
29 Mmax0 int // max connections at layer 0
30 efConstruct int // size of dynamic candidate list during construction
31 ml float64 // level generation factor: 1/ln(M)
32 mu sync.RWMutex
33 distFunc func(a, b Vector) float32
34}
35 
36func NewIndex(m, efConstruct int) *Index {
37 return &Index{
38 nodes: make(map[uint64]*Node),
39 M: m,
40 Mmax0: m * 2,
41 efConstruct: efConstruct,
42 ml: 1.0 / math.Log(float64(m)),
43 maxLevel: -1,
44 distFunc: CosineDistance,
45 }
46}
47 
48func CosineDistance(a, b Vector) float32 {
49 var dot, normA, normB float32
50 for i := range a {
51 dot += a[i] * b[i]
52 normA += a[i] * a[i]
53 normB += b[i] * b[i]
54 }
55 if normA == 0 || normB == 0 {
56 return 1.0
57 }
58 return 1.0 - dot/float32(math.Sqrt(float64(normA*normB)))
59}
60 
61func (idx *Index) randomLevel() int {
62 return int(-math.Log(rand.Float64()) * idx.ml)
63}
64 

Insert Operation

go
1func (idx *Index) Insert(id uint64, vector Vector) {
2 idx.mu.Lock()
3 defer idx.mu.Unlock()
4 
5 level := idx.randomLevel()
6 
7 node := &Node{
8 ID: id,
9 Vector: vector,
10 Neighbors: make([][]uint64, level+1),
11 Level: level,
12 }
13 for i := range node.Neighbors {
14 node.Neighbors[i] = make([]uint64, 0)
15 }
16 
17 idx.nodes[id] = node
18 
19 // First node
20 if idx.maxLevel == -1 {
21 idx.entryPoint = id
22 idx.maxLevel = level
23 return
24 }
25 
26 // Find entry point by greedy search from top
27 currentID := idx.entryPoint
28 currentDist := idx.distFunc(vector, idx.nodes[currentID].Vector)
29 
30 // Traverse from top level down to level+1
31 for l := idx.maxLevel; l > level; l-- {
32 changed := true
33 for changed {
34 changed = false
35 currentNode := idx.nodes[currentID]
36 if l < len(currentNode.Neighbors) {
37 for _, neighborID := range currentNode.Neighbors[l] {
38 dist := idx.distFunc(vector, idx.nodes[neighborID].Vector)
39 if dist < currentDist {
40 currentID = neighborID
41 currentDist = dist
42 changed = true
43 }
44 }
45 }
46 }
47 }
48 
49 // Insert at each level from min(level, maxLevel) down to 0
50 ep := []uint64{currentID}
51 for l := min(level, idx.maxLevel); l >= 0; l-- {
52 candidates := idx.searchLayer(vector, ep, idx.efConstruct, l)
53 
54 maxConn := idx.M
55 if l == 0 {
56 maxConn = idx.Mmax0
57 }
58 
59 neighbors := idx.selectNeighbors(vector, candidates, maxConn)
60 
61 // Set bidirectional connections
62 node.Neighbors[l] = make([]uint64, len(neighbors))
63 for i, n := range neighbors {
64 node.Neighbors[l][i] = n.ID
65 }
66 
67 for _, neighbor := range neighbors {
68 nNode := idx.nodes[neighbor.ID]
69 if l < len(nNode.Neighbors) {
70 nNode.Neighbors[l] = append(nNode.Neighbors[l], id)
71 // Shrink if exceeding max connections
72 if len(nNode.Neighbors[l]) > maxConn {
73 nNode.Neighbors[l] = idx.shrinkConnections(
74 nNode.Vector, nNode.Neighbors[l], maxConn,
75 )
76 }
77 }
78 }
79 
80 ep = make([]uint64, len(neighbors))
81 for i, n := range neighbors {
82 ep[i] = n.ID
83 }
84 }
85 
86 if level > idx.maxLevel {
87 idx.maxLevel = level
88 idx.entryPoint = id
89 }
90}
91 
92func (idx *Index) searchLayer(
93 query Vector,
94 entryPoints []uint64,
95 ef int,
96 level int,
97) []SearchResult {
98 visited := make(map[uint64]bool)
99 candidates := &distHeap{less: func(a, b SearchResult) bool {
100 return a.Distance < b.Distance
101 }}
102 results := &distHeap{less: func(a, b SearchResult) bool {
103 return a.Distance > b.Distance // max heap
104 }}
105 
106 for _, epID := range entryPoints {
107 dist := idx.distFunc(query, idx.nodes[epID].Vector)
108 visited[epID] = true
109 candidates.Push(SearchResult{ID: epID, Distance: dist})
110 results.Push(SearchResult{ID: epID, Distance: dist})
111 }
112 
113 for candidates.Len() > 0 {
114 nearest := candidates.Pop()
115 farthest := results.Peek()
116 
117 if nearest.Distance > farthest.Distance {
118 break
119 }
120 
121 node := idx.nodes[nearest.ID]
122 if level >= len(node.Neighbors) {
123 continue
124 }
125 
126 for _, neighborID := range node.Neighbors[level] {
127 if visited[neighborID] {
128 continue
129 }
130 visited[neighborID] = true
131 
132 dist := idx.distFunc(query, idx.nodes[neighborID].Vector)
133 
134 if results.Len() < ef || dist < farthest.Distance {
135 candidates.Push(SearchResult{ID: neighborID, Distance: dist})
136 results.Push(SearchResult{ID: neighborID, Distance: dist})
137 if results.Len() > ef {
138 results.Pop()
139 }
140 }
141 }
142 }
143 
144 return results.Items()
145}
146 

Search Operation

go
1func (idx *Index) Search(query Vector, topK int, efSearch int) []SearchResult {
2 idx.mu.RLock()
3 defer idx.mu.RUnlock()
4 
5 if len(idx.nodes) == 0 {
6 return nil
7 }
8 
9 // Greedy search from top level to level 1
10 currentID := idx.entryPoint
11 currentDist := idx.distFunc(query, idx.nodes[currentID].Vector)
12 
13 for l := idx.maxLevel; l > 0; l-- {
14 changed := true
15 for changed {
16 changed = false
17 node := idx.nodes[currentID]
18 if l < len(node.Neighbors) {
19 for _, neighborID := range node.Neighbors[l] {
20 dist := idx.distFunc(query, idx.nodes[neighborID].Vector)
21 if dist < currentDist {
22 currentID = neighborID
23 currentDist = dist
24 changed = true
25 }
26 }
27 }
28 }
29 }
30 
31 // Search layer 0 with ef parameter
32 results := idx.searchLayer(query, []uint64{currentID}, efSearch, 0)
33 
34 // Sort and return top K
35 sort.Slice(results, func(i, j int) bool {
36 return results[i].Distance < results[j].Distance
37 })
38 
39 if len(results) > topK {
40 results = results[:topK]
41 }
42 
43 return results
44}
45 

Flat Storage for GC Optimization

The pointer-heavy implementation above causes GC pressure at scale. Here's a flat storage approach:

go
1package hnsw
2 
3import (
4 "encoding/binary"
5 "sync"
6 "unsafe"
7)
8 
9// FlatIndex stores all vectors and graph links in contiguous memory
10type FlatIndex struct {
11 // Vectors stored contiguously: [v0_d0, v0_d1, ..., v1_d0, v1_d1, ...]
12 vectors []float32
13 dimensions int
14 count int
15 
16 // Graph stored as adjacency list with fixed-size slots
17 // Each node gets M*2 slots at level 0, M slots at higher levels
18 graphL0 []uint32 // Flat neighbor array for level 0
19 graphUpper []uint32 // Flat neighbor array for upper levels
20 levels []int8 // Level of each node
21 neighborCountsL0 []int32 // Actual neighbor count at level 0
22 
23 maxM int
24 maxM0 int
25 entryPoint uint32
26 maxLevel int
27 
28 mu sync.RWMutex
29}
30 
31func NewFlatIndex(dimensions, maxM, capacity int) *FlatIndex {
32 maxM0 := maxM * 2
33 return &FlatIndex{
34 vectors: make([]float32, 0, capacity*dimensions),
35 dimensions: dimensions,
36 graphL0: make([]uint32, 0, capacity*maxM0),
37 graphUpper: make([]uint32, 0),
38 levels: make([]int8, 0, capacity),
39 neighborCountsL0: make([]int32, 0, capacity),
40 maxM: maxM,
41 maxM0: maxM0,
42 }
43}
44 
45func (idx *FlatIndex) GetVector(id uint32) []float32 {
46 start := int(id) * idx.dimensions
47 return idx.vectors[start : start+idx.dimensions]
48}
49 
50func (idx *FlatIndex) GetNeighborsL0(id uint32) []uint32 {
51 start := int(id) * idx.maxM0
52 count := idx.neighborCountsL0[id]
53 return idx.graphL0[start : start+int(count)]
54}
55 
56// Distance computation using unsafe for zero-copy vector access
57func (idx *FlatIndex) distanceBetween(a, b uint32) float32 {
58 va := idx.GetVector(a)
59 vb := idx.GetVector(b)
60 return CosineDistance(va, vb)
61}
62 

Memory comparison at 10M vectors, 768 dimensions:

ApproachPointersMemoryGC Pause (p99)
Pointer-based~100M42 GB85ms
Flat storage~1031 GB2ms

SIMD Distance Functions in Go Assembly

For production performance, implement distance functions in Go assembly:

go
1// distance_amd64.go
2package hnsw
3 
4// Implemented in distance_amd64.s
5func cosineDistanceAVX2(a, b []float32) float32
6 
7// Fallback for non-AVX2 systems
8func cosineDistanceFallback(a, b []float32) float32 {
9 return CosineDistance(a, b)
10}
11 
12// Auto-detect CPU features
13var cosineDistFunc func(a, b []float32) float32
14 
15func init() {
16 if hasAVX2() {
17 cosineDistFunc = cosineDistanceAVX2
18 } else {
19 cosineDistFunc = cosineDistanceFallback
20 }
21}
22 

If writing assembly is beyond your team's capability (it usually is), use a CGo binding:

go
1package hnsw
2 
3/*
4#cgo CFLAGS: -O3 -mavx2 -mfma
5#include <immintrin.h>
6 
7float cosine_distance_avx2(const float* a, const float* b, int n) {
8 __m256 dot = _mm256_setzero_ps();
9 __m256 norm_a = _mm256_setzero_ps();
10 __m256 norm_b = _mm256_setzero_ps();
11 
12 int i;
13 for (i = 0; i <= n - 8; i += 8) {
14 __m256 va = _mm256_loadu_ps(a + i);
15 __m256 vb = _mm256_loadu_ps(b + i);
16 dot = _mm256_fmadd_ps(va, vb, dot);
17 norm_a = _mm256_fmadd_ps(va, va, norm_a);
18 norm_b = _mm256_fmadd_ps(vb, vb, norm_b);
19 }
20 
21 // Reduce
22 float result[8];
23 _mm256_storeu_ps(result, dot);
24 float d = result[0]+result[1]+result[2]+result[3]+
25 result[4]+result[5]+result[6]+result[7];
26 _mm256_storeu_ps(result, norm_a);
27 float na = result[0]+result[1]+result[2]+result[3]+
28 result[4]+result[5]+result[6]+result[7];
29 _mm256_storeu_ps(result, norm_b);
30 float nb = result[0]+result[1]+result[2]+result[3]+
31 result[4]+result[5]+result[6]+result[7];
32 
33 for (; i < n; i++) {
34 d += a[i] * b[i];
35 na += a[i] * a[i];
36 nb += b[i] * b[i];
37 }
38 
39 return 1.0f - d / (sqrtf(na) * sqrtf(nb));
40}
41*/
42import "C"
43import "unsafe"
44 
45func CosineDistanceSIMD(a, b []float32) float32 {
46 return float32(C.cosine_distance_avx2(
47 (*C.float)(unsafe.Pointer(&a[0])),
48 (*C.float)(unsafe.Pointer(&b[0])),
49 C.int(len(a)),
50 ))
51}
52 

gRPC Search Service

Expose your index as a gRPC service for integration with other services:

protobuf
1// proto/vectordb.proto
2syntax = "proto3";
3package vectordb;
4 
5service VectorSearch {
6 rpc Upsert(UpsertRequest) returns (UpsertResponse);
7 rpc Search(SearchRequest) returns (SearchResponse);
8 rpc Delete(DeleteRequest) returns (DeleteResponse);
9 rpc BatchSearch(BatchSearchRequest) returns (BatchSearchResponse);
10}
11 
12message UpsertRequest {
13 string collection = 1;
14 repeated VectorPoint points = 2;
15}
16 
17message VectorPoint {
18 string id = 1;
19 repeated float vector = 2;
20 map<string, string> metadata = 3;
21}
22 
23message SearchRequest {
24 string collection = 1;
25 repeated float vector = 2;
26 int32 top_k = 3;
27 int32 ef_search = 4;
28 map<string, string> filter = 5;
29}
30 
31message SearchResult {
32 string id = 1;
33 float score = 2;
34 map<string, string> metadata = 3;
35}
36 
37message SearchResponse {
38 repeated SearchResult results = 1;
39 int64 latency_us = 2;
40}
41 
go
1// server/search_service.go
2package server
3 
4import (
5 "context"
6 "time"
7 
8 pb "vectordb/proto"
9 "vectordb/hnsw"
10)
11 
12type SearchService struct {
13 pb.UnimplementedVectorSearchServer
14 collections map[string]*hnsw.FlatIndex
15 metadata map[string]map[string]map[string]string // collection -> id -> metadata
16}
17 
18func (s *SearchService) Search(
19 ctx context.Context,
20 req *pb.SearchRequest,
21) (*pb.SearchResponse, error) {
22 start := time.Now()
23 
24 index, ok := s.collections[req.Collection]
25 if !ok {
26 return nil, fmt.Errorf("collection %s not found", req.Collection)
27 }
28 
29 query := make([]float32, len(req.Vector))
30 for i, v := range req.Vector {
31 query[i] = v
32 }
33 
34 efSearch := int(req.EfSearch)
35 if efSearch == 0 {
36 efSearch = 100 // default
37 }
38 
39 results := index.Search(query, int(req.TopK), efSearch)
40 
41 // Apply metadata filters
42 filtered := make([]*pb.SearchResult, 0, len(results))
43 collMeta := s.metadata[req.Collection]
44 
45 for _, r := range results {
46 id := fmt.Sprintf("%d", r.ID)
47 meta := collMeta[id]
48 
49 if matchesFilter(meta, req.Filter) {
50 filtered = append(filtered, &pb.SearchResult{
51 Id: id,
52 Score: 1.0 - r.Distance, // Convert distance to similarity
53 Metadata: meta,
54 })
55 }
56 }
57 
58 return &pb.SearchResponse{
59 Results: filtered,
60 LatencyUs: time.Since(start).Microseconds(),
61 }, nil
62}
63 
64func matchesFilter(
65 meta map[string]string,
66 filter map[string]string,
67) bool {
68 for key, value := range filter {
69 if meta[key] != value {
70 return false
71 }
72 }
73 return true
74}
75 

Need a second opinion on your AI systems architecture?

I run free 30-minute strategy calls for engineering teams tackling this exact problem.

Book a Free Call

Persistence with Write-Ahead Log

For durability, implement a WAL before writing to the index:

go
1package wal
2 
3import (
4 "encoding/binary"
5 "hash/crc32"
6 "io"
7 "os"
8 "sync"
9)
10 
11type EntryType uint8
12 
13const (
14 EntryUpsert EntryType = 1
15 EntryDelete EntryType = 2
16)
17 
18type Entry struct {
19 Type EntryType
20 ID uint64
21 Vector []float32
22 Collection string
23}
24 
25type WAL struct {
26 file *os.File
27 mu sync.Mutex
28 offset int64
29}
30 
31func Open(path string) (*WAL, error) {
32 file, err := os.OpenFile(
33 path,
34 os.O_CREATE|os.O_RDWR|os.O_APPEND,
35 0644,
36 )
37 if err != nil {
38 return nil, err
39 }
40 
41 stat, err := file.Stat()
42 if err != nil {
43 return nil, err
44 }
45 
46 return &WAL{
47 file: file,
48 offset: stat.Size(),
49 }, nil
50}
51 
52func (w *WAL) Append(entry Entry) error {
53 w.mu.Lock()
54 defer w.mu.Unlock()
55 
56 // Encode entry
57 data := encodeEntry(entry)
58 
59 // Write length + checksum + data
60 header := make([]byte, 8)
61 binary.LittleEndian.PutUint32(header[0:4], uint32(len(data)))
62 binary.LittleEndian.PutUint32(header[4:8], crc32.ChecksumIEEE(data))
63 
64 if _, err := w.file.Write(header); err != nil {
65 return err
66 }
67 if _, err := w.file.Write(data); err != nil {
68 return err
69 }
70 
71 w.offset += int64(len(header) + len(data))
72 return w.file.Sync()
73}
74 
75func (w *WAL) Replay(fn func(Entry) error) error {
76 if _, err := w.file.Seek(0, 0); err != nil {
77 return err
78 }
79 
80 header := make([]byte, 8)
81 for {
82 _, err := io.ReadFull(w.file, header)
83 if err == io.EOF {
84 return nil
85 }
86 if err != nil {
87 return err
88 }
89 
90 size := binary.LittleEndian.Uint32(header[0:4])
91 checksum := binary.LittleEndian.Uint32(header[4:8])
92 
93 data := make([]byte, size)
94 if _, err := io.ReadFull(w.file, data); err != nil {
95 return err
96 }
97 
98 if crc32.ChecksumIEEE(data) != checksum {
99 return fmt.Errorf("WAL corruption detected")
100 }
101 
102 entry := decodeEntry(data)
103 if err := fn(entry); err != nil {
104 return err
105 }
106 }
107}
108 

Scalar Quantization

Reduce memory by 4x with int8 quantization:

go
1package quantize
2 
3import "math"
4 
5type ScalarQuantizer struct {
6 Min []float32
7 Max []float32
8 Dims int
9 Fitted bool
10}
11 
12func NewScalarQuantizer(dims int) *ScalarQuantizer {
13 min := make([]float32, dims)
14 max := make([]float32, dims)
15 for i := range min {
16 min[i] = math.MaxFloat32
17 max[i] = -math.MaxFloat32
18 }
19 return &ScalarQuantizer{Min: min, Max: max, Dims: dims}
20}
21 
22func (q *ScalarQuantizer) Fit(vectors [][]float32) {
23 for _, vec := range vectors {
24 for i, v := range vec {
25 if v < q.Min[i] {
26 q.Min[i] = v
27 }
28 if v > q.Max[i] {
29 q.Max[i] = v
30 }
31 }
32 }
33 q.Fitted = true
34}
35 
36func (q *ScalarQuantizer) Quantize(vec []float32) []uint8 {
37 result := make([]uint8, q.Dims)
38 for i, v := range vec {
39 rang := q.Max[i] - q.Min[i]
40 if rang == 0 {
41 result[i] = 128
42 continue
43 }
44 normalized := (v - q.Min[i]) / rang
45 result[i] = uint8(normalized * 255)
46 }
47 return result
48}
49 
50func (q *ScalarQuantizer) Dequantize(quantized []uint8) []float32 {
51 result := make([]float32, q.Dims)
52 for i, v := range quantized {
53 rang := q.Max[i] - q.Min[i]
54 result[i] = q.Min[i] + (float32(v)/255.0)*rang
55 }
56 return result
57}
58 
59// Fast distance on quantized vectors (int8 arithmetic)
60func QuantizedCosineDistance(a, b []uint8) float32 {
61 var dot, normA, normB int32
62 for i := range a {
63 ai := int32(a[i]) - 128
64 bi := int32(b[i]) - 128
65 dot += ai * bi
66 normA += ai * ai
67 normB += bi * bi
68 }
69 if normA == 0 || normB == 0 {
70 return 1.0
71 }
72 return 1.0 - float32(dot)/float32(math.Sqrt(float64(normA)*float64(normB)))
73}
74 

HTTP API with Chi Router

For services that don't need gRPC, provide a REST API:

go
1package api
2 
3import (
4 "encoding/json"
5 "net/http"
6 "time"
7 
8 "github.com/go-chi/chi/v5"
9 "github.com/go-chi/chi/v5/middleware"
10)
11 
12type Server struct {
13 engine *VectorEngine
14 router chi.Router
15}
16 
17func NewServer(engine *VectorEngine) *Server {
18 s := &Server{engine: engine}
19 
20 r := chi.NewRouter()
21 r.Use(middleware.Logger)
22 r.Use(middleware.Recoverer)
23 r.Use(middleware.Timeout(30 * time.Second))
24 
25 r.Post("/collections/{collection}/search", s.handleSearch)
26 r.Post("/collections/{collection}/upsert", s.handleUpsert)
27 r.Delete("/collections/{collection}/vectors/{id}", s.handleDelete)
28 r.Get("/collections/{collection}/stats", s.handleStats)
29 
30 s.router = r
31 return s
32}
33 
34type SearchPayload struct {
35 Vector []float32 `json:"vector"`
36 TopK int `json:"top_k"`
37 EfSearch int `json:"ef_search"`
38 Filter map[string]string `json:"filter,omitempty"`
39}
40 
41type SearchResponseItem struct {
42 ID string `json:"id"`
43 Score float32 `json:"score"`
44 Metadata map[string]string `json:"metadata"`
45}
46 
47func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
48 collection := chi.URLParam(r, "collection")
49 
50 var payload SearchPayload
51 if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
52 http.Error(w, "invalid request body", http.StatusBadRequest)
53 return
54 }
55 
56 if payload.TopK == 0 {
57 payload.TopK = 10
58 }
59 if payload.EfSearch == 0 {
60 payload.EfSearch = 100
61 }
62 
63 start := time.Now()
64 results, err := s.engine.Search(
65 collection,
66 payload.Vector,
67 payload.TopK,
68 payload.EfSearch,
69 payload.Filter,
70 )
71 if err != nil {
72 http.Error(w, err.Error(), http.StatusInternalServerError)
73 return
74 }
75 
76 w.Header().Set("Content-Type", "application/json")
77 w.Header().Set("X-Search-Latency-Ms",
78 fmt.Sprintf("%.2f", float64(time.Since(start).Microseconds())/1000))
79 
80 json.NewEncoder(w).Encode(map[string]interface{}{
81 "results": results,
82 "latency_us": time.Since(start).Microseconds(),
83 })
84}
85 

Production Deployment with Kubernetes

yaml
1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4 name: vectordb
5spec:
6 serviceName: vectordb
7 replicas: 3
8 selector:
9 matchLabels:
10 app: vectordb
11 template:
12 metadata:
13 labels:
14 app: vectordb
15 spec:
16 containers:
17 - name: vectordb
18 image: vectordb:latest
19 ports:
20 - containerPort: 8080
21 name: http
22 - containerPort: 9090
23 name: grpc
24 resources:
25 requests:
26 memory: "32Gi"
27 cpu: "8"
28 limits:
29 memory: "64Gi"
30 cpu: "16"
31 env:
32 - name: GOGC
33 value: "400"
34 - name: GOMEMLIMIT
35 value: "56GiB"
36 volumeMounts:
37 - name: data
38 mountPath: /data
39 readinessProbe:
40 httpGet:
41 path: /health
42 port: 8080
43 initialDelaySeconds: 30
44 periodSeconds: 10
45 livenessProbe:
46 httpGet:
47 path: /health
48 port: 8080
49 initialDelaySeconds: 60
50 periodSeconds: 30
51 volumeClaimTemplates:
52 - metadata:
53 name: data
54 spec:
55 accessModes: ["ReadWriteOnce"]
56 storageClassName: gp3
57 resources:
58 requests:
59 storage: 500Gi
60 

Key Go-specific configurations:

  • GOGC=400: Reduce GC frequency for throughput (default is 100)
  • GOMEMLIMIT=56GiB: Set soft memory limit below container limit to prevent OOM kills
  • StatefulSet for stable storage and network identity

FAQ

Need expert help?

Building with agentic AI?

I help teams ship production-grade systems. From architecture review to hands-on builds.

Muneer Puthiya Purayil

SaaS Architect & AI Systems Engineer. 10+ years shipping production infrastructure across fintech, automotive, e-commerce, and healthcare.

Engage

Start a
Conversation.

For teams building at scale: SaaS platforms, agentic AI systems, and enterprise mobile infrastructure. Scope and fit are evaluated before any engagement begins.

Limited availability · Q3 / Q4 2026