Назад
Golang
gRPC в Go
gRPC - современный RPC-фреймворк от Google, построенный на HTTP/2 и Protocol Buffers. В Go он особенно популярен благодаря скорости, минимальному оверхеду и качественной официальной поддержке.
Как работает gRPC
- Пишешь контракт в .proto-файле (сообщения + сервисы)
- Генерируешь код с помощью protoc + плагинов
- структуры сообщений (.pb.go)
- интерфейс сервера и клиент (.grpc.pb.go)
- Реализуешь интерфейс сервера
- Запускаешь grpc-сервер на net.Listen
- Клиент подключается и вызывает методы как обычные функции
Общение идет по 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