分布式系统下的服务实例(01.分布式服务追踪与调用链系统)
分布式系统下的服务实例(01.分布式服务追踪与调用链系统)1.Sleuth可以结合Zipkin可以实现界面化的形式管理我们接口依赖信息;2.官方文档地址如下:https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.0.1.RELEASE/single/spring-cloud-sleuth.html2. 阿里的鹰眼系统3. Skywalking(非常推荐大家使用 功能非常强大)---Skywalking1.Spring Cloud Sleuth实现了一种分布式的服务链路跟踪解决方案,通过使用Sleuth可以让我们快速定位某个服务的问题。
产生背景在微服务系统中,随着业务的发展,系统会变得越来越大,那么各个服务之间的调用关系也就变得越来越复杂。一个 HTTP 请求会调用多个不同的微服务来处理返回最后的结果,在这个调用过程中,可能会因为某个服务出现网络延迟过高或发送错误导致请求失败,这个时候,对请求调用的监控就显得尤为重要了。Spring Cloud Sleuth 提供了分布式服务链路监控的解决方案。下面介绍 Spring Cloud Sleuth 整合 Zipkin 的解决方案。
分布式服务追踪系统优点1.RPC远程调用过程中,服务与服务依赖的关系非常复杂,A调用B服务,B服务C服务 如果某个服务出现问题可能会导致整个链响应延迟;
2.如果服务的依赖关系非常复杂,建议改成MQ异步的形式。
服务追踪常用框架1. Sleuth Zipkin SpringCloud封装了 Sleuth Zipkin
2. 阿里的鹰眼系统
3. Skywalking(非常推荐大家使用 功能非常强大)---Skywalking
Sleuth Zipkin1.Spring Cloud Sleuth实现了一种分布式的服务链路跟踪解决方案,通过使用Sleuth可以让我们快速定位某个服务的问题。
2.官方文档地址如下:https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.0.1.RELEASE/single/spring-cloud-sleuth.html
服务追踪常见名词1.Sleuth可以结合Zipkin可以实现界面化的形式管理我们接口依赖信息;
2.Sleuth 每一次RPC远程调用请求都会生成一个spanid记录每一次rpc请求的信息,还有一个traceid 全局唯一id;
3.spanid为请求单元ID、traceid 为请求链全局id
构建分布式服务追踪调用链系统ZipkinServer环境搭建在 Spring Boot 2.0 版本之后,官方已不推荐自己搭建定制了,而是直接提供了编译好的 jar 包。详情可以查看官网:https://zipkin.io/pages/quickstart.html
注意:zipkin官网已经提供定制了,使用官方jar运行即可。
相关依赖下载:https://note.youdao.com/ynoteshare/index.html?id=d2e8f0a302cf0f709e79fe9da4e9556f&type=note&_time=1637654916654
默认端口号启动zipkin服务
java –jar zipkin.jar 默认端口号; 9411
http://127.0.0.1:9411
指定端口号启动9411
java -jar zipkin.jar --server.port=8080
http://192.168.18.220:8080
客户端整合ZipkinMaven依赖<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
配置文件中新增
zipkin:
base-url: http://127.0.0.1:9411/
###全部采集
sleuth:
sampler:
probability: 1.0
请求头中获取TraceID
log.info("<X-B3-TraceId>:{}" request.getHeader("X-B3-TraceId"));
log.info("<X-B3-SpanId>:{}" request.getHeader("X-B3-SpanId"));
log.info("<X-B3-ParentSpanId>:{}" request.getHeader("X-B3-ParentSpanId"));
X-B3-TraceId:对应TraceID;
X-B3-SpanId:对应SpanID;
X-B3-ParentSpanId:前面一环的SpanID;
X-B3-Sampled:是否被选中抽样输出;
X-Span-Name:工作单元名称。
微信公众号环境搭建课程标题:<如何构建分布式 APM 服务监控系统>
1.什么是APM?
2.如何实现服务监控
3.什么是SkyWalking
4.SkyWalking如何实现警告?
5.如何实现告警调用微信公众号接口
6.构建微信公众号服务
7.构建微信公众号微信模板
7.SkyWalking监控服务报错调用微信公众号模板
如果系统发生报错的话 ,可以通过哪些手段拦截?
1.aop的形式 异常通知
2.全局捕获异常
搭建微信公众号环境1.导入开源的微信公众号框架项目 weixin-java-mp-demo-springboot-master
2. 申请一个测试的微信公众号
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login&token=579271486&lang=zh_CN
3.免费为每个用户分配一个测试的appid和秘钥
appID
wx5c43fde3c9733d9e
appsecret
b8b217126c33a5fb7074927d5e72a81a
openid: 微信公众号开放的唯一userid-------
4.拷贝 weixin-java-mp-demo-springboot-master 依赖和pom 配置
相关依赖下载:https://note.youdao.com/ynoteshare/index.html?id=d2e8f0a302cf0f709e79fe9da4e9556f&type=note&_time=1637654916654
mayikt-wx-message
对接微信公众号模板接口对接阿里云短信接口:需要先创建微信模板,通过调用接口传递。
是完全免费的---如果是在生产环境 千万不要去用测试微信公众号。
先申请一个正式公众号“每特教育故障提醒”不需要花费钱 免费。
1.微信公众号创建模板信息
http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
服务名称:{{first.DATA}}
IP和端口:{{keyword1.DATA}}
错误内容:{{keyword2.DATA}}
错误时间:{{keyword3.DATA}}
发生了系统错误,请您及登录服务器查看并且解决。
2.模板创建成功之后 会返回一个 模板id:3pG8ePjjcqhxGXh6cb_rQ5JgXP_TGLamqkgs5bmBI54
3.发送微信模板代码
package com.mayikt.api.message;
import com.mayikt.api.message.dto.ServiceErrorDto;
import com.mayikt.wx.mp.config.WxMpConfiguration;
import com.mayikt.wx.mp.config.WxMpProperties;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author 余胜军
* @ClassName WechatTemplateService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@RestController
@Slf4j
public class WechatTemplateService {
@Autowired
private WxMpProperties wxMpProperties;
@Value("${mayikt.errorTemplateId}")
private String errorTemplateId;
/**
* 调用该接口发送微信模板错误推送
*
* @param serviceErrorDto
* @return
*/
// @RequestMapping("sendWechatTemplateError")
// public String sendWechatTemplateError(ServiceErrorDto serviceErrorDto) {
// WxMpTemplateMsgService wxMpTemplateMsgService = WxMpConfiguration.getMpServices().get("wx5c43fde3c9733d9e").getTemplateMsgService();
// WxMpTemplateMessage wxMpTemplateMessage = new WxMpTemplateMessage();
// wxMpTemplateMessage.setTemplateId("3pG8ePjjcqhxGXh6cb_rQ5JgXP_TGLamqkgs5bmBI54");
// wxMpTemplateMessage.setToUser("okYSmtzp4wWCrDCncMfGSRECVSeM");
// List<WxMpTemplateData> data = new ArrayList<>();
// data.add(new WxMpTemplateData("first" "mayikt-member"));
// data.add(new WxMpTemplateData("keyword1" "192.168.110.1:8080"));
// data.add(new WxMpTemplateData("keyword2" "空指针异常"));
// SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd ");
// String format = formatter.format(new Date());
// data.add(new WxMpTemplateData("keyword3" format " 20:30"));
// wxMpTemplateMessage.setData(data);
// wxMpTemplateMessage.setUrl("http://www.mayikt.com");
// try {
// wxMpTemplateMsgService.sendTemplateMsg(wxMpTemplateMessage);
// } catch (Exception e) {
// e.printStackTrace();
//// userMapper.updateByUserIdOpenIdIsNull(openId);
//// UpdateWrapper<FollowOpenId> followOpenIdUpdateWrapper = new UpdateWrapper<>();
//// followOpenIdUpdateWrapper.eq("open_id" openId);
//// followOpenIdMapper.delete(followOpenIdUpdateWrapper);
// }
// return "ok";
// }
}
4.优化该代码:
@Autowired
private WxMpProperties wxMpProperties;
@Value("${mayikt.errorTemplateId}")
private String errorTemplateId;
@RequestMapping("sendWechatTemplateError")
public String sendWechatTemplateError(@RequestBody ServiceErrorDto serviceErrorDto) {
WxMpTemplateMsgService wxMpTemplateMsgService = WxMpConfiguration.getMpServices().get(wxMpProperties.getConfigs().get(0).getAppId()).getTemplateMsgService();
WxMpTemplateMessage wxMpTemplateMessage = new WxMpTemplateMessage();
wxMpTemplateMessage.setTemplateId(errorTemplateId);
wxMpTemplateMessage.setToUser(serviceErrorDto.getOpenId());
List<WxMpTemplateData> data = new ArrayList<>();
data.add(new WxMpTemplateData("first" serviceErrorDto.getServiceName()));
data.add(new WxMpTemplateData("keyword1" serviceErrorDto.getIp() ":" serviceErrorDto.getPort()));
data.add(new WxMpTemplateData("keyword2" serviceErrorDto.getErrorMsg()));
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = formatter.format(serviceErrorDto.getErrorTime());
data.add(new WxMpTemplateData("keyword3" format));
wxMpTemplateMessage.setData(data);
wxMpTemplateMessage.setUrl("http://www.mayikt.com");
try {
wxMpTemplateMsgService.sendTemplateMsg(wxMpTemplateMessage);
} catch (Exception e) {
log.error("<e:>" e);
}
return "ok";
}
import lombok.Data;
import java.util.Date;
/**
* @author 余胜军
* @ClassName ServiceErrorDto
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Data
public class ServiceErrorDto {
/**
* ip地址
*/
private String ip;
/**
* 端口号
*/
private Integer port;
/**
* 服务的名称
*/
private String serviceName;
/**
* 错误内容
*/
private String errorMsg;
/**
* 错误时间
*/
private Date errorTime;
/**
* 用户的关注微信公众号的 openId
*/
private String openId;
}
5.测试json数据
{
"ip":"192.168.110.1"
"port":8080
"serviceName":"mayikt-member"
"errorMsg":"null"
"errorTime":"2021-11-23 00:16:47"
"openId":"okYSmtzp4wWCrDCncMfGSRECVSeM"
}
127.0.0.1:9099/sendWechatTemplateError
创建springboot项目1.定义一段测试代码:
@RestController
public class MayiktService {
@RequestMapping("/mayikt")
public String mayikt(Long id) {
return "ok" 1 % id;
}
}
2.定义全局捕获异常
import com.alibaba.fastjson.JSONObject;
import com.mayikt.service.asyn.AsynSendWechatTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.client.RestTemplate;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
/**
* 全局捕获异常
*/
@ControllerAdvice
@Slf4j
public class MyExceptionHandler {
@Value("${server.port}")
private String serverPort;
@Value("${spring.application.name}")
private String serviceName;
@Autowired
private AsynSendWechatTemplate asynSendWechatTemplate;
@ExceptionHandler(value = Exception.class)
public String exceptionHandler(Exception e) {
log.error("未知异常!原因是:" e);
JSONObject data = new JSONObject();
data.put("ip" getIpAddress());
data.put("port" serverPort);
data.put("serviceName" serviceName);
data.put("errorMsg" e.getLocalizedMessage());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = formatter.format(new Date());
data.put("errorTime" format);
data.put("openId" "okYSmtzp4wWCrDCncMfGSRECVSeM");
// HttpHeaders headers = new HttpHeaders();
// MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
// headers.setContentType(type);
// headers.add("Accept" MediaType.APPLICATION_JSON.toString());
// HttpEntity<String> formEntity = new HttpEntity<String>(data.toString() headers);
// String result = restTemplate.postForEntity("http://127.0.0.1:9099/sendWechatTemplateError" formEntity String.class).getBody();
// log.info("result:" result);
asynSendWechatTemplate.sendWechatTemplate(data);
return "系统出现错误!";
}
public static String getIpAddress() {
String hostAddress = "";
try {
InetAddress address = InetAddress.getLocalHost();
hostAddress = address.getHostAddress();
} catch (UnknownHostException e) {
}
return hostAddress;
}
}
3.注入restTemplate
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
4.优化代码 改成异步实现
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
/**
* @author 余胜军
* @ClassName AsynSendWechatTemplate
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Component
@Slf4j
public class AsynSendWechatTemplate {
private static ArrayBlockingQueue<JSONObject> arrayBlockingQueue =
new ArrayBlockingQueue<JSONObject>(1024);
@Autowired
private RestTemplate restTemplate;
public AsynSendWechatTemplate() {
new Thread(new ThreadAsynSendWechatTemplate()).start();
}
/**
* 存入到 队列中
*
* @param data
*/
public void sendWechatTemplate(JSONObject data) {
arrayBlockingQueue.offer(data);
}
class ThreadAsynSendWechatTemplate implements Runnable {
@Override
public void run() {
while (true) {
JSONObject data = arrayBlockingQueue.poll();
if (data != null) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept" MediaType.APPLICATION_JSON.toString());
HttpEntity<String> formEntity = new HttpEntity<String>(data.toString() headers);
String result = restTemplate.postForEntity("http://127.0.0.1:9099/sendWechatTemplateError" formEntity String.class).getBody();
log.info("result:" result);
}
try {
// 避免cpu飙高的问题
Thread.sleep(100);
} catch (Exception e) {
}
}
}
}
public static String getIpAddress() {
String hostAddress = "";
try {
InetAddress address = InetAddress.getLocalHost();
hostAddress = address.getHostAddress();
} catch (UnknownHostException e) {
}
return hostAddress;
}
}
skyWalking
课程标题:<基于skyWalking构建企业级apm服务监控系统>
1.什么是skyWalking
2.skyWalking架构设计原理
3.skyWalking实现服务监控
4.SkyWalking如何实现警告?
5.SkyWalking监控服务报错调用微信公众号模板
6.SkyWalking数据库持久化方案
20点25分准时开始
SkyWalking是一个开源的观测平台,用于从服务和云原生等基础设施中收集、分析、聚合以及可视化数据,SkyWalking 提供了一种简便的方式来清晰地观测分布式系统,甚至可以观测横跨不同云的系统,SkyWalking 更像是一种现代的应用程序性能监控(Application Performance Monitoring,即APM)工具,专为云原生,基于容器以及分布式系统而设计。
监控--分布式追踪调用链 、jvm内存变化、智能报警、cpu飙高、服务器基本配置信息
(图片摘自:http://skywalking.apache.org/ )
SkyWalking 无侵入式的收集 不需要引入任何的jar 启动的时候
被我们agent代理拦截即可---jdk提供一种技术 应用程序
对服务器监控(服务堆内存、cpu使用率、服务报错信息)
aop技术
请求前
rpc请求前后
请求后
在我们项目中引入它的jar
1. 探针:基于不同的来源探针可能是不一样的,但作用都是收集数据,将数据格式化为SkyWalking 适用的格式。例如在Java中则是做字节码植入,无侵入式的收集,并通过 HTTP 或者 GRPC 方式发送数据到平台后端 通过Agent技术 代理主函数
SkyWalking Agent 代理主程序 采集日志
Elk kafka aop技术采集日志
2.平台后端:是一个支持集群模式运行的后台,用于数据聚合、数据分析以及驱动数据流从探针到用户界面的流程。平台后端还提供了各种可插拔的能力,如不同来源数据(如来自Zipkin)格式化,不同存储系统以及集群管理。你甚至还可以使用观测分析语言来进行自定义聚合分析。
3.存储:是开放式的,可以选择一个既有的存储系统,如ElasticSearch、H2 或 MySQL 集群(Sharding-Sphere 管理),也可以选择自己实现一个存储系统。
用户界面:也就是SkyWalking的可视化界面,UI非常炫酷且强大,同样它也是可定制以匹配你已存在的后端的
4.SkyWalking 为观察和监控分布式系统提供了许多不同场景下的解决方案。例如为Java、C#及Node.js提供语言自动探针,无侵入式的收集。同时也为一些编译型语言C 、GO等提供了手动打点 SDK(目前还未支持)。除此之外,还可以使用服务网格基础探针来收集数据,以帮助了解整个分布式系统。
5.在SkyWalking中也存在服务、服务实例及端点概念,因为SkyWalking就是提供了这些概念的观测能力:
6.服务(Service):表示对请求提供相同行为的一系列或一组工作负载。在使用打点代理或 SDK 的时候,你可以定义服务的名字。如果不定义的话,SkyWalking 将会使用你在平台上定义的名字,如 Istio。
7.服务实例(Service Instance):上述的一组工作负载中的每一个工作负载称为一个实例。就像 Kubernetes 中的 pods 一样,服务实例未必就是操作系统上的一个进程。但当你在使用打点代理的时候, 一个服务实例实际就是操作系统上的一个真实进程。
端点(Endpoint):对于特定服务所接收的请求路径,如 HTTP 的 URI 路径和 gRPC 服务的类名 方法签名
综上,SkyWalking 优势如下:
8.多种监控手段,语言探针和服务网格(Service Mesh)
模块化,UI、存储、集群管理多种机制可选
支持告警
优秀的可视化方案:
http://skywalking.apache.org/
skywalking架构原理在整个skywalking的系统中,有四个角色:
1.skywalking agent和业务系统关联在一起,负责收集各种监控数据;
2.oapservice是负责处理监控数据的,比如接受skywalking agent的监控数据,并存储在数据库中(例如elasticsearch、mysql中等);接受skywalking webapp的前端请求,从数据库查询数据,并返回数据给前端。,Skywalking oapservice通常以集群的形式存在;
3.skywalking webapp,前端界面,用于展示数据;
4.用于存储监控数据的数据库,比如mysql、elasticsearch等;
skywalking 底层原理是?
1.springboot项目启动的时候 是不需要引入任何的jar包,
2.启动springboot项目被skywalking skywalking-agent.jar 拦截
3.将rpc请求数据 发送给我们的skywalking oapservice接口项目
4.连接到我们的skywalking webapp项目展示数据
5.数据最终是可以持久化存放在 db或者es中。
skywalking 环境安装1. 下载apache-skywalking-apm-6.5.0.tar安装包
相关依赖下载:https://note.youdao.com/ynoteshare/index.html?id=d2e8f0a302cf0f709e79fe9da4e9556f&type=note&_time=1637654916654
2. 进入到bin目录(直接双击启动startup.bat)
3. 启动启动oapService和我们的webappService
4. 查看管理界面http://127.0.0.1:8080/
agent 里面 skywalking-agent.jar 代理 springboot应用程序
logs ---日历目录
skywalking-oap-server.log
springboot实现监控1. 创建一个springboot项目
2. 将该springboot项目打成jar包 mvn package
3. java -javaagent:skywalking-agent.jar路径 -jar springboot jar包
范例:
D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent>java -javaagent:D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent\skywalking-agent.jar -jar D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent\mayikt-thymeleaf-1.0-SNAPSHOT.jar
4. 访问接口测试http://127.0.0.1:9095/mayikt/getUser?age=1
为了避免skywalking 展示数据延迟问题,建议 将自动刷新改为1-3s
大家在演示效果的过程中,如果没有任何数据 注意:手动点击
5.agent\config\agent.config 修改应用的名称
agent.service_name=${SW_AGENT_NAME:mayiktAppDemo}
6.Idea 相关的配置:
-javaagent:D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent\skywalking-agent.jar
-Dskywalking.agent.service_name=mayikt-member
-Dskywalking.collector.backend_service=127.0.0.1:11800
feign客户端整合SkyWalkingSkywalking(6.5.0) 支持的Rpc框架有以下几种:
Dubbo 2.5.4 -> 2.6.0
Dubbox 2.8.4
Apache Dubbo 2.7.0
Motan 0.2.x -> 1.1.0
gRPC 1.x
Feign客户端
1.启动生产者与消费者服务
2.生产者服务启动
-javaagent:D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent\skywalking-agent.jar
-Dskywalking.agent.service_name=mayikt-producer
-Dskywalking.collector.backend_service=127.0.0.1:11800
3.消费者服务启动
-javaagent:D:\path\cloud\apache-skywalking-apm-6.5.0\apache-skywalking-apm-bin\agent\skywalking-agent.jar
-Dskywalking.agent.service_name=mayikt-consumer
-Dskywalking.collector.backend_service=127.0.0.1:11800
4.访问接口
http://127.0.0.1:9008/orderToMember?id=0
5.演示效果:
SkyWalking获取全局追踪idmaven依赖:
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>6.5.0</version>
</dependency>
生产者接口:
@RequestMapping("/member")
public String orderToMember(@RequestParam("id") Integer id) {
// 获取request对象
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
getHeders(request);
// 获取traceId
String traceId = TraceContext.traceId();
log.info(">>traceId:{}<<" traceId);
Integer j = 1 / id;
return "我是会员服务:" traceId " " j;
}
public static void getHeders(HttpServletRequest request) {
//2.获得所有头的名称
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {//判断是否还有下一个元素
String nextElement = headerNames.nextElement();//获取headerNames集合中的请求头
String header2 = request.getHeader(nextElement);//通过请求头得到请求内容
log.info("请求头=========={}" nextElement "VALUE:" header2);
//System.out.println(nextElement ":" header2);
}
}
SkyWalking告警
SkyWalking 告警功能
SkyWalking 告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中
SkyWalking 的发行版都会默认提供config/alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:
1.过去3分钟内服务平均响应时间超过1秒
2.服务成功率在过去2分钟内低于80%
3.服务90%响应时间在过去3分钟内低于1000毫秒
4.服务实例在过去2分钟内的平均响应时间超过1秒
5.端点平均响应时间过去2分钟超过1秒
1.SkyWalking 调用开发者自己定义 接受报警接口;
2.开发者接受报警内容之后 在去调用微信公众号接口发送模板提醒
接受数据的格式[{
"scopeId": 1
"scope": "SERVICE"
"name": "serviceA"
"id0": 12
"id1": 0
"ruleName": "service_resp_time_rule"
"alarmMessage": "alarmMessage xxxx"
"startTime": 1560524171000
} {
"scopeId": 1
"scope": "SERVICE"
"name": "serviceB"
"id0": 23
"id1": 0
"ruleName": "service_resp_time_rule"
"alarmMessage": "alarmMessage yyy"
"startTime": 1560524171000
}]
scopeId、scope:所有可用的 Scope 详见
org.apache.skywalking.oap.server.core.source.DefaultScopeDefine
name:目标 Scope 的实体名称
id0:Scope 实体的 ID
id1:保留字段,目前暂未使用
ruleName:告警规则名称
alarmMessage:告警消息内容
startTime:告警时间,格式为时间戳
编写告警系统接口1.封装报警参数的对象
/**
* 封装报警参数的对象
*/
public class AlarmMessageDto {
private int scopeId;
private String name;
private int id0;
private int id1;
private String alarmMessage;
private long startTime;
public int getScopeId() {
return scopeId;
}
public String getName() {
return name;
}
public int getId0() {
return id0;
}
public int getId1() {
return id1;
}
public String getAlarmMessage() {
return alarmMessage;
}
public long getStartTime() {
return startTime;
}
public void setScopeId(int scopeId) {
this.scopeId = scopeId;
}
public void setName(String name) {
this.name = name;
}
public void setId0(int id0) {
this.id0 = id0;
}
public void setId1(int id1) {
this.id1 = id1;
}
public void setAlarmMessage(String alarmMessage) {
this.alarmMessage = alarmMessage;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
}
2.提供报警接口
import com.mayikt.entity.AlarmMessageDto;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* 报警接口
*/
@RestController
public class PoliceService {
private List<List<AlarmMessageDto>> listAlarmMessage = new ArrayList<>();
/**
* 存放告警信息
*
* @param alarmMessageList
*/
@RequestMapping(value = "/police" method = RequestMethod.POST)
public void alarm(@RequestBody List<AlarmMessageDto> alarmMessageList) {
listAlarmMessage.add(alarmMessageList);
}
/**
* 打印告警信息
*
* @return
*/
@RequestMapping("/getListAlarmMessageDto")
public List<List<AlarmMessageDto>> getListAlarmMessageDto() {
return listAlarmMessage;
}
}
3.调用微信接口发送报警模板
4.访问接口压力测试
http://127.0.0.1:9008/orderToMember?id=0
调用微信模块接口1.创建微信模板接口
https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
scopeId:{{first.DATA}}
服务名称:{{keyword1.DATA}}
警告内容:{{keyword2.DATA}}
警告时间:{{keyword3.DATA}}
您可以登录企业内部skywalking平台查看,具体错误信息。
2.调用微信接口发送模板信息
/**
* 存放告警信息
* http://127.0.0.1:11111/police
*
* @param alarmMessageList
*/
@RequestMapping(value = "/police" method = RequestMethod.POST)
public void alarm(@RequestBody List<AlarmMessageDto> alarmMessageList) {
listAlarmMessage.add(alarmMessageList);
WxMpTemplateMsgService wxMpTemplateMsgService = WxMpConfiguration.getMpServices().get("wx5c43fde3c9733d9e").getTemplateMsgService();
alarmMessageList.forEach((alarmMessageDto -> {
WxMpTemplateMessage wxMpTemplateMessage = new WxMpTemplateMessage();
// 改成刚刚创建好的模板id
wxMpTemplateMessage.setTemplateId("vQo2a5gWeY3lhMeRR6ekf8WqtX37z3eIaOwEWM9tLN8");
// 发送关注微信公众号的openid
wxMpTemplateMessage.setToUser("okYSmtzp4wWCrDCncMfGSRECVSeM");
List<WxMpTemplateData> data = new ArrayList<>();
data.add(new WxMpTemplateData("first" alarmMessageDto.getScopeId() ""));
data.add(new WxMpTemplateData("keyword1" alarmMessageDto.getName()));
data.add(new WxMpTemplateData("keyword2" alarmMessageDto.getAlarmMessage()));
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = formatter.format(alarmMessageDto.getStartTime());
data.add(new WxMpTemplateData("keyword3" format));
wxMpTemplateMessage.setData(data);
// 点击该模板 访问到http://127.0.0.1:8080/trace
wxMpTemplateMessage.setUrl("http://127.0.0.1:8080/trace");
try {
wxMpTemplateMsgService.sendTemplateMsg(wxMpTemplateMessage);
} catch (Exception e) {
log.error("<e:{}>" e);
}
}));
}
3.演示效果
SkyWalking数据持久化SkyWalking 默认是将数据存入在内存中,如果重启SkyWalking 数据则都会丢失。
我们可以选择将数据持久化存放在mysql、es中等。
1.数据可以持久化在mysql、es中等。
mysql:
properties:
jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/skywalking?serverTimezone=UTC&characterEncoding=utf-8"}
dataSource.user: ${SW_DATA_SOURCE_USER:root}
dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
2.需要在oap-libs/ 放入 mysql-connector-java-8.0.16.jar
mysql-connector-java-8.0.16.jar 下载:
3.重启SkyWalking
自动创建表结构
相关依赖下载:https://note.youdao.com/ynoteshare/index.html?id=d2e8f0a302cf0f709e79fe9da4e9556f&type=note&_time=1637654916654