此外,对于获取历史数据接口,从原先的循环读取多个 key 的数据,优化为从数据库并发读取各个 key 的数据。经过这些优化之后,服务的高峰 PCT99 从100ms降低到15ms。 上述是一个比较典型的 Go 语言服务优化案例。概括为两点: 从业务层面上提高并发 减少内存和对象的使用 优化的过程中使用了 pprof 工具发现性能瓶颈点,然后发现“io.Reader”接口具备的 Pipeline 的数据处理方式,进而整体优化了整个服务的性能。 服务监控 Go 语言的 runtime 包提供了多个接口供开发者获取当前进程运行的状态。在 kite 框架中集成了协程数量,协程状态,GC 停顿时间,GC 频率,堆栈内存使用量等监控。实时采集每个当前正在运行的服务的这些指标,分别针对各项指标设置报警阈值,例如针对协程数量和 GC 停顿时间。另一方面,我们也在尝试做一些运行时服务的堆栈和运行状态的快照,方便追查一些无法复现的进程重启的情况。 编程思维和工程性 相对于传统 Web 编程语言,Go 在编程思维上的确带来了许多的改变。每一个 Go 开发服务都是一个独立的进程,任何一个请求处理造成 Panic,都会让整个进程退出,因此当启动一个协程的时候需要考虑是否需要使用 recover 方法,避免影响其它协程。对于 Web 服务端开发,往往希望将一个请求处理的整个过程能够串起来,这就非常依赖于 Thread Local 的变量,而在 Go 语言中并没有这个概念,因此需要在函数调用的时候传递 context。 最后,使用 Go 开发的项目中,并发是一种常态,因此就需要格外注意对共享资源的访问,临界区代码逻辑的处理,会增加更多的心智负担。这些编程思维上的差异,对于习惯了传统 Web 后端开发的开发者,需要一个转变的过程。 关于工程性,也是 Go 语言不太所被提起的点。实际上在 Go 官方网站关于为什么要开发 Go 语言里面就提到,目前大多数语言当代码量变得巨大之后,对代码本身的管理以及依赖分析变得异常苦难,因此代码本身成为了最麻烦的点,很多庞大的项目到最后都变得不敢去动它。而 Go 语言不同,其本身设计语法简单,类C的风格,做一件事情不会有很多种方法,甚至一些代码风格都被定义到 Go 编译器的要求之内。而且,Go 语言标准库自带了源代码的分析包,可以方便地将一个项目的代码转换成一颗 AST 树。 下面以一张图形象地表达下 Go 语言的工程性: 同样是拼成一个正方形,Go 只有一种方式,每个单元都是一致。而 Python 拼接的方式可能可以多种多样。 写在最后 今日头条使用 Go 语言构建了大规模的微服务架构,本文结合 Go 语言特性着重讲解了并发,超时控制,性能等在构建微服务中的实践。事实上,Go 语言不仅在服务性能上表现卓越,而且非常适合容器化部署,我们很大一部分服务已经运行于内部的私有云平台。结合微服务相关组件,我们正朝着 Cloud Native 架构演进。 更多技术实践内容可以关注今日头条技术博客:techblog.toutiao.com 作者介绍 项超,今日头条高级研发工程师。2015年加入今日头条,负责服务化改造相关工作,在内部推广Go语言的使用,研发内部微服务框架kite,集成服务治理,负载均衡等多种微服务功能,实现了Go语言构建大规模微服务架构在头条的落地。曾就职于小米。 今日荐文
Google、亚马逊、微软 、阿里巴巴开源软件一览 (责任编辑:本港台直播) |