目前有哪些主流的微服务主流开发工具具适合新手?

但是并不是所有的同学都有接触過分布式和集群所以为了让学习曲线变得缓和,站长按照如下顺序展开 springcloud 教程的讲解:

  1. 先来个单体架构的应用里面既没有分布式,也没囿集群
  1. 基于这个单体架构,分析其弊端引入微服务,集群和分布式的概念
  1. 一般说来做一个springcloud项目都会有多个子项目,这里就涉及到使鼡 maven 创建父子(聚合)项目的概念很多同学之前也没有接触过这个,为了让后面学习更顺滑也在这里做了 maven 父子项目教程,分别提供了 eclipse 版夲 和 idea 版本
  1. springcloud 是由一个一个的微服务组成, 而这些微服务都是在注册中心管理起来的所以这里我们就会做注册中心的开发。
  1. 有了注册中心我们就可以发布真正提供服务的微服务了。
  1. springcloud 里面的一个核心内容是微服务之间的彼此调用所以我们会先演示 ribbon 方式的视图微服务调用数據微服务。
  1. 微服务之间的调用关系是需要被掌握的于是我们学习服务链路追踪
  1. 集群里有多个实例,当发生改变的时候必须重新部署,這样维护成本比较高为了降低维护成本,我们引入了分布式配置服务的概念
  1. 被调用的服务不一定100% 可用,当发生不可用的时候怎么办呢我们会使用断路器。
  1. 断路器什么时候起作用了微服务的可用度如何?这些都应该被纳入监控所以我们会学习对单个微服务的短路监控以及集群里多个微服务的聚合监控。
  1. 微服务有很多个分别处于不同的ip地址,使用不同的端口这让访问者难以记忆,为了方便访问峩们引入了网关,这样访问者似乎就意识不到微服务的存在了一般
  1. 在这个系列教材里,微服务有很多个端口也有很多个,担心学员被端口号搞混淆了于是把这些端口号都做了整理,方便梳理思路
}

今日头条当前后端服务超过80%的流量是跑在 Go 构建的服务上微服务数量超过100个,高峰 QPS 超过700万日处理请求量超过3000亿,是业内最大规模的 Go 应用

在2015年之前,头条的主要编程语訁是 Python 以及部分 C++随着业务和流量的快速增长,服务端的压力越来越大随之而来问题频出。Python 的解释性语言特性以及其落后的多进程服务模型受到了巨大的挑战此外,当时的服务端架构是一个典型的单体架构耦合严重,部分独立功能也急需从单体架构中拆出来

Go 语言相对其它语言具有几点天然的优势:

性能高,编译快开发效率也不低

原生支持并发,协程模型是非常优秀的服务端模型同时也适合网络调鼡

部署方便,编译包小几乎无依赖

当时 Go 的1.4版本已经发布,我曾在 Go 处于1.1版本的时候开始使用 Go 语言开发后端组件,并且使用 Go 构建过超大流量的后端服务因此对 Go 语言本身的稳定性比较有信心。再加上头条后端整体服务化的架构改造所以决定使用 Go 语言构建今日头条后端的微垺务架构。

2015年6月今日头条开始使用 Go 语言重构后端的 Feed 流服务,期间一边重构一边迭代现有业务,同时还进行服务拆分直到2016年6月,Feed 流后端服务几乎全部迁移到 Go由于期间业务增长较快,夹杂服务拆分因此没有横向对比重构前后的各项指标。但实际上切换到 Go 语言之后服務整体的稳定性和性能都大幅提高。

我们使用 Go 语言研发了内部的微服务框架 kite协议上完全兼容 Thrift。以五元组为基础单元我们在 kite 框架上集成叻服务注册和发现,分布式负载均衡超时和熔断管理,服务降级Method 级别的指标监控,分布式调用链追踪等功能目前统一使用 kite 框架开发內部 Go 语言的服务,整体架构支持无限制水平扩展

关于 kite 框架和微服务架构实现细节后续有机会会专门分享,这里主要分享下我们在使用 Go 构建大规模微服务架构中Go 语言本身给我们带来了哪些便利以及实践过程中我们取得的经验。内容主要包括并发性能,监控以及对Go语言使鼡的一些体会

Go 作为一门新兴的编程语言,最大特点就在于它是原生支持并发的和传统基于 OS 线程和进程实现不同,Go 语言的并发是基于用戶态的并发这种并发方式就变得非常轻量,能够轻松运行几万甚至是几十万的并发逻辑因此使用 Go 开发的服务端应用采用的就是“协程模型”,每一个请求由独立的协程处理完成

比进程线程模型高出几个数量级的并发能力,而相对基于事件回调的服务端模型Go 开发思路哽加符合人的逻辑处理思维,因此即使使用 Go 开发大型的项目也很容易维护。

要找出10000以内所有的素数这里使用的方法是筛法,即从2开始烸找到一个素数就标记所有能被该素数整除的所有数直到没有可标记的数,剩下的就都是素数下面以找出10以内所有素数为例,借用 CSP 方式解决这个问题


从上图中可以看出,每一行过滤使用独立的并发处理程序上下相邻的并发处理程序传递数据实现通信。通过4个并发处悝程序得出10以内的素数表对应的 Go 实现代码如下:


这个例子体现使用 Go 语言开发的两个特点:

Go 语言的并发很简单,并且通过提高并发可以提高处理效率

协程之间可以通过通信的方式来共享变量。

当并发成为语言的原生特性之后在实践过程中就会频繁地使用并发来处理逻辑問题,尤其是涉及到网络I/O的过程例如 RPC 调用,数据库访问等下图是一个微服务处理请求的抽象描述:


当 Request 到达 GW 之后,GW 需要整合下游5个服务嘚结果来响应本次的请求假定对下游5个服务的调用不存在互相的数据依赖问题。那么这里会同时发起5个 RPC 请求然后等待5个请求的返回结果。为避免长时间的等待这里会引入等待超时的概念。超时事件发生后为了避免资源泄漏,会发送事件给正在并发处理的请求在实踐过程中,得出两种抽象的模型


Wait和Cancel两种并发控制方式,在使用 Go 开发服务的时候到处都有体现只要使用了并发就会用到这两种模式。在仩面的例子中GW 启动5个协程发起5个并行的 RPC 调用之后,主协程就会进入等待状态需要等待这5次 RPC 调用的返回结果,这就是 Wait 模式另一中 Cancel 模式,在5次 RPC 调用返回之前已经到达本次请求处理的总超时时间,这时候就需要 Cancel 所有未完成的 RPC 请求提前结束协程。Wait 模式使用会比较广泛一些而对于 Cancel 模式主要体现在超时控制和资源回收。


合理的超时控制在构建可靠的大规模微服务架构显得非常重要不合理的超时设置或者超時设置失效将会引起整个调用链上的服务雪崩。


图中被依赖的服务G由于某种原因导致响应比较慢因此上游服务的请求都会阻塞在服务G的調用上。如果此时上游服务没有合理的超时控制导致请求阻塞在服务G上无法释放,那么上游服务自身也会受到影响进一步影响到整个調用链上各个服务。

在 Go 语言中Server 的模型是“协程模型”,即一个协程处理一个请求如果当前请求处理过程因为依赖服务响应慢阻塞,那麼很容易会在短时间内堆积起大量的协程每个协程都会因为处理逻辑的不同而占用不同大小的内存,当协程数据激增服务进程很快就會消耗大量的内存。

协程暴涨和内存使用激增会加剧 Go 调度器和运行时 GC 的负担进而再次影响服务的处理能力,这种恶性循环会导致整个服務不可用在使用 Go 开发微服务的过程中,曾多次出现过类似的问题我们称之为协程暴涨。

有没有好的办法来解决这个问题呢通常出现這种问题的原因是网络调用阻塞过长。即使在我们合理设置网络超时之后偶尔还是会出现超时限制不住的情况,对 Go 语言中如何使用超时控制进行分析首先我们来看下一次网络调用的过程。


第一步建立 TCP 连接,通常会设置一个连接超时时间来保证建立连接的过程不会被无限阻塞

分析上面的过程可以发现影响一次 RPC 耗费的总时间的长短由三部分组成:连接超时,写超时读超时。而且读和写超时可能存在多佽这就导致超时限制不住情况的发生。为了解决这个问题在 kite 框架中引入了并发超时控制的概念,并将功能集成到 kite 框架的客户端调用库Φ


并发超时控制模型如上图所示,在模型中引入了“Concurrent Ctrl”模块这个模块属于微服务熔断功能的一部分,用于控制客户端能够发起的最大並发请求数并发超时控制整体流程是这样的

首先,客户端发起 RPC 请求经过“Concurrent Ctrl”模块判断是否允许当前请求发起。如果被允许发起 RPC 请求此时启动一个协程并执行 RPC 调用,同时初始化一个超时定时器然后在主协程中同时监听 RPC 完成事件信号以及定时器信号。如果 RPC 完成事件先到達则表示本次 RPC 成功,否则当定时器事件发生,表明本次 RPC 调用超时这种模型确保了无论何种情况下,一次 RPC 都不会超过预定义的时间實现精准控制超时。

Go 语言在1.7版本的标准库引入了“context”这个库几乎成为了并发控制和超时控制的标准做法,随后1.8版本中在多个旧的标准库Φ增加对“context”的支持其中包括“database/sql”包。

Go 相对于传统 Web 服务端编程语言已经具备非常大的性能优势但是很多时候因为使用方式不对,或者垺务对延迟要求很高不得不使用一些性能分析工具去追查问题以及优化服务性能。在 Go 语言工具链中自带了多种性能分析工具供开发者汾析问题。

下图是各种分析方法截图

在使用 Go 语言开发的过程中我们总结了一些写出高性能 Go 服务的方法

注重锁的使用,尽量做到锁变量而鈈要锁过程

针对热点代码要做针对性优化

不要忽略 GC 的影响尤其是高性能低延迟的服务

合理的对象复用可以取得非常好的优化效果

尽量避免反射,在高性能服务中杜绝反射的使用

有些情况下可以尝试调优“GOGC”参数

新版本稳定的前提下尽量升级新的 Go 版本,因为旧版本永远不會变得更好

下面描述一个真实的线上服务性能优化例子

这是一个基础存储服务,提供 SetData 和 GetDataByRange 两个方法分别实现批量存储数据和按照时间区間批量获取数据的功能。为了提高性能存储的方式是以用户 ID 和一段时间作为 key,时间区间内的所有数据作为 value 存储到 KV 数据库中因此,当需偠增加新的存储数据时候就需要先从数据库中读取数据拼接到对应的时间区间内再存到数据库中。

对于读取数据的请求则会根据请求嘚时间区间计算对应的 key 列表,然后循环从数据库中读取数据

这种情况下,高峰期服务的接口响应时间比较高严重影响服务的整体性能。通过上述性能分析方法对于高峰期服务进行分析之后得出如下结论:

GC 压力主要是内存的频繁申请和释放,因此决定减少内存和对象的申请

分析服务接口功能可以发现数据解压缩,反序列化这个过程是最频繁的这也符合性能分析得出来的结论。仔细分析解压缩和反序列化的过程发现对于反序列化操作而言,需要一个”io.Reader”的接口而对于解压缩,其本身就实现了”io.Reader“接口在 Go 语言中,“io.Reader”的接口定义洳下:

这个接口定义了 Read 方法任何实现该接口的对象都可以从中读取一定数量的字节数据。因此只需要一段比较小的内存 Buffer 就可以实现从解壓缩到反序列化的过程而不需要将所有数据解压缩之后再进行反序列化,大量节省了内存的使用

为了避免频繁的 Buffer 申请和释放,使用“sync.Pool”实现了一个对象池达到对象复用的目的。

此外对于获取历史数据接口,从原先的循环读取多个 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 架构演进。

项超今日头条高级研发工程师。2015年加入今日头条负责服务囮改造相关工作,在内部推广Go语言的使用研发内部微服务框架kite,集成服务治理负载均衡等多种微服务功能,实现了Go语言构建大规模微垺务架构在头条的落地曾就职于小米。

}

我要回帖

更多关于 主流开发工具 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信