SpringCloud分布式微服务链路追踪方案:Zipkin

news2024/10/6 22:33:17

创作博客的目的是希望将自己掌握的知识系统地整理一下,并以博客的形式记录下来。这不仅是为了帮助其他有需要的人查阅相关内容,也是为了自己能够更好地巩固和加深对这些知识的理解。创作的时候也是对自己所学的一次复盘和总结,在创作的过程中,自己也会更全面深入的思考和总结,对于知识的理解也更加深刻,这也让我更加愿意花时间和精力去创作。此外,日后在需要的时候,也可以方便地回顾和参考这些记录。
感谢大家的关注和支持,希望我的分享对你们有所帮助。如果有任何建议或问题,欢迎随时与我交流讨论!

一、引言

随着微服务架构的广泛应用,系统的复杂性也随之增加。在这种复杂的系统中,应用通常由多个相互独立的服务组成,每个服务可能分布在不同的主机上。微服务架构虽然提高了系统的灵活性和可扩展性,但也带来了新的挑战,尤其是在故障排查和性能优化方面。这时,链路追踪(Tracing)成为了一个非常重要的工具。

在这里插入图片描述
注:图片来自网络

如图,在复杂的调用链路中假设存在一条调用链路响应缓慢,如何定位其中延迟高的服务呢?

  • 日志: 通过分析调用链路上的每个服务日志得到结果,这种方式耗时高效率低
  • zipkin:Zipkin是Twitter开源的分布式跟踪系统,是开箱即用的产品,主要用来收集系统的时许数据,从而追踪系统的调用问题,使用zipkin的web UI可以一眼看出延迟高的服务。
  • SkyWalking等

本文只介绍zipkin的使用方式。
在这里插入图片描述
如图所示,各业务系统在彼此调用时,将特定的跟踪消息传递至zipkin,zipkin在收集到跟踪信息后将其聚合处理、存储、展示等,用户可通过web UI方便获得网络延迟、调用链路、系统依赖等等。

在这里插入图片描述
使用zipkin涉及到以下几个概念:

  • Span:基本工作单元,一次链路调用(可以是RPC,DB等没有特定的限制)创建一个span,通过一个64位ID标识它,span通过还有其他的数据,例如描述信息,时间戳,key-value对的(Annotation)tag信息,parent-id等,其中parent-id可以表示span调用链路来源,通俗的理解span就是一次请求信息
  • Trace:类似于树结构的Span集合,表示一条调用链路,存在唯一标识
  • Annotation:注解,用来记录请求特定事件相关信息(例如时间),通常包含四个注解信息
    • cs: Client Start,表示客户端发起请求
    • sr:Server Receive,表示服务端收到请求
    • ss:Server Send,表示服务端完成处理,并将结果发送给客户端
    • cr:Client Received,表示客户端获取到服务端返回信息
  • BinaryAnnotation:提供一些额外信息,一般已key-value对出现

二、安装Zipkin

Zipkin 是由推特开发的分布式链路追踪系统,用于对 Sleuth 产生的日志加以收集并采用可视化的数据对链路追踪进行分析与图表展示,Zipkin 是典型的 C/S(客户端与服务端)架构模式,需要独立部署 Zipkin 服务器,同时也需要在微服务内部持有Zipkin客户端才可以自动实现日志的推送与展示。

1. Jar包部署

下载地址

运行

java -jar zipkin-server-2.3.1-exec.jar

在这里插入图片描述
这样zipkin就是以内存存储的方式进行启动了

2. docker部署

docker-zipkin官方文档:docker-zipkin

  1. 使用以下命令从Docker Hub上拉取Zipkin的Docker镜像:

docker pull openzipkin/zipkin

  1. 运行Zipkin容器

docker run -d --restart always -p 9411:9411 --name zipkin openzipkin/zipkin

该命令将Zipkin以守护进程模式(-d)运行Zipkin容器,并设置容器在退出时始终重启(–restart always)。同时,将容器的9411端口映射到主机的9411端口,以便外部访问。

  1. 测试

Zipkin服务启动后,可以在浏览器中访问以下URL查看Zipkin的Web UI:http://localhost:9411,如果出现下面的画面,那么代表我们zipkin服务配置成功了

在这里插入图片描述

三、项目集成Zipkin

在 Spring Cloud 中集成 Zipkin使用起来还是很方便的,只需引入相关依赖并配置 Zipkin 的地址即可,然后就会把请求的监控数据发往 Zipkin。

  1. 引入依赖
    安装完成后,我们需要引入 sleuth 和 zipkin的依赖。
<!-- sleuth 可以省略-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

<!-- zipkin链路追踪 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

zipkin依赖同时包含了seuth,可以省略sleuth的引用

  1. 添加Zipkin相关配置
spring:
  # sleuth 配置
  sleuth:
    web:
      client:
        enabled: true
    sampler:
      probability: 1.0 # 采样比例为: 0.1(即10%),设置的值介于0.0到1.0之间,1.0则表示全部采集。默认为0.1
  # zipkin 配置
  zipkin:
    base-url: http://192.168.253.10:9411  # 指定了Zipkin服务器的地址

参数示例:

spring:  
  zipkin:  
    base-url: http://<zipkin-server-address>:<zipkin-port>/  # Zipkin服务器地址,例如:http://localhost:9411/  
    sender:  
      type: web  # 发送追踪数据的方式,通常是'web'(HTTP)或'kafka'  
    service:  
      name: ${spring.application.name}  # 服务名,通常会从spring.application.name属性中获取  
  sleuth:  
    sampler:  
      probability: 1.0  # 采样率,1.0表示捕获所有追踪信息,0.1表示10%的追踪信息  
    web:  
      client:  
        # 客户端相关的配置,例如是否开启日志输出等  
      skip-pattern: /health.*,/info.*,/metrics.* # 匹配这些URL模式的请求将不会被追踪  
    baggage-keys: # 行李标签(Baggage),可以在整个分布式追踪中传递的键值对  
      - some-key  
      - another-key  
    propagation:  
      type: b3 # 追踪传播的格式,如b3(Zipkin的默认格式)  
    log:  
      slf4j:  
        enabled: true # 是否在日志中启用Sleuth的日志输出 
  cloud:  
    stream:  
      default-binder: rabbit  # 如果你使用RabbitMQ作为消息代理,则配置此选项(对于Kafka或其他消息代理,配置会不同)  
      bindings:  
        output:  # 如果使用消息队列(如RabbitMQ或Kafka)来发送追踪数据,则配置此部分  
          destination: zipkin  
          content-type: application/x-protobuf

配置说明:
spring.application.name:应用的名称,将作为Zipkin中追踪的服务名称。
spring.sleuth.sampler.probability:采样率,决定哪些追踪数据会被发送到Zipkin服务器。设置为1.0表示捕获所有追踪信息。
spring.sleuth.web.client.skip-pattern:正则表达式模式列表,用于指定哪些URL模式的请求将不会被追踪。
spring.sleuth.baggage-keys:行李标签(Baggage)的键列表,这些键值对可以在整个分布式追踪中传递。
spring.sleuth.propagation.type:追踪传播的格式,如b3是Zipkin的默认格式。
spring.sleuth.log.slf4j.enabled:是否在日志中启用Sleuth的日志输出。
spring.zipkin.base-url:Zipkin服务器的地址,追踪数据将发送到这个地址。
spring.zipkin.sender.type:发送追踪数据的方式,如通过HTTP(‘web’)或Kafka。
spring.zipkin.compression.enabled:是否启用发送前的数据压缩。
spring.cloud.stream.bindings.output:如果使用消息队列发送追踪数据,这部分配置指定了消息队列的目的地、内容类型等。
请注意,这些配置可能会因Spring Cloud和Spring Cloud Sleuth的版本不同而有所变化。

启动项目,查看请求链路情况

在这里插入图片描述

在这里插入图片描述

四、Zipkin数据持久化

Zipkin 默认是将监控数据存储在内存的,如果Zipkin 挂掉或重启的话,那么监控数据就会丢失。所以如果想要搭建生产可用的Zipkin,就需要实现监控数据的持久化。而想要实现数据持久化,自然就是得将数据存储至数据库。

Zipkin 支持将数据存储至:

  • 内存(默认)
  • MySQL
  • Elasticsearch
  • Cassandra

1. 内存存储

默认方式

用法示例:

java -jar zipkin.jar

参数:
MEM_MAX_SPANS:保存的最大 span 的数量,超过了会把最早的 span 删除。默认为500000

将内存中保存的span加倍的示例:

MEM_MAX_SPANS=1000000 java -Xmx1G -jar zipkin.jar

2. mysql存储

首先我们需要在数据库中,执行下面的官方SQL脚本,创建对应的表:官方脚本传送门

如果上述地址过期,请执行下面的SQL脚本,在之前,需要创建一个数据库,叫zipkin

--
-- Copyright The OpenZipkin Authors
-- SPDX-License-Identifier: Apache-2.0
--

CREATE TABLE IF NOT EXISTS zipkin_spans (
  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
  `trace_id` BIGINT NOT NULL,
  `id` BIGINT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `remote_service_name` VARCHAR(255),
  `parent_id` BIGINT,
  `debug` BIT(1),
  `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
  `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query',
  PRIMARY KEY (`trace_id_high`, `trace_id`, `id`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
ALTER TABLE zipkin_spans ADD INDEX(`remote_service_name`) COMMENT 'for getTraces and getRemoteServiceNames';
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';

CREATE TABLE IF NOT EXISTS zipkin_annotations (
  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
  `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
  `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',
  `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
  `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
  `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
  `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
  `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
  `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null'
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds';
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces and autocomplete values';
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces and autocomplete values';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';

CREATE TABLE IF NOT EXISTS zipkin_dependencies (
  `day` DATE NOT NULL,
  `parent` VARCHAR(255) NOT NULL,
  `child` VARCHAR(255) NOT NULL,
  `call_count` BIGINT,
  `error_count` BIGINT,
  PRIMARY KEY (`day`, `parent`, `child`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

执行完成后,我们将会得到下面的三个表
在这里插入图片描述

其中

  • zipkin_spans:存放基本工作单元,也就是一次链路调用的信息
  • zipkin_dependencies:存放的依赖信息
  • zipkin_annotations:用来记录请求特定事件相关信息(例如时间)

然后在按照下面的方式进行启动:

jar包启动

java -jar zipkin.jar --STORAGE_TYPE=mysql --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=root --MYSQL_HOST=localhost --MYSQL_TCP_PORT=3306

docker启动

docker run -d -p 9411:9411 \
  -e STORAGE_TYPE=mysql \
  -e MYSQL_HOST=mysql-host \
  -e MYSQL_PORT=3306 \
  -e MYSQL_USER=root \
  -e MYSQL_PASS=password \
  -e MYSQL_DB=zipkin \
  --name zipkin \
  openzipkin/zipkin

参数:

  • MYSQL_DB:MySQL数据库名,默认为 zipkin
  • MYSQL_USER:用户名
  • MYSQL_HOST:主机地址
  • MYSQL_TCP_PORT:端口
  • MYSQL_MAX_CONNECTIONS:最大连接数据,默认 10
  • MYSQL_USE_SSL:是否使用ssl,需要 javax.net.ssl.trustStore 和 javax.net.ssl.trustStorePassword,默认 false
  • MYSQL_JDBC_URL: 自己设置 JDBC 的 url

3. elasticsearch存储

Zipkin-Elasticsearch 存储数据库的官方文档:elasticsearch-storage

首先,你需要一个运行中的Elasticsearch集群,并且可以正常连接。

环境变量参数:

在启动Zipkin容器时,需要配置一些环境变量来指定Elasticsearch集群的连接信息。这些环境变量包括:

  • STORAGE_TYPE: 存储类型,设为elasticsearch
  • ES_HOSTS: Elasticsearch集群的主机地址,多个地址用逗号分隔
  • ES_HTTP_LOGGING: (可选) Elasticsearch/OpenSearch API 请求,可选项BASIC, HEADERS, BODY
  • ES_INDEX: (可选) Elasticsearch索引名称,默认为zipkin
  • ES_TIMEOUT:连接Elasticsearch的超时时间,单位是毫秒;默认10000(10秒)
  • ES_USERNAME:Elasticsearch的用户名
  • ES_PASSWORD:Elasticsearch的密码
  • ES_PIPELINE:指定Elasticsearch的Ingest Pipeline,用于预处理文档

jar包启动示例:

$ STORAGE_TYPE=elasticsearch ES_HOSTS=http://elasticsearch-host:9200 java -jar zipkin.jar

docker启动示例:

docker run -d -p 9411:9411 \
  -e STORAGE_TYPE=elasticsearch \
  -e ES_HOSTS=http://elasticsearch-host:9200 \
  --name zipkin \
  openzipkin/zipkin

Zipkin 支持的这几种存储方式中,内存显然是不适用于生产的,这一点开始也说了。而使用MySQL 的话,当数据量大时,查询较为缓慢,也不建议使用。Twitter 官方使用的是Cassandra作为Zipkin 的存储数据库,但国内大规模用Cassandra 的公司较少,而且Cassandra 相关文档也不多。

综上,故采用Elasticsearch 是个比较好的选择。

五、原理简介

Zipkin Server主要包括四个模块:

  • Collector 接收或收集各应用传输的数据
  • Storage 存储接受或收集过来的数据,当前支持Memory,MySQL,Cassandra,ElasticSearch等,默认存储在内存中
  • API(Query) 负责查询Storage中存储的数据,提供简单的JSON API获取数据,主要提供给web UI使用
  • Web 提供简单的web界面

Zipkin 分为两端,Zipkin 服务端和Zipkin 客户端,客户端也就是微服务的应用。客户端配置服务端的 URL 地址,一旦发生服务间的调用的时候,会被配置在微服务里面的 Sleuth 的监听器监听,并生成相应的 Trace 和 Span 信息发送给服务端。发送的方式主要有两种,一种是 HTTP 报文的方式,另一种是消息总线的方式如 RabbitMQ、kafka等。

链路追踪基本原理:

一个完整请求链路的追踪ID(traceid)用于查出本次请求调用的所有服务,每一次服务调用的跨度ID(spanid)用来记录调用顺序

在这里插入图片描述
上游服务parenetid用来记录调用的层级关系

在这里插入图片描述
调用时间timestamp,把请求发出、接收、处理的时间都记录下来,计算业务处理耗时和网络耗时,然后用可视化界面展示出来每个调用链路,性能,故障

在这里插入图片描述
还可以记录一些其他信息,比如发起调用服务名称、被调服务名称、返回结果、IP、调用服务的名称等,最后,我们再把相同spanid的信息合成一个大的span块,就完成了一个完整的调用链

在这里插入图片描述
注:图片来自chenchenchen

参考文章:

  • zipkin官方文档
  • SpringCloud 入门实战–Zipkin
  • 分布式链路追踪原理详解及SkyWalking、Zipkin区别

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

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

相关文章

python爬虫需要什么HTTP代理?

用来爬虫的话&#xff0c;还是建议用高匿名代理&#xff0c;但显然题主用了高匿名代理还是出现了一部分问题&#xff0c;我们可以先找到问题关键再解决它&#xff0c;一般爬虫用了高匿名代理出现被封会有以下几种原因&#xff1a; 1.代理IP的质量不过关 一般来说每个网站都有…

AI写文章生成器,这些工具都可以一键智能生成文章

在AI技术快速发展的今天&#xff0c;AI写作生成器成为我们创作内容的重要工具&#xff0c;它可以提高我们的写作效率&#xff0c;节省时间和精力。下面小编就来和大家分享几款优秀的AI写作生成器&#xff0c;帮助你快速生成高质量的文章。 1.专业AI写作工具-文章在线生成器 专…

ChatGPT对那些带有残疾迹象的简历有偏见——但它可以改善

ChatGPT对那些带有残疾迹象的简历有偏见——但它可以改善 去年&#xff0c;华盛顿大学(University of Washington)研究生凯特•格拉兹科(Kate Glazko)在寻找研究实习机会时注意到&#xff0c;招聘人员在网上发布消息称&#xff0c;他们使用OpenAI的ChatGPT和其他人工智能工具来…

如何模拟一个具有网络管理功能的被测件的一些思路

不知道大家有没有遇到过这个问题&#xff1f; 当我们在学习如何测试网络管理时&#xff0c;难题不在于如何编写测试脚本&#xff0c;而是编写完测试脚本后&#xff0c;没有真实被测件来让我们执行测试脚本&#xff0c;进而调试脚本。这也是我在给大家讲CANoe工具和CAPL编程语言…

Android Media Framework(八)OMXNodeInstance - Ⅰ

OpenMAX框架的学习有两大难点&#xff0c;一是组件的状态切换与buffer的流转过程&#xff0c;这部分内容我们已经在IL Spec中学习过了&#xff1b;二是OMX组件使用的buffer类型与buffer分配过程&#xff0c;这一节我们来重点剖析OMX组件使用的buffer类型。 1、引言 在实际应用…

我原以为政务类网站不追求漂亮,打脸啦,漂亮得颠覆你认知。

我原本以为政务类网站一定时沉稳、工整、信息量大的&#xff0c;这些和漂流都关联不上&#xff0c;直到最近看了一些网站&#xff0c;发现我的认识狭隘了。 政务类网站的设计风格通常需要注重以下几个方面&#xff1a; 稳重和专业感&#xff1a; 政务类网站需要给人以稳重、正…

c++分隔字符串

可以使用getline函数。 有两个版本&#xff1a; 至于为什么可以使用getline函数返回值作为while的判断条件&#xff0c;cprimer中表述如下&#xff1a;

51-60 CVPR 2024 最佳论文 | Generative Image Dynamics

在2023年11月&#xff0c;谷歌研究院发布了一项令人瞩目的研究成果——Generative Image Dynamics&#xff08;生成图像动力学&#xff09;。这项技术的核心是将静态的图片转化为动态的、无缝循环的视频&#xff0c;而且更令人兴奋的是&#xff0c;这些生成的视频还具有交互性。…

【Web APIs】JavaScript 事件基础 ② ( “ 事件 “ 开发步骤 | 常见鼠标 “ 事件 “ )

文章目录 一、" 事件 " 开发步骤1、" 事件 " 开发步骤2、完整代码示例 二、常见鼠标 " 事件 "1、常见鼠标 " 事件 "2、鼠标 " 事件 " 代码示例 Web APIs 博客相关参考文档 : WebAPIs 参考文档 : https://developer.mozilla…

计算机组成原理 | CPU子系统(1)基本概述

基本结构模型 运算与缓存部件 数据寄存部件 PSW不是很清楚 存储器是什么&#xff1f;属于那个结构里&#xff1f; 时序处理部件 cpu是大脑&#xff0c;控制器是神经元 ①通过硬件产生控制信号 ②通过软件产生控制信号 外频&#xff08;系统时钟信号&#xff09;&#xff0c;…

Springboot整合cxf进行WebService发布和WebService调用

import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; /** 测试接口 author Μr.ηobοdy date 2019-12-29 */ WebService(name “UserService”, // 暴露服务名称 targetNamespace “http://servic…

后端数据null前端统一显示成空

handleNullValues方法在封装请求接口返回数据时统一处理 // null 转 function handleNullValues(data) {// 使用递归处理多层嵌套的对象或数组function processItem(item) {if (Array.isArray(item)) {return item.map(processItem);} else if (typeof item object &&…

深入解析 Python dataclass:类属性与类方法解释

文章目录 dataclass实例属性和类属性自动设置属性 实例方法静态方法&#xff08;staticmethod&#xff09;和 类方法&#xff08;classmethod&#xff09;静态方法类方法 dataclass dataclass 是 Python 3.7 引入的一个装饰器&#xff0c;用于简化类的定义。 使用 dataclass …

Unity的ScrollView滚动视图复用

发现问题 在游戏开发中有一个常见的需求&#xff0c;就是需要在屏幕显示多个&#xff08;多达上百&#xff09;显示item&#xff0c;然后用户用手指滚动视图可以选择需要查看的item。 现在的情况是在100个data的时候&#xff0c;Unity引擎是直接创建出对应的100个显示item。 …

0801功率放大问题

3个学时讲一个电路&#xff08;两个共集共集并联&#xff09;&#xff0c;4个问题&#xff0c;发展线索 丙类放大电路用在高频通讯行业&#xff0c;低频功放是甲类&#xff0c;乙类&#xff0c;甲乙类 PT三极管的损耗 Pv电源提供的功率 现代模电通常使用方法b 只有交流…

聊聊 golang 中 channel

1、引言 Do not communicate by sharing memory; instead, share memory by communicating Golang 的并发哲学是“不要通过共享内存进行通信&#xff0c;而要通过通信来共享内存”&#xff0c;提倡通过 channel 进行 goroutine 之间的数据传递和同步&#xff0c;而不是通过共享…

YashanDB为新质生产力赋能 灌注合肥区域转型源动力

当前&#xff0c;数据要素已成为我国数字经济的“核心引擎”与“关键生产要素”&#xff0c;为全面激发数据要素的价值&#xff0c;各地区正积极探索数据要素交易平台的可行模式&#xff0c;加快在数据要素领域的布局。近日&#xff0c;深圳计算科学研究院崖山数据库系列产品受…

JDBC从入门到精通-笔记(一):JDBC基本概念与开发基础

视频资源&#xff1a;JDBC从入门到精通视频教程-JDBC实战精讲_哔哩哔哩_bilibili JDBC定义与本质 概念 什么是JDBC&#xff1a;Java DataBase Connectivity JDBC本质&#xff1a;SUN公司制定的一套接口&#xff08;interface&#xff09;&#xff0c;java.sql.*。 面向接口调…

【progressBar-js】优雅的 前端进度条 构建!

progressBar-js JS 前端进度条小工具 您可以通过此工具来构建一个有效的工具条&#xff0c;接下来就是一个示例&#xff01; 使用示例 引入 progressBar-js 库 直接在这里将 css 和 js 文件引入进来就算是成功导入了哦&#xff01;&#xff01;&#xff01; <link href&…

SVN学习(001 svn安装)

尚硅谷SVN高级教程(svn操作详解) 总时长 4:53:00 共72P 此文章包含第1p-第p19的内容 介绍 为什么使用版本控制工具 版本控制工具的功能 版本控制简介 客户端服务器结构 c/s结构 服务端的结构&#xff1a; 服务程序 、版本库(存放我们上传的文件) 客户端的三个基本操作&#…