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

【数据库】MySQL InnoDB Cluster 高可用架构部署(MGR 3节点)

本实践基于 3 节点集群(1 主 2 从,支持自动故障转移),所有节点已通过 Tar 包部署 MySQL 8.0.43(满足 8.0.17+ 版本要求),操作系统为 Rocky Linux 8root 密码统一为 root.COM2025*。mysql单节点可参考:https://fixpng.top/blog/#/articles?articleId=20205

一、InnoDB Cluster 核心架构与原理

MySQL 官方文档:https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-innodb-cluster.html

InnoDB Cluster 作为 MySQL 官方原生高可用解决方案,核心是基于 MySQL Group Replication(MGR 组复制) 构建的分布式集群体系,通过“节点协同+协议保障+路由透明化”三层设计,实现数据一致性、自动故障转移与简化运维。其架构并非孤立组件的堆砌,而是各模块深度联动的有机整体,需从“协议原理-组件分工-数据流转”三个维度理解。

1. 核心协议:Group Replication(MGR)的底层逻辑

MGR 是 InnoDB Cluster 的“灵魂”,它基于 Paxos 分布式共识协议(优化实现),将多个 MySQL 节点组成一个“复制组”,实现事务的全局一致性同步与节点角色协同。其核心原理可拆解为以下 4 个关键机制

在这里插入图片描述

1.1 事务的“全局共识”机制(强一致性保障)

MGR 采用“写事务全局投票,读事务本地执行”的模式,确保所有节点的数据最终一致(默认配置下为“最终一致”,可通过参数调整为“强一致”),具体流程如下:

  1. 事务发起:客户端向当前主节点(Primary)提交写事务(DML/DDL),主节点先执行事务并生成二进制日志(binlog);
  2. 日志分发:主节点将事务的 binlog 封装为“事务日志事件”,通过 MGR 插件发送给复制组内所有从节点(Secondary);
  3. 节点投票:每个从节点接收事务日志后,先验证事务的合法性(如主键冲突、权限校验),再向主节点反馈“同意提交”或“拒绝”;
  4. 共识决策:主节点收集投票结果,若超过半数节点(含主节点)同意(Paxos 多数派原则),则判定事务“全局通过”,主节点正式提交事务并通知所有从节点;
  5. 从节点执行:从节点收到“事务通过”通知后,执行该事务的 binlog 并提交,确保与主节点数据一致。

关键差异:传统主从复制(如 GTID 异步复制)中,主节点提交事务后直接返回客户端,无需等待从节点确认,可能导致主节点宕机时未同步的事务丢失;而 MGR 的“多数派投票”机制,可确保事务至少在半数节点上完成同步,极大降低数据丢失风险。

1.2 单主模式的角色协同逻辑

InnoDB Cluster 支持“单主模式”(默认)和“多主模式”,本方案采用单主模式(1 主 2 从),角色分工与切换逻辑如下:

  • 角色定义
    • Primary 节点:唯一接收写请求的节点,负责事务的发起与投票协调,同时将读请求分发至自身或从节点(可选);
    • Secondary 节点:仅接收读请求(默认),参与事务投票与日志执行,主节点故障时参与新主选举。
  • 角色选举触发条件
    1. 集群初始化时,自动选举第一个加入组的节点为 Primary;
    2. Primary 节点宕机(如服务崩溃、网络中断)或主动下线(如运维操作);
    3. Primary 节点因“脑裂防护”被踢出集群(如网络分区导致无法与多数节点通信)。
  • 选举优先级规则
    MGR 并非随机选举新主,而是按以下优先级排序(确保选举出“最优节点”):
    1. 节点权重(priority):通过参数 group_replication_member_weight 配置(默认 50,取值 0-100),权重越高优先级越高;
    2. 事务进度(gtid_executed):权重相同时,优先选择已执行 GTID 范围最大的节点(确保数据最新,减少数据恢复成本);
    3. 节点 UUID 排序:前两项一致时,按节点 UUID 字典序升序选择(兜底规则)。
1.3 脑裂防护与成员管理

分布式集群的核心风险是“脑裂”(多节点同时认为自己是 Primary,导致数据分裂),MGR 通过以下机制防护:

  • 多数派通信原则:任何节点要成为 Primary,必须能与复制组内超过半数节点建立通信(如 3 节点集群需至少与 1 个其他节点连通);
  • 成员资格服务(MGM):MGR 内置“成员资格服务”,实时监控节点状态,当节点超时未响应(参数 group_replication_member_expel_timeout 控制,默认 5 秒),则将其“踢出”集群,避免影响整体稳定性;
  • 自动重新加入:被踢出的节点恢复后,会自动向集群发起“重新加入”请求,通过 GTID 自动同步缺失的事务,无需人工干预。
1.4 数据同步模式切换

MGR 支持两种数据同步模式,可根据业务对“一致性”和“性能”的需求灵活调整:

同步模式核心参数适用场景优缺点对比
异步模式(默认)group_replication_consistency=OFF写性能优先(如互联网业务、高并发场景)优点:写延迟低,性能高;缺点:极端情况下(主节点宕机)可能丢失少量未同步事务
强一致模式group_replication_consistency=BEFORE_ON_PRIMARY_FAILOVER数据一致性优先(如金融、交易场景)优点:主节点故障后无数据丢失;缺点:写事务需等待所有节点确认,延迟略高

2. 核心组件:三层架构的分工与联动

InnoDB Cluster 并非仅依赖 MGR,而是通过 MySQL Server(节点)、MySQL Shell(管理)、MySQL Router(路由) 三个组件的联动,实现“部署-运维-接入”全流程的简化。三者的分工与协作逻辑如下:

  • MySQL Server:集群节点(需启用 Group Replication 插件,确保数据同步);
  • MySQL Shell:集群部署与管理的命令行工具,提供可视化运维能力;
  • MySQL Router:透明路由组件,自动分发读写请求(写请求至主节点,读请求至从节点),降低客户端对接复杂度。

在这里插入图片描述

2.1 底层:MySQL Server(集群节点)

所有节点需启用 MGR 插件并配置相关参数,是集群的“数据存储与计算核心”,关键配置与作用如下:

  • 必选插件
    • group_replication.so:MGR 核心插件,负责事务同步、投票、选举;
    • mysqlx.so:MySQL X 协议插件,支持 MySQL Shell 通过 X 协议管理节点(默认启用)。
  • 核心参数(3 节点集群示例)
    [mysqld]
    # 基础配置
    server-id=101  # 每个节点唯一(101/102/103)
    datadir=/data/mysql  # 数据目录(Tar 部署路径)
    socket=/tmp/mysql.sock
    port=3306# GTID 配置(MGR 依赖 GTID 实现事务追踪)
    gtid_mode=ON
    enforce_gtid_consistency=ON
    log_bin=/data/mysql/binlog/mysql-bin
    binlog_format=ROW  # MGR 仅支持 ROW 格式# MGR 核心配置
    plugin-load-add=group_replication.so  # 加载 MGR 插件
    group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"  # 集群唯一 ID(UUID 格式)
    group_replication_local_address="192.168.31.123:33061"  # 本节点 MGR 通信端口(非 3306,默认 33061)
    group_replication_group_seeds="192.168.31.123:33061,192.168.31.124:33061,192.168.31.125:33061"  # 集群种子节点列表
    group_replication_member_weight=80  # 节点权重(主节点可设更高,如 80,从节点设 50)
    group_replication_single_primary_mode=ON  # 启用单主模式
    group_replication_enforce_update_everywhere_checks=OFF  # 单主模式下禁用多主校验
    
  • 核心作用:存储业务数据、执行事务、参与 MGR 协议交互,是集群的“物理基础”。
2.2 中层:MySQL Shell(管理工具)

MySQL Shell 是 InnoDB Cluster 的 “运维入口”,基于 Python/JavaScript 脚本引擎,提供命令行交互界面,支持集群部署、扩容、监控、故障恢复等全流程运维,核心能力如下:

  • 集群生命周期管理
    • 初始化集群(dba.createCluster());
    • 添加节点(cluster.addInstance())、移除节点(cluster.removeInstance());
    • 故障节点重新加入(cluster.rejoinInstance());
    • 切换主节点(cluster.setPrimaryInstance());
    • 解散集群(cluster.dissolve());
    • 切换集群模式(单主→多主:cluster.switchToMultiPrimaryMode();多主→单主:cluster.switchToSinglePrimaryMode())。
  • 状态监控与配置
    • 查看集群拓扑与结构(cluster.describe());
    • 查看集群运行状态(cluster.status());
    • 检查节点与集群的 GTID 同步状态(cluster.checkInstanceState(),注:该方法已标注 deprecated,未来将移除);
    • 配置集群全局参数(cluster.setOption())、节点个性化参数(cluster.setInstanceOption())。
  • 账号与路由管理
    • 创建 / 升级集群管理员账号(cluster.setupAdminAccount());
    • 创建 / 升级 MySQL Router 专用账号(cluster.setupRouterAccount());
    • 查看已接入的 Router 实例(cluster.listRouters())、删除 Router 元数据(cluster.removeRouterMetadata())。
  • 故障恢复与应急处理
    • 集群完全 outage 后重启恢复(dba.rebootClusterFromCompleteOutage());
    • 集群失票后强制恢复仲裁(cluster.forceQuorumUsingPartitionOf());
    • 隔离集群写流量(cluster.fenceWrites())、恢复写流量(cluster.unfenceWrites())。
  • 自动化与扩展能力
    • 支持通过脚本批量部署多节点集群;
    • 扫描更新集群最新拓扑(cluster.rescan());
    • 基于dba对象快速获取已有集群(dba.getCluster())、配置节点初始化参数(dba.configureInstance())。

查看帮助文档

Object.keys(dba);
dba.help();
2.3 上层:MySQL Router(透明路由)

MySQL Router 是客户端与集群之间的“中间件”,负责请求的分发与路由,核心价值是“让客户端无需感知集群拓扑变化”,具体作用如下:

  • 请求路由策略
    • 写请求路由:自动识别当前 Primary 节点,将所有写请求(如 INSERT/UPDATE/DELETE)转发至 Primary,确保数据写入唯一入口;
    • 读请求路由:支持多种分发策略(可通过配置文件调整):
      1. 轮询(Round-Robin):将读请求均匀分发至所有 Secondary 节点(默认),实现读负载均衡;
      2. 权重路由:按节点权重分配读请求(如性能高的节点权重更高);
      3. 就近路由:结合地理位置信息,将请求转发至最近的节点(适用于跨地域集群)。
  • 自动拓扑感知
    MySQL Router 会定期(默认 5 秒)从集群中获取最新拓扑信息(如 Primary 节点切换、节点上下线),无需重启服务即可更新路由规则。例如:
    1. 当 Primary 节点宕机,新主选举完成后,Router 会在 5 秒内将写请求转发至新 Primary;
    2. 当某个 Secondary 节点下线,Router 会自动将其从读请求分发列表中移除,避免客户端连接失败。
  • 连接池与高可用
    • 内置连接池,复用客户端连接,减少 MySQL 节点的连接创建开销;
    • 支持“故障重试”,当某个节点连接失败时,自动重试其他可用节点(如读请求失败时重试其他 Secondary);
    • 提供“健康检查”接口,可集成监控系统(如 Prometheus),实时监控 Router 与集群的连接状态。
2.4 组件联动流程(以“客户端写请求”为例)
  1. 客户端通过 MySQL 标准协议连接 MySQL Router 的“写端口”(默认 6446),无需指定具体集群节点;
  2. MySQL Router 查询本地缓存的“集群拓扑”,确认当前 Primary 节点(如 192.168.31.123);
  3. Router 将写请求转发至 Primary 节点;
  4. Primary 节点执行事务,通过 MGR 向 Secondary 节点(124/125)分发事务日志并发起投票;
  5. 超过半数节点(Primary+1 个 Secondary)确认事务后,Primary 提交事务并返回结果给 Router;
  6. Router 将结果转发至客户端,完成一次写请求;
  7. 若期间 Primary 节点宕机,MGR 自动选举新主(如 124),Router 感知拓扑变化后,后续写请求自动转发至新主,客户端无感知。

3. 核心特性与适用场景

InnoDB Cluster 作为官方方案,其特性与业务场景高度匹配,需明确其优势与局限性:

3.1 核心优势
  • 原生集成:与 MySQL Server 深度集成,无需依赖第三方工具(如 Orchestrator、Keepalived),版本兼容性更高(避免第三方工具与 MySQL 版本不匹配问题);
  • 自动化程度高:从集群部署(MySQL Shell 一键创建)到故障转移(MGR 自动选举),再到路由更新(Router 自动感知),全流程无需人工干预,降低运维成本;
  • 数据一致性强:基于 Paxos 协议的“多数派投票”机制,可配置为“强一致”模式,满足金融、交易等对数据一致性要求高的场景;
  • 透明化接入:客户端无需修改连接代码,仅需将连接地址改为 MySQL Router 端口,即可无缝对接集群,后续集群扩容、节点切换均无感知;
  • 弹性扩展:支持在线添加/移除节点,扩展过程中集群正常提供服务(如添加 Secondary 节点时,自动同步数据,不影响读写)。
3.2 局限性与注意事项
  • 集群规模限制:MGR 集群节点数建议为 3-9 个(节点过多会导致投票延迟增加,影响写性能),不适合超大规模集群(如 20+ 节点);
  • 写性能开销:相比传统异步复制,MGR 的“投票机制”会增加写事务延迟(尤其是强一致模式),高并发写场景(如 QPS 10 万+)需谨慎评估;
  • 存储引擎限制:仅支持 InnoDB 存储引擎(其他引擎如 MyISAM 不支持事务,无法参与 MGR 同步);
  • 网络依赖高:MGR 对网络稳定性要求高,节点间网络延迟需控制在 10ms 以内(建议部署在同一局域网或低延迟专线环境),避免因网络延迟导致投票超时、节点被踢出集群;
  • DDL 操作注意:执行大表 DDL(如 ALTER TABLE)时,会锁定表并同步至所有节点,可能导致集群写性能下降,建议在业务低峰期执行,或采用“Online DDL”(MySQL 8.0 支持大部分 DDL 在线执行)。
3.3 适用场景
  • 中小规模集群:节点数 3-9 个,适合企业级应用、SaaS 服务等场景;
  • 数据一致性要求高的业务:如金融交易、电商订单、支付系统等,可配置强一致模式;
  • 运维资源有限的团队:无需专业运维人员即可管理集群,降低人力成本;
  • 客户端接入复杂的场景:如多语言客户端、 legacy 系统,通过 MySQL Router 实现透明接入,无需修改客户端代码。
3.4 不适用场景
  • 超大规模集群:节点数超过 10 个,MGR 投票延迟会显著影响写性能;
  • 极致写性能场景:如日志采集、实时数据分析等,对写延迟要求极高(如 <1ms),传统异步复制或分库分表方案更合适;
  • 跨地域部署场景:节点分布在不同地域(如北京、上海),网络延迟高(>50ms),MGR 投票易超时,建议采用“主从复制+异地灾备”方案。

通过以上对 InnoDB Cluster 架构、原理与特性的深度解析,可明确其作为官方高可用方案的核心价值——以“原生集成+自动化+一致性”为核心,平衡运维成本与业务可靠性,是中小规模 MySQL 业务实现高可用的优选方案。

二、集群节点信息表

节点IP主机名数据库节点名称服务器配置操作系统软件环境server-id角色
192.168.31.123VM-Rocks8-MySQL-192-168-31-123mysql-node12c8g 100GBLinux Rocks8Tar 部署的 MySQL 8.0.43101
192.168.31.124VM-Rocky8-MySQL-192-168-31-124mysql-node22c8g 100GBLinux Rocks8Tar 部署的 MySQL 8.0.43102
192.168.31.125VM-Rocky8-MySQL-192-168-31-125mysql-node32c8g 100GBLinux Rocks8Tar 部署的 MySQL 8.0.43103

在这里插入图片描述

三、所有节点的 MySQL 配置

所有节点已完成基础部署,核心配置文件为 /etc/my.cnf,需补充组复制相关参数以满足集群要求。以下为完整配置(需根据节点修改 server-idgroup_replication_local_address):

[mysqld]
# 基础认证与网络配置
# default_authentication_plugin=mysql_native_password  # 按需启用,8.0默认caching_sha2_password
port=3306
user=mysql
basedir=/usr/local/mysql  # 安装根目录
datadir=/data/3306/data   # 自定义数据目录
socket=/var/tmp/mysql.sock# 统一socket路径(已适配客户端连接)
log-error=/data/3306/logs/mysql-error.log  # 日志路径
slow_query_log_file=/data/3306/logs/slow.log# 慢查询日志路径
max_allowed_packet=1073741824
skip-name-resolve=1       # 禁用DNS解析,加速连接
lower_case_table_names=1  # 表名不区分大小写(需所有节点一致)
character_set_server=utf8mb4
collation_server=utf8mb4_general_ci
# sql_mode=""  # 按需启用,生产环境建议保留严格模式
# default-time-zone = 'Asia/Shanghai'  # 已通过时区数据导入生效# 性能优化配置(适配2c8g服务器)
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections=800
max_connect_errors=100000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 512
interactive_timeout = 1800
wait_timeout = 1800
connect_timeout= 1800
net_read_timeout= 1800
tmp_table_size = 32M
max_heap_table_size = 32M# InnoDB 引擎配置(适配4G缓冲池)
innodb_buffer_pool_size=4G
innodb_buffer_pool_instances = 4  # 按缓冲池大小拆分(1G/实例)
innodb_data_file_path = ibdata1:50M:autoextend
innodb_flush_log_at_trx_commit = 1  # 事务安全优先(生产环境推荐)
innodb_log_buffer_size = 32M
innodb_log_file_size = 2G
innodb_log_files_in_group = 3
innodb_max_undo_log_size = 4G
innodb_open_files = 65535
innodb_flush_method = O_DIRECT  # 绕过系统缓存,减少IO开销
innodb_lru_scan_depth = 4000
innodb_lock_wait_timeout = 10
innodb_rollback_on_timeout = 1
innodb_print_all_deadlocks = 1
innodb_online_alter_log_max_size = 4G
innodb_print_ddl_logs = 1
innodb_status_file = 1# 慢查询日志配置(便于SQL优化)
slow_query_log = 1
long_query_time = 1  # 执行超1秒视为慢查询
log-queries-not-using-indexes = 1  # 记录未使用索引的SQL
log_throttle_queries_not_using_indexes = 3  # 每秒最多记录3条无索引SQL# Binlog 配置(集群同步核心)
server_id=101  # 注意:node2改为102,node3改为103(所有节点唯一)
log-bin = /data/3306/binlog/mysql-bin  # binlog路径(自定义目录)
binlog_format=row  # 行模式复制(避免SQL_mode差异导致同步失败)
log_bin_trust_function_creators=on  # 允许创建存储函数
max_binlog_size = 1G  # 单个binlog文件最大1G
binlog_row_image = full  # 记录完整行数据(确保同步完整性)
sync_binlog = 1  # 每次事务刷盘(安全优先)
binlog_cache_size = 4M
max_binlog_cache_size = 2G
binlog_expire_logs_seconds = 604800  # binlog保留7天(避免磁盘占满)# GTID 配置(基于GTID的复制,便于集群管理)
gtid_mode=on
enforce_gtid_consistency=on
log-slave-updates=1  # 从节点记录binlog(集群必需)
log_replica_updates=1  # 兼容8.0新参数,替代log-slave-updates# -------------------------- 组复制核心配置(所有节点需添加,数据库初始化完成后才添加) --------------------------
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
plugin_load_add = group_replication.so # 手动加载 Group Replication 插件(关键步骤)
group_replication_group_name="ce786e81-649c-4f2c-b1d8-6e8a731092f5"  # 组UUID(所有节点一致,用uuidgen命令生成)
group_replication_start_on_boot=OFF  # 禁止开机自动启动组复制(由集群管理)
group_replication_local_address="mysql-node1:33061"  # 当前节点通信地址(node2改mysql-node2:33061,node3改mysql-node3:33061)
group_replication_group_seeds="mysql-node1:33061,mysql-node2:33061,mysql-node3:33061"  # 所有节点通信地址(种子列表,所有节点一致)
group_replication_bootstrap_group=OFF  # 禁止自动初始化组(仅主节点初始化时临时改为ON)
group_replication_single_primary_mode=ON  # 启用单主模式(1主2从,符合当前架构)
group_replication_enforce_update_everywhere_checks=OFF  # 单主模式禁用全节点更新检查
group_replication_ip_whitelist="192.168.31.0/24"  # 允许接入的IP段(限制非法节点,所有节点一致)
group_replication_communication_max_message_size=10485760  # 组复制通信最大消息大小(10MB,避免大事务失败)[client]  # 通用客户端段(适配socket路径,mysql/mysqladmin/mysqldump均生效)
socket=/var/tmp/mysql.sock  # 与服务器socket路径一致
user=root  # 可选,默认登录用户
#default-character-set=utf8mb4  # 可选,默认字符集,部分工具可能不兼容

配置说明

  1. 路径适配:所有目录(basedir/datadir/log-bin/log-error)均为部署时自定义的路径(非默认路径),需确保与实际部署一致;
  2. 权限保障:配置后需确认目录所有者为 mysql 用户,避免权限问题:
    chown -R mysql:mysql /usr/local/mysql
    chown -R mysql:mysql /data/3306
    

四、部署前置操作(所有节点执行)

1. 环境初始化(防火墙、SELinux、主机解析)

# 1. 关闭防火墙(或开放3306/33061端口,生产环境推荐开放端口而非关闭)
systemctl stop firewalld
systemctl disable firewalld
# 若需开放端口(替代关闭防火墙):
# firewall-cmd --zone=public --add-port=3306/tcp --permanent
# firewall-cmd --zone=public --add-port=33061/tcp --permanent
# firewall-cmd --reload# 2. 关闭SELinux(需避免权限拦截,永久生效需重启)
setenforce 0  # 临时关闭
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config  # 永久关闭# 3. 配置主机名解析(3节点互认,避免依赖DNS,集群通信必需)
cat >> /etc/hosts << EOF
192.168.31.123  VM-Rocks8-MySQL-192-168-31-123  mysql-node1
192.168.31.124  VM-Rocky8-MySQL-192-168-31-124  mysql-node2
192.168.31.125  VM-Rocky8-MySQL-192-168-31-125  mysql-node3
EOF# 4. 测试节点间网络连通性(确保3306服务端口、33061组复制端口互通)
ping -c 3 mysql-node1  # 测试主机名解析
ping -c 3 mysql-node2
ping -c 3 mysql-node3
telnet mysql-node1 3306  # 测试MySQL服务端口(需先启动MySQL)
telnet mysql-node1 33061 # 测试组复制端口(后续配置后验证)

2. 补充组复制配置并重启 MySQL

所有节点已完成部署,需先补充上述组复制配置,再重启 MySQL 使配置生效:

# 1. 编辑配置文件(补充组复制参数,按节点修改server-id和local_address)
vi /etc/my.cnf# 2. 停止MySQL服务(停止方式,基于systemd配置)
systemctl stop mysqld
# 若未配置systemd,用mysqld_safe停止:
# mysqladmin -uroot -p shutdown --socket=/var/tmp/mysql.sock# 3. 启动MySQL服务(启动方式)
systemctl start mysqld
# 若未配置systemd,用mysqld_safe启动:
# mysqld_safe --user=mysql --basedir=/usr/local/mysql --datadir=/data/3306/data &# 4. 验证组复制插件加载情况(Tar部署直接执行mysql命令,无需进入容器)
mysql -uroot -p --socket=/var/tmp/mysql.sock -e "SELECT * FROM information_schema.plugins WHERE plugin_name LIKE 'group_replication';"
# 预期输出:plugin_name=group_replication,plugin_status=ACTIVE(插件已激活)

五、安装 MySQL Shell(所有节点,集群管理工具)

MySQL Shell 是部署和管理 InnoDB Cluster 的核心工具,版本需与 MySQL 一致(8.0.43),直接通过 RPM 安装:

# 1. 安装依赖(Rocky Linux 8 需先启用epel源,避免依赖缺失,按需执行)
# dnf install -y epel-release
# dnf clean all && dnf makecache# 2. 下载并安装 MySQL Shell(8.0.43,与MySQL版本一致)
wget https://dev.mysql.com/get/Downloads/MySQL-Shell/mysql-shell-8.0.43-1.el8.x86_64.rpm
dnf install -y mysql-shell-8.0.43-1.el8.x86_64.rpm# 3. 验证安装(输出版本即成功)
mysqlsh --version
# 示例输出:mysqlsh   Ver 8.0.43 for Linux on x86_64 - for MySQL 8.0.43 (MySQL Community Server (GPL))# 4. 配置MySQL Shell环境变量(确保可直接调用mysqlsh命令)
echo 'export PATH=/usr/local/mysql/bin:$PATH' >> /etc/profile
source /etc/profile

六、部署 InnoDB Cluster(仅在主节点 mysql-node1 执行)

通过 MySQL Shell 的 dba 模块完成集群初始化与节点添加,步骤如下:

1. 初始化集群(主节点 mysql-node1,192.168.31.123)

# 1. 以root用户登录MySQL Shell(连接本地节点,指定socket路径)
mysqlsh root@localhost:3306 --socket=/var/tmp/mysql.sock --password=root.COM2025*# 2. 检查节点配置(自动检测参数是否符合集群要求,若有报错按提示修复)
dba.checkInstanceConfiguration("root@localhost:3306?socket=/var/tmp/mysql.sock")
# 若提示“需要配置”,执行自动修复(按提示输入root密码root.COM2025*)
dba.configureInstance("root@localhost:3306?socket=/var/tmp/mysql.sock")# 若报错:Dba.checkInstanceConfiguration: Argument #1: Invalid URI: Illegal character [/] found at position 27 (ArgumentError),则使用
dba.checkInstanceConfiguration('root@localhost:3306?socket=%2Fvar%2Ftmp%2Fmysql.sock')
dba.configureInstance('root@localhost:3306?socket=%2Fvar%2Ftmp%2Fmysql.sock')# 3. 临时修改主节点的group_replication_bootstrap_group为ON(仅初始化集群时需要)
# 在MySQL Shell的SQL模式下执行(输入\sql切换到SQL模式)
\sql
SET GLOBAL group_replication_bootstrap_group=ON;
\js  # 切回JavaScript模式(集群命令需JS模式)# 4. 初始化集群(创建集群名为my_innodb_cluster,生成集群管理员账号)
var cluster = dba.createCluster('my_innodb_cluster');
# 执行后按提示设置集群管理员(如clusteradmin)和密码(如Cluster@2025,用于后续集群管理)# 5. 恢复group_replication_bootstrap_group为OFF(初始化完成后重置)
\sql
SET GLOBAL group_replication_bootstrap_group=OFF;
\js# 6. 验证集群初始化结果(输出“1个节点,状态ONLINE”即成功)
var cluster = dba.getCluster();
cluster.status();{"clusterName": "my_innodb_cluster","defaultReplicaSet": {"name": "default","primary": "VM-Rocks8-MySQL-192-168-31-123:3306","ssl": "REQUIRED","status": "OK_NO_TOLERANCE","statusText": "Cluster is NOT tolerant to any failures.","topology": {"VM-Rocks8-MySQL-192-168-31-123:3306": {"address": "VM-Rocks8-MySQL-192-168-31-123:3306","memberRole": "PRIMARY","mode": "R/W","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"}},"topologyMode": "Single-Primary"},"groupInformationSourceMember": "VM-Rocks8-MySQL-192-168-31-123:3306"
}

2. 添加从节点到集群(继续在 mysql-node1 的 MySQL Shell 中执行)

2.1 添加 mysql-node2(192.168.31.124,从节点)
# 先检查node2的配置(若有参数问题,用dba.configureInstance自动修复)
dba.checkInstanceConfiguration('root@mysql-node2:3306')
# 若提示修复,执行:dba.configureInstance('root@mysql-node2:3306')# 添加node2到集群(输入node2的root密码root.COM2025*)
cluster.addInstance('root@mysql-node2:3306');
# 提示从节点(mysql-node2)存在 “集群外的独立事务”,GTID 不一致,无法直接加入集群。
# Please select a recovery method [C]lone/[A]bort (default Abort): C 克隆
  • Clone 插件的重启逻辑与 systemd 服务管理不兼容,克隆完可能自动重启失败
  • 我们去对应服务器 systemctl restart mysqld
2.2 添加 mysql-node3(192.168.31.125,从节点)
# 检查node3的配置(同node2)
dba.checkInstanceConfiguration('root@mysql-node3:3306')
dba.configureInstance('root@mysql-node3:3306')# 添加node3到集群(输入node3的root密码root.COM2025*)
cluster.addInstance('root@mysql-node3:3306');
# 克隆同node2

3. 验证集群状态(所有节点添加完成后)

# 在MySQL Shell中执行,查看集群完整状态
cluster.status();{"clusterName": "my_innodb_cluster","defaultReplicaSet": {"name": "default","primary": "VM-Rocks8-MySQL-192-168-31-123:3306","ssl": "REQUIRED","status": "OK","statusText": "Cluster is ONLINE and can tolerate up to ONE failure.","topology": {"VM-Rocks8-MySQL-192-168-31-123:3306": {"address": "VM-Rocks8-MySQL-192-168-31-123:3306","memberRole": "PRIMARY","mode": "R/W","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"},"VM-Rocky8-MySQL-192-168-31-124:3306": {"address": "VM-Rocky8-MySQL-192-168-31-124:3306","memberRole": "SECONDARY","mode": "R/O","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"},"VM-Rocky8-MySQL-192-168-31-125:3306": {"address": "VM-Rocky8-MySQL-192-168-31-125:3306","memberRole": "SECONDARY","mode": "R/O","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"}},"topologyMode": "Single-Primary"},"groupInformationSourceMember": "VM-Rocks8-MySQL-192-168-31-123:3306"
}

七、安装配置 MySQL Router(客户端入口)

MySQL Router 实现“透明路由”,客户端只需连接 Router 端口,无需感知集群拓扑变化。如果有更高的可用性要求,也可以使用 Keepalived 或 Heartbeat 等工具来实现 MySQL Router 的高可用配置。

1. 安装 MySQL Router(版本与 MySQL 一致,8.0.43)

  • MySQL Router 下载:https://dev.mysql.com/downloads/router/
  • MySQL Router 文档:https://dev.mysql.com/doc/mysql-router/8.0/en/
# 1. 下载并安装 MySQL Router(Rocky Linux 8 RPM包)
wget https://cdn.mysql.com//Downloads/MySQL-Router/mysql-router-community-8.0.43-1.el8.x86_64.rpm
md5sum mysql-router-community-8.0.43-1.el8.x86_64.rpm # b770c6bdbfcf8d1376c997272c56b3c4  
dnf install -y mysql-router-community-8.0.43-1.el8.x86_64.rpm# 2. 初始化 Router(关联InnoDB Cluster,自动生成路由配置,需集群管理员账号)
# 会提示输入 root 用户的密码(即 root.COM2025* 或集群管理员密码)
mysqlrouter --bootstrap root@mysql-node1:3306 \--user=mysqlrouter \--directory=/etc/mysqlrouter \--conf-use-gr-notifications# 3. 启动Router并设置开机自启(用systemd管理)
systemctl start mysqlrouter
systemctl enable mysqlrouter# 4. 验证Router状态(默认端口:读写6446,只读6447)
netstat -tulnp | grep mysqlrouter
# 预期输出(端口监听正常):
# tcp6       0      0 :::6446                 :::*                    LISTEN      xxx/mysqlrouter  # 读写端口
# tcp6       0      0 :::6447                 :::*                    LISTEN      xxx/mysqlrouter  # 只读端口# 5. 查看Router配置(确认路由规则指向节点)
cat /etc/mysqlrouter/mysqlrouter.conf

八、集群功能验证

1. 读写分离验证(客户端连接Router端口)

# 1. 连接Router读写端口6446(写请求自动转发至主节点mysql-node1)
mysql -uroot -p'root.COM2025*' -h192.168.31.123 -P6446# 2. 创建测试数据(主节点支持写操作)
CREATE DATABASE IF NOT EXISTS test_cluster;
USE test_cluster;
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP);
INSERT INTO t1 (name) VALUES ('test_innodb_cluster_1'), ('test_innodb_cluster_2');
SELECT * FROM t1;  # 预期返回2条数据(写成功)
exit;# 3. 连接Router只读端口6447(读请求自动转发至从节点node2/node3)
mysql -uroot -p'root.COM2025*' -h192.168.31.123 -P6447# 4. 读取数据(从节点已同步主节点数据)
USE test_cluster;
SELECT * FROM t1;  # 预期返回与主节点一致的2条数据(读成功)
# 尝试写操作(从节点只读,会报错,验证读写分离生效)
INSERT INTO t1 (name) VALUES ('test_innodb_cluster_3');
# 预期报错:SQL 错误 [1290] [HY000]: The MySQL server is running with the --super-read-only option so it cannot execute this statement
exit;

2. 自动故障转移验证(模拟主节点宕机)

# 1. 查看当前主节点(在MySQL Shell中执行,连接任意在线节点)
mysqlsh root@mysql-node1:3306 --password=root.COM2025*
var cluster = dba.getCluster();
cluster.status();  # 预期输出:"primary": "VM-Rocks8-MySQL-192-168-31-123:3306"(当前主节点)
exit;# 2. 模拟主节点宕机(停止mysql-node1的MySQL服务)
systemctl stop mysqld  # 或用mysqladmin停止:mysqladmin -uroot -p shutdown --socket=/var/tmp/mysql.sock# 3. 等待10-30秒(集群检测节点离线并触发选举),查看故障转移结果
mysqlsh root@mysql-node2:3306 --password=root.COM2025*
var cluster = dba.getCluster();
cluster.status();
# 预期关键输出(故障转移成功):
# "primary": "VM-Rocky8-MySQL-192-168-31-124:3306"(新主节点为node2或node3)
{"clusterName": "my_innodb_cluster","defaultReplicaSet": {"name": "default","primary": "VM-Rocky8-MySQL-192-168-31-124:3306","ssl": "REQUIRED","status": "OK_NO_TOLERANCE_PARTIAL","statusText": "Cluster is NOT tolerant to any failures. 1 member is not active.","topology": {"VM-Rocks8-MySQL-192-168-31-123:3306": {"address": "VM-Rocks8-MySQL-192-168-31-123:3306","memberRole": "SECONDARY","mode": "n/a","readReplicas": {},"role": "HA","shellConnectError": "MySQL Error 2003: Could not open connection to 'VM-Rocks8-MySQL-192-168-31-123:3306': Can't connect to MySQL server on 'VM-Rocks8-MySQL-192-168-31-123:3306' (111)","status": "(MISSING)"},"VM-Rocky8-MySQL-192-168-31-124:3306": {"address": "VM-Rocky8-MySQL-192-168-31-124:3306","memberRole": "PRIMARY","mode": "R/W","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"},"VM-Rocky8-MySQL-192-168-31-125:3306": {"address": "VM-Rocky8-MySQL-192-168-31-125:3306","memberRole": "SECONDARY","mode": "R/O","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"}},"topologyMode": "Single-Primary"},"groupInformationSourceMember": "VM-Rocky8-MySQL-192-168-31-124:3306"
}# 4. 验证新主节点可写(连接Router读写端口6446,自动转发至新主)
mysql -uroot -p'root.COM2025*' -h192.168.31.123 -P6446
USE test_cluster;
INSERT INTO t1 (name) VALUES ('test_failover');  # 新主节点支持写操作
SELECT * FROM t1;  # 预期返回3条数据(含新插入的test_failover)
exit;# 5. 恢复原主节点(mysql-node1)并重新加入集群
# 5.1 启动原主节点的MySQL服务
systemctl start mysqld# 5.2 等待服务启动完成(约30秒),在MySQL Shell中执行重新加入命令
mysqlsh root@mysql-node2:3306 --socket=/var/tmp/mysql.sock --password=root.COM2025*
var cluster = dba.getCluster();
cluster.rejoinInstance('root@mysql-node1:3306?socket=/var/tmp/mysql.sock', {password: 'root.COM2025*'});# 5.3 验证集群恢复状态(所有节点均为ONLINE,原主节点变为从)
cluster.status();
# 预期输出:3个节点均为"status": "ONLINE","primary"仍为新主(如mysql-node2)
exit;

九、后期管理(下线节点、单主多主切换)

1. 从集群中删除节点(适用于节点下线/故障场景)

当集群中某节点需维护、下线或故障无法恢复时,需将其从集群中移除,避免影响集群整体状态。操作需在 主节点(mysql-node1)的 MySQL Shell 中执行,分两种场景处理:

1.1 场景1:节点在线(可正常连接,如主动下线维护)

以删除 mysql-node3(192.168.31.125:3306) 为例:

# 1. 登录主节点MySQL Shell,获取集群对象
mysqlsh root@192.168.31.123:3306  --password=root.COM2025*
var cluster = dba.getCluster();# 2. 执行删除命令(指定待删除节点的地址,输入节点root密码确认)
cluster.removeInstance('root@mysql-node3:3306');# 3. 确认删除结果(查看集群状态,node3应消失或显示为OFFLINE_REMOVED)
cluster.status();
# 预期输出片段:
{"clusterName": "my_innodb_cluster","defaultReplicaSet": {"name": "default","primary": "VM-Rocks8-MySQL-192-168-31-123:3306","ssl": "REQUIRED","status": "OK_NO_TOLERANCE","statusText": "Cluster is NOT tolerant to any failures.","topology": {"VM-Rocks8-MySQL-192-168-31-123:3306": {"address": "VM-Rocks8-MySQL-192-168-31-123:3306","memberRole": "PRIMARY","mode": "R/W","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"},"VM-Rocky8-MySQL-192-168-31-124:3306": {"address": "VM-Rocky8-MySQL-192-168-31-124:3306","memberRole": "SECONDARY","mode": "R/O","readReplicas": {},"replicationLag": "applier_queue_applied","role": "HA","status": "ONLINE","version": "8.0.43"}},"topologyMode": "Single-Primary"},"groupInformationSourceMember": "VM-Rocks8-MySQL-192-168-31-123:3306"
}# 之后可按“2. 添加从节点”步骤重新加入集群
cluster.addInstance('root@mysql-node3:3306');
1.2 场景2:节点离线(无法连接,如硬件故障)

若节点已宕机(如 mysql-node2 断电),直接执行 removeInstance 会报错,需添加 --force 参数强制删除:

# 1. 主节点MySQL Shell中,获取集群对象
var cluster = dba.getCluster();# 2. 强制删除离线节点(无需连接节点,直接从集群元数据中移除,这时必须使用集群中显示的名字)
cluster.removeInstance('VM-Rocky8-MySQL-192-168-31-124:3306', {force: true});cluster.removeInstance('VM-Rocky8-MySQL-192-168-31-124:3306');
WARNING: MySQL Error 2003 (HY000): Can't connect to MySQL server on 'VM-Rocky8-MySQL-192-168-31-124:3306' (111)
ERROR: The instance 'VM-Rocky8-MySQL-192-168-31-124:3306' is not reachable and cannot be safely removed from the cluster.
To safely remove the instance from the cluster, make sure the instance is back ONLINE and try again. If you are sure the instance is permanently unable to rejoin the group and no longer connectable, use the 'force' option to remove it from the metadata.Do you want to continue anyway (only the instance metadata will be removed)? [y/N]: yThe instance will be removed from the InnoDB Cluster.The instance 'VM-Rocky8-MySQL-192-168-31-124:3306' was successfully removed from the cluster.# 3. 验证结果
cluster.status();# 节点重启启动并正常后,之后可按“2. 添加从节点”步骤重新加入集群
cluster.addInstance('root@mysql-node2:3306');
注意事项:
  • 3节点集群删除1个节点后,剩余2节点仍可提供服务,但仅能容忍 0个故障(再故障1个节点则集群不可用),需尽快补充节点;
  • 删除主节点前,需先通过“5. 单主/多主模式切换”将主节点角色转移到其他节点,避免集群无主。

2. 单主模式与多主模式切换

InnoDB Cluster 支持两种拓扑模式:

  • 单主模式(默认):1个主节点(可读写)+ N个从节点(只读),适合写操作少、读操作多的场景;
  • 多主模式(Multi-Primary):所有节点均为可读写,适合写操作分散、需多节点并行写入的场景(需确保业务无数据冲突)。

切换操作需在 任意在线节点的 MySQL Shell 中执行,且集群所有节点需处于 ONLINE 状态。

2.1 单主模式 → 多主模式切换
# 1. 登录MySQL Shell,获取集群对象
mysqlsh root@mysql-node1:3306 --password=root.COM2025*
var cluster = dba.getCluster();# 2. 切换为多主模式(指定拓扑模式为multi-primary)
cluster.switchToMultiPrimaryMode();# 3. 验证切换结果(所有节点的memberRole变为PRIMARY,mode变为R/W)
cluster.status();
# 预期输出片段:
# "topologyMode": "Multi-Primary",
# "topology": {
#   "VM-Rocks8-MySQL-192-168-31-123:3306": {"memberRole": "PRIMARY", "mode": "R/W"},
#   "VM-Rocky8-MySQL-192-168-31-124:3306": {"memberRole": "PRIMARY", "mode": "R/W"},
#   "VM-Rocky8-MySQL-192-168-31-125:3306": {"memberRole": "PRIMARY", "mode": "R/W"}
# }# 4. 测试多主写入(在任意节点执行写操作,其他节点可同步)
# 在node2执行:
mysql -uroot -p'root.COM2025*' -h192.168.31.124 -P3306 -e "INSERT INTO test_cluster.t1 (name) VALUES ('multi-primary-node2');"
# 在node3执行查询,验证数据同步:
mysql -uroot -p'root.COM2025*' -h192.168.31.125 -P3306 -e "SELECT * FROM test_cluster.t1;"
2.2 多主模式 → 单主模式切换

切换回单主模式时,需指定 新主节点(若不指定,集群会默认选择原单主节点):

# 1. 获取集群对象
var cluster = dba.getCluster();# 2. 切换为单主模式,指定mysql-node1为新主节点
cluster.switchToSinglePrimaryMode('root@mysql-node1:3306');# 3. 验证切换结果(仅指定节点为PRIMARY,其他为SECONDARY且mode为R/O)
cluster.status();
# 预期输出片段:
# "topologyMode": "Single-Primary",
# "primary": "VM-Rocks8-MySQL-192-168-31-123:3306",
# "topology": {
#   "VM-Rocks8-MySQL-192-168-31-123:3306": {"memberRole": "PRIMARY", "mode": "R/W"},
#   "VM-Rocky8-MySQL-192-168-31-124:3306": {"memberRole": "SECONDARY", "mode": "R/O"},
#   "VM-Rocky8-MySQL-192-168-31-125:3306": {"memberRole": "SECONDARY", "mode": "R/O"}
# }# 4. 测试单主写入(仅主节点可写,从节点写操作报错)
# 在node2执行写操作,预期报错:
mysql -uroot -p'root.COM2025*' -h192.168.31.124 -P3306 -e "INSERT INTO test_cluster.t1 (name) VALUES ('single-primary-node2');"
# 报错信息:ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
模式切换注意事项:
  • 多主模式数据冲突:多主模式下,若多个节点同时修改同一条数据(如同一 idname 字段),会触发集群冲突检测,导致其中一个节点的事务回滚,需业务层通过分库分表、主键规则(如节点ID前缀)避免冲突;
  • 切换权限:仅集群管理员(如 clusteradmin)或 root 用户可执行模式切换;
  • MySQL Router 适配:模式切换后,Router 会自动更新路由规则(单主模式下 6446 端口指向唯一主节点,多主模式下 6446 端口可转发到任意主节点),无需重启 Router。

十、常见问题排查

1. 节点添加失败:提示“无法连接到节点的33061端口”

  • 排查方向
    1. 确认目标节点的 group_replication_local_address 配置是否正确(如 node2 应为 mysql-node2:33061);
    2. 检查目标节点防火墙是否开放 33061 端口(需手动开放,或已关闭防火墙);
    3. 测试节点间 33061 端口连通性:telnet mysql-node2 33061,若不通需检查网络策略(如iptables)。

2. 集群初始化失败:提示“binlog路径不存在”

  • 排查方向
    1. 确认 my.cnflog-bin 配置的路径(如 /data/3306/binlog/mysql-bin)是否存在,若不存在需手动创建并授权:
      mkdir -p /data/3306/binlog
      chown -R mysql:mysql /data/3306/binlog
      
    2. 重启 MySQL 服务,重新执行初始化。

3. Router 无法连接集群:提示“无法找到集群节点”

  • 排查方向
    1. 检查 Router 配置文件(/etc/mysqlrouter/mysqlrouter.conf)中 group_replication_seeds 是否与 my.cnf 一致;
    2. 验证集群是否正常运行(cluster.status() 输出 status: OK);
    3. 查看 Router 日志(/var/log/mysqlrouter/mysqlrouter.log),是否有“节点认证失败”,需重新执行 mysqlrouter --bootstrap 刷新配置。

4. 从节点同步失败:提示“GTID不一致”

  • 排查方向
    1. 确认所有节点的 gtid_mode 均为 onenforce_gtid_consistency 均为 on
    2. 若从节点 GTID 缺失,通过集群命令重新同步:cluster.rejoinInstance('root@从节点IP:3306?socket=/var/tmp/mysql.sock')
    3. 查看主节点 binlog 是否已过期(binlog_expire_logs_seconds 配置是否过短),需调整保留时间。

5. 重大可用性问题可参考官方文档 7.8 节

https://dev.mysql.com/doc/mysql-shell/8.0/en/troubleshooting-innodb-cluster.html

  • 7.8 Restoring and Rebooting an InnoDB Cluster
    • 7.8.1 Rejoining an Instance to a Cluster
    • 7.8.2 Restoring a Cluster from Quorum Loss
    • 7.8.3 Rebooting a Cluster from a Major Outage
    • 7.8.4 Rescanning a Cluster
    • 7.8.5 Fencing a Cluster

十一、运维注意事项

  1. 目录权限保障
    所有目录(/usr/local/mysql//data/3306)需确保所有者为 mysql 用户,避免因权限不足导致服务启动失败或数据同步异常,定期检查:

    chown -R mysql:mysql /usr/local/mysql
    chown -R mysql:mysql /data/3306
    
  2. 备份策略

    • 主节点定时全量备份(使用 mysqldumpxtrabackup),备份路径建议与数据目录分离(如 /data/backup):
      # 每日凌晨2点全量备份(示例脚本)
      echo "0 2 * * * mysqldump -uroot -p'root.COM2025*' --socket=/var/tmp/mysql.sock --all-databases --single-transaction --master-data=2 > /data/backup/mysql_full_$(date +%Y%m%d).sql" >> /var/spool/cron/root
      
    • 备份文件需定期归档至集群外服务器,避免集群故障时备份丢失。
  3. 日志管理
    日志(错误日志/慢查询日志/binlog)需定期清理,避免磁盘占满,可通过日志轮转工具(如 logrotate)自动管理:

mysql-error.log

# 配置logrotate
cat > /etc/logrotate.d/mysql-error.log << EOF
/data/3306/logs/mysql-error.log {dailyrotate 7compressmissingoknotifemptypostrotatesystemctl restart mysqldendscript
}
EOF
  1. 版本一致性
    所有节点的 MySQL、MySQL Shell、MySQL Router 版本必须严格一致(本实践均为 8.0.43),需避免手动升级单个组件,防止版本兼容问题。
http://www.dtcms.com/a/483557.html

相关文章:

  • 网站关键词选取网站开发使用软件有哪些
  • 网站建设 鼠标定制化网站开发公司
  • WebUI自动化测试:POM设计模式全解析
  • tauri 应用相关文件夹
  • 建设网站哪家便宜南昌网站排名
  • AI赋能,重塑未来招聘:深度解析易路AI人岗匹配解决方案
  • 四川网站建设的公司哪家好苏州网站建设熊掌
  • QT6中Dial、Key Sequence Edit、LCD Number 功能及用法详解
  • 为什么要创建网站公司网站建设管理
  • Tomcat核心架构与生产部署指南
  • 启闭机闸门的网站建设wp做图网站
  • 一个网站项目的价格表wordpress主题Qinmei
  • 虎扑的网站是用什么技术做的江苏免费建站
  • 做网站前景怎样国家企业年审营业执照官网
  • 开封市城乡建设局网站宁德公司做网站
  • mysql网站数据库深圳双区建设
  • 论述网站建设整个流程网站开发完整的解决方案
  • Web渗透之身份认证与访问控制缺陷(越权(水平垂直),访问控制(没有验证),脆弱验证(Cookie,JWT,Session等))
  • CoRL-2025 | SocialNav-SUB:用于社交机器人导航场景理解的视觉语言模型基准测试
  • 做优化网站是什么意思设计网络品牌营销方案思路
  • 单网页网站网站 制作公司
  • c++20|第k大-快速选择|nth_element
  • 小杰深度学习(sixteen)——视觉-经典神经网络——MobileNetV2
  • asp.net企业网站设计广州一建筑外墙脚手架坍塌
  • 自动化测试脚本环境搭建
  • VSCode通过SSH连接到Ubuntu虚拟机失败“找不到ssh安装”问题解决
  • 古镇营销型网站建设代做淘宝客网站
  • 网站开发设计学做婴儿衣服网站好
  • 苏州市工业园区规划建设局网站俄语网站
  • 8网站建设做网站百度建设网站的目的