Choose the setting and its scope
Three different mechanisms appear below:
- Resource tuning tags set a supported target field for a resource created through the origin API.
- Adapter configuration controls the process that translates requests, such as its connection pool.
- Native infrastructure settings size a shared database or cluster through the system that owns that infrastructure.
Try provisioned Cosmos DB locally
This example uses a local Cloud Adapter process and an Azure test environment. The process is local; its Cosmos DB resources and capacity are real Azure resources.1
Install the CLI and inspect the mapping
If needed, install the Tensor9 CLI:Inspect the mapping before creating the test table:Prepare the Azure subscription, resource group, location and runtime identity described in Configuration Examples. The identity needs the target access required for both resource provisioning and item operations.
2
Start the DynamoDB adapter
Run the service in a terminal you can leave open:This starts a local endpoint for DynamoDB table and item requests.
3
Point your test client at the printed endpoint
In a second terminal, copy the listening endpoint:The service-specific endpoint directs DynamoDB calls from this process to the adapter. Keep the origin credentials appropriate to the adapter endpoint; the adapter’s Azure identity is separate.To configure a single client programmatically instead:
4
Create, inspect and exercise a test table
Use the complete request in the next section. Wait for the table to become available, inspect its native Cosmos capacity, then run the point-write and update examples. Record the table name, native container identity, effective throughput and test time together.
5
Finish the experiment
Delete only the disposable data created for the experiment. Follow the deployment’s resource-ownership policy when removing containers and accounts. Stopping the local process does not stop Azure capacity charges or delete backend data.Press Control-C in the adapter terminal when finished.
Provisioned Cosmos DB: give a table its own capacity
For a table that owns a dedicated Cosmos container, send the backend selector and autoscale maximum in the DynamoDBCreateTable tags. Save this complete request as create-orders.json:
BillingMode: PAY_PER_REQUEST remains an origin-facing DynamoDB setting. It does not make the selected Cosmos account serverless. Likewise, changing DynamoDB provisioned read or write units through UpdateTable does not resize the Cosmos container.
40,000 RU/s is an example capacity budget. Choose the value from measurements of your own item sizes, queries, writes and indexes. The target field uses 1,000-RU/s increments and a minimum of 1,000 RU/s; the actual container’s storage, throughput history and account constraints can require a higher minimum.
The container must belong to this table for the example to provide a per-table capacity budget. Several logical tables sharing a pre-provisioned container share its throughput. Manage that shared container’s capacity with its infrastructure owner; do not treat a logical table tag as an isolated budget.
Inspect the native result
Set these values from the deployment’s actual Azure resource coordinates. An origin table name is not proof of a native container name:40000. If it differs, keep the create response and the target inspection output and follow Understanding Behavior with Explain. A successful DescribeTable does not independently verify Azure capacity.
Size a second table independently
A small lookup table and a busy orders table need not have the same budget. In a second copy ofcreate-orders.json, change the table name to tuning-reference and the maximum to 4000. Keep a dedicated target container for each table.
Run each workload alone, then run both together. Inspect both native containers. This checks table-specific sizing and exposes shared account, adapter or network constraints that separate RU budgets cannot remove.
Treat global secondary indexes as additional capacity consumers. The provisioned Cosmos mapping uses Azure-managed index containers. Include index storage, index maintenance and index-query traffic in the budget, and use the provisioned Cosmos profile when choosing the table layout.
Compare a point operation with a conditional update
First write and read a small item:Diagnose throttling before increasing the maximum
For an existing container, change throughput through its infrastructure owner and inspect the effective value afterward. Do not assume adding a tag later, repeating
CreateTable, or calling UpdateTable is a capacity-update command. Keep the desired configuration synchronized with any native change so a later deployment does not restore an older value.
Serverless Cosmos DB: choose consumption capacity
Use the serverless backend when its consumption model fits the workload. The selector is:CreateTable request. Omit the provisioned-container autoscale tag. Serverless Cosmos does not have a dedicated autoscale band to reserve, and DynamoDB ProvisionedThroughput does not create one.
Compare a quiet period followed by a representative burst with the same workload on provisioned Cosmos. Record successful operations, throttled requests, total retries, end-to-end latency and consumed request units. A low average request rate can hide a burst that exceeds the target’s limits.
Choose provisioned Cosmos when the table needs the mapping’s managed global secondary indexes. Do not switch an existing table’s backend tag to move data or change account mode. Create the destination, migrate the data and validate queries and consumers before changing traffic. See Cosmos serverless behavior.
Firestore: tune the update shape
Firestore bills native document work and storage. The adapter’s request shape matters because a write that needs the old item can perform more work than an unconditional write. DynamoDB provisioned capacity settings do not reserve a Firestore read/write budget.Start with the normal validation behavior
KeepFIRESTORE_ALLOW_OVERSIZED_BLIND_UPDATES absent or set it to the string "false" in the selected service’s configuration. The adapter enforces the resulting DynamoDB item’s 400-KiB limit. Unconditional puts and deletes without return values or Streams can already avoid an item read; eligible top-level REMOVE-only updates can also do so.
For a Firestore-backed test table with the same key schema as tuning-orders, compare:
Opt in to blind SET updates where the size tradeoff fits
This adapter-configuration fragment enables eligible SET/REMOVE requests to use a masked Firestore write without reading the item first:CreateTable tag or a process environment variable. Do not add an origin-to-backend declaration merely to repeat the installation’s normal mapping; Configuration Files explains the compact configuration and service-specific settings.
The optimized request must meet all these conditions:
- Only top-level literal SET and/or REMOVE actions.
- No condition expression and
ReturnValues=NONE. - Streams disabled.
- No changes to the configured TTL attribute, primary key or secondary-index keys.
- No local secondary indexes that require checking the combined item and projected index-entry size.
"false" does not rewrite existing data.
Run the same SET workload with the setting off and on. Include a condition-expression case and a returned-image case in both runs to verify that application behavior remains correct. See the Firestore profile for the detailed request restrictions.
Spanner: separate channels from instance capacity
Spanner instance processing units are shared infrastructure capacity. The adapter’s gRPC channels are a separate concurrency control. A table’s DynamoDB RCU/WCU settings do not allocate processing units to that table. The adapter defaults to 32 channels. A configuration fragment for a comparison at 16 channels is:Batch independent work
For a Spanner-backed test table with the example key schema, save this asbatch-orders.json:
UnprocessedItems and retry only the remaining work using the application’s retry policy. Batching can amortize native work across independent puts and deletes. It does not provide cross-item atomicity, express conditional writes or replace TransactWriteItems. Include time spent waiting to assemble a batch in end-to-end latency.
Decide when to add processing units
Increase client concurrency gradually while measuring Spanner service utilization and application p95/p99 latency. Add instance capacity when service utilization is the bottleneck. If utilization is low, investigate channels, client queueing, network placement and the operation’s commit path first. Ordinary reads on this mapping are strong even whenConsistentRead=false. Changing that flag does not buy a cheaper consistency mode. Conditional and complex updates can read the item before committing, so a benchmark of simple assignments does not predict their latency.
Choose regional or multi-region placement for the failure coverage you need, then measure the application’s actual locations. Connection tuning cannot eliminate cross-region latency. See Spanner behavior and transactions.
Bigtable: distinguish a hot row from a full cluster
Bigtable capacity belongs to the cluster. The adapter uses a connection pool and a single-cluster-routing app profile so its strong-read and conditional-write behavior has a consistent target. The pool defaults to 64 channels and accepts values from 1 through 64. For a smaller workload, compare this configuration with the default:
Measure unconditional puts separately from conditional or returned-image updates. Guarded read-modify-write can repeat when another client changes the row. Adding cluster nodes cannot split a single item’s contention across machines.
Use cluster utilization, hottest-node utilization and native service latency to decide whether to add nodes. Adding clusters does not itself enable transparent failover in the adapter’s single-cluster route. The Bigtable profile also identifies the transaction, index, stream and TTL differences that capacity tuning cannot change.
PostgreSQL: budget the shared connection pool
The PostgreSQL backend is available through Cloud SQL, Scaleway Managed PostgreSQL, and PostgreSQL operated with the deployment. They share the DynamoDB adapter’s PostgreSQL request behavior; their database provisioning and operations differ. Provision the database dependency before starting the adapter, and keep its connection coordinates and credentials in their appropriate configuration and secret stores. The compact installation file needs extra service configuration for this dependency, not a redundant declaration of every automatically derived service mapping.Increase the pool only within the database budget
T9_POSTGRES_POOL_SIZE is a process environment setting. Its default is 8 connections per pool. To compare a 16-connection pool on the Cloud SQL backend:
This example assumes one pool per process. If a process opens several backend pools, count each one. Include temporary overlap during rolling replacements and connection refresh. Compare the total with the database’s actual connection limit and memory budget.
Match the remedy to the bottleneck
- If requests wait for a pool slot while database CPU and storage have headroom, try a modest pool increase.
- If database CPU or storage latency is saturated, a larger pool can make tail latency worse. Size the database or reduce work per request.
- If many requests contend on the same item, inspect lock waits and retry rates. More connections do not remove the conflict.
- If table or index creation overlaps a load spike, include that schema work in capacity planning.
UpdateTable capacity changes also do not resize the PostgreSQL instance.
Back up table metadata, items, index state and stream state together. A throughput improvement is not sufficient if the recovery procedure cannot restore a consistent application view.
Run a repeatable comparison
For every backend, keep one experiment record with the mapping, target identity, resource ownership, requested setting, effective setting and workload. Include the application-visible outcome and the native observation.
Change one setting at a time. Repeat the baseline after the tuned run to check whether a warm cache, a background operation or a different load level explains the result. Record the warm-up separately rather than dropping slow startup behavior without explanation.
Use request explanations and diagnostic response headers to inspect representative requests. Preserve the explanation reference alongside the measurements. For throughput runs, keep the diagnostic mode and sampling policy consistent so the instrumentation is not another changing variable.
Change and rollback checklist
- Identify the owner: table container, shared database, or adapter process.
- Save the previous requested and effective settings.
- Check whether the change requires a process restart, a native infrastructure operation, or a new destination and data migration.
- Apply the change through the owning configuration and wait for readiness.
- Verify both the origin request behavior and native target settings.
- Compare the same workload and restore the earlier configuration if the result is worse.