TiDB系列之:TiCDC同步TiDB数据库数据到Kafka集群Topic

news2024/12/23 10:30:13

TiDB系列之:TiCDC同步TiDB数据库数据到Kafka集群Topic

  • 一、Changefeed 概述
    • Changefeed 状态流转
    • 操作 Changefeed
  • 二、同步数据到Kafka
    • 创建同步任务,复制增量数据 Kafka
    • Sink URI 配置 kafka
    • 最佳实践
    • TiCDC 使用 Kafka 的认证与授权
    • TiCDC 集成 Kafka Connect
  • 三、自定义 Kafka Sink 的 Topic 和 Partition 的分发规则
    • Matcher 匹配规则
    • Topic 分发器
    • DDL 事件的分发
    • Partition 分发器
    • 列选择功能
    • 处理超过 Kafka Topic 限制的消息
    • TiCDC 层数据压缩功能

使用TiCDC同步TiDB数据库数据方案如下:

  • TiDB系列之:使用TiCDC增量同步TiDB数据库数据
  • TiDB系列之:TiCDC同步数据到Kafka集群使用Debezium数据格式

使用 TiCDC 创建一个将增量数据复制到 Kafka 的 Changefeed。

一、Changefeed 概述

Changefeed 是 TiCDC 中的单个同步任务。Changefeed 将一个 TiDB 集群中数张表的变更数据输出到一个指定的下游。TiCDC 集群可以运行和管理多个 Changefeed。

Changefeed 状态流转

同步任务状态标识了同步任务的运行情况。在 TiCDC 运行过程中,同步任务可能会运行出错、手动暂停、恢复,或达到指定的 TargetTs,这些行为都可以导致同步任务状态发生变化。本节描述 TiCDC 同步任务的各状态以及状态之间的流转关系。

在这里插入图片描述
以上状态流转图中的状态说明如下:

  • Normal:同步任务正常进行,checkpoint-ts 正常推进。处于这个状态的 changefeed 会阻塞 GC 推进。
  • Stopped:同步任务停止,由于用户手动暂停 (pause) changefeed。处于这个状态的 changefeed 会阻挡 GC 推进。
  • Warning:同步任务报错,由于某些可恢复的错误导致同步无法继续进行。处于这个状态的 changefeed 会不断重试,试图继续推进,直到状态转为 Normal。默认重试时间为 30 分钟(可以通过 changefeed-error-stuck-duration 调整),超过该时间,changefeed 会进入 Failed 状态。处于这个状态的 changefeed 会阻挡 GC 推进。
  • Finished:同步任务完成,同步任务进度已经达到预设的 TargetTs。处于这个状态的 changefeed 不会阻挡 GC 推进。
  • Failed:同步任务失败。处于这个状态的 changefeed 不会自动尝试恢复。为了让用户有足够的时间处理故障,处于这个状态的 changefeed 会阻塞 GC 推进,阻塞时长为 gc-ttl 所设置的值,其默认值为 24 小时。在此期间,如果导致任务失败的问题被修复,用户可以手动恢复 changefeed。超过了 gc-ttl 时长后,如果 changefeed 仍然处于 Failed 状态,则同步任务无法恢复。

注意:

  • 如果是因为 changefeed 阻塞了 GC, 则 changefeed 最多阻塞 GC 推进 gc-ttl 所指定的时长,超过该时长后,changefeed 会被设置成 failed 状态,错误类型为 ErrGCTTLExceeded,不再阻塞 GC 推进。
  • 如果 changefeed 遭遇错误码为 ErrGCTTLExceeded、ErrSnapshotLostByGC 或者 ErrStartTsBeforeGC 类型的错误,则不再阻塞 GC 推进。

以上状态流转图中的编号说明如下:

  • ① 执行 changefeed pause 命令。
  • ② 执行 changefeed resume 恢复同步任务。
  • ③ changefeed 运行过程中发生可恢复的错误,自动重试。
  • ④ changefeed 自动重试成功,checkpoint-ts 已经继续推进。
  • ⑤ changefeed 自动重试超过 30 分钟,重试失败,进入 failed 状态。此时 changefeed 会继续阻塞上游 GC,阻塞时长为 gc-ttl 所配置的时长。
  • ⑥ changefeed 遇到不可重试错误,直接进入 failed 状态。此时 changefeed 会继续阻塞上游 GC,阻塞时长为 gc-ttl 所配置的时长。
  • ⑦ changefeed 的同步进度到达 target-ts 设置的值,完成同步。
  • ⑧ changefeed 停滞时间超过 gc-ttl 所指定的时长,遭遇 GC 推进错误,不可被恢复。
  • ⑨ changefeed 停滞时间小于 gc-ttl 所指定的时长,故障原因被修复,执行 changefeed resume 恢复同步任务。

操作 Changefeed

通过 TiCDC 提供的命令行工具 cdc cli,你可以管理 TiCDC 集群和同步任务,具体可参考管理 TiCDC Changefeed。你也可以通过 HTTP 接口,即 TiCDC OpenAPI 来管理 TiCDC 集群和同步任务,详见 TiCDC OpenAPI。

如果你使用的 TiCDC 是用 TiUP 部署的,可以通过 tiup cdc:v<CLUSTER_VERSION> cli 来使用 TiCDC 命令行工具,注意需要将 v<CLUSTER_VERSION> 替换为 TiCDC 集群版本,例如 v8.1.0。你也可以通过直接执行 cdc cli 直接使用命令行工具。

二、同步数据到Kafka

创建同步任务,复制增量数据 Kafka

使用以下命令来创建同步任务:

cdc cli changefeed create \
    --server=http://10.0.10.25:8300 \
    --sink-uri="kafka://127.0.0.1:9092/topic-name?protocol=canal-json&kafka-version=2.4.0&partition-num=6&max-message-bytes=67108864&replication-factor=1" \
    --changefeed-id="simple-replication-task"
Create changefeed successfully!
ID: simple-replication-task
Info: {"sink-uri":"kafka://127.0.0.1:9092/topic-name?protocol=canal-json&kafka-version=2.4.0&partition-num=6&max-message-bytes=67108864&replication-factor=1","opts":{},"create-time":"2023-11-28T22:04:08.103600025+08:00","start-ts":415241823337054209,"target-ts":0,"admin-job-type":0,"sort-engine":"unified","sort-dir":".","config":{"case-sensitive":false,"filter":{"rules":["*.*"],"ignore-txn-start-ts":null,"ddl-allow-list":null},"mounter":{"worker-num":16},"sink":{"dispatchers":null},"scheduler":{"type":"table-number","polling-time":-1}},"state":"normal","history":null,"error":null}
  • –server:TiCDC 集群中任意一个 TiCDC 服务器的地址。
  • –changefeed-id:同步任务的 ID,如果不指定该 ID,TiCDC 会自动生成一个 UUID。
  • –sink-uri:同步任务下游的地址,详见:Sink URI 配置 Kafka。
  • –start-ts:指定 changefeed 的开始 TSO。TiCDC 集群将从这个 TSO 开始拉取数据。默认为当前时间。
  • –target-ts:指定 changefeed 的目标 TSO。TiCDC 集群拉取数据直到这个 TSO 停止。默认为空,即 TiCDC 不会自动停止。
  • –config:指定 changefeed 配置文件,详见:TiCDC Changefeed 配置参数。

Sink URI 配置 kafka

Sink URI 用于指定 TiCDC 目标系统的连接信息,遵循以下格式:

[scheme]://[host]:[port][/path]?[query_parameters]

如果下游 Kafka 有多个主机或端口,可以在 Sink URI 中配置多个 [host]:[port]

URI 中可配置的的参数如下:

参数描述
topic-name变量,使用的 Kafka topic 名字。
kafka-version下游 Kafka 版本号。该值需要与下游 Kafka 的实际版本保持一致。
kafka-client-id指定同步任务的 Kafka 客户端的 ID(可选,默认值为 TiCDC_sarama_producer_同步任务的 ID)。
partition-num下游 Kafka partition 数量(可选,不能大于实际 partition 数量,否则创建同步任务会失败,默认值 3)。
max-message-bytes每次向 Kafka broker 发送消息的最大数据量(可选,默认值 10MB)。从 v5.0.6 和 v4.0.6 开始,默认值分别从 64MB 和 256MB 调整至 10 MB。
replication-factorKafka 消息保存副本数(可选,默认值 1),需要大于等于 Kafka 中 min.insync.replicas 的值。
required-acks在 Produce 请求中使用的配置项,用于告知 broker 需要收到多少副本确认后才进行响应。可选值有:0(NoResponse:不发送任何响应,只有 TCP ACK),1(WaitForLocal:仅等待本地提交成功后再响应)和 -1(WaitForAll:等待所有同步副本提交后再响应。最小同步副本数量可通过 broker 的 min.insync.replicas 配置项进行配置)。(可选,默认值为 -1)。
compression设置发送消息时使用的压缩算法(可选值为 none、lz4、gzip、snappy 和 zstd,默认值为 none)。注意 Snappy 压缩文件必须遵循官方 Snappy 格式。不支持其他非官方压缩格式。
protocol输出到 Kafka 的消息协议,可选值有 canal-json、open-protocol、avro、debezium 和 simple。
auto-create-topic当传入的 topic-name 在 Kafka 集群不存在时,TiCDC 是否要自动创建该 topic(可选,默认值 true)。
enable-tidb-extension可选,默认值是 false。当输出协议为 canal-json 时,如果该值为 true,TiCDC 会发送 WATERMARK 事件,并在 Kafka 消息中添加 TiDB 扩展字段。从 6.1.0 开始,该参数也可以和输出协议 avro 一起使用。如果该值为 true,TiCDC 会在 Kafka 消息中添加三个 TiDB 扩展字段。
max-batch-size从 v4.0.9 开始引入。当消息协议支持把多条变更记录输出至一条 Kafka 消息时,该参数用于指定这一条 Kafka 消息中变更记录的最多数量。目前,仅当 Kafka 消息的 protocol 为 open-protocol 时有效(可选,默认值 16)。
sasl-user连接下游 Kafka 实例所需的 SASL/PLAIN 或 SASL/SCRAM 认证的用户名(authcid)(可选)。
sasl-password连接下游 Kafka 实例所需的 SASL/PLAIN 或 SASL/SCRAM 认证的密码(可选)。如有特殊字符,需要用 URL encode 转义。
sasl-mechanism连接下游 Kafka 实例所需的 SASL 认证方式的名称,可选值有 plain、scram-sha-256、scram-sha-512 和 gssapi。
dial-timeout和下游 Kafka 建立连接的超时时长,默认值为 10s。
read-timeout读取下游 Kafka 返回的 response 的超时时长,默认值为 10s。
write-timeout向下游 Kafka 发送 request 的超时时长,默认值为 10s。
avro-decimal-handling-mode仅在输出协议是 avro 时有效。该参数决定了如何处理 DECIMAL 类型的字段,值可以是 string 或 precise,表明映射成字符串还是浮点数。
avro-bigint-unsigned-handling-mode仅在输出协议是 avro 时有效。该参数决定了如何处理 BIGINT UNSIGNED 类型的字段,值可以是 string 或 long,表明映射成字符串还是 64 位整型。

最佳实践

  • TiCDC 推荐用户自行创建 Kafka Topic,你至少需要设置该 Topic 每次向 Kafka broker 发送消息的最大数据量和下游 Kafka partition 的数量。在创建 changefeed 的时候,这两项设置分别对应 max-message-bytes 和 partition-num 参数。
  • 如果你在创建 changefeed 时,使用了尚未存在的 Topic,那么 TiCDC 会尝试使用 partition-num 和 replication-factor 参数自行创建 Topic。建议明确指定这两个参数。

TiCDC 使用 Kafka 的认证与授权

使用 Kafka 的 SASL 认证时配置样例如下所示:

  • SASL/PLAIN
--sink-uri="kafka://127.0.0.1:9092/topic-name?kafka-version=2.4.0&sasl-user=alice-user&sasl-password=alice-secret&sasl-mechanism=plain"
  • SASL/SCRAM
    SCRAM-SHA-256、SCRAM-SHA-512 与 PLAIN 方式类似,只需要将 sasl-mechanism 指定为对应的认证方式即可。

TiCDC 集成 Kafka Connect

如要使用 Confluent 提供的 data connectors 向关系型或非关系型数据库传输数据,请选择 avro 协议,并在 schema-registry 中提供 Confluent Schema Registry 的 URL。

配置样例如下所示:

--sink-uri="kafka://127.0.0.1:9092/topic-name?&protocol=avro&replication-factor=3" 
--schema-registry="http://127.0.0.1:8081" 
--config changefeed_config.toml
[sink]
dispatchers = [
 {matcher = ['*.*'], topic = "tidb_{schema}_{table}"},
]

三、自定义 Kafka Sink 的 Topic 和 Partition 的分发规则

Matcher 匹配规则

以如下示例配置文件中的 dispatchers 配置项为例:

[sink]
dispatchers = [
  {matcher = ['test1.*', 'test2.*'], topic = "Topic 表达式 1", partition = "ts" },
  {matcher = ['test3.*', 'test4.*'], topic = "Topic 表达式 2", partition = "index-value" },
  {matcher = ['test1.*', 'test5.*'], topic = "Topic 表达式 3", partition = "table"},
  {matcher = ['test6.*'], partition = "ts"}
]
  • 对于匹配了 matcher 规则的表,按照对应的 topic 表达式指定的策略进行分发。例如表 test3.aa,按照 topic 表达式 2 分发;表 test5.aa,按照 topic 表达式 3 分发。
  • 对于匹配了多个 matcher 规则的表,以靠前的 matcher 对应的 topic 表达式为准。例如表 test1.aa,按照 topic 表达式 1 分发。
  • 对于没有匹配任何 matcher 的表,将对应的数据变更事件发送到 --sink-uri 中指定的默认 topic 中。例如表 test10.aa 发送到默认 topic。
  • 对于匹配了 matcher 规则但是没有指定 topic 分发器的表,将对应的数据变更发送到 --sink-uri 中指定的默认 topic 中。例如表 test6.aa 发送到默认 topic。

Topic 分发器

Topic 分发器用 topic = “xxx” 来指定,并使用 topic 表达式来实现灵活的 topic 分发策略。topic 的总数建议小于 1000。

Topic 表达式的基本规则为 [prefix][{schema}][middle][{table}][suffix],详细解释如下:

  • prefix:可选项,代表 Topic Name 的前缀。
  • {schema}:可选项,用于匹配库名。
  • middle:可选项,代表库表名之间的分隔符。
  • {table}:可选项,用于匹配表名。
  • suffix:可选项,代表 Topic Name 的后缀。

其中 prefix、middle 以及 suffix 仅允许出现大小写字母(a-z、A-Z)、数字(0-9)、点号(.)、下划线(_)和中划线(-);{schema}、{table} 均为小写,诸如 {Schema} 以及 {TABLE} 这样的占位符是无效的。

一些示例如下:

  • matcher = [‘test1.table1’, ‘test2.table2’], topic = “hello_{schema}_{table}”
    • 对于表 test1.table1 对应的数据变更事件,发送到名为 hello_test1_table1 的 topic 中。
    • 对于表 test2.table2 对应的数据变更事件,发送到名为 hello_test2_table2 的 topic 中。
  • matcher = [‘test3.', 'test4.’], topic = “hello_{schema}_world”
    • 对于 test3 下的所有表对应的数据变更事件,发送到名为 hello_test3_world 的 topic 中。
    • 对于 test4 下的所有表对应的数据变更事件,发送到名为 hello_test4_world 的 topic 中。
  • matcher = [‘test5., 'test6.’], topic = “hard_code_topic_name”
    • 对于 test5 和 test6 下的所有表对应的数据变更事件,发送到名为 hard_code_topic_name 的 topic 中。你可以直接指定 topic 名称。
  • matcher = [‘.’], topic = “{schema}_{table}”
    • 对于 TiCDC 监听的所有表,按照“库名_表名”的规则分别分发到独立的 topic 中;例如对于 test.account 表,TiCDC 会将其数据变更日志分发到名为 test_account 的 Topic 中。

DDL 事件的分发

库级别 DDL

诸如 create database、drop database 这类和某一张具体的表无关的 DDL,称之为库级别 DDL。对于库级别 DDL 对应的事件,被发送到 --sink-uri 中指定的默认 topic 中。

表级别 DDL

诸如 alter table、create table 这类和某一张具体的表相关的 DDL,称之为表级别 DDL。对于表级别 DDL 对应的事件,按照 dispatchers 的配置,被发送到相应的 topic 中。

例如,对于 matcher = [‘test.*’], topic = {schema}_{table} 这样的 dispatchers 配置,DDL 事件分发情况如下:

  • 若 DDL 事件中涉及单张表,则将 DDL 事件原样发送到相应的 topic 中。
    • 对于 DDL 事件 drop table test.table1,该事件会被发送到名为 test_table1 的 topic 中。
  • 若 DDL 事件中涉及多张表(rename table / drop table / drop view 都可能涉及多张表),则将单个 DDL 事件拆分为多个发送到相应的 topic 中。
    • 对于 DDL 事件 rename table test.table1 to test.table10, test.table2 to test.table20,则将 rename table test.table1 to test.table10 的 DDL 事件发送到名为 test_table1 的 topic 中,将 rename table test.table2 to test.table20 的 DDL 事件发送到名为 test.table2 的 topic 中。

Partition 分发器

partition 分发器用 partition = “xxx” 来指定,支持 default、index-value、columns、table 和 ts 共五种 partition 分发器,分发规则如下:

  • default:默认使用 table 分发规则。使用所属库名和表名计算 partition 编号,一张表的数据被发送到相同的 partition。单表数据只存在于一个 partition 中并保证有序,但是发送吞吐量有限,无法通过添加消费者的方式提升消费速度。
  • index-value:使用事件所属表的主键、唯一索引或由 index 配置指定的索引的值计算 partition 编号,一张表的数据被发送到多个 partition。单表数据被发送到多个 partition 中,每个 partition 中的数据有序,可以通过添加消费者的方式提升消费速度。
  • columns:使用由 columns 指定的列的值计算 partition 编号。一张表的数据被发送到多个 partition。单表数据被发送到多个 partition 中,每个 partition 中的数据有序,可以通过添加消费者的方式提升消费速度。
  • table:使用事件所属的表的库名和表名计算 partition 编号。
  • ts:使用事件的 commitTs 计算 partition 编号。一张表的数据被发送到多个 partition。单表数据被发送到多个 partition 中,每个 partition 中的数据有序,可以通过添加消费者的方式提升消费速度。一条数据的多次修改可能被发送到不同的 partition 中。消费者消费进度不同可能导致消费端数据不一致。因此,消费端需要对来自多个 partition 的数据按 commitTs 排序后再进行消费。

以如下示例配置文件中的 dispatchers 配置项为例:

[sink]
dispatchers = [
    {matcher = ['test.*'], partition = "index-value"},
    {matcher = ['test1.*'], partition = "index-value", index = "index1"},
    {matcher = ['test2.*'], partition = "columns", columns = ["id", "a"]},
    {matcher = ['test3.*'], partition = "table"},
]
  • 任何属于库 test 的表均使用 index-value 分发规则,即使用主键或者唯一索引的值计算 partition 编号。如果有主键则使用主键,否则使用最短的唯一索引。
  • 任何属于库 test1 的表均使用 index-value 分发规则,并且使用名为 index1 的索引的所有列的值计算 partition 编号。如果指定的索引不存在,则报错。注意,index 指定的索引必须是唯一索引。
  • 任何属于库 test2 的表均使用 columns 分发规则,并且使用列 id 和 a 的值计算 partition 编号。如果任一列不存在,则报错。
  • 任何属于库 test3 的表均使用 table 分发规则。
  • 对于属于库 test4 的表,因为不匹配上述任何一个规则,所以使用默认的 default,即 table 分发规则。

如果一张表,匹配了多个分发规则,以第一个匹配的规则为准。

注意

  • 从 v6.1 开始,为了明确配置项的含义,用来指定 partition 分发器的配置项由原来的 dispatcher 改为 partition,partition 为 dispatcher 的别名。例如,以下两条规则完全等价:
[sink]
dispatchers = [
   {matcher = ['*.*'], dispatcher = "index-value"},
   {matcher = ['*.*'], partition = "index-value"},
]

但是 dispatcher 与 partition 不能出现在同一条规则中。例如,以下规则非法:

{matcher = ['*.*'], dispatcher = "index-value", partition = "table"},

列选择功能

列选择功能支持对事件中的列进行选择,只将指定的列的数据变更事件发送到下游。

以如下示例配置文件中的 column-selectors 配置项为例:

[sink]
column-selectors = [
    {matcher = ['test.t1'], columns = ['a', 'b']},
    {matcher = ['test.*'], columns = ["*", "!b"]},
    {matcher = ['test1.t1'], columns = ['column*', '!column1']},
    {matcher = ['test3.t'], columns = ["column?", "!column1"]},
]
  • 对于表 test.t1,只发送 a 和 b 两列的数据。
  • 对于属于库 test 的表(除 t1 外),发送除 b 列之外的所有列的数据。
  • 对于表 test1.t1,发送所有以 column 开头的列,但是不发送 column1 列的数据。
  • 对于表 test3.t,发送所有以 column 开头且列名长度为 7 的列,但是不发送 column1 列的数据。
  • 不匹配任何规则的表将不进行列过滤,发送所有列的数据。

注意:

  • 经过 column-selectors 规则过滤后,表中的数据必须要有主键或者唯一键被同步,否则在 changefeed 创建或运行时会报错。

处理超过 Kafka Topic 限制的消息

Kafka Topic 对可以接收的消息大小有限制,该限制由 max.message.bytes 参数控制。当 TiCDC Kafka sink 在发送数据时,如果发现数据大小超过了该限制,会导致 changefeed 报错,无法继续同步数据。为了解决这个问题,TiCDC 新增一个参数 large-message-handle-option 并提供如下解决方案。

目前,如下功能支持 Canal-JSON 和 Open Protocol 两种编码协议。使用 Canal-JSON 协议时,你需要在 sink-uri 中设置 enable-tidb-extension=true。

TiCDC 层数据压缩功能

从 v7.4.0 开始,TiCDC Kafka sink 支持在编码消息后立即对数据进行压缩,并与消息大小限制参数比较。该功能能够有效减少超过消息大小限制的情况发生。

配置样例如下所示:

[sink.kafka-config.large-message-handle]
# 该参数从 v7.4.0 开始引入
# 默认为 "none",即不开启编码时的压缩功能
# 可选值有 "none"、"lz4"、"snappy",默认为 "none"
large-message-handle-compression = "none"

开启了 large-message-handle-compression 之后,消费者收到的消息经过特定压缩协议编码,消费者应用程序需要使用指定的压缩协议进行数据解码。

该功能和 Kafka producer 的压缩功能不同:

  • large-message-handle-compression 中指定的压缩算法是对单条 Kafka 消息进行压缩,并且压缩是在与消息大小限制参数比较之前进行。
  • 你也可以同时通过 sink-uri 的 compression 参数配置压缩算法,该配置启用的压缩功能应用在整个发送数据请求,其中包含多条 Kafka 消息。

如果设置了 large-message-handle-compression,TiCDC 在收到一条消息后,先将该消息与消息大小限制参数的值进行对比,大于该消息大小限制的消息会被压缩。如果同时还设置了 sink-uri 的 compression,TiCDC 会根据 sink-uri 的设置,在 sink 级别再次对整个发送数据请求进行压缩。

两种压缩方法的压缩率的计算方法均为:compression ratio = 压缩前的大小 / 压缩后的大小 * 100

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

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

相关文章

移动硬盘有盘符却难启?数据恢复全攻略

现象解析&#xff1a;移动硬盘有盘符打不开的谜团 在日常的数字生活中&#xff0c;移动硬盘作为数据存储与传输的重要工具&#xff0c;扮演着不可或缺的角色。然而&#xff0c;当用户遇到移动硬盘在系统中显示盘符却无法正常访问的情况时&#xff0c;无疑会令人感到焦头烂额。…

hackme漏洞打靶

1.安装好靶机后点击启动进入这样的一个页面 然后我们就要去找这个靶机的IP地址&#xff0c;首先将该虚拟机网卡设置为net模式&#xff0c;然后在物理机中查看自己ip&#xff0c;看看vmnet8的地址c段是什么&#xff0c;我这里是209&#xff0c;然后用工具去扫描该c段下哪个ip开放…

离乡路远,归途已断

首发于我的个人独立博客 guqing’s blog 每次踏上回乡的路&#xff0c;我心中总有一种难以言喻的情感。故乡&#xff0c;那片孕育我成长的土地&#xff0c;依然静静地躺在那儿&#xff0c;似乎未曾改变。 然而&#xff0c;每次回到家乡&#xff0c;我都能感受到微妙的变化&…

探索七款前沿UI设计软件:创新与实践

之前我们分享了制作原型的有用工具。制作完原型后&#xff0c;我们需要优化界面&#xff0c;这就是 UI 设计师的任务了。UI 设计软件对设计师来说非常重要。UI 设计工具的使用是否直接影响到最终结果的质量&#xff0c;所以有人会问&#xff1a;UI 界面设计使用什么软件&#x…

【切面编程】自定义注解实现操作日志

创建一个项目工程 引入相关依赖 <!-- aop切面 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- lombok --> <dependency><gro…

24导游证报名照片要求是什么❓整理好了❗

24导游证报名照片要求是什么❓整理好了❗ 导游资格考试今天开始报名啦&#xff01; ⚠️考生们注意&#xff0c;需要上传免冠证件照、身份证扫描件、学历证明等照片信息&#xff01; ⚠️这里需要注意一下上传的照片文件信息规格&#xff0c;否则上传失败&#xff0c;无法完…

中国星坤耳机插座系列:空间与音质的体验升级

在现代电子设备日益普及的今天&#xff0c;耳机插座作为连接音频设备与用户的重要接口&#xff0c;其设计和性能直接影响着用户的听觉体验。中国星坤耳机插座以其精巧的设计和卓越的性能&#xff0c;为用户提供了既节省空间又保证音质的解决方案。本文将探讨星坤耳机插座的特点…

Vue3_对接声网实时音视频_多人视频会议

目录 一、声网 1.注册账号 2.新建项目 二、实时音视频集成 1.声网CDN集成 2.iframe嵌入html 3.自定义UI集成 4.提高进入房间速度 web项目需要实现一个多人会议&#xff0c;对接的声网的灵动课堂。在这里说一下对接流程。 一、声网 声网成立于2014年&#xff0c;是全球…

知乎信息流广告怎么投?一文读懂知乎广告开户及投放!

作为中国领先的问答社区&#xff0c;知乎以其高质量的内容和活跃的用户群体成为了众多品牌青睐的营销阵地。为了帮助企业更高效地利用知乎平台进行品牌推广&#xff0c;云衔科技提供了全方位的知乎广告开户及代运营服务&#xff0c;助力您的品牌在知乎上实现快速增长。 一、知…

提单和提货单有什么区别❓一文读懂‼️

提货单与提单的区别 在国际贸易和物流领域中&#xff0c;提货单&#xff08;D/O&#xff09;和提单&#xff08;B/L&#xff09;是两个关键的单据&#xff0c;它们在货物清关和提货过程中扮演着重要角色。以下是对这两个单据的详细解释和它们之间的区别。 提货单&#xff08;…

pdf文件怎么删除页面?看完就能学会的四种删除pdf页面方法!

pdf文件怎么删除页面&#xff1f;在日常使用PDF文档的过程中&#xff0c;我们时常会遇到一些没必要存在的页面&#xff0c;保留这些页面可能带来多重不利影响&#xff0c;首先它们会打断阅读的流畅性&#xff0c;这会让人在阅读时感到突兀与不适&#xff0c;其次&#xff0c;这…

CentOS7下搭建配置SVN服务器

1、通过yum安装subversion&#xff0c;根据提示完成安装 <span style"color:#333333"><span style"background-color:#f5f5f5">sudo yum install subversion</span></span> subversion安装在/bin目录 <span style"colo…

蓝桥杯 Python 研究生组-2023-省赛-工作时长

蓝桥账户中心https://www.lanqiao.cn/problems/3494/learning/ 问题描述 小蓝手里有一份 20222022 年度自己的上班打卡记录文件&#xff0c;文件包含若干条打卡记录&#xff0c;每条记录的格式均为“yyyy-MM-dd HH:mm:ssyyyy-MM-dd HH:mm:ss”&#xff0c;即按照年-月-日 时:…

专业级翻译解决方案:2024年商务翻译工具精选

现在科技发达了&#xff0c;不会外语也不怕了&#xff08;因为可以借助很多翻译工具解决这个头疼的问题啦&#xff09;。如果说到翻译你想到的还是百度翻译&#xff0c;那你可以拓宽一些翻译工具待用库啦。现在有不少多功能&#xff0c;好用的翻译软件咯。 1.福昕在线翻译 链…

矿用综采工作面软件开发

故障诊断算法软件界面设计实时监测故障机理分析实时故障诊断 1.软件原型图 2.通信协议

SpringBoot集成GraalVM创建高性能原生镜像

1. GraalVM 原生镜像的介绍 GraalVM原生镜像为部署和运行Java应用程序提供了一种新的方式。与Java虚拟机相比&#xff0c;原生镜像可以以更小的内存占用和更快的启动时间运行。 它们非常适用于使用容器镜像部署的应用程序&#xff0c;当与 "功能即服务"&#xff08…

vue3 主页面 跳转到子页面后 ,再次切换到主页面后 主页面及其它的所有页面 竟然不显示了的解决。

1、child 子页面是这样写的&#xff0c;先上个代码图&#xff0c;template里面包含了Tabs,还有一个Modal(这个是后来加的&#xff09; 2、然后从parent跳转到了这个child&#xff0c;再次切换到parent页面时&#xff0c;什么页面的视图都不显示出来了 3、然后我们可以看到chi…

MySQL:初识数据库初始SQL创建数据库

目录 1、初始数据库 1.1 什么是数据库 1.2 什么是MySQL 2、数据库 2.1 数据库服务&数据库 2.2 C/S架构 3、 初始SQL 3.1 什么是SQL 3.2 SQL分类 4、使用SQL 4.1 查看数据库 4.1.2 语句解析 4.2 创建数据库 4.2.1 if not exists校验 4.2.2 手动明确字符集和排…

GPT 和 BERT 系列论文阅读总结

文章目录 1. GPT1.1 GPT的目的和任务1.2 GPT的实现1.2.1 Unsupervised pre-training1.2.2 Supervised fine-tuning1.2.3 特定任务的输入格式 2. BERT2.1 BERT的目的和任务2.2 BERT的实现2.2.1 Masked Language Model2.2.2 Next Sentence Prediction (NSP) 3. GPT-23.1 初见 pro…

HCL实验2:VLAN

目的&#xff1a;让PC_3和PC_5处于vlan1, PC_4和PC_6处于vlan2 SW1的配置命令: vlan 2 port GigabitEthernet 1/0/2 quit int g1/0/3 port link-type trunk port trunk permit vlan all quit SW2的配置命令&#xff1a; vlan 2 port GigabitEthernet 1/0/2 quit int g1/0/3 p…