0
4
2
0
专栏/.../

运维成本降低 90%,存储成本降低 3 倍:多点利用 TiDB 资源管控功能将 100+ 套 MySQL 集合到一个 TiDB 实践

 jiaxin  发表于  2024-10-22

多点介绍

多点DMALL 是一站式全渠道数字零售解决方案服务商,提供端到端的商业SaaS解决方案。多点DMALL通过Dmall OS提供零售联合云一站式解决方案,帮助零售商和品牌商数字化转型,实现线上线下一体化;同时通过多点App等工具赋能全渠道经营能力,并提供各类增值服务。

多点 DMALL 不仅是中国最大的零售数字化解决方案服务商,也在积极拓展海外市场,2023 年除中国内地以外市场的贡献的营收已达数亿元。多点Dmall已成功打入欧美市场,与惠康、万宁、SM集团等世界知名零售商建立合作,推动了香港等地零售业的数字化转型。截至2023年底,多点Dmall的业务已覆盖8个国家和地区,展现了其在全球SaaS市场中的竞争力和影响力。多点Dmall的成功,体现了中国SaaS企业在全球市场的突破和成长。

相关介绍:境外业务持续加持 多点DMALL喜提“世界独角兽”

背景

在当前快速发展的大环境下,多点Dmall正积极推进零售SaaS私有化项目,以实现系统的高效简化。我们的目标是通过整合应用和数据库,显著降低系统的复杂性,并有效减少硬件成本与运维管理开支。

目前,我们已经将 Docker 应用实例从300个优化减少至150个,同时将数据库集群数量从 200 个精简至 100 个。在数据库方面,我们主要采用 MySQL 技术,其中最大的生产环境包含了上千个 MySQL 集群。现在我们已经成功地将多个 MySQL 集群合并为一个 TiDB 集群(多库合一)。我们将利用现有的 TiDB 集群,借助其动态扩缩容和高效压缩存储的能力,进一步优化数据库合并流程。TiDB 的这些优势使其在处理大量数据合并时,比传统的 MySQL 到 MySQL 合并更具效率和灵活性。我们的合并策略包括将源端 MySQL 中的库表数据完全迁移到目标 TiDB 集群中。通过更新配置中心并重启业务应用,我们能够顺利完成数据迁移和系统切换。尽管整个流程可能会遇到一些挑战和复杂情况,需要我们不断地调整和优化。通过这一私有化项目的实施,我们能够大幅提升系统的性能和稳定性,同时实现成本效益的最大化。

MySQL 合库到 TiDB 前提条件

二八原则的适用性在每个行业都很普遍,80%的业务高 QPS 流量是由 20% 的数据库产生的。某私有化项目生产有170 个 MySQL v8.0 集群, QPS 高的一般就 30 个库左右,大部分 MySQL 是属于长尾 QPS 较低,我们计划是长尾的这些全合并至一套 TiDB 集群。经过内部讨论合并 MySQL 至 TiDB 需满足几个条件:

高QPS业务不合并

QPS比较高的业务往往对读写延迟有更高的要求,受限于本次改造硬件资源和TiDB分布式事务,部分业务读写延迟没有单机MySQL好,基于硬件资源本次选择 QPS 小于 100 的业务做合并。和业务方沟通遂对所有生产 MySQL 集群统计了周末两天(零售行业大多周末是高峰期)的峰值 QPS (规则是一段时间内,每隔一分钟取一次 prometheus 监控数据计算出主库的峰值 QPS +从库的峰值 QPS 即为集群的峰值 QPS ,当然这也是参考数据,不能代表绝对,真实数据是做大促活动时的峰值 QPS )

经过第一轮条件筛选后,有154个 MySQL 集群可以合并

有 DDH 同步下有的 MySQL 不合并

Dmall Data Hub 数据同步系统(简称 DDH),同步 MySQL 的 binlog 至下游 kafka 给大数据或业务系统使用。 TiDB 自身也有 TiCDC 能同步自身的变更 changelog 至下游 kafka,但 TiCDC 同步 kafka 中格式和我们已有 DDH 同步 kafka 格式(内部自研的kafka 消费格式)是完全不同的,为避免下游大数据或业务系统改造适配 kafka 新格式的成本风险,我们决定不合并有 DDH 的 MySQL 集群。

在第一轮筛选后的基础上,经过第二轮筛选,剩余 148 个集群可以合并

无主键表/非数值主键表/联合主键表不合并

这三种类型表我们 DRC 同步(支持全量+增量同步 MySQL 至 TiDB )不支持,况且非标准无数值主键表目前我们工单审核也是禁止提交的。 TiDB 自身 TiCDC 同步变更至 kafka 也是要求表有主键。

在第二轮筛选后的基础上,经过第三轮筛选,剩余 131 个集群可以合并

有特殊用法外键/视图/存储过程等不合并

由于历史原因有几种非标准用法 MySQL 还有小部分需要排除,标准工单审核也已经禁止提交, TiDB 里是不支持这几种用法,主要是外键、存储过程、物化视图、特殊函数等功能。

第三轮筛选后,剩余128个集群可以合并

有分库&基础组件服务&可下线等不合并

MySQL 里有物理分库,库名一样如都是 dmall_xxx,分布在多个 MySQL 集群里,合并至 TiDB 的话库名有冲突需要排除;中间件基础服务有小部分是没有接入配置中心(应用从配置中心拿数据库连接信息)如果合并需要改代码对业务上不透明,接入配置中心标准的我们的 DBA 刷配置中心把 MySQL 连接信息改为 TiDB 后业务方就只重启应用;经过几轮的筛选后再找业务方二次检查筛选,标记了30 个老 MySQL 集群无用可以下线的,再减去有物理分库、基础服务,能合并至 TiDB 的减少至75个 MySQL 集群

104个 MySQL 集群(75 个合并至 TiDB ,29 个下线)一主一从共可释放资源 212G 内存,1.1T 磁盘

合库目标 TiDB 版本升级至7.5

已有一套老版本 v5.4 TiDB 集群,有几个库在里面,升级 TiDB 版本至 v7.5(官方长期支持LTS)一是连接协议兼容 MySQL v8.0(@@version 8.0.11- TiDB -v7.5.0 我们源要合并的都是 MySQL v8.0,目标是让业务方不做任何改动把 MySQL 合并至 TiDB ),二是 v7.x 版本是新特性如RU资源管控、TTL自动清理无用数据,性能提升等

升级版本先必须在测试环境跑通后一段时间再做生产

升级前最好做好备份作为兜底

tiup 进行升级还是比较顺畅

升级前后读写延迟有降低 40-50% 左右,性能有一定提升。

升级前

升级后

#tiup 组件以及工具进行升级,并检查 tiup 版本到最新版本

tiup update cluster
tiup update --self
tiup update --all
tiup --version

#安装 TiDB 新版依赖

yum -y install irqbalance numactl

#是否有正在执行 DDL,确保升级时无

ADMIN SHOW DDL jobs;

#确保 region 状态为 health Checking region status of the cluster  TiDB -xxxx... All regions are healthy. 也会检查一些内核参数配置情况

tiup cluster check  TiDB -xxxx --cluster

# v5.4 TiDB 版本到 v7.5 进行了两次升级( v7.1 版本开始有个大特性资源管控成为正式功能 (GA) ,所以先升级到v7.1 版本过渡下)

tiup cluster upgrade  TiDB -xxxx v7.1.4 --transfer-timeout 300
tiup cluster upgrade  TiDB -xxxx v7.5.0 --transfer-timeout 300
tiup cluster display  TiDB -xxxx
tiup install ctl:v7.5.1

#dashboard 账号需要增加授权,不然会报错 TiDB  dashboard登录失败,新版 TiDB 对权限做了拆分细化,老版本 TiDB 登录 dashboard 账号只需要 select,process,config

GRANT SELECT,PROCESS,SHOW DATABASES,SUPER,CONFIG ON *.* TO 'xx'@'xx.xx.%.%'               
GRANT;
DASHBOARD_CLIENT,RESTRICTED_STATUS_ADMIN,RESTRICTED_VARIABLES_ADMIN,SYSTEM_VARIABLES_ADMIN ON *.* TO 'xx'@'xx.xx.%.%';

同步MySQL账号信息至TiDB

循环多次分别导出要合库 MySQL 账号信息还原至 TiDB

#pt工具导出源 MySQL 8.0 用户账号信息

pt-show-grants -u myxxxx  -p xxx -h  xxxx.com  -P 3306   > user_grant

#去掉不需用同步至 TiDB 的账号

grep -vE 'user1|user2|user3|user4|user5|user6|user7|user8|user9|user10|userN'  *_user_grant | awk -F':' '{print $2}'>>user_grant

#去掉 MySQL v8.0创建用户特有标识, TiDB 里识别不了

sed -i 's/REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD REQUIRE CURRENT DEFAULT//g' user_grant

#还原用户账号至 TiDB 
 
MySQL  -umyxxxx  -pxxx -h xxxx.com -P 4000  -f< user_grant

TiDB 计算节点新扩容2台

我们现有的TiDB集群,在配置较低的情况下,已经成功支撑了多个只读业务的平稳运行,实现了从MySQL到TiDB的无缝迁移。该集群由3台2核8GB的计算节点和3台4核32GB的高性能存储节点组成,确保了数据处理的高效性。

为了进一步提升性能并满足日益增长的业务需求,我们在现有的MySQL服务器上扩展了2个计算节点。这一策略不仅利用了MySQL服务器上未充分利用的内存资源,还通过分散新增计算节点的负载,有效减轻了写入操作的延迟,特别是在处理高并发数据库操作时。

通过这种优化,我们不仅提升了集群的计算能力,还通过智能分配资源,确保了数据同步和合库操作的流畅性,为业务的持续增长和稳定性提供了坚实的基础。

TiDB 新建合库 MySQL 专用域名

刷配置中心时使用该域名

ti4000i- TiDB -xxxx.com

同步 MySQL 数据至 TiDB

先手动同步表结构加上 auto_id_cache 配置(为什么加这后面 TiDB 配置参数有说明)

MySQL dump --single-transaction  --skip-add-drop-table  -umyxxxx  -pxxxx  -h        m3306i.xxx.com -P  3306 --set-gtid-purged=off  --no-data -B   dmall_xxxx    | sed 's/ENGINE=InnoDB/AUTO_ID_CACHE 1/g'  |  grep -v '/*!40' > dmall_xxxx_schema

#并去掉 MySQL  dump出来的注释语句(上诉dump语句sed里去掉), TiDB 里无法识别 /*!40xxxx
/*!40101 SET character_set_client = @saved_cs_client */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;


#批量替换utf8mb3至utf8mb4, TiDB 里不支持utf8mb3
sed -i 's/utf8mb3/utf8mb4/g' *_schema

Check TiDB 数据一致情况

  • 业务应用方自助在数据查询平台抽查数据情况
  • dba批量统计源 MySQL 逻辑库行数和目标 TiDB 里逻辑库行数对比
SELECT   table_schema AS db_name,   SUM(table_rows) AS db_table_rows,   COUNT(*) AS table_count FROM   information_schema.tables   GROUP BY   table_schema order by db_table_rows;
+-----------------------------+---------------+-------------+
| db_name                     | db_table_rows | table_count |
+-----------------------------+---------------+-------------+
..........
| dmall_xxxxxx       |      29420502 |         103 |
| dmall_xxx         |      36970804 |          16 |
| dmall_xxx        |      75332428 |         200 |
| dmall_xxx        |      86095799 |         226 |
| dmall_xxx        |     570319647 |           1 |
+-----------------------------+---------------+-------------+
85 rows in set (0.17 sec)

刷配置中心数据后业务研发重启应用验证

  • 配置中心里有应用 app 对应 key, value 是多少,应用启动拿配置中心 key,读取 value
  • DBA 把涉及合库老 MySQL 连接信息刷成 TiDB 后,应用重启后,读取 TiDB 连接生效

Check TiDB 集群连接数&慢查询情况

应用重启后新连接进 TiDB

合库后 TiDB 事务 OPS 在 400 左右

迁移 MySQL 集群元数据至 TiDB 集群

数据库管理平台里有权限控制,不同业务方看到的 MySQL , TiDB 库是不一样的,就需要把 MySQL 数据库管理平台中依赖元数据表迁移至 TiDB 集群。

  • 主要梳理涉及元数据库里几张表关联迁移, MySQL 集群表,集群实例表,集群 DNS 表,集群对于系统应用表(当时迁移生成的 SQL 也有30行)

如下示例为另一生产环境 MySQL 、 TiDB 应用列表

MySQL 应用

TiDB 应用

对 TiDB 有压力库进行资源隔离(Resource Control)

TiDB 资源管控特性提供了两层资源管理能力,包括在 TiDB 层的流控能力和 TiKV 层的优先级调度的能力。两个能力可以单独或者同时开启,TiDB 提供用户、会话级、语句级别设置资源组,可将压力大的应用绑定到某个资源组后,TiDB 层会根据用户所绑定资源组设定的配额对用户的读写请求做流控,TiKV 层会根据配额映射的优先级来对请求做调度。通过流控和调度这两层控制,可以实现应用的资源隔离,满足服务质量 (QoS) 要求。

  • TiDB 资源隔离不是分配 IO CPU 具体多少,而是通过配置 RU(Request Unit (RU) 是 TiDB 对 CPU、IO 等系统资源的统一抽象的计量单位,读写请求消耗不同的RU)

  • 一共 85 个数据库,其中 3 个大库超过 100GB(大库有大 DML、SQL 查询会消耗大量硬件资资源,引起整个 TiDB 集群血崩),其中有 1个 库存在慢查询多,其它81个业务资源使用量低,没有开启资源管控能力。

  • TiDB 集群通过硬件配置预估可用 RU 2.7 万个,按70%安全资源利用算(用最大额 RU 的话服务器压力会很大),可使用 RU 约2 万个,分配 70% 的 RU 给4个大库(约1.4万,当前 TiDB 集群 IO、CPU 已有些压力70%~80%,因此分别对 4 个大压力库配置 RU 避免引起雪崩。)

  • RU 形式隔离对大的业务慢查询相对暴力些,RU 用完后 SQL 会报错,而不单纯是执行变慢,需要评估好设置好 RU。

    • 当前 7.5 ga 功能下,是超过分配 RU 会预估等待一定时间,预估时间较长还没有执行就报错。这个时间是动态可调的,默认 30s,可以调整 ltb-max-wait-duration 控制。
    • Runaway Queries 可以避免报错问题,但是 7.5 是实验特性,因此需要等升级 8.x 版本解决。
#给不同资源组分配不同RU

CREATE RESOURCE GROUP IF NOT EXISTS xxxx1 RU_PER_SEC = 3000 PRIORITY = MEDIUM;
CREATE RESOURCE GROUP IF NOT EXISTS xxxx2 RU_PER_SEC = 3000 PRIORITY = MEDIUM;
CREATE RESOURCE GROUP IF NOT EXISTS xxxx3 RU_PER_SEC = 3000 PRIORITY = MEDIUM;
CREATE RESOURCE GROUP IF NOT EXISTS xxxx4 RU_PER_SEC = 5000 PRIORITY = MEDIUM;

#通过账号名给不同库(一个库一个账号名)绑定资源组

ALTER USER dmall_xxx@'xx.xx.%.%' RESOURCE GROUP xxxx1;
ALTER USER dmall_xxx@'xx.xx.%.%' RESOURCE GROUP xxxx2 ;
ALTER USER dmall_xxx@'xx.xx.%.%' RESOURCE GROUP xxxx3 ;
ALTER USER dmall_xxx@'xx.xx.%.%' RESOURCE GROUP xxxx4 ;  #写入量大的库账号设置5000RU

如图所示,针对空间占用大、慢查询多的两类数据库进行资源隔离限制,保障资源充足。

通过 TiDB 提供的 Dashboard 面板可以看到 TiDB 对 RU 的容量估算情况以及用户分配使用情况,监控粒度以及评估实现可视化。

配置 RU 后,在 Grafana 的监控面板中可以看到不同资源组 RU 消耗使用情况

Grafana 中 TiDB -Resource-Control 面板可以检测到 RU 更详细监控数据,包括 RU、Query、RRU 和 WRU 等监控。

值得注意的是,RU 分配不合理情况下,可能因 RU 资源不足,导致业务 SQL 查询报错的情况,需要调整 RU 分配情况。

在 Grafana 的 RU 监控面板中,Available RU 监控数据显示有为 0 情况,实际业务写入数据正常,可能监控数据采集有点异常。(官方已知问题:这个监控和 RU_PER_SEC 这个流速的概念是不对等的,这里显示的只是令牌桶瞬时的一个状态,后面会去掉。)

全链路压测

虽然 MySQL 合库至 TiDB 已经在测试环境跑过一段时间,但测试环境无法模拟真实生产环境,有些应用没使用或业务流量 QPS 都很小。在 MySQL 合并到 TiDB 落地生产合库上线后,本次私有化项目的商家临近大促活动前,进行一次非常有意义的全链路压测,业务测试人员模拟发起前端请求高并发 QPS ,经过应用层,压力传导到后端数据库 MySQL 、TiDB 、MongoDB、Redis,来验证技术架构方案面对高并发场景的支撑能力。

扩容计算节点和存储节点

若平峰期该 TiDB 集群是能支持业务,不用扩容。

  • 3 台低配计算 2Core 8GB 升级至 4Core 16GB 服务器( MySQL -> TiDB 只读业务库使用计算节点)
  • 3 台低配存储 4Core 32GB 升级至高配 16Core 64GB nvme 3.7TB 本地盘服务器
  • 高配 16Core 64GB nvme 本地盘服务器上新扩容 3 台计算节点给直接读写 TiDB 业务使用(主要用计算资源, MySQL 合库至 TiDB )

3 台2C 8G pd, TiDB 计算+3 台4C 32G高性能存储支撑不了压测流量,并发一上来写入 TiDB 延迟时间飙升(P99到了7s 多,tikv cpu 压力最高 70% 左右,IO压力 75% 左右)

扩容前:

3台16C 64G nvme本地盘计算+存储扩容好后,并发压测上来, TiDB 延迟时间明显比之前提升近非常大(P99 64ms,P999 稍微高些 3s 多,tikv cpu压力最高 30% 左右,IO 压力低),大多数业务压测是通过,有活动任务业务压测还是没通过(并发更新高,遂回滚到了 MySQL )

扩容后:

TiDB 配置参数

AUTO_ID_CACHE

启用该参数后 TiDB 主键自增列行为才和 MySQL 单调顺序递增一致
  • 中心化自增ID分配,auto_increment MySQL 兼容模式(TiDB 的 v7.5.1 版本存在使用 auto_id_cache 可能有bug https://asktug.com/t/topic/1025153)
  • 确保多个 TiDB 计算节点生成的自增列是单调递增( MySQL 中可能有依赖主键id做分页排序用法select xxx from t order by id where id>? limit n),v6.4.0版本之前存在自增id不连续问题
  • 不支持在已有表增加 auto_id_cache,只能新建表设置
  • 生产环境保险起见,需手动导出 MySQL 表结构加上auto_id_cache 后再导入表结构到目标 TiDB
#v6.4.0 之前
SELECT * FROM t ORDER BY b;
+---------+---------------------+
| a       | b                   |
+---------+---------------------+
|       1 | 2020-09-09 20:38:22 |
|       2 | 2020-09-09 20:38:22 |
|       3 | 2020-09-09 20:38:22 |
| 2000001 | 2020-09-09 20:43:43 |
|       4 | 2020-09-09 20:44:43 |
| 2030001 | 2020-09-09 20:54:11 |
+---------+---------------------+
6 rows in set (0.00 sec)


#v6.4.0 以后支持
CREATE TABLE t(a int AUTO_INCREMENT key) AUTO_ID_CACHE 1; 

#已有表增加 auto_id_cache 报错
[错误]: (1105, "Can't Alter AUTO_ID_CACHE between 1 and non-1, the underlying implementation is different")

sql_mode

MySQL TiDB
STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES, NO_ZERO_IN_DATE,NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION

TiDB sql_mode修改为和 MySQL 一致,避免对业务应用产生不可预期的错误,如

ERROR 1067 (42000): Invalid default value for 'update_time'

其它参数

  • 支持设置默认校对规则,兼容MySQL8.0,default_collation_for_utf8mb4
  • no utf8mb3,TiDB里不支持utf8mb3,源MySQL表有这字符集需要转化为utf8mb4

合并后资源以及人效收益

  1. 上百个 MySQL 实例(一主一从)合并至 TiDB 后(有部分 MySQL 下线),数据库集群数量的大幅减少(175 套 MySQL +1 套 TiDB 减少至 74 套 MySQL +1套 TiDB ),为整个系统简化助力(系统简化:运维、DBA、产研多方努力协作成果);

  1. 动态扩缩容能力(迁移扩容 3 人天降为 0.5 人天),有大促活动时新加服务器水平扩展,低峰时缩容,更好有效利用资源;

  1. 降低存储成本, TiDB 相比 MySQL 5倍左右压缩率,整体能降3倍左右存储( MySQL 一主一从两副本, TiDB 三副本);

整体收益

通过将 100+套 MySQL 实例合并至 1 套 TiDB ,系统运维得到显著简化,数据库集群数量减少从运维100+套 MySQL 到运维一套 TiDB 集群,整体的运维成本降低了 90%;这一整合大幅降低了运维、DBA和产研的协作成本; TiDB 的动态扩缩容特性使得资源管理更加高效,从迁移扩容的3人天降至仅需0.5人天,整体提高了 6 倍;此外, TiDB 相比 MySQL 5 倍左右压缩率, MySQL 一主一从两副本, TiDB 三副本的情况下存储成本降低了 3 倍。除此之外,具体收益如下:

  1. 简化系统架构:通过减少数据库实例的数量,简化了整体系统架构,降低了系统的复杂性,使得运维工作更为集中和高效。
  2. 降低硬件成本:由于 TiDB 的高性能和良好的资源使用效率,可以用更少的硬件资源支撑相同的业务负载,减少了服务器的采购和运行成本。
  3. 减少运维人力:管理一个 TiDB 集群比管理上百个 MySQL 实例所需的运维人员更少,因为 TiDB 提供了更为自动化的管理工具和流程。
  4. 提高资源利用率: TiDB 的计算和存储分离架构允许更灵活的资源分配,可以在业务高峰期间快速扩展资源,低峰期间缩减资源,从而提高资源的利用率。
  5. 降低存储成本: TiDB 具有高效的数据压缩能力,相比 MySQL 可以显著减少存储空间的使用,降低了存储相关的成本。
  6. 提升备份效率:虽然 TiDB 的备份空间占用可能较大,但通过优化备份策略和忽略冗余数据,可以减少备份所需的存储空间,同时提升备份和恢复的效率。
  7. 增强数据安全性: TiDB 提供了多副本和自动故障转移机制,增强了数据的安全性和可靠性,减少了因数据丢失或损坏导致的运维成本。
  8. 减少业务中断风险:通过资源隔离和动态扩缩容, TiDB 可以更好地应对业务流量波动,减少因资源不足导致的业务中断风险。
  9. 性能提升: TiDB 的优化器和执行引擎针对现代硬件进行了优化,可以提供比传统 MySQL 更优的性能,减少了因性能问题导致的运维干预。
  10. 统一监控和管理:使用 TiDB 后,可以通过统一的监控和管理界面来观察整个数据库集群的状态,简化了监控系统的部署和维护工作。
  11. 降低升级和迁移成本: TiDB 兼容 MySQL 协议,减少了从 MySQL 迁移到 TiDB 的复杂性和成本,同时 TiDB 的持续升级和优化可以减少未来的升级工作。

0
4
2
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论