当前位置: 首页 > news >正文

TiDB 组件 GC 原理及常见问题

本文详细介绍了 TiDB 的 Garbage Collection(GC)机制及其在 TiDB 组件中的实现原理和常见问题排查方法。 TiDB 底层使用单机存储引擎 RocksDB,并通过 MVCC 机制,基于 RocksDB 实现了分布式存储引擎 TiKV,以支持高可用分布式事务。 GC 过程旨在清理旧数据,减少其对性能的影响,主要包括四个步骤: 计算 GC safepoint、解析锁(Resolve locks)、连续范围数据删除(Delete ranges)和同步 GC safepoint 至集群其他组件。 文章还讲述了如何定位 GC leader、监控 GC 状态、以及处理 GC 过程中遇到的常见问题。

TiDB 底层使用的是单机存储引擎 RocksDB, 为了实现分布式事务接口,TiDB 又采用 MVCC 机制,基于 RocksDB 实现了高可用分布式存储引擎 TiKV。 也就是当新写入(增删改)的数据覆盖到旧数据时,旧数据不会被替换掉,而是与新写入的数据同时保留,并以时间戳来区分版本。 当这些历史版本堆积越来越多时,就会引出一系列问题,最常见的便是读写变慢。 TiDB 为了降低历史版本对性能的影响,会定期发起 Garbage Collection( https://docs-archive.pingcap.com/zh/tidb/v7.2/garbage-collection-overview GC)清理不再需要的旧数据。

在 上一篇文章 中,我们介绍了 MVCC 版本堆积相关原理及排查手段,当我们发现 MVCC 版本堆积已经对当前集群读写产生了性能影响时,则需要检查当前集群 GC 的状态及相关参数是否需要进行调整。

本文我们将重点介绍 TiDB 组件中 GC 的相关原理及常见排查手段。由于篇幅原因,TiKV 侧的 GC 相关内容我们将在另一篇文章中独立介绍。

GC leader

通过对 TiDB 分布式事务( https://tidb.net/blog/7730ed79 )实现的了解,我们知道 TiDB 集群具体的数据存储在 TiKV 上,集群的元数据信息存在 PD 上,TiDB 要做数据旧版本的回收,则需要有个类似 GC worker 的角色从 PD 拿到元数据信息然后对 TiKV 中的数据做垃圾回收工作。这个角色目前我们放在 TiDB 中,一个就够,所以我们借助 PD 维护选举出一个 GC leader 的角色,来统一协调整个集群的 GC 工作。

GC leader 是 TiDB 中负责推动集群 GC 工作的一个协程(goroutinue), 一个 TiDB 集群中,同一时刻有且只有一个 TiDB 上会有这个 GC leader 角色。

常见排查指导

通常如果怀疑系统 GC 状态可能存在异常,我们可以从 gc leader 所报的日志中查看当前 GC 的详细状态。

  • 如何查找 GC leader 在哪个 tidb 上?
mysql> select variable_name,variable_value from mysql.tidb where variable_name = "tikv_gc_leader_desc"\G;
*************************** 1. row ***************************variable_name: tikv_gc_leader_desc
variable_value: host:172-16-120-219, pid:3628952, start at 2024-01-17 16:34:58.022047311 +0800 CST m=+9.910349289
1 row in set (0.00 sec)
  • 找到 gc leader 对应的 tidb 实例,在日志中 grep "gc_worker" 关键字即可看到当前 GC 的整体运行状态。关于日志中字段的具体含义,我们可以在后面的章节会详细展开介绍。
tidb@172-16-120-219:~/shirly/tiup$ ps aux | grep 3628952
tidb     3592616  0.0  0.0   8160  2456 pts/2    S+   15:12   0:00 grep --color=auto 3628952
tidb     3628952  8.2  0.2 10914336 1065168 ?    Ssl  Jan17 4158:25 bin/tidb-server -P 4005 --status=10080 --host=0.0.0.0 --advertise-address=127.0.0.1 --store=tikv --initialize-insecure --path=127.0.0.1:2379,127.0.0.1:2381,127.0.0.1:2383 --log-slow-query=/DATA/disk4/shirly/tiup/tidb-deploy/tidb-4005/log/tidb_slow_query.log --config=conf/tidb.toml --log-file=/DATA/disk4/shirly/tiup/tidb-deploy/tidb-4005/log/tidb.log
tidb@172-16-120-219:~/shirly/tiup$ grep "gc_worker" /DATA/disk4/shirly/tiup/tidb-deploy/tidb-4005/log/tidb.log  | head
[2024/02/02 19:29:59.062 +08:00] [INFO] [gc_worker.go:1073] ["[gc worker] start resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446541678411803] [concurrency=3]
[2024/02/02 19:29:59.291 +08:00] [INFO] [gc_worker.go:1095] ["[gc worker] finish resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446541678411803] [regions=1236]
[2024/02/02 19:30:59.065 +08:00] [INFO] [gc_worker.go:1073] ["[gc worker] start resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446557407051824] [concurrency=3]
[2024/02/02 19:30:59.283 +08:00] [INFO] [gc_worker.go:1095] ["[gc worker] finish resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446557407051824] [regions=1236]
[2024/02/02 19:31:59.060 +08:00] [INFO] [gc_worker.go:1073] ["[gc worker] start resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446573135691804] [concurrency=3]
[2024/02/02 19:31:59.297 +08:00] [INFO] [gc_worker.go:1095] ["[gc worker] finish resolve locks"] [uuid=6345a3cad480026] [safePoint=0] [try-resolve-locks-ts=447446573135691804] [regions=1236]
[2024/02/02 19:32:59.072 +08:00] [INFO] [gc_worker.go:347] ["[gc worker] starts the whole job"] [uuid=6345a3cad480026] [safePoint=447446510221131776] [concurrency=3]
[2024/02/02 19:32:59.074 +08:00] [INFO] [gc_worker.go:1073] ["[gc worker] start resolve locks"] [uuid=6345a3cad480026] [safePoint=447446510221131776] [try-resolve-locks-ts=447446588864331831] [concurrency=3]
[2024/02/02 19:32:59.305 +08:00] [INFO] [gc_worker.go:1095] ["[gc worker] finish resolve locks"] [uuid=6345a3cad480026] [safePoint=447446510221131776] [try-resolve-locks-ts=447446588864331831] [regions=1236]
[2024/02/02 19:33:59.057 +08:00] [INFO] [gc_worker.go:307] ["[gc worker] there's already a gc job running, skipped"] ["leaderTick on"=6345a3cad480026]

TiDB GC 整体流程及常见问题

TiDB GC 整体流程主要分四个步骤,本章我们将逐一展开介绍。

目前我们 TiDB 侧的 GC 流程主要分为四个步骤:

  • 计算 GC safepoint, 即 TiDB GC 时需要知道具体删除哪个时间点之前的旧版本。
  • 清理 GC safepoint 之前事务留下的锁,即旧版本数据在被清理前,需要明确残留锁所在事务的状态。
  • Delete-ranges 连续范围数据删除,即对于 truncate table 等这类在 TiKV 中连续保存的数据,直接在此阶段进行物理删除以优化性能。
  • 将最新 safepoint 同步到集群其他组件(TiKV)

TiDB 中 GC worker 以上行为的发生频率我们可以在 grafana 监控中 tikv-details->GC->TiDB GC worker actions 看到。

下面我们逐一介绍每个步骤的原理、相关监控、配置及常见问题。

Step 1 计算 GC safepoint

根据 文章 对数据写入的简单介绍,我们知道当对同一个 key 进行多次增删改后,会在 raftstore 层留下所有的历史版本,随着这些版本的堆积,整体的读写性能将受到影响。TiDB 会定期触发 GC 工作对这些历史版本进行回收,那每次 GC 具体回收哪些旧版本数据呢?TiDB 在每次发生 GC 时,都会根据当前配置参数计算出一个 safepoint , 来决定具体回收哪些旧版本数据。

GC safepoint 的定义

  • Safepoint 是一个时间戳,对应一个具体的物理时间。
  • TiDB GC 会保证 ts >safepoint 的所有快照数据的安全性。

如上图,当前 key 一共有四个版本,

  • 如果 gc safepoint 是 5:00, 则 GC 后只会保留 key_4:00 这条数据。
  • 如果 gc safepoint 是 2:30, 则 GC 后会保留 key_4:00,key_3:00,key_02:00 这三条数据。以确保读 2:30 这一时刻的快照时,能读到 key_02:00 这条数据。

另外,当前系统的 gc safepoint 我们也可以在系统表 mysql.tidb 中看到:

GC safepoint 的计算过程及常见问题

了解了 GC safepoint, 我们知道其对集群数据的安全性非常重要,算错了 safepoint, 就可能将还需要的旧版本数据提前永久删除掉。所以在计算 safepoint 的时候,我们考虑到了多种情况。

以下是当前 gc worker 计算 safepoint 的主要过程:

1. 根据 GC lifetime 配置计算

GC lifetime ( https://docs.pingcap.com/tidb/stable/system-variables#tidb_gc_life_time-new-in-v50 )的定义:这个变量用于指定每次 GC 时需要保留的数据时限,默认为 10 分钟,即一般情况下,只保证十分钟以内的数据快照安全性即可。

GC safepoint = Current time - GC lifetime (10min by default)
  • 常见问题

当我们调整 gc lifetime 时,比如调大 gc lifetime 时,在 lifetime 符合要求之前会跳过几次 GC,相关 gc_worker 的日志如下

tidb_172.26.55.107_4000.log:[2024/01/16 09:06:52.689 +08:00] [Info] [gc_worker.go:1613] ["[gc worker] sent safe point to PD"] [uuid=6342b1728dc000d] ["safe point"=447035326078648378]
tidb_172.26.55.107_4000.log:[2024/01/16 09:15:11.099 +08:00] [Info] [gc_worker.go:731] ["[gc worker] there's another service in the cluster requires an earlier safe point. gc will continue with the earlier one"] [uuid=6342b1728dc000d] [ourSafePoint=447035555467755520] [minSafePoint=447035326078648378]

对于这种情况符合预期,无绪介入。

2. 检查长时间运行且未提交的事务

检查当前集群所有 session 里面中,是否存在未提交的事务,且该事务 begin 时间早于上一步算出来的 gc safepoint

GC safepoint = min(GC safepoint,min_start_ts among all sessions)

也就是说,gc safepoint 不应晚于当前正在执行中的事务的开始时间。

为了降低长时间运行的未提交事务对 GC 的影响,我们在 v6.1.0 中引入了参数 tidb_gc_max_wait_time( https://docs.pingcap.com/tidb/dev/system-variables#tidb_gc_max_wait_time-new-in-v610 ) (默认 24 小时),也就是当某个事务执行时间超过 24 小时后,该事务不会再卡住 gc safepoint 的推进。

  • 常见问题

GC 在这一步卡住,可以从 gc_worker 日志中看到具体卡住的事务详情:

[gc_worker.go:359] ["[gc worker] gc safepoint blocked by a running session"] [uuid=609099af5940005] [globalMinStartTS=437144990507073574] [safePoint=2022/11/04 23:29:59.969 +08:00]

Workaround: 检查 processlist 定位卡住的那个事务,咨询业务侧是否可以对该事务进行清理:

select * from INFORMATION_SCHEMA.CLUSTER_PROCESSLIST where TIMESTAMPDIFF(minute, now(), concat("2021-", substring_index(txnstart, "(", 1) )) < -10;

3. 检查当前工具需要保留的快照版本

在实际业务集群中,用户可能使用了 CDC/BR 等备份工具,这些备份工具可能需要更早的一个快照进行备份,也就意味着这部分数据不能被 GC 掉。

GC safepoint = min(GC safepoint, min_service_gc_safe_points)
  • 常见问题

如果 GC 被这部分卡住了,一般可以通过 gc_worker 的日志类似如下:

[2022/02/24 17:18:01.444 +05:30] [INFO] [gc_worker.go:411] ["[gc worker] gc safepoint blocked by a running session"] [uuid=5f56cf29bac008e] [globalMinStartTS=431397745740742701] [safePoint=431398894023213056]
[2022/02/24 17:18:01.450 +05:30] [INFO] [gc_worker.go:581] ["[gc worker] there's another service in the cluster requires an earlier safe point. gc will continue with the earlier one"] [uuid=5f56cf29bac008e] [ourSafePoint=431397745740742701] [minSafePoint=431337131664474119] 

在确认了是这一步卡住的后,就可以通过 PD 查看一下具体是哪个服务卡住了 GC 并介入处理了。

// 通过 pd-ctl 查看 service_gc_safe_points 下面的服务需要的最旧快照对应的 safepoint
tidb@172-16-120-219:~/shirly/tiup$  tiup ctl:v7.5.0 pd  -u http://127.0.0.1:2379  service-gc-safepoint
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl pd -u http://127.0.0.1:2379 service-gc-safepoint
{"service_gc_safe_points": [{"service_id": "gc_worker","expired_at": 9223372036854775807,"safe_point": 447873652897873920 // 这个是在当前这一步上传的 gc safepoint.},{"service_id": "ticdc-default-157...","expired_at": 9223372036854645313,"safe_point": 447873653919043430}],"gc_safe_point": 447873652897873920 // 这个是 TiDB GC 最后一步上传的 safepoint, 用于通知 tikv 用。
}
// 计算每个 service safepoint 实际对应的时间。
tidb@172-16-120-219:~/shirly/tiup$ tiup ctl:v7.5.0 pd  -u http://127.0.0.1:2379  tso 447873652897873920
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl pd -u http://127.0.0.1:2379 tso 447873652897873920
system:  2024-02-21 15:59:59.055 +0800 CST
logic:   0
tidb@172-16-120-219:~/shirly/tiup$ tiup ctl:v7.5.0 pd  -u http://127.0.0.1:2379  tso 447873653919043430
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl pd -u http://127.0.0.1:2379 tso 447873653919043430
system:  2024-02-21 16:00:02.95 +0800 CST
logic:   118630

Step 2 : Resolve locks

为什么要清理锁

在有了 gc safepoint 之后,意味着在本轮 GC 中,我们在保证所有 tso >= safepoint 版本的快照安全性的基础上,可以开始删除旧版本了, 那么在删除旧版本之前,如果遇到了锁怎么办呢?根据我们之前对分布式事务的理解,用户在 commit 一个事务之后,TiKV 内部还是有可能留下锁的,而这些锁的提交状态则是存在 primary-key 上,试想以下情况:

  • 事务 1:
  • 事务 ID 即 start_ts 是 t1, commit_ts 为 t2。
  • 更新 A,B,C 三个 key, 客户端 commit 且返回成功。
  • 当前分布式事务 primary_key 是 A , 也就是事务的状态存在 A 上 。
  • B,C 上有当前 t1 所在事务的残留 lock 。
  • 事务 2:
  • 事务 ID 即 start_ts 为 t3, commit_ts 为 t4。(t1<t2<t3<t4)。
  • 更新 A, D 两个 key, 客户端 commit 且返回成功。
  • A,**D** 新版本写入成功,无残留锁。

现在假设我们算出来的 GC safepoint 是 t4 , 也就是保证能读到 t4 这一时刻的快照数据一致即可。对于 A , 当前 t4 可见的数据为 A_t4=>t3,A_t3=>12, 也就是 A 在 t4 这个时刻快照读到的数据是 12。

对于比这个版本更旧的版本 A_t2=>t1 我们认为在当前 gc safepoint 下是可以删除的。那我们可以直接删除 A_t2=>t1 这个版本吗?

假设我们直接删除,删除之后,如果用户要读 t4 这个快照里面 B 的值,发现 B 上有个指向 (A,t1) 的这个 lock, 我们开始从 A 上确认事务 t1 的状态,但是在 TiKV 中找不到 (A,t1) 这个事务,也就无法确认其状态。

以上,就是我们为什么要在真正清理旧版本数据之前,要先对 gc safepoint 之前启动的事务所在残留锁进行清理的原因,这个过程我们定义为 Resolve locks。

Resolve locks 具体过程

知道了 Resolve locks 的原因后,我们很容易就理解,resolve locks 这一步简单理解,就是对 tikv 中的 Lock CF 进行扫描,并清理掉 lock.ts <= gc safepoint 的锁即可。在实际操作中,我们操作步骤如下:

  1. 将请求发给每个 region 的 leader 获取到 lock
  2. 根据 lock 状态,逐个 resolve lock:
  3. 向 PD 定位当前 lock 里面 primary-key 所在的 region 信息
  4. 向对应的 TiKV 发送获取当前 (primary-key,事务 ID ) 对应的事务状态
  5. 根据 (primary-key,事务 ID) 对应的状态:
  • 事务已提交,向 tikv 提交 lock。
  • 事务已 rollback, 向 tikv 发送回滚该 lock 的消息。

相关配置

既然是按照 region 查找锁并进行清理,这个过程完全可以是并发的,针对这一步,目前 TiDB 提供了以下参数:

  • tidb_gc_concurrency( https://docs.pingcap.com/tidb/v6.5/system-variables#tidb_gc_concurrency-new-in-v50 )Resolve locks 步骤中的线程数,默认 -1 表示使用 TiKV 实例的个数作为并发数。一般情况下不用去调整这个值。

相关监控

在 grafana 上 tikv-details/gc/resolveLocks Progress 面板中,可以看到这一步骤以 region 为单位的执行进度。

常见问题

这一步是否可能卡住 GC?

一般的 resolveLocks 不应该卡住 GC,当这一步骤出现问题时,数据可能存在一致性问题,如果数据比较重要的话,应立即联系官方协助恢复。同样的,这一步骤出现问题需要通过 gc worker 的日志进行判断,可以参考 GC leader 章节的方式定位相关日志。

历史上 v5.1.3 有个 bug( https://github.com/pingcap/tidb/issues/26359 )会导致数据一致性的问题而导致 Resolve Locks 失败。错误日志类似长这样:

[gc_worker.go:621]["[gc worker] resolve locks returns an error"]..

Resolve locks 对性能的影响

对于比较空闲的集群,GC 期间 resolve locks 是会对 TiKV 产生性能影响的,主要原因为 resolve lock 需要对集群中所有 region 读取 lock 信息而导致静默 region 被唤醒,从而导致 raftstore/TiKV CPU 出现抖动。具体影响如下:

  1. 不 hibernate 但 GC。一个 tikv 维护 1w 个 region 需要消耗 15% cpu 的开销。
  2. 不 hibernate 不 GC。一个 tikv 维护 1w 个 region 需要消耗 10% cpu 的开销。
  3. hibernate 不 GC。一个 tikv 维护 1w 个 region 需要消耗 1% cpu 的开销。
  4. hibernate 定期 GC。一个 tikv 维护 1w 个 region 需要消耗 1% cpu 的开销外加 GC 期间达到 10-15% 的开销。

所以 4 相比 1 于就会有类似的尖刺现象,因为平常的 baseline 更低

Step 3 : Delete Ranges

在上一步骤中,我们已经将锁清理完毕,也就是所有 gc safepoint 之前的事务状态已经明确。所以,从这一步开始,我们可以真正地开始清理数据了。在正常情况下,因为我们底层用的是 rocksdb, 在我们明确一个版本可以清理以后,会直接调用 rocksdb 的 delete 接口去清理该 key. 但我们知道,rocksdb 本身使用的是 LSM 架构,也就是说它也有 mvcc, 它的一次删除,最终也是转化成了一次写入。那数据什么时候会真正清理呢?就需要等我们 rocksdb 的。compaction 操作来清理了,这个过程就十分漫长了,后续我们还会继续谈论这个话题。

现在从 TiDB 视角看,有一些数据清理操作,如:

  • Drop table/index
  • Truncate table
  • Drop partition
  • ...

以上操作在 GC 时需要将连续的大片数据进行删除。对于这部分数据,我们认为在过了 GC safepoint 之后,可以直接清理,不需要跟普通的 GC 一样对历史版本一边读一边删除的过程。Delete Ranges 就是我们针对这种连续的大块删除的优化。在这一步骤中,我们会直接对数据进行物理回收,空间会立刻被释放出来,极大地减少这一块 GC 对系统读写的压力。

具体步骤如下:

  • 执行 SQL 阶段:这些符合 delete-range 要求的 SQL 会在执行 时,记录在系统表 mysql.gc_delete_range,并标记其删除的时间 ts:

  • GC 阶段:根据上表中删除时间 ts 与当前 gc safepoint 进行比对,对于符合删除条件的数据,调用 tikv 的 unsafeDestroyRange 接口对所有 tikv 发送。TiKV 在收到这个请求后,会直接绕过 raft 对本地的 rocksdb 进行 destroyRange 操作。同时,做完以后,我们会将结果记录在系统表 gc_delete_range_done 里面:

常见问题

这一步也很少出问题,但是不排除短期内需要删除大量数据时,这一步执行比较慢而导致 GC 看似被卡住的情况。对于这种情况不需要做太多介入,耐心等待其完成即可。

Step 4 : Sync gc safepoint

最后,我们会将 GC safepoint 存储到 PD 上,以通知 tikv 进行 GC。TiKV 定期会从 PD 上拿 gc safepoint, 如果发生了变更,则会拿当前的 gc safepoint 开始 tikv 本地的 GC 工作。

相关监控

我们可以从 grafana 上的 tikv-details->GC->TiKV auto GC safepoint 观察 gc safepoint 推进是否符合预期:

常见问题

PD 一共提供了两个接口来存 gc_safepoint, 分别为:

  • UpdateServiceGCSafepoint:在 计算 GC safepoint 那一步调用,这步调用成功,意味着TiDB侧 GC 正式开始
  • UpdateGCSafepoint 在最后这一步“ save gc safepoint toPD ”执行,这一步调用成功,意味着TiDB侧 GC 正式结束。

一般情况下这两个接口的 safepoint 应该是保持一致的,当不一致时,一般是

updateGCSafepoint< UpdateServiceGCSafepoint

也就是 GC 在 TiDB 这一侧某一步卡住了。生产情况下有些卡住是符合预期的,如下面这种情况:

  • 在工具卡住 gc safepoint 之后,两接口的 gc safepoint 出现不一致。如果此时又正好调大了 gc lifetime, 那么在下一次 gc 成功执行完成之前,这两个接口对应的值会一直不一致。

具体影响:无。

相关文章:

TiDB 组件 GC 原理及常见问题

本文详细介绍了 TiDB 的 Garbage Collection&#xff08;GC&#xff09;机制及其在 TiDB 组件中的实现原理和常见问题排查方法。 TiDB 底层使用单机存储引擎 RocksDB&#xff0c;并通过 MVCC 机制&#xff0c;基于 RocksDB 实现了分布式存储引擎 TiKV&#xff0c;以支持高可用分…...

【c++】STl-list使用list模拟实现

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;c_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 …...

号卡极团分销管理系统 index.php SQL注入漏洞复现

0x01 产品简介 号卡极团分销管理系统,同步对接多平台,同步订单信息,支持敢探号一键上架,首页多套UI+商品下单页多套模板,订单查询支持实时物流信息、支持代理商自定义域名、泛域名绑定,内置敢探号、172平台、号氪云平台第三方接口以及号卡网同系统对接! 0x02 漏洞概述…...

内核驱动更新

1.声明我们是开源的 .c 文件末尾加上 2.在Kconfig里面修改设备&#xff0c;bool&#xff08;双态&#xff09;-----》tristate&#xff08;三态&#xff09; 3.进入menuconfig修改为M 4.编译内核 make modules 也许你会看到一个 .ko 文件 5.复制到根目录文件下 在板子…...

故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab) 模型描述 偏最小二乘法(Partial Least Squares, PLS)是一种统计建模方法,用于建立变量之间的线性关系模型。它是对多元线性回归方法的扩展,特别适用于处理高维数据和具有多重共线性的数据集。…...

我为什么选择成为程序员?

前言&#xff1a; 我选择成为程序员不是兴趣所在&#xff0c;也不是为了职业发展&#xff0c;全是生活所迫&#xff01; 第一章&#xff1a;那年&#xff0c;我双手插兜&#xff0c;对外面的世界一无所知 时间回到2009年&#xff0c;时间过得真快啊&#xff0c;一下就是15年前…...

Open CASCADE学习|统计形状拓扑数量

边界表示法&#xff08;Boundary Representation&#xff0c;简称B-Rep&#xff09;是几何造型中最成熟、无二义的表示法。它主要用于描述物体的几何信息和拓扑信息。在边界表示法中&#xff0c;一个实体&#xff08;Solid&#xff09;由一组封闭的面&#xff08;Face&#xff…...

LeetCode 热题 100 题解(二):双指针部分(2)| 滑动窗口部分(1)

题目四&#xff1a;接雨水&#xff08;No. 43&#xff09; 题目链接&#xff1a;https://leetcode.cn/problems/trapping-rain-water/description/?envTypestudy-plan-v2&envIdtop-100-liked 难度&#xff1a;困难 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&am…...

常用的深度学习自动标注软件

0. 简介 自动标注软件是一个非常节省人力资源的操作&#xff0c;而随着深度学习的发展&#xff0c;这些自动化标定软件也越来越多。本文章将会着重介绍其中比较经典的自动标注软件 1. AutoLabelImg AutoLabelImg 除了labelimg的初始功能外&#xff0c;额外包含十多种辅助标注…...

选择程序员是为什么?

本章节是关于为什么会选择一名程序员的经验分享 首先&#xff0c;我为什么会选择这个方向&#xff0c;可能是因为钱多&#xff0c;学东西不就是为了赚钱嘛&#xff1f;这是一点&#xff0c;不过最让我接收这个行业的是好奇世界的新大陆&#xff0c;可以简单的说就是&#xff0c…...

线程池参数如何设置

线程池参数设置 hello丫&#xff0c;各位小伙伴们&#xff0c;好久不见了&#xff01; 下面&#xff0c;我们先来复习一下线程池的参数 1、线程池参数有哪些&#xff1f; corePoolSize&#xff08;核心线程数&#xff09;&#xff1a;线程池中的常驻核心线程数。即使这些线程…...

qt环境搭建-镜像源安装Qt Creator(5.15.2)以及配置环境变量

前言&#xff1a; 版本&#xff1a;5.15.2 镜像源&#xff1a;ustc与清华 纯小白&#xff0c;找了半天的镜像源安装qtcreator&#xff0c;搞了半天结果安装的是最新的&#xff0c;太新的对小白很不友好&#xff0c;bug比较多&#xff0c;支持的系统也不全&#xff0c;口碑不…...

SQL Server详细安装使用教程

1.安装环境 现阶段基本不用SQL Server数据库了&#xff0c;看到有这样的分析话题&#xff0c;就把多年前的存货发一下&#xff0c;大家也可以讨论看看&#xff0c;思路上希望还有价值。 SQL Server 2008 R2有32位版本和64位版本&#xff0c;32位版本可以安装在Windows XP及以上…...

深度解读C++17中的std::string_view:解锁字符串处理的新境界

深入研究C17中的std::string_view&#xff1a;解锁字符串处理的新境界 一、简介二、std::string_view的基础知识2.1、构造函数2.2、成员函数 三、std::string_view为什么性能高&#xff1f;四、std::string_view的使用陷阱五、std::string_view源码解析六、总结 一、简介 C中有…...

汇编基础-----常见命令基本使用

汇编基础-----常见命令基本使用 MOV&#xff1a;将数据从一个位置复制到另一个位置。 MOV destination, source例如&#xff1a; MOV RAX, RBX ; 将RBX寄存器中的值复制到RAX寄存器中ADD/SUB&#xff1a;将两个操作数相加或相减。 ADD destination, source SUB destinatio…...

科研学习|可视化——相关性结果的可视化

一、相关性分析介绍 相关性分析是指研究两种或者两种以上的变量之间相关关系的统计分析方法&#xff0c;一般分析步骤为&#xff1a; 1&#xff09;判断变量间是否存在关联&#xff1b;2&#xff09;分析关联关系&#xff08;线性/非线性&#xff09;、关联方向&#xff08;正相…...

MapReduce过程解析

一、Map过程解析 Read阶段&#xff1a;MapTask通过用户编写的RecordReader&#xff0c;从输入的InputSplit中解析出一个个key/value。Map阶段&#xff1a;将解析出的key/value交给用户编写的Map()函数处理&#xff0c;并产生一系列的key/value。Collect阶段&#xff1a;在用户编…...

速看!这8道嵌入式面试题你都会吗?

大家好&#xff0c;我是知微&#xff01; 正逢求职季&#xff0c;分享一些嵌入式面试当中经常会遇到的题目&#xff0c;希望这些干货对小伙伴们面试有用哦&#xff01; 1、介绍一下static关键字的作用 在C语言中&#xff0c;static 关键字有几种不同的作用&#xff0c;根据其…...

基于SSM的电影网站(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电影网站&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMv…...

SOCKS代理是如何提高网络性能和兼容性的?

SOCKS代理作为一种网络协议中间件&#xff0c;不仅在提升网络隐私和安全性方面发挥着重要作用&#xff0c;也在提高网络性能和兼容性方面有着不容忽视的影响&#x1f680;。本文将深入探讨SOCKS代理如何通过减少网络延迟&#x1f680;、优化数据传输&#x1f504;、提高跨平台兼…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...