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

表存储的性能与可伸缩性查检表Performance and scalability checklist for Table storage

Microsoft 为开发使用表存储的高性能应用程序制定了许多经过证实的做法。Microsoft has developed a number of proven practices for developing high-performance applications with Table storage. 此查检表列出了开发人员在优化性能时可以遵循的关键做法。This checklist identifies key practices that developers can follow to optimize performance. 在设计应用程序时以及在整个流程中,请牢记这些做法。Keep these practices in mind while you are designing your application and throughout the process.

Azure 存储在容量、事务速率和带宽方面存在可伸缩性与性能目标。Azure Storage has scalability and performance targets for capacity, transaction rate, and bandwidth. 有关 Azure 存储可伸缩性目标的详细信息,请参阅标准存储帐户的可伸缩性和性能目标表存储的可伸缩性和性能目标For more information about Azure Storage scalability targets, see Scalability and performance targets for standard storage accounts and Scalability and performance targets for Table storage.

清单Checklist

本文以查检表的形式组织了在开发表存储应用程序时在性能方面可以遵循的经过证实的做法。This article organizes proven practices for performance into a checklist you can follow while developing your Table storage application.

完成Done 类别Category 设计注意事项Design consideration
  可伸缩性目标Scalability targets 是否可将应用程序设计为避免使用的存储帐户数超过最大数目?Can you design your application to use no more than the maximum number of storage accounts?
  可伸缩性目标Scalability targets 是否要避免接近容量和事务限制?Are you avoiding approaching capacity and transaction limits?
  可伸缩性目标Scalability targets 是否在接近实体数/秒的可伸缩性目标?Are you approaching the scalability targets for entities per second?
  网络Networking 客户端设备是否具有足够高的带宽和足够低的延迟,以实现所需的性能?Do client-side devices have sufficiently high bandwidth and low latency to achieve the performance needed?
  网络Networking 客户端设备是否具有优质网络链接?Do client-side devices have a high quality network link?
  网络Networking 客户端应用程序是否位于存储帐户所在的同一区域?Is the client application in the same region as the storage account?
  直接客户端访问Direct Client Access 是否使用共享访问签名 (SAS) 和跨源资源共享 (CORS) 来实现对 Azure 存储的直接访问?Are you using shared access signatures (SAS) and cross-origin resource sharing (CORS) to enable direct access to Azure Storage?
  批处理Batching 应用程序是否使用实体组事务来批处理更新?Is your application batching updates by using entity group transactions?
  .NET 配置.NET configuration 是否使用 .NET Core 2.1 或更高版本来实现最佳性能?Are you using .NET Core 2.1 or later for optimum performance?
  .NET 配置.NET configuration 是否已将客户端配置为使用足够数量的并发连接?Have you configured your client to use a sufficient number of concurrent connections?
  .NET 配置.NET configuration 对于 .NET 应用程序,是否已将 .NET 配置为使用足够数量的线程?For .NET applications, have you configured .NET to use a sufficient number of threads?
  并行度Parallelism 是否能够确保对并行度进行适当的界定,使客户端功能不会过载或接近可伸缩性目标?Have you ensured that parallelism is bounded appropriately so that you don't overload your client's capabilities or approach the scalability targets?
  工具Tools 是否使用 Microsoft 提供的最新版客户端库和工具?Are you using the latest versions of Microsoft-provided client libraries and tools?
  重试Retries 是否对限制错误和超时使用重试策略和指数退避?Are you using a retry policy with an exponential backoff for throttling errors and timeouts?
  重试Retries 对于不可重试的错误,应用程序是否会避免重试?Is your application avoiding retries for non-retryable errors?
  配置Configuration 是否使用 JSON 进行表请求?Are you using JSON for your table requests?
  配置Configuration 是否已关闭 Nagle 算法以改进小型请求的性能?Have you turned off the Nagle algorithm to improve the performance of small requests?
  表和分区Tables and partitions 是否已对数据进行了适当的分区?Have you properly partitioned your data?
  热分区Hot partitions 是否会避免使用仅追加和仅预置模式?Are you avoiding append-only and prepend-only patterns?
  热分区Hot partitions 插入/更新的内容是否会分布在多个分区中?Are your inserts/updates spread across many partitions?
  查询范围Query scope 是否已将架构设计为允许在大多数情况下使用点查询,尽量少用表查询?Have you designed your schema to allow for point queries to be used in most cases, and table queries to be used sparingly?
  查询密度Query density 查询是否通常只扫描和返回应用程序会使用的行?Do your queries typically only scan and return rows that your application will use?
  限制返回的数据Limiting returned data 是否使用筛选来避免返回不需要的实体?Are you using filtering to avoid returning entities that are not needed?
  限制返回的数据Limiting returned data 是否使用投影来避免返回不需要的属性?Are you using projection to avoid returning properties that are not needed?
  非规范化Denormalization 是否已对数据实施非规范化,以此避免在尝试获取数据时无效的查询或多次读取请求?Have you denormalized your data such that you avoid inefficient queries or multiple read requests when trying to get data?
  插入、更新和删除Insert, update, and delete 是否会对需要进行事务处理或可以同时完成的请求进行批处理,以此减少不必要的重复操作?Are you batching requests that need to be transactional or can be done at the same time to reduce round-trips?
  插入、更新和删除Insert, update, and delete 是否会避免仅仅为了确定是否需要调用插入或更新而检索某个实体?Are you avoiding retrieving an entity just to determine whether to call insert or update?
  插入、更新和删除Insert, update, and delete 是否考虑过将各种需要频繁检索的数据作为属性一起存储在单个实体中而非多个实体中?Have you considered storing series of data that will frequently be retrieved together in a single entity as properties instead of multiple entities?
  插入、更新和删除Insert, update, and delete 对于那些始终需要一起检索并可成批写入的实体(例如时序数据),是否考虑过使用 Blob 而非表?For entities that will always be retrieved together and can be written in batches (for example, time series data), have you considered using blobs instead of tables?

可伸缩性目标Scalability targets

如果应用程序接近或超过任何可伸缩性目标,则可能会出现事务处理延迟或限制越来越严重的现象。If your application approaches or exceeds any of the scalability targets, it may encounter increased transaction latencies or throttling. 当 Azure 存储对应用程序进行限制时,该服务将开始返回 503(服务器繁忙)或 500(操作超时)错误代码。When Azure Storage throttles your application, the service begins to return 503 (Server busy) or 500 (Operation timeout) error codes. 保持在可伸缩性目标限制范围内,以避免这些错误,是增强应用程序性能的重要组成部分。Avoiding these errors by staying within the limits of the scalability targets is an important part of enhancing your application's performance.

有关表服务的可伸缩性目标的详细信息,请参阅表存储的可伸缩性和性能目标For more information about scalability targets for the Table service, see Scalability and performance targets for Table storage.

最大存储帐户数Maximum number of storage accounts

如果即将达到特定订阅/区域组合允许的最大存储帐户数,你是否会使用多个存储帐户进行分片,以增加流入量、流出量、每秒 I/O 操作次数 (IOPS) 或容量?If you're approaching the maximum number of storage accounts permitted for a particular subscription/region combination, are you using multiple storage accounts to shard to increase ingress, egress, I/O operations per second (IOPS), or capacity? 对于这种情况,Microsoft 建议在可能的情况下,利用存储帐户的更高限制来减少工作负荷所需的存储帐户数。In this scenario, Microsoft recommends that you take advantage of increased limits for storage accounts to reduce the number of storage accounts required for your workload if possible. 若要请求提高存储帐户的限制,请联系 Azure 支持部门Contact Azure Support to request increased limits for your storage account. 有关详细信息,请参阅宣布推出更大容量和规模的存储帐户For more information, see Announcing larger, higher scale storage accounts.

容量和事务目标Capacity and transaction targets

如果应用程序正接近单个存储帐户的可伸缩性目标,可考虑采用以下方法之一:If your application is approaching the scalability targets for a single storage account, consider adopting one of the following approaches:

  • 重新考虑导致应用程序接近或超过可伸缩性目标的工作负载。Reconsider the workload that causes your application to approach or exceed the scalability target. 能否对其进行另外的设计,以便使用较少的带宽、容量或处理事务?Can you design it differently to use less bandwidth or capacity, or fewer transactions?
  • 如果应用程序肯定会超出伸缩性目标之一,请创建多个存储帐户并将应用程序数据跨多个这样的存储帐户进行分区。If your application must exceed one of the scalability targets, then create multiple storage accounts and partition your application data across those multiple storage accounts. 如果使用这种模式,则在设计应用程序时,必须确保能够在以后添加更多的存储帐户,以便进行负载均衡。If you use this pattern, then be sure to design your application so that you can add more storage accounts in the future for load balancing. 存储帐户本身除了用于数据存储、事务处理或数据传输之外,并无其他开销。Storage accounts themselves have no cost other than your usage in terms of data stored, transactions made, or data transferred.
  • 如果应用程序接近带宽目标,请考虑压缩客户端的数据,以减少将数据发送到 Azure 存储所需的带宽。If your application is approaching the bandwidth targets, consider compressing data on the client side to reduce the bandwidth required to send the data to Azure Storage. 压缩数据虽然可以节省带宽并提高网络性能,但也可能会对性能带来负面影响。While compressing data may save bandwidth and improve network performance, it can also have negative effects on performance. 评估客户端数据压缩和解压缩的额外处理要求对性能造成的影响。Evaluate the performance impact of the additional processing requirements for data compression and decompression on the client side. 请记住,存储压缩数据可能会使故障排除变得更复杂,因为使用标准工具查看这些数据可能会更困难。Keep in mind that storing compressed data can make troubleshooting more difficult because it may be more challenging to view the data using standard tools.
  • 如果应用程序接近可伸缩性目标,请确保对重试使用指数退避。If your application is approaching the scalability targets, then make sure that you are using an exponential backoff for retries. 最好是尝试通过实施本文中所述的建议来避免达到可伸缩性目标。It's best to try to avoid reaching the scalability targets by implementing the recommendations described in this article. 但是,对重试使用指数退避会导致应用程序无法快速重试,从而导致限制问题恶化。However, using an exponential backoff for retries will prevent your application from retrying rapidly, which could make throttling worse. 有关详细信息,请参阅标题为超时和服务器繁忙错误的部分。For more information, see the section titled Timeout and Server Busy errors.

数据操作的目标Targets for data operations

Azure 存储会在存储帐户流量增加时进行负载均衡,但如果流量突然增加,则可能无法立即获得此吞吐量。Azure Storage load balances as the traffic to your storage account increases, but if the traffic exhibits sudden bursts, you may not be able to get this volume of throughput immediately. 在激增期间会出现限制和/或超时现象,因为 Azure 存储会自动对表进行负载均衡。Expect to see throttling and/or timeouts during the burst as Azure Storage automatically load balances your table. 让流量缓慢增加通常会有更好的效果,因为系统有时间进行适当的负载均衡。Ramping up slowly generally provides better results, as the system has time to load balance appropriately.

实体数/秒(存储帐户)Entities per second (storage account)

对于单个帐户来说,访问表时的可伸缩性限制高达每秒 20,000 个实体(每个实体 1 KB)。The scalability limit for accessing tables is up to 20,000 entities (1 KB each) per second for an account. 一般情况下,每个插入、更新、删除或扫描的实体都会计入此目标的计数。In general, each entity that is inserted, updated, deleted, or scanned counts toward this target. 因此,包含 100 个实体的批量插入计为 100 个实体。So a batch insert that contains 100 entities would count as 100 entities. 一个查询扫描了 1000 个实体但只返回 5 个,则会将其计为 1000 个实体。A query that scans 1000 entities and returns 5 would count as 1000 entities.

实体数/秒(分区)Entities per second (partition)

在单个分区中,访问表时的可伸缩性目标为每秒 2,000 个实体(每个实体 1 KB),使用前面部分所述的相同计数方法。Within a single partition, the scalability target for accessing tables is 2,000 entities (1 KB each) per second, using the same counting as described in the previous section.

网络Networking

物理网络对应用程序的约束可能会严重影响性能。The physical network constraints of the application may have a significant impact on performance. 以下部分描述了用户可能会遇到的某些限制。The following sections describe some of limitations users may encounter.

客户端网络功能Client network capability

如以下各部分所述,网络链接的带宽和质量在应用程序性能方面发挥着重要作用。Bandwidth and the quality of the network link play important roles in application performance, as described in the following sections.

吞吐量Throughput

通常情况下,对带宽来说,问题在于客户端的功能。For bandwidth, the problem is often the capabilities of the client. 较大的 Azure 实例的 NIC 具有较大的容量,因此如果需要提高单个计算机的网络限制,则应考虑使用较大的实例或更多 VM。Larger Azure instances have NICs with greater capacity, so you should consider using a larger instance or more VMs if you need higher network limits from a single machine. 如果从本地应用程序访问 Azure 存储,可应用相同的规则:了解客户端设备的网络功能以及与 Azure 存储位置的网络连接情况,然后根据需要对其进行改进,或者将应用程序设计为可在这种网络功能下工作。If you are accessing Azure Storage from an on premises application, then the same rule applies: understand the network capabilities of the client device and the network connectivity to the Azure Storage location and either improve them as needed or design your application to work within their capabilities.

请注意,因错误和数据包丢失而导致的网络状况会降低有效吞吐量,使用任何网络都是这样。As with any network usage, keep in mind that network conditions resulting in errors and packet loss will slow effective throughput. WireShark 或 NetMon 可用于诊断此问题。Using WireShark or NetMon may help in diagnosing this issue.

位置Location

在任何分布式环境中,将客户端放置在服务器附近可提供最佳性能。In any distributed environment, placing the client near to the server delivers in the best performance. 要以最低的延迟访问 Azure 存储,则最好是将客户端放置在同一 Azure 区域内。For accessing Azure Storage with the lowest latency, the best location for your client is within the same Azure region. 例如,如果 Azure Web 应用使用 Azure 存储,请将二者放在同一个区域(例如美国西部或东南亚)。For example, if you have an Azure web app that uses Azure Storage, then locate them both within a single region, such as US West or Asia Southeast. 将资源放到一起可降低延迟和成本,因为在同一个区域使用带宽是免费的。Co-locating resources reduces the latency and the cost, as bandwidth usage within a single region is free.

如果客户端应用程序要访问 Azure 存储但不是托管在 Azure 中(例如移动设备应用或本地企业服务),则将存储帐户放在靠近这些客户端的区域可降低延迟。If client applications will access Azure Storage but are not hosted within Azure, such as mobile device apps or on premises enterprise services, then locating the storage account in a region near to those clients may reduce latency. 如果客户端广泛分布在各地(例如,有些客户端分布在北美,有些则在欧洲),请考虑在每个区域使用一个存储帐户。If your clients are broadly distributed (for example, some in North America, and some in Europe), then consider using one storage account per region. 如果应用程序存储的数据是特定于各个用户的,不需要在存储帐户之间复制数据,则此方法更容易实施。This approach is easier to implement if the data the application stores is specific to individual users, and does not require replicating data between storage accounts.

SAS 和 CORSSAS and CORS

假设你需要授权用户 Web 浏览器或手机应用中运行的代码(例如 JavaScript)访问 Azure 存储中的数据。Suppose that you need to authorize code such as JavaScript that is running in a user's web browser or in a mobile phone app to access data in Azure Storage. 一种方法是构建充当代理的服务应用程序。One approach is to build a service application that acts as a proxy. 用户的设备将对服务进行身份验证,而后者又可授权访问 Azure 存储资源。The user's device authenticates with the service, which in turn authorizes access to Azure Storage resources. 这样,就可以避免在不安全的设备上公开存储帐户密钥。In this way, you can avoid exposing your storage account keys on insecure devices. 但是,此方法会明显增大服务应用程序的开销,因为在用户设备与 Azure 存储之间传输的所有数据必须通过服务应用程序。However, this approach places a significant overhead on the service application, because all of the data transferred between the user's device and Azure Storage must pass through the service application.

使用共享访问签名 (SAS) 即可避免将服务应用程序用作 Azure 存储的代理。You can avoid using a service application as a proxy for Azure Storage by using shared access signatures (SAS). 使用 SAS 可让用户设备通过受限访问令牌直接对 Azure 存储发出请求。Using SAS, you can enable your user's device to make requests directly to Azure Storage by using a limited access token. 例如,如果用户想要将照片上传到应用程序,则服务应用程序可以生成 SAS 并将其发送到用户的设备。For example, if a user wants to upload a photo to your application, then your service application can generate a SAS and send it to the user's device. SAS 令牌可按指定的时间间隔授予写入 Azure 存储资源的权限,该时间过后,SAS 令牌将会过期。The SAS token can grant permission to write to an Azure Storage resource for a specified interval of time, after which the SAS token expires. 有关 SAS 的详细信息,请参阅使用共享访问签名 (SAS) 授予对 Azure 存储资源的有限访问权限For more information about SAS, see Grant limited access to Azure Storage resources using shared access signatures (SAS).

通常,Web 浏览器不允许某个域上的网站所托管的页面中的 JavaScript 对另一个域执行某些操作(例如写入操作)。Typically, a web browser will not allow JavaScript in a page that is hosted by a website on one domain to perform certain operations, such as write operations, to another domain. 此策略称为同源策略,可防止一个页面上的恶意脚本获取另一网页上的数据的访问权限。Known as the same-origin policy, this policy prevents a malicious script on one page from obtaining access to data on another web page. 但是,在云中构建解决方案时,同源策略可能会成为一种限制。However, the same-origin policy can be a limitation when building a solution in the cloud. 跨源资源共享 (CORS) 是一种浏览器功能,它使目标域能够与信任源自源域的请求的浏览器通信。Cross-origin resource sharing (CORS) is a browser feature that enables the target domain to communicate to the browser that it trusts requests originating in the source domain.

例如,假设 Azure 中运行的某个 Web 应用程序对 Azure 存储帐户发出了某个资源请求。For example, suppose a web application running in Azure makes a request for a resource to an Azure Storage account. 该 Web 应用程序是源域,存储帐户是目标域。The web application is the source domain, and the storage account is the target domain. 可为任何 Azure 存储服务配置 CORS,以便与从 Azure 存储信任的源域发出请求的 Web 浏览器通信。You can configure CORS for any of the Azure Storage services to communicate to the web browser that requests from the source domain are trusted by Azure Storage. 有关 CORS 的详细信息,请参阅 Azure 存储的跨源资源共享 (CORS) 支持For more information about CORS, see Cross-origin resource sharing (CORS) support for Azure Storage.

SAS 和 CORS 都有助于避免 Web 应用程序上出现不必要的负载。Both SAS and CORS can help you avoid unnecessary load on your web application.

批处理事务Batch transactions

表服务支持对位于同一个表中的属于同一分区组的实体执行事务批处理。The Table service supports batch transactions on entities that are in the same table and belong to the same partition group. 有关详细信息,请参阅执行实体组事务For more information, see Performing entity group transactions.

.NET 配置.NET configuration

如果使用的是 .NET Framework,则本部分列出的数种快速配置设置可以用于显著提高性能。If using the .NET Framework, this section lists several quick configuration settings that you can use to make significant performance improvements. 如果使用其他语言,则需查看类似的概念是否适用于所选择的语言。If using other languages, check to see if similar concepts apply in your chosen language.

使用 .NET CoreUse .NET Core

使用 .NET Core 2.1 或更高版本开发 Azure 存储应用程序,以利用性能增强功能。Develop your Azure Storage applications with .NET Core 2.1 or later to take advantage of performance enhancements. 建议尽量使用 .NET Core 3.x。Using .NET Core 3.x is recommended when possible.

有关 .NET Core 的性能改进的详细信息,请参阅以下博客文章:For more information on performance improvements in .NET Core, see the following blog posts:

提高默认连接限制Increase default connection limit

在 .NET 中,以下代码可将默认的连接限制(通常情况下,在客户端环境中为 2,在服务器环境中为 10)提高到 100。In .NET, the following code increases the default connection limit (which is usually 2 in a client environment or 10 in a server environment) to 100. 通常情况下,应将值大致设置为应用程序使用的线程数。Typically, you should set the value to approximately the number of threads used by your application.

ServicePointManager.DefaultConnectionLimit = 100; //(Or More)  

在打开任何连接前设置连接限制。Set the connection limit before opening any connections.

对于其他编程语言,请参阅该语言的文档以确定如何设置连接限制。For other programming languages, see that language's documentation to determine how to set the connection limit.

有关详细信息,请参阅博客文章 Web 服务:并发连接For more information, see the blog post Web Services: Concurrent Connections.

增大最小线程数Increase minimum number of threads

如果结合异步任务使用同步调用,可能需要增大线程池中的线程数:If you are using synchronous calls together with asynchronous tasks, you may want to increase the number of threads in the thread pool:

ThreadPool.SetMinThreads(100,100); //(Determine the right number for your application)  

有关详细信息,请参阅 ThreadPool.SetMinThreads 方法。For more information, see the ThreadPool.SetMinThreads method.

不受限制的并行度Unbounded parallelism

虽然并行度有助于提高性能,但在使用不受限制的并行度时应保持谨慎,因为这意味着对线程数或并行请求数没有限制。While parallelism can be great for performance, be careful about using unbounded parallelism, meaning that there is no limit enforced on the number of threads or parallel requests. 请务必限制上传或下载数据、访问同一存储帐户中的多个分区以及访问同一分区中的多个项的并行请求。Be sure to limit parallel requests to upload or download data, to access multiple partitions in the same storage account, or to access multiple items in the same partition. 如果并行度不受限制,应用程序则可能会超出客户端设备的承受程度或超出存储帐户的可伸缩性目标,导致延迟和限制时间增长。If parallelism is unbounded, your application can exceed the client device's capabilities or the storage account's scalability targets, resulting in longer latencies and throttling.

客户端库和工具Client libraries and tools

为获得最佳性能,请始终使用 Microsoft 提供的最新客户端库和工具。For best performance, always use the latest client libraries and tools provided by Microsoft. Azure 存储客户端库适用于各种语言。Azure Storage client libraries are available for a variety of languages. Azure 存储还支持 PowerShell 和 Azure CLI。Azure Storage also supports PowerShell and Azure CLI. Microsoft 正在积极开发这些客户端库和工具,并注重其性能,使用最新服务版本对其进行更新,确保这些工具可以在内部协调好许多经过证实的做法。Microsoft actively develops these client libraries and tools with performance in mind, keeps them up-to-date with the latest service versions, and ensures that they handle many of the proven performance practices internally.

处理服务错误Handle service errors

当服务无法处理请求时,Azure 存储会返回错误。Azure Storage returns an error when the service cannot process a request. 了解 Azure 存储在特定情况下可能返回的错误将有助于优化性能。Understanding the errors that may be returned by Azure Storage in a given scenario is helpful for optimizing performance.

超时和服务器繁忙错误Timeout and Server Busy errors

如果应用程序即将达到可伸缩性限制,Azure 存储可能会对其进行限制。Azure Storage may throttle your application if it approaches the scalability limits. 在某些情况下,Azure 存储可能会出于某种暂时性的状况而无法处理请求。In some cases, Azure Storage may be unable to handle a request due to some transient condition. 对于这两种情况,服务可能返回 503(服务器繁忙)或 500(超时)错误。In both cases, the service may return a 503 (Server Busy) or 500 (Timeout) error. 如果服务正在对数据分区进行重新均衡以提高吞吐量,则也可能会发生这些错误。These errors can also occur if the service is rebalancing data partitions to allow for higher throughput. 通常,客户端应用程序应重试导致上述某种错误的操作。The client application should typically retry the operation that causes one of these errors. 但是,如果 Azure 存储因为应用程序即将超出可伸缩性目标而限制应用程序,或者其他某种原因导致服务无法为请求提供服务,则过于频繁的重试可能会使问题变得更糟。However, if Azure Storage is throttling your application because it is exceeding scalability targets, or even if the service was unable to serve the request for some other reason, aggressive retries may make the problem worse. 建议使用指数退避重试策略,客户端库默认采用此行为。Using an exponential back off retry policy is recommended, and the client libraries default to this behavior. 例如,应用程序可能会在 2 秒后、4 秒后、10 秒后,以及 30 秒后进行重试,最后彻底放弃重试。For example, your application may retry after 2 seconds, then 4 seconds, then 10 seconds, then 30 seconds, and then give up completely. 这样,应用程序可明显减少其在服务中施加的负载,而不会使得导致出现限制的行为恶化。In this way, your application significantly reduces its load on the service, rather than exacerbating behavior that could lead to throttling.

连接错误可以立即重试,因为它不是限制造成的,而且应该是暂时性的。Connectivity errors can be retried immediately, because they are not the result of throttling and are expected to be transient.

不可重试的错误Non-retryable errors

客户端库将处理重试,同时能够识别哪些错误可重试,哪些不可重试。The client libraries handle retries with an awareness of which errors can be retried and which cannot. 但是,如果直接调用 Azure 存储 REST API,则不应重试某些错误。However, if you are calling the Azure Storage REST API directly, there are some errors that you should not retry. 例如,400(错误的请求)错误表示客户端应用程序发送了一个无法处理的请求(因为该请求未采用预期的格式)。For example, a 400 (Bad Request) error indicates that the client application sent a request that could not be processed because it was not in the expected form. 每次重新发送此请求都会导致相同的响应,因此没有必要重试。Resending this request results the same response every time, so there is no point in retrying it. 如果直接调用 Azure 存储 REST API,请注意潜在错误以及是否应重试这些错误。If you are calling the Azure Storage REST API directly, be aware of potential errors and whether they should be retried.

有关 Azure 存储错误代码的详细信息,请参阅状态和错误代码For more information on Azure Storage error codes, see Status and error codes.

配置Configuration

本部分列出了多个快速配置设置,可以使用这些设置显著提高表服务的性能:This section lists several quick configuration settings that you can use to make significant performance improvements in the Table service:

使用 JSONUse JSON

从存储服务 2013-08-15 版开始,表服务就支持使用 JSON 而非基于 XML 的 AtomPub 格式来传输表数据。Beginning with storage service version 2013-08-15, the Table service supports using JSON instead of the XML-based AtomPub format for transferring table data. 使用 JSON 最多可以减少 75% 的有效负载大小,并可以显著提高应用程序的性能。Using JSON can reduce payload sizes by as much as 75% and can significantly improve the performance of your application.

有关详细信息,请参阅文章 Microsoft Azure Tables: Introducing JSON(Microsoft Azure 表:JSON 简介)和 Payload Format for Table Service Operations(表服务操作的有效负载格式)。For more information, see the post Microsoft Azure Tables: Introducing JSON and Payload Format for Table Service Operations.

禁用 NagleDisable Nagle

Nagle 的算法已跨 TCP/IP 网络进行了广泛的实施,是一种改进网络性能的方法。Nagle's algorithm is widely implemented across TCP/IP networks as a means to improve network performance. 不过,该方法并非适用于所有情况(例如高度交互式的环境)。However, it is not optimal in all circumstances (such as highly interactive environments). Nagle 的算法会对 Azure 表服务请求的性能造成负面影响,因此应尽量将其禁用。Nagle's algorithm has a negative impact on the performance of requests to the Azure Table service, and you should disable it if possible.

架构Schema

数据的呈现和查询方式是影响表服务性能的单个最大因素。How you represent and query your data is the biggest single factor that affects the performance of the Table service. 虽然每个应用程序都不同,但本部分仍概要列出了一些通用的经过验证的做法,这些做法适用于:While every application is different, this section outlines some general proven practices that relate to:

  • 表设计Table design
  • 高效的查询Efficient queries
  • 高效的数据更新Efficient data updates

表和分区Tables and partitions

表划分为分区。Tables are divided into partitions. 存储在分区中的每个实体共享相同的分区键,并具有唯一的行键,用于在该分区中标识自己。Every entity stored in a partition shares the same partition key and has a unique row key to identify it within that partition. 分区具有好处,但也带来了可伸缩性限制。Partitions provide benefits but also introduce scalability limits.

  • 好处:可以在同一个分区中更新单个事务、原子事务和批处理事务的实体,每种事务最多包含 100 个单独的存储操作(总大小限制为 4 MB)。Benefits: You can update entities in the same partition in a single, atomic, batch transaction that contains up to 100 separate storage operations (limit of 4 MB total size). 此外,假定需要检索相同数量的实体,则在单个分区中查询数据要比跨多个分区查询数据更高效(不过,如果需要查询表数据,则请继续阅读以获取更进一步的建议)。Assuming the same number of entities to be retrieved, you can also query data within a single partition more efficiently than data that spans partitions (though read on for further recommendations on querying table data).
  • 可伸缩性限制:对存储在单个分区中的实体的访问不能进行负载均衡,因为分区支持原子批处理事务。Scalability limit: Access to entities stored in a single partition cannot be load-balanced because partitions support atomic batch transactions. 因此,总体说来单个表分区的可伸缩性目标低于表服务的相应目标。For this reason, the scalability target for an individual table partition is lower than for the Table service as a whole.

考虑到表和分区的这些特点,应该采用以下设计原则:Because of these characteristics of tables and partitions, you should adopt the following design principles:

  • 将客户端应用程序频繁更新或查询的数据放到同一分区中的同一工作逻辑单元。Locate data that your client application frequently updates or queries in the same logical unit of work in the same partition. 例如,如果应用程序要聚合写入或者你要执行原子批处理操作,请将数据放到同一分区。For example, locate data in the same partition if your application is aggregating writes or you are performing atomic batch operations. 此外,与跨分区的数据相比,可以更高效地对单个分区中的数据进行查询。Also, data in a single partition can be more efficiently queried in a single query than data across partitions.
  • 将客户端应用程序不会插入、更新或查询的数据放到不同分区中的同一工作逻辑单元(即,单个查询或批量更新)。Locate data that your client application does not insert, update, or query in the same logical unit of work (that is, in a single query or batch update) in separate partitions. 请记住,单个表中的分区键没有数量限制,因此即使设置数百万个分区键也不是问题,也不会影响性能。Keep in mind that there is no limit to the number of partition keys in a single table, so having millions of partition keys is not a problem and will not impact performance. 例如,如果应用程序是一个需要用户登录的热门网站,不妨使用用户 ID 作为分区键。For example, if your application is a popular website with user login, using the User ID as the partition key could be a good choice.

热分区Hot partitions

热分区是指这样一种分区,即收到了某个帐户的过多流量,但又无法对其进行负载均衡,因为该分区为单个分区。A hot partition is one that is receiving a disproportionate percentage of the traffic to an account, and cannot be load balanced because it is a single partition. 一般情况下,热分区的创建有以下两种模式:In general, hot partitions are created one of two ways:

“仅追加”和“仅预置”模式Append Only and Prepend Only patterns

“仅追加”模式是指流向某个给定分区键的所有(或几乎所有)流量都会按当前时间增加或减少。The "Append Only" pattern is one where all (or nearly all) of the traffic to a given partition key increases and decreases according to the current time. 例如,假设应用程序使用当前日期作为日志数据的分区键。For example, suppose that your application uses the current date as a partition key for log data. 此设计会导致所有插入内容进入表中的最后一个分区,并且系统无法正确地进行负载均衡。This design results in all of the inserts going to the last partition in your table, and the system cannot load balance properly. 如果进入该分区的流量超出分区级的可伸缩性目标,则会导致限制。If the volume of traffic to that partition exceeds the partition-level scalability target, then it will result in throttling. 最好是确保将流量发送到多个分区,以便对跨表请求进行负载均衡。It's better to ensure that traffic is sent to multiple partitions, to enable load balance the requests across your table.

高流量数据High-traffic data

如果分区方案导致单个分区的数据较其他分区的数据使用更为频繁,则也可能会看到限制现象,因为该分区达到了单个分区的可伸缩性目标。If your partitioning scheme results in a single partition that just has data that is far more used than other partitions, you may also see throttling as that partition approaches the scalability target for a single partition. 最好是确保分区方案不会导致单个分区接近可伸缩性目标。It's better to make sure that your partition scheme results in no single partition approaching the scalability targets.

查询Querying

本部分介绍有关查询表服务的经过证实的做法。This section describes proven practices for querying the Table service.

查询范围Query scope

有多种方式可指定需要查询的实体的范围。There are several ways to specify the range of entities to query. 以下列表描述了查询范围的每个选项。The following list describes each option for query scope.

  • 点查询: 点查询会同时指定要检索的实体的分区键和行键,因此可确切地检索到一个实体。Point queries:- A point query retrieves exactly one entity by specifying both the partition key and row key of the entity to retrieve. 此类查询非常高效,应尽可能使用。These queries are efficient, and you should use them wherever possible.
  • 分区查询: 分区查询用于检索共享分区键的一组数据。Partition queries: A partition query is a query that retrieves a set of data that shares a common partition key. 通常情况下,该查询会指定一系列行键值或者一系列用于某些实体属性和分区键的值。Typically, the query specifies a range of row key values or a range of values for some entity property in addition to a partition key. 这些查询效率不如点查询,应谨慎使用。These queries are less efficient than point queries, and should be used sparingly.
  • 表查询: 表查询用于检索没有共享分区键的一组实体。Table queries: A table query is a query that retrieves a set of entities that does not share a common partition key. 此类查询效率不高,应尽可能避免使用。These queries are not efficient and you should avoid them if possible.

通常情况下,应避免进行扫描(大于单个实体的查询),但如果必须要进行扫描,则应尝试对数据进行组织,使扫描仅检索所需数据,避免扫描或返回大量不需要的实体。In general, avoid scans (queries larger than a single entity), but if you must scan, try to organize your data so that your scans retrieve the data you need without scanning or returning significant amounts of entities you don't need.

查询密度Query density

影响查询效率的另一关键因素是返回的实体数与查找返回的集合时扫描过的实体数的比率。Another key factor in query efficiency is the number of entities returned as compared to the number of entities scanned to find the returned set. 如果应用程序在执行表查询时使用了某个属性值的筛选器,而该属性值仅供 1% 的数据共享,则该查询需要扫描 100 个实体才会返回 1 个实体。If your application performs a table query with a filter for a property value that only 1% of the data shares, the query will scan 100 entities for every one entity it returns. 前面讨论的表可伸缩性目标均与所扫描的实体数相关,与返回的实体数无关:查询密度低很容易导致表服务限制应用程序,因为表服务在检索要查找的实体时需要扫描的实体过多。The table scalability targets discussed previously all relate to the number of entities scanned, and not the number of entities returned: a low query density can easily cause the Table service to throttle your application because it must scan so many entities to retrieve the entity you are looking for. 有关如何避免限制的详细信息,请参阅标题为反规范化的部分。For more information on how to avoid throttling, see the section titled Denormalization.

限制返回的数据量Limiting the amount of data returned

如果知道某个查询将要返回的实体并不是客户端应用程序所需要的,则应考虑使用筛选器来减少返回的集合的大小。When you know that a query will return entities that you don't need in the client application, consider using a filter to reduce the size of the returned set. 虽然没有返回到客户端的实体仍会计入可伸缩性限制,但应用程序的性能会提高,因为网络负载大小会下降,同时客户端应用程序必须处理的实体数会下降。While the entities not returned to the client still count toward the scalability limits, your application performance will improve because of the reduced network payload size and the reduced number of entities that your client application must process. 请记住,可伸缩性目标与扫描的实体数相关,因此查询在筛选掉许多实体后仍可能导致限制,即使返回很少的实体。Keep in mind that the scalability targets relate to the number of entities scanned, so a query that filters out many entities may still result in throttling, even if few entities are returned. 有关提高查询效率的详细信息,请参阅标题为查询密度的部分。For more information on making queries efficient, see the section titled Query density.

如果客户端应用程序只需表中实体提供的一组有限的属性,则可以使用投影来限制所返回数据集的大小。If your client application needs only a limited set of properties from the entities in your table, you can use projection to limit the size of the returned data set. 就像使用筛选一样,投影有助于减少网络负载和客户端处理。As with filtering, projection helps to reduce network load and client processing.

非规范化Denormalization

与使用关系数据库不同,根据经过验证的做法,若要提高表数据的查询效率,需对数据进行非规范化。Unlike working with relational databases, the proven practices for efficiently querying table data lead to denormalizing your data. 也就是说,需要将相同的数据复制到多个实体中(一个实体对应一个用于查找数据的键)以尽量降低查询在查找客户端所需数据时必须扫描的实体数,这样就不必扫描大量实体来查找应用程序需要的数据。That is, duplicating the same data in multiple entities (one for each key you may use to find the data) to minimize the number of entities that a query must scan to find the data the client needs, rather than having to scan large numbers of entities to find the data your application needs. 例如,在电子商务网站中,可能希望通过两种方式查找订单:按客户 ID(供此客户的订单)和按日期(提供某个日期的订单)。For example, in an e-commerce website, you may want to find an order both by the customer ID (give me this customer's orders) and by the date (give me orders on a date). 在表存储中,最好是将实体(或者对实体的引用)存储两次 – 一次使用表名称、PK 和 RK 进行存储,以按客户 ID 快速查找,另一次则通过日期来加快查找速度。In Table Storage, it is best to store the entity (or a reference to it) twice – once with Table Name, PK, and RK to facilitate finding by customer ID, once to facilitate finding it by the date.

插入、更新和删除Insert, update, and delete

本部分介绍的经过验证的做法用于修改存储在表服务中的实体。This section describes proven practices for modifying entities stored in the Table service.

批处理Batching

批处理事务在 Azure 存储中称为实体组事务。Batch transactions are known as entity group transactions in Azure Storage. 实体组事务中的所有操作都必须位于单个表的单个分区中。All operations within an entity group transaction must be on a single partition in a single table. 在可能的情况下,请使用实体组事务来批量执行插入、更新和删除操作。Where possible, use entity group transactions to perform inserts, updates, and deletes in batches. 使用实体组事务可减少客户端应用程序与服务器之间的往返操作次数、减少需要收费的事务数(一个实体组事务计为一个收费事务,最多可能包含 100 个存储操作),以及启用原子更新(实体组事务中的所有操作都成功或都失败)。Using entity group transactions reduces the number of round trips from your client application to the server, reduces the number of billable transactions (an entity group transaction counts as a single transaction for billing purposes and can contain up to 100 storage operations), and enables atomic updates (all operations succeed or all fail within an entity group transaction). 高延迟性的环境(例如移动设备)可以充分利用实体组事务。Environments with high latencies such as mobile devices will benefit greatly from using entity group transactions.

UpsertUpsert

尽可能使用表的“Upsert”操作。Use table Upsert operations wherever possible. 有两种类型的“Upsert”,两种都可能比传统的“插入”和“更新”操作更高效:There are two types of Upsert, both of which can be more efficient than a traditional Insert and Update operations:

  • InsertOrMerge:若要上传实体的一部分属性,但不确定实体是否已存在,请使用此操作。InsertOrMerge: Use this operation when you want to upload a subset of the entity's properties, but aren't sure whether the entity already exists. 如果实体存在,则该调用会更新包含在“Upsert”操作中的属性,保留所有现有的属性不变,而如果实体不存在,则会插入新的实体。If the entity exists, this call updates the properties included in the Upsert operation, and leaves all existing properties as they are, if the entity does not exist, it inserts the new entity. 这类似于在查询中使用投影,因为只需上传在更改的属性。This is similar to using projection in a query, in that you only need to upload the properties that are changing.
  • InsertOrReplace:若要上传全新实体,但不确定实体是否已存在,请使用此操作。InsertOrReplace: Use this operation when you want to upload an entirely new entity, but you aren't sure whether it already exists. 仅当知道这个刚上传的实体完全正确时才使用此操作,因为该实体会完全覆盖旧实体。Use this operation when you know that the newly uploaded entity is entirely correct because it completely overwrites the old entity. 例如,需要更新用于存储用户当前位置的实体,而不管应用程序以前是否存储过该用户的位置数据;新位置实体是完整的,不需要任何旧实体提供的任何信息。For example, you want to update the entity that stores a user's current location regardless of whether or not the application has previously stored location data for the user; the new location entity is complete, and you do not need any information from any previous entity.

将数据系列存储在单个实体中Storing data series in a single entity

有时候,应用程序会存储一系列需要频繁进行一次性检索的数据:例如,应用程序可能会跟踪一段时间内的 CPU 使用情况,以便绘制过去 24 小时内数据的滚动图表。Sometimes, an application stores a series of data that it frequently needs to retrieve all at once: for example, an application might track CPU usage over time in order to plot a rolling chart of the data from the last 24 hours. 一种方法是每小时构建一个表实体,每个实体代表一个具体的小时,并存储该小时的 CPU 使用情况。One approach is to have one table entity per hour, with each entity representing a specific hour and storing the CPU usage for that hour. 为了针对该数据绘图,应用程序需要检索保留过去 24 小时内数据的实体。To plot this data, the application needs to retrieve the entities holding the data from the 24 most recent hours.

此外,也可以让应用程序将每小时的 CPU 使用情况存储为单个实体的独立属性:更新每个小时的时候,应用程序可以使用单个“InsertOrMerge Upsert”调用来更新最近的一个小时的值。Alternatively, your application could store the CPU usage for each hour as a separate property of a single entity: to update each hour, your application can use a single InsertOrMerge Upsert call to update the value for the most recent hour. 针对数据进行绘图时,应用程序只需检索 1 个实体而非 24 个,这样的查询非常高效。To plot the data, the application only needs to retrieve a single entity instead of 24, making for an efficient query. 有关查询效率的详细信息,请参阅标题为查询范围的部分。For more information on query efficiency, see the section titled Query scope).

在 Blob 中存储结构化数据Storing structured data in blobs

如果需要在执行批量插入后再统一检索实体的范围,请考虑使用 Blob,而不要使用表。If you are performing batch inserts and then retrieving ranges of entities together, consider using blobs instead of tables. 日志文件就是一个很好的例子。A good example is a log file. 可以批处理几分钟的日志,插入这些日志,然后一次性检索好几分钟的日志。You can batch several minutes of logs and insert them, and then retrieve several minutes of logs at a time. 在这种情况下,使用 Blob 要比使用表的性能更好,因为这可以大幅减少要写入或读取的对象数,并可能会减少需要发出的请求数。In this case, performance is better if you use blobs instead of tables, since you can significantly reduce the number of objects written to or read, and also possibly the number of requests that need made.

后续步骤Next steps