learn.lianglianglee.com/专栏/SpringCloud微服务实战(完)/22 如何确定一次完整的请求过程——服务链路跟踪.md.html
2022-08-14 03:40:33 +08:00

310 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>22 如何确定一次完整的请求过程——服务链路跟踪.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/SpringCloud微服务实战/00 开篇导读.md.html">00 开篇导读</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/01 以真实“商场停车”业务切入——需求分析.md.html">01 以真实“商场停车”业务切入——需求分析</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/02 具象业务需求再抽象分解——系统设计.md.html">02 具象业务需求再抽象分解——系统设计</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/03 第一个 Spring Boot 子服务——会员服务.md.html">03 第一个 Spring Boot 子服务——会员服务</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/04 如何维护接口文档供外部调用——在线接口文档管理.md.html">04 如何维护接口文档供外部调用——在线接口文档管理</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目.md.html">05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/06 服务多不易管理如何破——服务注册与发现.md.html">06 服务多不易管理如何破——服务注册与发现</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/07 如何调用本业务模块外的服务——服务调用.md.html">07 如何调用本业务模块外的服务——服务调用</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/08 服务响应慢或服务不可用怎么办——快速失败与服务降级.md.html">08 服务响应慢或服务不可用怎么办——快速失败与服务降级</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/09 热更新一样更新服务的参数配置——分布式配置中心.md.html">09 热更新一样更新服务的参数配置——分布式配置中心</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/10 如何高效读取计费规则等热数据——分布式缓存.md.html">10 如何高效读取计费规则等热数据——分布式缓存</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/11 多实例下的定时任务如何避免重复执行——分布式定时任务.md.html">11 多实例下的定时任务如何避免重复执行——分布式定时任务</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/12 同一套服务如何应对不同终端的需求——服务适配.md.html">12 同一套服务如何应对不同终端的需求——服务适配</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/13 采用消息驱动方式处理扣费通知——集成消息中间件.md.html">13 采用消息驱动方式处理扣费通知——集成消息中间件</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/14 Spring Cloud 与 Dubbo 冲突吗——强强联合.md.html">14 Spring Cloud 与 Dubbo 冲突吗——强强联合</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/15 破解服务中共性问题的繁琐处理方式——接入 API 网关.md.html">15 破解服务中共性问题的繁琐处理方式——接入 API 网关</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/16 服务压力大系统响应慢如何破——网关流量控制.md.html">16 服务压力大系统响应慢如何破——网关流量控制</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/17 集成网关后怎么做安全验证——统一鉴权.md.html">17 集成网关后怎么做安全验证——统一鉴权</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/18 多模块下的接口 API 如何统一管理——聚合 API.md.html">18 多模块下的接口 API 如何统一管理——聚合 API</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/19 数据分库后如何确保数据完整性——分布式事务.md.html">19 数据分库后如何确保数据完整性——分布式事务</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/20 优惠券如何避免超兑——引入分布式锁.md.html">20 优惠券如何避免超兑——引入分布式锁</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/21 如何查看各服务的健康状况——系统应用监控.md.html">21 如何查看各服务的健康状况——系统应用监控</a>
</li>
<li>
<a class="current-tab" href="/专栏/SpringCloud微服务实战/22 如何确定一次完整的请求过程——服务链路跟踪.md.html">22 如何确定一次完整的请求过程——服务链路跟踪</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/23 结束语.md.html">23 结束语</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>22 如何确定一次完整的请求过程——服务链路跟踪</h1>
<p>微服务体系下,一个请求会调用多个服务,整个请求就会形成一个调用链,普通的日志输出是无法将整个体系串联起来,调用过程中某一个节点出现异常,定位排查难度系数增高,这种情况下就需要一个组件,来分析系统性能、展现调用链路,以便出现故障时快速定位并解决问题,由此 APM 工具闪亮登场。</p>
<h3>APM 是什么</h3>
<p>全称是 Application Performance Management关注于系统内部执行、系统间调用的性能瓶颈分析与传统监控软件比如 Zabbix只提供一些零散的监控点和指标相比即便告警也不知道问题是出在哪里。</p>
<p>抛开商业工具先不谈开源产品就有许多Pinpoint、Zipkin、CAT、SkyWalking 等,产品间比较,网络中有相当多的资料来解读,本篇案例实战中采用 SkyWalking 来监控系统,来看看 APM 的功效。</p>
<p>为什么采用 SkyWalking 呢?国内优秀开源项目,更符合国人的开发使用习惯,对国内生态兼容的更好,目前已经捐献给 Apache 组织,影响力进一步扩大、社区活跃度也很高。另外,它透过字节码注入这种无侵入的方式来监控系统,大大降低第三方工具对系统的代码污染。</p>
<h3>安装 SkyWalking</h3>
<p>下载地址(国内镜像):</p>
<blockquote>
<p><a href="https://mirrors.tuna.tsinghua.edu.cn/apache/skywalking/">https://mirrors.tuna.tsinghua.edu.cn/apache/skywalking/</a></p>
</blockquote>
<p>解压后目录如下:</p>
<p><img src="assets/9aa148b0-b1f0-11ea-bd8b-f5b5dd060a76" alt="img" /></p>
<p>进入 config 文件夹,打开主配置文件 application.yml可以发现 SkyWalking 有几种支持集群配置方式ZooKeeper、Nacos、Etcd、Consul、Kubernates本示例以单机版演示。SkyWalking 支持三种存储方式H2、MySQL、ElasticSearch 三种H2 默认将数据存储在内存中,重启后数据丢失。官方推荐 ElasticSearch结果不言而喻ElasticSearch 存储更快更多。</p>
<h4><strong>安装 ElasticSearch</strong></h4>
<p>下载 ElasticSearch官方下载需要梯子</p>
<blockquote>
<p><a href="https://thans.cn/mirror/elasticsearch.html">https://thans.cn/mirror/elasticsearch.html</a></p>
</blockquote>
<p>我下载的是 Mac 版本,注意版本兼容问题,本处采用 6.8.x如果采用 ES 7+ 版本,在与 SkyWalking 融合时,会出现数据无法写入的情况。</p>
<p>解压目录如下:</p>
<p><img src="assets/89463ad0-b1f0-11ea-9720-1767a279d140" alt="img" /></p>
<p>启动 ElasticSearch<code>-d</code> 为后台运行方式)</p>
<p><img src="assets/7b9437c0-b1f0-11ea-b251-5b2a75be970d" alt="img" /></p>
<p>访问 http://127.0.0.1:9200/,注意正常情况下输出页面,表明 ElasticSearch 安装成功。</p>
<p><img src="assets/6e0af260-b1f0-11ea-b251-5b2a75be970d" alt="img" /></p>
<h4><strong>配置 SkyWalking</strong></h4>
<p>打开主配置文件,修改配置相应:</p>
<p><img src="assets/5efdf330-b1f0-11ea-93d2-c1260a2f08e6" alt="img" /></p>
<p>变更存储方式为 ElasticSearch采用默认配置同时注释掉原来的 h2 配置。</p>
<h4><strong>安装监控台</strong></h4>
<p>配置 webapp 目录下的 webapp.yml 文件,变更默认超时时间 10000变更 <code>server.por t= 13800</code>,(原有的 8080 端口与默认的 sentinel-dashboard 端口冲突)如果超时,适当调大一些。</p>
<p>以上配置结束后,启动 SkyWalking访问 SkyWalking 的 UIhttp://127.0.0.1:8080正常如下</p>
<p><img src="assets/4e1f6850-b1f0-11ea-9c5b-879a3fcf9fcf" alt="img" /></p>
<p>日志显示启动成功,管理平台页面 默认端口 8080登录信息 admin/admin打开浏览器地址显示如下</p>
<p><img src="assets/40420f80-b1f0-11ea-9720-1767a279d140" alt="img" /></p>
<h4><strong>安装客户端</strong></h4>
<p>agent 俗称探针,以无侵入的方式来收集和发送数据到归集器。本案例以 Java 的方式加载探针,即 <code>java -jar</code> 的方式。在测试前,首先要构建出 jar 包。在 Eclipse 的根项目中执行 <code>&quot;maven install&quot;</code> 命令,构建输出 jar 包。</p>
<p>我的 SkyWalking agent 所在目录:</p>
<blockquote>
<p>/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar</p>
</blockquote>
<p>构建 jar 过程中出现一个小插曲,启动后显示异常:</p>
<pre><code class="language-shell">appledeMacBook-Air:target apple$ java -jar parking-member.jar
parking-member.jar 中没有主清单属性
</code></pre>
<p>虽然 pom 配置中引用了 spring-boot-maven-plugin 插件但构建出的jar依然无法找到主清单启动服务由于我们的 parent 标签为自定义,无法按照标准的 spring-boot-starter-parent 方式构建可执行 jar这里要特殊处理一下增加如下配置项才能达到与 spring-boot-starter-parent 一样的效果,在每个子模块的 pom 中增加此配置,重新测试可以正常启动。</p>
<pre><code class="language-xml">&lt;executions&gt;
&lt;execution&gt;
&lt;goals&gt;
&lt;goal&gt;repackage&lt;/goal&gt;
&lt;/goals&gt;
&lt;/execution&gt;
&lt;/executions&gt;
</code></pre>
<p>先拿 member 启动一个 agent看数据能否正常写入 Elasticsearch 库中去,在终端窗口中执行如下命令:</p>
<pre><code class="language-shell">java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-member-service -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-member-service.jar
</code></pre>
<p>查看 agent 目录的日志文件 skywalking-api.log可以看到客户端正常运行</p>
<pre><code class="language-verilog">DEBUG 2020-02-05 11:45:06:003 SkywalkingAgent-5-ServiceAndEndpointRegisterClient-0 ServiceAndEndpointRegisterClient : ServiceAndEndpointRegisterClient running, status:CONNECTED.
</code></pre>
<p>按以上方式,多启动几个应用,并执行几个业务逻辑功能,比如会员绑定用户手机号、开通月卡、付费离场等等,来看下 SkyWalking 的数据收集、展现情况。</p>
<blockquote>
<p>注意后面的 jar 执行包路径,如下命令是基于当前目录下执行的操作。</p>
</blockquote>
<pre><code class="language-shell">java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-card-service -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-card-service.jar
java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-admin-server -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-admin-server.jar
java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-gateway-service -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-gateway.jar
java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-resource-service -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-resource.jar
java -javaagent:/Users/apple/software/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=parking-message-service -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar parking-message-service.jar
</code></pre>
<h3>监控台数据展现</h3>
<p>刷新 SkyWalking 的 UI 界面,可以看到已经有数据收集到。(重点关注图中彩色框框住的三个关键区域)</p>
<p><img src="assets/c7d16370-b1ef-11ea-a86d-6bef2be14d31" alt="img" /></p>
<p><img src="assets/d5df1b10-b1ef-11ea-9720-1767a279d140" alt="img" /></p>
<p><img src="assets/e5929370-b1ef-11ea-9720-1767a279d140" alt="img" /></p>
<p><img src="assets/f3b4bd70-b1ef-11ea-9393-5b60e11add67" alt="img" /></p>
<p><img src="assets/01819b80-b1f0-11ea-bd8b-f5b5dd060a76" alt="img" /></p>
<p>服务、服务实例、服务接口、数据库的性能监控,服务间的引用关系,服务接口的链路跟踪等等,都能从监控台找到相应的展现,我们这里重点关注下服务请求的链路跟踪。</p>
<h4><strong>请求链路案例分析</strong></h4>
<p>找一个涉及到两个以上服务的链路,深入分析一下,以会员绑定手机号为例子,请求调用到涉及会员服务、月卡服务两个。</p>
<p><img src="assets/18b51750-b1f0-11ea-93f9-195c98efcdf6" alt="img" /></p>
<p>左侧为请求端点显示:蓝色是正常的,红色是异常请求。</p>
<p>图中顶部棕色框圈住的部分是 traceid什么是 traceid这是一个全局的请求标识从源头请求开始中间涉及到的所有服务接口调用都携带此全局标识用于标记这是一次完整的请求链路通过这一 id 将所有请求串联起来,形成一个调用树,如上图中蓝色箭头所示的位置。</p>
<p>从中显露出两个信息:</p>
<ol>
<li>一条完整的请求链路,可以跟踪相应的日志信息(借助日志工具,比如 ELK</li>
<li>链路中的节点耗时,为后期优化提供了确切证据</li>
</ol>
<p>至此,本篇带你使用 SkyWalking 融合到微服务中去,为微服务系统的正常运行保驾护航。有兴趣的同学,可以对照安装下其它的几个监控系统,对比一下,才能发现各自的优劣。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/SpringCloud微服务实战/21 如何查看各服务的健康状况——系统应用监控.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/SpringCloud微服务实战/23 结束语.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709975bbcde83cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>