1953700 叶婧鑫 第一周任务 - XLab-Tongji/2021-WorkloadSimulation GitHub Wiki

第一周 学习任务

1.背景知识了解

1.1 云

云是和本地相对的,传统的应用必须跑在本地服务器上,现在流行的应用都跑在云端。云是一个数据存储中心,能提供计算、服务、甚至应用功能,只要能上网你想要的资料都能找出来进行查询、修改、保存。

四种部署方式(公有云,私有云,社区云,混合云)

私有云和公有云的显著差别在于对数据的掌控。

**公有云:**通常指第三方提供商用户能够使使用的云,公有云一般可通过 Internet 使用,可能是免费或成本低廉的。关注分布式、大集群;在主机层实现安全隔离;用户无法自主运维,公有云服务商统一运维。

**私有云:**是为一个客户单独使用而构建的,因而提供对数据、安全性和服务质量的最有效控制。关注高可用、灵活性;在网络层实现安全隔离;自主运维也可以托管给第三方运维。

**社区云:**建立在一个特定的小组里多个目标相似的公司之间,他们共享一套基础设施,企业也像是共同前进,所产生的成本由他们共同承担。社区云的成员都可以登录云中获取信息和使用应用程序。

**混合云:**两种或两种以上的云计算模式的混合体,如公有云和私有云混合。他们相互独立,但在云的内部又相互结合,可以发挥出所混合的多种云计算模型各自的优势。

三种服务模式(IaaS、PaaS、SaaS)

其实云计算是分几层的,分别是Infrastructure(基础设施)-as-a-Service,Platform(平台)-as-a-Service,Software(软件)-as-a-Service。**基础设施在最下端,平台在中间,软件在顶端。**IaaS的主要作用是提供虚拟机或者其他资源作为服务提供给用户;PaaS的主要作用是将一个开发和运行平台作为服务提供给用户;SaaS这一层是我们生活每天接触的一层,大多是通过网页浏览器来接入,任何一个远程服务器上的应用都可以通过网络来运行,就是SaaS了。


1.2 云原生

img

云原生 = 微服务 + DevOps + 持续交付 + 容器化

img

定义:云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。

云原生既包含技术(微服务,敏捷基础设施),也包含管理(DevOps,持续交付,康威定律,重组等),可以说是一系列云技术、企业管理方法的集合。

云原生的代表技术包括:容器、服务网格、微服务、不可变基础设施和声明式API。这些技术能够构建容错性好、易于管理和便于观察的松耦合系统

结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更,通过整合健壮且有效的自动化,工程师可以用很少的劳动来完成频繁的、预期中的高危代码修改。

管理层面:

  • **DevOps:**从字面上来理解只是Dev(开发人员)+Ops(运维人员),DevOps的意思就是开发和运维不再是分开的两个团队,是一个团队。强调的是高效组织团队之间通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。

  • **持续交付:**在不影响用户使用服务的前提下频繁把新功能发布给用户使用。

其他:

  • **松耦合系统:**松耦合系统通常是基于消息的系统,此时客户端和远程服务并不知道对方是如何实现的。客户端和服务之间的通讯由消息的架构支配。只要消息符合协商的架构,则客户端或服务的实现就可以根据需要进行更改,而不必担心会破坏对方。

  • **云与云原生:**云是一切的基础,为上层应用的运行提供了计算、网络、存储等基础架构资源;容器在云的基础架构和应用之间,集有了应用和基础架构资源。


1.3 微服务

微服务解决的是我们软件开发中一直追求的**低耦合+高内聚。**微服务倡导运用化整为零,实现各个功能的独立开发与部署、提升应用架构的灵活性,从而提升对业务的响应速度。

微服务的本质是把一块大饼分成若干块低耦合的小饼,比如一块小饼专门负责接收外部的数据,一块小饼专门负责响应前台的操作,小饼可以进一步拆分,比如负责接收外部数据的小饼可以继续分成多块负责接收不同类型数据的小饼,这样每个小饼出问题了,其它小饼还能正常对外提供服务。一个微服务基本是一个能独立发布的应用服务,每个服务可以由专门的组织来单独完成,依赖方只要定好输入和输出口即可完全开发。

**特点:**微服务是一种架构风格,也是一种服务;微服务的颗粒比较小,一个大型复杂软件应用由多个微服务组成;每种服务只做一件事,是一种松耦合的能够被独立开发和部署的无状态化服务(独立扩展、升级和可替换)。


1.4 容器

一般说的“容器”,都是“Linux容器”。容器是与系统其他部分隔离开的一系列进程。

运行这些进程所需的所有文件都由另一个镜像提供,这意味着从开发到测试再到生产的整个过程中,Linux 容器都具有可移植性和一致性。相对于依赖重复传统测试环境的开发渠道,容器的运行速度要快得多。容器提供进程级的隔离,可以将操作系统管理的资源划分到相互隔离的组中,在相互隔离的组之间解决资源使用存在冲突的问题。

**优势:**在于运维的时候不需要再关心每个服务所使用的技术栈了,每个服务都被无差别地封装在容器里,可以被无差别地管理和维护。

Docker:

Docker项目通过容器镜像,直接将一个应用运行所需的完整环境,即:整个操作系统的文件系统也打包了进去。

Docker项目大大降低了容器技术的使用门槛。轻量级,可移植,虚拟化,语言无关,写了程序扔上去做成镜像可以随处部署和运行,开发、测试和生产环境彻底统一了,还能进行资源管控和虚拟化。

Docker允许开发人员将各种应用以及依赖包打包到一个可移植的Docker容器中,以Docker容器为资源分割和调度的基本单位,封装整个软件运行时的环境,然后发布到Linux机器上。

按照Docker的设计方案,应用软件的交付过程如同海上运输,操作系统OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱。用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员(开发人员或系统管理员)定制。如此一来,交付一个应用软件产品,就相当于交付一系列标准化组件的集合。


1.5 Logging,Metrics 和 Tracing

Logging,Metrics 和 Tracing 有各自专注的部分。

  • Logging - 用于记录离散的事件。例如,应用程序的调试信息或错误信息。它是我们诊断问题的依据。
  • Metrics - 用于记录可聚合的数据。例如,队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新;HTTP 请求个数可被定义为一个计数器,新请求到来时进行累加。
  • Tracing - 用于记录请求范围内的信息。例如,一次远程方法调用的执行过程和耗时。它是我们排查系统性能问题的利器。

三者有重复部分,如下图

img


2 分布式跟踪系统 Open Tracing

2.1 一个典型的trace案例

分布式追踪系统发展很快,种类繁多,但核心步骤一般有三个:代码埋点,数据存储、查询展示。

下图是一个分布式调用的例子,客户端发起请求,请求首先到达负载均衡器,接着经过认证服务,计费服务,然后请求资源,最后返回结果。

一个客户通过手机客户端向web发起了一个HTTP请求,产生一个复杂的调用流程:mobile client (HTTP) → web tier (RPC) → auth service (RPC) → billing service (RPC) → resource request (API) → response to web tier (API) → response to client (HTTP)

img

数据被采集存储后,分布式追踪系统一般会选择使用包含时间轴的时序图来呈现这个 Trace。

img

但在数据采集过程中,由于需要侵入用户代码,并且不同系统的 API 并不兼容,这就导致了如果您希望切换追踪系统,往往会带来较大改动。

为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范。 OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。


2.2 概念与术语

2.2.1 Traces:

一个trace代表一个潜在的,分布式的,存在并行数据或并行执行轨迹(潜在的分布式、并行)的系统。一个trace可以认为是多个span的有向无环图(DAG)。

2.2.2 Spans:

一个span代表系统中具有开始时间和执行时长的逻辑运行单元。span之间通过嵌套或者顺序排列建立逻辑因果关系。

每个 Span 包含以下的状态(下面会有详细说明):

  • An operation name,操作名称

  • A start time stamp,起始时间

  • A finish time stamp,结束时间

  • Span Tag,一组键值对构成的 Span 标签集合。

  • Span Log,一组 span 的日志集合。

  • SpanContext,跨越进程边界传递到下级span的状态。

  • References(Span间关系),相关的零个或者多个 Span(Span 间通过 SpanContext 建立这种关系)

2.2.3 Inter-Span References

一个span可以和一个或者多个span间存在因果关系。

ChildOf引用: 一个span可能是一个父级span的孩子,即"ChildOf"关系。在"ChildOf"引用关系下,父级span某种程度上取决于子span。下面这些情况会构成"ChildOf"关系:

  • 一个RPC调用的服务端的span,和RPC服务客户端的span构成ChildOf关系
  • 一个sql insert操作的span,和ORM的save方法的span构成ChildOf关系

  • 很多span可以并行工作(或者分布式工作)都可能是一个父级的span的子项,他会合并所有子span的执行结果,并在指定期限内返回。

    "ChildOf"关系的父子节点关系的时序图

  [-Parent Span---------]
         [-Child Span----]

    [-Parent Span--------------]
         [-Child Span A----]
          [-Child Span B----]
        [-Child Span C----]
         [-Child Span D---------------]
         [-Child Span E----]

FollowsFrom 引用: 一些父级节点不以任何方式依然他们子节点的执行结果,这种情况下,我们说这些子span和父span之间是"FollowsFrom"的因果关系。

"FollowsFrom"关系的父子节点关系的时序图。

    [-Parent Span-]  [-Child Span-]


    [-Parent Span--]
     [-Child Span-]


    [-Parent Span-]
                [-Child Span-]
一个tracer过程中,各span的关系


        [Span A]  ←←←(the root span)
            |
     +------+------+
     |             |
 [Span B]      [Span C] ←←←(Span C 是 Span A 的孩子节点, ChildOf)
     |             |
 [Span D]      +---+-------+
               |           |
           [Span E]    [Span F] >>> [Span G] >>> [Span H]
                                       ↑
                                       ↑
                                       ↑
                         (Span G 在 Span F 后被调用, FollowsFrom)


上述tracer与span的时间轴关系


––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

 [Span A···················································]
   [Span B··············································]
      [Span D··········································]
    [Span C········································]
         [Span E·······]        [Span F··] [Span G··] [Span H··]

2.2.4 Logs

每个span可以进行多次Logs操作,每一次Logs操作,都需要一个带时间戳的时间名称,以及可选的任意大小的存储结构。每次 log 操作包含至少一个键值对,以及一个时间戳。键值对中,键必须为 string,值可以是任意类型。

2.2.5 Tags

每个span可以有多个键值对(key: value)形式的Tags,Tags是没有时间戳的,支持简单的对span进行注解和补充。键值对中,键必须为 string,值可以是字符串,布尔,或者数字类型。

2.2.6 SpanContext

SpanContext代表跨越进程边界,传递到下级span的状态。每个span必须提供方法访问SpanContext。(例如,包含<trace_id, span_id, sampled>元组),并用于封装Baggage .

2.2.7 Baggage

Baggage是存储在SpanContext中的一个键值对(SpanContext)集合。它会在一条追踪链路上的所有span内全局传输,包含这些span对应的SpanContexts,该 Trace 中的所有 Span 都可以获取到其中的信息。"Baggage"会随着trace一同传播,Baggage可理解为随着trace运行过程传送的行李。

2.2.8 Baggage&Span Tags

  • Baggage在全局范围内,(伴随业务系统的调用)跨进程传输数据。Span的tag不会进行传输,因为他们不会被子级的span继承。
  • span的tag可以用来记录业务相关的数据,并存储于追踪系统中。

2.2.9 Inject &Extract

SpanContexts可以通过Injected操作向Carrier增加,或者通过ExtractedCarrier中获取,跨进程通讯数据(例如:HTTP头)。通过这种方式,SpanContexts可以跨越进程边界,并提供足够的信息来建立跨进程的span间关系,因此可以实现跨进程连续追踪。


2.3 分布式追踪系统监控服务有以下好处

OpenTracing 通过提供平台无关、厂商无关的 API,使得开发人员能够方便的添加(或更换)追踪系统的实现。

  • 通过在各个微服务埋点打印的调用链日志,能够把一个请求处理的完整链路端到端地展示出来

  • 能够快速定位到异常环节,如中间在某个环节响应慢或是处理失败

  • 能够根据调用链日志生成服务依赖关系拓扑图,直观地观察到故障点或哪个微服务是系统的瓶颈点所在

  • 甚至能够根据采集的日志进行告警配置


3 数据分析

调用链信息

[
    {
        "_index": "jaeger-span-2021-07-11", //索引名称
        "_type": "_doc", //文件类型
        "_id": "USfdknoBWY9Z9HArJlSP", //唯一标识
        "_score": 1, //和查询条件相关性的匹配程度
        "_source": {//追踪来源
            "traceID": "3cc530b6c6acc620c3cf99aee18a299c", //调用链ID
            "spanID": "5f28894eabf2bc1a", //调用链中此条span的ID
            "flags": 1, //获取成功
            //操作名称,每一个span都需要通过一个operation_name创建,必须高度概括
            "operationName": "hipstershop.ProductCatalogService/ListProducts", 
           //Span间关系,每个span必须提供方法访问SpanContext(跨越进程边界传递到下级span的状态)
           "references": [
                {
                    "refType": "CHILD_OF", //父子关系
                    //调用链ID(同一条调用链)
                    "traceID": "3cc530b6c6acc620c3cf99aee18a299c", 
                    //子span的ID
                    "spanID": "4c20971ee967b5ec"
            ], 
            "startTime": 1625961604516295, //追踪起始时间戳(更精确)
            "startTimeMillis": 1625961604516, //追踪起始时间戳
            "duration": 22, //追踪花费时间

            //一组键值对构成的 Span 标签集合,为 Span 添加一些简单解释和补充信息,无时间戳
            //出现true 代表这个span是错误状态,出现false 或没有 error tag ,代表span没有发生错误
            "tags": [
                //RPC Server Tags
                //这些tag作用于基于rpc的服务入口的span
                //此次主要监控的是RPC服务框架
                {
                    "key": "rpc.system", //rpc框架
                    "type": "string", 
                    "value": "grpc"//grpc是一款RPC框架
                }, 
                {
                    "key": "rpc.service", //rpc服务名称
                    "type": "string", 
                    "value": "hipstershop.ProductCatalogService"
                }, 
                {
                    "key": "rpc.method", //rpc请求被处理的方法
                    "type": "string", 
                    "value": "ListProducts"
                }, 
    
                //下面这些tag可以被客户端或者服务端提供,用于描述远程请求过程中,请求调用的方向
                //客户端记录下行访问,服务端记录上行访问
                {
                    "key": "net.peer.ip", //目标IP
                    "type": "string", 
                    "value": "127.0.0.1"
                }, 
                {
                    "key": "net.peer.port", //目标 port
                    "type": "string", 
                    "value": "59270"
                }, 
                
                //自定义instrumentation且用于跟踪本应用内的application及activity生命周期
                //具体不太清楚
                {
                    "key": "instrumentation.name", 
                    "type": "string", 
                    "value": "go.opentelemetry.io/otel/sdk/tracer"
                }, 
                
                //RPC Server Tags
                {
                    "key": "status.code", //rpc返回值
                    "type": "int64", 
                    "value": "0"
                }, 
                {
                    "key": "status.message", //具体报错信息
                    "type": "string", 
                    "value": ""
                }, 
                {
                    "key": "span.kind", //span类型
                    "type": "string", 
                    "value": "server"//指定这个span代表一个服务端,客户端为client
                }, 
                {
                    "key": "internal.span.format", //span格式
                    "type": "string", 
                    "value": "jaeger"//jaeger分布式追踪系统
                }
            ], 
            //这条span里面没有采样Sampling,如果此tag没有提供,追踪系统使用自己的默认采样规则
            //大多数追踪系统通过不同方式实现采样
            //有些情况下,应用系统需要通知追踪程序,这条特定的调用需要被记录,即使根据默认采样规则,它不 需要被记录。
            //追踪系统不保证一定采纳这个参数,但是会尽可能的保留这条调用。
            //由sampling.priority - integer tag 提供这样的方式
            //如果大于 0, 追踪系统尽可能保存这条调用链
            //等于 0, 追踪系统不保存这条调用链
            //如果此tag没有提供,追踪系统使用自己的默认采样规则
            
            //每个span可以进行多次Logs操作
            //每一次日志记录都会包含一个时间戳,并至少包含一个基于键值对的域
            "logs": [
                {
                    "timestamp": 1625961604516301, //时间戳
                    
                    //事件域代表span生命周期内某些关键时间点的标识
                    "fields": [
                        {
                            "key": "message.type", //类型
                            "type": "string", 
                            "value": "RECEIVED"
                        }, 
                        {
                            "key": "message.id", //id
                            "type": "int64", 
                            "value": "1"
                        }, 
                        {
                            "key": "message.uncompressed_size", //大小
                            "type": "int64", 
                            "value": "0"
                        }, 
                        {
                            "key": "name", //名字
                            "type": "string", 
                            "value": "message"
                        }
                    ]
                }, 
                {
                    "timestamp": 1625961604516315, 
                    "fields": [
                        {
                            "key": "message.type", 
                            "type": "string", 
                            "value": "SENT"
                        }, 
                        {
                            "key": "message.id", 
                            "type": "int64", 
                            "value": "1"
                        }, 
                        {
                            "key": "message.uncompressed_size", 
                            "type": "int64", 
                            "value": "1434"
                        }, 
                        {
                            "key": "name", 
                            "type": "string", 
                            "value": "message"
                        }
                    ]
                }
            ], 
            
            //跨进程追踪,提供方法访问SpanContext
            "process": {
                "serviceName": "productcatalogservice", //服务名称
                "tags": [
                    {
                        "key": "exporter", 
                        "type": "string", 
                        "value": "jaeger"
                    }, 
                    {
                        "key": "float", 
                        "type": "float64", 
                        "value": "312.23"
                    }, 
                    {
                        "key": "ip", 
                        "type": "string", 
                        "value": "172.20.6.219"
                    }, 
                    {
                        "key": "name", 
                        "type": "string", 
                        "value": "productcatalogservice-667c4db95c-vghmz"
                    }, 
                    {
                        "key": "node_name", 
                        "type": "string", 
                        "value": "10.0.80.216"
                    }
                ]
            }
        }
    }, 
⚠️ **GitHub.com Fallback** ⚠️