0

0

Xtrabackup使用指南

php中文网

php中文网

发布时间:2016-06-07 16:32:13

|

1950人浏览过

|

来源于php中文网

原创

一、Xtrabackup介绍 A、Xtrabackup是什么 Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品。 Xtrabackup有两个主要的工具:xtrabackup、innobackupex 1、xtrabackup只

  一、xtrabackup介绍

  A、Xtrabackup是什么

  Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品。

  Xtrabackup有两个主要的工具:xtrabackup、innobackupex

  1、xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表
  2、innobackupex是参考了InnoDB Hotbackup的innoback脚本修改而来的.innobackupex是一个perl脚本封装,封装了xtrabackup。主要是为了方便的同时备份InnoDB和MyISAM引擎的表,但在处理myisam时需要加一个读锁。并且加入了一些使用的选项。如slave-info可以记录备份恢复后,作为slave需要的一些信息,根据这些信息,可以很方便的利用备份来重做slave。
  3、官方文档:http://www.percona.com/docs/wiki/percona-xtrabackup:start

  B、Xtrabackup可以做什么

  在线(热)备份整个库的InnoDB、 XtraDB表
  在xtrabackup的上一次整库备份基础上做增量备份(innodb only)
  以流的形式产生备份,可以直接保存到远程机器上(本机硬盘空间不足时很有用)

  MySQL数据库本身提供的工具并不支持真正的增量备份,二进制日志恢复是point-in-time(时间点)的恢复而不是增量备份。Xtrabackup工具支持对InnoDB存储引擎的增量备份,工作原理如下:

  (1)首先完成一个完全备份,并记录下此时检查点的LSN(Log Sequence Number)。
  (2)在进程增量备份时,比较表空间中每个页的LSN是否大于上次备份时的LSN,如果是,则备份该页,同时记录当前检查点的LSN。

  首先,在logfile中找到并记录最后一个checkpoint(“last checkpoint LSN”),然后开始从LSN的位置开始拷贝InnoDB的logfile到xtrabackup_logfile;接着,开始拷贝全部的数据文件.ibd;在拷贝全部数据文件结束之后,才停止拷贝logfile。

  因为logfile里面记录全部的数据修改情况,所以,即时在备份过程中数据文件被修改过了,恢复时仍然能够通过解析xtrabackup_logfile保持数据的一致。

  C、Xtrabackup备份原理

  XtraBackup基于InnoDB的crash-recovery功能。它会复制innodb的data file,由于不锁表,复制出来的数据是不一致的,在恢复的时候使用crash-recovery,使得数据恢复一致。

  InnoDB维护了一个redo log,又称为transaction log,事务日志,它包含了innodb数据的所有改动情况。当InnoDB启动的时候,它会先去检查data file和transaction log,并且会做二步操作:

  XtraBackup在备份的时候, 一页一页地复制innodb的数据,而且不锁定表,与此同时,XtraBackup还有另外一个线程监视着transactions log,一旦log发生变化,就把变化过的log pages复制走。为什么要急着复制走呢? 因为transactions log文件大小有限,写满之后,就会从头再开始写,所以新数据可能会覆盖到旧的数据。

  在prepare过程中,XtraBackup使用复制到的transactions log对备份出来的innodb data file进行crash recovery。

  D、实现细节

  XtraBackup以read-write模式打开innodb的数据文件,然后对其进行复制。其实它不会修改此文件。也就是说,运行XtraBackup的用户,必须对innodb的数据文件具有读写权限。之所以采用read-write模式是因为XtraBackup采用了其内置的innodb库来打开文件,而innodb库打开文件的时候就是rw的。

  XtraBackup要从文件系统中复制大量的数据,所以它尽可能地使用posix_fadvise(),来告诉OS不要缓存读取到的数据,从而提升性能。因为这些数据不会重用到了,OS却没有这么聪明。如果要缓存一下的话,几个G的数据,会对OS的虚拟内存造成很大的压力,其它进程,比如mysqld很有可能被swap出去,这样系统就会受到很大影响了。

  在备份innodb page的过程中,XtraBackup每次读写1MB的数据,1MB/16KB=64个page。这个不可配置。读1MB数据之后,XtraBackup一页一页地遍历这1MB数据,使用innodb的buf_page_is_corrupted()函数检查此页的数据是否正常,如果数据不正常,就重新读取这一页,最多重新读取10次,如果还是失败,备份就失败了,退出。在复制transactions log的时候,每次读写512KB的数据。同样不可以配置。

  二、Xtrabackup安装

  本文通过源码方式安装Xtrabackup,最新的版本是1.6.

  Xtrabackup与一般的源码构建方式不同,它采用的在MySQL源代码上打补丁的构建方式。下载的源码包比较大就是是因为这个包里打包了编译需要的两个MySQL Source,一个5.1.56,一个5.5.10。

  安装编译所需的依赖包

yum install libaio libaio-devel

  编译安装Xtrabackup

wget  http://www.percona.com/redir/downloads/XtraBackup/XtraBackup-1.6/source/xtrabackup-1.6.tar.gz
tar xvf xtrabackup-1.6.tar.gz 
cd xtrabackup-1.6
utils/build.sh innodb55

  注:build.sh是源码包中提供的编译脚本,MySQL 5.1可用参数innodb51_builtin。

  编译成功后,会在对应mysql版本目录中生成一个xtrabackup程序,我这里生成的路径是mysql-5.5.10/storage/innobase/xtrabackup/中

ls  mysql-5.5.10/storage/innobase/xtrabackup/
 
Makefile  xtrabackup.c  xtrabackup_innodb55  xtrabackup.o

  复制相应文件和建立软链到/usr/bin下,这么做的原因是满足innobackupex脚本的需要。

cp  mysql-5.5.10/storage/innobase/xtrabackup/xtrabackup_innodb55 /usr/bin/xtrabackup_55
cp innobackupex /usr/bin/innobackupex
#备份时如果打包就需要这个命令,非必需。
cp  libtar-1.2.11/libtar/tar4ibd /usr/bin/tar4ibd  
ln -sf /usr/local/webserver/mysql/bin/mysql  /usr/bin/mysql

  三.Xtrabackup的备份与恢复使用

  A、Xtrabackup常用参数选项如下:

--defaults-file=#
默认配置文件的路径,如果不该参数,xtrabackup将从依次从以下位置查找配置文件/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/etc/my.cnf、~/.my.cnf,并读取配置文件中的[mysqld]和[xtrabackup]配置段。[mysqld]中只需要指定datadir、innodb_data_home_dir、innodb_data_file_path、innodb_log_group_home_dir、innodb_log_files_in_group、innodb_log_file_size6个参数即可让xtrabackup正常工作。
 
--defaults-extra-file=#
如果使用了该参数,在读取了全局配置文件之后,会再读取这里指定的配置文件
 
--target-dir=name
备份文件的存放目录路径
 
--backup
实施备份到target-dir
 
--prepare
实施对备份文件进行恢复前的准备(生成InnoDB log file)
 
--print-param
打印备份或恢复时需要的参数
 
--use-memory=#
该参数在 prepare 的时候使用,控制prepare时innodb实例使用的内存量
 
--suspend-at-end
在target-dir目录下产生一个xtrabackup_suspended文件,将xtrabackup进程挂起,不停地将数据文件的变化同步到备份文件,直到用户手工删除xtrabackup_suspended文件
 
--throttle=#
每秒IO次数,限制backup时使用的I/O操作量,使备份对数据库正常业务的影响最小化
 
--log-stream
该参数在backup的时候使用,将xtrabackup_logfile的内容输出到标准输出,使用该参数时会自动使用suspend-at-end参数,innobackupex脚本的stream 模式会使用该参数。
 
--incremental-lsn=name
增量备份时只拷贝LSN比该参数指定值新的ibd pages,前次备份到了哪个LSN可以看前次备份集的xtrabackup_checkpoints文件
 
--incremental-basedir=name
该参数在backup的时候使用,备份比该参数指定位置的备份集新的idb pages
 
--incremental-dir=name
该参数在prepare的时候使用,指定prepare时产生的.delta 文件和日志文件的存放路径
 
--tables=name
在备份file-per-table类型的数据文件时使用,使用正则表达式指定需要备份的innodb表
 
--datadir=name
MySQL数据库的数据文件目录。

  B、普通备份方式

  a)普通备份(全量备份)

mkdir -p /data0/backup/mysql
xtrabackup_55  --defaults-file=/data0/mysql/my.cnf --backup --target-dir=/data0/backup/mysql/
cp -r  /data0/mysql/data/testinnodb/ /data0/backup/mysql/

  注意:xtrabackup只备份数据文件,并不备份数据表结构(.frm),所以这里要手动备份一下,以便xtrabackup恢复的时候使用。

  全量备份恢复

  实施对备份文件进行恢复前的准备

xtrabackup_55 --defaults-file=/data0/mysql/my.cnf --prepare  --target-dir=/data0/backup/mysql/

  从备份目录复制对应数据库表结构到默认的数据目录

cp -r /data0/backup/mysql/testinnodb/ /data0/mysql/data/

  删除默认数据目录中对应的数据文件并复制备份的数据文件到默认数据目录

rm /data0/backup/mysql/ib*
cp /data0/backup/mysql/ib*  /data0/mysql/data/

  修改数据目录权限

ImgGood
ImgGood

免费在线AI照片编辑器

下载
chown -R mysql:mysql /data0/mysql/data

  重启MySQL

/data0/mysql/mysql restart

  b)增量备份

  增量备份优点:

  1、数据库太大没有足够的空间全量备份,作增量备份有效节省空间,且效率高。
  2、支持热备份。备份过程不锁表,不受时间限制,不影响用户使用。
  3、每日备份只产生少量数据,远程备份传输更方便。同时节省空间。
  4、备份恢复基于文件操作,降低直接对数据库操作风险。
  5、备份效率更高,恢复效率更高。

  这个我研究N久没成功,原因暂时还没找到。我测试环境的Mysql版本是5.5.11的,xtrabackup_55是根据MySQL5.5.9的源码编译的,不知道和这个有关系没?待验证!这里只把实现步骤整理出来。

  增量备份及模拟恢复步骤:

  先做一次全量备份,增量备份需要以此为基础

#建立备份目录
mkdir -p /data0/backup/mysql/base
#建立一个全量备份
xtrabackup_55  --defaults-file=/data0/mysql/my.cnf --backup --target-dir=/data0/backup/mysql/base
#生成的备份数据文件
ls /data0/backup/mysql/base/
ibdata1  xtrabackup_checkpoints  xtrabackup_logfile
#备份数据库表结构
cp -r  /data0/mysql/data/testinnodb/ /data0/backup/mysql/

  以此全量备份为基础进行增量备份

#建立备份目录
mkdir -p /data0/backup/mysql/delta
#建立一个增量备份
xtrabackup_55  --defaults-file=/data0/mysql/my.cnf --backup  --target-dir=/data0/backup/mysql/delta  --incremental-basedir=/data0/backup/mysql/base
#生成的备份数据文件
ls /data0/backup/mysql/delta/
ibdata1.delta  xtrabackup_checkpoints  xtrabackup_logfile

  注:在增量备份目录下,数据文件都是以.delta结尾的。增量备份只备份上一次全量备份后被修改过的page,所以增量备份只暂用较少的空间。增量备份可以在增量备份的基础上增量。增量备份目录每次都需修改的。比如第二次增量就改成/data0/backup/mysql/delta2)

  增量备份恢复过程:

  首先需要分别对全量、增量备份各做一次prepare操作。

xtrabackup_55  --defaults-file=/data0/mysql/my.cnf --prepare --target-dir=/data0/backup/mysql/base
xtrabackup_55  --defaults-file=/data0/mysql/my.cnf --prepare --target-dir=/data0/backup/mysql/base --incremental-dir=/data0/backup/mysql/delta/

  从备份目录复制对应数据库表结构到默认的数据目录

cp -r /data0/backup/mysql/testinnodb/ /data0/mysql/data/

  删除默认数据目录中对应的数据文件并复制备份的数据文件到默认数据目录

rm /data0/backup/mysql/ib*
cp /data0/backup/mysql/ib*  /data0/mysql/data/

  修改数据目录权限

chown -R mysql:mysql /data0/mysql/data

  重启MySQL

/data0/mysql/mysql restart

  四、innobackupex的备份与恢复使用

  A、数据备份

  通常一般都直接使用innobackupex,因为它能同时备份InnoDB和MyISAM引擎的表。要注意的是my.cnf里datadir这个参数是必须要指定的,xtrabackup_55是根据它去定位innodb数据文件的位置。

  innobackupex语法

innobackup [--sleep=MS] [--compress[=LEVEL]] [--include=REGEXP] [--user=NAME] [--password=WORD]
[--port=PORT] [--socket=SOCKET] [--no-timestamp] [--ibbackup=IBBACKUP-BINARY] [--slave-info] [--stream=tar]
[--defaults-file=MY.CNF] [--databases=LIST] [--remote-host=HOSTNAME] BACKUP-ROOT-DIR
 
innobackup --apply-log [--use-memory=MB] [--uncompress] [--defaults-file=MY.CNF] [--ibbackup=IBBACKUP-BINARY] BACKUP-DIR
 
innobackup --copy-back [--defaults-file=MY.CNF] BACKUP-DIR
 
各参数说明:
 
--defaults-file
同xtrabackup的--defaults-file参数
 
--apply-log
对xtrabackup的--prepare参数的封装
 
--copy-back
做数据恢复时将备份数据文件拷贝到MySQL服务器的datadir ;
 
--remote-host=HOSTNAME
通过ssh将备份数据存储到进程服务器上;
 
--stream=[tar]
 
备份文件输出格式, tar时使用tar4ibd , 该文件可在XtarBackup binary文件中获得.如果备份时有指定--stream=tar, 则tar4ibd文件所处目录一定要在$PATH中(因为使用的是tar4ibd去压缩, 在XtraBackup的binary包中可获得该文件)。
 
在使用参数stream=tar备份的时候,你的xtrabackup_logfile可能会临时放在/tmp目录下,如果你备份的时候并发写入较大的话xtrabackup_logfile可能会很大(5G+),很可能会撑满你的/tmp目录,可以通过参数--tmpdir指定目录来解决这个问题。
 
--tmpdir=DIRECTORY
 
当有指定--remote-host or --stream时, 事务日志临时存储的目录, 默认采用MySQL配置文件中所指定的临时目录tmpdir
 
--redo-only --apply-log组,
 
强制备份日志时只redo ,跳过rollback。这在做增量备份时非常必要。
 
--use-memory=#
 
该参数在prepare的时候使用,控制prepare时innodb实例使用的内存量
 
--throttle=IOS
 
同xtrabackup的--throttle参数
 
--sleep=是给ibbackup使用的,指定每备份1M数据,过程停止拷贝多少毫秒,也是为了在备份时尽量减小对正常业务的影响,具体可以查看ibbackup的手册 ;
 
--compress[=LEVEL]
对备份数据迚行压缩,仅支持ibbackup,xtrabackup还没有实现;
 
--include=REGEXP
对xtrabackup参数--tables的封装,也支持ibbackup。备份包含的库表,例如:--include="test.*",意思是要备份test库中所有的表。如果需要全备份,则省略这个参数;如果需要备份test库下的2个表:test1和test2,则写成:--include="test.test1|test.test2"。也可以使用通配符,如:--include="test.test*"。
 
--databases=LIST
列出需要备份的databases,如果没有指定该参数,所有包含MyISAM和InnoDB表的database都会被备份;
 
--uncompress
解压备份的数据文件,支持ibbackup,xtrabackup还没有实现该功能;
 
--slave-info,
备份从库, 加上--slave-info备份目录下会多生成一个xtrabackup_slave_info 文件, 这里会保存主日志文件以及偏移, 文件内容类似于:CHANGE MASTER TO MASTER_LOG_FILE='', MASTER_LOG_POS=0
 
--socket=SOCKET
指定mysql.sock所在位置,以便备份进程登录mysql.

备份前首先所需要建立一个备份所需的目录

mkdir -p /data0/backup/mysql

  1、普通备份

innobackupex --database="testinnodb test" --user=root --no-lock --defaults-file=/data0/mysql/my.cnf  /data0/backup/mysql 2>/tmp/mysqlbackup.log

  注:使用mysql的root用户将数据库testinnodb和test的备份,备份路径是/data0/backup/mysql/。备份成功后会在该目录下将创建以时间戳为名称的备份目录。no-lock参数用于指定备份时不锁定表。2>/tmp/mysqlbackup.log是将备份过程中的输出信息保存到/tmp/mysqlbackup.log中。

  2、打包备份

innobackupex  --database="testinnodb test"  --user=root --defaults-file=/data0/mysql/my.cnf  --no-lock --stream=tar /data0/backup/mysql/ 2>/tmp/innobackup.log 1>/data0/backup/mysql/mike.tar

  注:这种备份时间会比较长,主要是执行压缩操作。这种方式打的包需要使用tar izxvf解压。参数-i是必须加上的。

  3、压缩备份

innobackupex  --database="testinnodb test"  --user=root --defaults-file=/data0/mysql/my.cnf  --no-lock --stream=tar /data0/backup/mysql/ 2>/tmp/innobackup.log|gzip>/data0/backup/mysql/mike.tar.gz

  4、备份到远程服务器
  
  备份当前机器下的数据到192.168.1.101的/data0/目录下。

innobackupex  --database="testinnodb test"  --user=root --defaults-file=/data0/mysql/my.cnf  --no-lock --stream=tar /data0/backup/mysql/|ssh root@192.168.1.101  cat ">"/data0/backup.tar

  B、数据恢复

  以压缩后的备份数据为例,普通备份和打包备份的恢复方法和这个类似,就不在举例了。

  解包备份数据

tar xvzfi  mike.tar.gz

  指定恢复备份所需的xtrabackup_logfile文件的目录

innobackupex --apply-log --user=root --defaults-file=/data0/mysql/my.cnf --no-lock /data0/backup/mysql

  从备份目录拷贝数据、索引、日志到my.cnf文件里规定初始的数据目录位置。

innobackupex --copy-back --user=root --defaults-file=/data0/mysql/my.cnf --no-lock /data0/backup/mysql

  修改数据目录权限

chown -R mysql:mysql /data0/mysql/data

  重启MySQL

/data0/mysql/mysql restart

  五、参考文档

  http://www.google.com
  http://www.linuxidc.com/Linux/2011-05/35410.htm
  http://blogold.chinaunix.net/u4/122567/showart_2537465.html

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

89

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

276

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

59

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

99

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

105

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

230

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

619

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

173

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Smarty3.0模板引擎使用指南
Smarty3.0模板引擎使用指南

共11课时 | 1.3万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2.1万人学习

Webpack4.x---十天技能课堂
Webpack4.x---十天技能课堂

共20课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号