在当下,云原生的火爆不容小觑。随着虚拟化技术的成熟和分布式框架的普及,在容器技术、可持续交付、编排系统等开源社区的推动下,以及微服务等开发理念的带动下,应用上云已经是不可逆转的趋势,云原生(Cloud Native)的概念也应运而生,更是火得一塌糊涂。
Cloud表示应用程序位于云中,而不是传统的数据中心;Native表示应用程序从设计之初即考虑到云的环境,原生为云而设计,在云上以最佳姿势运行,充分利用和发挥云平台的弹性+分布式优势。
而作为云原生的基石之一,监控和日志的重要性自是不言而喻。
监控(Monitoring)和日志(Logging),是大型分布式系统中最关键的基础设施之一。因为没有监控,就没办法知晓服务的运行情况,也没办法知道集群中有没有Down机、机器的CPU使用率和负载是否正常、网站的Traffic是否正常,以及服务的出错率是不是在可容忍范围之内。简而言之,监控使得我们可以实时了解网站的运营情况和可用性情况。
监控通常是从整体上了解网站的情况,需要具备实时性,而日志则是详尽地记录着系统运行情况,每一次Service的调用,每一次数据库的访问,都应该写进日志,特别是当系统出现问题时,我们希望日志系统能提供完整的错误堆栈和尽可能完备的上下文,从而为系统维护提供支持。
为了帮助开发者对云原生监控和日志解决方案等概念有个系统的了解和应用,京东云与AI事业部云产品研发部架构师高云川老师在《六周玩转云原生》系列技术公开课《第四讲:走近监控与日志,云原生基石探秘》中,和与会者们共同讨论了在记录和监控云原生应用时各种值得借鉴和遵循的优秀实践与标准,并通过精彩的案例解析分享京东智联云在云原生监控&日志的落地实践。
同时,通过邀请开发者们动手实践,深入参与并体验云原生监控体验,参加课程的同学纷纷表示收获颇丰。那么,高云川老师究竟分享了哪些干货?云原生下的可观测性是什么?Prometheus监控方案和EFK的日志方案究竟如何实践?下面让我们一起来回顾下精华内容吧!
云原生下的可观测性
在云原生中,典型的代表技术包括容器(我们通常理解为Docker)、服务网格、服务治理、微服务、微服务框架、还有不可变基础设施等。这里面就涉及到OS层相关的探索以及声明式API,这是它的典型特征之一。
因此,构建云原生应用的目标之一就是构建容错性好、便于管理和便于观测的松耦合系统,这里面的观测就是我们今天要讲的可观测性。利用综合可靠的自动化手段,云原生技术使工程能够轻松的应对大规模伸缩和频繁持续的交付。目前我们讲的云原生基本都是讲K8S,所以基本上也可以叫它Kubernetes native。
云原生的可观测性是指提供对系统行为的高度细致的见解以及丰富的上下文,非常适合调试目的。正如下图所示,2017年的一篇文章提出了这一概念。作者认为:可观测性其实是监控系统,就是这个圆圈的Monitoring部分。可观测性不仅仅包含监控系统,也包含了相关的以调试(包括测试、做负载压测等)为目的的方式。
我们通常所说的监控系统是最适合报告系统整体运行状况的,目标是保证我们的监控系统它自身的简单、高效和稳定。通俗的理解一下,可观测性就是通过技术手段描绘系统的更全面的状态,对我们自己的整体系统有一个非常全面的认知,以一个非常低的门槛且形象的方式让用户具象化的感受到自己对业务的假设是否符合预期,以其获得对业务更深的insight。
下面我们说一下这个监控的意义。我们通常会遇到一些问题,比如:“这个服务我感觉它好像不太正常,但是我也不知道系统到底是不是有问题?”“这个问题我修了很长时间,但是还没有修复,压力山大怎么办呢?”“好不容易看到异常信息,但是一堆信息,我无从查找,怎么办?”“我部署了一个微服务应用,可能七八十个子系统的管理员,线上出问题了,我要去排查它的时候,我无从入手,怎么办呢?”......
这里面就引出了监控的意义:线上的异常通常会导致不稳定性,不稳定性会带来损失,所以说我们监控系统最主要的目标就是缩短异常的平均修复时间MTTR。异常的修复过程我们可以总结为三个步骤:see-know-act。这是一个循环的过程,提出一个核心的要求,就要足够快速地采集线上的数据,通过快速观察、假设、分析结果从而快速找到规律、发现异常,快速行动止损——我们平均修复时间越短,受到的经济损失就会降得越低。
监控手段可以分成三大支柱,第一个Metrics,第二个Logging,第三个是Tracing系统,分别是以时序监控指标为代表的监控指标系列,第二个是日志系列,第三个是分布式跟踪系统。
时序数据就是一堆离散的点,每个点包含一个时间标识time,一个value标识,这个就是最基本的时序指标。日志部分大家应该接触得比较多,应用系统里面通常都会打日志,为了在调试时更方便地看到系统在这个时刻的运行状态是什么样的。
日志一般会分为两种类型:一种是非结构化的日志数据,一种是对日志数据做结构化,做结构化的那个日志数据其实会有更多的分析优势。第三个Tracing系统就是分布式链路跟踪,通过给请求一个唯一标识,那么它经过的每一个服务都记录下它的调用路径,并且记录下它在该服务的处理时间、异常日志各种信息和相关事件信息,我们可以得到全链路的链路图,以便进一步了解系统、追踪问题。
目前业界采用最广泛的是Metrics系统,它的数据时效性是最强、最有效的,能够让你最快发现系统的异常。而Logging日志系统主要是用于分析的场景,时效性比较中等,一般当发生告警、异常的时候,通过Metrics已经观察不出来可能的问题或是只能限定问题范围,就需要日志来进行进一步的分析。
基于Prometheus的监控方案
监控系统其实就是个数据处理系统,包含数据的抽象、采集、存储、计算和数据的使用,下面我们就来介绍下监控方案Prometheus。Prometheus是CNCF下最早期毕业的项目之一,现在是时序监控领域、云原生领域的事实监控标准,整体架构设计非常优雅。
中间这一部分Prometheus Server是一个单体应用,可以独立启动。我们可以针对其配置采集任务。不同的组件PaaS产品基本都有通用开源的Exporter,通过这种方式可以很好地利用开源,便捷的采集各类产品的监控数据。采集管理之后就是存储,Prometheus内含了一个TSDB。可以针对时序指标数据做存储及计算。存储完数据之后需要暴露给用户使用,它通过一个Restful的API来实现。通过外层使用Prometheus的原生UI,我们可以调用它的接口来获取相关的数据,进行相关的实时分析,也可以采用Grafana这个观测性领域最为广泛应用的工具来查看。
蓝色框里的是Prometheus跟K8S的结合,为什么说Prometheus是云原生的事实监控标准呢?它跟K8S是无缝集成的,只要用户在K8S里面声明了一个service或是一个注解,那么Prometheus就会自动做服务发现,把相关实例的监控信息自动抓取出来,完全实现对应用和监控的分离。
最后我们介绍一下Alertmanager,它是Prometheus里面第二个二进制文件,实现了对告警的处理。Prometheus可以设置规则触发告警,但是Prometheus本身不负责发出告警,这时候就需要把Alertevents push到Alertmanager。Alertmanager负责报警的发送、收敛、沉默相关的功能。
下面通过Prometheus介绍一下Prometheus对数据的抽象,以便我们对监控系统整体的数据抽象有个大概的了解。
什么是时序数据呢?我们前面讲到过,其实就是由一个时间time和一个value构成的一个影响的序列,那么在Prometheus里面,它除了有time和value以外,还有一个metric name,如 内存指标,CPU空闲、内存用量,都通过metric name标识。目前主流的TSDB系统基本都支持时间达到秒级或者毫秒级精度为主。采样频率一般推荐周期型的采样,比如一台云主机可能每5秒钟暴露一个监控数据点,把相关所有的监控数据指标暴露一次,Prometheus来定实抓取一次,这样就可以形成长期的时序曲线。
还有另外一种更偏重业务场景的离散型,比如当某个用户访问时,我在这一分钟内把这个用户访问记录、请求数量标记下,如果他在下一分钟不访问了就不标记,这种采样方式可以显著降低监控量。
下面我们介绍下Prometheus的数据查询语言PromQL。需要指控一个监控指标的名称、聚合维度以及需要指定一个计算因子,我们叫它“算子”。
下面介绍一个用户场景:用户A拥有1万台云主机,云主机的监控数据粒度为5秒一个点,如何做到秒出一个月CPU使用率趋势图数据呢?用户在控制台里面不可能等待很长时间,这个时候大概有50亿的数据需要在该次请求里面被访问,这时该怎么做?我们目前采用的方案也是业界通常采用的方案,就是采用降采样+预聚合的方式,将预算前置,大幅度降低数据规模,确保查询的实时性。我们提前把数据规模降下来,比如原来有50亿个原始数据点,通过降采样和预聚合可能只有1万个点了,这时候我们做一个API查询查询出这1万个点,就可以实时反馈给用户系统。
降采样和预聚合是监控数据处理领域最主要的两种计算方式。降采样是指在时间维度上,把细粒度的数据聚合成一个时间粒度更粗的形式。在上面的第一幅图中,原来数据有3个点,每个点5秒钟上报一次,那么这时对这个原始点做一个降采样处理,把3个点通过某种算子聚合成一个点,那么给用户展示的数据粒度其实会变成15秒一个点,数据粒度变得宽泛了,但是返回的数据规模其实降低了3倍,这就是降采样的过程。
跟降采样对比的话,降采样是在时间轴上做聚合运算,把数据规模降低,而预聚合是在Y轴value相关的维度上做运算,以此来降低数据规模。假设按照上面来说,用户有1万台云主机,云主机监控数据上面标注了用户的user信息以及云主机的ID信息,这时就需要对每一个时间点做一个预聚合,跨维度预算只保留用户的user信息,把云主机的ID忽略掉,这时候就可以把1万个点通过某种算子聚合成1个点,以此降掉的数据规模达到1万倍。
基于EFK的日志方案
当购买了一台云主机,应用产生了自己的业务应用日志,如何把它采集到服务端并进行统一的展示呢?我们介绍一个最简单的方案,就是EFK。在日志方案上,EFK(Elasticsearch、Fluentd、Kibana)是云原生领域最为主流的日志管理方案。Fluentd是CNCF里面毕业较晚的一些项目,它可以把各种数据源的日志进行统一化的采集,利用内置的Pipeline实现采集、处理之后投递的功能。
我们简单介绍一下Fluentd的工作流程。上图是一个典型的Fluentd的配置,主要分为三个block:第一个是source部分,source就是指定采集的日志源,可能是一个文件、一个HTTP接口、也可能是一个TCP。通过定义采集数据源,把数据抓到本地进程里。抓过来之后需要对相关数据做一个匹配处理操作。
Fluentd是一个开源项目,支持独立部署,在跟K8S集成的过程中往往需要把它的container信息、workload相关信息都附加过来,这时就需要利用到它的filter功能,为它附加workload上的相关标签,以此达到每一条日志都可以知道它是哪一个workload产生的、哪个APP产生的目的。
数据采集和处理完之后,这时就需要把它发到服务端。我们可以在这指定一个type elasticsearch,直接把它投递到ES里边,做一个日志的索引,到时就可以进行相关的检索了。
京东目前的整体方案原理上和这个类似,只不过做了些企业级的支持。我们的采集端做了Fluentd开源适配,会把数据传输到Kafka里做数据的中继,中继下面对接实时分析系统、索引系统等相关系统。
这里展示了数据被采集投递到ES之后,我们用KIbana进行检索的一个事例。左侧我们可以看到容器的ID、name,相关的label也可以采集到,假如我们在自己的工作负载上打一些标签,那么采过来的日志会自动打上这个标签,告诉你这个是应用A还是应用B产生的日志。另外一个是中间件MySQL产生的日志,有了这些标签,它就可以按照业务进行相关检索分析,也可以做相关的数据视图。右边是做数据视图的一个事例,在这展示了不同POD的日志数据量比例,可以看到大概占75%。
京东智联云在云原生监控&日志的落地实践
京东智联云定制了一套监控的标准,分为四层监控:
首先是基础监控,主要是指机器资源、物理机的一些监控,面向K8S集群运维、物理资源相关运维等内容。
其次是存活监控,也叫健康检查,通过简单的手段对应用进行定时探测,每1分钟过来探测一下这个应用是不是健康的。我们可以使用的方式就是进程、端口监控,进行简单的语义监控。
第三部分是应用性能监控。在监控领域,业界通常采用的是谷歌提出的四大黄金指标:流量、数据的错误率、平均延迟以及容量。大家对容量关注的不多,但是PV、平响 、错误码 这三个指标是衡量一个系统健康与否、是否符合预期的重要依据。
最上面一层是业务监控。有时候我们也从用户的视角进行相关的探测,比如打开京东APP的时候,从一个终端用户来看,APP首页的信息接口是不是足够健康、足够快速呢?这时候我们就需要做一些外部的探测。
我们在K8S的监控方案大致如此。云K8S里面我们部署了各种的exporter,比如MySQL服务、ES等,包括用户自定义的应用、自己的监控接口等。
我们同样使用原生的Prometheus对数据进行抓取,整体流程和上面介绍的Prometheus方案是一样的,唯一做的改造不是用本地存储,而是用Remote write的方式,通过京东智联云的openAPI把数据推送到了云监控。云监控数据过来之后,首先做个数据中继推到MQ里,把数据双写到tsdb cache 和tsdb storage里边,再对其中相关的计算任务进行刚才预聚合任务、抽样任务。
这里再详细说一下TSDB。TSDB是我们自研的一款时序数据库,之所以自研就是因为市面上的TSDB不能满足企业级的需要。很多企业都选择了自研。我们刚才介绍到Prometheus是单层应用,它能支撑的量是有限的。当数据规模达到一定程度时,Prometheus就会成为瓶颈,所以不能直接采用Prometheus,必须有一套自己验证大数据量的TSDB解决方案。
我们的TSDB相较于传统的TSDB有以下几个特征:
数据压缩:采用gorilla的压缩算法,数据量大幅压缩。数据如果太臃肿的话,内存会消耗大量资源,而通过数据压缩之后,数据体量是极小的,可以加速我们的查询支持。
缓存层:内存缓存近28小时的数据,使得查询性能成倍提升,提高了系统的可靠性,目前可以达到几十万的QPS。
抽样+路由:灵活的抽样规则,自适应路由,按需使用抽样数据,提高性能。当用户来查询时,28小时之内的数据会让他路由到tsdb cache进行实时的内存查询;如果时间很长,比如用户要查询1个月的数据,那么我们会把它路由到tsdb storage来进行一个全量的查询。
预聚合:分布式实时计算框架,热点自发现、自修复。
存储与计算分离:计算能力按需伸缩,降低资源成本。tsdb架构采用存储与计算分离的架构,数据可以长期存储,成本极其便宜。
全面兼容prometheus接口及语法规范。其实我们现在兼容两种协议:Prometheus和openTSDB,我们云上K8S的对接方案完全就是按照Prometheus的格式进行对接的。
我们的内部监控系统构建依然是围绕着See-konw-act流程的,所以也围绕See-konw-act做了些相关的工作。
如何让用户发现问题呢?如果只能靠用户提前设置指标的话,那么用户的覆盖程度可能会有遗漏,所以系统会自动帮用户做多维度的聚合运算,做相关时序指标的异常检测,比如恒定阈值、突升突降、同环比、3-sigma等方式,看是不是符合动态分布的数据。当我们检测到一条时序不符合的时候会自动触发告警,帮用户更快发现系统的异常。
那如何让用户更快地诊断异常、定位问题所在呢?我们提供相关实时大规模跨维度分析计算能力,也提供异常诊断,即根因定位。我们提供了复杂查询的分析手段,在不影响线上服务稳定性的情况下,允许用户在线上直接做相关请求的抽样,以此来获取更多线上数据信息,来诊断问题、定位问题。
问题被定位之后,该如何执行呢?告警是最简单的,但是我们要保证告警信息的触达能力。假如DNS出了问题,那么整个网络就瘫痪了,但是监控系统是不能瘫痪的,所以我们也做了相关的稳定性保障:当网络瘫痪的时候,我们的告警依然能够触发出来。另外,告警的分组、收敛、分级、升级以及屏蔽都是企业级需要的功能。
京东智联云云原生监控实践
上一期我们讲了京东智联云的DevOps,DevOps最终应用发布之后就到了运维和监控环节。线上应用发布之后,我们需要观测它的运行指标,当线上出现异常时,我们观测它的日志以便我们定位问题。
我们还可以从外部进行判测,比如我可以从广州电信、河南联通分别探测服务是不是可以正常访问,这就是我们京东智联云的云拨测服务;当云主机重启、K8S产生一系列事件时,我们的云事件服务会通知用户做一些相关的告警以及自动化操作——这就是我们的运维和监控体系。