Go 语言中的超时处理

最近在项目里用 Go 语言对一些微服务进行重构,由于 Go 对我来说仍然算是一种新语言,因此在项目过程中碰到的一些比较不同一些写法,将会以 Tips 的方式记录在这里。今天想记录的是 Go 语言里的超时处理。

超时在一些业务场景里非常普遍,例如:

– 数据库访问操作,进行网络连接时通常都有超时时间。
– 本地客户端用阻塞方式异步访问远程,等待一段时间之后,如果远程没有返回结果,则认为超时。
– 微服务在启动时,需要初始化某些数据,例如等待服务注册表返回的总线密码等等,如果在规定的时间内未获得需要的内容,则认为超时,服务启动失败。

在 Java 等传统语言里,通常会首先记录当前时间,然后使用一个无限循环进行资源等待检查,如果需要等待的资源无法获取到,则将当前线程休眠一段时间,当休眠恢复后检查时间是否超过规定时间,如果超时则抛出异常,否则继续进入循环进行等待。用伪代码表述如下:


long startTime = Time.currentTimeMillis();
long EXPIRE = 1000*30; // 30 seconds to expire

while (true) {
    resource = getResourceFromRemote();
    if (resource == null) {
        Thread.sleep(1000); // Sleep 1 second
    }

    long currentTime = Time.currentTimeMillis();
    if (currentTime - startTime > EXPIRE)
        throw new RuntimeException("Expired to get remote resource");
    }

上述 Java 实现中,需要手工处理超时时间以及线程休眠等等,看上去也是非常的清晰,但是在 Go 语言的版本里,整个过程会显得更加简洁:


for resource := getResourceFromRemote(); resource == nil {
    select {
        case <-time.After(time.Second * 30):
            panic("Unable to receive resource within 30 seconds.")
        default:
            logs.Info("Resource is not received, waiting for 1 seconds...")
            time.Sleep(time.Second) // Wait for 1s until the resource is received.
    }
}

首先也是进入一个循环,循环条件是可以获取需要的资源,在循环内部使用 select 语句试图从 case 语句指定的通道里读取数据,如果无法读取到数据则进入下一个 case, <- time.After(time.Second * 30) 表示在 30 秒之后从通道内返回数据,在未到达规定的时间执行 ‘default’ 语句并且使用 time.Sleep(time.Second) 休眠 1 秒。

在这个 Go 语言的版本里,虽然看上去代码更加简洁,更多是利用 Go 语言本身的的一些特性,而不是过多依赖于函数库,这体现了 Go 语言设计时将一些互联网时代常用的功能变成语言本身的实用主义特点。

56 次阅读

新项目

八月底一位资深的同事离职,他手上的一个新项目交给我来带,简单的交接后同事就离职了。九月初开始上手这个项目,由于这个项目实际上是后台从老项目迁移,前端重新开发,其中使用到的技术基于微服务架构非常繁杂,简单列举一下:

后端:

  • 开发语言:Golang, Ruby, Shell
  • 开发框架:Sinatra (Ruby), Beego (Go)

前端:

  • 开发语言:Javascript (ES6)
  • 开发框架:React, Redux, Saga
  • 编译工具:Babel
  • 打包工具:Webpack
  • 包管理器:npm

基础架构部分:

  • 服务发现:etcd
  • 缓存:Redis, Memcached
  • 消息中间件:Redis
  • 容器技术:Docker
  • 容器编排:Kubernates
  • 容器安装:Helm
  • 数据库:Mongo

作为架构师我需要熟悉这一系列的技术,重新梳理架构,了解旧代码。吾生也有涯,而代码无涯,之后整个九月都很痛苦,到目前为止也仍然在不停学习中。由于项目时间紧,任务重,从一开始只有两个人,到目前增加了到将近六个人的小团队,仍然都在加班赶工。我自己有很长时间的Java技术背景,做过解决方案架构,又专门去学了项目管理,比较看重用户体验和项目组的氛围,接手这样一个项目之后渐渐会有些感觉不吐不快。政治上的槽点就不宜多说,单说技术和项目管理方面:

  • 这个项目有很多代码是从旧项目迁移过来的,一份代码被若干人改过,风格迥异。
  • 注释偏少(程序员的通病?),搭配一些奇葩的变量命名方式,让人抓狂。
  • 架构的文档少。
  • 接口更是没有文档,有时想调用某个接口,往往需要去直接看代码。
  • 代码日志输出不规范,后端代码调试困难。
  • 一些配置,例如IP地址, 被写死在代码里,直到碰到错误时才发现。

这些都是我们后面需要逐步去改进梳理的,有时在繁忙的工作之余,我会仔细思考一些问题:为什么我们越来越不快乐了,我们曾经是那么喜欢技术本身带来挑战和成就感?把时间耗费在修复前人因为种种原因而犯下的错误是不是对自己生命的浪费?作为对职业的尊重和责任,我常常感到非常无奈,这也许便是成长的烦恼。对于这个项目相关技术现象的几点看法,或许能解释一点点上述困惑,欢迎大家探讨:

  • 前端开发真的是日新月异,像 React 这样的技术虽然克服了传统前端开发的一些性能问题,但是缺少开发工具的支持,开发效率上未见得到实质的提升。现代前端开发我们实际上看到已经形成了一个非常深的技术栈:从开发语言,框架到打包工具等等。这使得前端开发的学习成本越来越高,这大概也是前端开发现在细分成一些专门的职位方向的原因。
  • 过分追求新技术,异构技术对于团队来说不是好事。从技术栈可以看到,我们使用到的语言,框架,基础软件是不少的,这大大地增加了团队,特别是一些新手的学习负担。在我看来,技术够用就好,最关键的还是能够满足需求,只有当一样技术无法满足需求时,再去考虑更新的方案。很多开源框架演进非常快,意味着一定的不稳定性,做技术跟踪也需要大量的时间。
  • 微服务治理是个很大,但是很现实的话题。虽然在为服务架构中,服务注册和服务发现已经有现成的软件去解决,但是仍然不够。服务之间的互相调用仍然是彼此交织在一起,分布在各种代码逻辑里,编织成错综复杂的调用网络,维护起来十分困难。
  • 产业界仍然有很浮躁的气象,虽然重复造轮子的事情少了,但是凡事都想拿来主义,比如原来可以用单一技术将一件事情做到极致,现在却多使用各种开源代码攒成一件成品,就好比苹果电脑和 DIY PC 一样,后者自然是很难做出精品的。

 

714 次阅读

人生需要做减法

从业多年,养成了随手将所需要的资料存下来以备不时之需的习惯,久而久之电脑上文件、邮件,以及浏览器的收藏夹就越来越庞大。虽然我也有经常整理文件的习惯,但面对成百上千的文件时,仍然倍感焦虑。文件太多,有时急需要查找一个需要的文件时却往往无法查找,而大多数文件其实大多数时间时使用一次就可能被尘封遗忘。周末终于下决心按下 Reset 键,改变一下这种混乱状态,于是花了一天的时间将工作用的电脑重装了一遍,首先将所有文件备份,然后工作电脑上只保存必须的文件。顿时感觉干净和清爽起来。

我想电脑中的文件时间久了需要整理,我们的人生更时如此需要多做减法。特别是在这庸庸扰扰的当代社会,我们内心充斥着大量的欲望,又有多少人可以记得自己内心深处的声音,自己的人生目标时什么,我们自己的初心是什么。脑袋里过多的杂念也应该及时清理,只留下和自己人生目标所相配的代办事项,生活中过多的杂物,太久就扔掉或者送人吧。少就是多,看似少了,但最重要的事项所获得的时间却多了,我们离真实的自己又进一步。唯有如此,我们才能放下包袱,轻装前行,始终专注于生命中最重要的、最值得做的事情。当下流行的极简生活,就是这个原理。

这里分享一个邮件处理的小技巧,常用的邮件客户端都有基于规则的邮件过滤,根据一定的规则可以将邮件自动分配到不同的文件夹当中。对于一些订阅的邮件,例如周报之类的就可以采取这种方法自动归档到“周报”文件夹中。除此之外,就不建议使用太多的自动分类目录了。可以继续添加一个规则:将直接发送给“我”的邮件(我会把它们留在“收件箱”里),和抄送给“我”的邮件分别过滤到不同的目录中。因为,直接发送给“我”的邮件通常意味着较高的优先级,而抄送给“我”的邮件则可能优先级较低,重要的事情先行,可以有效降低焦虑感。但同时,这些在“发送”和“抄送”中都出现了“我”的邮件,往往时需要我们花时间去看的,所以这两个“发送给我的邮件”和“抄送邮件”都需要手工处理,看完之后立即将邮件分类到不同的邮件目录中存档。处理邮件的结构如下:


+ 收件箱 (应用规则:收件人中出现“我”的邮件地址,手工归档)
+ 抄送邮件(应用规则:抄送栏中出现“我”的邮件地址,手工归档)
+ 周报 (应用规则:标题出现“周报”,自动归档)
+ 归档
+-- 项目1(归档邮件)
+-- 项目2(归档邮件)

这样,每天只需要关注“收件箱”,“抄送邮件”,“周报”等目录中的新邮件即可,每天处理邮件的时间和工作量就变得可控了,处理邮件的焦虑感也明显减轻。

621 次阅读