go-micro.dev/v5@v5.12.0/internal/website/docs/guides/migration/from-grpc.md (about)

     1  ---
     2  layout: default
     3  ---
     4  
     5  # Migrating from gRPC
     6  
     7  Step-by-step guide to migrating existing gRPC services to Go Micro.
     8  
     9  ## Why Migrate?
    10  
    11  Go Micro adds:
    12  - Built-in service discovery
    13  - Client-side load balancing
    14  - Pub/sub messaging
    15  - Multiple transport options
    16  - Unified tooling
    17  
    18  You keep:
    19  - Your proto definitions
    20  - gRPC performance (via gRPC transport)
    21  - Type safety
    22  - Streaming support
    23  
    24  ## Migration Strategy
    25  
    26  ### Phase 1: Parallel Running
    27  Run Go Micro alongside existing gRPC services
    28  
    29  ### Phase 2: Gradual Migration
    30  Migrate services one at a time
    31  
    32  ### Phase 3: Complete Migration
    33  All services on Go Micro
    34  
    35  ## Step-by-Step Migration
    36  
    37  ### 1. Existing gRPC Service
    38  
    39  ```protobuf
    40  // proto/hello.proto
    41  syntax = "proto3";
    42  
    43  package hello;
    44  option go_package = "./proto;hello";
    45  
    46  service Greeter {
    47    rpc SayHello (HelloRequest) returns (HelloReply) {}
    48  }
    49  
    50  message HelloRequest {
    51    string name = 1;
    52  }
    53  
    54  message HelloReply {
    55    string message = 1;
    56  }
    57  ```
    58  
    59  ```go
    60  // Original gRPC server
    61  package main
    62  
    63  import (
    64      "context"
    65      "log"
    66      "net"
    67      "google.golang.org/grpc"
    68      pb "myapp/proto"
    69  )
    70  
    71  type server struct {
    72      pb.UnimplementedGreeterServer
    73  }
    74  
    75  func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
    76      return &pb.HelloReply{Message: "Hello " + req.Name}, nil
    77  }
    78  
    79  func main() {
    80      lis, _ := net.Listen("tcp", ":50051")
    81      s := grpc.NewServer()
    82      pb.RegisterGreeterServer(s, &server{})
    83      log.Fatal(s.Serve(lis))
    84  }
    85  ```
    86  
    87  ### 2. Generate Go Micro Code
    88  
    89  Update your proto generation:
    90  
    91  ```bash
    92  # Install protoc-gen-micro
    93  go install go-micro.dev/v5/cmd/protoc-gen-micro@latest
    94  
    95  # Generate both gRPC and Go Micro code
    96  protoc --proto_path=. \
    97    --go_out=. --go_opt=paths=source_relative \
    98    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    99    --micro_out=. --micro_opt=paths=source_relative \
   100    proto/hello.proto
   101  ```
   102  
   103  This generates:
   104  - `hello.pb.go` - Protocol Buffers types
   105  - `hello_grpc.pb.go` - gRPC client/server (keep for compatibility)
   106  - `hello.pb.micro.go` - Go Micro client/server (new)
   107  
   108  ### 3. Migrate Server to Go Micro
   109  
   110  ```go
   111  // Go Micro server
   112  package main
   113  
   114  import (
   115      "context"
   116      "go-micro.dev/v5"
   117      "go-micro.dev/v5/server"
   118      pb "myapp/proto"
   119  )
   120  
   121  type Greeter struct{}
   122  
   123  func (s *Greeter) SayHello(ctx context.Context, req *pb.HelloRequest, rsp *pb.HelloReply) error {
   124      rsp.Message = "Hello " + req.Name
   125      return nil
   126  }
   127  
   128  func main() {
   129      svc := micro.NewService(
   130          micro.Name("greeter"),
   131      )
   132      svc.Init()
   133  
   134      pb.RegisterGreeterHandler(svc.Server(), new(Greeter))
   135  
   136      if err := svc.Run(); err != nil {
   137          log.Fatal(err)
   138      }
   139  }
   140  ```
   141  
   142  **Key differences:**
   143  - No manual port binding (Go Micro handles it)
   144  - Automatic service registration
   145  - Returns error, response via pointer parameter
   146  
   147  ### 4. Migrate Client
   148  
   149  **Original gRPC client:**
   150  ```go
   151  conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
   152  defer conn.Close()
   153  
   154  client := pb.NewGreeterClient(conn)
   155  rsp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
   156  ```
   157  
   158  **Go Micro client:**
   159  ```go
   160  svc := micro.NewService(micro.Name("client"))
   161  svc.Init()
   162  
   163  client := pb.NewGreeterService("greeter", svc.Client())
   164  rsp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
   165  ```
   166  
   167  **Benefits:**
   168  - No hardcoded addresses
   169  - Automatic service discovery
   170  - Client-side load balancing
   171  - Automatic retries
   172  
   173  ### 5. Keep gRPC Transport (Optional)
   174  
   175  Use gRPC as the underlying transport:
   176  
   177  ```go
   178  import (
   179      "go-micro.dev/v5"
   180      "go-micro.dev/v5/client"
   181      "go-micro.dev/v5/server"
   182      grpcclient "go-micro.dev/v5/client/grpc"
   183      grpcserver "go-micro.dev/v5/server/grpc"
   184  )
   185  
   186  svc := micro.NewService(
   187      micro.Name("greeter"),
   188      micro.Client(grpcclient.NewClient()),
   189      micro.Server(grpcserver.NewServer()),
   190  )
   191  ```
   192  
   193  This gives you:
   194  - gRPC performance
   195  - Go Micro features (discovery, load balancing)
   196  - Compatible with existing gRPC clients
   197  
   198  ## Streaming Migration
   199  
   200  ### Original gRPC Streaming
   201  
   202  ```protobuf
   203  service Greeter {
   204    rpc StreamHellos (stream HelloRequest) returns (stream HelloReply) {}
   205  }
   206  ```
   207  
   208  ```go
   209  func (s *server) StreamHellos(stream pb.Greeter_StreamHellosServer) error {
   210      for {
   211          req, err := stream.Recv()
   212          if err == io.EOF {
   213              return nil
   214          }
   215          if err != nil {
   216              return err
   217          }
   218          
   219          stream.Send(&pb.HelloReply{Message: "Hello " + req.Name})
   220      }
   221  }
   222  ```
   223  
   224  ### Go Micro Streaming
   225  
   226  ```go
   227  func (s *Greeter) StreamHellos(ctx context.Context, stream server.Stream) error {
   228      for {
   229          var req pb.HelloRequest
   230          if err := stream.Recv(&req); err != nil {
   231              return err
   232          }
   233          
   234          if err := stream.Send(&pb.HelloReply{Message: "Hello " + req.Name}); err != nil {
   235              return err
   236          }
   237      }
   238  }
   239  ```
   240  
   241  ## Service Discovery Migration
   242  
   243  ### Before (gRPC with Consul)
   244  
   245  ```go
   246  // Manually register with Consul
   247  config := api.DefaultConfig()
   248  config.Address = "consul:8500"
   249  client, _ := api.NewClient(config)
   250  
   251  reg := &api.AgentServiceRegistration{
   252      ID:      "greeter-1",
   253      Name:    "greeter",
   254      Address: "localhost",
   255      Port:    50051,
   256  }
   257  client.Agent().ServiceRegister(reg)
   258  
   259  // Cleanup on shutdown
   260  defer client.Agent().ServiceDeregister("greeter-1")
   261  ```
   262  
   263  ### After (Go Micro)
   264  
   265  ```go
   266  import "go-micro.dev/v5/registry/consul"
   267  
   268  reg := consul.NewConsulRegistry()
   269  svc := micro.NewService(
   270      micro.Name("greeter"),
   271      micro.Registry(reg),
   272  )
   273  
   274  // Registration automatic on Run()
   275  // Deregistration automatic on shutdown
   276  svc.Run()
   277  ```
   278  
   279  ## Load Balancing Migration
   280  
   281  ### Before (gRPC with custom LB)
   282  
   283  ```go
   284  // Need external load balancer or custom implementation
   285  // Example: round-robin DNS, Envoy, nginx
   286  ```
   287  
   288  ### After (Go Micro)
   289  
   290  ```go
   291  import "go-micro.dev/v5/selector"
   292  
   293  // Client-side load balancing built-in
   294  svc := micro.NewService(
   295      micro.Selector(selector.NewSelector(
   296          selector.SetStrategy(selector.RoundRobin),
   297      )),
   298  )
   299  ```
   300  
   301  ## Gradual Migration Path
   302  
   303  ### 1. Start with New Services
   304  
   305  New services use Go Micro, existing services stay on gRPC.
   306  
   307  ```go
   308  // New Go Micro service can call gRPC services
   309  // Configure gRPC endpoints directly
   310  grpcConn, _ := grpc.Dial("old-service:50051", grpc.WithInsecure())
   311  oldClient := pb.NewOldServiceClient(grpcConn)
   312  ```
   313  
   314  ### 2. Migrate Read-Heavy Services First
   315  
   316  Services with many clients benefit most from service discovery.
   317  
   318  ### 3. Migrate Services with Fewest Dependencies
   319  
   320  Leaf services are easier to migrate.
   321  
   322  ### 4. Add Adapters if Needed
   323  
   324  ```go
   325  // gRPC adapter for Go Micro service
   326  type GRPCAdapter struct {
   327      microClient pb.GreeterService
   328  }
   329  
   330  func (a *GRPCAdapter) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
   331      return a.microClient.SayHello(ctx, req)
   332  }
   333  
   334  // Register adapter as gRPC server
   335  s := grpc.NewServer()
   336  pb.RegisterGreeterServer(s, &GRPCAdapter{microClient: microClient})
   337  ```
   338  
   339  ## Checklist
   340  
   341  - [ ] Update proto generation to include `--micro_out`
   342  - [ ] Convert handler signatures (response via pointer)
   343  - [ ] Replace `grpc.Dial` with Go Micro client
   344  - [ ] Configure service discovery (Consul, Etcd, etc)
   345  - [ ] Update deployment (remove hardcoded ports)
   346  - [ ] Update monitoring (Go Micro metrics)
   347  - [ ] Test service-to-service communication
   348  - [ ] Update documentation
   349  - [ ] Train team on Go Micro patterns
   350  
   351  ## Common Issues
   352  
   353  ### Port Already in Use
   354  
   355  **gRPC**: Manual port management
   356  ```go
   357  lis, _ := net.Listen("tcp", ":50051")
   358  ```
   359  
   360  **Go Micro**: Automatic or explicit
   361  ```go
   362  // Let Go Micro choose
   363  svc := micro.NewService(micro.Name("greeter"))
   364  
   365  // Or specify
   366  svc := micro.NewService(
   367      micro.Name("greeter"),
   368      micro.Address(":50051"),
   369  )
   370  ```
   371  
   372  ### Service Not Found
   373  
   374  Check registry:
   375  ```bash
   376  # Consul
   377  curl http://localhost:8500/v1/catalog/services
   378  
   379  # Or use micro CLI
   380  micro services
   381  ```
   382  
   383  ### Different Serialization
   384  
   385  gRPC uses protobuf by default. Go Micro supports multiple codecs.
   386  
   387  Ensure both use protobuf:
   388  ```go
   389  import "go-micro.dev/v5/codec/proto"
   390  
   391  svc := micro.NewService(
   392      micro.Codec("application/protobuf", proto.Marshaler{}),
   393  )
   394  ```
   395  
   396  ## Performance Comparison
   397  
   398  | Scenario | gRPC | Go Micro (HTTP) | Go Micro (gRPC) |
   399  |----------|------|----------------|-----------------|
   400  | Simple RPC | ~25k req/s | ~20k req/s | ~24k req/s |
   401  | With Discovery | N/A | ~18k req/s | ~22k req/s |
   402  | Streaming | ~30k msg/s | ~15k msg/s | ~28k msg/s |
   403  
   404  *Go Micro with gRPC transport performs similarly to pure gRPC*
   405  
   406  ## Next Steps
   407  
   408  - Read [Go Micro Architecture](../architecture.md)
   409  - Explore [Plugin System](../plugins.md)
   410  - Check [Production Patterns](../examples/realworld/)
   411  
   412  ## Need Help?
   413  
   414  - [Examples](../examples/)
   415  - [GitHub Issues](https://github.com/micro/go-micro/issues)
   416  - [API Documentation](https://pkg.go.dev/go-micro.dev/v5)