Skip to content

Commit

Permalink
更新可观测内容
Browse files Browse the repository at this point in the history
  • Loading branch information
isno committed Feb 14, 2024
1 parent fe73051 commit 582f047
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ export default defineUserConfig({
children: [
'/ServiceMesh/What-is-ServiceMesh.md',
'/ServiceMesh/MicroService-history.md',
'/ServiceMesh/overview.md'
'/ServiceMesh/overview.md',
'/ServiceMesh/The-future-of-ServiceMesh.md'
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion Observability/What-is-Observability.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 9.1 什么是可观测性

什么是可观测性?观测的是什么?Google Cloud 介绍 OpenTelemetry 时提到了这么一个概念[^1]
什么是可观测性?观测的是什么?Google Cloud 介绍 OpenTelemetry 时提到了这么一个概念 telemetry data [^1]

:::tip telemetry data(遥测数据)

Expand Down
10 changes: 5 additions & 5 deletions Observability/logging.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# 9.2.2 事件日志

对于日志的生产和处理,相信程序员们绝对不会陌生。绝大多数程序员生涯的伊始第一行代码打印 “hello world” 开始,再到从 Nginx 的 access.log 中通过 awk 挖掘信息,而今天只要稍微复杂点的系统,已经很难只依靠 tail、grep、awk 来从日志中挖掘信息。现在对日志的完整处理,除了打印,还包含着日志采集、日志传输、日志清洗、日志存储、分析与检索、告警与智能化响应一系列步骤。
对于日志的生产和处理,相信程序员们绝对不会陌生,绝大多数程序员生涯的第一行代码是从打印 “hello world” 开始,再到通过 awk 挖掘 Nginx 的 access.log 中的信息。而今天只要稍微复杂点的系统,已经很难只依靠 tail、grep、awk 来从日志中挖掘信息。现在对日志的完整处理,除了打印,还包含着日志采集、日志传输、日志清洗、日志存储、分析与检索、告警与智能化响应一系列步骤。

日志的处理和分析是典型的大数据分析场景之一,高吞吐写入、低成本海量存储、实时文本检索,业内通常以 ELK(倒排索引架构,消耗巨大的资源建立索引,巨大的存储成本)和 Grafana Loki(轻量索引,检索性能慢)为代表的两类权衡架构。

## ELK

谈论实现一套完整的日志系统,相信用户或多或少都应该听说过这几个名词:Elasticsearch、ELK 或者 Elastic Stack。
谈论实现一套完整的日志系统,工程师们或多或少都应该听说过这几个名词:Elasticsearch、ELK(B) 或者 Elastic Stack。

:::tip ELKB

ELK 是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch、Logstash 和 Kibana。 Elasticsearch 是一个搜索和分析引擎。 Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。Beats 作为轻量级的数据搬运工,集合了多种单一用途数据采集器,将数据发送给 Logstash 或 ElasticSearch,其可扩展的框架及丰富的预置采集器将使工作事半功倍。
ELK 是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch、Logstash 和 Kibana。Elasticsearch 是一个搜索和分析引擎。 Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。Beats 作为轻量级的数据搬运工,集合了多种单一用途数据采集器,将数据发送给 Logstash 或 ElasticSearch,其可扩展的框架及丰富的预置采集器将使工作事半功倍。
:::

总结起来, ELK 是一组开源组件组成的套件,组件之间作用不用,各司其事,可以像网络协议一样按分层来理解和归类,所以形成一个类似 TCP/IP Stack 类似的 ELK Stack,如下图所示。但明确的是 ELK 中的 Stack 肯定不是协议栈,跟协议没有任何区别。为严谨准确,我们把上面的所有名词简称为 Elastic。
总结起来,ELKB 是一组开源组件组成的套件,组件之间作用不用,各司其事,可以像网络协议一样按分层来理解和归类,形成一个类似 TCP/IP Stack 类似的 ELK Stack,如下图所示。但明确的是 ELK 中的 Stack 肯定不是协议栈,且和协议没有任何关系。为统一明确,本文把上面的所有名词简称为 Elastic。

<div align="center">
<img src="../assets/elk-stac.svg" width = "350" align=center />
<p>Loki 架构:与 Prometheus、Grafana 密切集成</p>
</div>

ELK 中最核心的是 Elasticsearch,它是一个分布式搜索分析引擎,提供一种准实时搜索服务(生产环境中可以做到上报 10 秒后可搜,不惜成本万亿级日志秒级响应)。与 Elasticsearch 类似的产品还有商业公司 Splunk 和 Apache 开源的 Solr。事实上,Elasticsearch 和 Solr 都使用了著名的 Java 信息检索工具包 Lucene,Lucene 的作者就是大名鼎鼎的 Doug Cutting,如果你不知道谁是 Doug Cutting,那你一定听过他儿子玩具的名字 -- Hadoop。
Elastic 中最核心的是 Elasticsearch,它是一个分布式搜索分析引擎,提供一种准实时搜索服务(生产环境中可以做到上报 10 秒后可搜,不惜成本万亿级日志秒级响应)。与 Elasticsearch 类似的产品还有商业公司 Splunk 和 Apache 开源的 Solr。事实上,Elasticsearch 和 Solr 都使用了著名的 Java 信息检索工具包 Lucene,Lucene 的作者就是大名鼎鼎的 Doug Cutting,如果你不知道谁是 Doug Cutting,那你一定听过他儿子玩具的名字 -- Hadoop。


Elasticsearch 在日志场景中的优势在于全文检索能力,能快速从海量的数据中检索出关键词匹配的日志,其底层核心技术是转置索引(Inverted index)。正常的索引是按 ID 查询详情,类似字典通过页码查询内容。转置索引反过来,将每一行文本进行分词,变成一个个词(Term),然后构建词(Term) -> 行号列表(Posting List) 的映射关系,将映射关系按照词进行排序存储。当需要查询某个词在哪些行出现的时候,先在 词 -> 行号列表 的有序映射关系中查找词对应的行号列表,然后用行号列表中的行号去取出对应行的内容。这样的查询方式,可以避免遍历对每一行数据进行扫描和匹配,只需要访问包含查找词的行,在海量数据下性能有数量级的提升。
Expand Down
4 changes: 2 additions & 2 deletions Observability/profiles.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# 9.2.4 Profiles

熟悉 Go 语言的朋友一定了解 pprof,进行性能分析时,通过 pprof 的 CPU profiling 或者 Memory profiling 功能分析函数耗时以及内存占用情况。Profiles 就是进行 profiling 时程序运行的动态画像,当于动态的内部数据,说明各类资源分配的情况,能精确到进程、代码
熟悉 Go 语言的朋友一定了解 pprof,当我们需要对软件进行性能分析时,可以通过 pprof 的 CPU profiling 或者 Memory profiling 功能分析函数耗时以及内存占用情况。此刻,你应该已经理解到 Profiles 就是对动态程序进行 profiling 时程序运行的动态画像,相当于动态程序的各类内部数据,能说明各类资源分配的情况,分析时能定位到具体的函数和代码

Profiles 数据一般表示成火焰图、堆栈图,内存分析图等形式,可以让我们足够细地了解到程序使用各类资源的全貌,是回答从“是什么”到“为什么”的依据,例如通过 trace 了解到延迟在什么地方产生,再通过 Profiles 定位到是哪行代码影响。2021年国内某站崩溃,工程师们就是使用火焰图观察到到一处 Lua 代码存在异常,才找到问题的源头[^1]
Profiles 数据一般表示成火焰图、堆栈图,内存分析图等形式,可以让我们足够细地了解到程序使用各类资源的全貌,是回答从“是什么”到“为什么”的依据,例如通过 trace 获知延迟在什么地方产生,再通过 Profiles 定位到是哪行代码影响。2021年国内某站崩溃,工程师们就是使用火焰图观察到到一处 Lua 代码存在异常,才找到问题的源头[^1]

<div align="center">
<img src="../assets/lua-cpu-flame-graph.webp" width = "500" align=center />
Expand Down
10 changes: 5 additions & 5 deletions Observability/signals.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# 9.2 可观测性数据分类

尽管可观测性这一术语是近年来从控制理论引进的新词,但实际上,它在计算机科学领域已有深厚的实践基础,计算机领域一般会将可观测性的遥测数据分解为三个更具体方向进行研究:事件日志、链路追踪和聚合度量。
尽管可观测性这一术语是近年来从控制理论引进的新词,但实际上,它在计算机科学领域已有深厚的实践基础,计算机领域一般会将可观测性的遥测数据分解为三个更具体方向进行研究:事件日志、链路追踪和聚合度量。以上三个领域虽然各有侧重,但也并非完全孤立,它们之间存在着天然的交集与互补。2017 年的分布式追踪峰会结束后,Peter Bourgon 撰写了总结文章《Metrics, Tracing, and Logging》[^1]系统地阐述了这三者的定义、特征以及它们之间的关系与差异,受到了业界的广泛认可。如下韦恩图所示,三者之间的关系。

<div align="center">
<img src="../assets/observability.jpg" width = "550" align=center />
</div>

- **Metrics(度量)**:传统监控和告警领域的代名词,用来计算事件发生数量的数据集,例如服务 QPS、API 响应延迟、某个接口的失败数等。呈数字化指标出现,特征是具有时间属性、且可聚合,这样既能做常见的监控告警,也可以用来做趋势分析。Metrics 提供的信息可用于系统整体行为和监控状况的分析,它不一定能揭示问题根本原因,但可以作为发现问题的起点。一个典型例子是你收到一条告警”请求成功率跌到了 10%“,你意识到不妙,立即开始处理,结合其他 Signals 找到 root cause,从而解决问题。
- **Logging(日志)**:程序员最熟悉的也是最古老又最具体的 Signal,描述一系列离散的事件,特别是非预期的行为、异常情况。在缺乏有力的 APM 系统时,Logging 数据通常是工程师在定位问题时最直接的手段。如果说 Metrics 告诉你应用程序出现问题,那么 Logging 就告诉你为什么出现问题。日志的采集、存储和查询需要消耗大量资源,应用中通常采样使用。

- **Tracing(追踪)**:分布式系统中多个服务之间或多或少存在依赖,Tracing 通过有向无环图的方式记录分布式系统依赖中发生事件之间的因果关系,从而可以轻松分析出请求中异常点。与日志相同的是会消耗大量的资源,通常也需要根据采样的方式减少数据量。与日志不同的是,追踪技术依赖特定网络协议和语言,这种依赖使得追踪工具需要以插件或者探针的形式进行深度集成,对业务具有一定的侵入性。

以上三个领域虽然各有侧重,但也并非完全孤立,它们之间存在着天然的交集与互补。2017 年的分布式追踪峰会结束后,Peter Bourgon 撰写了总结文章《Metrics, Tracing, and Logging》[^1]系统地阐述了这三者的定义、特征以及它们之间的关系与差异,受到了业界的广泛认可。

<div align="center">
<img src="../assets/observability.png" width = "350" align=center />
</div>

来自于 Cindy Sridharan 的著作《Distributed Systems Observability》进一步将这三个类型的数据称为可观测性的三大支柱(three pillars),不过将它们成为支柱容易让人产生误解,支柱就像一个房子的均匀受力支撑点,缺一不可。而事实上这三者都可以独立存在,系统中只存在 Logging、Tracing 未尝不可。在 CNCF 发布的最新可观测性白皮书中,将这些可观测的数据统一称为信号(Signals),主要的信号除了 Metrics、logs、traces 之外又额外增加了 Profiles 和 Dumps。

Expand Down
39 changes: 36 additions & 3 deletions Observability/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,57 @@
<p>Uber 使用 Jaeger 生成的追踪链路拓扑</p>
</div>

分布式链路追踪诞生的标志性事件就是 Google Dapper 论文的发表。2010年4月,Benjamin H. Sigelman 等人在 Google Technical Report 上发表了《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》[^2],论文详细阐述了 Google 内部分布式链路追踪系统 Dapper 的设计理念,还提出了成为后续链路追踪系统设计的共识的两个概念 Trace(追踪)和 Span(跨度)。
分布式链路追踪诞生的标志性事件就是 Google Dapper 论文的发表。2010年4月,Benjamin H. Sigelman 等人在 Google Technical Report 上发表了《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》[^2]论文,文中详细阐述了 Google 内部分布式链路追踪系统 Dapper 的设计理念,还提出了成为后续链路追踪系统设计共识的两个基础术语 Trace(追踪)和 Span(跨度)。

## Trace 和 Span

一条 Trace 代表一次入口请求在 IT 系统内的完整调用轨迹及其关联数据集合。其中,全局唯一的链路标识 TraceId 是代表性的一个属性,通过 TraceId 我们才能将同一个请求分散在不同节点的链路数据准确的关联起来,实现请求粒度的“确定性关联”。当前,光有 TraceId 还不够,请求在每一跳的接口方法上执行了什么动作、耗时多久、执行状态是成功还是失败?承载这些信息的记录就是跨度(Span)。每一次 Trace 实际上都是由若干个有顺序、有层级关系的 Span 所组成一颗“追踪树”(Trace Tree),如下图所示。
一条 Trace 代表一次入口请求在 IT 系统内的完整调用轨迹及其关联数据集合。其中,全局唯一的链路标识 TraceId 是代表性的一个属性,通过 TraceId 我们才能将同一个请求分散在不同节点的链路数据准确的关联起来,实现请求粒度的“确定性关联”。

Span 代表系统中一个逻辑运行单元,Span 之间通过嵌套或者顺序排列建立因果关系。Span 之内记录着请求在每一跳的接口方法上执行了什么动作、耗时多久、执行状态是成功还是失败,Span 包含的对象如下:

- Operation Name:描述当前接口的行为语义。比如 /api/createOrder 代表执行了一次创建订单的动作。
- SpanId/ParentSpanId:接口调用的层级标识,用来还原 Trace 内部的层调用关系。
- Start/FinishTime:接口调用的开始和结束时间,两者相减是该次调用的耗时。
- StatusCode:响应状态,标识该次调用是成功还是失败。
- Tags & Events:调用附加信息。

每一次 Trace 实际上都是由若干个有顺序、有层级关系的 Span 所组成一颗“追踪树”(Trace Tree),如下图所示。

<div align="center">
<img src="../assets/Dapper-trace-span.png" width = "350" align=center />
<p>Trace 和 Spans</p>
</div>

总结分布式链路追踪的原理就是在分布式应用的接口方法中设置一些观察点,在入口节点给每个请求分配一个全局唯一的标识 traceId,当请求流经这些观察点时就会记录一条对应的链路日志(Span),最后通过 TraceId 将一次请求的所有链路日志进行组装,就能还原出该次请求的链路轨迹。如图所示,根据拓扑图中 Span 记录的时间信息和响应结果,我们就可以定位到出错或者缓慢的服务。
总结分布式链路追踪的原理就是在分布式应用的接口方法中设置一些观察点,在入口节点给每个请求分配一个全局唯一的标识 TraceId,当请求流经这些观察点时就会记录一条对应的链路日志(Span)。最后通过 TraceId 将一次请求的所有链路日志进行组装,就能还原出该次请求的链路轨迹。

如图所示,根据拓扑图中 Span 记录的时间信息和响应结果,我们就可以定位到出错或者缓慢的服务。

<div align="center">
<img src="../assets/skywalking-ui.jpeg" width = "550" align=center />
<p>Skywalking 链路分析</p>
</div>

## 追踪技术的核心

实现追踪的核心技术是方法增强(通常也称为埋点,指的是在代码中插入额外的逻辑来捕获和记录执行信息)。Dapper 的论文中提出的设计原则要求方法增强必须满足应用级透明性和低开销着两个关键条件。

- 应用级透明:开发者不需要修改业务代码或者仅需要极少的修改即可实现埋点,这意味着追踪逻辑对应用层不可见或者几乎不可见。
- 低开销:


**2.基于服务的追踪**,基于服务的追踪是目前最为常见的追踪实现方式,被 Zipkin、SkyWalking、Pinpoint 等主流追踪系统广泛采用。基于服务追踪的实现思路是通过某些手段给目标应用注入追踪探针(Probe),譬如针对 Java 应用,一般就通过 Java Agent 注入。

探针可以看做是一个寄生在目标服务身上的一个小型微服务系统,它一般会有自己的专用服务注册、心跳检测等功能,有专门的数据收集协议,可以把从目标系统监控得到的服务调用信息,通过另一次独立的 HTTP 或者 RPC 请求发送给追踪系统。

因此,基于服务方式的追踪系统会比基于日志的追踪消耗更多的资源,也具有更强的侵入性,而换来的收益就是追踪的精确性和稳定性都有保证,不必再依靠日志归集来传输跟踪数据。


**3.基于边车代理的追踪**,服务网格的专属方案,也是最理想的分布式追踪模型,边车代理对应用完全透明,有自己独立数据通道,追踪数据通过控制平面上报,无论对日志服务本身还是,都不会有依赖和干扰;它与程序语言无法,无论应用采用什么编程语言,只要它通过网络(HTTP或 gRPC)访问服务,就可以被追踪到。如果非要总结种方式的实现有什么缺点,就是边车代理本身对应用透明的原理,决定了它只能实现服务调用层面的追踪。

现在,市场占有率最高的 Envoy 就提供了完善的追踪功能,但没有提供自己的界面端和存储端,需要配合专门的 UI 与存储系统来使用,不过 SkyWalking、Zipkin、Jaeger 等系统都可以接受来自 Envoy 的追踪数据。



## 代表性项目

在没有形成大一统标准的早期,Dapper 的思想和协议影响了大量的开源项目。受到 Dapper 的启发,Twitter 开发了自己的分布式追踪系统 Zipkin,Zipkin 是第一个被广泛采用的开源的分布式链路追踪系统,提供了数据收集、存储和查询的功能以及友好的 UI 界面来展示追踪信息。
Expand Down
1 change: 1 addition & 0 deletions ServiceMesh/The-future-of-ServiceMesh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# 服务网格的未来
Loading

0 comments on commit 582f047

Please sign in to comment.