# Go dan gRPC di 2026: Microservices Berkinerja Tinggi dan Pertanyaan Wawancara > Pembahasan mendalam tentang gRPC dengan Go di 2026. Protocol Buffers, RPC unary dan streaming, interceptor, pola tingkat produksi, serta pertanyaan wawancara umum untuk backend engineer. - Published: 2026-06-08 - Updated: 2026-06-09 - Author: Anthony Fillion-Maillet - Tags: go, grpc, microservices, backend, interview, protocol-buffers - Reading time: 11 min --- gRPC telah menjadi lapisan komunikasi default untuk microservices Go yang membutuhkan latensi rendah dan kontrak API yang ketat. Dengan grpc-go v1.81, Go 1.26, dan kematangan ekosistem [go-grpc-middleware](https://github.com/grpc-ecosystem/go-grpc-middleware), membangun layanan gRPC tingkat produksi di Go menjadi lebih mudah dari sebelumnya — dan topik ini tetap menjadi salah satu yang paling sering diuji dalam wawancara backend. > **gRPC vs REST Sekilas** > > gRPC menggunakan HTTP/2 dan Protocol Buffers untuk serialisasi biner, menghasilkan payload hingga 10x lebih kecil serta streaming dua arah secara native. REST tetap lebih cocok untuk API publik; gRPC unggul pada komunikasi antarlayanan di mana performa dan keamanan tipe menjadi prioritas. ## Mengapa gRPC Mendominasi Komunikasi Backend Go Tiga sifat menjadikan gRPC pilihan alami untuk microservices Go. Pertama, Protocol Buffers menghasilkan kode Go bertipe kuat saat kompilasi, sehingga ketidakcocokan kontrak tertangkap sebelum deployment. Kedua, multiplexing HTTP/2 menghilangkan head-of-line blocking dan mendukung streaming full-duplex melalui satu koneksi TCP. Ketiga, model interceptor selaras dengan filosofi composition-over-inheritance Go, sehingga aspek lintas-potong seperti autentikasi dan tracing dapat disusun secara komposabel. Ekosistem gRPC di Go telah terkonsolidasi pada beberapa pustaka yang teruji. [grpc-go](https://github.com/grpc/grpc-go) menangani inti transport dan codegen. Paket [go-grpc-middleware v2](https://pkg.go.dev/github.com/grpc-ecosystem/go-grpc-middleware/v2) menyediakan interceptor produksi untuk logging, metrik, autentikasi, dan recovery. [Stats handler gRPC dari OpenTelemetry](https://opentelemetry.io/docs/languages/go/) mencakup distributed tracing tanpa kode interceptor khusus. ## Mendefinisikan Layanan dengan Protocol Buffers Setiap layanan gRPC dimulai dari sebuah berkas `.proto`. Skema tersebut mendefinisikan kontrak layanan, tipe pesan, dan metode RPC. Contoh berikut memodelkan layanan pengguna dengan pencarian unary dan metode server-streaming untuk feed aktivitas. ```protobuf // user_service.proto syntax = "proto3"; package user.v1; option go_package = "gen/user/v1;userv1"; service UserService { // Unary RPC: single request, single response rpc GetUser(GetUserRequest) returns (GetUserResponse); // Server streaming: single request, stream of responses rpc StreamActivity(StreamActivityRequest) returns (stream ActivityEvent); } message GetUserRequest { string user_id = 1; } message GetUserResponse { string user_id = 1; string email = 2; string display_name = 3; int64 created_at_unix = 4; } message StreamActivityRequest { string user_id = 1; int32 limit = 2; } message ActivityEvent { string event_id = 1; string action = 2; string resource = 3; int64 timestamp_unix = 4; } ``` Menjalankan `protoc --go_out=. --go-grpc_out=. user_service.proto` menghasilkan dua berkas: satu berisi tipe pesan dan satu berisi antarmuka client/server gRPC. Antarmuka server yang dihasilkan inilah yang harus dipenuhi oleh implementasi Go. ## Mengimplementasikan Server gRPC di Go Implementasi server menyematkan struct `UnimplementedUserServiceServer` yang dihasilkan, yang menyediakan kompatibilitas maju — menambahkan RPC baru ke berkas proto tidak akan merusak kode server yang ada sampai metode tersebut diimplementasikan secara eksplisit. ```go // server/user_server.go package server import ( "context" "fmt" "time" userv1 "myapp/gen/user/v1" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type UserServer struct { userv1.UnimplementedUserServiceServer store UserStore // interface for DB access } func NewUserServer(store UserStore) *UserServer { return &UserServer{store: store} } // GetUser handles the unary RPC func (s *UserServer) GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.GetUserResponse, error) { if req.GetUserId() == "" { return nil, status.Error(codes.InvalidArgument, "user_id is required") } user, err := s.store.FindByID(ctx, req.GetUserId()) if err != nil { return nil, status.Errorf(codes.Internal, "lookup failed: %v", err) } if user == nil { return nil, status.Error(codes.NotFound, "user not found") } return &userv1.GetUserResponse{ UserId: user.ID, Email: user.Email, DisplayName: user.DisplayName, CreatedAtUnix: user.CreatedAt.Unix(), }, nil } // StreamActivity sends activity events as a server stream func (s *UserServer) StreamActivity(req *userv1.StreamActivityRequest, stream userv1.UserService_StreamActivityServer) error { events, err := s.store.GetActivity(stream.Context(), req.GetUserId(), int(req.GetLimit())) if err != nil { return status.Errorf(codes.Internal, "activity fetch failed: %v", err) } for _, evt := range events { if err := stream.Send(&userv1.ActivityEvent{ EventId: evt.ID, Action: evt.Action, Resource: evt.Resource, TimestampUnix: evt.Timestamp.Unix(), }); err != nil { return fmt.Errorf("stream send: %w", err) } } return nil } ``` Dua pola yang perlu dicermati: `status.Error` dan `status.Errorf` menghasilkan error gRPC-native dengan kode status yang tepat, yang dapat diperiksa client secara terprogram. Penyematan `UnimplementedUserServiceServer` memastikan keamanan saat kompilasi ketika proto berkembang. ## Bootstrap Server Produksi dengan Interceptor Server gRPC polos memang menangani permintaan, tetapi minim observabilitas, autentikasi, dan recovery panic. Layanan produksi membutuhkan rantai interceptor. Pustaka [go-grpc-middleware v2](https://github.com/grpc-ecosystem/go-grpc-middleware) menyediakan interceptor komposabel yang dirangkai dengan `grpc.ChainUnaryInterceptor`. ```go // cmd/server/main.go package main import ( "log" "net" "os" "os/signal" "syscall" "google.golang.org/grpc" "google.golang.org/grpc/reflection" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/ratelimit" userv1 "myapp/gen/user/v1" "myapp/server" ) func main() { // Interceptor order matters: recovery first, then metrics, then auth srv := grpc.NewServer( // OpenTelemetry tracing via stats handler (not interceptor) grpc.StatsHandler(otelgrpc.NewServerHandler()), grpc.ChainUnaryInterceptor( recovery.UnaryServerInterceptor(), // catch panics ratelimit.UnaryServerInterceptor(limiter), // rate limiting logging.UnaryServerInterceptor(logger), // structured logging authInterceptor, // token validation ), grpc.ChainStreamInterceptor( recovery.StreamServerInterceptor(), ratelimit.StreamServerInterceptor(limiter), logging.StreamServerInterceptor(logger), ), ) // Register service implementation userv1.RegisterUserServiceServer(srv, server.NewUserServer(store)) // Enable reflection for grpcurl and debugging reflection.Register(srv) lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("listen: %v", err) } // Graceful shutdown on SIGTERM go func() { sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) <-sig log.Println("shutting down gRPC server") srv.GracefulStop() }() log.Printf("gRPC server listening on :50051") if err := srv.Serve(lis); err != nil { log.Fatalf("serve: %v", err) } } ``` Urutan interceptor menentukan prioritas eksekusi. Recovery berjalan lebih dulu untuk menangkap panic dari interceptor mana pun di hilir. Rate limiting berjalan sebelum autentikasi untuk melindungi lapisan autentikasi itu sendiri dari penyalahgunaan. Tracing OpenTelemetry menggunakan `StatsHandler` alih-alih interceptor — inilah [pendekatan yang direkomendasikan](https://grpc.io/docs/guides/interceptors/) sejak grpc-go v1.81, karena stats handler memiliki akses ke peristiwa transport tingkat lebih rendah. ## Pola Penanganan Error gRPC di Go Penanganan error yang tepat membedakan layanan gRPC produksi dari sekadar prototipe. gRPC mendefinisikan sekumpulan [kode status kanonis](https://grpc.io/docs/guides/status-codes/) yang dipahami setiap client. Paket `status` di Go memetakan kode-kode ini menjadi error. Pola-pola utamanya: - Kembalikan `codes.InvalidArgument` untuk permintaan yang salah bentuk (bug client) - Kembalikan `codes.NotFound` ketika sumber daya tidak ada - Kembalikan `codes.Internal` untuk kegagalan server yang tak terduga - Kembalikan `codes.Unauthenticated` ketika kredensial hilang atau tidak valid - Kembalikan `codes.PermissionDenied` ketika kredensial valid tetapi tidak mencukupi ```go // errors.go — reusable error constructors package rpcerr import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // NotFound wraps a resource-not-found error with a consistent message func NotFound(resource, id string) error { return status.Errorf(codes.NotFound, "%s %q not found", resource, id) } // InvalidArg wraps a validation error func InvalidArg(field, reason string) error { return status.Errorf(codes.InvalidArgument, "%s: %s", field, reason) } // Internal wraps an unexpected error, hiding internals from the client func Internal(err error) error { // Log the real error server-side; return generic message to client return status.Error(codes.Internal, "internal server error") } ``` Membungkus error dalam konstruktor spesifik-domain menjaga konsistensi kode status di seluruh RPC. Client dapat melakukan switch pada `status.Code(err)` untuk menangani setiap kasus tanpa mem-parsing string error. ## Menguji Layanan gRPC dengan bufconn Pengujian integrasi layanan gRPC biasanya memerlukan menjalankan server TCP nyata. Paket `bufconn` menyediakan listener dalam-memori yang menghilangkan alokasi port dan overhead jaringan sepenuhnya. ```go // server_test.go package server_test import ( "context" "net" "testing" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/test/bufconn" userv1 "myapp/gen/user/v1" "myapp/server" ) const bufSize = 1024 * 1024 func setupServer(t *testing.T) userv1.UserServiceClient { t.Helper() lis := bufconn.Listen(bufSize) // in-memory listener srv := grpc.NewServer() userv1.RegisterUserServiceServer(srv, server.NewUserServer(mockStore{})) go func() { if err := srv.Serve(lis); err != nil { t.Errorf("server exited: %v", err) } }() t.Cleanup(srv.GracefulStop) // Dial the in-memory listener conn, err := grpc.NewClient( "passthrough:///bufconn", grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) { return lis.DialContext(ctx) }), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { t.Fatalf("dial bufconn: %v", err) } t.Cleanup(func() { conn.Close() }) return userv1.NewUserServiceClient(conn) } func TestGetUser_NotFound(t *testing.T) { client := setupServer(t) _, err := client.GetUser(context.Background(), &userv1.GetUserRequest{ UserId: "nonexistent", }) // Verify gRPC status code st, ok := status.FromError(err) if !ok || st.Code() != codes.NotFound { t.Errorf("expected NotFound, got %v", err) } } ``` `bufconn` membuat koneksi gRPC nyata dengan serialisasi penuh dan eksekusi interceptor, hanya saja tanpa TCP. Pengujian berjalan lebih cepat dan dapat dijalankan paralel tanpa konflik port. Ini adalah pola standar yang digunakan di dalam repositori grpc-go itu sendiri. ## Mengamankan gRPC dengan mTLS dan Autentikasi Token Layanan gRPC produksi memerlukan keamanan transport. Dua pendekatan mendominasi: mTLS untuk autentikasi antarlayanan di mana kedua sisi menyajikan sertifikat, dan autentikasi berbasis token (JWT atau API key) untuk identitas client dalam kanal yang sudah aman. Konfigurasi mTLS memuat sertifikat saat server dijalankan: ```go // tls.go — mTLS server credentials package main import ( "crypto/tls" "crypto/x509" "os" "google.golang.org/grpc/credentials" ) func loadTLSCredentials(certFile, keyFile, caFile string) (credentials.TransportCredentials, error) { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { return nil, err } caPool := x509.NewCertPool() caPEM, err := os.ReadFile(caFile) if err != nil { return nil, err } caPool.AppendCertsFromPEM(caPEM) tlsCfg := &tls.Config{ Certificates: []tls.Certificate{cert}, ClientAuth: tls.RequireAndVerifyClientCert, // enforce mTLS ClientCAs: caPool, MinVersion: tls.VersionTLS13, // TLS 1.3 minimum in 2026 } return credentials.NewTLS(tlsCfg), nil } ``` TLS 1.3 menjadi baseline untuk layanan gRPC pada 2026, menawarkan handshake lebih cepat (1-RTT) dan suite cipher yang lebih kuat dibanding TLS 1.2. Untuk autentikasi berbasis token yang dilapis di atas TLS, sebuah interceptor unary mengekstrak token dari metadata gRPC dan memvalidasinya sebelum handler dieksekusi. > **Rotasi Sertifikat mTLS** > > Jalur sertifikat yang di-hardcode mengharuskan restart server untuk rotasi. Deployment produksi sebaiknya menggunakan `tls.Config.GetCertificate` atau sidecar seperti Envoy untuk menangani pembaruan sertifikat otomatis tanpa downtime. ## Pertanyaan Wawancara: gRPC dan Microservices Go Pertanyaan-pertanyaan berikut sering muncul dalam wawancara backend engineering yang berfokus pada Go dan sistem terdistribusi. Setiap jawaban menyasar kedalaman yang diharapkan di level senior. **Apa empat tipe RPC dalam gRPC dan kapan masing-masing sesuai?** Unary (satu permintaan, satu respons) mencakup sebagian besar operasi CRUD. Server streaming cocok untuk skenario di mana server mendorong banyak hasil — feed aktivitas, hasil pencarian, pembaruan real-time. Client streaming berlaku untuk skenario unggah atau penulisan batch di mana client mengirim banyak pesan sebelum server merespons. Bidirectional streaming melayani chat, penyuntingan kolaboratif, atau protokol apa pun di mana kedua sisi mengirim secara independen. **Bagaimana gRPC menangani kompatibilitas mundur ketika sebuah field proto dihapus?** Proto3 tidak pernah menggunakan ulang nomor field. Menghapus sebuah field berarti server mengabaikan nilainya jika client lama masih mengirimnya, dan client lama yang membaca respons cukup melihat nilai zero untuk field yang dihapus. Kata kunci `reserved` mencegah penggunaan ulang nomor atau nama field secara tidak sengaja. Ini secara fundamental berbeda dari API JSON di mana penghapusan field dapat menyebabkan kegagalan deserialisasi. > **Aturan Kompatibilitas Wire Protobuf** > > Jangan pernah mengubah tipe atau nomor field yang sudah ada. Tambahkan field baru dengan nomor baru. Gunakan `reserved` untuk memensiunkan nomor lama. Aturan ini berlaku di semua bahasa dan menjamin deployment tanpa downtime. **Jelaskan peran interceptor dalam layanan gRPC produksi.** Interceptor adalah lapisan middleware gRPC. Mereka dieksekusi sebelum dan sesudah handler, dalam urutan registrasinya. Rantai produksi yang umum: recovery (menangkap panic) > rate limiting > logging > autentikasi > validasi. Pustaka [go-grpc-middleware v2](https://github.com/grpc-ecosystem/go-grpc-middleware) menyediakan interceptor komposabel yang mengikuti pola ini. Interceptor tidak dapat memodifikasi lapisan transport (TLS, port) — mereka hanya beroperasi pada level RPC. **Apa perbedaan antara `grpc.StatsHandler` dan sebuah interceptor?** Interceptor membungkus handler RPC dan beroperasi di level aplikasi. Stats handler menerima peristiwa level transport: koneksi dimulai, pengiriman/penerimaan pesan, penyelesaian RPC. OpenTelemetry menggunakan stats handler karena mereka menangkap metrik yang tak terlihat oleh interceptor, seperti jumlah byte dan peristiwa siklus hidup koneksi. Sejak grpc-go v1.66+, [rekomendasi resmi](https://grpc.io/docs/guides/interceptors/) adalah menggunakan stats handler untuk observabilitas dan interceptor untuk logika bisnis. **Bagaimana Anda mengimplementasikan graceful shutdown untuk server gRPC?** `GracefulStop()` berhenti menerima koneksi baru dan menunggu RPC yang sedang berjalan selesai. Polanya: dengarkan SIGTERM dalam sebuah goroutine, panggil `GracefulStop()`, lalu panggilan `Serve()` akan kembali. Untuk RPC streaming yang mungkin berjalan tanpa batas, tetapkan deadline dengan pembatalan context atau gunakan health check yang berhenti mengembalikan `SERVING` sebelum shutdown dimulai, memberi load balancer waktu untuk menguras trafik. **Kapan sebuah tim sebaiknya memilih gRPC ketimbang REST untuk layanan internal?** gRPC adalah pilihan yang lebih kuat ketika: layanan membutuhkan kontrak API ketat yang diberlakukan saat kompilasi; sistem memerlukan streaming (server push, dua arah); latensi penting dan serialisasi biner mengurangi ukuran payload; tim mengelola kode client maupun server. REST lebih disukai untuk API publik yang dikonsumsi browser (JSON native, tanpa proxy), API dengan caching berat via semantik HTTP, atau tim yang membutuhkan kompatibilitas tooling maksimum. Banyak arsitektur menggunakan keduanya — [gRPC secara internal dengan gateway REST](https://grpc.io/docs/languages/go/quickstart/) untuk konsumen eksternal. ## Kesimpulan - Protocol Buffers memberlakukan kontrak API saat kompilasi — perubahan yang merusak muncul saat code generation, bukan saat runtime - Pola `UnimplementedServer` menyediakan kompatibilitas maju ketika menambahkan RPC baru ke layanan yang berkembang - Urutan interceptor penting: recovery dulu, lalu rate limiting, lalu autentikasi — pustaka [go-grpc-middleware v2](https://github.com/grpc-ecosystem/go-grpc-middleware) menangani perangkaian - Gunakan `grpc.StatsHandler` dengan OpenTelemetry untuk tracing; sisakan interceptor untuk logika bisnis seperti autentikasi dan validasi - `bufconn` memungkinkan pengujian integrasi yang cepat dan bebas port yang menjalankan seluruh stack gRPC termasuk serialisasi dan interceptor - mTLS dengan TLS 1.3 adalah baseline 2026 untuk keamanan antarlayanan; lapisi autentikasi token di atasnya untuk identitas dalam mesh - Persiapkan diri untuk [pertanyaan wawancara gRPC](/technologies/go/interview-questions/grpc) dengan memahami empat tipe RPC, aturan kompatibilitas mundur proto, dan perbedaan interceptor vs stats handler --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/go/go-grpc-microservices-2026