云原生数据库海山(He3DB)PostgreSQL版核心设计理念

本期深入解析云原生数据库海山PostgreSQL版(以下简称“He3DB”)的设计理念,探讨在设计云原生数据库过程中遇到的工程挑战,并展示He3DB如何有效地解决这些问题。

He3DB是移动云受到 Amazon Aurora 论文启发而独立自主设计的云原生数据库产品,它与 Aurora 以及其他云厂商的同类竞品共享一些核心设计理念,特别是计算与存储分离、日志即数据库(Log is Database)、以及共享存储。这些理念构成了现代云原生数据库的技术基础,目的是为了提高可扩展性、可靠性和性能。

为了方便大家更进一步的了解 He3DB ,下面我也将逐一解析这几个核心设计理念,并探讨 He3DB 在工程实现或产品核心设计上与 Aurora 及其竞品的不同之处。

云原生数据库核心设计理念

1.计算与存储分离:

这一理念意味着数据库的计算层和存储层在物理上是独立的。这种分离使得两者可以独立地扩展,提高了资源利用率,同时也简化了数据的备份和恢复过程。

2.日志即数据库(Log is Database):

在这种设计下,所有的数据库修改操作首先被记录到日志中,这个日志之后被用作构建和更新数据库状态的唯一来源。这种方法把所有的写转化为日志写,给予我们更多的方法提升写性能以及跨AZ的高可用能力。

3.共享存储:

使用共享存储架构意味着所有的计算节点可以访问同一个存储系统,这样可以实现数据的高可用性和容错性,同时简化了数据管理。

现在即便许多云原生数据库产品在设计上追求解决类似的问题,但在工程实现和产品能力上依然存在显著差异。这些差异导致了性能、高可用性、容量支持以及成本效益等方面的不同。

其实也很好理解,例如,某些产品通过使用高性能硬件提高了性能,但相应地也增加了成本。另一些产品则在底层存储设计上天然支持跨 AZ,从而在高可用性方面表现更佳。

目前许多云服务提供商在推广其云原生数据库产品时强调了它们在多个方面相对于RDS的优势,但从市场接受度来看,RDS依然占据主导地位。这主要是因为云数据库的主要客户群体是中小型企业,这些企业对数据库的负载和存储容量需求相对较低,而RDS的功能和性能已经足够满足他们的业务需求。但由于云原生数据库的架构设计导致其成本相对较高,且在处理小规模数据和低负载场景时,其性能并不总是能超越RDS。所以业内同类竞品在宣传时,往往更强调它们产品能力上限。

而He3DB产品的研发初期,我们除了需要保证它的上限处于业内主流水平 ,其实更关注的是它的下限表现,因为我们期望最终实现的不仅是在能力上全面超越RDS,同时在全场景使用下,成本也要明显优于RDS。为此,我们分别从“性能”“成本”这两个方面设定了以下研发目标:

1.性能目标

l  适应性能:确保在低容量和低负载的场景下,He3DB的性能能与RDS相匹配。

l  优越性能:在面对高负载和高容量的情况时,He3DB的性能要比RDS高出2到3倍。

l  性能指标:实现写入吞吐量(TPS)超过10万,读取吞吐量(QPS)超过100万。

2.成本目标

l  成本效益:任意业务场景负载下,He3DB的成本不高于RDS。

l  成本竞争力:竞品相比,He3DB能够实现至少30%的成本降低。

通过制定这些明确的研发目标,He3DB计划在性能提升成本控制方面实现突破,从而解决市场推广过程中遇到的主要问题,并为用户提供更优的数据库解决方案。

接下来,我将重点介绍He3DB的架构设计,从而解释我们如何实现设计目标,并使它在成本控制上优于传统的关系数据库服务(RDS)以及同类竞品。

3.He3DB设计目标:

l  支持一主15备,能够满足企业对扩展性的需求。

l  支持高达100TB的数据存储能力,适应大规模数据处理需求。

l  主备节点共享存储,这意味着增加备机不会造成存储成本的增加,从而实现了成本效优

l  性能方面,He3DB能够达到读取查询处理速率(QPS)100万次、写入事务处理速率(TPS)10万次的高性能标准。

下面我将从技术角度一一解释He3DB如何实现这些目标。

一、如何支持一主15备:

在PostgreSQL中,随着备机数量的增加,流复制会导致主服务器的性能下降,因为主服务器需要将写操作(WAL)复制到每个备机。在复制过程中,主服务器会遇到瓶颈,尤其是当备机的数量增加到5个以上时。He3DB 需要解决的问题是如何有效地同步和分发日志,以支持一主多备(至少15备)的架构,而不会对主服务器的性能造成显著影响。为此,He3DB采取以下设计:

1.   专用的WAL服务

提供一个专用的WAL日志服务,该服务负责接收主服务器的WAL日志,持久化存储,并将其分发给所有的备机。这样,主服务器只需发送一份WAL日志到WAL服务,由WAL服务来负责分发给各个备机,极大地减少了主服务器的负担。

2.   异步复制

采用异步复制机制,主服务器在写入WAL后不必等待所有备份确认,可以立即继续处理新的事务,这有助于提高主服务器的性能。

3.   批量发送和压缩

WAL服务可以将日志更改批量发送,并在传输前对其进行压缩,以减少网络传输的数据量。

4.   负载均衡和缓存

WAL服务可以使用负载均衡技术来平衡对不同备机的日志分发,同时使用缓存机制来存储热数据,以便快速分发给备机。

5.   多副本一致性算法

采用一致性算法来确保WAL服务的高可用和数据一致性,即使在WAL服务节点故障的情况下也能正常运行。

通过这样的设计,He3DB才能够确保即使在多达15个备机的情况下,主服务器的性能也不会受到明显影响,同时保持数据的高可用性和一致性。这种设计是在主数据库和备机之间引入了一个中间层,来协调日志的持久化和分发过程。关于这个模块的设计我以后会专门出一期再跟大家进行详细介绍。

二、如何支持100T 容量:

He3DB采用计算与存储分离的架构,并利用S3作为底层的持久存储层,这种设计具有多方面的优势:

1.   存储容量和弹性

S3提供了几乎无限的存储容量和良好的弹性。它可以根据需要自动扩展,用户无需预先分配存储空间,也无需担心空间不足的问题。

2.   高可用性和耐久性

S3提供了数据服务的高可用性以及高可靠性,这意味着数据丢失的风险极低。

3.   成本效益

相比于高性能硬件解决方案,S3提供了成本效益更高的存储服务。由于其按使用量计费和无需前期投资的特性,用户可以在控制成本的同时享受高质量的存储服务。

4.   性能优化

通过在S3上层增加数据缓存服务层,可以解决访问S3时遇到的高延迟问题。这层缓存可以用于存储数据,提高访问速度。

5.   自动化扩展和缩容

数据缓存服务层(DS)支持多节点,并且可以根据业务负载自动扩缩容,对外提供透明服务。这允许He3DB动态地调整资源,以应对不同的负载需求。

6.   数据分层

通过将数据按热度进行分层,冷数据(低频访问数据)可以在S3中进行极限压缩,以降低存储成本。热数据则存储在更快速的缓存层中,以提供更佳的性能。

总的来说,He3DB通过将S3作为持久层的选择,结合数据缓存服务层的设计,提出了一个既能满足大规模数据存储需求,又具有成本效益,同时能够提供必要性能保障的解决方案。这种架构特别适合云原生数据库的需求,可以有效地支持数据的扩展性、弹性和成本控制。

三、如何实现共享存储:

在He3DB这样的一主多备架构中,数据的一致性是通过日志同步机制来保证的。主节点和备节点之间通过WAL(Write-Ahead Logging)日志来同步数据变更。

为了帮助大家更好地理解共享存储设计,我再简单介绍一些背景知识:

1.   数据写入和一致性

l  在主节点上持久化写入数据后,由于备节点的数据同步存在延迟,它们读取的数据可能不会立即反映最新的更改,导致主备节点间的数据不一致。

2.   日志顺序号(LSN)和数据同步

l  PostgreSQL在主备节点间同步数据状态是通过日志顺序号(LSN)来标识的。每当主节点上发生数据更改,都会生成一个新的WAL日志条目,并分配一个唯一的LSN。

l  主节点的WAL日志LSN始终是最新的。备节点不断地处理这些WAL日志来追赶主节点的状态。但在WAL日志负载较高的情况下,主备节点可能会在同一时刻对应不同的LSN,从而导致它们所见的数据状态有所差异。

3.   数据PAGE多版本维护

l  虽然大部分时间内主备节点看到的数据状态是一致的,某些数据可能会因为WAL日志同步的延迟而出现版本差异。为了确保数据的一致性和准确性,数据库本身需要管理数据的多个版本。

l  多版本数据管理机制防止在查询操作中访问到还未同步的“未来”数据版本,或者已经被覆盖的“过去”数据版本。

通过实现多版本数据管理,He3DB确保了即使在高负载情况下,数据最终也能达到一致性,同时避免了因为访问错误版本的数据而导致的正确性问题。

在业界,一些数据库产品在处理数据PAGE版本差异时,选择在计算引擎或存储引擎层面进行设计。通常做法是记录一个基础数据页面(PAGE),然后通过链表记录与该PAGE相关的WAL日志条目,以此来异步回放并实现多版本的数据页面读取。

He3DB最初的设计也采用了这种方法。然而,这种设计在性能达到理想状态方面存在挑战,并且会占用较多的内存资源,因为需要在内存中管理元数据。此外,一旦出现问题,问题定位过程比较复杂。

为了解决这些问题,He3DB进行了设计上的改进,实现了所谓的“分布式多版本数据PAGE控制”:

1.单一数据版本维护:

l  数据存储服务(DS)仅维护单一版本的数据。DS控制WAL日志的回放节奏,确保DS是最慢WAL回放节点。这种设计实质上意味着DS主要负责维护主备节点读取一致的数据部分,而由于WAL同步的差异影响到的数据通常很少。

2.本地盘缓存模块:

在每个计算节点,He3DB引入了一个本地盘缓存模块,专门用于缓存和维护主备节点之间的差异数据版本。例如,如果主节点的当前LSN是100,备机1的LSN是30,备机2的LSN是60,而DS的回放LSN是25,那么:

l  主节点的本地盘缓存模块会维护从LSN 25到100之间变更的数据页面。

l  备机1会缓存从LSN 25到30之间变更的数据页面。

l  备机2会缓存从LSN 30到60之间变更的数据页面。

随着每个节点的WAL日志的不断推进,计算节点能够迅速回收相关的缓存页面数据,从而有效释放存储空间。

看到这里可能有人会问,如果出现本地缓存数据的问题怎么办。这一点我们也有考虑到。

He3DB会基于DS重新生成备份节点,并将其加入集群中,而不会影响数据的准确性。这种新的设计不仅提高了性能,减少了内存的使用,还简化了问题定位和故障恢复的流程,从而大幅提高了数据库的可维护性和稳定性。

四、如何保证高性能以及控制波动率:

He3DB在不引入任何高性能硬件的情况下实现了高性能和控制性能波动的策略。下面我将从写和读两个场景分析性能表现:

1.写性能

He3DB的设计理念是“日志即是数据库”(log is database),这意味着所有的写操作都被转换为日志写入。通过将日志写操作外包给专门的WAL服务(wal service),HE3DB能够借助WAL服务的高吞吐量来提升写性能。这个设计允许系统将数据写入操作并行化和分布化,从而提升整体的写入速度。

2.读性能

He3DB采用了计算存储双缓存设计,该设计通过冷热数据分层来保证性能的可控性:

l  热数据:存放在计算节点本地盘,这些是频繁访问的数据。

l  中数据:存放在DS,支持数据分片,对用户透明。

l  冷数据:存放在S3存储中,通过压缩能够进一步降低存储成本。

计算节点的本地盘缓存的热数据源自databuffer的淘汰数据。在业务初始阶段,He3DB会积极缓存所有数据,以保证访问性能稳定,这时候读性能可以与传统的关系数据库服务(如RDS)持平。

随着业务周期的推进和更多统计信息的收集,He3DB会开始进行数据回收,即从本地盘删除部分数据以优化存储。为了降低S3在性能波动上的影响,DS层在初期会尽量缓存所有数据,只有在确认某些数据是不是高频访问数据后,才会将其迁移到S3。

五、控制波动率和成本

冷热数据的策略设计对于控制性能波动和成本至关重要。He3DB遵循的原则是确保高频访问的数据一定能在FC(本地盘缓存)命中,对于不能确定是否为冷数据的,则绝不会直接通过访问S3访问。如果FC的当前容量无法覆盖所有高频数据,He3DB将触发动态的扩容操作而不是简单地将数据淘汰到DS层。

通过这种机制,He3DB能够在没有高性能硬件支持的情况下,通过软件层面的优化实现性能上的提升,同时保持成本的可控和性能的稳定性。这样的设计也允许系统在面对不同的工作负载和数据访问模式时,能够灵活调整资源分配,以适应业务需求的变化。

后续He3DB将采用智能预测和用户知识结合的方法来管理冷热数据。这种策略不仅提高了数据存储的效率,还有助于实现成本的优化。以下是一些实施该策略时可以考虑的要点和可能的扩展:

1.智能数据分层:

利用机器学习模型以及业务访问统计信息预测数据的访问模式,自动将数据分为冷热中三层。

2.用户参与:

用户可以标注特定数据或模式,指导He3DB更好地识别冷热数据。

3.动态定价模型:

根据冷热数据管理策略,设计一个灵活的定价模型。用户可以根据他们的实际使用情况选择不同的价格计划。

4.性能与成本权衡:

通过用户界面允许客户根据业务需求调整性能和成本的平衡,例如,允许客户指定对于特定数据集的最大响应时间。

5.透明度和控制:

提供仪表板和工具,让用户可以看到数据的冷热状态,预估成本,并能够手动调整数据层级。

6.自动化策略调整:

系统可以根据历史数据和预测结果自动调整数据的冷热分层策略,以适应数据访问模式的变化。

7.可扩展性和弹性:

设计系统时要考虑到未来数据量的增长,确保系统能够水平扩展,同时保持性能和成本效率。

8.反馈循环:

建立定期的反馈机制,持续监控和优化冷热数据预测模型的准确性。

通过这些综合的策略,He3DB可以为用户提供一个自动化、高效且成本可控的数据管理系统。用户可以根据自己的业务需求和成本敏感度,调整系统的配置以达到最佳的性能和成本平衡。这种灵活性和自适应性使得He3DB能够在激烈的市场竞争中为用户提供显著的价值。

在产品稳定性设计方面,我们的团队坚守一个核心原则——追求简洁性和控制复杂度。我们相信,只有通过简化设计和控制复杂性,我们才能确保产品的稳定性和可靠性,这也是我们对客户的责任。

这一原则不仅指导着我们的整体设计思路,也直接影响我们在架构设计过程中的决策:

1.PG(PostgreSQL)改造策略:

l  我们决定采用插件化的方法来开发PG的改造部分。这样做可以最小化对PG内核的影响,确保改动是可控的,并将自研代码封装在独立模块中,实现模块的高内聚和低耦合。

l  插件化还有助于我们在未来快速兼容PG不同的内核版本。

2.存储层选择:

l  我们选择了S3来作为我们的技术存储层,而不是开发一个专用的数据库存储系统。这种做法最大限度地利用了现有的云基础设施,避免了不必要的开发工作,同时也能够享受云服务提供的稳定性和可扩展性。

3.数据页的多版本设计:

l  我们将数据页的设计从集中式转变为分布式多版本,这样可以简化整体架构,并使风险更加可控。分布式设计提高了系统的伸缩性和容错能力,同时也简化了数据管理。

总而言之,我们的设计哲学是通过简化和模块化来增强产品的稳定性。我们通过插件化来保护核心系统不受破坏,通过利用成熟的云服务来降低开发难度,以及通过采用分布式数据缓存服务提高系统的可靠性和伸缩性。这些决策共同构成了我们对客户负责任的设计承诺。

今年我们还计划孵化若干新技术以验证我们的创新理念。这些创新成果将逐步以专利申请或学术论文的形式公开,具体创新包括:

1.增量快照技术:

我们正在开发一种增量快照技术,用于高效管理数据页(PAGE)多版本,这有望提升数据处理的灵活性和效率。

2.数据快照设计:

借助创新的数据快照设计,He3DB将能够在无需传统备份的情况下,实现一定时间周期内任意时间点的数据恢复能力。

这些技术进步不仅将增强He3DB的市场竞争力,还将为我们的客户提供更加稳定、可靠且易于管理的数据库解决方案。

六、作者介绍

薛港,移动云高级研发工程师,负责云原生数据库海山PostgreSQL版架构设计。拥有逾十年数据库内核开发经验,在云计算基础设施与数据库整合领域具备丰富的实践知识。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

html+javascript,用date完成,距离某一天还有多少天

图片展示: html代码 如下: <style>* {margin: 0;padding: 0;}.time-item {width: 500px;height: 45px;margin: 0 auto;}.time-item strong {background: orange;color: #fff;line-height: 100px;font-size: 40px;font-family: Arial;padding: 0 10px;margin-right: 10px…

Day98:云上攻防-云原生篇K8s安全Config泄漏Etcd存储Dashboard鉴权Proxy暴露

目录 云原生-K8s安全-etcd(Master-数据库)未授权访问 etcdV2版本利用 etcdV3版本利用 云原生-K8s安全-Dashboard(Master-web面板)未授权访问 云原生-K8s安全-Configfile鉴权文件泄漏 云原生-K8s安全-Kubectl Proxy不安全配置 知识点&#xff1a; 1、云原生-K8s安全-etcd未…

性能优化-02

uptime 依次显示当前时间、系统运行时间以及正在登录用户数&#xff0c;最后三个数字依次则是过去1分钟、5 分钟、15 分钟的平均负载(Load Average) 平均负载是指单位时间内&#xff0c;系统处于可运行状态和不可中断状态的平均进程数&#xff0c;也就是平均活跃进程数&#xf…

执行npm命令一直出现sill idealTree buildDeps怎么办?

一、问题 今天在运行npm时候一直出项sill idealTree buildDeps问题 二、 解决 1、网上查了一下&#xff0c;有网友说先删除用户界面下的npmrc文件&#xff08;注意一定是用户C:\Users\{账户}\下的.npmrc文件下不是nodejs里面&#xff09;&#xff0c;进入到对应目录下&#x…

golang实现定时监控 CLOSE_WAIT 连接的数量

文章目录 go实现定时检查大量的 CLOSE_WAIT 连接背景&#xff1a;为什么监控指定端口上的 CLOSE_WAIT 连接数量原因&#xff1a;什么是CLOSE_WAITgo实现定时检查大量的 CLOSE_WAIT 连接参考 go实现定时检查大量的 CLOSE_WAIT 连接 监控指定端口的连接状态&#xff0c;特别是关…

分类算法——KNN算法(二)

什么是K-近邻算法 1KNN原理 K Nearest Neighbor算法又叫KNN算法&#xff0c;这个算法是机器学习里面一个比较经典的算法&#xff0c;总体来说KNN算法是相对比较容易理解的算法。 定义 如果一个样本在特征空间中的k个最相似&#xff08;即特征空间中最邻近&#xff09;的样本…

搭建Python王国:初心者的武装指南

Python环境搭建与配置 进入编程世界的大门&#xff0c;选择了Python作为你的剑&#xff0c;那么接下来&#xff0c;你需要的是一把磨好的利剑——一个配置妥当的Python开发环境。本文将指引你完成这个必要的准备过程&#xff0c;从安装Python到选择合适的IDE&#xff0c;再到理…

性能升级,INDEMIND机器人AI Kit助力产业再蜕变

随着机器人进入到越来越多的生产生活场景中&#xff0c;作业任务和环境变得更加复杂&#xff0c;机器人需要更精准、更稳定、更智能、更灵敏的自主导航能力。 自主导航技术作为机器人技术的核心&#xff0c;虽然经过了多年发展&#xff0c;取得了长足进步&#xff0c;但在实践…

Linux/Tenten

Tenten Enumeration Nmap 扫描发现对外开放了22和80端口&#xff0c;使用nmap详细扫描这两个端口 ┌──(kali㉿kali)-[~/vegetable/HTB/Tenten] └─$ nmap -sC -sV -p 22,80 -oA nmap 10.10.10.10 Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-25 00:52 EST Nmap …

epic免费游戏在哪里领 epic免费游戏怎么领取 图文教程一看就会

Epic Games是一家位于美国北卡罗来纳州卡里的视频游戏和软件开发商&#xff0c;由Tim Sweeney于1991年创立。该公司最著名的作品包括《堡垒之夜》和虚幻引擎&#xff0c;后者是一种广泛用于游戏开发的商用游戏引擎。Epic Games在2020年和2024年分别与索尼和迪士尼达成财务合作及…

SpringBoot生成二维码并扫码

文章目录 一、引入依赖二、配置1.yml配置2.配置文件实体二维码生成工具类 三、接口测试测试1、生成二维码手机扫码测试 结束 ★★★★★ 一、引入依赖 ZXing 是一个开源的条形码和二维码图像处理库&#xff0c;它提供了生成、解码和识别各种格式的条形码和二维码的功能。 <…

【word2pdf】Springboot word转pdf(自学使用)

文章目录 概要整体介绍具体实现官网pom文件增加依赖 遇到的问题本地运行OK&#xff0c;发布到Linux报错还是本地OK&#xff0c;但是Linux能运行的&#xff0c;但是中文乱码 小结 概要 Springboot word 转 pdf 整体介绍 搜了一下&#xff0c;发现了能实现功能的方法有四种 U…

ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

多 线 程

1&#xff0e;什么是多线程? 有了多线程&#xff0c;我们就可以让程序同时做多件事情 2.多线程的作用? 提高效率 3&#xff0e;多线程的应用场景? 只要你想让多个事情同时运行就需要用到多线程 比如:软件中的耗时操作、所有的聊天软件、所有的服务器 1.进程和线程【理解】 …

mybiats-puls-插入测试以及雪花算法

一&#xff0c;测试 /* * 插入测试 * */ Test public void test01() {User user new User();/** 自动帮我们生成id* */user.setName("kuku");user.setAge(3);user.setEmail("2983394967qq.com");final int insert mapper.insert(user);System.out.print…

OceanMind海睿思入选《2024 中国MarTech行业生态图》

「Morketing研究院」正式发布《2024 中国MarTech行业生态图》&#xff0c;中新赛克海睿思作为国内数据治理优秀厂商&#xff0c;成功入选「数据与分析」板块「数据管理平台」子类&#xff0c;占据Martech领域关键节点。 ◎《2024中国MarTech行业生态图》 关于MarTech生态图 《…

【Django开发】前后端分离美多商城项目第7篇:登录,使用登录的流程【附代码文档】

美多商城项目4.0文档完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;美多商城&#xff0c;项目准备1.B2B--企业对企业,2.C2C--个人对个人,3.B2C--企业对个人,4.C2B--个人对企业,5.O2O--线上到线下,6.F2C--工厂到个人。项目准备&#xff0c;配置1. 修改set…

记录一次Java中使用P12证书访问https,nginx返回403的问题

目录 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确2、编写初始java代码3、结果响应 403 Forbidden4、解决方案 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确 成功返回&#xff0c;说明p12证书和密钥是没问题的。 2、编写初始java代码 …

智慧公厕是公共厕所信息化向高端发展的必然

现代社会的发展离不开科技的加持&#xff0c;公共厕所作为城市基础设施之一&#xff0c;也在不断引入智慧化的概念&#xff0c;实现信息化、智慧化和数字化的使用和管理。智慧公厕通过物联网、大数据、云计算、网络通信和自动化控制技术的应用&#xff0c;成为了高级的社会公共…

【vue】watchEffect 自动侦听器

watchEffect&#xff1a;自动监听值的变化 获取旧值时&#xff0c;不是很方便&#xff0c;建议用watch <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…