1。简介本文使用go-micro搭建微服务的服务端和客户端,使用gin集成客户端搭建HTTPApi,在代码中模拟客户端RPC调用服务端方法返回408的问题,以及如何解决它?客户端输出日志:{"id":"go.micro.client","code":408,"detail":"contextdeadlineexceeded","status":"RequestTimeout"}2.使用go-micro构建关于proto和consul的server和client相关内容不是本文的重点,不再赘述。有兴趣的读者可以参考公众号的历史文章。创建服务器服务的代码:funcmain(){registry:=consul.NewRegistry(func(options*registry.Options){options.Addrs=[]string{"127.0.0.1:8500"}options.Timeout=5*time.Second})//创建一个新服务service:=grpc.NewService(micro.Name("go.micro.srv.user"),micro.Registry(registry),)//处理程序user.RegisterUserHandler(service.Server(),new(user_handler.User))//初始化标志service.Init()//启动服务service.Run()}Servermethod:typeUserstruct{}func(u*User)Login(ctxcontext.Context,req*user.LoginRequest,rsp*user.LoginResponse)error{time.Sleep(10*time.Second)//模拟超时响应rsp.Username="Welcome"+req.Emailreturnnil}客户端代码:funcmain(){r:=NewRouter()server:=&http.Server{Addr:":8080",Handler:r,ReadTimeout:time.Second*20,WriteTimeout:time.Second*20,MaxHeaderBytes:1<<20,}如果错误:=server.ListenAndServe();err!=nil{log.Fatal(err)}}//省略User.Login相关代码funcNewRouter()*gin.Engine{r:=gin.New()userHandler:=new(User)r.GET("/login",userHandler.Login)returnr}funcNewClient()user.UserService{registry:=consul.NewRegistry(func(options*registry.Options){options.Addrs=[]string{"127.0.0.1:8500"}options.Timeout=5*time.Second})client:=grpc.NewClient(client.DialTimeout(15*time.Second),client.RequestTimeout(15*time.Second),client.Registry(registry),)userClient:=user.NewUserService("go.micro.srv.user",client)returnuserClient}分别启动服务端和客户端,然后使用curl请求Api:?/Users/frankcurlhttp://127.0.0.1:8080/login{"data":"Welcomegopher@88.com"}%阅读以上内容运行结果,可以发现我们搭建的server和client运行正常3.模拟返回408的问题我们在server的方法中使用time.Sleep(10*time.Second)来模拟扩展响应时间。我们修改客户端代码,设置客户端超时时间也设置为10s。修改客户端代码:client.DialTimeout(10*time.Second),client.RequestTimeout(10*time.Second),阅读以上代码,我们将客户端超时时间改为10s,然后重启客户端应用,使用curlrequestsApi:/Users/frankcurlhttp://127.0.0.1:8080/login运行curl,没有返回响应结果。我们查看客户端的日志,发现:{"id":"go.micro.client","code":408,"detail":"contextdeadlineexceeded","status":"RequestTimeout"}原因就是在server方法中,我们在代码中使用time.Sleep(10*time.Second)来模拟响应需要10s,而在client中,我们定义的clienttimeout由原来的15s改为10s,导致返回408的问题。需要注意的是go-micro中客户端默认的超时时间是5s。4.解决方案在我们了解了问题的原因之后,聪明的读者朋友们可能已经有了解决问题的办法。要解决这个问题,有两种解决方案。第一个是修改客户端的超时时间,将超时时间延长到能够收到响应结果的时间。但是需要注意的是,http服务器的读写时间还必须能够收到响应结果的持续时间,本文我们设置为20s,如下:server:=&http.Server{Addr:":8080",Handler:r,ReadTimeout:time.Second*20,WriteTimeout:time.Second*20,MaxHeaderBytes:1<<20,}并且还需要注意其上下游服务之间的超时时间避免雪崩等问题。二是优化服务端方法的响应时间,将其响应时间缩短到客户端的超时时间内。具体怎么优化,要看实际情况,比如是不是读写数据库的时间太长,或者代码的时间复杂度太高。5.小结本文介绍如何解决客户端RPC调用服务端时返回错误码408的问题。我们使用go-micro和gin搭建示例代码,通过修改示例代码来分析408错误码的原因。.当读者遇到这个问题时,建议先使用第二种方法解决。如果使用第一种方式,需要特别注意避免分布式系统的雪崩问题。
