learn.lianglianglee.com/专栏/SpringCloud微服务实战(完)/21 如何查看各服务的健康状况——系统应用监控.md.html
2022-05-11 18:52:13 +08:00

831 lines
19 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>21 如何查看各服务的健康状况——系统应用监控.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">00 开篇导读.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/01 以真实“商场停车”业务切入——需求分析.md">01 以真实“商场停车”业务切入——需求分析.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/02 具象业务需求再抽象分解——系统设计.md">02 具象业务需求再抽象分解——系统设计.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/03 第一个 Spring Boot 子服务——会员服务.md">03 第一个 Spring Boot 子服务——会员服务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/04 如何维护接口文档供外部调用——在线接口文档管理.md">04 如何维护接口文档供外部调用——在线接口文档管理.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目.md">05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/06 服务多不易管理如何破——服务注册与发现.md">06 服务多不易管理如何破——服务注册与发现.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/07 如何调用本业务模块外的服务——服务调用.md">07 如何调用本业务模块外的服务——服务调用.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/08 服务响应慢或服务不可用怎么办——快速失败与服务降级.md">08 服务响应慢或服务不可用怎么办——快速失败与服务降级.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/09 热更新一样更新服务的参数配置——分布式配置中心.md">09 热更新一样更新服务的参数配置——分布式配置中心.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/10 如何高效读取计费规则等热数据——分布式缓存.md">10 如何高效读取计费规则等热数据——分布式缓存.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/11 多实例下的定时任务如何避免重复执行——分布式定时任务.md">11 多实例下的定时任务如何避免重复执行——分布式定时任务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/12 同一套服务如何应对不同终端的需求——服务适配.md">12 同一套服务如何应对不同终端的需求——服务适配.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/13 采用消息驱动方式处理扣费通知——集成消息中间件.md">13 采用消息驱动方式处理扣费通知——集成消息中间件.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/14 Spring Cloud 与 Dubbo 冲突吗——强强联合.md">14 Spring Cloud 与 Dubbo 冲突吗——强强联合.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/15 破解服务中共性问题的繁琐处理方式——接入 API 网关.md">15 破解服务中共性问题的繁琐处理方式——接入 API 网关.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/16 服务压力大系统响应慢如何破——网关流量控制.md">16 服务压力大系统响应慢如何破——网关流量控制.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/17 集成网关后怎么做安全验证——统一鉴权.md">17 集成网关后怎么做安全验证——统一鉴权.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/18 多模块下的接口 API 如何统一管理——聚合 API.md">18 多模块下的接口 API 如何统一管理——聚合 API.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/19 数据分库后如何确保数据完整性——分布式事务.md">19 数据分库后如何确保数据完整性——分布式事务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/20 优惠券如何避免超兑——引入分布式锁.md">20 优惠券如何避免超兑——引入分布式锁.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/SpringCloud微服务实战/21 如何查看各服务的健康状况——系统应用监控.md">21 如何查看各服务的健康状况——系统应用监控.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/22 如何确定一次完整的请求过程——服务链路跟踪.md">22 如何确定一次完整的请求过程——服务链路跟踪.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/23 结束语.md">23 结束语.md.html</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>21 如何查看各服务的健康状况——系统应用监控</h1>
<p>各个微服务模块基本已经就位,但系统运行的情况是怎么样,有没有办法查看的到呢?本篇就带你一起看看如何查看系统运行时的一些信息。</p>
<h3>Actuator 插件</h3>
<p>细心的小伙伴发现了,每个微服务的 pom 文件配置中都有如下的 jar 引用,这是 Spring Boot 提供的一系列额外特性组件以帮助你监控管理运行中的系统应用。</p>
<pre><code class="language-xml">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre>
<p>除了需要引入对应 jar 包外,还需要指定的配置。由于默认只开放了 health、info 两个 API其它 API 要正常使用,需将 exposure 配置项置为 <code>*</code>,才能正常使用 Actuator 暴露出来的接口。</p>
<pre><code class="language-properties">management.endpoints.web.exposure.include=*
</code></pre>
<p>下图是 Actuator 提供的所有对外接口,左上角四个是 Web 应用独有的。</p>
<p><img src="assets/1585366802627-25dce92f-c9f3-4933-ab2e-b1f9689f09be.jpeg" alt="img" /></p>
<p>启动任意一个应用后,在浏览器中输入网址 http://localhost:10065/actuator/ 就可以查看所有接口地址,响应信息均是以 JSON 形式输出。举例,访问 http://localhost:10065/actuator/metrics浏览器响应信息如下</p>
<p><img src="assets/1585366802627-25dce92f-c9f3-4933-ab2e-b1f9689f09be.jpeg" alt="img" /></p>
<p>通过访问不同的地址,就可以获取关于服务的相关信息,更多 Actuator 组件相关的文档介绍可参见 <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints">Spring Boot Actuator官方文档介绍</a>。但插件返回的信息全部是文本信息,不够直观明了,对监控者而言需要花费不少精力才能解读背后的信息。</p>
<h3>Spring Boot Admin</h3>
<p>这里引入 Spring Boot Admin它是一个 Web 应用,官网地址:</p>
<blockquote>
<p><a href="https://github.com/codecentric/spring-boot-admin">https://github.com/codecentric/spring-boot-admin</a></p>
</blockquote>
<p>它是基于 Actutor在其上做了 UI 美化,对使用者而言可用性大大提高,下面我们来直观地体验一下。</p>
<p><img src="assets/d229b6b0-abb9-11ea-9f6f-19813f3028d9" alt="img" /></p>
<p><img src="assets/c1a077c0-abb9-11ea-80ed-076e906dd9d7" alt="img" /></p>
<p><img src="assets/b0e4de30-abb9-11ea-8f72-51878cbe80a4" alt="img" /></p>
<h3>新建监控服务端</h3>
<p>基于 Spring Boot 快速建立 parking-admin 子模块pom.xml 中加入依赖:</p>
<pre><code class="language-xml">&lt;properties&gt;
&lt;spring.boot.admin.version&gt;2.1.2&lt;/spring.boot.admin.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;de.codecentric&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-admin-starter-server&lt;/artifactId&gt;
&lt;version&gt;${spring.boot.admin.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>application.yml 配置文件:</p>
<pre><code class="language-yaml">server:
port: 10090
management:
endpoints:
web:
exposure:
include: \\*
security:
enabled: false
endpoint:
health:
show-details: ALWAYS
spring:
application:
name: parking-admin
</code></pre>
<p>应用主类也很简单,增加 @EnableAdminServer 注解即可:</p>
<pre><code class="language-java">@EnableAdminServer
@SpringBootApplication
public class BootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(BootAdminApplication.class, args);
}
}
</code></pre>
<p>启动应用后,服务端就算完工了,浏览器打开 <code>localhost:8081</code> 查看 Spring Boot Admin 主页面:</p>
<p><img src="assets/a11f6470-abb9-11ea-b301-356ca9767908" alt="img" /></p>
<p>页面一直处于 Loading 状态,直接到有被监控端应用加入进来。</p>
<h3>添加监控端应用</h3>
<p>直接在相应的需要监控的模块中,引入相应的 client jar 即可。(版本建议与 spring-boot-admin-starter-server 保持一致)</p>
<pre><code class="language-xml">&lt;dependency&gt;
&lt;groupId&gt;de.codecentric&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-admin-starter-client&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre>
<p>相应的 application.properties 中增加配置:</p>
<pre><code class="language-properties">#必须暴露出来不然admin-server无法获取health数据
management.endpoints.web.exposure.include=*
management.security.enabled=false
management.endpoint.health.show-details=ALWAYS
#admin server address
spring.boot.admin.client.url=http://localhost:10090
</code></pre>
<p>就这么两步,其它无须做过多更改,启动主程序类,我们为资源服务为例,返回监控页面,会发现资源服务实例已经被监控到,并罗列在界面中:</p>
<p><img src="assets/8b6f7b60-abb9-11ea-a7f9-7f5598d3120d" alt="img" /></p>
<p>点击应用实例,进入更详细的信息查看,至此通过 Spring Boot Admin 实现的应用监控已可以正常使用。</p>
<p>监控虽然已经跨出代码开发行列,但时下 DevOps、SRE 概念的盛行,开发与运维的界线越为越模糊,合作越来越紧密,了解一些监控知识是很必要的。另外,监控微服务是任何一个微服务架构中都不可或缺的一环。但 Spring Boot Admin 仅仅只能监控应用本身的信息,应用所属的宿主机信息无法监控到,你知道有什么方法可以监控吗?</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/SpringCloud微服务实战/20 优惠券如何避免超兑——引入分布式锁.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/SpringCloud微服务实战/22 如何确定一次完整的请求过程——服务链路跟踪.md">下一页</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":"709975b9785e3cfa","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>