您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

多租户 SaaS 数据库租户模式Multi-tenant SaaS database tenancy patterns

在设计多租户 SaaS 应用程序时,必须慎重选择最符合应用程序需要的租户模型。When designing a multi-tenant SaaS application, you must carefully choose the tenancy model that best fits the needs of your application. 租户模型确定如何将每个租户的数据映射到存储。A tenancy model determines how each tenant’s data is mapped to storage. 所选的租户模型会影响应用程序设计和管理。Your choice of tenancy model impacts application design and management. 今后改用不同的模型可能需要付出一定的代价。Switching to a different model later is sometimes costly.

本指南介绍备选租户模型。This article describes alternative tenancy models.

A.A. SaaS 概念和术语SaaS concepts and terminology

在软件即服务 (SaaS) 模型中,贵公司不会销售软件的许可证In the Software as a Service (SaaS) model, your company does not sell licenses to your software. 而是,每个客户都会向贵公司支付租金,使每个客户成为贵公司的租户Instead, each customer makes rent payments to your company, making each customer a tenant of your company.

作为支付租金的回报,每个租户都可以访问 SaaS 应用程序组件,并将数据存储在 SaaS 系统中。In return for paying rent, each tenant receives access to your SaaS application components, and has its data stored in the SaaS system.

术语租户模型是指租户存储数据的组织方式:The term tenancy model refers to how tenants' stored data is organized:

  • 单租户: 每个数据库仅存储来自一个租户的数据。Single-tenancy:  Each database stores data from only one tenant.
  • 多租户: 每个数据库都存储来自多个独立租户的数据(使用保护数据隐私的机制)。Multi-tenancy:  Each database stores data from multiple separate tenants (with mechanisms to protect data privacy).
  • 混合租户模式也可用。Hybrid tenancy models are also available.

B.B. 如何选择适当的租户模型How to choose the appropriate tenancy model

一般情况下,租户模型不会影响应用程序的功能,但可能会影响总体解决方案的其他方面。In general, the tenancy model does not impact the function of an application, but it likely impacts other aspects of the overall solution. 以下条件用于评估每个模型:The following criteria are used to assess each of the models:

  • 可伸缩性:Scalability:

    • 租户数目。Number of tenants.
    • 每个租户的存储量。Storage per-tenant.
    • 总存储量。Storage in aggregate.
    • 工作负荷。Workload.
  • 租户隔离: 数据隔离和性能(一个租户的工作负荷是否影响其他租户)。Tenant isolation:  Data isolation and performance (whether one tenant’s workload impacts others).

  • 每个租户的成本: 数据库成本。Per-tenant cost:  Database costs.

  • 开发复杂性:Development complexity:

    • 架构更改。Changes to schema.
    • 查询更改(模式所需)。Changes to queries (required by the pattern).
  • 操作复杂性:Operational complexity:

    • 监视和管理性能。Monitoring and managing performance.
    • 架构管理。Schema management.
    • 还原租户。Restoring a tenant.
    • 灾难恢复。Disaster recovery.
  • 可自定义性: 易于支持租户特定或租户类特定的架构自定义。Customizability:  Ease of supporting schema customizations that are either tenant-specific or tenant class-specific.

有关租户的讨论侧重于数据层。The tenancy discussion is focused on the data layer. 但是,请花费片刻时间思考一下应用程序层。But consider for a moment the application layer. 应用程序层被视为单一实体。The application layer is treated as a monolithic entity. 如果将应用程序划分成多个小型组件,所选的租户模型可能会更改。If you divide the application into many small components, your choice of tenancy model might change. 在所用的租户和存储技术或平台方面,可以不同的方式对待某些组件。You could treat some components differently than others regarding both tenancy and the storage technology or platform used.

C.C. 包含单租户数据库的独立单租户应用Standalone single-tenant app with single-tenant database

应用程序级隔离Application level isolation

在此模型中,针对每个租户重复安装整个应用程序一次。In this model, the whole application is installed repeatedly, once for each tenant. 应用的每个实例是独立实例,因此,它永远不与其他任何独立实例交互。Each instance of the app is a standalone instance, so it never interacts with any other standalone instance. 应用的每个实例只有一个租户,因此只需要一个数据库。Each instance of the app has only one tenant, and therefore needs only one database. 租户包含自身的整个数据库。The tenant has the database all to itself.

设计恰好包含一个单租户数据库的独立应用。Design of standalone app with exactly one single-tenant database.

每个应用实例安装在单独的 Azure 资源组中。Each app instance is installed in a separate Azure resource group. 该资源组可以属于软件供应商或租户拥有的订阅。The resource group can belong to a subscription that is owned by either the software vendor or the tenant. 在任一情况下,供应商可为租户管理软件。In either case, the vendor can manage the software for the tenant. 每个应用程序实例已配置为连接到其相应的数据库。Each application instance is configured to connect to its corresponding database.

每个租户数据库部署为独立数据库。Each tenant database is deployed as a standalone database. 此模型提供最佳的数据库隔离性。This model provides the greatest database isolation. 但是,隔离需要向每个数据库分配足够的资源来处理数据库峰值负载。But the isolation requires that sufficient resources be allocated to each database to handle its peak loads. 此处的一个要点是,无法对不同资源组中部署的数据库或不同的订阅使用弹性池。Here it matters that elastic pools cannot be used for databases deployed in different resource groups or to different subscriptions. 从总体数据库成本的角度看,这种限制使得这种独立单租户应用模型成了最昂贵的解决方案。This limitation makes this standalone single-tenant app model the most expensive solution from an overall database cost perspective.

供应商管理Vendor management

供应商可以访问所有独立应用实例中的所有数据库,即使应用实例安装在不同的租户订阅中。The vendor can access all the databases in all the standalone app instances, even if the app instances are installed in different tenant subscriptions. 访问是通过 SQL 连接实现的。The access is achieved via SQL connections. 这种跨实例访问可让供应商出于报告或分析目的,在集中位置进行架构管理和跨数据库查询。This cross-instance access can enable the vendor to centralize schema management and cross-database query for reporting or analytics purposes. 如果需要此类集中化管理,必须部署一个可将租户标识符映射到数据库 URI 的目录。If this kind of centralized management is desired, a catalog must be deployed that maps tenant identifiers to database URIs. Azure SQL 数据库提供一个分片库,将该库与 SQL 数据库一起使用可以提供目录。Azure SQL Database provides a sharding library that is used together with a SQL database to provide a catalog. 该分片库的正式名称为弹性数据库客户端库The sharding library is formally named the Elastic Database Client Library.

D.D. 采用“每个租户各有数据库”模型的多租户应用Multi-tenant app with database-per-tenant

接下来的这个模式使用包含许多数据库的多租户应用程序,这些数据库都是单租户数据库。This next pattern uses a multi-tenant application with many databases, all being single-tenant databases. 针对每个新租户预配一个新数据库。A new database is provisioned for each new tenant. 可通过为每个节点添加更多的资源来纵向扩展应用程序层。The application tier is scaled up vertically by adding more resources per node. 或者,可通过添加更多的节点来横向扩展应用。Or the app is scaled out horizontally by adding more nodes. 缩放基于工作负荷,不受各个数据库的数目或规模的影响。The scaling is based on workload, and is independent of the number or scale of the individual databases.

设计采用“每个租户各有数据库”模型的多租户应用。Design of multi-tenant app with database-per-tenant.

根据租户进行自定义Customize for a tenant

与独立应用模式一样,使用单租户数据库可提供强大的租户隔离性。Like the standalone app pattern, the use of single-tenant databases gives strong tenant isolation. 在其模型仅指定了单租户数据库的任何应用中,可以根据任一给定数据库的租户自定义和优化该数据库的架构。In any app whose model specifies only single-tenant databases, the schema for any one given database can be customized and optimized for its tenant. 这种自定义不会影响应用中的其他租户。This customization does not affect other tenants in the app. 某个租户所需的数据可能超过了所有租户所需的基本数据字段。Perhaps a tenant might need data beyond the basic data fields that all tenants need. 此外,附加的数据字段可能需要索引。Further, the extra data field might need an index.

使用“每个租户各有数据库”模型,可以直截了当地定义一个或多个租户的架构。With database-per-tenant, customizing the schema for one or more individual tenants is straightforward to achieve. 应用程序供应商必须设计适当的过程,以慎重地大规模管理架构自定义。The application vendor must design procedures to carefully manage schema customizations at scale.

弹性池Elastic pools

如果将数据库部署在同一个资源组中,可将其分组到弹性数据库池。When databases are deployed in the same resource group, they can be grouped into elastic database pools. 通过池可以经济高效地在许多数据库之间共享资源。The pools provide a cost-effective way of sharing resources across many databases. 与创建足够大的数据库来适应它所遇到的用量高峰相比,使用这种池选项的成本更低廉。This pool option is cheaper than requiring each database to be large enough to accommodate the usage peaks that it experiences. 即使入池的数据库共享资源访问权限,也仍能实现较高程度的性能隔离。Even though pooled databases share access to resources they can still achieve a high degree of performance isolation.

使用弹性池设计采用“每个租户各有数据库”模型的多租户应用。Design of multi-tenant app with database-per-tenant, using elastic pool.

Azure SQL 数据库提供所需的工具用于配置、监视和管理共享。Azure SQL Database provides the tools necessary to configure, monitor, and manage the sharing. 可以通过 Azure 门户和 Log Analytics 查看池级和数据库级性能指标。Both pool-level and database-level performance metrics are available in the Azure portal, and through Log Analytics. 指标可以提供聚合性能和租户特定性能的深入见解。The metrics can give great insights into both aggregate and tenant-specific performance. 可以在池之间移动单个数据库,以便向特定的租户提供保留的资源。Individual databases can be moved between pools to provide reserved resources to a specific tenant. 使用这些工具可确保以经济高效的方式获得良好性能。These tools enable you to ensure good performance in a cost effective manner.

“每个租户各有数据库”模型的操作规模Operations scale for database-per-tenant

Azure SQL 数据库平台提供多种管理功能,用于大规模管理大量数据库(例如 100,000 以上的数据库)。The Azure SQL Database platform has many management features designed to manage large numbers of databases at scale, such as well over 100,000 databases. 这些功能使“每个租户各有数据库”模式变得合理。These features make the database-per-tenant pattern plausible.

例如,假设某个系统使用一个包含 1000 个租户的数据库作为其唯一的数据库。For example, suppose a system has a 1000-tenant database as its only one database. 该数据库可能包含 20 个索引。The database might have 20 indexes. 如果该系统改用 1000 个单租户数据库,则索引数量会提高到 20,000 个。If the system converts to having 1000 single-tenant databases, the quantity of indexes rises to 20,000. 自动优化过程中,默认会在 SQL 数据库中启用自动索引功能。In SQL Database as part of Automatic tuning, the automatic indexing features are enabled by default. 自动索引会自动管理所有 20,000 个索引,以及这些索引的持续创建和删除优化操作。Automatic indexing manages for you all 20,000 indexes and their ongoing create and drop optimizations. 这些自动操作发生在单个数据库内部,不受其他数据库中类似操作的协调或限制。These automated actions occur within an individual database, and they are not coordinated or restricted by similar actions in other databases. 自动索引在繁忙数据库中处理索引的方式与在不太繁忙的数据库中不同。Automatic indexing treats indexes differently in a busy database than in a less busy database. 如果必须手动完成这种异常繁重的管理任务,则以“每个租户各有数据库”规模进行这种索引管理自定义是不切实际的。This type of index management customization would be impractical at the database-per-tenant scale if this huge management task had to be done manually.

其他可以正常缩放的管理功能包括:Other management features that scale well include the following:

  • 内置备份。Built-in backups.
  • 高可用性。High availability.
  • 磁盘中加密。On-disk encryption.
  • 性能遥测。Performance telemetry.

自动化Automation

可以编写管理操作的脚本,并通过 devops 模型提供这些操作。The management operations can be scripted and offered through a devops model. 甚至可以在应用程序中自动化和公开操作。The operations can even be automated and exposed in the application.

例如,可将单个租户自动恢复到以前的某个时间点。For example, you could automate the recovery of a single tenant to an earlier point in time. 恢复操作只需还原一个存储租户的单租户数据库。The recovery only needs to restore the one single-tenant database that stores the tenant. 此还原操作不会影响其他租户,确保以每个租户的粒度级完成管理操作。This restore has no impact on other tenants, which confirms that management operations are at the finely granular level of each individual tenant.

E.E. 包含多租户数据库的多租户应用Multi-tenant app with multi-tenant databases

另一种可用模式是在一个多租户数据库中存储许多租户。Another available pattern is to store many tenants in a multi-tenant database. 应用程序实例可以包含任意数量的多租户数据库。The application instance can have any number of multi-tenant databases. 多租户数据库的架构必须包含一个或多个租户标识符列,以便能够选择性地检索任意给定租户中的数据。The schema of a multi-tenant database must have one or more tenant identifier columns so that the data from any given tenant can be selectively retrieved. 此外,该架构可能需要几个只由一部分租户使用的表或列。Further, the schema might require a few tables or columns that are used by only a subset of tenants. 但是,静态代码和引用数据只会存储一次,并由所有租户共享。However, static code and reference data is stored only once and is shared by all tenants.

丧失租户隔离性Tenant isolation is sacrificed

数据: 使用多租户数据库势必会丧失租户隔离性。Data:  A multi-tenant database necessarily sacrifices tenant isolation. 多个租户的数据统一存储在一个数据库中。The data of multiple tenants is stored together in one database. 在开发期间,需确保查询永远不会公开多个租户中的数据。During development, ensure that queries never expose data from more than one tenant. SQL 数据库支持行级安全性,这种安全性可以强制某个查询返回的数据划归到单个租户。SQL Database supports row-level security, which can enforce that data returned from a query be scoped to a single tenant.

处理: 多租户数据库在其所有租户之间共享计算和存储资源。Processing:  A multi-tenant database shares compute and storage resources across all its tenants. 可将数据库作为一个整体进行监视,确保其性能可接受。The database as a whole can be monitored to ensure it is performing acceptably. 但是,Azure 系统不提供内置的方式来监视或管理单个租户对这些资源的使用。However, the Azure system has no built-in way to monitor or manage the use of these resources by an individual tenant. 因此,多租户数据库增大了遇到干扰性邻居的风险:一个过度活跃的租户的工作负荷影响同一数据库中其他租户的性能体验。Therefore, the multi-tenant database carries an increased risk of encountering noisy neighbors, where the workload of one overactive tenant impacts the performance experience of other tenants in the same database. 其他应用程序级监视可以监视租户级性能。Additional application-level monitoring could monitor tenant-level performance.

成本更低Lower cost

一般而言,多租户数据库的每租户成本最低。In general, multi-tenant databases have the lowest per-tenant cost. 独立数据库的资源成本比同等大小的弹性池的成本更低。Resource costs for a standalone database are lower than for an equivalently sized elastic pool. 此外,在租户只需有限存储的情况下,有可能会将数百万个租户存储在单个数据库中。In addition, for scenarios where tenants need only limited storage, potentially millions of tenants could be stored in a single database. 没有任何弹性池可以包含数百万个数据库。No elastic pool can contain millions of databases. 但是,使用包含 1000 个池、每个池包含 1000 个数据库的解决方案可以实现百万量级的规模,而风险是管理变得复杂。However, a solution containing 1000 databases per pool, with 1000 pools, could reach the scale of millions at the risk of becoming unwieldy to manage.

下面介绍多租户数据库模型的两种变体,其中,分片多租户模型是灵活性和可伸缩性最高的模型。Two variations of a multi-tenant database model are discussed in what follows, with the sharded multi-tenant model being the most flexible and scalable.

F.F. 包含单个多租户数据库的多租户应用Multi-tenant app with a single multi-tenant database

最简单的多租户数据库模式使用单个独立数据库来托管所有租户的数据。The simplest multi-tenant database pattern uses a single standalone database to host data for all tenants. 添加更多的租户时,该数据库会使用更多的存储和计算资源进行纵向扩展。As more tenants are added, the database is scaled up with more storage and compute resources. 通过这种纵向扩展也许能够做到高枕无忧,不过,规模始终有一个最终的限制。This scale up might be all that is needed, although there is always an ultimate scale limit. 但是,在远远未达到该限制之前,数据库可能就会变得难以管理。However, long before that limit is reached the database becomes unwieldy to manage.

在多租户数据库中,侧重于单个租户的管理操作更难实现。Management operations that are focused on individual tenants are more complex to implement in a multi-tenant database. 大规模执行这些操作可能会使速度变得非常缓慢,让人无法接受。And at scale these operations might become unacceptably slow. 一个例子是只是对一个租户的数据执行时间点还原。One example is a point-in-time restore of the data for just one tenant.

G.G. 包含分片多租户数据库的多租户应用Multi-tenant app with sharded multi-tenant databases

大多数 SaaS 应用程序每次只访问一个租户的数据。Most SaaS applications access the data of only one tenant at a time. 使用此访问模式可在多个数据库或分片之间分布租户数据,其中,任一租户的所有数据包含在一个分片中。This access pattern allows tenant data to be distributed across multiple databases or shards, where all the data for any one tenant is contained in one shard. 将分片模型与多租户数据库模式相结合可以实现几乎无限的规模。Combined with a multi-tenant database pattern, a sharded model allows almost limitless scale.

设计包含分片多租户数据库的多租户应用。Design of multi-tenant app with sharded multi-tenant databases.

管理分片Manage shards

分片增大了设计和操作管理的复杂性。Sharding adds complexity both to the design and operational management. 需要在目录中维护租户与数据库之间的映射。A catalog is required in which to maintain the mapping between tenants and databases. 此外,需要执行管理过程来管理分片和租户填充。In addition, management procedures are required to manage the shards and the tenant population. 例如,必须设计相应的过程来添加和删除分片,以及在分片之间移动租户数据。For example, procedures must be designed to add and remove shards, and to move tenant data between shards. 一种缩放方式是添加一个新分片并在其中填充新租户。One way to scale is to by adding a new shard and populating it with new tenants. 在其他时候,可将密集填充的分片拆分成两个不太密实的分片。At other times you might split a densely populated shard into two less-densely populated shards. 移动或停用多个租户后,可将稀疏填充的分片合并在一起。After several tenants have been moved or discontinued, you might merge sparsely populated shards together. 合并会导致资源利用变得更加经济高效。The merge would result in more cost-efficient resource utilization. 还可以在分片之间移动租户,以均衡工作负荷。Tenants might also be moved between shards to balance workloads.

SQL 数据库提供一个可与分片库和目录数据库结合使用的拆分/合并工具。SQL Database provides a split/merge tool that works in conjunction with the sharding library and the catalog database. 提供的应用可以拆分与合并分片,并可以在分片之间移动租户数据。The provided app can split and merge shards, and it can move tenant data between shards. 应用还会在执行这些操作期间维护目录,将受影响的租户标记为已脱机,然后移动这些租户。The app also maintains the catalog during these operations, marking affected tenants as offline prior to moving them. 移动后,应用会使用新映射再次更新目录,并将租户标记为已重新联机。After the move, the app updates the catalog again with the new mapping, and marking the tenant as back online.

小型数据库更易于管理Smaller databases more easily managed

通过在多个数据库之间分配租户,分片多租户解决方案可以生成更易于管理的小型数据库。By distributing tenants across multiple databases, the sharded multi-tenant solution results in smaller databases that are more easily managed. 例如,将特定的租户还原到以前的某个时间点现在涉及到从备份中还原单个小型数据库,而不是从包含所有租户的大型数据库中还原。For example, restoring a specific tenant to a prior point in time now involves restoring a single smaller database from a backup, rather than a larger database that contains all tenants. 可以选择数据库大小以及每个数据库的租户数,以均衡工作负荷与管理工作量。The database size, and number of tenants per database, can be chosen to balance the workload and the management efforts.

架构中的租户标识符Tenant identifier in the schema

根据所用的分片方法,可能需要对数据库架构施加更多的约束。Depending on the sharding approach used, additional constraints may be imposed on the database schema. SQL 数据库拆分/合并应用程序要求架构包含分片键,这通常是租户标识符。The SQL Database split/merge application requires that the schema includes the sharding key, which typically is the tenant identifier. 租户标识符是所有分片表的主键中的前导元素。The tenant identifier is the leading element in the primary key of all sharded tables. 租户标识符可让拆分/合并应用程序快速找到和移动与特定租户关联的数据。The tenant identifier enables the split/merge application to quickly locate and move data associated with a specific tenant.

分片的弹性池Elastic pool for shards

可将分片多租户数据库放在弹性池中。Sharded multi-tenant databases can be placed in elastic pools. 一般而言,在一个池中放置许多单租户数据库,与在少量多租户数据库中放置许多租户的经济高效性相当。In general, having many single-tenant databases in a pool is as cost efficient as having many tenants in a few multi-tenant databases. 当有大量的相对不活跃租户时,多租户数据库就很有优势。Multi-tenant databases are advantageous when there are a large number of relatively inactive tenants.

H.H. 混合分片多租户数据库模型Hybrid sharded multi-tenant database model

在混合模型中,所有数据库在其架构中包含租户标识符。In the hybrid model, all databases have the tenant identifier in their schema. 这些数据库都能存储多个租户,并且可以分片。The databases are all capable of storing more than one tenant, and the databases can be sharded. 因此,在架构的意义上,它们都是多租户数据库。So in the schema sense, they are all multi-tenant databases. 但实际上,其中一些数据库只包含一个租户。Yet in practice some of these databases contain only one tenant. 不管怎样,给定数据库中存储的租户数量不会对数据库架构造成影响。Regardless, the quantity of tenants stored in a given database has no effect on the database schema.

移动租户Move tenants around

随时可将特定的租户移到其自身的多租户数据库中。At any time, you can move a particular tenant to its own multi-tenant database. 也随时可以改变主意,将租户移回到包含多个租户的数据库中。And at any time, you can change your mind and move the tenant back to a database that contains multiple tenants. 此外,在预配新数据库时,还可将租户分配到新的单租户数据库中。You can also assign a tenant to new single-tenant database when you provision the new database.

当可识别的租户组的资源需求有很大差异时,混合模型的优势将很明显。The hybrid model shines when there are large differences between the resource needs of identifiable groups of tenants. 例如,假设无法向参与免费试用的租户提供与订阅租户相同的性能级别。For example, suppose that tenants participating in a free trial are not guaranteed the same high level of performance that subscribing tenants are. 策略可以是将处于免费试用阶段的租户存储在由所有免费试用租户共享的某个多租户数据库中。The policy might be for tenants in the free trial phase to be stored in a multi-tenant database that is shared among all the free trial tenants. 当某个免费试用租户订阅基本服务级别时,可将该租户移到可能包含更少租户的另一个多租户数据库中。When a free trial tenant subscribes to the basic service level, the tenant can be moved to another multi-tenant database that might have fewer tenants. 可将购买高级服务级别的订阅者移到其购得的新单租户数据库中。A subscriber that pays for the premium service level could be moved to its own new single-tenant database.

Pools

在此混合模型中,可将订阅者租户的单租户数据库放在资源池中,以减少每个租户的数据库成本。In this hybrid model, the single-tenant databases for subscriber tenants can be placed in resource pools to reduce database costs per tenant. “每个租户各有数据库”模型中也采用了这种做法。This is also done in the database-per-tenant model.

I.I. 租户模型的比较Tenancy models compared

下表汇总了主要租户模型之间的差异。The following table summarizes the differences between the main tenancy models.

度量Measurement 独立应用Standalone app 每个租户各有数据库Database-per-tenant 分片多租户Sharded multi-tenant
缩放Scale 中型Medium
1 到数百个1-100s
很高Very high
1 到数十万个1-100,000s
不受限制Unlimited
1 到数百万个1-1,000,000s
租户隔离Tenant isolation 很高Very high High 低;任何单一实例租户(即 MT 数据库中独立的租户)除外。Low; except for any singleton tenant (that is alone in an MT db).
每个租户的数据库成本Database cost per tenant 高;大小根据峰值而定。High; is sized for peaks. 低;使用池。Low; pools used. 最低,适用于 MT 数据库中的小租户。Lowest, for small tenants in MT DBs.
性能监视和管理Performance monitoring and management 仅限每租户Per-tenant only 聚合 + 每租户Aggregate + per-tenant 聚合;不过,对于单一实例,将应用“仅限每租户”模式。Aggregate; although is per-tenant only for singletons.
开发复杂性Development complexity Low Low 中等;受分片影响。Medium; due to sharding.
操作复杂性Operational complexity 低到高。Low-High. 单个操作较简单,大规模操作较复杂。Individually simple, complex at scale. 低到中等。Low-Medium. 模式可以解决大规模操作的复杂性。Patterns address complexity at scale. 低到高。Low-High. 单个租户的管理比较复杂。Individual tenant management is complex.
 

后续步骤Next steps