首页
学习
活动
专区
工具
TVP
发布

维护数千规模MySQL实例,数据库灾备体系构建指南

前言

数据是企业重要的生产资料,并且往往是不可再生的,关键数据(客户订购、交易和生产信息等)丢失会使企业陷入困境,为了应对数据丢失造成的损失,必须对重要数据进行灾备保护。

一般数据从产生到存储,主要经过应用、中间件、数据库、操作系统、磁驱动、服务器硬件、网络交换机再到存储。其中数据库环节的灾备保护尤为重要,"移动云"为数据提供的灾备恢复机制包括备份容灾

其中,备份主要是指为业务系统产生的重要客户数据制作一份或者多份拷贝,以增强数据的安全性。

容灾则是指在相隔较远的两地(“移动云”为广州和北京两地)建立两套或多套功能相同的业务系统,互相之间可以进行健康状态监视和功能切换。当一处系统因设备故障、人为意外或自然灾害等不可抗力停止工作时,整套业务系统可以切换到另一处,使得该系统功能仍可以继续正常工作,客户能够正常访问。

首先,来看一下数据库备份。

备份

对于“移动云”数据库运维人员来说,数据库的备份与恢复是日常运维中最常见的工作之一。在数据库运维的过程中,经常会遇到服务器宕机、磁盘损坏和人工误操作等情况,在这种情况下,要保证数据不丢失、或者最小程度的丢失,本地和异地备份起着至关重要的作用。

因此对于DBA来说,备份工具的使用、备份策略的选择以及备份系统的完善都是需要时刻关注的,定期进行备份的有效性测试更是不能忽视的重要环节。

下面我从最基本的备份类型和方法入手,结合“移动云”MySQL数据库本地和异地备份与恢复机制,跟大家分享和探讨下DBA在生产环境需要掌握的基本备份技能。

备份有哪几种类型和形式?

根据备份形式的不同,MySQL数据库备份可以划分为:

  • 冷备份;
  • 热备份;
  • 温备份;
  • 物理备份;
  • 逻辑备份;
  • 本地备份;
  • 远程备份;
  • 全量和增量备份、日志备份。

1)其中,根据备份时数据库的状态可以分为冷备份、热备份和温备份

冷备份是指在数据库关闭的情况下进行备份,这种备份非常简单,只需要关闭数据库,复制相关的物理文件即可。目前,线上数据库一般很少能够接受关闭数据库,所以该方式很少使用。因为是直接拷贝数据文件,冷备份的恢复无法解决数据空洞的问题,同时在跨平台进行恢复需要考虑系统版本、文件大小写敏感和浮点数格式等因素,通常在硬件故障下,如磁盘故障而且不能确认存储的其他盘是否有问题,需要把数据目录中的数据迁移到其他的物理设备上。

热备份是指在数据库运行的过程中进行备份,对生产环境中的数据库运行没有任何影响。常见的热备方案是利用mysqldump、xtrabackup等工具进行备份。热备份也叫在线备份,大多数基于数据块变化跟踪备份,服务不需要停机,对业务影响小,通常生产环境的备份都是围绕着在线备份展开。

温备份也是在数据库运行的过程中进行备份,但是备份会对数据库操作有所影响。该备份利用锁表的原理备份数据库,由于影响了数据库操作,故该备份方式也很少使用。

2)根据备份文件的种类可以分为物理备份、逻辑备份

物理备份是指复制数据库的物理文件,物理备份是对物理文件数据块的拷贝,通过拷贝日志文件和数据文件,并在数据文件应用日志进行checkpoint前滚、回滚来达到数据备份的一致性,相对于逻辑备份效率要快很多。

物理备份即可以在数据库运行的情况下进行备份,也可以在数据库关闭的情况下进行备份。该备份方式不仅备份速度快,而且恢复速度也快,但由于无法查看备份后的内容,所以只能等到恢复之后,才能校验备份出来的数据是否正确。

逻辑备份是指备份文件的内容是可读的,通常是将数据导出为可执行可读的SQL文本文件,该文本一般是由一条条SQL语句或者表的实际数据组成,是SQL layer层得到的SQL语句。常见的逻辑备份方式有mysqldump、SELECT*INTO OUTFLE等方法。这类备份方法的好处是可以观察备份后的文件内容,缺点是恢复时间往往会很长,适用于数据量较小的实例。

日常运维工作中DBA实际使用的备份手段通常是逻辑备份和物理备份相结合,MySQL相关的逻辑备份工具主要有:

  • MySQL官方的mysqldump,属于单线程的逻辑备份工具;
  • 开源的MySQL多线程逻辑导出工具mydumper,以行记录级别实现并行备份,主线程切分chunk,并按chunk进行导出;
  • 5.7版本推出的并行多线程逻辑备份工具mysqlpump,该工具多线程的颗粒度是表,单表依然是单线程导出;
  • 通过SQL语句导出到文本。

从逻辑备份工具由单线程到多线程的演变特点可以看出,逻辑备份效率较低,遇到实例过大时,逻辑备份就不是一个好的选择了,这时DBA通常考虑物理备份,MySQL常用的物理备份工具主要有:

  • MySQL Enterprise Backup (企业版本);
  • XtraBackup。

以上工具都可以同时备份MyISAM和InnoDB存储引擎表,可以理解为是对日志文件和数据文件的拷贝,“移动云”生产环境主要采用XtraBackup工具进行数据库的本地备份。

3)根据备份内容,可以划分为全量备份、增量备份、日志备份

全量备份是指对数据库进行一次完整的备份,备份所有的数据。这是一般常见的备份方式,可以使用全量备份快速恢复数据库,或者搭建从库。恢复速度也是最快的,但是每次备份会消耗较多的磁盘空间,并且备份时间较长。

增量备份是指基于上次全量备份或增量备份,对数据库新增的修改进行备份。增量备份又分为累积增量备份和差异增量备份。增量备份依赖于最近一次的全量备份,恢复时同样依赖于全量恢复和增量备份的应用,这种备份方式有利于减少备份时磁盘的使用,加快备份速度。但是恢复的时候速度较慢,并且操作也比较复杂。

日志备份是指对MySQL数据库二进制日志的备份。该备份方式一般与上面的全量或增量备份结合使用,可以使数据库恢复到任意位置,例如可以采用全量备份和Binlog备份来实现整体备份需求。

4)根据备份文件存储位置,可以划分为本地备份、远程备份

考虑到本地备份存储资源的消耗以及选择远程备份能够减少数据库服务器的内存和IO压力,“移动云”生产环境采用本地+远程备份(NBU)的方式,本地由于磁盘空间限制仅保留近期的备份文件,并保证能够快速恢复,远程则用于保留较长时间的历史备份。

前面提到的多种备份方式,每个都有自己的优缺点。在“移动云”生产环境中,备份一般需要满足以下三个需求:

  • 备份时,数据库不能中断服务,即需要热备份;
  • 生产环境中,需要随时恢复到某个时间点,便于线上出现问题后的数据回滚;
  • 可以用来快速搭建新的从库,建立复制关系,实现数据的高可用、负载均衡等目标。

考虑到上述需求,我们选择本地以物理备份为主,逻辑备份为辅,加上远程备份,来满足线上使用数据库的需求。

备份原则:每周一次全备,每天一次增备,本地统一保留21天,对于超过21天的数据如无特殊需求,到后期会自动删除,对于较重要的数据需保留更久则通过远程备份实现(NBU备份)。

备份方案:备份通过crontab进行调度,每天晚上2点进行备份。备份脚本统一放在各节点指定目录下,如:/path/sh/backup.sh ,备份日志统一放在/path/logs/backuplog/目录下。备份形式为物理备份。该备份为速度最快的模式,不会锁表,对线上业务基本无影响。备份文件过期后会自动删除,可以避免保留大量的备份数据导致磁盘空间不足。

物理备份和恢复可以采用开源Percona XtraBackup工具。xtrabackup用于热备innodb,xtradb表中的数据,不能备份其他类型的表,也不能备份数据表结构,innobackupex是对xtrabackup进行封装,提供了更为全面和完善的功能,可在线备份innodb,myisam类型的表,恢复时需要停服务。innobackupex分为全量备份和增量备份。

全量备份

1)备份阶段

在全量备份时,只需要指定连接数据库的参数和备份目录即可。

innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup /path/backup_dir/

在备份完成后,innobackupex会输出以下信息:

***
190827 17:36:04 innobackupex:Starting ibbackup with command:xtrabackup***
***
innobackupex: Backup created in directory '/path/backup_dir/20190827_165206_full'
innobackupex: MySQL binlog position: filename 'mysql-bin.032074', position 271, GTID of the last change '22513e1b-6b32-11e6-839c-6c92bf2a2c87:1-2004,
7b405c05-b3a1-11e5-8c14-fa163eb8d0f8:1-16,
85977e48-4c5e-ee1a-54ce-d90c0a6017b4:1-5828461614'
innobackupex: Backup history record uuid 1da6bda3-c8ae-11e9-9e2c-6c92bf2a2c07 successfully written
190827 17:36:16  innobackupex: Connection to database server closed
190827 17:36:16  innobackupex: completed OK!
2019-08-27 17:36:16  backup complete!.
2019-08-27 17:36:16  backup success!

通过输出信息可以看出,其实innobackupex在执行时,调用了xtrabackup脚本。并且备份文件会存储在一个以备份时间命名的子目录下。

2)Prepare阶段

在创建备份后,备份数据通常处于不可用状态。因为在redo log中可能存在未提交的事务,需要通过准备阶段来使备份数据达到一致的状态。通过prepare阶段,备份数据就可以用来恢复了。

在准备阶段,需要指定–apply-log选项和备份路径。

innobackupex --defaults-file=/path/conf/my.cnf --apply-log /path/backup_dir/2019-08-27_17-36-16

执行后输出信息如下:

InnoDB:Shutdown completed;log sequence number 1735134
190827 17:44:33 innobackupex:completed OK!

状态显示为“completed OK”,表明innobackupex执行完了所有所需的操作,数据达到一致状态。

3)恢复阶段

在Prepare阶段过后,如果需要用备份数据来恢复数据库,则只需要指定–copy-back和备份数据所在的目录即可,此时数据库需处于关闭的状态。

innobackupex --defaults-file=/path/conf/my.cnf --copy-back /path/backup_dir/2019-08-27_17-36-16

innobackupex将所有的数据文件复制到datadir目录,该目录由my.cnf配置文件中datadir参数指定。最后输出如下信息:

innobackupex:Finish copying back files.
190827 17:50:33 innobackupex:completed OK!

复制完成后,文件属性不会改变,因此建议将datadir和backup_dir目录权限设置为相同,否则在启动MySQL数据库之前,需修改文件的所有权。

chown -R mysql:mysql /path/datadir

另外,在恢复过程中,datadir目录必须为空,如果不为空,innobackupex --copy-back 将不会复制,除非指定了 --force-non-empty-directories选项。

增量备份

在日常的数据库备份中,并不是每次备份之间的数据都有所改变。DBA可以只备份那些修改的部分。不仅可以节约备份所需的磁盘空间,也可以大大缩短备份的时间。增量备份即可以做到这一点,因为在InnDB页面中有一个日志序列号(LSN),它充当数据库版本号的作用。每次修改数据库,这个数字就会增加。增量备份复制指定LSN位置以后的所有页面。

1)备份阶段

增量备份基于全量备份,所以首先需要创建一个全量备份,这时备份目录中会存在xtrabackup-checkpoints文件,内容如下:

backup_type = full-backuped
from_lsn = 0
to_lsn = 834506398072
last_lsn = 834632595548
compact = 0

增量备份时需要指定–incremental选项和basedir信息。

innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup --incremental --incremental-basedir=/path/backup_dir/ /path/incremental_backup_dir

增量备份完成后,会在新创建的增量备份目录中/path/incremental_backup_dir创建一个时间目录,例如:/path/incremental_backup_dir/2019-8-27_17-48-30。同样在该目录中存在xtrabackup-checkpoints文件内容如下:

backup_type = incremental
from_lsn = 834506398072
to_lsn = 838872449882
last_lsn = 838890942246
compact = 0

增量备份还可以基于以前的增量备份完成。

innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup --incremental --incremental-basedir=/path/backup_dir/ /path/incremental_backup_dir/

xtrabackup-checkpoints文件内容如下:

backup_type = incremental
from_lsn = 838872449882
to_lsn = 843244982934
last_lsn = 843341702758
compact = 0

前面提到增量备份是基于LSN的,所以增量备份也可以直接指定LSN来完成,例如:

innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup --incremental --incremental-lsn=834506398072 /path/incremental_backup_dir/

2)Prepare阶段

在增量备份的prepare阶段,所有已提交的事务必须在每个备份上重放,这将完全合并到增量备份。为了得到可用的备份,未提交的事务必须回滚。如果已经在全量备份上重放了提交的事务并回滚了未提交事务,则将无法在此备份上添加增量。如果在增量备份上执行上述操作,则将无法添加其余的增量备份。因此prepare阶段需要制定–redo-only选项,例如:

  • 首先,在全量备份上执行innobackup --apply-log --redo-only base_dir
  • 然后,在所有的增量备份上(除最后一个)执行innobackup --apply-log --redo-only --incremental-dir=/path/incremental_backup_dir base_dir
  • 在最后一个增量备份上执行innobackup --apply-log --incremental-dir=/path/incremetal_backup_dir base_dir

3)恢复阶段

通过prepare阶段,base目录包含了所有数据,在恢复时,只需要通过以下操作即可:

innobackupex --defaults-file=/path/conf/my.cnf --copy-back /path/base_dir

远程备份

在现网环境中,由于本地磁盘空间有限,通常本地仅保留一个月左右的备份数据,对于更早的数据如无特殊需求,到后期会自动删除,对于较重要的数据需保留更久则通过远程备份实现(Netbackup备份)。

不过在远程备份时,备份传输引发的网卡流量以及对线上业务造成影响不可忽视,需要考虑到网卡的能力,不能因为备份影响了线上业务的运行。这时可以考虑使用双网卡,一块用于备份,一块用来提供线上服务。如果没有这个条件,可以考虑在备份时限制速度来达到目的。

1)远程限速流备份

这种备份方式最大的好处是不消耗本地磁盘空间,并且通过该备份方式备份完成后,数据库的最后位置(binlog位点)就是最新的,因为传输完成的时候,备份才结束。相对别的备份方式,该备份方式的binlog位点信息更新。

当需要将DB主机的数据备份到远程服务器上,在远程服务器上开启一个端口利用pv和nc达到限速的目的,例如:

mkdir -p /tmp/backup
nc -l port | pv -q -L 100m | tar -xi

然后在DB主机上执行备份,如下:

mkdir -p /tmp/tmpbackup
innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup --stream=tar --tmpdir=/tmp/tmpbackup --salve-info /tmp/backup /path/backup
(路径与远程服务器上nc的当前路径一致)

也可以将备份集打个tar包,如下:

innobackupex --defaults-file=/path/conf/my.cnf --host=127.0.0.1 --port=3306 --user=mysql --password=backup --stream=tar --tmpdir=/tmp/tmpbackup --salve-info /tmp/backup /path/backup 2>/path/backup/bak_tar.log | gzip 1>/path/backup/test.tar.gz

查看bak_tar.log有无错误信息,若显示备份正常,则进入/path/backup/ 下执行tar -xvifz test.tar.gz. 查看目录大小(du -sh),并查看备份文件是否完整。

限速也可以通过innobackupex本地提供的参数–throttle通过限制磁盘的I/O来实现,一定程度上减少磁盘压力。不过它仅限于InnoDB的日志和文件的操作,对其他的存储引擎没有效果。

远程限速流备份的也存在一定的缺点,比如传输过程中,如果网络出现问题,那么备份将会失败,并且由于限速,导致备份时间拖长。

2)Netbackup远程备份

NetBackup是“移动云”备份与恢复管理工具。在备份过程中,通过网络将数据传送至NetBackup服务器,该服务器则通过使用相关策略为其选择最合适的存储介质类型。

在恢复过程中,管理员能够浏览到用户需要恢复的数据和目录,同时,NetBackup服务器会找到这些数据或目录并且帮助客户进行恢复,执行过程可以选择:创建备份作业调度和时间窗口、创建特定日期备份作业调度和创建特定日期不激活备份作业调度。系统架构如下图所示:

常见问题

前面介绍了备份恢复相关基础知识,我们知道日常运维中较常用的备份工具是mysqldump、Percona Xtrabackup,大多数DBA的备份恢复自动化体系和平台都是围绕这两个工具进行开展。

那面对成百上千个MySQL实例的维护,备份恢复有哪些问题呢?下面我们具体来看一下。

1)本地存储备份,磁盘空间需求更大,占用数据库服务器主板系统总线,内存,CPU,硬盘IO资源,不仅造成资源的浪费而且由于资源消耗放大了备份对线上业务的影响。

2)集中化管理缺失,备份的方式多样化,恢复演练错误率高,维护困难。

3)备份文件有效性校验,备份文件不做校验通常是最容易忽视的问题,出现故障时发现备份文件不可用会造成严重损失。

4)集群备份节点选择问题。备份或多或少对线上业务都有影响,建议备份任务在slave、statistic或只读节点上执行, 那么当集群发生主备切换,如果备份节点没有动态进行切换,导致在写库上进行备份,使线上业务受备份操作影响。

早期我们通过Netbackup实现异地备份,从而减少本地磁盘空间的消耗,并通过编写自动化脚本,引入一些开源工具,如:zabbix用于监控备份执行情况,ELK工具用于备份日志的记录和查询,ansible用于脚本的批量推送和维护。

并搭建备份恢复测试环境来实现备份有效性校验,例如可以通过下面简单的方式进行日常备份和集中恢复测试:

但总体而言备份体系中依然缺乏集中化管理,如份策略的修改和备份脚本的维护较复杂,备份完成情况、占用空间大小、完成时间以及校验结果等内容的记录和呈现也不够直观,缺少图形化界面。

脚本存放在数据库本地缺乏版本维护和统一管理,突发故障或变更前的临时备份依然靠手工ssh登录数据库主机执行,存在效率低和安全性差的问题。所以在这样的背景下,我们也开始寻求更高阶的运维方式——平台化 。

平台化的目标是整合已有的备份工具和手段,将复杂操作、重复操作程序化,并收口登录数据库主机的操作行为,提高操作安全性,增加管理和审核机制,提升运维效率,减少人为故障,解放运维人员。

备份管理平台

平台构建采用前、后端分离的方式,保证一定的扩展性并尽量避免耦合。因为平台不仅面向DBA还要面向系统运维人员,因此要使用动态菜单。不同权限,不同专业的人看到的菜单是不同的。

平台可以记录操作日志,具备安全审计的能力。在交互实现方面,要做到可视化、自动化和自助化。平台开发后端采用的是Django框架,前端采用Vue.JS,同时利用了缓存Redis和MySQL作为数据存储,通过标准的restful接口进行数据传输。

Redis作为信息缓存器,主要存储一些前端Dashboard以及数据库的基本信息,加快前端访问速度。

Django-Celery模块用于异步任务,由于备份操作执行的时间较长,没有办法立即返回结果,因此需要采用异步形式完成操作。

Ansible用于批量的备份执行、校验以及备份策略的修改。数据连接采用pymysql模块,能够实现不同种类数据库连接。

备份管理功能上主要包括:备份执行、备份恢复、历史备份和备份策略,备份监控放在了首页上进行展示,页上可以看到备份的执行时间、执行情况、备份校验和备份文件大小等信息,部分内容如下图所示:

clipboard.png

管理平台可以提供备份执行和备份恢复的功能,除了日常备份与恢复测试,这里可以提供变更前或故障发生时的临时备份,如下:

备份执行

备份恢复时可以指定某个时间点的备份文件对现网数据进行恢复。平台也提供了在测试环境进行数据恢复的接口,可以将个别业务表的历史数据恢复并导出,用于数据比对和故障排查。

备份恢复

可以通过管理平台对备份策略进行设置,对日常备份的执行时间、保留周期、备份方式等进行设置或修改,并且提供了对每套数据库进行策略修改的接口。

备份策略修改

容灾

容灾是在备份的基础上,建立一个异地的数据系统,该系统是本地关键应用数据的一个实时复制。

容灾方案应支持自动灾备切换和手工灾备切换功能。在灾难发生时,支持进行自动检测和切换,启动异地高可用的设备或节点,切换后数据只读类服务应可即时可用,保障业务连续性。部分复杂业务功能可进行手工灾备切换。同时,运营管理平台应该提供手工灾备切换功能,允许维护人员手工切换主、备设备或节点,以进行系统维护或者灾备演练。

为实现容灾,移动云运营管理平台及后端数据库以异地(华南、华北两个区域)主备方式部署和运行,业务数据实现异地异步同步。华南2资源池内部署运营管理平台的主服务节点,华北1资源池内部署备节点。当华南2资源池整体故障时,可启用华北1备节点的运营管理平台服务。

RPO/RTO测算

进行灾备解决方案设计时,需关注灾备的两个关键技术指标:

1)RTO:RecoveryTime Object,恢复时间目标。指灾难发生后,从IT系统宕机导致业务停顿之刻开始,到IT系统恢复至可以支持各部门运作,业务恢复运营之时,此两点之间的时间段称为RTO。RTO是反映业务恢复及时性的指标,体现了企业能容忍的IT系统最长恢复时间。RTO值越小,代表容灾系统的恢复能力越强,但企业投资也越高。

2)RPO:Recovery Point Object,恢复点目标。指灾难发生后,容灾系统进行数据恢复,恢复得来的数据所对应的时间点称为RPO。RPO是反映数据丢失量的指标,体现了企业能容忍的最大数据丢失量的指标。RPO值越小,代表企业数据丢失越少,企业损失越小。

根据数据类型和数据保留周期测算推导自己的RPO/RTO。

  • 基于数据重要级别分析,为各系统进行分级为A、B、C、D;
  • 基于保留周期分析,定义各备份数据的保留时间;
  • 基于数据类型分析,区分数据库、应用数据、配置文件系统等。

根据以上调研可以进行RPO和RTO的测算,例如:

数据库灾备方案

数据库用于存放运营管理平台所有用户的持久化业务数据。为保证切换至备节点后,用户业务数据无丢失,需实现数据库异地灾备。

数据库灾备包括了灾难发生前数据的实时异地备份及故障排除后的数据恢复方法。

1)数据库备份

假设节点1为主节点、节点2为灾备。在节点2建立节点1数据库副本,包括数据库以及消息队列等中间件持久化数据。目前副本只支持单节点形式部署,不支持负载均衡模式,节点1数据库中的增量数据每秒进行一次异地备份,存放到节点2灾备数据库中。节点1和节点2间使用专线传输,保证数据备份的及时可靠。当故障发生时,对于数据库切换过程中暂存于节点1数据库中的数据可能会丢失,如订单状态,支付状态等,需要在完成数据库切换后由用户重新操作。

2)数据库恢复

灾备中心切换成功后,用户数据将存放于节点2的灾备数据库中。故障排除后,需要将数据恢复到节点1。从节点2灾备数据库启用至故障恢复期间产生的订单、用户数据需要以全量复制形式恢复到节点1数据库,该过程使用手动进行。数据恢复后再将数据库访问入口从节点2调整到节点1。至此完成数据库的恢复操作。

3)同步方案

小结

结合以上备份和容灾方案就构建了移动云一套完整的数据库灾备体系,为企业用户提供多数据中心带来的更高级别的安全性和产品的稳定性以及实现更细产品颗粒度级别的备份控制。

作者介绍

刘书浩,中国移动DBA,负责“移动云”业务系统的数据库运维、标准化等工作;擅长MySQL技术领域,熟悉MySQL复制结构、Cluster架构及运维优化;具有自动化运维经验,负责“移动云”数据库管理平台的搭建。

本文由 dbaplus 社群授权转载。

原文链接

https://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=2650781638&idx=2&sn=af78070ad26230f6ec3d40cd0a6bfcbe&chksm=f3f90253c48e8b456c544d3ff1bd006e06449a29236247da143ac4af4463bb4e539b30ea5ae4&scene=27#wechat_redirect

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/bdyoo0QZCmLTH0HmPUop
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券