GoãšgRPC 2026幎çïŒé«æ§èœãã€ã¯ããµãŒãã¹æ§ç¯ãšé¢æ¥å¯Ÿçã¬ã€ã
Goã«ããgRPCãã€ã¯ããµãŒãã¹æ§ç¯ã培åºè§£èª¬ãProtocol Buffersãã¹ããªãŒãã³ã°RPCãã€ã³ã¿ãŒã»ãã¿ãŒãæ¬çªéçšãã¿ãŒã³ã颿¥é »åºè³ªåãŸã§ç¶²çŸ ãã2026幎çã¬ã€ãã

gRPCã¯ãäœã¬ã€ãã³ã·ãŒãšå³å¯ãªAPIå¥çŽãå¿ èŠãšããGoãã€ã¯ããµãŒãã¹ã«ãããŠãããã©ã«ãã®éä¿¡ã¬ã€ã€ãŒãšããŠã®å°äœã確ç«ããŠãããgrpc-go v1.81ãGo 1.26ããããŠgo-grpc-middlewareãšã³ã·ã¹ãã ã®æçã«ãããæ¬çªã°ã¬ãŒãã®gRPCãµãŒãã¹ãGoã§æ§ç¯ããããã»ã¹ã¯ãã€ãŠãªãã»ã©ç°¡æœã«ãªã£ãããŸããgRPCã¯ããã¯ãšã³ããšã³ãžãã¢ã®é¢æ¥ã«ãããŠæãé »ç¹ã«åããããããã¯ã®äžã€ã§ãããã
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ã¡ãœãããå®çŸ©ããã以äžã®äŸã§ã¯ããŠãŒã¶ãŒãµãŒãã¹ãã¢ãã«åãããŠãã¿ãªãŒã«ãã¯ã¢ãããšã¢ã¯ãã£ããã£ãã£ãŒãã®ããã®ãµãŒããŒã¹ããªãŒãã³ã°ã¡ãœãããå«ãã
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ã远å ããŠããã¡ãœãããæç€ºçã«å®è£
ãããŸã§æ¢åã®ãµãŒããŒã³ãŒãã¯å£ããªãã
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ã§ãã§ãŒã³åå¯èœãªåæå¯èœãªã€ã³ã¿ãŒã»ãã¿ãŒãæäŸããã
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ïŒèªèšŒæ å ±ã¯æå¹ã ãæš©éãäžè¶³ããŠããå Žåã«è¿ã
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ããã±ãŒãžã¯ã€ã³ã¡ã¢ãªãªã¹ããŒãæäŸããããŒãå²ãåœãŠãšãããã¯ãŒã¯ãªãŒããŒããããå®å
šã«æé€ããã
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ã®èšå®ã¯ããµãŒããŒèµ·åæã«èšŒææžãèªã¿èŸŒãããšã§è¡ãããã
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ã¡ã¿ããŒã¿ããããŒã¯ã³ãæœåºãããã³ãã©ã®å®è¡åã«æ€èšŒãè¡ãã
ããŒãã³ãŒããããèšŒææžãã¹ã¯ãããŒããŒã·ã§ã³æã«ãµãŒããŒã®åèµ·åãå¿
èŠãšãããæ¬çªãããã€ã¡ã³ãã§ã¯ãtls.Config.GetCertificateãŸãã¯Envoyã®ãããªãµã€ãã«ãŒã䜿çšããŠãããŠã³ã¿ã€ã ãªãã®èªåèšŒææžæŽæ°ãå®çŸãã¹ãã§ããã
颿¥é »åºè³ªåïŒgRPCãšGoãã€ã¯ããµãŒãã¹
以äžã®è³ªåã¯ãGoãšåæ£ã·ã¹ãã ã«çŠç¹ãåœãŠãããã¯ãšã³ããšã³ãžãã¢ã®é¢æ¥ã§é »ç¹ã«åºé¡ããããååçã¯ã·ãã¢ã¬ãã«ã§æ±ããããæ·±ããç®æšãšããŠããã
gRPCã®4ã€ã®RPCåãšã¯äœããããããã©ã®ãããªå Žé¢ã§äœ¿çšããã®ãé©åãã
ãŠãã¿ãªãŒïŒåäžãªã¯ãšã¹ããåäžã¬ã¹ãã³ã¹ïŒã¯ãã»ãšãã©ã®CRUDæäœãã«ããŒããããµãŒããŒã¹ããªãŒãã³ã°ã¯ããµãŒããŒãè€æ°ã®çµæãããã·ã¥ããã·ããªãªïŒã¢ã¯ãã£ããã£ãã£ãŒããæ€çŽ¢çµæããªã¢ã«ã¿ã€ã æŽæ°ïŒã«é©ããŠãããã¯ã©ã€ã¢ã³ãã¹ããªãŒãã³ã°ã¯ãã¯ã©ã€ã¢ã³ãããµãŒããŒã®å¿çåã«è€æ°ã®ã¡ãã»ãŒãžãéä¿¡ããã¢ããããŒãã·ããªãªããããæžã蟌ã¿ã«é©çšããããåæ¹åã¹ããªãŒãã³ã°ã¯ããã£ãããå調線éããŸãã¯åæ¹ãç¬ç«ããŠéä¿¡ãããããã³ã«ã«å©çšãããã
protoãã£ãŒã«ããåé€ãããéãgRPCã¯ã©ã®ããã«åŸæ¹äºææ§ã確ä¿ãããã
Proto3ã¯ãã£ãŒã«ãçªå·ãåå©çšããªãããã£ãŒã«ããåé€ããå Žåãå€ãã¯ã©ã€ã¢ã³ãããã®å€ããŸã éä¿¡ããŠããã°ãµãŒããŒã¯ãããç¡èŠããå€ãã¯ã©ã€ã¢ã³ããã¬ã¹ãã³ã¹ãèªãéã«ã¯åé€ããããã£ãŒã«ãã®ãŒãå€ã衚瀺ããããreservedããŒã¯ãŒãã«ãããã£ãŒã«ãçªå·ãååã®èª€ã£ãåå©çšã鲿¢ããããããã¯ããã£ãŒã«ãåé€ããã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ã®å€±æãåŒãèµ·ããå¯èœæ§ãããJSON APIãšã¯æ ¹æ¬çã«ç°ãªãã
æ¢åãã£ãŒã«ãã®åãçªå·ã倿ŽããŠã¯ãªããªããæ°ãããã£ãŒã«ãã«ã¯æ°ããçªå·ãå²ãåœãŠããå€ãçªå·ãé圹ãããã«ã¯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ãã¶ã€ã³ãã¿ãŒã³ïŒGoéçºè ãæŒãããã¹ãå¿ é ãã¿ãŒã³ãšé¢æ¥å¯Ÿç
Goã®èšèšææ³ã«åºã¥ããã¶ã€ã³ãã¿ãŒã³ãäœç³»çã«è§£èª¬ãFunctional OptionsãStrategyãObserverãMiddlewareãªã©ã颿¥ã§åãããå®è·µçãã¿ãŒã³ãšãã®åçäŸã玹ä»ããŸãã

Go 1.26颿¥å¯ŸçïŒGreen Tea GCãgo fixããŒã«ãã¹ã¿ãã¯æé©åã®åŸ¹åºè§£èª¬
Go 1.26ã®é¢æ¥å¯ŸçãšããŠãæ°ããGreen Teaã¬ããŒãžã³ã¬ã¯ã¿ãå·æ°ãããgo fixããŒã«ãã¹ã©ã€ã¹ã®ã¹ã¿ãã¯å²ãåœãŠæé©åãªã©ãäž»èŠãªå€æŽç¹ã詳ãã解説ããŸãã

Go颿¥ã®é »åº25å: éçºè åãå®å šã¬ã€ã
é »åº25åã§Goã®é¢æ¥ãå¶ããããŽã«ãŒãã³ããã£ãã«ãã€ã³ã¿ãŒãã§ãŒã¹ã䞊è¡åŠçãã¿ãŒã³ãã³ãŒãäŸãšãšãã«è§£èª¬ã