关于云计算:面向无人驾驶-云端大脑-可用性的云原生实践

作者:张海立,驭势科技云平台研发总监

行业背景

驭势科技(UISEE)是国内当先的主动驾驶公司,致力于为全行业、全场景提供 AI 驾驶服务,交付赋能出行和物流新生态的 AI 驾驶员。因为须要保障各个场景下 “真 · 无人”(即无安全员在车上或跟车)的业务运作,咱们比拟重视在 “云端大脑” 上做了一些保障其高可用和可察看性方面的实际。

让咱们假如有这样一个场景:在一个厂区运行了几十台的无人物流拖车,思考到 “真无人” 环境下的平安经营,咱们会采取车云连贯长时间断开(个别为秒级)即停车的策略;如果在经营的过程中,云端呈现故障且不足高可用能力,这将造成所有车辆停运。显然这对业务经营会造成微小影响,因而云平台的稳定性和高可用性是十分重要和要害的。

为什么抉择 KubeSphere

咱们和 KubeSphere 的结缘能够说是 “始于颜值,陷于才华”。早在 KubeSphere 2.0 公布之时,咱们因缘际会在社区的新闻中留意到这个产品,并马上被它 “小清爽” 的界面所吸引。于是,从 2.0 开始咱们便开始在公有云上进行小范畴试用,并在 2.1 公布之后开始投入到咱们私有云环境的治理中应用。

KubeSphere 3.0 是一个十分重要的里程碑公布,它带来了 Kubernetes 多集群治理的能力、进一步加强了在监控和告警方面的能力,并在 3.1 中继续对这些能力进行夯实。由此,咱们也开始更大范畴地将 KubeSphere 利用到咱们自有的和客户托管的集群(及在其中运行的工作负载)的治理上,同时咱们也在进一步摸索如何将现有的 DevOps 环境和 KubeSphere 做整合,最终的指标还是心愿将 KubeSphere 打造成咱们外部面向云原生各利用、服务、平台的对立入口和集中管理的外围。

正是因为 KubeSphere 提供了这样优良的管控能力,使得咱们有了更多工夫从业务角度去晋升云平台的可用性。这次分享的两个内容就是咱们晚期和当初正在推动的两项可用性相干的实际。

“高可用”实际:提供热备能力的 Operator

“高可用” 方面,咱们冀望解决的问题是如何确保云端服务呈现故障时能够用最快的速度从新复原到稳固运行的状态。

限定区域 L4 无人驾驶场景的 “高可用” 诉求

“高可用” 从工夫量化的角度通常就是几个 9 级别抉择,但落到具体的业务场景,所面临的问题和挑战却是各不相同的。如上图所列举的,对于咱们 “限定区域 L4 无人驾驶场景” 而言,以 toB 业务为主所造成的客户公有云品种繁多、对于复原过程容忍度不同、以及客户定制服务产生的历史包袱较多是制约咱们构建高可用计划的几个次要问题。面对这些限度,咱们抉择了一个比拟 “简略粗犷” 的思路,试图 “化繁为简” 跳出跨云高可用老本高、为服务附加高可用能力交融危险高的常见问题包围圈。

一种通过 Operator 实热备切换的高可用办法

如上图所示,这个计划的思路很间接 —— 实现服务 Pod 状态监测并在状态异样时进行主备 Pod 切换。如果咱们从 Controller 的 “Observe – Analyze – Act” 体系来看,它做了如下工作:

  • 监测:同时可能监测 Pod / Deployment / StatefulSet / Service 的变动(包含可能监控特定的 Namespace);监测到有变动则触发 Reconcile 调协过程(即以下两个操作)
  • 判断:遍历所有 Service,获取 Deployment / StatefulSet,将其 status 中的服务的总数量与可用数量进行比拟;如果有正本不可用,则再遍历 dp/sts 外面的 Pod,通过容器的状态及重启次数来找到不衰弱的 Pod,当一个 dp/sts 下所有的 Pod 都不衰弱,则认为这个服务整体不衰弱
  • 切换:同一个服务部署主备两套 dp/sts,在以后服务的 dp/sts 指向的 Pod 全都不衰弱时(即整个服务不衰弱),若另一套 dp/sts 衰弱,切换至另一套 dp/sts

在这个 Operator 的开发框架上,咱们选用了 Kubernetes 官网社区的 Operator SDK,即 Kubebuilder。从技术上看,它对于编写 Controller 通常须要的外围组件 client-go 有比拟好的封装,能够帮忙开发者更专一于业务逻辑的开发;从社区的反对角度看,倒退也比拟安稳,这里也向大家举荐在应用中能够参考云原生社区组织翻译的 Kubebuilder 中文文档。

行百里者半九十:高可用性能落地的长尾在于测试

因为 “高可用” 性能的特殊性,它的测试尤其重要,但惯例的测试伎俩可能并不是很实用(这里存在一个有意思的 “悖论”:测试是为了发现问题,而高可用的启用会防止产生问题)。所以咱们在实现这个 Operator 的开发后,其实更多的工夫是花在测试方面,在这里咱们次要施行了三个方面的测试工作:

  • 端到端的 BDD 测试:这块作为根底性能验证和测试,咱们应用了反对 Cucumber BDD 测试框架的 Godog 我的项目(反对 Cucmber Gherkin 语法),BDD 也适宜业务方间接导入需要
  • 针对运行环境的混沌测试:这块咱们应用 ChaosBlade 对 Kubernetes 物理节点的零碎运行环境进行相干混沌测试,以测验呈现基建故障时的高可用体现
  • 针对业务层面的混沌测试:这里咱们应用 Chaos Mesh 对主备服务进行 Pod 级别的测试,应用 Chaos Mesh 一方面是因为它在这个层面性能笼罩比拟全面,另一方面也是因为它的 Dashboard 便于管理测试所用到的各项测试用例

简略总结一下,在这个 “高可用” 方面的晚期实际过程中,咱们有几点领会:首先,还是须要相熟 Kubernetes Controller 以及 client-go 类库的外围机制;其次,找一个趁手的 Operator 开发框架会大大晋升你的研发效率;最初但也是最重要的一点,高可用这块的研发工作其实是由 “20% 工夫的开发 + 80% 的全方位测试” 组成的,做好测试、做好全面测试十分十分重要。

“可察看”实际:车云端到端 SkyWalking 接入

“可察看” 方面,咱们冀望解决的问题是在服务故障复原后,如何确保咱们可能尽可能快的定位到问题的本源,以便尽早真正打消问题隐患。

无人驾驶车云一体化架构下的 “可察看” 诉求

“车云一体化” 架构是无人驾驶的一个重要外围,从云端视角来看,它的一个微小挑战就是业务链路十分长,远长于传统的互联网纯云端的业务链路。这个超长链路上任意一点的问题都有可能引发故障,轻则告警、重则导致车辆异样离线,所以对于链路上的点点滴滴、各式各样的信息咱们总是心愿可能应收尽收,以便于定位问题。同时,纯正的日志类数据也是不够的,因为链路太长且又散布在车云的不同中央,单靠日志不便于疾速定位问题产生的区间从而进行有针对性的问题开掘。

为了便于大家更具象的理解链路之长,下图咱们给出了一个形象的 “车云一体化” 架构图,感兴趣的敌人能够数一下这 “7 x 2” 的调用链路。

通过 SkyWalking 实现车云全链路追踪

Apache SkyWalking 是社区中一个优良而且沉闷的可察看性平台我的项目,它同时提供了 Logging、Metrics、Tracing 可察看性三元组的性能,其中尤以追踪能力最为扎实,对于追踪零碎的一些基本概念举荐能够参看吴晟老师翻译的 OpenTracing 概念和术语。为了不便大家对后续内容有更好的把握,也补救一下演讲时无奈开展的细节,这边也简略整顿几个关键点供大家参考:

  • Trace:一个 Trace 代表一个潜在的,分布式的,存在并行数据或并行执行轨迹(潜在的分布式、并行)的零碎。一个 Trace 能够认为是多个 Span 的有向无环图(DAG)。
  • Span:在服务中埋点时,最须要关注的内容。一个 Span 代表零碎中具备开始工夫和执行时长的逻辑运行单元。Span 之间通过嵌套或者顺序排列建设逻辑因果关系。在 SkyWalking 中,Span 被辨别为:

    • LocalSpan:服务外部调用办法时创立的 Span 类型
    • EntrySpan:申请进入服务时会创立的 Span 类型(例如解决其余服务对于本服务接口的调用)
    • ExitSpan:申请来到服务时会创立的 Span 类型(例如调用其余服务的接口)
    • SkyWalking 中,创立一个 ExitSpan 就相当于创立了一个 Parent Span,以 HTTP 申请为例,此时须要将 ExitSpan 的上下文编码后,放到申请的 Header 中;在另一个服务接管到申请后,须要创立一个 EntrySpan,并从 Header 中解码上下文信息,以解析出它的 Parent 是什么。通过这样的形式,ExitSpan 和 EntrySpan 就能够串联在一起。
    • SkyWalking 中未对 ChildOf 和 FollowsFrom 两种类型的 Span 作辨别
  • TraceSegment:SkyWalking 中的概念,介于 Trace 和 Span 之间,是一条 Trace 的一段,能够蕴含多个 Span。一个 TraceSegment 记录了一个线程中的执行过程,一个 Trace 由一个或多个 TraceSegment 组成,一个 TraceSegment 又由一个或多个 Span 组成。
  • SpanContext:代表逾越过程上下文,传递到上级 Span 的状态。在 Go 中,通过 context.Context 在同一个服务中进行传递。
  • Baggage:存储在 SpanContext 中的一个键值对汇合。它会在一条追踪链路上的所有 Span 内全局传输,蕴含这些 Span 对应的 SpanContext。Baggage 会随着 Trace 一起流传。

    • SkyWalking 中,上下文数据通过名为 sw8 的头部项进行传递,值中蕴含 8 个字段,由 - 进行宰割(包含 Trace ID,Parent Span ID 等等)
    • 另外 SkyWalking 中还提供名为 sw8-correlation 的扩大头部项,能够传递一些自定义的信息
  • 与 Jaeger / Zipkin 相比,尽管都是对 OpenTracing 的实现,然而 ExitSpan、EntrySpan 的概念是在 SkyWalking 中独有的,应用下来体验较好的点在于:

    • 应用语义化的 ExitSpan 和 EntrySpan,使代码逻辑更为清晰
    • 心愿逻辑清晰的起因是,有时候创立 Span 的确容易出错,尤其是在对服务链路不相熟的状况下。所以进行埋点时,对 OpenTracing 的了解是根底,也须要理解服务的链路。

SkyWalking 的插件体系是保障咱们得以在一个宏大的微服务架构中进行埋点的根底,官网为 Java、Python、Go、 Node.js 等语言都提供了插件,对 HTTP 框架、SQL、NoSQL、MQ、RPC 等都有插件反对(Java 的插件最为丰盛,有 50+,其余语言的插件可能没有这么全面 )。咱们基于 Go 和 Python 官网插件的研发思路,又进一步扩大和自制了一些插件,例如:

  • Go · GORM:GORM 反对为数据库操作注册插件,只需在插件中创立 ExitSpan
  • Go · gRPC:利用 gRPC 拦截器,在 metadata(相似 HTTP 的 Header) 中写入上下文
  • Go · MQTT:没有找到能够应用的中间件,所以间接写了函数,在公布和收到音讯时手动调用
  • Python · MQTT:在 Payload 中写入 Carrier(可参考 OpenTracing 中 Baggage 的概念,携带蕴含 Trace 上下文信息的键值对) 中的上下文数据
  • Python · Socket:因为比拟底层,依照官网做法自定义 Socket 插件后,HTTP 申请、MQTT 收发音讯都会被记录,输入信息过多;所以又自定义了两个函数联合业务手动调用

前途是光明的,路线是波折的 —— 记一些咱们踩过的坑

因为微服务架构中波及的语言环境、中间件品种以及业务诉求通常都比拟丰盛,这导致在接入全链路追踪的过程中不免遇到各种主观和主观的坑,这里给大家介绍几个常见场景。

案例一:Kong 网关的插件链路接入问题

找不到官网插件是最常见的一种接入问题。比方咱们在接入 SkyWalking 时,官网还未公布 SkyWalking 的 Kong 插件(5 月才公布)。咱们因为业务须要在

Kong 中接入了自定义的一个权限插件,用于对 API 和资源的受权;这个插件会调用权限服务的接口进行受权。那么这个插件中的调用,也应属于调用链中的一环

,所以咱们的解决思路是间接在权限插件中进行了埋点,具体造成的链路如下图所示。

案例二:跨线程/跨过程的链路接入问题

对于跨线程,这里给大家一个提醒:能够应用函数 capture() 以及 continued();应用 Snapshot,为 Context 上下文创立快照。
对于跨过程,咱们遇到一个比拟坑的坑是 Python 版本问题:Python 服务中新起一个过程后,原先过程的 SkyWalking Agent 在新过程中无奈被应用;须要重新启动一个 Agent 能力失常应用,实际后发现 Python 3.9 可行,Python 3.5 中则会报错 “agent can only be started once”(找谁说理去。。。)

案例三:官网 Python Redis 插件 Pub/Sub 断路问题

这个案例是一个典型的官网插件不能笼罩事实业务场景的问题。官网提供的 Python 库中,有提供 Redis 插件;一开始咱们认为装置了 Redis 插件,对于所有 Redis 操作,都能相互连贯;然而实际上,对于 Pub/Sub 操作,链路是会断开的。

查看代码后发现,对于所有的 Redis 操作,插件都创立一个 ExitSpan。然而在咱们的场景中,须要进行 Pub/Sub 操作;这导致两个操作都会创立 ExitSpan,而使链路无奈相连。对于这种状况,最初咱们通过革新了一下插件来解决问题,大家如果遇到相似状况也须要留神官网插件的功能定位。

案例四:MQTT Broker 的多种 Data Bridge 接入问题

一般来说,对 MQTT Broker 的追踪链路是 Publisher => Subscriber;然而也存在场景,MQTT Broker 接管到音讯后,通过规定引擎调用告诉核心的接口;而规定引擎调用接口时,没有方法把 Trace 信息放到 Header 中。

这是一个典型的中间件高级能力未被插件笼罩的问题。通常这种状况还是得就坡下驴,按理论状况做定制。比方这个案例中咱们通过约定好参数名称,放到申请体中,在告诉核心收到申请后,从申请体中抽取链路的 Context 的形式最终实现了下图的链路贯通。

最初也总结一下咱们在 “可察看” 这部分的一些实际领会:首先,还是须要依靠一个成熟的继续演进的工具/平台
;其次,就是依附它,同时也要和它一起一直成长、一直自我完善;最初,
断路不可怕,凡人说过 “星星之火,能够燎原”,明确指标、保持致力,肯定有机会解决问题的。

最初的最初,再次感激 KubeSphere 团队为中国乃至寰球的开源社区奉献了这么一个卓越的云原生产品,咱们也心愿能尽本人所能多参加社区建设,与 KubeSphere 社区共成长!

本文由博客一文多发平台 OpenWrite 公布!

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据