2

基于Skywalking实现全链路追踪的万字攻略(有手就能操作版) - 运维 - dbaplus社群:...

 5 months ago
source link: https://dbaplus.cn/news-134-5764-1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

基于Skywalking实现全链路追踪的万字攻略(有手就能操作版) - 运维 - dbaplus社群:围绕Data、Blockchain、AiOps的企业级专业社群。技术大咖、原创干货,每天精品原创文章推送,每周线上技术分享,每月线下技术沙龙。 本文将重点介绍基于Skywalking的全链路实现,包括Skywalking的整体架构和基本概念原理、Skywalking环境部署、SpringBoot和Python集成Skywalking监控实现等。



一、Skywalking基本介绍



1.Skywalking整体架构

图片

Skywalking 8.x版本架构图

SkyWalking整体架构在逻辑上分为四部分:探针Agent、平台后端OAP、存储和UI界面。

  • 探针Agent:负责从应用中收集链路信息,并发送给SkyWalking的OAP服务器。它会收集Tracing和Metrics数据,将数据格式化为SkyWalking适用的格式。探针安装在服务所在的服务器上,以方便数据的获取。

  • 平台后端OAP:接收探针发送的数据,并在内存中使用分析引擎进行数据的整合运算,然后将数据存储到对应的存储介质上。OAP支持数据聚合、数据分析以及驱动数据流从探针到用户界面的流程。分析包括Skywalking原生链路跟踪和性能指标以及第三方来源,包括Istio及 Envoy telemetry、Zipkin链路跟踪格式化等。

  • 存储:通过开放的插件化的接口存放SkyWalking数据,目前支持的存储器有Elasticsearch、MySQL、ShardingSphere、TiDB、H2等。

  • 用户界面UI:负责提供控制台,查看链路、服务指标等。UI是一个基于接口高度定制化的Web系统,用户可以可视化查看和管理SkyWalking数据。



2.Skywalking基本概念

1)Skywalking中的核心概念

与Prometheus不同,SkyWalking的度量机制是围绕以下具有层次结构的核心概念构建的:

  • 层(Layer):表示计算机科学中的一个抽象框架,如 Operating System(OS_LINUX 层)、Kubernetes(k8s层)。该层将是从不同技术检测到的不同服务的所有者。

  • 服务:表示一组或一组工作负载,它为传入请求提供相同的行为。

  • 服务实例(Service Instance):服务组中的单个工作负载。

  • 端点(Endpoint):传入请求的服务路径。

  • 进程:操作系统进程。在某些场景下,service instance不是一个进程,比如一个 Kubernetes Pod可能包含多个进程。

2)Skywalking中的指标流

Metric名称和属性(标签)由SkyWalking OAP服务器根据数据源以及OAL和MAL配置。SkyWalking 提供了对时间序列指标进行下采样(down-sampling),并生成不同时间段数据(分钟、小时、天)的能力。SkyWalking指标流如下:

图片

二、Skywalking原理解析



1.Skywalking中Trace实现

Skywalking中实现了OpenTracing中的Trace、Span、Tags、Logs等核心概念,不同之处是在Trace级别和Span级别之间加了一个Segment概念,用于表示一个服务实例内的Span集合。

1)Trace ID

在Skywalking中,全局ID由三个 long 类型的字段(part1、part2、part3)构成,分别记录了ServiceInstanceId、Thread ID和Context生成序列,格式如下所示:

${ServiceInstanceId}.${Thread ID}.(${时间戳} * 10000 + 线程自增序列([0, 9999]))

2) TraceSegment

在SkyWalking中,TraceSegment是一个介于Trace与Span之间的概念,它是一条Trace的一段,可以包含多个Span。在微服务架构中,一个请求基本都会涉及跨进程(以及跨线程)的操作,例如,RPC调用、通过MQ异步执行、HTTP请求远端资源等,处理一个请求就需要涉及到多个服务的多个线程。TraceSegment记录了一个请求在一个线程中的执行流程(即Trace信息)。将该请求关联的TraceSegment串联起来,就能得到该请求对应的完整Trace。

图片

TraceSegment的核心结构如图所示,包括以下核心字段:

  • traceSegmentId(ID类型):TraceSegment的全局唯一标识

  • refs(List<TraceSegmentRef> 类型):它指向父TraceSegment

  • relatedGlobalTraces(DistributedTraceIds类型):记录当前TraceSegment所属Trace的Trace ID。

  • spans(List<AbstractTracingSpan>类型):当前TraceSegment包含的所有Span。

  • ignore(boolean类型):ignore字段表示当前TraceSegment是否被忽略。

3)Context

SkyWalking中的每个TraceSegment都与一个Context上下文对象一对一绑定,Context上下文不仅记录了TraceSegment的上下文信息,还提供了管理TraceSegment生命周期、创建Span以及跨进程(跨线程)传播相关的功能。

2.Trace的收集和发送

1)Context的生成与采样

应用访问时,如果不做任何限制,每个请求都会生成一条完整的Trace。在面对海量的业务请求时会同步产生海量的Trace数据,对网络和存储都带来巨大的压力,因此几乎所有的Trace系统都支持采样功能。在Skywalking Agent中是通过SamplingService服务实现的,SamplingService的trySampling()方法递增samplingFactorHolder字段,当增加到阈值(默认值为3,可以通过agent.sample_n_per_3_secs配置进行修改)时会返回false,表示采样失,这时就会生成IgnoredTracerContext,IgnoredTracerContext是个空Context实现,不会记录Trace信息。

图片

2)Trace的收集

当TracingContext通过stopSpan()方法关闭最后一个Span时,会调用finish()方法关闭相应的TraceSegment,与此同时,还会通知所有监听TracingContext关闭事件的监听器TracingContextListener。TraceSegmentServiceClient主要功能就是在TraceSegment结束时对其进行收集,并发送到后端的OAP集群。

图片

3.Skywalking OAP内核架构

Skywalking OAP采用微内核架构,使用ModuleManager(组件管理器)管理多个Module(组件),一个Module可以对应多个ModuleProvider(组件服务提供者),ModuleProvider是Module底层真正的实现。

在OAP服务启动时,一个Module只能选择使用一个ModuleProvider对外提供服务。一个ModuleProvider可能支撑了一个非常复杂的大功能,在一个ModuleProvider中,可以包含多个Service,一个Service实现了一个ModuleProvider中的一部分功能,通过将多个Service进行组装集成,可以得到ModuleProvider的完整功能。

三、Skywalking环境部署

Skywalking测试demo环境如下所示,分别测试SpringBoot应用和Python程序的监控实现。

图片

1.解压安装包,使用9.3.0版本

# tar -xzvf apache-skywalking-apm-9.3.0.tar.gz# mv apache-skywalking-apm-bin/ /usr/local/skywalking



2.修改OAP配置文件,指定存储类型为MySQL

# vi config/application.ymlcluster:  selector: ${SW_CLUSTER:standalone}storage:  selector: ${SW_STORAGE:mysql}  mysql:    properties:      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://192.168.112.121:3306/swtest?rewriteBatchedStatements=true&allowMultiQueries=true"}      dataSource.user: ${SW_DATA_SOURCE_USER:root}      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:123456}      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}    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}



3.对Webapp进行配置

# vi webapp/application.ymlserverPort: ${SW_SERVER_PORT:-18080}# Comma seperated list of OAP addresses.oapServices: ${SW_OAP_ADDRESS:-http://192.168.112.121:12800}

默认使用8080端口访问,修改为18080。

4.下载MySQL连接jar并拷贝到oap-libs

#下载链接:mysql-connector-java-8.0.28.jarhttps://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.28/mysql-connector-java-8.0.28.jar# cp mysql-connector-java-8.0.28.jar /usr/local/skywalking/oap-libs/

将jar包放在oap-libs目录下即可,如果没有连接jar包,会抛如下异常:

java.lang.RuntimeException: Failed to get driver instance for jdbcUrl=jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true&allowMultiQueries=true



5.连接mysql创建应用库swtest

# mysql -uroot -pmysql> create database swtest;

在mysql中创建配置文件中的应用库swtest,否则会提示报错。

com.zaxxer.hikari.pool.HikariPool - 574 [main] ERROR [] - HikariPool-1 - Exception during pool initialization.java.sql.SQLSyntaxErrorException: Unknown database 'swtest'



6.启动Skywalking服务

进入bin目录执行startup.sh文件即可启动SkyWalking平台。

cd ../bin./startup.sh

启动成功看log输出日志:

2023-11-04 16:06:18,455 - com.linecorp.armeria.common.util.SystemInfo - 237 [main] INFO  [] - hostname: tango-db01 (from /proc/sys/kernel/hostname)2023-11-04 16:06:20,036 - com.linecorp.armeria.server.Server - 797 [armeria-boss-http-*:12800] INFO  [] - Serving HTTP at /0:0:0:0:0:0:0:0%0:12800 - http://127.0.0.1:12800/

再查看swtest库中,已经创建了很多表:

mysql> show tables;+--------------------------------------------------------+| Tables_in_swtest                                       |+--------------------------------------------------------+| alarm_record                                           || alarm_record_tag                                       || browser_app_error_rate                                 |



7.访问UI页面,端口为18080:http://192.168.112.121:18080/

图片

四、Skywalking全链路监控实现



1.SpringBoot应用集成Skywalking监控

1)环境准备

在mysql中创建表并插入数据:

mysql> use sw_mysql;Database changedmysql> CREATE TABLE `sw_tb` (     -> `id` int(11) NOT NULL AUTO_INCREMENT,     -> `username` varchar(50) DEFAULT NULL,     -> `password` varchar(50) DEFAULT NULL,    -> PRIMARY KEY (`id`)     -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8    -> ;Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> insert into sw_mysql.sw_tb(`username`,`password`) values('张三','AAA'),('李四','BBB'),('王五','CCC');Query OK, 3 rows affected (0.00 sec)Records: 3  Duplicates: 0  Warnings: 0
mysql> select * from sw_mysql.sw_tb;+----+----------+----------+| id | username | password |+----+----------+----------+|  1 | 张三     | AAA      ||  2 | 李四     | BBB      ||  3 | 王五     | CCC      |+----+----------+----------+3 rows in set (0.00 sec)

2)在Eclipse中创建SpringBoot项目

在pom.xml文件中添加引入Skywalking的依赖包:

  <dependency>            <groupId>org.apache.skywalking</groupId>            <artifactId>apm-toolkit-trace</artifactId>            <version>8.3.0</version>        </dependency>        <dependency>            <groupId>org.apache.skywalking</groupId>            <artifactId>apm-toolkit-log4j-2.x</artifactId>            <version>8.3.0</version>        </dependency>  <dependency> <!-- 引入log4j2依赖 -->      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-log4j2</artifactId>  </dependency>

配置trace:

使用apm-toolkit-trace输出traceid信息,并修改log4j2.xml配置日志格式。这样会将traceid信息写入日志,用于后续的日志采集和集中分析。

    <Properties>        <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符 %logger{36} 表示 Logger 名字最长36个字符-->        <!--1.文件输出格式-->        <property name="file_pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%traceId] [%thread] [%-5level]  %msg %l%n" />        <!--2.控制台显示日志格式-->        <!--[%traceId]:追踪id-->        <!--[%sw_ctx]:打印为[$serviceName,$instanceName,$traceId,$traceSegmentId,$spanId]:服务名,实例名,追踪id,追踪片段id,跨度id-->        <property name="console_pattern" value="%red{%d{yyyy-MM-dd HH:mm:ss}} [%traceId] %green{[%thread]} %magenta{[%-5level]} %cyan{%msg} %l%n"/>        <!--3.skyWalking收集格式-->        <property name="skyWalking_pattern" value="%msg %l%n"/>        <!-- 定义日志存储的路径 -->        <property name="FILE_PATH" value="./log/spring-skywalking/" />        <property name="FILE_NAME" value="spring-skywalking" />    </Properties>

控制程序如下:

package com.tango.skywalking_mysql.controller;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;
import com.tango.skywalking_mysql.SkywalkingMysqlApplication;
import org.apache.logging.log4j.LogManager;  import org.apache.logging.log4j.Logger;  
@RestController@RequestMapping("/demo")public class DemoController {
    private static final Logger logger = LogManager.getLogger(SkywalkingMysqlApplication.class);     @Autowired    private JdbcTemplate template;
    @GetMapping("/mysql")    public String mysql() {      String result="";      try {        this.selectById(1);        System.out.println("skywalking-test!");        logger.info("skywalking-test!");        result="MySQL查询正常";      } catch(Exception e) {        System.out.println(e);        logger.error(e);        result="MySQL查询异常";      }        return result;    }
    public Object selectById(Integer id) {        return template.queryForObject("SELECT id, username, password FROM sw_tb WHERE id = ?",new BeanPropertyRowMapper<>(Object.class), id);    }}

在IDE配置中添加如下选项,配置Skywalking agent和服务的地址。

-javaagent:D:\Skywalking-demo\skywalking-agent\skywalking-agent.jar-Dskywalking.agent.service_name=skywalking-demo-service-Dskywalking.collector.backend_service=192.168.112.121:11800
图片

3)运行SpringBoot服务程序

运行应用后输出以下信息,表示agent启动成功。

INFO 2023-11-04 17:11:44.918 main SkyWalkingAgent : Skywalking agent begin to install transformer ... Starting application skywalking_mysql[31m2023-11-04 17:11:52[m [TID: N/A] [32m[main][m [35m[INFO ][m [36mStarting application skywalking_mysql[m com.tango.skywalking_mysql.SkywalkingMysqlApplication.main(SkywalkingMysqlApplication.java:13)

同时能够查看到日志中的traceid信息:

[31m2023-11-04 17:17:43[m [TID: e6978740bf3e41bfa6a53760e2d64b8a.44.16988302617370001] [32m[http-nio-18079-exec-1][m [35m[INFO ][m [36mskywalking-test![m com.tango.skywalking_mysql.controller.DemoController.mysql(DemoController.java:29)skywalking-test![31m2023-11-04 17:20:39[m [TID: e6978740bf3e41bfa6a53760e2d64b8a.47.16988304392400001] [32m[http-nio-18079-exec-4][m [35m[INFO ][m [36mskywalking-test![m com.tango.skywalking_mysql.controller.DemoController.mysql(DemoController.java:29)skywalking-test!

查看服务端的11800端口,已经有服务。

[root@tango-DB01 config]# netstat -an|grep 11800tcp6       0      0 :::11800                :::*                    LISTEN     tcp6       0      0 192.168.112.121:11800   192.168.112.1:49590     ESTABLISHED

访问SpringBoot应用服务:

每查询一次发起一笔业务访问:http://192.168.112.1:18079/demo/mysql

4)登录Skywalking监控服务运行情况

在Skywalking界面看到新的Service:skywalking-demo-service

图片

查看服务的运行性能指标情况:

图片

查看服务的拓扑结构,这是一个访问mysql数据库的应用。

图片

查看trace信息:

图片

查看具体的SQL语句执行情况:

图片

2.Python应用集成Skywalking监控

1)Python程序中Agent配置

在Python程序中引入Skywalking Agent:

from skywalking import agent,config
#配置OAP服务信息config.init(agent_collector_backend_services='192.168.112.121:11800', agent_name='skywalking-demo-python')agent.start()

2)运行Python程序,在Skywalking监控服务运行情况

拓扑图如下所示,包括服务和mysql数据库:

图片

查看Trace信息:

图片

查看具体执行的SQL信息:

图片

3)代码实现

完整代码实现如下:

# -*- coding: utf-8 -*-import pymysqlimport sysimport timeimport codecsimport loggingimport base64

from skywalking import agent,config # 配置logging模块  logging.basicConfig(filename='test.log', level=logging.INFO)  
def getInfo(sql):  ip="192.168.112.121"  port=3306  user="root"  pwd=base64.decodebytes(b"MTIzNDU2Cg==").strip().decode('utf-8')  dbname="sw_mysql"  info = []  conn = pymysql.connect(host=ip,port=port,user=user,passwd=pwd,database=dbname,charset='utf8')  cursor = conn.cursor()  try:    cursor.execute(sql)    info = cursor.fetchall()  except Exception as e:    print(e)  conn.commit()  cursor.close()  conn.close()  return info
if __name__ == '__main__':    if sys.version[0] == "2":        reload(sys)        sys.setdefaultcoding("utf8")    config.init(agent_collector_backend_services='192.168.112.121:11800', agent_name='skywalking-demo-python')    agent.start()    exec_sql = "select id,username,password from sw_mysql.sw_tb"    while True:        get_info = getInfo(exec_sql)        if len(get_info) > 0:            print(get_info[0])            print("Success!")        else:            print("Error!")                time.sleep(5)    agent.stop()

以上是基于Skywalking的全链路跟踪的简单指标采集实现。Skywalking功能强大,还具备拓扑关联分析、分布式跟踪和上下文传播、告警等功能,值得深入研究。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK