Golang微服务出现nil指针解引用panic问题排查求助
Golang gRPC微服务nil指针panic排查
问题背景
开发的Golang gRPC微服务在调用SaveUser接口时触发panic,错误信息为:panic: runtime error: invalid memory address or nil pointer dereference
相关代码如下:
type DBserver struct { protoc.UnimplementedUserManagementServer i.DBService } func NewDBserver(service i.DBService) *DBserver { return &DBserver{ DBService: service, } } func (ds *DBserver) Listen(address string) { lis, err := net.Listen("tcp", address) if err != nil { //TODO: log properly (main logger file) log.Fatalf("could not listen to tcp conn port :%s : %s", address, err) } ServerRegistrar := grpc.NewServer() protoc.RegisterUserManagementServer(ServerRegistrar, &DBserver{}) if err := ServerRegistrar.Serve(lis); err != nil { //TODO: log properly (main logger file) log.Fatalf("could not serve grpc :%s", err) } } func (ds *DBserver) SaveUser(ctx context.Context, u *protoc.User) (*protoc.DBresponse, error) { User := modals.User{ Fname: u.Fname, Mname: u.Mname, Lname: u.Lname, Username: u.Username, Password: u.Password, Contact: int(u.Contact), Email: u.Email, Sex: u.Sex, Role: int(u.Role), CreatedBy: u.CreatedBy, } log.Printf("calling DB to create user:\n %v", User) createdID, err := ds.DBService.Users("create", User) if err != nil { return &protoc.DBresponse{ Success: false, ID: "", }, err } return &protoc.DBresponse{ Success: true, ID: createdID, }, nil }
运行时错误栈:
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x7b89be] goroutine 9 [running]: github.com/tazafrosoul/school-system/db-manager/transport/grpc.(*DBserver).SaveUser(0xc000022bf0, {0xc0001ee0f0?, 0x4f2966?}, 0x0?) /home/taz/projects/go/src/github.com/tazafrosoul/school-system/db-manager/transport/grpc/dbserver.go:56 +0x11e github.com/tazafrosoul/school-system/common/grpc/protoc._UserManagement_SaveUser_Handler({0x8328e0?, 0xc000022bf0}, {0x947788, 0xc0001d6b70}, 0xc0001cc580, 0x0) /home/taz/projects/go/src/github.com/tazafrosoul/school-system/common/grpc/protoc/dbmgr_grpc.pb.go:79 +0x169 google.golang.org/grpc.(*Server).processUnaryRPC(0xc0001f8200, {0x947788, 0xc0001d6ae0}, {0x94a738, 0xc000228000}, 0xc0001b3200, 0xc0001d64e0, 0xc2c3c0, 0x0) /home/taz/go/pkg/mod/google.golang.org/grpc@v1.60.1/server.go:1372 +0xe03 google.golang.org/grpc.(*Server).handleStream(0xc0001f8200, {0x94a738, 0xc000228000}, 0xc0001b3200) /home/taz/go/pkg/mod/google.golang.org/grpc@v1.60.1/server.go:1783 +0xfec google.golang.org/grpc.(*Server).serveStreams.func2.1() /home/taz/go/pkg/mod/google.golang.org/grpc@v1.60.1/server.go:1016 +0x59 created by google.golang.org/grpc.(*Server).serveStreams.func2 in goroutine 8 /home/taz/go/pkg/mod/google.golang.org/grpc@v1.60.1/server.go:1027 +0x115 exit status 2
移除第56行createdID, err := ds.DBService.Users("create", User)并模拟变量后,代码可正常运行,需排查问题原因。
问题原因
问题出在Listen方法的服务注册环节:
protoc.RegisterUserManagementServer(ServerRegistrar, &DBserver{})
这里直接新建了一个空的DBserver实例,没有初始化它的DBService字段——而你通过NewDBserver方法创建的、已经正确注入DBService的实例根本没被用到。
当gRPC请求触发SaveUser方法时,当前实例的ds.DBService是nil,调用ds.DBService.Users自然会触发nil指针解引用panic。
修复方案
修改Listen方法,使用当前DBserver实例(即方法接收者ds)来注册服务,而不是新建空实例:
func (ds *DBserver) Listen(address string) { lis, err := net.Listen("tcp", address) if err != nil { log.Fatalf("could not listen to tcp conn port :%s : %s", address, err) } ServerRegistrar := grpc.NewServer() // 使用已初始化DBService的当前实例ds protoc.RegisterUserManagementServer(ServerRegistrar, ds) if err := ServerRegistrar.Serve(lis); err != nil { log.Fatalf("could not serve grpc :%s", err) } }
这样注册的服务实例已经通过NewDBserver注入了有效的DBService,调用SaveUser时就不会出现nil指针问题了。
内容的提问来源于stack exchange,提问作者TaZ AfroSoul
相关产品推荐
相关产品推荐

