MySQL 主从 AUTO_INCREMENT 不一致问题分析

作者:vivo 互联网数据库团队 - Wei Haodong

本文介绍了 MySQL5.7 中常见的replace into 操作造成的主从auto_increment不一致现象,一旦触发了主从切换,业务的正常插入操作会触发主键冲突的报错提示。

一、问题描述

1.1 问题现象

在 MySQL 5.7 版本中,REPLACE INTO 操作在表存在自增主键的情况下,可能会出现表的auto_increment值主从不一致现象,如果在此期间发生主从故障切换,当原来的slave节点变成了新的master节点,由于表的auto_increment值是小于原主库的,当业务继续写入时,就会收到主键冲突的报错提示。

相关报错信息如下:

! 报错提示

ERROR 1062 (23000): Duplicate entry 'XXX' for key 'PRIMARY'

1.2 影响评估

在业务逻辑中使用了Replace into,或者INSERT...ON DUPLICATE KEY UPDATE。

一旦出现了表的auto_increment值主从不一致现象,在出现MySQL主从故障切换后,业务的正常写入会报主键冲突的错误,当auto_increment相差不多,或许在业务重试的时候会跳过报错,但是auto_increment相差较多时,会超出业务重试的次数,这样造成的影响会更大。

二、问题复现

2.1 环境搭建

这里在测试环境中,搭建MySQL社区版 5.7 版本,一主一从的架构。

【OS】:CentOS Linux release 7.3

【MySQL】:社区版本 5.7

【主从架构】:一主一从

【库表信息】:库名:test2023

 表名:test_autoincrement

表结构如下:

CREATE TABLE `test_autoincrement` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`name` varchar(100) NOT NULL DEFAULT 'test' COMMENT '测试名字',`uid` int(11) NOT NULL COMMENT '测试表唯一键',PRIMARY KEY (`id`),UNIQUE KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2 准备测试数据

MySQL [test2023]> insert into test_autoincrement(name,uid) select '张三',1001;
Query OK, 1 row affected (0.08 sec)
Records: 1  Duplicates: 0  Warnings: 0MySQL [test2023]> insert into test_autoincrement(name,uid) select '李四',1002;
Query OK, 1 row affected (0.06 sec)
Records: 1  Duplicates: 0  Warnings: 0MySQL [test2023]>
MySQL [test2023]> insert into test_autoincrement(name,uid) select '王五',1003;
Query OK, 1 row affected (0.08 sec)
Records: 1  Duplicates: 0  Warnings: 0

正常情况下,插入一行数据,影响的行数是1。

此时查看主从节点表的autoincrement值,可以看到此时主从的AUTO_INCREMENT是一致的,都是4,即自增主键下一次申请的值是4。

图片

2.3 问题复现模拟

2.3.1 模拟REPLACE INTO操作

MySQL [test2023]> REPLACE INTO test_autoincrement (name,uid) values('张三丰',1001);
Query OK, 2 rows affected (0.01 sec)

这里通过REPLACE INTO操作判断,如果存在唯一ID为1001的记录,那么将name字段的值更改为"张三丰",可发现此时影响的行数是2。现在我们再次查看主从节点表的autoincrement值。

图片

此时出现了主从节点表的AUTO_INCREMENT不一致现象。

2.3.2 模拟主从切换

由于是在测试环境,这里就直接进行了主从关系的更改。

(1)停止当前slave节点的复制线程

MySQL [test2023]> stop slave;
Query OK, 0 rows affected (0.08 sec)

(2)查看当前slave节点的Executed_Gtid_Set值

MySQL [test2023]> show master status\G
*************************** 1. row ***************************File: binlog.000002Position: 4317Binlog_Do_DB:Binlog_Ignore_DB:
Executed_Gtid_Set: 9cc90407-ff89-11ed-8b7a-fa163e2d11e1:1-82,
a0c1d6ff-5764-11ee-94ea-fa163e2d11e1:1-11
1 row in set (0.01 sec)

(3)重做主从关系

MySQL [test2023]> CHANGE MASTER TO MASTER_HOST = '原slave节点的IP地址', MASTER_USER = '复制账户', MASTER_PASSWORD = '密码', MASTER_PORT = 端口, MASTER_AUTO_POSITION = 1 ;
Query OK, 0 rows affected, 2 warnings (0.21 sec)MySQL [test2023]> start slave;
Query OK, 0 rows affected (0.05 sec)
MySQL [test2023]> show slave status\G
*************************** 1. row ***************************Slave_IO_State: Waiting for master to send eventMaster_Host: XXXMaster_User: XXXMaster_Port: XXXConnect_Retry: 60Master_Log_File: binlog.000002Read_Master_Log_Pos: 4317Relay_Log_File: relay.000004Relay_Log_Pos: 445Relay_Master_Log_File: binlog.000002Slave_IO_Running: YesSlave_SQL_Running: YesReplicate_Do_DB:Replicate_Ignore_DB:Replicate_Do_Table:Replicate_Ignore_Table:Replicate_Wild_Do_Table:Replicate_Wild_Ignore_Table:Last_Errno: 0Last_Error:Skip_Counter: 0Exec_Master_Log_Pos: 4317Relay_Log_Space: 726Until_Condition: NoneUntil_Log_File:Until_Log_Pos: 0Master_SSL_Allowed: NoMaster_SSL_CA_File:Master_SSL_CA_Path:Master_SSL_Cert:Master_SSL_Cipher:Master_SSL_Key:Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: NoLast_IO_Errno: 0Last_IO_Error:Last_SQL_Errno: 0Last_SQL_Error:Replicate_Ignore_Server_Ids:Master_Server_Id: 461470011Master_UUID: a0c1d6ff-5764-11ee-94ea-fa163e2d11e1Master_Info_File: mysql.slave_master_infoSQL_Delay: 0SQL_Remaining_Delay: NULLSlave_SQL_Running_State: Slave has read all relay log; waiting for more updatesMaster_Retry_Count: 86400Master_Bind:Last_IO_Error_Timestamp:Last_SQL_Error_Timestamp:Master_SSL_Crl:Master_SSL_Crlpath:Retrieved_Gtid_Set: a0c1d6ff-5764-11ee-94ea-fa163e2d11e1:11Executed_Gtid_Set: 9cc90407-ff89-11ed-8b7a-fa163e2d11e1:1-82,
a0c1d6ff-5764-11ee-94ea-fa163e2d11e1:1-11Auto_Position: 1Replicate_Rewrite_DB:Channel_Name:Master_TLS_Version:
1 row in set (0.00 sec)

2.3.3 模拟业务正常写入

MySQL [test2023]> insert into test_autoincrement(name,uid) select '赵六',1004;
ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'

到这里我们看到了预期的报错现象,如果是正常业务系统,这里的主从节点表的AUTO_INCREMENT可能会相差非常大,业务的正常插入就会持续报错了。

意味着真实的操作是先做delete操作,然后再进行insert。

三、原因分析

3.1 为什么从库节点的 autoincrement 没有变化?

# at 10790
#230927 16:23:45 server id 46147000  end_log_pos 10863 CRC32 0x85c60fb7         Update_rows: table id 122 flags: STMT_END_FBINLOG '
keYTZRO4JcACRQAAACYqAAAAAHoAAAAAAAEACHRlc3QyMDIzABJ0ZXN0X2F1dG9pbmNyZW1lbnQA
AwMPAwKQAQCCO6qB
keYTZR+4JcACSQAAAG8qAAAAAHoAAAAAAAEAAgAD///4AQAAAAYA5byg5LiJ6QMAAPgEAAAACQDl
vKDkuInkuLDpAwAAtw/GhQ==
'/*!*/;
### UPDATE `test2023`.`test_autoincrement`
### WHERE
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2='张三' /* VARSTRING(400) meta=400 nullable=0 is_null=0 */
###   @3=1001 /* INT meta=0 nullable=0 is_null=0 */
### SET
###   @1=4 /* INT meta=0 nullable=0 is_null=0 */
###   @2='张三丰' /* VARSTRING(400) meta=400 nullable=0 is_null=0 */
###   @3=1001 /* INT meta=0 nullable=0 is_null=0 */
# at 10863
#230927 16:23:45 server id 46147000  end_log_pos 10894 CRC32 0xe204d99b         Xid = 331
COMMIT/*!*/;

这里可以看到REPLACE INTO操作对应的binlog日志记录其实是update操作,从库节点在应用update操作时,发现命中数据时,对应的autoincrement是没有变化的。

3.2 REPLACE INTO 操作的官方定义是什么?

官方对于 REPLACE INTO 的定义如下:

摘选自MySQL :: MySQL 5.7 Reference Manual :: 13.2.8 REPLACE Statement

REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted. See Section 13.2.5, “INSERT Statement”.

REPLACE is a MySQL extension to the SQL standard. It either inserts, or deletes and inserts. For another MySQL extension to standard SQL—that either inserts or updates—see Section 13.2.5.2, “INSERT ... ON DUPLICATE KEY UPDATE Statement”.

这里可以看到一张表包含主键或者唯一键的情况下,replace操作会判断原有的数据行是否存在,如果存在的话,就先删除旧的数据,然后进行insert操作,如果不存在的话,就和insert操作时一样的。

第二段也提到了INSERT ... ON DUPLICATE KEY UPDATE Statement ,其实这个操作也会造成上面的主从autoincrement不一致现象,这里就不展开讨论了。

! Note

REPLACE makes sense only if a table has a PRIMARY KEY or UNIQUE index. Otherwise, it becomes equivalent to INSERT, because there is no index to be used to determine whether a new row duplicates another.

3.3  为什么REPLACE INTO操作在binlog日志中记录的是update操作?

这里我们通过源码文件sql_insert.cc和log_event.cc进行分析。

sql_insert.cc:
...
/* Check if there is more uniq keys after field */static int last_uniq_key(TABLE *table,uint keynr)
{/*When an underlying storage engine informs that the unique keyconflicts are not reported in the ascending order by settingthe HA_DUPLICATE_KEY_NOT_IN_ORDER flag, we cannot rely on thisinformation to determine the last key conflict.The information about the last key conflict will be used todo a replace of the new row on the conflicting row, ratherthan doing a delete (of old row) + insert (of new row).Hence check for this flag and disable replacing the last rowby returning 0 always. Returning 0 will result in doinga delete + insert always.*/if (table->file->ha_table_flags() & HA_DUPLICATE_KEY_NOT_IN_ORDER){return 0;}while (++keynr < table->s->keys){if (table->key_info[keynr].flags & HA_NOSAME){return 0;}}return 1;
}
.../*The manual defines the REPLACE semantics that it is eitheran INSERT or DELETE(s) + INSERT; FOREIGN KEY checks inInnoDB do not function in the defined way if we allow MySQLto convert the latter operation internally to an UPDATE.We also should not perform this conversion if we havetimestamp field with ON UPDATE which is different from DEFAULT.Another case when conversion should not be performed is whenwe have ON DELETE trigger on table so user may notice thatwe cheat here. Note that it is ok to do such conversion fortables which have ON UPDATE but have no ON DELETE triggers,we just should not expose this fact to users by invokingON UPDATE triggers.*/if (last_uniq_key(table,key_nr) &&!table->file->referenced_by_foreign_key() &&(!table->triggers || !table->triggers->has_delete_triggers())){if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&error != HA_ERR_RECORD_IS_THE_SAME)goto err;if (error != HA_ERR_RECORD_IS_THE_SAME)info->stats.deleted++;elseerror= 0;thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);/*Since we pretend that we have done insert we should callits after triggers.*/goto after_trg_n_copied_inc;}else{
...}
...

上述源码中可以看到在主库中replace 操作其实是insert 或者 delete + insert 

The manual defines the REPLACE semantics that it is either an INSERT or DELETE(s) + INSERT;

而 MySQL 在主从同步的binlog日志中,将replace操作转换为update操作的条件为:当发生冲突的键是最后一个唯一键,且没有外键约束,且没有触发器,由于我们的测试表中是没有外键约束,也没有触发器的,所以从库接收到的binlog日志中转化为update的条件即为最后一个唯一键。

这里,我们再进行测试一下(去掉表中的唯一索引uid)。

(1)创建新表

CREATE TABLE `test_autoincrement_2` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`name` varchar(100) NOT NULL DEFAULT 'test' COMMENT '测试名字',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

(2)插入测试数据

insert into test_autoincrement_2(name) select '孙七';insert into test_autoincrement_2(name) select '周八';insert into test_autoincrement_2(name) select '吴九';#此时主从表结构是一致的,如下:CREATE TABLE `test_autoincrement_2` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`name` varchar(100) NOT NULL DEFAULT 'test' COMMENT '测试名字',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4

(3)replace into 操作验证主库和从库的AUTO_INCREMENT

MySQL [test2023]> REPLACE INTO test_autoincrement_2 (id,name) values(3,'郑十');
Query OK, 2 rows affected (0.08 sec)

这里我们把id=3的这一行数据对应的name修改为’郑十’,可发现上述影响的行数是2。

再次验证主库和从库的AUTO_INCREMENT,发现并没有发生变化,还是4。

CREATE TABLE `test_autoincrement_2` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`name` varchar(100) NOT NULL DEFAULT 'test' COMMENT '测试名字',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4

(4)分析binlog日志文件

# at 8089
#230928 15:52:08 server id 461470011  end_log_pos 8151 CRC32 0xc2ff85bb         Update_rows: table id 481 flags: STMT_END_FBINLOG '
qDAVZRM7eYEbRgAAAJkfAAAAAOEBAAAAAAEACHRlc3QyMDIzABR0ZXN0X2F1dG9pbmNyZW1lbnRf
MgACAw8CkAEAFSqQxg==
qDAVZR87eYEbPgAAANcfAAAAAOEBAAAAAAEAAgAC///8AwAAAAYA5ZC05Lmd/AMAAAAGAOmDkeWN
gbuF/8I=
'/*!*/;
### UPDATE `test2023`.`test_autoincrement_2`
### WHERE
###   @1=3 /* INT meta=0 nullable=0 is_null=0 */
###   @2='吴九' /* VARSTRING(400) meta=400 nullable=0 is_null=0 */
### SET
###   @1=3 /* INT meta=0 nullable=0 is_null=0 */
###   @2='郑十' /* VARSTRING(400) meta=400 nullable=0 is_null=0 */
# at 8151
#230928 15:52:08 server id 461470011  end_log_pos 8182 CRC32 0xaa39d2a4         Xid = 699
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

总结:可发现binlog日志记录的同样是update 操作。只是当表中除了主键外没有额外的唯一键时,replace into的操作并不会触发从库的auto_increment的异常问题。比如上述的案例REPLACE INTO test_autoincrement_2 (id,name) values(3,'郑十');,这里仅更改了name字段,由‘吴九‘修改为’郑十’。但是主键id是没有变化的,当然也就不需要再次使用auto_increment,这里也可以看到主库的auto_increment当然也没有发现变化(当表中除了主键外含有额外的唯一键时,是会触发申请auto_increment的),binlog接收的仍然是update操作,所以从库的auto_increment也是没有变化的,这样就没法造成auto_increment和主库不一致的问题了。

四、解决方案

到这里,我们是明白了replace into 会造成主从的auto_increment 不一致,但是怎么去解决呢?

4.1 升级到 MySQL 8.0 版本

在 MySQL 8.0 版本中已将AUTO_INCREMENT值做了持久化,且在做更新操作时,会将表上的自增列被更新为比auto_increment更大的值,auto_increment值也将被更新。

4.2 修改 AUTO_INCREMENT 值

线上环境可能已经有很多这种情况,在没有触发业务报错的情况下,一般是很难发现这个隐患,如何在日常巡检中找到这些问题才是关键。

巡检逻辑一:这里可以通过巡检判断从库的max(id) >= AUTO_INCREMENT的方式来找出已经存在问题的表信息。然后通过SQL语句:ALTER TABLE table_name AUTO_INCREMENT = new_value;  进行修改。

巡检步骤可参考:

(1)仅检测某从节点,包含auto_increment 属性的表,过滤SQL如下:

select TABLE_SCHEMA,TABLE_NAME,AUTO_INCREMENT from information_schema.tables where table_schema not in ('information_schema','mysql','performance_schema','sys') AUTO_INCREMENTis not null \G

(2)加锁后读表信息,语句如下:

① 给表加锁

lock tables table_name write;

②读取数据和表auto_increment值进行比对

MAXID=select max(id) from table_name;
AUTO_INCREMENT=select AUTO_INCREMENT from information_schema.tables where TABLE_NAME='t1' ;

③ 判断条件

如果MAXID >= AUTO_INCREMENT , 判断为异常

巡检逻辑二:可以在高可用切换的时候增加AUTO_INCREMENT值判断,如果AUTO_INCREMENT值不一致,则不发生切换,不过这里的slave节点AUTO_INCREMENT的值本身可能因为延迟等问题,就会稍落后maste主节点,正常的巡检还是有难度的,还有就是当MySQL主从切换触发时,如果是因为原主库宕机了,不触发切换也会有问题,所以还是需要提前尽快把这个隐患排除掉。

4.3 禁用 replace into 操作

业务侧禁用replace into 或 insert ... on duplicate  key update ,实现方式可以通过代码逻辑来实现。

4.4 replace into操作的表不增加其他唯一索引

这里其实实现还是有难度的,自增id是不可控的,业务一般是不会使用数据库自带的自增id。

五、问题总结

1. REPLACE INTO 操作在表存在自增主键且包含唯一索引的情况下,当出现数据冲突的时候,会触发AUTO_INCREMENT在主从节点的不一致,一旦主从发生切换,就会造成业务的写入报主键冲突的错误。解决建议:业务更改实现方式,避免使用replace into,或者使用MySQL8.0 及以上的版本来解决该问题。

2. 该问题是一个官方的BUG,不过并没有在MySQL5.7的版本中得到修复 。

MySQL Bugs: #83030: AUTO_INCREMENT not updated when using REPLACE INTO

参考文献:

  1. MySQL Bugs: #83030: AUTO_INCREMENT not updated when using REPLACE INTO

  2. MySQL :: WL#6204: InnoDB persistent max value for autoinc columns

  3. MySQL Bugs: #20188: REPLACE or ON DUPLICATE KEY UPDATE in auto_increment breaks binlog

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络——初识网络

在现如今&#xff0c;网络已经成了一种基础设施&#xff0c;大到国家&#xff0c;小到个人&#xff0c;网络已经充斥在我们每个人的身 边&#xff0c;如果一个人突然失去了网络&#xff0c;那么它的生活或多或少会出现一些不方便的地方&#xff0c;网络现在已 经伴随着我们的吃…

python镜像安装(ios、windows)

如果你在使用Python时发现官方网站下载速度过慢&#xff0c;可以考虑使用国内的Python镜像源下载Python。国内的Python镜像源可以提供更快的下载速度和更好的下载体验。 以下是使用国内Python镜像源下载Python的步骤&#xff1a; 步骤 1&#xff1a;选择Python版本 首先&…

C++11 设计模式1. 模板方法(Template Method)模式学习。UML图

一 什么是 "模板方法&#xff08;Template Method&#xff09;模式" 在固定步骤确定的情况下&#xff0c;通过多态机制在多个子类中对每个步骤的细节进行差异化实现&#xff0c;这就是模板方法模式能够达到的效果。 模板方法模式属于&#xff1a;行为型模式。 二 &…

PostgreSQL入门到实战-第十四弹

PostgreSQL入门到实战 PostgreSQL数据过滤(七)官网地址PostgreSQL概述PostgreSQL中BETWEEN 命令理论PostgreSQL中BETWEEN 命令实战更新计划 PostgreSQL数据过滤(七) BETWEEN运算符允许您检查值是否在值的范围内。 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容…

坚持十天做完Python入门编程100题第三天加班

坚持十天做完Python入门编程100题第三天加班 第24题 扫描文件列表第25题 如何将字典转换成JSON并写入json文件&#xff1f;第26题 JSON转换成字典 第24题 扫描文件列表 如何扫描当前目录下的文件列表&#xff1f;解析&#xff1a;可以使用python内置的glob模块&#xff0c;用法…

Python | Leetcode Python题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; class Solution:def generateParenthesis(self, n: int) -> List[str]:if n 0:return []total_l []total_l.append([None]) # 0组括号时记为Nonetotal_l.append(["()"]) # 1组括号只有一种情况for i in range(2,n1): …

区块链:开启信任的新时代

区块链是一种基于去中心化、分布式的数据存储、传输、记录和验证的数据库技术。它通过一串使用密码学算法链接起来的区块&#xff0c;形成了一个公开透明、不可篡改的数据记录系统。 区块链技术的核心特点就是去中心化。在传统的中心化系统中&#xff0c;数据存储和记录往往由…

商家转账到零钱功能如何操作开通

商家转账到零钱是什么&#xff1f; 商家转账到零钱是微信商户号里的一个功能&#xff0c;以前叫做企业付款到零钱。从 2022 年 5 月 18 日开始&#xff0c;原企业付款到零钱升级为商家转账到零钱&#xff0c;已开通商户的功能使用不受影响&#xff0c;新开通商户可前往产品中心…

langchain + azure chatgpt组合配置并运行

首先默认你已经有了azure的账号。 最重要的是选择gpt-35-turbo-instruct模型、api_version&#xff1a;2023-05-15&#xff0c;就这两个参数谷歌我尝试了很久才成功。 我们打开https://portal.azure.com/#home&#xff0c;点击更多服务&#xff1a; 我们点击Azure OpenAI&#…

竞品数据的监测范围

常规的数据监测一般指的是价格监测&#xff0c;品牌对线上产品链接中的页面价、到手价进行监测&#xff0c;同时也可监测标题变化、销量变化、库存变化、优惠信息变化等&#xff0c;对于对够执行数据监测的系统来说&#xff0c;不管哪个品牌的数据都可做到以上维度的监测&#…

【算法基础】选择排序与冒泡排序的思想与实现

文章目录 1. 选择排序1.1 思想1.2 实现 2. 冒泡排序2.1 思想2.2 实现 1. 选择排序 1.1 思想 选择排序的思想很简单&#xff0c;如上图所示。在每一次遍历子数组的过程中&#xff0c;选择最小的和子数组的第一位交换。子数组的选择从一开始的整个数组&#xff0c;到后面范围逐渐…

全局锁和表锁 :给表加个字段怎么有这么多阻碍?

全局锁和表锁 &#xff1a;给表加个字段怎么有这么多阻碍&#xff1f; 今天我要跟你聊聊 MySQL 的锁。数据库锁设计的初衷是处理并发问题。作为多用户共享的资源&#xff0c;当出现并发访问的时候&#xff0c;数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则…

互联网大厂ssp面经之路:计算机网络part1

1. 计算机网络的组成部分有哪些&#xff1f; a. 硬件设备&#xff1a;计算机网络由各种硬件设备组成&#xff0c;包括计算机、服务器、路由器、交换机、网卡等。这些设备通过物理连接&#xff08;如网线、光纤&#xff09;相互连接。 b. 协议&#xff1a;计算机网络中的通信需…

ROS2 采集虚拟仿真环境图像并发布

简介&#xff1a;ROS2功能的学习我们还是在基于OpenAI的gym虚拟仿真环境中来完成&#xff0c;gym虚拟仿真环境安装请参考另一篇教程&#xff0c;这里不再重复说明&#xff0c;接下来我们开始创建一个ROS2的功能节点&#xff0c;并发布虚拟仿真环境小车摄像头的图像&#xff0c;…

图像分割-RSPrompter

文章目录 前言1. 自动化提示器1.1 多尺度特征增强器1.2 RSPrompterAnchor-based PrompterQuery-based Prompter 2. SAM的扩展3. 结果WHU数据集NWPU数据集SSDD数据集 前言 《RSPrompter: Learning to prompt for remote sensing instance segmentation based on visual foundati…

即插即用篇 | YOLOv5/v7引入Haar小波下采样 | 一种简单而有效的语义分割下采样模块

本改进已集成到 YOLOv5-Magic 框架。 下采样操作如最大池化或步幅卷积在卷积神经网络(CNNs)中被广泛应用,用于聚合局部特征、扩大感受野并减少计算负担。然而,对于语义分割任务,对局部邻域的特征进行池化可能导致重要的空间信息丢失,这有助于逐像素预测。为了解决这个问题…

前端window.open的简单使用

JavaScript 中的 Window.open() 用法详解-CSDN博客 window.open("https://www.baidu.com/?tn49055317_12_hao_pg", _blank);

如何在mac毒轻松获取佣金收益

目前 mac毒(macdo.cn) 网站开启了获取佣金的渠道&#xff0c;你可以通过分享专属推广链接的方式来获取佣金。 下面介绍一下具体如何操作&#xff1a; 如何获取专属推广链接 1.首先你需要在mac毒网站注册一个自己的账号&#xff0c;然后在前台进入「会员中心」 2. 接着进入「推…

[leetcode]remove-duplicates-from-sorted-list

. - 力扣&#xff08;LeetCode&#xff09; 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入&…

【全套源码教程】基于SpringBoot+MyBatis+Vue的流浪动物救助网站的设计与实现

目录 前言 需求分析 可行性分析 技术实现 后端框架&#xff1a;Spring Boot 持久层框架&#xff1a;MyBatis 前端框架&#xff1a;Vue.js 数据库&#xff1a;MySQL 功能介绍 前台界面功能介绍 动物领养及捐赠 宠物论坛 公告信息 商品页面 寻宠服务 个人中心 购…