Назад
Golang

gRPC в Go

gRPC - современный RPC-фреймворк от Google, построенный на HTTP/2 и Protocol Buffers. В Go он особенно популярен благодаря скорости, минимальному оверхеду и качественной официальной поддержке.

Как работает gRPC

  1. Пишешь контракт в .proto-файле (сообщения + сервисы)
  2. Генерируешь код с помощью protoc + плагинов
    • структуры сообщений (.pb.go)
    • интерфейс сервера и клиент (.grpc.pb.go)
  3. Реализуешь интерфейс сервера
  4. Запускаешь grpc-сервер на net.Listen
  5. Клиент подключается и вызывает методы как обычные функции

Общение идет по HTTP/2, бинарная сериализация через protobuf, мультиплексирование, deadlines, метаданные, интерсепторы, четыре вида RPC.

Четыре типа RPC в gRPC

  • Unary - классический запрос-ответ
  • Server streaming - клиент один запрос, сервер шлет поток ответов
  • Client streaming - клиент шлет поток, сервер дает один ответ
  • Bidirectional streaming - обе стороны шлют сколько угодно и когда угодно

Пример (Unary)

proto/greeter.proto

syntax = "proto3";

package greeter;
option go_package = "github.com/yourname/project/proto;proto";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

Генерация:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

protoc --go_out=. --go-grpc_out=. proto/greeter.proto

server/main.go:

package main

import (
 "context"
 "fmt"
 "log"
 "net"

 pb "github.com/yourname/project/proto"
 "google.golang.org/grpc"
)

type greeterServer struct {
 pb.UnimplementedGreeterServer
}

func (s *greeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
 msg := fmt.Sprintf("Привет, %s!", in.Name)
 return &pb.HelloResponse{Message: msg}, nil
}

func main() {
 lis, err := net.Listen("tcp", ":50051")
 if err != nil {
  log.Fatalf("не удалось открыть порт: %v", err)
 }

 s := grpc.NewServer()
 pb.RegisterGreeterServer(s, &greeterServer{})
 
 log.Printf("gRPC сервер запущен на :50051")
 if err := s.Serve(lis); err != nil {
  log.Fatalf("ошибка запуска: %v", err)
 }
}

client/main.go:

package main

import (
 "context"
 "log"
 "os"
 "time"

 pb "github.com/yourname/project/proto"
 "google.golang.org/grpc"
 "google.golang.org/grpc/credentials/insecure"
)

func main() {
 conn, err := grpc.NewClient(
  "localhost:50051",
  grpc.WithTransportCredentials(insecure.NewCredentials()),
 )
 if err != nil {
  log.Fatalf("не удалось подключиться: %v", err)
 }
 defer conn.Close()

 client := pb.NewGreeterClient(conn)

 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
 defer cancel()

 name := "Вася"
 if len(os.Args) > 1 {
  name = os.Args[1]
 }

 resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: name})
 if err != nil {
  log.Fatalf("ошибка вызова: %v", err)
 }

 log.Printf("Ответ сервера: %s", resp.Message)
}

Какие есть особенности?

Плюсы

  • Высокая производительность (часто в 5-12 раз быстрее JSON+REST)
  • HTTP/2 из коробки: мультиплексирование, меньшая задержка
  • Строгая типизация и генерация кода - минимум ошибок в контракте
  • Четыре вида стриминга - мощный инструмент для реального времени
  • Встроенные deadlines, cancellation, metadata
  • Интерсепторы для логирования, метрик, авторизации, retry
  • Поддержка reflection, TLS, gzip, keepalive

За и против

Недостатки:

  • Инструментов меньше, чем у REST (нет нативного swagger)
  • Браузеры не понимают без grpc-web или прокси
  • Отладка сложнее (помогают grpcurl, evans, bloomrpc)
  • Бинарный протокол - не читается глазами

Удобнее использовать для:

  • Микросервисы внутри кластера
  • Мобильные приложения и бэкенд (экономия трафика и батареи)
  • Высоконагруженные стриминговые сервисы
  • Системы с жесткими требованиями к задержке
  • Полиглотные команды (один .proto - клиенты на многих языках)

Удачи с gRPC - одним из самых удобных и быстрых инструментов для микросервисов😌

1