title: 65. gRPC Name Resolver Kustom: Mengoptimalkan Service Discovery dengan Gaya Sendiri
date: 2024-06-11
tags: [golang, grpc, networking, distributed systems, service discovery]
gRPC telah lama menjadi andalan developer dalam membangun microservices yang cepat, ringan, dan mudah di-maintain. Salah satu komponen krusial yang sering terlupakan adalah Name Resolver. Secara default, gRPC menghadirkan beberapa resolver seperti dns:// atau passthrough://, namun kebutuhan di lingkungan distributed modern — seperti orchestrator custom, service mesh, atau environment hybrid — kerap membutuhkan sentuhan “kustom”. Masalahnya, sangat sedikit engineer yang benar-benar memahami betapa powerful dan fleksibelnya membuat Name Resolver Kustom sendiri.
Pada artikel ini, saya akan membahas lebih dalam tentang gRPC Name Resolver Kustom — mulai dari arsitektur, alur kerja, hingga implementasi sederhana dan use case-nya di sistem nyata.
Mengapa Perlu Name Resolver Kustom?
Saat bekerja dengan microservices, cara layanan menemukan endpoint satu sama lain (service discovery) adalah life and death. Dalam konteks gRPC, target endpoint seperti dns:///service.mydomain.com akan diproses oleh name resolver. Tapi bagaimana jika source layanan datangnya dari registry unik, file lokal, atau bahkan API bespoke internal? Di sinilah Custom Name Resolver dibutuhkan.
Beberapa skenario umum:
- Integrasi dengan registry internal (HashiCorp Consul, ETCD, dsb)
- Dynamic microservice pada Kubernetes dengan label/filter khusus
- Service discovery via API Gateway khusus yang tidak support DNS A/AAAA secara native
Alur Kerja Name Resolver di gRPC
Mari jabarkan diagram sederhana tentang proses name resolution di gRPC.
sequenceDiagram
participant Client
participant gRPC Library
participant NameResolver
participant LoadBalancer
Client->>gRPC Library: Dial ("myres://user-service/id-1234")
gRPC Library->>NameResolver: Build("myres")
NameResolver->>gRPC Library: UpdateState(Resolved addresses)
gRPC Library->>LoadBalancer: Pass endpoint list
LoadBalancer->>Client: Ready to RPC!
Summary:
- Client memulai koneksi dengan target khusus via
proto://target - gRPC memilih resolver sesuai schema (proto)
- Name Resolver mem-fetch dan mengkalkulasi endpoint dari source kustom
- Update state ke gRPC core untuk diteruskan ke load balancer dan dial RPC
Anatomy Name Resolver pada gRPC-Go
Name resolver adalah implementasi dari interface berikut (simplified):
type Builder interface {
Scheme() string
Build(target Target, cc ClientConn, opts BuildOptions) (Resolver, error)
}
type Resolver interface {
ResolveNow(ResolveNowOptions)
Close()
}
- Builder: Registrasi awal yang menentukan “scheme” resolver
- Resolver: Proses backend fetching/monitoring ke source endpoint
Studi Kasus: Custom In-Memory Resolver
Katakan kita punya service discovery berbasis YAML lokal.
File: services.yaml
user-service:
- 10.0.0.2:50051
- 10.0.0.3:50051
order-service:
- 10.0.0.4:50052
Langkah 1: Definisikan Scheme Resolver
const scheme = "yamlmem"
func init() {
resolver.Register(&yamlMemBuilder{})
}
type yamlMemBuilder struct{}
func (b *yamlMemBuilder) Scheme() string { return scheme }
func (b *yamlMemBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
// Fetch endpoints dari YAML berdasarkan target.Endpoint
addrs := resolveFromYaml(target.Endpoint)
cc.UpdateState(resolver.State{Addresses: addrs})
return &yamlMemResolver{cc: cc}, nil
}
Langkah 2: Proses Resolving YAML
func resolveFromYaml(endpoint string) []resolver.Address {
// 1. Load file YAML
// 2. Parse endpoint
// 3. Return []resolver.Address dengan format host:port
// Di sini saya simplifikasi hardcoded
if endpoint == "user-service" {
return []resolver.Address{
{Addr: "10.0.0.2:50051"},
{Addr: "10.0.0.3:50051"},
}
}
return nil
}
type yamlMemResolver struct{ cc resolver.ClientConn }
func (r *yamlMemResolver) ResolveNow(o resolver.ResolveNowOptions) {}
func (r *yamlMemResolver) Close() {}
Langkah 3: Dial dengan Scheme Kustom
conn, err := grpc.Dial("yamlmem:///user-service", grpc.WithInsecure())
if err != nil {
log.Fatalf("dial failed: %v", err)
}
Dengan pattern ini, setiap kali kita menjalankan grpc.Dial dengan scheme yamlmem://, resolver kustom akan otomatis mengambil dan memperbarui endpoint dari YAML.
Simulasi Hasil: Tabel Resolusi
| Client Dial Target | gRPC Scheme Resolver | Endpoints Didapatkan |
|---|---|---|
yamlmem:///user-service | yamlmem | 10.0.0.2:50051, 10.0.0.3:50051 |
yamlmem:///order-service | yamlmem | 10.0.0.4:50052 |
dns:///api.example.org | dns |
Pengembangan Lanjutan
a. Live Update
Tentu, di dunia nyata resolver akan memonitor sumber (file, registry, REST API) dan memanggil cc.UpdateState() saat ada perubahan.
go func() {
for changes := range watchServiceChange() {
cc.UpdateState(resolver.State{Addresses: changes})
}
}()
b. Error Handling
cc.ReportError(err) bisa dipakai saat proses resolve gagal. Ini akan mengirim feedback ke client/error balancer.
c. Advanced Use Case: Resolver untuk Service Mesh Labels
Bayangkan Anda ingin hanya service dengan label blue atau canary yang resolve-able. Custom resolver dapat melakukan filtering endpoint sebelum meng-update state.
Kapan Harus Membuat Resolver Kustom?
| Use Case | Harus Kustom? | Alasan |
|---|---|---|
| DNS biasa | Tidak | Built-in resolver sudah cukup |
| Load dari file/registry sendiri | Ya | Diperlukan access logic non-standar |
| Koneksi dengan API eksternal | Ya | Sumber data endpoints bukan lewat DNS |
| Filtering berdasarkan business logic | Ya | Filtering/logic hanya di sisi aplikasi |
| Single static host | Tidak | Bisa pakai passthrough:// |
Kesimpulan
Kemampuan menciptakan gRPC Name Resolver Kustom bisa jadi superpower bagi engineer yang ingin microservice yang lebih fleksibel, scalable, dan sesuai kebutuhan distribusi layanan modern. Baik itu registry internal, service mesh, atau hybrid environment — dengan resolver kustom, kita bisa mendefinisikan cara service discovery sendiri, tanpa harus menunggu provider atau “hack” DNS.
Referensi & Tools
Selamat bereksperimen dan eksplor gRPC lebih dalam dengan resolver kustom!
Tinggalkan komentar kalau ada ide atau pertanyaan seputar resolver unik atau integrasi service discovery di perusahaan Anda 👍
Follow saya untuk artikel selanjutnya tentang distributed systems & scalable microservices!