近万服务实例稳定运行0故障,携程微服务框架实践及思考

携程从.Net技术栈的时代就已经开始微服务领域的探索,转入Java技术栈之后,先是自研微服务框架,然后是高性能的Dubbo。目前我们正在Service Mesh的道路上探索,希望接下来能够实现微服务框架的全面标准化以及云原生。

一、过去(自研服务框架)

携程在.Net技术栈时代,开始是基于ESB总线,虽然解决了内网服务调用的治理问题,但是集中式的服务架构,经常会出现单个服务把整个总线拖垮,进而导致全网瘫痪的现象。基于注册中心的SOA服务架构,通过分布式的服务调用,解决了单点故障带来的巨大影响。

目前,携程主要是以Java技术栈为主,考虑到兼容历史.Net技术栈,现在的框架以自研为主,但是对比开源的高性能服务框架,自研的框架可能又存在下述提到的几个问题。

二、现在(CDubbo服务框架)

CDubbo名字里的C代表携程的治理,Dubbo代表阿里开源的Dubbo SDK。纵观过去两年的实践和探索,从2018年4月的第一个版本落地,到现在的近万服务实例,我们大致可以总结为下面的几个主要里程碑。

2.1 注册发现

注册发现是分布式服务框架的核心要素,为了支持现有的服务互通,所以需要接入携程的注册中心。

服务注册支持健康检测扩展机制,业务可以根据业务场景自定义健康检测扩展,例如当依赖的数据库不可用时不再对外提供服务。服务端通过5s一次的心跳保持服务的可用性,当连续N次没有发送心跳时就会自动通知客户端。

客户端发起对服务的订阅,通过推拉结合的模式,保证节点在客户端的最终一致性。通过Dubbo的扩展机制,实现了自定义的路由策略,比如根据方法名指定路由策略,以及根据请求参数决定不同的路由策略,同时也能够支持就近访问,优先访问本机房的服务。

2.2 监控-CAT

对微服务来说,没有了监控就好比瞎子一样,什么也不清楚。CAT提供了分布式链路追踪的能力,可以提供很好的报表,以及场景化的问题分析。

有时,需要了解服务总的请求量以及单机的请求分布和QPS,或者还要知道服务的执行耗时及99线。CAT的聚合报表可以帮助我们更好的了解服务的健康状况。

对于超时,可能需要知道哪个阶段变慢,客户端还是服务端,序列化阶段还是服务执行过程太慢。对于异常报错,可以看到哪个过程出现的异常,同时会打印异常堆栈信息,帮助问题的定位。

2.3 监控-Metrics

框架人员需要了解公司服务的宏观情况,比如各机房都有哪些服务,哪些服务使用了protobuf序列化格式,哪些服务使用了SOA协议等,以及平均执行耗时等情况。业务同事可能也想知道自己服务具体情况,比如有哪些调用方,线程池是否已经跑满了。

通过接入携程的Dashboard,可以提供全局的总量、错误量、线程池统计信息,也可以根据机房、协议、序列化格式等聚合数据。还能够自定义告警规则,在问题发生时能够尽早的介入。

2.4 动态配置

对业务同事来说,有可能会存在依赖的服务突然变慢导致客户端超时的情况。框架人员可能需要在机房故障时,需要全局调整check为false,以解决A B 服务循环依赖谁都无法启动的问题。动态配置提供了配置热生效的能力,不需要为了一个配置重新发布,成本很高。

服务端的多个方法,可能执行耗时也会有所不同,通过多级别的参数配置,可以设置服务默认超时为1s,单独为执行较慢的方法设置独立的超时时间为5s。

服务Owner可能更清楚自己服务的耗时,通过服务端对客户端的参数设置,不需要每个调用方都设置一次超时,设置的时间也会更合理一些。为了避免配置出错带来的损失,我们提供了友好的可视化界面。

2.5 SOA协议及互通

为了支持现有客户端迁移到CDubbo,需要考虑支持现有的SOA协议。除了要确保兼容HTTP 1.1协议不变,其次要保证跟客户端的序列化器一致。

CDubbo会通过Tomcat端口接收SOA协议的请求,利用现有的序列化器执行请求对象的转换,并保证Dubbo内部调用和Filter链路的一致性,确保业务逻辑的统一,也就是业务代码不需要改动,就可以启动两个协议。

2.6 测试平台

对于私有的二进制协议来说,没有现成的Postman等工具可以使用。有时,开发人员需要在本地验证测试环境的服务,也可能要验证本地启动的服务端,每个开发人员都构造一个客户端显得成本比较高。

通过VI(github开源叫coreStone),以及利用Dubbo 2.7.3提供的元数据中心和泛化调用能力,我们实现了类似postman的调用工具。不但可以支持直连,也能够支持本地测试,同时还可以支持protobuf序列化格式。关于protobuf序列化的测试方案,已经贡献到dubbo社区,感兴趣的同学可以自行了解。

2.7 升级Dubbo 2.7.3

关于Dubbo 2.7.3的详细升级历程,可以参考https://www.infoq.cn/article/kOxdaV3y9fMZ0Bzs0jb2

现在回顾下升级的最终结果如何。目前,携程99%的服务已经跑在dubbo 2.7.3之上,迄今为止0故障,只有一些不兼容的小问题,对于不兼容的问题也是确保了编译时提前暴露,运行时没有任何问题。

在发布后,也陆续的出现了一些小的问题,比如预热能力不生效,异常情况下不会回调onError等问题,支持服务端异步的Trace埋点等,这些问题已经在开源版本彻底修复了。

2.8 Threadless

业务同事反馈,需要把线程控制在理想的范围之内。但是,dubbo的线程数量太多,一方面是服务级独享线程池,当调用方依赖了10个服务,每个服务的QPS为1,lantency可能只有10ms的情况下,由于每个服务独立线程池,至少也需要10个线程了。如果多服务共享一个线程池,由于客户端默认是Cached的线程池模式,那么在这个场景下可能只要1个线程就足够了。另一方面,对同步服务来说,dubbo 2.7.5的threadless可以省去DubboClientHandler线程,Netty IO线程直接把响应交给业务线程,从而节省了一次线程切换。

通过实践,业务线程数量有了很大程度的下降,在高QPS以及依赖服务数量较多的情况下,甚至可以下降60-70%。

2.9 CDubbo服务体系

现有CDubbo的服务体系,同时支持Dubbo和SOA协议,对于Dubbo客户端能够支持TCP协议的传输,对于现有的SOA客户端,能够兼容现有的SOA协议。

同时,也能够支持内网和外网gateway的请求,保证了多协议的配置统一,以及兼容了SOA的序列化格式。

2.10 性能表现

从协议层面来看,Dubbo协议的响应较SOA协议有所提升,平均耗时从之前的1ms降低到了0.3ms左右,当然具体提升也要根据服务的报文及请求量有所差异。

可能有些人会觉得几毫秒的性能提升不足以挂齿,但是性能的稳定性对服务来说会很重要。我们观察了服务流量突增3-4倍的情况下,客户端还能保持0异常。长连接的多路复用,提供了很好的抗冲击能力。

2.11 扩展性

微服务框架跟业务代码耦合比较重,框架人员主要是用20%的时间解决业务80%的需求,另外20%的需求却需要80%时间的问题,更适合留给业务自己去解决,能够提供这个能力的唯有扩展性,dubbo无论横向和纵向的扩展能力都很好。

通过实践,发现业务的确在各个层级都有自己的扩展。例如:业务扩展了Router层,支持自己的路由规则,扩展了负载均衡策略,机票同事甚至扩展了Transport层换成了适合自己的传输协议。

2.12 生态

好的生态,可以降低开发成本,例如利用现有的开源dubbo admin,dubbo go等组件。另外,也可以降低业务的学习成本,在其他公司学习的dubbo框架,到了携程还可以接着用,不需要重新学习私有的服务框架。技术支持也比较少,很多业务同事对dubbo框架非常熟悉。

2.13 Dubbo协议存在的问题

除了前面提到的各种优点,经过实践发现现有的协议也存在着各种不足。除了对网关不太友好,没有移动端的SDK等问题。现有的扩展机制,在A和B服务都扩展了cluster AOP的情况下,可能会导致扩展的相互影响,如何能够保持扩展性又降低相互影响是值得探讨和解决的问题。

三、未来(Service Mesh)

网上关于Service Mesh的意义讲了很多,众说纷纭,个人认为可能最主要还是以下几点。

  • 标准化意味着更低的成本,比如研发成本低,学习成本也比较低,其他公司学习的微服务框架,到携程还可以继续用,省去了学习和踩坑的成本。
  • 进程解耦,框架同学可能比较感兴趣,中间件无法独立升级的问题一直困扰着框架研发同学,在这个问题上,envoy可以独立升级也是值得期待的。
  • 通过下沉,复用了云基础设施的一些能力,一方面,能够更好的支持多语言,业务根据自己的场景选择合适的语言,另一方面,通过下沉也能够让SDK更简单,减少Jar依赖的兼容性问题。
  • 因为更加标准以及下沉,能够带来更好的云部署能力,业务出海时可以根据实际情况部署需要的组件,不再依赖框架全家桶了。

3.1 Service Mesh SDK

下图是Istio官网提供的ServiceMesh架构图,如果说istio解决了控制平面的标准化,envoy或者sofa-mosn解决了数据平面的标准化,那么对于SDK来说,是否需要有个标准化的组件,或者是否存在适合我们的标准的SDK呢?

对于部分中小公司,没有自己的中间件团队,可能会选择付费版的sofa。但是,对于携程这样的规模,对扩展性要求很强,同时已经存在上千dubbo服务的公司来说,我们可能更期待3.0的标准化能力。

3.2 现有协议不适合下沉

现有的SOA协议可能不太适合作为标准协议,基于Http 1.1的文本协议,跟TCP协议相比,建连带来的成本,很大程度上会导致长尾,影响服务的稳定性。

Dubbo协议由于对网关不太友好,同时存在着跨语言和协议穿透性等问题,envoy本身也可以理解为单机网关代理,所以也不太适合作为标准协议。

其次,存在的跨语言和协议穿透性问题,阿里刘军同学有过分享,感兴趣的同学可以参考:https://www.infoq.cn/article/y5HC2JjtAvMWYILmVILU

3.3 新协议

既然现有的协议都不太适合,是否可以考虑云原生的标准协议gRPC。没错,从协议层面来看,这个选择没有问题,但是gRPC跟proto强绑定的问题,需要携程现有的几千个服务重写业务逻辑代码,这个成本可是无法被接受的。

我们对于新的协议的期待,应该是能够基于POJO对象,同时还要符合gRPC协议规范。一方面,能够很好的利用云原生的基础能力。另一方面,对于小众语言,也可以利用现有的gRPC框架实现与主流SDK的互通。

对于新的SDK,不但要有标准的传输协议,同时考虑到服务框架与业务的紧密耦合,扩展性也是要保留的主要的特性,还需要考虑API的标准化,利用统一的监控组件。

3.4 总结

现在,我们实现了SDK的部分标准化。未来,我们一定会在云原生的道路上走的更快,更稳,更标准。

作者介绍

海洋,携程技术专家。对微服务和并发编程,以及应用性能调优等领域有较浓厚兴趣。

本文转载自公众号携程技术(ID:ctriptech)。

原文链接

近万服务实例稳定运行0故障,携程微服务框架实践及思考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章