Skywalking高级使用

news2024/9/22 17:25:06

Skywalking高级使用

    • RPC调用监控
    • Mysql调用监控
    • Skywalking常用插件
    • 获取追踪ID
    • 过滤指定的端点
    • 告警功能
    • Skywalking原理
    • Open Tracing介绍

RPC调用监控

Skywalking(6.5.0)支持的RPC框架有以下几种:
(1) Dubbo 2.5.4 -> 2.6.0
(2) Dubbox 2.8.4
(3) Apache Dubbo 2.7.0
(4) Motan 0.2.x -> 1.1.0
(5) gRPC 1.x
(6) Apache ServiceComb Java Chassis 0.1 -> 0.5,1.0.x
(7) SOFARPC 5.4.0
我们使用Spring Boot和Dubbo搭建一个简单的服务提供方和服务消费方来测试Skywalking对于RPC调用的支持。

1、服务提供方
pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itcast</groupId>
    <artifactId>skywalking_dubbo_provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>skywalking_dubbo_provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--添加springboot和dubbo集成配置-->
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这里直接使用了dubbo-spring-boot-starter这一dubbo与spring-boot集成的组件。
官方文档地址:https://github.com/alibaba/dubbo-spring-boot-starter/blob/master/README_zh.md

application.properties:

spring.application.name=skywalking_dubbo_provider
spring.dubbo.server=true
spring.dubbo.registry=N/A
server.port=8086

为了简化环境搭建,采用了本地直接调用的方式,所以将注册中心写成N/A表示不注册到注册中心。

IHelloService接口:

public interface IHelloService {
    public String hello();
}

简化项目的开发,将IHelloService接口在消费方和提供方都编写一份。

HelloServiceImpl实现类:

import com.alibaba.dubbo.config.annotation.Service;
import com.itcast.api.IHelloService;
import org.springframework.stereotype.Component;

@Service(interfaceClass = IHelloService.class)
@Component
public class HelloServiceImpl implements IHelloService {
    @Override
    public String hello() {
        return "hello skywalking";
    }
}

SkywalkingDubboProviderApplication启动类:

import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//添加dubbo生效注解
@EnableDubboConfiguration
public class SkywalkingDubboProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(SkywalkingDubboProviderApplication.class, args);
    }

}

需要添加@EnableDubboConfiguration注解。

2、服务消费方
pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itcast</groupId>
    <artifactId>skywalking_dubbo_consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>skywalking_dubbo_consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties:

spring.application.name=skywalking_dubbo_consumer
server.port=8085

IHelloService接口:

public interface IHelloService {
    public String hello();
}

简化项目的开发,将IHelloService接口在消费方和提供方都编写一份。

TestController:

import com.alibaba.dubbo.config.annotation.Reference;
import com.itcast.api.IHelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @Reference(url = "dubbo://127.0.0.1:20880")
    private IHelloService helloService;

    @GetMapping("/hello")
    public String hello(){
        return helloService.hello();
    }
}

采用直连而非从注册中心获取服务地址的方式,在@Reference注解中声明
url = “dubbo://127.0.0.1:20880”

SkywalkingDubboConsumerApplication启动类:

import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//添加dubbo生效注解
@EnableDubboConfiguration
public class SkywalkingDubboConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SkywalkingDubboConsumerApplication.class, args);
    }

}

需要添加@EnableDubboConfiguration注解。

3、部署方式
(1) 将skywalking_dubbo_consumer.jar和skywalking_dubbo_provider.jar上传至/usr/local/skywalking目录下。
(2) 首先我们复制两份agent,防止使用的冲突。

[root@skywalking skywalking]# cd /usr/local/skywalking/apache-skywalking-apm-bin/
[root@skywalking apache-skywalking-apm-bin]# cp -r agent agent_dubbo_provider
[root@skywalking apache-skywalking-apm-bin]# cp -r agent agent_dubbo_consumer
[root@skywalking apache-skywalking-apm-bin]# vi agent_dubbo_provider/config/agent.config

修改agent_dubbo_provider配置中的应用名为:

# The service name in UI
agent.service_name=${SW_AGENT_NAME:dubbo_provider}

接着修改agent_dubbo_consumer:

[root@skywalking apache-skywalking-apm-bin]# vi agent_dubbo_consumer/config/agent.config

修改应用名:

# The service name in UI
agent.service_name=${SW_AGENT_NAME:dubbo_consumer}

(3) 先启动provider,等待启动成功。

#切换到目录下
[root@skywalking ~]# cd /usr/local/skywalking/
#启动provider
[root@skywalking skywalking]# java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_dubbo_provider/skywalking-agent.jar -jar skywalking_dubbo_provider.jar &

在这里插入图片描述
出现如图所示内容,应用就已经启动成功了。

(4) 启动consumer,等待启动成功。

#启动consumer
[root@skywalking skywalking]# java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_dubbo_consumer/skywalking-agent.jar -jar skywalking_dubbo_consumer.jar &

在这里插入图片描述

(5) 调用接口,接口地址为:http://虚拟机IP地址:8085/hello
(6) 此时如果页面显示
在这里插入图片描述
那么dubbo的调用就成功了。
(7) 打开skywalking查看dubbo调用的监控情况。
仪表盘:
在这里插入图片描述
目前 dubbo_provider 和 dubbo_consumer 的服务已经出现,同时出现了两个接口分别是:
1》/hello接口,是浏览器调用dubb_consumer的http接口
2》com.itcast.api.IHelloService.hello()是dubbo_consumer调用dubbo_provider的dubbo接口

拓扑图:
在这里插入图片描述
该图中已经表示出了一个调用的链路关系:
User(浏览器) ----> dubber_consumer ----> dubbo_provider
并且在服务的上方标识出了每个服务代表的内容,dubbo_consumer是SpringMvc的服务,而dubbo_provider是Dubbo的服务。

追踪:
在这里插入图片描述
在这里插入图片描述
追踪图中显示本次调用耗时19ms,其中dubbo接口耗时3ms,那么另外的16ms其实是SpringMVC接
口的开销,这样就能很好的评估出每个环节的耗时时间。

Mysql调用监控

1、使用docker启动Mysql
docker安装参考:CentOS7 中 Docker 的安装
虚拟机中已经安装了docker,我们先将docker启动:

systemctl start docker

使用docker命令启动mysql:

docker run -di --name=skywalking_mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=123456 centos/mysql-57-centos7

在这里插入图片描述
MYSQL_ROOT_PASSWORD环境变量指定root的密码为123456

这样就可以在外部访问mysql了。使用工具连接mysql,端口为33306密码为123456。创建数据库:
在这里插入图片描述
在这里插入图片描述

执行建表语句:

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入几条数据:

insert into `t_user`(`name`) values ('张三'),('李四'),('王五');

2、Spring Data JDBC访问Mysql

创建一个Spring Boot工程,集成Spring Data JDBC。
pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itcast</groupId>
    <artifactId>skywalking_mysql</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>skywalking_mysql</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

引入了 spring-boot-starter-data-jdbc , 由于使用了5.7的mysql版本,所以驱动版本固定为5.1.46。

pojo类:

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Table("t_user")
public class User {
    @Id
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

添加Table注解,修改表明为t_user。

dao接口:

import com.itcast.skywalking_mysql.pojo.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Integer> {
}

controller类:

import com.itcast.skywalking_mysql.dao.UserRepository;
import com.itcast.skywalking_mysql.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class MysqlController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/users")
    public List<User> findAll(){
        List<User> result = new ArrayList<>();
        userRepository.findAll().forEach((user) -> {
            result.add(user);
        });

        return result;
    }
}

由于Spring Data JDBC的findAll方法返回的是一个迭代器,所以需要遍历迭代器将数据进行返
回。

启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SkywalkingMysqlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SkywalkingMysqlApplication.class, args);
    }

}

application.properties:

spring.datasource.url=jdbc:mysql://192.168.75.103:33306/skywalking??useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
server.port=8087

3、部署方式
(1) 将 skywalking_mysql.jar 上传至 /usr/local/skywalking 目录下。
(2) 首先我们复制agent,防止使用的冲突。

[root@skywalking ~]# cd /usr/local/skywalking/apache-skywalking-apm-bin/
[root@skywalking apache-skywalking-apm-bin]# cp -r agent agent_mysql
[root@skywalking apache-skywalking-apm-bin]# vi agent_mysql/config/agent.config

修改agent_mysql配置中的应用名为:

# The service name in UI
agent.service_name=${SW_AGENT_NAME:skywalking_mysql}

(3) 启动skywalking_mysql应用,等待启动成功。

#切换到目录下
[root@skywalking /]# cd /usr/local/skywalking/
#启动spring boot
[root@skywalking skywalking]# java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_mysql/skywalking-agent.jar -jar skywalking_mysql.jar &

(4) 调用接口,接口地址为:http://虚拟机IP地址:8087/users
(5) 此时如果页面显示
在这里插入图片描述
那么mysql的调用就成功了。

(6) 打开skywalking查看mysql调用的监控情况。
服务仪表盘:
在这里插入图片描述

数据库仪表盘:
在这里插入图片描述
点击数据库仪表盘可以看到详细的数据库响应时长、吞吐量、SLA等数据。

拓扑图:
在这里插入图片描述
该图中已经表示出了一个调用的链路关系:
User(浏览器) ----> skywalking_mysql ----> localhost:33306
并且在服务的上方标识出了每个服务代表的内容,skywalking_mysql是SpringMVC的服务,而localhost:33306是mysql的服务。

追踪:
在这里插入图片描述
追踪图中显示本次调用耗时950ms,其中spring MVC接口耗时948ms,那么另外的2ms是调用Mysql的耗时。
点击mysql的调用,可以看到详细的sql语句。
在这里插入图片描述
这样可以很好的定位问题产生的原因,特别是在某些sql语句执行慢的场景下。

Skywalking常用插件

1、配置覆盖
在之前的案例中,我们每次部署应用都需要复制一份agent,修改其中的服务名称,这样显得非常麻烦。可以使用Skywalking提供的配置覆盖功能通过启动命令动态指定服务名,这样agent只需要部署一份即可。Skywalking支持的几种配置方式:
(1) 系统配置(System properties)
使用skywalking. + 配置文件中的配置名作为系统配置项来进行覆盖。
1》为什么需要添加前缀?
agent的系统配置和环境与目标应用共享,所以加上前缀可以有效的避免冲突。
2》案例
通过如下进行agent.service_name的覆盖

-Dskywalking.agent.service_name=skywalking_mysql

(2) 探针配置(Agent options)
Add the properties after the agent path in JVM arguments.

-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]

1》案例
通过如下进行agent.service_name的覆盖

-javaagent:/path/to/skywalking-agent.jar=agent.service_name=skywalking_mysql

2》特殊字符
如果配置中包含分隔符(,或者=),就必须使用引号包裹起来

-javaagent:/path/to/skywalking-agent.jar=agent.ignore_suffix='.jpg,.jpeg'

3、系统环境变量(System environment variables)
1》案例
由于agent.service_name配置项如下所示:

# The service name in UI
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

可以在环境变量中设置SW_AGENT_NAME的值来指定服务名。

4、覆盖优先级
探针配置 > 系统配置 > 系统环境变量 > 配置文件中的值

所以我们的启动命令可以修改为:

java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_mysql/skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_mysql -jar skywalking_mysql.jar &

或者

java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_mysql/skywalking-agent.jar=agent.service_name=skywalking_mysql -jar skywalking_mysql.jar &

获取追踪ID

Skywalking提供我们Trace工具包,用于在追踪链路时进行信息的打印或者获取对应的追踪ID。我们使用Spring Boot编写一个案例进行测试。
pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itcast</groupId>
    <artifactId>skywalking_plugins</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>skywalking_plugins</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <skywalking.version>6.5.0</skywalking.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--skywalking trace工具包-->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>${skywalking.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

添加了对应的坐标:

<!--skywalking trace工具包-->
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>${skywalking.version}</version>
</dependency>

本案例中使用6.5.0的版本号。

PluginController类:

import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PluginController {

    //获取trace id,可以在RocketBot追踪中进行查询
    @GetMapping("/getTraceId")
    public String getTraceId(){
        //使当前链路报错,并且提示报错信息
        ActiveSpan.error(new RuntimeException("Test-Error-Throwable"));
        //打印info信息
        ActiveSpan.info("Test-Info-Msg");
        //打印debug信息
        ActiveSpan.debug("Test-debug-Msg");
        return TraceContext.traceId();
    }
}

使用TraceContext.traceId()可以打印出当前追踪的ID,方便在RocketBot中进行搜索。
ActiveSpan提供了三个方法进行信息的打印:
(1) error方法会将本次调用变为失败状态,同时可以打印对应的堆栈信息和错误提示。
(2) info方法打印info级别的信息。
(3) debug方法打印debug级别的信息。

部署方式
(1) 将skywalking_plugins.jar上传至/usr/local/skywalking目录下。
(2) 启动skywalking_plugins应用,等待启动成功。

java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_plugins -jar skywalking_plugins.jar &

(3) 调用接口,接口地址为:http://虚拟机IP地址:8088/getTraceId
(4) 此时如果页面显示
在这里插入图片描述
可以看到追踪ID已经打印出来,然后我们在RocketBot上进行搜索。
在这里插入图片描述
可以搜索到对应的追踪记录,但是显示调用是失败的,这是因为使用了ActiveSpan.error方法,点开追踪的详细信息:
在这里插入图片描述
异常的信息包含了以下几个部分:
1》事件类型为error
2》调用方法时传递的异常类型RuntimeException
3》调用方法时传递的异常信息Test-Error-Throwable
4》异常堆栈

通过上述内容,我们可以根据业务来定制调用异常时的详细信息。
在这里插入图片描述
除了异常信息之外,还有info信息和debug信息也都会打印。

过滤指定的端点

在开发过程中,有一些端点(接口)并不需要去进行监控,比如Swagger相关的端点。这个时候我们就
可以使用Skywalking提供的过滤插件来进行过滤。在skywalking_plugins中编写两个接口进行测试:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FilterController {
    //此接口可以被追踪
    @GetMapping("/include")
    public String include(){
        return "include";
    }

    //此接口不可被追踪
    @GetMapping("/exclude")
    public String exclude(){
        return "exclude";
    }
}

部署方式
1、将skywalking_plugins.jar上传至/usr/local/skywalking目录下。
2、将agent中的/agent/optional-plugins/apm-trace-ignore-plugin-6.4.0.jar插件拷贝到plugins目录下。

[root@skywalking ~]# cd /usr/local/skywalking/apache-skywalking-apm-bin/agent
[root@skywalking agent]# cp optional-plugins/apm-trace-ignore-plugin-6.5.0.jar  plugins/apm-trace-ignore-plugin-6.5.0.jar

3、重启OAP程序

ps -ef | grep oap
kill -9 47218
./oapService.sh

4、启动skywalking_plugins应用,等待启动成功。

java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_plugins -Dskywalking.trace.ignore_path=/exclude -jar skywalking_plugins.jar &

这里添加-Dskywalking.trace.ignore_path=/exclude参数来标识需要过滤哪些请求,支持AntPath表达式:
/path/* , /path/** , /path/?
(1) ? 匹配任何单字符
(2) * 匹配0或者任意数量的字符
(3) ** 匹配0或者更多的目录

5、调用接口,接口地址为:
http://虚拟机IP地址:8088/exclude
http://虚拟机IP地址:8088/include
在这里插入图片描述
在这里插入图片描述

6、在追踪中进行查看:
在这里插入图片描述
exclude接口已经被过滤,只有include接口能被看到。

告警功能

1、告警功能简介
Skywalking每隔一段时间根据收集到的链路追踪的数据和配置的告警规则(如服务响应时间、服务响应时间百分比)等,判断如果达到阈值则发送相应的告警信息。发送告警信息是通过调用webhook接口完成,具体的webhook接口可以使用者自行定义,从而开发者可以在指定的webhook接口中编写各种告警方式,比如邮件、短信等。告警的信息也可以在RocketBot中查看到。

以下是默认的告警规则配置,位于skywalking安装目录下的config文件夹下alarm-setting.yml文件中:

rules:
  # Rule unique name, must be ended with `_rule`.
  service_resp_time_rule:
    metrics-name: service_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 3
    silence-period: 5
    message: Response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes.
  service_sla_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_sla
    op: "<"
    threshold: 8000
    # The length of time to evaluate the metrics
    period: 10
    # How many times after the metrics match the condition, will trigger alarm
    count: 2
    # How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
    silence-period: 3
    message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
  service_p90_sla_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_p90
    op: ">"
    threshold: 1000
    period: 10
    count: 3
    silence-period: 5
    message: 90% response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes
  service_instance_resp_time_rule:
    metrics-name: service_instance_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 2
    silence-period: 5
    message: Response time of service instance {name} is more than 1000ms in 2 minutes of last 10 minutes
#  Active endpoint related metrics alarm will cost more memory than service and service instance metrics alarm.
#  Because the number of endpoint is much more than service and instance.
#
#  endpoint_avg_rule:
#    metrics-name: endpoint_avg
#    op: ">"
#    threshold: 1000
#  Active endpoint related metrics alarm will cost more memory than service and service instance metrics alarm.
#  Because the number of endpoint is much more than service and instance.
#
#  endpoint_avg_rule:
#    metrics-name: endpoint_avg
#    op: ">"
#    threshold: 1000
#    period: 10
#    count: 2
#    silence-period: 5
#    message: Response time of endpoint {name} is more than 1000ms in 2 minutes of last 10 minutes

webhooks:
#  - http://127.0.0.1/notify/
#  - http://127.0.0.1/go-wechat/

以上文件定义了默认的4种规则:
(1) 最近3分钟内服务的平均响应时间超过1秒
(2) 最近2分钟服务成功率低于80%
(3) 最近3分钟90%服务响应时间超过1秒
(4) 最近2分钟内服务实例的平均响应时间超过1秒

规则中的参数属性如下:

属性含义
metrics-nameoal脚本中的度量名称
threshold阈值,与metrics-name和下面的比较符号相匹配
op比较操作符,可以设定>,<,=
period多久检查一次当前的指标数据是否符合告警规则,单位分钟
count达到多少次后,发送告警消息
silence-period在多久之内,忽略相同的告警消息
message告警消息内容
include-names本规则告警生效的服务列表

webhooks可以配置告警产生时的调用地址。

2、告警功能测试代码
编写告警功能接口进行测试,创建skywalking_alarm项目。
AlarmController:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AlarmController {

    //每次调用睡眠1.5秒,模拟超时的报警
    @GetMapping("/timeout")
    public String timeout(){
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "timeout";
    }
}

该接口主要用于模拟超时,多次调用之后就可以生产告警信息。

WebHooks:

import com.itcast.skywalking_alarm.pojo.AlarmMessage;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class WebHooks {

    private List<AlarmMessage> lastList = new ArrayList<>();

    @PostMapping("/webhook")
    public void  webhook(@RequestBody List<AlarmMessage> alarmMessageList){
        lastList = alarmMessageList;
    }

    @GetMapping("/show")
    public List<AlarmMessage> show(){
        return lastList;
    }
}

产生告警时会调用webhook接口,该接口必须是Post类型,同时接口参数使用RequestBody。参数格式为:
在这里插入图片描述

AlarmMessage:

public class AlarmMessage {
    private int scopeId;
    private String name;
    private int id0;
    private int id1;
    //告警的消息
    private String alarmMessage;
    //告警的产生时间
    private long startTime;

    public int getScopeId() {
        return scopeId;
    }

    public void setScopeId(int scopeId) {
        this.scopeId = scopeId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId0() {
        return id0;
    }

    public void setId0(int id0) {
        this.id0 = id0;
    }

    public int getId1() {
        return id1;
    }

    public void setId1(int id1) {
        this.id1 = id1;
    }

    public String getAlarmMessage() {
        return alarmMessage;
    }

    public void setAlarmMessage(String alarmMessage) {
        this.alarmMessage = alarmMessage;
    }

    public long getStartTime() {
        return startTime;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
    }

    @Override
    public String toString() {
        return "AlarmMessage{" +
                "scopeId=" + scopeId +
                ", name='" + name + '\'' +
                ", id0=" + id0 +
                ", id1=" + id1 +
                ", alarmMessage='" + alarmMessage + '\'' +
                ", startTime=" + startTime +
                '}';
    }
}

3、部署测试
首先需要修改告警规则配置文件,将webhook地址修改为:

webhooks:
	- http://127.0.0.1:8089/webhook

然后重启skywalking重启OAP程序

ps -ef | grep oap
kill -9 47218
./oapService.sh

(1) 将skywalking_alarm.jar上传至/usr/local/skywalking目录下。
(2) 启动skywalking_alarm应用,等待启动成功。

java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_alarm -jar skywalking_alarm.jar

(3) 不停调用接口,接口地址为:http://虚拟机IP:8089/timeout
在这里插入图片描述

(4) 直到出现告警:
在这里插入图片描述

(5) 查看告警信息接口:http://虚拟机IP:8089/show
在这里插入图片描述
从上图中可以看到,我们已经获取到了告警相关的信息,在生产中使用可以在webhook接口中对接短信、邮件等平台,当告警出现时能迅速发送信息给对应的处理人员,提高故障处理的速度。

Skywalking原理

1、java agent原理
上文中我们知道,要使用Skywalking去监控服务,需要在其VM参数中添加"-
javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar"。这里就使用到了java agent技术。

Java agent是什么?
Java agent是java命令的一个参数。参数javaagent可以用于指定一个jar包。
(1) 这个jar包的MANIFEST.MF文件必须指定Premain-Class项。
(2) Permain-Class指定的那个类必须实现premain()方法。

当Java虚拟机启动时,在执行main函数之前,JVM会先运行-javaagent所指定jar包内Premain-Class这个类的premain方法。

如何使用java agent?
(1) 定义一个MANIFEST.MF文件,必须包含Premain-Class选项,通常也会加入Can-Redefine-Classes和Can-Retransform-Classes选项。
(2) 创建一个Premain-Class指定的类,类中包含premain方法,方法逻辑由用户自己确定。
(3) 将premain的类和MANIFEST.MF文件打成jar包。
(4) 使用参数-javaagent:jar包路径启动要代理的方法。

2、搭建java agent工程
使用maven创建java_agent_demo工程:
在这里插入图片描述

在java文件夹下创建PreMainAgent类:

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class PreMainAgent {

    /**
     * 在这个 premain 函数中,开发者可以进行对类的各种操作。
     * 1、agentArgs 是 premain 函数得到的程序参数,随同 “– javaagent”一起传入。与 main 函数不同的是,
     * 这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。
     * 2、Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。*
     * java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,
     * 集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
     * @param agentArgs
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("=========premain方法执行1========");
        System.out.println(agentArgs);
    }

    /**
     * 如果不存在 premain(String agentArgs, Instrumentation inst)
     * 则会执行 premain(String agentArgs)
     * @param agentArgs
    */
    public static void premain(String agentArgs) {
        System.out.println("=========premain方法执行2========");
        System.out.println(agentArgs);
    }
}

类中提供两个静态方法,方法名均为premain,不能拼错。

在pom文件中添加打包插件:

<build>
     <plugins>
         <plugin>
             <artifactId>maven-assembly-plugin</artifactId>
             <configuration>
                 <appendAssemblyId>false</appendAssemblyId>
                 <descriptorRefs>
                     <descriptorRef>jar-with-dependencies</descriptorRef>
                 </descriptorRefs>
                 <archive>
                     <!--自动添加META-INF/MANIFEST.MF -->
                     <manifest>
                         <addClasspath>true</addClasspath>
                     </manifest>
                     <manifestEntries>
                         <Premain-Class>PreMainAgent</Premain-Class>
                         <Agent-Class>PreMainAgent</Agent-Class>
                         <Can-Redefine-Classes>true</Can-Redefine-Classes>
                         <Can-Retransform-Classes>true</Can-Retransform-Classes>
                     </manifestEntries>
                 </archive>
             </configuration>
             <executions>
                 <execution>
                     <id>make-assembly</id>
                     <phase>package</phase>
                     <goals>
                         <goal>single</goal>
                     </goals>
                 </execution>
             </executions>
         </plugin>
     </plugins>
 </build>

该插件会在自动生成META-INF/MANIFEST.MF文件时,帮我们添加agent相关的配置信息。

使用maven的package命令进行打包:
在这里插入图片描述
打包成功之后,复制打包出来的jar包地址。
在这里插入图片描述

3、搭建主工程
使用maven创建java_agent_user工程:
在这里插入图片描述
Main类代码:

public class Main {
    public static void main(String[] args) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hello World");
    }
}

先运行一次,然后点击编辑MAIN启动类:
在这里插入图片描述

在VM options中添加代码:
在这里插入图片描述

代码为:

-javaagent:D:\shipin\资料-分布式链路追踪skywalking\分布式链路追踪skywalking\代码\java_agent_demo\target\java-agent-demo-1.0-SNAPSHOT.jar=HELLOAGENT

启动时加载javaagent,指向上一节中编译出来的java agent工程jar包地址,同时在最后追加参数
HELLOAGENT。

运行MAIN方法,查看结果:
在这里插入图片描述
可以看到java agent的代码优先于MAIN函数的方法运行,证明java agent运行正常。

4、统计方法调用时间
Skywalking中对每个调用的时长都进行了统计,这一小节中我们会使用ByteBuddy和Java agent技术来统计方法的调用时长。
Byte Buddy是开源的、基于Apache 2.0许可证的库,它致力于解决字节码操作和instrumentation API的复杂性。Byte Buddy所声称的目标是将显示的字节码操作隐藏在一个类型安全的领域特定语言背后。通过使用Byte Buddy,任何熟悉Java编程语言的人都有望非常容易地进行字节码操作。Byte Buddy提供了额外的API来生成Java agent,可以轻松的增强我们已有的代码。

添加依赖:

<dependencies>

   <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy</artifactId>
        <version>1.9.2</version>
    </dependency>
    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy-agent</artifactId>
        <version>1.9.2</version>
    </dependency>
</dependencies>

修改PreMainAgent代码:

public class PreMainAgent {

    public static void premain(String agentArgs, Instrumentation inst) {
        //创建一个转换器,转换器可以修改类的实现
        //ByteBuddy对java agent提供了转换器的实现,直接使用即可
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
                return builder
                        // 拦截任意方法
                        .method(ElementMatchers.<MethodDescription>any())
                        // 拦截到的方法委托给TimeInterceptor
                        .intercept(MethodDelegation.to(MyInterceptor.class));
            }
        };
        new AgentBuilder // Byte Buddy专门有个AgentBuilder来处理Java Agent的场景
                .Default()
                // 根据包名前缀拦截类
                .type(ElementMatchers.nameStartsWith("com.agent"))
                // 拦截到的类由transformer处理
                .transform(transformer)
                .installOn(inst);
    }
}

先生成一个转换器,ByteBuddy提供了java agent专用的转换器。通过实现Transformer接口利用builder对象来创建一个转换器。转换器可以配置拦截方法的格式,比如用名称,本例中拦截所有方法,并定义一个拦截器类MyInterceptor。

创建完拦截器之后可以通过Byte Buddy的AgentBuilder创造者来构建一个agent对象。AgentBuilder可以对指定的包名前缀来生效,同时需要指定转换器对象。

MyInterceptor类:

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MyInterceptor {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable<?> callable)
            throws Exception {
        long start = System.currentTimeMillis();
        try {
            //执行原方法
            return callable.call();
        } finally {
            //打印调用时长
            System.out.println(method.getName() + ":" + (System.currentTimeMillis() - start)  + "ms");
        }
    }
}

MyInterceptor就是一个拦截器的实现,统计的调用的时长。参数中的method是反射出的方法对象,而
callable就是调用对象,可以通过callable.call()方法来执行原方法。
重新打包,执行maven package命令。接下来修改主工程代码。主工程将Main类放置到 com.agent 包
下。修改代码内容为:

package com.agent;

public class Main {
    public static void main(String[] args) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hello World");
    }
}

休眠1秒,使统计时长的演示效果更好一些。执行main方法之后显示结果:
在这里插入图片描述
我们在没有修改代码的情况下,利用java agent和Byte Buddy统计出了方法的时长,Skywalking的
agent也是基于这些技术来实现统计调用时长。

Open Tracing介绍

OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。OpenTracing中最核心的概念就是Trace。

1、Trace的概念
在广义上,一个trace代表了一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准中,trace是多个span组成的一个有向五环图(DAG),每一个span代表trace中被命名并计时的连续性的执行片段。
在这里插入图片描述

例如客户端发起的一次请求,就可以认为是一个Trace。将上面的图通过Open Tracing的语义修改完之后做可视化,得到下面的图:
在这里插入图片描述
图中每一个色块其实就是一个span。

2、Span的概念
一个Span代表系统中具有开始时间和执行时长的逻辑运行单元。span之间通过嵌套或者顺序排列建立逻辑因果关系。
Span里面的信息包括:操作的名字,开始时间和结束时间,可以附带多个key:value构成的Tags(key必须是String,value可以是String,bool或者数字),还可以附带Logs信息(不一定所有的实现都支持)也是key:value形式。

下面例子是一个Trace,里面有8个Span:
在这里插入图片描述
一个span可以和一个或者多个span间存在因果关系。OpenTracing定义了两种关系:Childof和FollowFrom。这两种引用类型代表了子节点和父节点间的直接因果关系。未来,OpenTracing将支持非因果关系的span引用关系。(例如:多个span被批量处理,span在同一个队列中,等等)
ChildOf很好理解,就是父亲Span依赖另一个孩子Span。比如函数调用,被调者是调用者的孩子,比如说RPC调用,服务端那边的Span,就是ChildOf客户端的。很多并发的调用,然后将结果聚合起来的操作,就构成了ChildOf关系。

如果父亲Span并不依赖于孩子Span的返回结果,这时可以说他构成FollowsFrom关系。
在这里插入图片描述
3、Log的概念
每个span可以进行多次Logs操作,每一次Logs操作,都需要一个带时间戳的时间名称,以及可选的任意大小的存储结构。
如下图是一个异常的Log
在这里插入图片描述
如下图是两个正常信息的Log,它们都带有时间戳和对应的事件名称、消息内容。
在这里插入图片描述
4、Tags的概念
每个span可以有多个键值对(key:value)形式的Tags,Tags是没有时间戳的,支持简单的对span进行注解和补充。

如下图就是一个Tags的详细信息,其中记录了数据库访问的SQL语句等内容。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732846.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划 DP (六) 字符串编辑

1.字符串编辑 字符串编辑问题是一类常见的问题&#xff0c;通常涉及对字符串进行插入、删除、替换等操作&#xff0c;以达到某种特定的目标。 常见的字符串编辑问题包括&#xff1a; 编辑距离&#xff08;Edit Distance&#xff09;&#xff1a;给定两个字符串&#xff0c;通…

最新抖音娱乐测评小程序源码 Thinkphp后端 抖音引流小程序

最新抖音娱乐测评小程序源码 thinkphp后端 抖音引流小程序 附搭建教程 测试环境 NginxPHP7.0MySQL5.6 网站运行目录设置为 /web 数据库配置文件 \source\application\database.php 后台登录地址 http://你的域名/index.php?s/admin/passport/login

python环境

卸载旧环境 wini 打开应用卸载 删除python解释器和pycharm 删除配置文件夹JetBrains C:\Users\CJC\AppData\Roaming\JetBrains 安装 安装python解释器 安装pycharm 查看或设置该项目的解释器和安装包 快捷键 全局搜索 双击shift 当前文件中搜索 ctrl f 查看函数…

MySQL数据库对象与数据备份和还原详解

目录 一、视图 1. 什么是视图 2. 视图与数据表的区别 3. 视图的优点 4. 创建视图 二、索引 1. 什么是索引 2. 为什么要使用索引 3. 索引优缺点 4. 何时不使用索引 5. 索引何时失效 6. 索引分类 6.1 普通索引 6.2 唯一索引 6.3 主键索引 6.4 组合索引 三、数据的…

RabbitMQ系列(25)--RabbitMQ搭建镜像队列

前言&#xff1a;如果RabbitMQ集群中只有一个Broker节点&#xff0c;那么该节点的失效将导致整体服务的临时性不可用&#xff0c;并且也可能会导致消息的丢失&#xff0c;虽然可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true&#xff0c;这样可以保证消息…

mysql 常用命令综合简单运用

目录 第一大题创建数据库创建用户表及约束字段修改位置修改字段数据类型修改字段名字添加字段修改表名字删除字段修改表的存储引擎 第二大题创建表及外键和其他约束删除外键约束和查找外键名 第三大题创建数据库创建用户同时授权一些功能修改用户的密码更新权限列表查看用户的权…

pytorch线性模型 学习前要学习的基础知识

跟着刘二大人学pytorch&#xff0c;补全一下我的基础缺失 1.numpy基础 import numpy as np from PIL import Image anp.array([1,2,3]) #生成一维数组 print(a) bnp.arange(1,4)#创建等差数组&#xff0c;默认等差是1&#xff0c;数组为1&#xff0c;2&#xff0c;3&#xff0…

spring 详解三 IOC(spring实例化及后处理器)

Spring实例化基本流程 Spring在容器初始化的时候&#xff0c;读取XMl配置&#xff0c;将其封装成BeanDefinition(Bean定义)对象&#xff0c;描述所有bean的信息 BeanDefinition会注册存储到beanDefinitionMap集合中 Spring框架遍历beanDefinitionMap&#xff0c;使用反射创建Be…

pycharm如何给一串中文快捷加引号(方法二)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 商人重利轻别离&#xff0c;前月浮梁买茶去。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银群【此类生物】问了一个Pycharm基础的问题&a…

SpringBoot配置动态定时任务

1.配置ScheduledTask 主要是实现SchedulingConfigurer&#xff0c;动态传入cron。 package com.hzl.boot.config;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Propert…

使用promise函数封装post请求,封装aes加解密方法,并进行请求头aes加密,封装sm2国密加解密,进行请求体数据加密,响应数据解密。

export default {async post(url, params { header:{}, data:{} }, showLoading true){if(showLoading){uni.showLoading({title:"加载中",mask:true})}let options{header:{...params.header},url:globalParams.basepathurl.url,data:{...params.data}}//渠道 ae…

Devops系列五(CI篇之pipeline libraray)jenkins将gitlab helm yaml和argocd 串联,自动部署到K8S

一、说在前面的话 本文是CI篇的上文&#xff0c;因为上一篇已经作了总体设计&#xff0c;就不再赘述&#xff0c;有需要的请看前文。 我们将演示&#xff0c;使用CI工具–jenkins&#xff0c;怎么和CD工具–argocd串联&#xff0c;重点是在Jenkins该怎么做。准备工作和argocd等…

C++常用库函数 5.输入和输出函数

函数名&#xff1a;fclose 函数原型&#xff1a;int fclose(FILE *stream)&#xff1b; 参数&#xff1a;streamFILE 结构的指针。 所需头文件&#xff1a;<cstdio> 返回值&#xff1a;如果该流成功关闭&#xff0c;fclose 返回0。如果出错&#xff0c;则返回 EOF。 功…

AI在金融领域的应用

AI金融领域 信贷业务 个人信贷单笔数额小、数量大&#xff0c;需要大量的人力和时间投入&#xff0c;信贷审核的数据也呈现出分散化、碎片化的特点。同时传统金融机构和互联网金融公司的风控环节中&#xff0c;普遍存在信息不对称、成本高、时效性差、效率低等问题&#xff0c…

动态规划之343 整数拆分(第6道)

题目&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例&#xff1a; 解法&#xff1a; 其实可以从1开始遍历 j &#xff0c;然后有两种…

Mysql之视图,索引,备份与恢复

目录 一&#xff0c;视图 1.视图是什么&#xff1f; 2.视图的重要性&#xff1f; 3.那些地方使用视图&#xff1f; 4.基本语法 二&#xff0c;索引 1.索引是什么&#xff1f; 2.索引的重要性&#xff1f; 3.索引的种类&#xff1a; 4.那些地方使用索引&#xff1f; 5.…

Gateway服务集成Nacos2021.0.4错误解决

问题 gateway服务集成nacos&#xff0c;启动后报错&#xff1a; Caused by: com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information:; 版本&#xff1a; jdk:1.8 spring-b…

10_Linux中断

目录 Linux中断API函数 中断号 上半部与下半部 软中断 tasklet 工作队列 设备树中断信息节点 获取中断号 修改设备树文件 按键中断驱动程序编写 编写测试APP Linux中断API函数 先来回顾一下裸机实验里面中断的处理方法: 1.使能中断,初始化相应的寄存器。 2.注册中…

windows配置启动若依前后端项目

一、后端 1、环境准备 JDK8、Redis、Mysql、Maven【并配置镜像源】 以上工具全部使用msi/exe安装&#xff0c;并勾选添加到环境变量&#xff0c;如果没有添加到环境变量可以参考其他博主关于每种怎么配置的情况 mysql新增一个目录名为ry-vue的空数据库 2、前往若依官网下载…

MAC M1上docker rocketmq简单环境搭建和代码

工作了这么多年&#xff0c;rocketmq还没有用过&#xff0c;由于现在的工作中涉及到了&#xff0c;周六吃完午饭就开始搞&#xff0c;结果到现在3点钟才把环境弄好&#xff0c;测试代码搞起。 整个流程分成两步 安装简单的rocket环境起springboot项目测试 参考文章&#xff…