目录
随着分布式应用大规模部署,应用可观测性从理论到落地已经在众多大型互联网应用中得到实践,经过多年沉淀,行业内也逐步形成了相应的一整套解决方案,比如针对日志可视化ELK解决方案,分布式链路追踪APM解决方案SkyWalking,可视化监控工具Prometheus等等。今天将详细介绍下APM解决方案中一款重要工具SkyWalking的使用。
?SkyWalking是一个开源的可观测平台,用于从服务和云原生等基础设施收集、分析、聚合以及可视化数据。官网地址:Apache SkyWalking
SkyWalking 提供了一种简便的方式来清晰地观测分布式系统。相比较zipkin而言,skywalking利用agent字节码增强技术实现代码无侵入,通信方式采用GRPC,性能较好,实现方式是java探针,支持告警,支持JVM监控,支持全局调用统计,UI界面更加强大等优点。
SkyWalking 有哪些功能呢?下面列举了其主要的功能点:
监控手段丰富,可以通过语言探针和 service mesh 获得监控是数据;
多种类型的语言自动探针,包括 Java,.NET Core 和 Node.JS;
轻量高效,无需大数据平台,和大量的服务器资源;
模块化,UI、存储、集群管理都有多种机制可选;
支持各类告警机制;
提供优秀的可视化解决方案,支持各类监控数据的可视化;
下面是SkyWalking的整体架构图
从官网提供的Skywalking架构图来看,分成几个部分,简单来说,可以分成下面几个部分
OAP后端
OAP负责接收 Agent 发送的 Tracing 和Metric的数据信息,然后进行分析Analysis Core,存储到外部存储器 Storage ,最终提供查询Query 功能
WEB-UI
UI负责提供web控制台,查看链路,查看各种指标,性能等
Agent探针
Agent负责收集日志数据:Agent以探针的方式,进行请求链路的数据采集,并向OAP服务器上报
Storage存储
数据的存储层,支持ElasticSearch、Mysql、H2多种方式
官网关于SkyWalking的详细工作流程图如下
如果在实际应用中,简化上面的流程之后其核心工作流程分为下面几步:
随着业务规模的不断增长,应用的微服务数量也在随着增长,当微服务的数量越来越大时,一旦系统中出现某个问题,如果不借助工具或其他监测手段,解决问题是耗时耗力的,尤其是N多个微服务之间的调用链路很长,调用关系非常复杂的时候,对于排查、定位分析和解决问题将变得异常困难。因此急需一种可视化工具,可以追踪分布式调用的完整链路的信息,并提供可视化分析界面。
市面上提供的可用于微服务应用监控工具有很多,下面列举一些常用的解决方案:
Zipkin:Twitter公司开源的一个分布式追踪工具,被Spring Cloud Sleuth集成,使用广泛而稳定,需要在应用程序中埋点,对代码侵入性强;
Cat:美团大众点评开源的一款分布式链路追踪工具。需要在应用程序中埋点,对代码侵入性强;
Pinpoint:一个韩国团队开源的产品,探针收集的数据粒度非常细,但性能损耗大,因其出现的时间较长,完成度很高;
SkyWalking:中国人吴晟(华为)开源的一款分布式追踪,分析,告警的工具,现在是Apache旗下开源项目,对云原生支持,目前增长势头强劲,社区活跃,中文文档没有语言障碍;
OpenTelemetry ,是 CNCF 的一个可观测性项目,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方 vendor 无关的服务;
Grafana,是一个监控仪表系统,由Grafana Labs公司开源的的一个系统监测 (System Monitoring) 工具。帮助用户简化监控的复杂度,用户只需要提供需要监控的数据,它就可以生成各种可视化仪表。同时它还支持报警功能,可以在系统出现问题时通知用户;
Prometheus,主要用于对基础设施的监控,包括服务器(CPU、MEM等)、数据库(MYSQL、PostgreSQL等)、Web服务等,几乎所有东西都可以通过Prometheus进行监控。而它的数据,则是通过配置,建立与数据源的联系来获取的;
相比于其他框架,SkyWalking有自己的优势,主要体现在下面几点:
Skywalking采用字节码增强的技术实现,微服务以java-agent的方式集成,业务代码本身无侵入,像Zipkin代码侵入性就比较高。
1)链路追踪、拓扑分析能力强,采用先进的流式拓扑分析设计;
2)Skywalking功能比较丰富,插件丰富,报表统计,UI界面更加人性化,更符合国人的使用习惯;
Java生态、功能丰富,国人开发、社区活跃,迭代迅速。
官网安装包下载地址:Downloads | Apache SkyWalking
为了后面的演示,即将springboot服务接入到Skywalking,需要部署OAP服务,以及Java Agent,对应的安装包如下:
下载oap安装包
oap即Skywalking服务端,如下进到官网后,选择下面这里的包,选择合适的版本进行下载,这里我选择9.3.0的版本;
下载Java Agent包
即服务端agent,用于收集来自客户端的端点信息和指标信息,然后上报到oap服务端
oap的服务运行起来很简单,最直接的方式就是解压后进入到bin目录直接使用脚本启动即可
tar -zxvf apache-skywalking-apm-9.3.0.tar.gz
cd apache-skywalking-apm-bin
cd bin
启动脚本说明:
1、oapService.sh,oap的服务启动脚本;
2、webappService.sh,web-ui服务启动脚本;
3、startup.sh,同时包含了启动上面两个服务的脚本
实际使用时,为了方便直接使用 startup.sh启动即可
启动成功后会有两个服务,如上所示:
启动成功后,可以直接访问web-ui界面,访问地址:IP:8080,如果需要修改ui界面的访问端口,直接修改web-app目录下的配置文件中的端口即可;
访问的界面如下
默认情况下如果不做任何配置,Skywalking运行过程中产生的数据将会存储在H2,即内存数据库,一旦服务宕机或被重启,数据将丢失,Skywalking提供了多种持久化数据存储的方式,可以选择mysql,es等,下面使用mysql来存储数据。
找到config目录下的application.yml配置文件,然后找到下面配置的地方,改为mysql
修改相关的mysql连接参数,指向你自己的连接,注意提前创建一个数据库
将mysql的连接jar包上传到oap-libs目录下,下载链接:文件分享
不管是使用哪种数据持久化方式,一定要上传对应的jar包之后再重启服务,否则会报连接驱动找不到的问题
然后刷新页面,就可以看到数据库下生成了很多Skywalking相关的数据表
在项目中,如何将springboot接入Skywalking,从而通过Skywalking来监控服务呢?下面来看具体的操作步骤
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getById")
public User find(@RequestParam String userId) {
return new User(userId, "jerry");
}
}
通过上面下载的Agent的包解压到本地目录(如果是服务器同样的操作)
本地启动项目时,添加如下启动参数
-javaagent:E:\code-self\skywalking-agent\skywalking-agent.jar -DSW_AGENT_NAME=sky-boot -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=服务端IP:11800
在idea中配置上面的这段启动参数
启动成功后,浏览器访问上面提供的测试接口
然后再在skywalking的web-ui界面上就能看到当前监控到的服务信息了
继续点进去,可以看到详细的各种监控指标信息
也可以点击其他的监控指标进行多维度查看
dubbo在微服务治理中也是经常使用的,下面通过实例演示下如何利用Skywalking监控dubbo服务
工程目录结构如下
顶层pom依赖
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<dubbo.version>3.1.5</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.14</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
该模块主要定义公共的实体类,服务接口
定义一个实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String id;
private String userName;
}
定义一个服务接口
public interface UserService {
User getByUserId(String userId);
}
发布api模块jar包
通过maven命令,将api模块的jar包发布到本地仓库以供其他模块依赖
模块结构如下
这里注册中心使用zk
<dependencies>
<dependency>
<groupId>com.congge</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<type>pom</type>
</dependency>
</dependencies>
server:
port: 8083
dubbo:
application:
name: sky-dubbo-provider
protocol:
name: dubbo
port: -1
registry:
address: zookeeper://IP地址:2181
protocol: zookeeper
import com.congge.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
@Slf4j
@DubboService
public class UserServiceImpl implements UserService{
@Override
public User getByUserId(String userId) {
log.info("[ServiceProvider] 根据 id 查询用户:{}", userId);
return new User(userId, "jerry");
}
}
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubbo
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
}
模块结构如下
<dependencies>
<dependency>
<groupId>com.congge</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<type>pom</type>
</dependency>
</dependencies>
server:
port: 8082
dubbo:
application:
name: sky-dubbo-consumer
protocol:
name: dubbo
port: -1
registry:
address: zookeeper://IP地址:2181
protocol: zookeeper
为了方便测试,自定义一个接口,在接口中调用dubbo服务
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@DubboReference
private UserService userService;
//http://localhost:8082/user/getByUserId?userId=001
@GetMapping("/getByUserId")
private User getByUserId(@RequestParam String userId) {
User user = userService.getByUserId(userId);
log.info("调用 dubbo 服务成功,获取用户信息:{}", JSON.toJSONString(user));
return user;
}
}
分别启动provider和consumer两个微服务模块,然后调用一下上面的接口,确认看到下面的结果后说明服务可以正常调通(前提:确保连接的zk服务可正常使用)
按照上述接入springboot的方式,idea启动的时候修改下启动配置参数,provider和consumer两个模块启动时分别添加如下参数:
provider配置的启动参数
-javaagent:E:\code-self\skywalking-agent\skywalking-agent.jar -DSW_AGENT_NAME=dubbo-provider -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=IP地址:11800
consumer配置的启动参数
-javaagent:E:\code-self\skywalking-agent\skywalking-agent.jar -DSW_AGENT_NAME=dubbo-consumer -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=IP地址:11800
配置之后再次启动两个模块的服务,再次访问接口,仍然能够得到期望的结果
此时再次到web-ui界面上看到在服务列表中出现了dubbo的两个服务信息
如果切换到拓扑图,也能够清晰看到两个服务的调用链路
本文详细介绍了Skywalking从搭建到使用的详细流程,事实上Skywalking的功能远不止这些,它不仅能够监控微服务的调用,还能监控像前端,PHP,nginx等众多其他的中间件,甚至还能与其他的可视化展示工具进行对接,可以说功能非常完善,如果整合你的项目在技术选项中需要集成一款链路监控,链路追踪以及可视化监控指标展示的工具,Skywalking也许是一个不错的选择。