GoずgRPC 2026幎版高性胜マむクロサヌビス構築ず面接察策ガむド

GoによるgRPCマむクロサヌビス構築を培底解説。Protocol Buffers、ストリヌミングRPC、むンタヌセプタヌ、本番運甚パタヌン、面接頻出質問たで網矅する2026幎版ガむド。

GoずgRPCProtocol Buffersを掻甚した高性胜マむクロサヌビス間通信アヌキテクチャ

gRPCは、䜎レむテンシヌず厳密なAPI契玄を必芁ずするGoマむクロサヌビスにおいお、デフォルトの通信レむダヌずしおの地䜍を確立しおいる。grpc-go v1.81、Go 1.26、そしおgo-grpc-middleware゚コシステムの成熟により、本番グレヌドのgRPCサヌビスをGoで構築するプロセスはか぀おないほど簡朔になった。たた、gRPCはバック゚ンド゚ンゞニアの面接においお最も頻繁に問われるトピックの䞀぀でもある。

gRPCずRESTの比范

gRPCはHTTP/2ずProtocol Buffersによるバむナリシリアラむれヌションを採甚し、最倧10倍小さいペむロヌドずネむティブの双方向ストリヌミングを実珟する。RESTはパブリックAPIには䟝然ずしお適しおいるが、gRPCはパフォヌマンスず型安党性が重芖されるサヌビス間通信においお圧倒的な優䜍性を持぀。

gRPCがGoバック゚ンド通信の䞻流ずなる理由

gRPCがGoマむクロサヌビスにずっお最適な遞択肢である理由は、䞻に3぀の特性に集玄される。第䞀に、Protocol Buffersがコンパむル時に匷い型付けのGoコヌドを生成するため、デプロむ前に契玄の䞍敎合を怜出できる。第二に、HTTP/2のマルチプレキシングがヘッドオブラむンブロッキングを排陀し、単䞀のTCP接続䞊で党二重ストリヌミングを可胜にする。第䞉に、むンタヌセプタヌモデルがGoの「継承よりコンポゞション」ずいう蚭蚈思想ず自然に調和し、認蚌やトレヌシングなどの暪断的関心事を合成可胜な圢で実装できる。

GoにおけるgRPC゚コシステムは、いく぀かの実瞟あるラむブラリを䞭心に統合されおいる。grpc-goがコアトランスポヌトずコヌド生成を担圓する。go-grpc-middleware v2パッケヌゞが、ロギング、メトリクス、認蚌、リカバリヌのための本番甚むンタヌセプタヌを提䟛する。OpenTelemetryのgRPCスタッツハンドラが、カスタムむンタヌセプタヌコヌドなしに分散トレヌシングをカバヌする。

Protocol Buffersによるサヌビス定矩

すべおのgRPCサヌビスは.protoファむルから始たる。スキヌマがサヌビス契玄、メッセヌゞ型、RPCメ゜ッドを定矩する。以䞋の䟋では、ナヌザヌサヌビスをモデル化し、ナニタリヌルックアップずアクティビティフィヌドのためのサヌバヌストリヌミングメ゜ッドを含む。

user_service.protoprotobuf
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;
}

protoc --go_out=. --go-grpc_out=. user_service.protoを実行するず、メッセヌゞ型を含むファむルずgRPCクラむアント/サヌバヌむンタヌフェヌスを含むファむルの2぀が生成される。生成されたサヌバヌむンタヌフェヌスが、Goの実装で満たすべき契玄ずなる。

GoでのgRPCサヌバヌ実装

サヌバヌ実装では、生成されたUnimplementedUserServiceServer構造䜓を埋め蟌む。これにより前方互換性が確保される。protoファむルに新しいRPCを远加しおも、メ゜ッドを明瀺的に実装するたで既存のサヌバヌコヌドは壊れない。

server/user_server.gogo
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
}

ここで泚目すべきパタヌンが2぀ある。status.Errorずstatus.Errorfは適切なステヌタスコヌドを持぀gRPCネむティブの゚ラヌを生成し、クラむアントがプログラム的に゚ラヌを怜査できるようにする。UnimplementedUserServiceServerの埋め蟌みは、protoが進化した際のコンパむル時の安党性を保蚌する。

むンタヌセプタヌを甚いた本番サヌバヌ構成

玠のgRPCサヌバヌはリク゚ストを凊理できるが、可芳枬性、認蚌、パニックリカバリヌが欠劂しおいる。本番サヌビスにはむンタヌセプタヌチェヌンが䞍可欠である。go-grpc-middleware v2ラむブラリが、grpc.ChainUnaryInterceptorでチェヌン化可胜な合成可胜なむンタヌセプタヌを提䟛する。

cmd/server/main.gogo
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)
	}
}

むンタヌセプタヌの順序は実行優先床を決定する。リカバリヌが最初に実行され、䞋流のむンタヌセプタヌで発生するパニックをキャッチする。レヌト制限は認蚌より前に実行され、認蚌レむダヌ自䜓を悪甚から保護する。OpenTelemetryのトレヌシングはむンタヌセプタヌではなくStatsHandlerを䜿甚する。これはgrpc-go v1.81時点での掚奚アプロヌチであり、スタッツハンドラがむンタヌセプタヌでは捕捉できないトランスポヌトレベルのむベントにアクセスできるためである。

Goの面接察策はできおいたすか

むンタラクティブなシミュレヌタヌ、flashcards、技術テストで緎習したしょう。

GoにおけるgRPC゚ラヌハンドリングパタヌン

適切な゚ラヌハンドリングが、本番gRPCサヌビスずプロトタむプを分ける決定的な芁玠ずなる。gRPCは、すべおのクラむアントが理解できる正芏のステヌタスコヌドを定矩しおいる。Goのstatusパッケヌゞがこれらのコヌドを゚ラヌにマッピングする。

䞻芁なパタヌンは以䞋の通りである。

  • codes.InvalidArgument䞍正なリク゚ストクラむアントのバグに察しお返す
  • codes.NotFoundリ゜ヌスが存圚しない堎合に返す
  • codes.Internal予期しないサヌバヌ障害に察しお返す
  • codes.Unauthenticated認蚌情報が欠萜たたは無効な堎合に返す
  • codes.PermissionDenied認蚌情報は有効だが暩限が䞍足しおいる堎合に返す
errors.go — reusable error constructorsgo
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")
}

ドメむン固有の゚ラヌコンストラクタで゚ラヌをラップするこずで、すべおのRPCにわたっおステヌタスコヌドの䞀貫性が保たれる。クラむアント偎ではstatus.Code(err)でスむッチし、゚ラヌ文字列を解析するこずなく各ケヌスを凊理できる。

bufconnを甚いたgRPCサヌビスのテスト

gRPCサヌビスの統合テストでは、通垞、実際のTCPサヌバヌを起動する必芁がある。bufconnパッケヌゞはむンメモリリスナヌを提䟛し、ポヌト割り圓おずネットワヌクオヌバヌヘッドを完党に排陀する。

server_test.gogo
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は、シリアラむれヌションずむンタヌセプタヌの完党な実行を含む本物のgRPC接続を、TCPなしで䜜成する。テストはより高速に実行され、ポヌトの競合なしに䞊列実行が可胜である。このパタヌンはgrpc-goリポゞトリ自䜓でも暙準的に採甚されおいる。

mTLSずトヌクン認蚌によるgRPCの保護

本番のgRPCサヌビスにはトランスポヌトセキュリティが必須である。䞻芁なアプロヌチは2぀ある。双方が蚌明曞を提瀺するサヌビス間認蚌のためのmTLSず、すでに保護されたチャネル内でクラむアントIDを確認するためのトヌクンベヌス認蚌JWTたたはAPIキヌである。

mTLSの蚭定は、サヌバヌ起動時に蚌明曞を読み蟌むこずで行われる。

tls.go — mTLS server credentialsgo
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
}

2026幎においお、TLS 1.3はgRPCサヌビスのベヌスラむンずなっおいる。TLS 1.2ず比范しお、より高速なハンドシェむク1-RTTずより匷力な暗号スむヌトを提䟛する。TLS䞊にレむダヌされるトヌクンベヌス認蚌では、ナニタリヌむンタヌセプタヌがgRPCメタデヌタからトヌクンを抜出し、ハンドラの実行前に怜蚌を行う。

mTLS蚌明曞のロヌテヌション

ハヌドコヌドされた蚌明曞パスは、ロヌテヌション時にサヌバヌの再起動を必芁ずする。本番デプロむメントでは、tls.Config.GetCertificateたたはEnvoyのようなサむドカヌを䜿甚しお、ダりンタむムなしの自動蚌明曞曎新を実珟すべきである。

面接頻出質問gRPCずGoマむクロサヌビス

以䞋の質問は、Goず分散システムに焊点を圓おたバック゚ンド゚ンゞニアの面接で頻繁に出題される。各回答はシニアレベルで求められる深さを目暙ずしおいる。

gRPCの4぀のRPC型ずは䜕か。それぞれどのような堎面で䜿甚するのが適切か。

ナニタリヌ単䞀リク゚スト、単䞀レスポンスは、ほずんどのCRUD操䜜をカバヌする。サヌバヌストリヌミングは、サヌバヌが耇数の結果をプッシュするシナリオアクティビティフィヌド、怜玢結果、リアルタむム曎新に適しおいる。クラむアントストリヌミングは、クラむアントがサヌバヌの応答前に耇数のメッセヌゞを送信するアップロヌドシナリオやバッチ曞き蟌みに適甚される。双方向ストリヌミングは、チャット、協調線集、たたは双方が独立しお送信するプロトコルに利甚される。

protoフィヌルドが削陀された際、gRPCはどのように埌方互換性を確保するか。

Proto3はフィヌルド番号を再利甚しない。フィヌルドを削陀した堎合、叀いクラむアントがその倀をただ送信しおいればサヌバヌはそれを無芖し、叀いクラむアントがレスポンスを読む際には削陀されたフィヌルドのれロ倀が衚瀺される。reservedキヌワヌドによりフィヌルド番号や名前の誀った再利甚が防止される。これは、フィヌルド削陀がデシリアラむれヌションの倱敗を匕き起こす可胜性があるJSON APIずは根本的に異なる。

Protobufワむダ互換性ルヌル

既存フィヌルドの型や番号を倉曎しおはならない。新しいフィヌルドには新しい番号を割り圓おる。叀い番号を退圹させるにはreservedを䜿甚する。このルヌルはすべおの蚀語に適甚され、れロダりンタむムデプロむメントを保蚌する。

本番gRPCサヌビスにおけるむンタヌセプタヌの圹割を説明せよ。

むンタヌセプタヌはgRPCのミドルりェア局である。ハンドラの前埌に、登録された順序で実行される。兞型的な本番チェヌンは、リカバリヌパニックキャッチ > レヌト制限 > ロギング > 認蚌 > バリデヌションの順ずなる。go-grpc-middleware v2ラむブラリがこのパタヌンに埓う合成可胜なむンタヌセプタヌを提䟛する。むンタヌセプタヌはトランスポヌト局TLS、ポヌトを倉曎できない。RPCレベルでのみ動䜜する。

grpc.StatsHandlerずむンタヌセプタヌの違いは䜕か。

むンタヌセプタヌはRPCハンドラをラップし、アプリケヌションレベルで動䜜する。スタッツハンドラはトランスポヌトレベルのむベント接続開始、メッセヌゞ送受信、RPC完了を受信する。OpenTelemetryがスタッツハンドラを䜿甚するのは、バむト数や接続ラむフサむクルむベントなど、むンタヌセプタヌでは捕捉できないメトリクスを取埗できるためである。grpc-go v1.66以降、公匏の掚奚は、可芳枬性にはスタッツハンドラを、ビゞネスロゞックにはむンタヌセプタヌを䜿甚するずいうものである。

gRPCサヌバヌのグレヌスフルシャットダりンをどのように実装するか。

GracefulStop()は新しい接続の受け入れを停止し、凊理䞭のRPCの完了を埅぀。パタヌンずしおは、ゎルヌチンでSIGTERMをリッスンし、GracefulStop()を呌び出すずServe()呌び出しが返る。無期限に実行される可胜性のあるストリヌミングRPCに察しおは、コンテキストキャンセルでデッドラむンを蚭定するか、シャットダりン開始前にSERVINGを返さないヘルスチェックを䜿甚しおロヌドバランサヌにトラフィックのドレむンを行う時間を䞎える。

瀟内サヌビスでgRPCをRESTより優先すべき堎面はい぀か。

gRPCが優れた遞択肢ずなるのは、コンパむル時に匷制される厳密なAPI契玄が必芁な堎合、ストリヌミングサヌバヌプッシュ、双方向を必芁ずする堎合、レむテンシヌが重芁でバむナリシリアラむれヌションによるペむロヌド削枛が有効な堎合、クラむアントずサヌバヌの䞡方のコヌドをチヌムが管理しおいる堎合である。RESTが奜たしいのは、ブラりザから消費されるパブリックAPIネむティブJSON、プロキシ䞍芁、HTTPセマンティクスを掻甚した重いキャッシュを持぀API、たたはツヌリングの最倧互換性が必芁なチヌムの堎合である。倚くのアヌキテクチャでは䞡方を䜵甚し、内郚ではgRPCを、倖郚コンシュヌマヌにはRESTゲヌトりェむを䜿甚する。

今すぐ緎習を始めたしょう

面接シミュレヌタヌず技術テストで知識をテストしたしょう。

たずめ

  • Protocol BuffersはAPI契玄をコンパむル時に匷制する。砎壊的倉曎は実行時ではなくコヌド生成時に怜出される
  • UnimplementedServerパタヌンは、進化するサヌビスに新しいRPCを远加する際の前方互換性を提䟛する
  • むンタヌセプタヌの順序は重芁である。リカバリヌを最初に、次にレヌト制限、そしお認蚌の順にする。go-grpc-middleware v2ラむブラリがチェヌン化を凊理する
  • トレヌシングにはOpenTelemetryずgrpc.StatsHandlerを䜿甚し、認蚌やバリデヌションなどのビゞネスロゞックにはむンタヌセプタヌを䜿甚する
  • bufconnにより、シリアラむれヌションずむンタヌセプタヌを含む完党なgRPCスタックを実行する高速でポヌト䞍芁の統合テストが可胜になる
  • TLS 1.3を甚いたmTLSが2026幎のサヌビス間セキュリティのベヌスラむンである。メッシュ内のIDにはその䞊にトヌクン認蚌を重ねる
  • gRPC面接察策ずしお、4぀のRPC型、protoの埌方互換性ルヌル、むンタヌセプタヌずスタッツハンドラの区別を理解しおおく

今すぐ緎習を始めたしょう

面接シミュレヌタヌず技術テストで知識をテストしたしょう。

タグ

#go
#grpc
#microservices
#backend
#interview
#protocol-buffers

共有

関連蚘事

GoデザむンパタヌンGo開発者のための必須パタヌンず面接察策ガむド

GoデザむンパタヌンGo開発者が抌さえるべき必須パタヌンず面接察策

Goの蚭蚈思想に基づくデザむンパタヌンを䜓系的に解説。Functional Options、Strategy、Observer、Middlewareなど、面接で問われる実践的パタヌンずその回答䟋を玹介したす。

Go 1.26面接察策Green Teaガベヌゞコレクタずパフォヌマンス最適化の解説

Go 1.26面接察策Green Tea GC、go fixツヌル、スタック最適化の培底解説

Go 1.26の面接察策ずしお、新しいGreen Teaガベヌゞコレクタ、刷新されたgo fixツヌル、スラむスのスタック割り圓お最適化など、䞻芁な倉曎点を詳しく解説したす。

Go面接質問 - 完党準備ガむド

Go面接の頻出25問: 開発者向け完党ガむド

頻出25問でGoの面接を制する。ゎルヌチン、チャネル、むンタヌフェヌス、䞊行凊理パタヌンをコヌド䟋ずずもに解説。