【GO-Micro】micro 重试机制

本贴最后更新于 2127 天前,其中的信息可能已经斗转星移

github 完整代码地址 https://github.com/Allenxuxu/microservices

在分布式系统中,经常会有服务出现故障,所以良好的重试机制可以大大的提高系统的可用性。本文主要分析 micro 的客户端重试机制,以及实例演示。

micro 重试实现

micro 框架提供方法设置客户端重试的次数。

Client.Init( client.Retries(3), )

当 client 请求失败时,客户端会根据 selector 的策略选择下一个节点重试请求。这样当一个服务实例故障时,客户端可以自动调用另一个实例。

我们来看看 micro 客户端内部重试的实现:

go-micro\client\rpc_client.go

func (r *rpcClient) Call(ctx context.Context, request Request, response interface{}, opts ...CallOption) error { ... //客户端call 调用函数, 在下面的循环中调用 call := func(i int) error { // call backoff first. Someone may want an initial start delay t, err := callOpts.Backoff(ctx, request, i) if err != nil { return errors.InternalServerError("go.micro.client", "backoff error: %v", err.Error()) } // only sleep if greater than 0 if t.Seconds() > 0 { time.Sleep(t) } // 根据selector策略 选出 下一个节点 node, err := next() if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.client", "service %s: %v", request.Service(), err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.client", "error getting next %s node: %v", request.Service(), err.Error()) } // 客户端调用 err = rcall(ctx, node, request, response, callOpts) r.opts.Selector.Mark(request.Service(), node, err) return err } ch := make(chan error, callOpts.Retries+1) var gerr error //根据设定的**Retries**(重试次数)循环调用 call,如果执行成功,调用超时或者设置的**Retry**函数执行出错则直接退出,不继续重试 for i := 0; i <= callOpts.Retries; i++ { go func(i int) { ch <- call(i) }(i) select { case <-ctx.Done(): //超时 return errors.Timeout("go.micro.client", fmt.Sprintf("call timeout: %v", ctx.Err())) case err := <-ch: // if the call succeeded lets bail early if err == nil { //调用成功 return nil } retry, rerr := callOpts.Retry(ctx, request, i, err) if rerr != nil { return rerr } if !retry { return err } gerr = err } } return gerr }

micro 将选举下一个节点,RPC 调用封装到一个匿名函数中,然后根据设定的重试次数循环调用。如果调用成功或者超时则直接返回,不继续重试。其中,当 callOpts 里设定的 Retry 函数执行失败,即第一个返回值为 false,或者第二个返回值为 err 不会 nil 时,也会退出循环直接返回。

我们来看下 Retry 是什么:

type CallOptions struct { Retry RetryFunc }

client 的 CallOptions 中定义了 Retry,我们跳转到 RetryFunc

go-micro\client\retry.go

// note that returning either false or a non-nil error will result in the call not being retried type RetryFunc func(ctx context.Context, req Request, retryCount int, err error) (bool, error) // RetryAlways always retry on error func RetryAlways(ctx context.Context, req Request, retryCount int, err error) (bool, error) { return true, nil } // RetryOnError retries a request on a 500 or timeout error func RetryOnError(ctx context.Context, req Request, retryCount int, err error) (bool, error) { if err == nil { return false, nil } e := errors.Parse(err.Error()) if e == nil { return false, nil } switch e.Code { // retry on timeout or internal server error case 408, 500: return true, nil default: return false, nil } }

从中我们可以发现,作者预实现了两个 Retry 函数:RetryAlwaysRetryOnError
RetryAlways 直接返回 true, nil,即不退出重试。
RetryOnError 只有当 e.Code(上一次 RPC 调用结果)为 408 或者 500 时才会返回 true, nil,继续重试。
micro 的默认 RetryRetryOnError,但是我们可以自定义并设置,下面的实验中将会演示。

DefaultRetry = RetryOnError // DefaultRetries is the default number of times a request is tried DefaultRetries = 1 // DefaultRequestTimeout is the default request timeout DefaultRequestTimeout = time.Second * 5

实验

当客户端请求另一个服务时,如果被请求的服务突然挂了,而此时客户端依旧会去请求,重试时客户端会请求另一个实例(有一定几率还会请求同一个实例,因为默认的负载均衡策略是哈希随机)。

我们修改 api/user 下的服务,在 main 函数中设置客户端重试。

sClient := hystrixplugin.NewClientWrapper()(service.Options().Service.Client()) sClient.Init( client.WrapCall(ocplugin.NewCallWrapper(t)), client.Retries(3), client.Retry(func(ctx context.Context, req client.Request, retryCount int, err error) (bool, error) { log.Log(req.Method(), retryCount, " client retry") return true, nil }), )

然后,我们依次启动 micro 网关,user API 服务,hello SRV 服务(启动两个实例)。

cd micro && make run cd api/user && make run cd srv/hello && make run cd srv/hello && make run

我们通过 kill -9 杀死其中一个 hello 服务,然后通过 postman 请求 GET 172.0.0.1:8080/user/test

[GIN] 2019/05/14 - 14:52:20 | 200 | 1.253576ms | 127.0.0.1 | GET /user/test 2019/05/14 14:52:48 Received Say.Anything API request 2019/05/14 14:52:48 0x19a1680 0 retry func 2019/05/14 14:52:48 msg:"Hello xuxu" [GIN] 2019/05/14 - 14:52:48 | 200 | 13.821193ms | 127.0.0.1 | GET /user/test

通过 usr API 服务的输出,我们可以看到重试一次后,客户端成功请求了另一个实例。

github 完整代码地址 https://github.com/Allenxuxu/microservices

  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 251 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone

    如果故障是由于超时引起的,产生请求多次的情况怎么处理比较好

  • someone

    Go micro 微服务实战 QQ 群 184572648 可以来一起交流 go micro 心得

  • someone
    作者

    可以配置熔断的,如果一定时间内请求多次失败,直接将这个实例熔断了。

推荐标签 标签

  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 31 关注
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    289 引用 • 4492 回帖 • 653 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 532 关注
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 7 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 248 关注
  • V2Ray
    1 引用 • 15 回帖
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖
  • Outlook
    1 引用 • 5 回帖 • 2 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 643 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 85 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 9 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    70 引用 • 193 回帖 • 412 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖 • 2 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    210 引用 • 2040 回帖
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    6 引用 • 26 回帖 • 544 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 2 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 702 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 9 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    227 引用 • 476 回帖
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 666 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    335 引用 • 324 回帖
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 653 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖 • 1 关注