跳到主要内容

服务端开发

如何构造并启动 Kitex Server?​

  • WithServiceAddr: 设置监听地址; 不设置时默认监听 :8888;
  • WithServerBasicInfo: 声明服务身份; 注册中心、日志和链路标签都依赖它;
  • WithRegistry: 接入服务注册; 实例启动时注册、退出时注销;
  • WithMiddleware: 插入认证、日志、限流等横切逻辑; 注册顺序影响调用顺序;
  • WithExitWaitTime: 限制优雅退出等待时间; 要和编排平台终止窗口协调;
func main() {
svr := userservice.NewServer(
new(UserServiceImpl),
server.WithServiceAddr(&net.TCPAddr{Port: 8888}),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "user"}),
)
if err := svr.Run(); err != nil {
log.Fatalf("run user service: %v", err)
}
}

如何实现一次请求的 Handler?​

  • context.Context: 携带 deadline、取消信号、元信息和链路信息; 要向下传递,不要存到长期对象;
  • response: 每个请求构造独立对象; 不要复用可能被并发修改的响应;
  • error: 业务异常用 kerrors.NewBizStatusError 表达; 系统异常保留 error chain 交给框架层;
  • nil 检查: 生成代码通常保证 req 非空,但防御性检查成本低、收益高;
type UserServiceImpl struct{}

func (s *UserServiceImpl) GetUser(
ctx context.Context,
req *api.GetUserRequest,
) (*api.GetUserResponse, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
if req == nil || req.Id <= 0 {
return nil, kerrors.NewBizStatusError(400, "invalid user id")
}
name := "Ada"
return &api.GetUserResponse{Name: &name}, nil
}

如何管理 Server 持有的资源?​

  • 依赖组装: 数据库、注册中心与观测组件的启动顺序见 生产服务骨架;
  • 请求对象: 每次调用独占请求和响应;不要跨请求复用可变对象;
  • 异步信息: RPCInfo 的冻结与 panic 处理见 错误处理与生命周期;
  • 退出: 摘流、等待在途请求与释放外部依赖的顺序见 生命周期;