diff options
| author | SixOnMyface <[email protected]> | 2025-10-25 20:08:05 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-10-25 17:08:05 +0000 |
| commit | 8f92f2dea65582ed45d1f29e1980313668c8364c (patch) | |
| tree | 8ff129030822a039499ad77f28027199dbfd4798 | |
| parent | 18ae5ce1c6f04ccb4964b0f9041bbcb00537c7b1 (diff) | |
Feature/ydbdocs 1388 (#27164)
Co-authored-by: Stepan Beloyarov <[email protected]>
13 files changed, 52 insertions, 52 deletions
diff --git a/ydb/docs/en/core/changelog-enterprise.md b/ydb/docs/en/core/changelog-enterprise.md index 38aafd43efa..47c2263b46b 100644 --- a/ydb/docs/en/core/changelog-enterprise.md +++ b/ydb/docs/en/core/changelog-enterprise.md @@ -364,7 +364,7 @@ Release date: October 12, 2023. * Excluded unused messages and methods from `QueryService`. * Added sorting by `Rack` in /nodes in the `viewer backend`. * Fixed an error where sorting queries returned an error in descending order. -* Improved interaction between `KQP` and `NodeWhiteboard`. +* Improved interaction between `QP` and `NodeWhiteboard`. * Removed support for old parameter formats. * Fixed an error where `DefineBox` was not being applied to disks with a static group. * Fixed a `SIGSEGV` error in the dinnode during `CSV` import via `YDB CLI`. diff --git a/ydb/docs/en/core/changelog-server.md b/ydb/docs/en/core/changelog-server.md index c4929429e90..3ed3f94a76d 100644 --- a/ydb/docs/en/core/changelog-server.md +++ b/ydb/docs/en/core/changelog-server.md @@ -538,7 +538,7 @@ Release date: October 12, 2023. * Excluded unused messages and methods from `QueryService`. * Added sorting by `Rack` in /nodes in the `viewer backend`. * Fixed an error where sorting queries returned an error in descending order. -* Improved interaction between `KQP` and `NodeWhiteboard`. +* Improved interaction between `QP` and `NodeWhiteboard`. * Removed support for old parameter formats. * Fixed an error where `DefineBox` was not being applied to disks with a static group. * Fixed a `SIGSEGV` error in the dinnode during `CSV` import via `YDB CLI`. diff --git a/ydb/docs/en/core/concepts/glossary.md b/ydb/docs/en/core/concepts/glossary.md index fb7ecdcaa1d..cfc17cc95c6 100644 --- a/ydb/docs/en/core/concepts/glossary.md +++ b/ydb/docs/en/core/concepts/glossary.md @@ -419,9 +419,9 @@ The **actor system pool** is a [thread pool](https://en.wikipedia.org/wiki/Threa - **System**: A pool that handles internal operations within {{ ydb-short-name }} node. It serves system [tablets](#tablet), [state storage](#state-storage), [distributed storage](#distributed-storage) I/O, and so on. -- **User**: A pool dedicated to user-generated load, such as running non-system tablets or queries executed by the [KQP](#kqp). +- **User**: A pool dedicated to user-generated load, such as running non-system tablets or queries executed by the [QP](#kqp). -- **Batch**: A pool for tasks without strict execution deadlines, including heavy queries handled by the [KQP](#kqp) background operations like backups, data compaction, and garbage collection. +- **Batch**: A pool for tasks without strict execution deadlines, including heavy queries handled by the [QP](#kqp) background operations like backups, data compaction, and garbage collection. - **IO**: A pool for tasks involving blocking operations, such as authentication or writing logs to files. @@ -710,7 +710,7 @@ The **read set** or **ReadSet data** is what participating shards forward during #### Transaction proxy {#transaction-proxy} -The **transaction proxy** or `TX_PROXY` is a service that orchestrates the execution of many [distributed transactions](#transactions): sequential phases, phase execution, planning, and aggregation of results. In the case of direct orchestration by other actors (for example, KQP data transactions), it is used for caching and allocation of unique [TxIDs](#txid). +The **transaction proxy** or `TX_PROXY` is a service that orchestrates the execution of many [distributed transactions](#transactions): sequential phases, phase execution, planning, and aggregation of results. In the case of direct orchestration by other actors (for example, QP data transactions), it is used for caching and allocation of unique [TxIDs](#txid). #### Transaction flags {#txflags} @@ -738,9 +738,9 @@ During the distributed query execution, **mediator time** is the logical time be MiniKQL is a low-level language. The system's end users only see queries in the [YQL](#yql) language, which relies on MiniKQL in its implementation. -#### KQP {#kqp} +#### Query Processor {#kqp} -**KQP** or **Query Processor** is a {{ ydb-short-name }} component responsible for the orchestration of user query execution and generating the final response. +**QP** or **Query Processor** (previously, **KQP**) is a {{ ydb-short-name }} component responsible for the orchestration of user query execution and generating the final response. ### Global schema {#global-schema} diff --git a/ydb/docs/en/core/contributor/datashard-distributed-txs.md b/ydb/docs/en/core/contributor/datashard-distributed-txs.md index 6ba6b1926fd..5f9f53aa44a 100644 --- a/ydb/docs/en/core/contributor/datashard-distributed-txs.md +++ b/ydb/docs/en/core/contributor/datashard-distributed-txs.md @@ -4,7 +4,7 @@ When the execution of a transaction depends on the state of other participants, the participants exchange data using so-called ReadSets. These are persistent messages exchanged between participants that are delivered at least once and contain read results with the state of the transaction. The use of ReadSets causes transactions to go through additional phases: -1. **Reading phase**: The participant reads, persists, and sends data that is needed by other participants. During this phase, KQP transactions (type `TX_KIND_DATA`, which have a non-empty `TDataTransaction.KqpTransaction` field and subtype `KQP_TX_TYPE_DATA`) validate optimistic locks. Older MiniKQL transactions (type `TX_KIND_DATA`, which have a non-empty `TDataTransaction.MiniKQL` field) perform reads and send arbitrary table data during this phase. Another example of using the reading phase is the distributed TTL transaction for deleting expired rows. The primary shard generates a bitmask matching expired rows, ensuring that both the primary and index shards delete the same rows. +1. **Reading phase**: The participant reads, persists, and sends data that is needed by other participants. During this phase, QP transactions (type `TX_KIND_DATA`, which have a non-empty `TDataTransaction.KqpTransaction` field and subtype `KQP_TX_TYPE_DATA`) validate optimistic locks. Older MiniKQL transactions (type `TX_KIND_DATA`, which have a non-empty `TDataTransaction.MiniKQL` field) perform reads and send arbitrary table data during this phase. Another example of using the reading phase is the distributed TTL transaction for deleting expired rows. The primary shard generates a bitmask matching expired rows, ensuring that both the primary and index shards delete the same rows. 2. **Waiting phase**: The participant waits until it has received all the necessary data from the other participants. 3. **Execution phase**: The participant uses both local and remote data to determine whether to abort or complete the transaction. The participant generates and applies the effects specified in the transaction body if the transaction is completed successfully. The transaction body typically includes a program that uses the same input data and leads all participants to come to the same conclusion. @@ -64,7 +64,7 @@ Transactions are stored on disk and in memory using the [TTransQueue](https://gi Volatile transactions are stored in memory and are currently lost when DataShard restarts (they may be migrated during graceful restarts in the future). The restart aborts the transaction for all participants, and any participant can initiate the abort before the transaction body is executed and its effects are persisted. Shards use this feature to make schema and partitioning changes faster by aborting all pending transactions without waiting for a planning deadline. -The distributed transaction body needs to have enough information about the other participants so that each shard can know when it needs to generate and send outgoing ReadSets and which shards should expect and wait for incoming ReadSets. KQP transactions currently use ReadSets for validating and committing optimistic locks, which are described using [TKqpLocks](https://github.com/ydb-platform/ydb/blob/a833a4359ba77706f9b1fe4104741ef0acfbc83b/ydb/core/protos/data_events.proto#L18) generated by the `TKqpDataExecutor` actor. This message describes the following shard sets: +The distributed transaction body needs to have enough information about the other participants so that each shard can know when it needs to generate and send outgoing ReadSets and which shards should expect and wait for incoming ReadSets. QP transactions currently use ReadSets for validating and committing optimistic locks, which are described using [TKqpLocks](https://github.com/ydb-platform/ydb/blob/a833a4359ba77706f9b1fe4104741ef0acfbc83b/ydb/core/protos/data_events.proto#L18) generated by the `TKqpDataExecutor` actor. This message describes the following shard sets: * `SendingShards` are shards that send ReadSets to all shards in the `ReceivingShards` set. * `ReceivingShards` are shards that expect ReadSets from all shards in the `SendingShards` set. @@ -93,13 +93,13 @@ DataShards handle `TEvTxProcessing::TEvPlanStep` events in the [TTxPlanStep](htt ## Execution phase in the DataShard tablet -The [PlanQueue](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/plan_queue_unit.cpp#L44) unit allows distributed transactions to start, subject to concurrency limits, in the increasing `(Step, TxId)` order. The transaction body is loaded from disk when needed (for evicted persistent transactions), KQP transactions [finalize execution plans](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/datashard_active_transaction.cpp#L667) and arrive at the [BuildAndWaitDependencies](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp#L72) unit. This unit analyzes transaction keys and ranges declared for reading and writing and may add dependencies on earlier conflicting transactions. For example, when transaction `A` writes to key `K` and a later transaction `B` reads from key `K`, then transaction `B` depends on transaction `A`, and transaction `B` cannot start until transaction `A` completes. Transactions leave `BuildAndWaitDependencies` when they no longer have direct dependencies on other transactions. +The [PlanQueue](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/plan_queue_unit.cpp#L44) unit allows distributed transactions to start, subject to concurrency limits, in the increasing `(Step, TxId)` order. The transaction body is loaded from disk when needed (for evicted persistent transactions), QP transactions [finalize execution plans](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/datashard_active_transaction.cpp#L667) and arrive at the [BuildAndWaitDependencies](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp#L72) unit. This unit analyzes transaction keys and ranges declared for reading and writing and may add dependencies on earlier conflicting transactions. For example, when transaction `A` writes to key `K` and a later transaction `B` reads from key `K`, then transaction `B` depends on transaction `A`, and transaction `B` cannot start until transaction `A` completes. Transactions leave `BuildAndWaitDependencies` when they no longer have direct dependencies on other transactions. -Next, persistent KQP transactions execute the read phase (which includes validating optimistic locks) and generate outgoing OutReadSets in the [BuildKqpDataTxOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/build_kqp_data_tx_out_rs_unit.cpp#L44) unit. Then, the [StoreAndSendOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L42) persists outgoing ReadSets and access logs for optimistic locks. Optimistic locks that have attached uncommitted changes are [marked with the `Frozen` flag](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L67), which prevents them from being aborted until the transaction completes. Otherwise, lock validity is ensured by assigning writes with a higher MVCC version and ensuring the correct execution order of conflicting transactions. Operations with access logs or outgoing ReadSets are [added to the `Incomplete` set](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L79), which ensures that new writes can't change the validity of previous reads and generally need to use a higher MVCC version. However, new reads don't necessarily need to block on the outcome of the incomplete transaction and can use a lower MVCC version as long as it's consistent with other transactions. +Next, persistent QP transactions execute the read phase (which includes validating optimistic locks) and generate outgoing OutReadSets in the [BuildKqpDataTxOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/build_kqp_data_tx_out_rs_unit.cpp#L44) unit. Then, the [StoreAndSendOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L42) persists outgoing ReadSets and access logs for optimistic locks. Optimistic locks that have attached uncommitted changes are [marked with the `Frozen` flag](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L67), which prevents them from being aborted until the transaction completes. Otherwise, lock validity is ensured by assigning writes with a higher MVCC version and ensuring the correct execution order of conflicting transactions. Operations with access logs or outgoing ReadSets are [added to the `Incomplete` set](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L79), which ensures that new writes can't change the validity of previous reads and generally need to use a higher MVCC version. However, new reads don't necessarily need to block on the outcome of the incomplete transaction and can use a lower MVCC version as long as it's consistent with other transactions. -Persistent KQP transactions prepare data structures for incoming InReadSets in the [PrepareKqpDataTxInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/prepare_kqp_data_tx_in_rs_unit.cpp#L31) unit and begin waiting for all necessary ReadSets from other participants in the [LoadAndWaitInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/load_and_wait_in_rs_unit.cpp#L36) unit. In some cases, such as blind writes to multiple shards without lock validation, distributed transactions may not require the exchange of ReadSets, and the ReadSet-related units don't perform any actions in these scenarios. +Persistent QP transactions prepare data structures for incoming InReadSets in the [PrepareKqpDataTxInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/prepare_kqp_data_tx_in_rs_unit.cpp#L31) unit and begin waiting for all necessary ReadSets from other participants in the [LoadAndWaitInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/load_and_wait_in_rs_unit.cpp#L36) unit. In some cases, such as blind writes to multiple shards without lock validation, distributed transactions may not require the exchange of ReadSets, and the ReadSet-related units don't perform any actions in these scenarios. -Finally, the KQP transaction operation reaches the [ExecuteKqpDataTx](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L59) unit. This unit validates local optimistic locks using previously persisted `AccessLog` data when available, validates ReadSets received from other participants, and, if everything checks out, executes the transaction body and returns a result. If lock validation fails locally or remotely, the transaction body is not executed, and the operation fails with an `ABORTED` status. +Finally, the QP transaction operation reaches the [ExecuteKqpDataTx](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L59) unit. This unit validates local optimistic locks using previously persisted `AccessLog` data when available, validates ReadSets received from other participants, and, if everything checks out, executes the transaction body and returns a result. If lock validation fails locally or remotely, the transaction body is not executed, and the operation fails with an `ABORTED` status. ### Volatile transactions diff --git a/ydb/docs/en/core/contributor/datashard-locks-and-change-visibility.md b/ydb/docs/en/core/contributor/datashard-locks-and-change-visibility.md index 3a82b80986f..48c65272e81 100644 --- a/ydb/docs/en/core/contributor/datashard-locks-and-change-visibility.md +++ b/ydb/docs/en/core/contributor/datashard-locks-and-change-visibility.md @@ -6,9 +6,9 @@ The underlying LocalDB support also allows very large transaction commits, not l ## High level overview -Complex YQL transactions (either interactive, i.e. when client begins a transaction and uses it to perform queries without committing in the same query, or that involve multiple sub-queries) are split into multiple "phases" by [KQP](https://github.com/ydb-platform/ydb/tree/main/ydb/core/kqp), where output of one phase potentially acts as input to the next phase. For example, when a YQL query contains a `JOIN`, the first phase may be reading the first table, and the second phase may use the output of the first table to perform lookup queries in the second table. +Complex YQL transactions (either interactive, i.e. when client begins a transaction and uses it to perform queries without committing in the same query, or that involve multiple sub-queries) are split into multiple "phases" by [QP](https://github.com/ydb-platform/ydb/tree/main/ydb/core/kqp), where output of one phase potentially acts as input to the next phase. For example, when a YQL query contains a `JOIN`, the first phase may be reading the first table, and the second phase may use the output of the first table to perform lookup queries in the second table. -For read-only queries KQP uses global [MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) snapshots to ensure consistency between sub-queries. But when transaction also writes, it needs to ensure [serializable](https://en.wikipedia.org/wiki/Serializability) isolation is not violated at commit time. Currently, this is achieved using [Optimistic concurrency control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control), where reads add optimistic "locks" to observed ranges, and writes by other transactions "break" those locks at their commit time. Transaction may successfully commit as long as none of those locks are broken at commit time, otherwise it fails with a "transaction locks invalidated" error. +For read-only queries QP uses global [MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) snapshots to ensure consistency between sub-queries. But when transaction also writes, it needs to ensure [serializable](https://en.wikipedia.org/wiki/Serializability) isolation is not violated at commit time. Currently, this is achieved using [Optimistic concurrency control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control), where reads add optimistic "locks" to observed ranges, and writes by other transactions "break" those locks at their commit time. Transaction may successfully commit as long as none of those locks are broken at commit time, otherwise it fails with a "transaction locks invalidated" error. There's another way to look at optimistic locks. A single transaction may read from multiple shards using read timestamps (this may be a single global MVCC snapshot timestamp, or multiple timestamps, different for each read), while other transactions concurrently write to the same tables or shards. When transaction commits, it is assigned a single commit timestamp in the global serializable order of execution. As long as all of those reads could be repeated at the commit timestamp, without any change to observed results, the transaction might as well have executed (in its entirety) at the commit timestamp. The optimistic lock, as long as it's not broken, tells the transaction that it is possible to move all reads to the commit timestamp. @@ -16,7 +16,7 @@ Uncommitted changes are not too different from reads in that regard. As long as ## How locks are used for reads -Operations proposed to DataShards are assigned a globally unique 64-bit `TxId`, which are allocated in large batches from global [TxAllocator](https://github.com/ydb-platform/ydb/tree/main/ydb/core/tx/tx_allocator) tablets. When KQP performs the first read in a multi-phase transaction, it also uses this `TxId` as a lock identifier (historically named `LockTxId`), which is then used in all subsequent queries in the same YQL transaction. DataShard will add new locks when operation has `LockTxId` specified (it is not zero): +Operations proposed to DataShards are assigned a globally unique 64-bit `TxId`, which are allocated in large batches from global [TxAllocator](https://github.com/ydb-platform/ydb/tree/main/ydb/core/tx/tx_allocator) tablets. When QP performs the first read in a multi-phase transaction, it also uses this `TxId` as a lock identifier (historically named `LockTxId`), which is then used in all subsequent queries in the same YQL transaction. DataShard will add new locks when operation has `LockTxId` specified (it is not zero): * See [LockTxId](https://github.com/ydb-platform/ydb/blob/3444af692d32224288c41ba8c21e416d5fd4996c/ydb/core/protos/tx_datashard.proto#L1612) field in `TEvRead` read requests * See [LockTxId](https://github.com/ydb-platform/ydb/blob/bcf764f1aa71683e3871616abe6f16b47cec42e4/ydb/core/protos/data_events.proto#L83) field in `TEvWrite` write requests @@ -24,7 +24,7 @@ Operations proposed to DataShards are assigned a globally unique 64-bit `TxId`, You may also see the `LockNodeId` field, which specifies the originating node id of the lock, which is used by DataShard for subscribing to lock status, and cleaning up locks when they are no longer needed. -Note that `LockTxId` is just a unique number, that is used across multiple operations in the same YQL transaction, while `TxId` is unique for every operation for a single DataShard. The use of the first `TxId` as `LockTxId` is not required, but since KQP already has a globally unique number, and `LockTxId` is unrelated to `TxId`, it elides an extra allocation. +Note that `LockTxId` is just a unique number, that is used across multiple operations in the same YQL transaction, while `TxId` is unique for every operation for a single DataShard. The use of the first `TxId` as `LockTxId` is not required, but since QP already has a globally unique number, and `LockTxId` is unrelated to `TxId`, it elides an extra allocation. Locks table (see [datashard_locks.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/datashard/datashard_locks.h) and [datashard_locks.cpp](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/datashard/datashard_locks.cpp)) indexes locks by their primary key ranges in a range tree, allowing finding and "breaking" them by point keys. In the simplest case when read operation reads a range it is added using a [SetLock](https://github.com/ydb-platform/ydb/blob/207ac81618e05ade724a8a8193bc9125d466bd06/ydb/core/tx/datashard/datashard_locks.h#L831) method, and when write operation writes a key it breaks other locks using a [BreakLocks](https://github.com/ydb-platform/ydb/blob/207ac81618e05ade724a8a8193bc9125d466bd06/ydb/core/tx/datashard/datashard_locks.h#L834) method. @@ -34,7 +34,7 @@ In the successful scenario, the lock exists and is not broken, `Generation` and In the unsuccessful scenarios, previously acquired locks are broken. For example, when changing the `Generation` of the lock (disabling the lock on restart) or the `Counter` (on an explicit error status, or when disabling and recreating the lock in the same generation). -The first `Generation` and `Counter` for each shard are remembered by KQP, and changes during transaction lifetime are indicative of possible inconsistencies and serializable isolation violations. Read-Write transactions, or transactions that did not use global MVCC snapshots for efficiency reasons, perform the final commit that validates `Generation`/`Counter` values and commit only succeeds when all of them match. +The first `Generation` and `Counter` for each shard are remembered by QP, and changes during transaction lifetime are indicative of possible inconsistencies and serializable isolation violations. Read-Write transactions, or transactions that did not use global MVCC snapshots for efficiency reasons, perform the final commit that validates `Generation`/`Counter` values and commit only succeeds when all of them match. Reads using global MVCC snapshots are already consistent. Nevertheless, they still acquire locks in case transaction might perform a write later in the lifecycle. @@ -42,14 +42,14 @@ When acquiring locks DataShard performs additional checks, on whether or not con ## How locks are used for writes -When KQP needs to make uncommitted changes in a YQL transaction, it uses DataShard write transactions with a non-zero `LockTxId`. DataShard will then use this `LockTxId` as `TxId` for persisting uncommitted changes, available as long as the lock is valid. Internally locks that have uncommitted writes are called write locks. Such locks also become persistent (see the [Locks](https://github.com/ydb-platform/ydb/blob/5aecdb67595db1a47c933b7d8da2cb662a50e185/ydb/core/tx/datashard/datashard_impl.h#L879) table and related tables below), surviving DataShard restarts. +When QP needs to make uncommitted changes in a YQL transaction, it uses DataShard write transactions with a non-zero `LockTxId`. DataShard will then use this `LockTxId` as `TxId` for persisting uncommitted changes, available as long as the lock is valid. Internally locks that have uncommitted writes are called write locks. Such locks also become persistent (see the [Locks](https://github.com/ydb-platform/ydb/blob/5aecdb67595db1a47c933b7d8da2cb662a50e185/ydb/core/tx/datashard/datashard_impl.h#L879) table and related tables below), surviving DataShard restarts. There are some limitations to such uncommitted write transactions: * Transaction must run in an immediate transaction mode (i.e. uncommitted writes cannot be distributed, uncommitted writes to different shards are performed independently instead) * Transaction must have a valid `LockNodeId` specified, DataShard subscribes to lock status using this node and automatically rolls back uncommitted changes when the lock expires (e.g. when transaction aborts unexpectedly, node is restarted and transaction state is lost, etc.) * Transaction must have a valid MVCC snapshot specified, which is used as the conflict detection baseline (and reads when needed), and expected to be used across all reads and writes in the same YQL transaction. -* The specified lock must be valid and non-broken, otherwise the specified `LockTxId` must not have any uncompacted data in LocalDB. This protects against edge cases where transaction rolls back due to lock status failure, and KQP tries writing to the shard again. +* The specified lock must be valid and non-broken, otherwise the specified `LockTxId` must not have any uncompacted data in LocalDB. This protects against edge cases where transaction rolls back due to lock status failure, and QP tries writing to the shard again. When the YQL transaction later reads using the same `LockTxId`, reads will use a per-query transaction map with [LocalDB](localdb-uncommitted-txs.md), where the `LockTxId` appears as if it's already committed, allowing transaction to observe its own changes, but not other uncommitted changes. Since reads are performed using an MVCC snapshot, the transaction map will have a special entry `[LockTxId] => v{min}`, so the uncommitted change is visible in all snapshots. @@ -90,7 +90,7 @@ Instead, when the write lock is validated, it becomes "frozen", and cannot be br ## Committing changes -When KQP needs to commit previously uncommitted changes, it proposes a transaction that commits previously acquired locks. Specifically this transaction must not have a `LockTxId` specified (the commit is not setting any new locks), and must include a previously set lock in [Locks](https://github.com/ydb-platform/ydb/blob/b07264456a2e8b5929901f258ad60399bb64678a/ydb/core/protos/tx_datashard.proto#L219) transaction field, and with Op set to [Commit](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L26). The commit transaction may either be immediate (when the YQL transaction involves a single shard, whether or not multiple phases have been used), or prepared as a distributed transaction with multiple participants. +When QP needs to commit previously uncommitted changes, it proposes a transaction that commits previously acquired locks. Specifically this transaction must not have a `LockTxId` specified (the commit is not setting any new locks), and must include a previously set lock in [Locks](https://github.com/ydb-platform/ydb/blob/b07264456a2e8b5929901f258ad60399bb64678a/ydb/core/protos/tx_datashard.proto#L219) transaction field, and with Op set to [Commit](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L26). The commit transaction may either be immediate (when the YQL transaction involves a single shard, whether or not multiple phases have been used), or prepared as a distributed transaction with multiple participants. To support distributed transactions all shards that validate locks must be included in [SendingShards](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L20), and all shards that have side-effects must be included in [ReceivingShards](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L21). During validation sending shards will generate persistent ReadSets and send them to all receiving shards, and receiving shards will wait for all expected ReadSets before executing the transaction. When transaction is executed with all successful validation results it will commit the lock by calling [KqpCommitLocks](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L228). Otherwise, transaction body will not be executed, and lock is erased with all uncommitted changes rolled back by calling [KqpEraseLocks](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L190), and it cannot be retried later on commit failure. @@ -100,7 +100,7 @@ Note that all uncommitted changes with the same `LockTxId` must be included in a {% endnote %} -The commit transaction may also have additional side-effects, which are atomically executed after the lock is committed. KQP will try to accumulate side-effects in memory until the same table is read in the same transaction, or until transaction commits, to reduce latency and fuse side-effects with commit as much as possible. When it is possible to accumulate all side-effects in memory, no uncommitted changes are persisted, and only read locks are optionally acquired. +The commit transaction may also have additional side-effects, which are atomically executed after the lock is committed. QP will try to accumulate side-effects in memory until the same table is read in the same transaction, or until transaction commits, to reduce latency and fuse side-effects with commit as much as possible. When it is possible to accumulate all side-effects in memory, no uncommitted changes are persisted, and only read locks are optionally acquired. When YQL transaction needs to rollback it runs an empty transactions with the [Rollback](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L27) lock op. Even if it didn't, when the [TLockHandle](https://github.com/ydb-platform/ydb/blob/0db14d1168517ecacab106e7abfe7af663020829/ydb/core/tx/long_tx_service/public/lock_handle.h#L15) is destroyed, subscribed DataShards will clean it up automatically in their [TxRemoveLock](https://github.com/ydb-platform/ydb/blob/0db14d1168517ecacab106e7abfe7af663020829/ydb/core/tx/datashard/remove_locks.cpp#L24) internal transaction. The explicit removal is preferred, since uncommitted changes is a finite resource and asynchronous cleanup via `TLockHandle` would not ensure that resource is freed before new transactions try to write more uncommitted changes. diff --git a/ydb/docs/en/core/contributor/load-actors-kqp.md b/ydb/docs/en/core/contributor/load-actors-kqp.md index efb8a7aeaba..6c6bb2093a6 100644 --- a/ydb/docs/en/core/contributor/load-actors-kqp.md +++ b/ydb/docs/en/core/contributor/load-actors-kqp.md @@ -1,4 +1,4 @@ -# KqpLoad +# Query Processor Load Runs general performance testing for the {{ ydb-short-name }} cluster by loading all components via the Query Processor layer. The load is similar to that from the [workload](../reference/ydb-cli/commands/workload/index.md) {{ ydb-short-name }} CLI subcommand, but it is generated from within the cluster. diff --git a/ydb/docs/en/core/reference/configuration/memory_controller_config.md b/ydb/docs/en/core/reference/configuration/memory_controller_config.md index 8aa9d9bb419..1ac1019a3ee 100644 --- a/ydb/docs/en/core/reference/configuration/memory_controller_config.md +++ b/ydb/docs/en/core/reference/configuration/memory_controller_config.md @@ -12,7 +12,7 @@ config: --- sankey-beta -Activity Components,"KQP", 20 +Activity Components,"QP", 20 Activity Components,Compaction, 10 Cache Components,Shared cache, 40 @@ -30,7 +30,7 @@ Examples of components managed by the memory controller: - [Shared cache](../../concepts/glossary.md#shared-cache): stores recently accessed data pages read from [distributed storage](../../concepts/glossary.md#distributed-storage) to reduce disk I/O and accelerate data retrieval. - [MemTable](../../concepts/glossary.md#memtable): holds data that has not yet been flushed to [SST](../../concepts/glossary.md#sst). -- [KQP](../../concepts/glossary.md#kqp): stores intermediate query results. +- [Query Processor](../../concepts/glossary.md#kqp): stores intermediate query results. - [Compaction](../../concepts/glossary.md#compaction): The process of organizing and cleaning up data, which is performed automatically (in the background) to optimize storage space. - Allocator caches: keep memory blocks that have been released but not yet returned to the operating system. @@ -104,7 +104,7 @@ memory_controller_config: The activity components include: -- KQP +- Query Processor - Compaction The memory limit for each activity component specifies the maximum amount of memory it can attempt to use. However, to prevent the {{ ydb-short-name }} process from exceeding the soft memory limit, the total consumption of activity components is further constrained by an additional limit known as the activities memory limit. If the total memory usage of the activity components exceeds this limit, any additional memory requests will be denied. When query execution approaches memory limits, {{ ydb-short-name }} activates [spilling](../../concepts/spilling.md) to temporarily save intermediate data to disk, preventing memory limit violations. @@ -113,7 +113,7 @@ As a result, while the combined individual limits of the activity components mig There are some other activity components that currently do not have individual memory limits. -Example of the `memory_controller_config` section with a specified KQP limit: +Example of the `memory_controller_config` section with a specified QP limit: ```yaml memory_controller_config: @@ -144,5 +144,5 @@ $Max(shared\_cache\_min\_percent * hard\_limit\_bytes / 100, shared\_cache\_min\ | `shared_cache_max_percent` /<br/>`shared_cache_max_bytes` | 50% | Maximum threshold for the shared cache memory limit. | | `mem_table_min_percent` /<br/>`mem_table_min_bytes` | 1% | Minimum threshold for the MemTable memory limit. | | `mem_table_max_percent` /<br/>`mem_table_max_bytes` | 3% | Maximum threshold for the MemTable memory limit. | -| `query_execution_limit_percent` /<br/>`query_execution_limit_bytes` | 20% | KQP memory limit. | +| `query_execution_limit_percent` /<br/>`query_execution_limit_bytes` | 20% | QP memory limit. | | `compaction_limit_percent` /<br/>`compaction_limit_bytes` | 10% | Compaction memory limit. | diff --git a/ydb/docs/ru/core/changelog-enterprise.md b/ydb/docs/ru/core/changelog-enterprise.md index 191b33470c3..a1e67cae403 100644 --- a/ydb/docs/ru/core/changelog-enterprise.md +++ b/ydb/docs/ru/core/changelog-enterprise.md @@ -363,7 +363,7 @@ * Исключены неиспользуемые сообщения и методы из `QueryService`. * Добавлена сортировка по `Rack` в `/nodes` во `viewer backend`. * Исправлена ошибка, при которой запрос с сортировкой возвращает ошибку при убывании. -* Исправлено взаимодействие `KQP` с `NodeWhiteboard`. +* Исправлено взаимодействие `QP` с `NodeWhiteboard`. * Удалена поддержка старых форматов параметров. * Исправлена ошибка, при которой `DefineBox` не применялся для дисков, на которых есть статическая группа. * Исправлена ошибка `SIGSEGV` в диннодах при импорте `CSV` через `YDB CLI`. diff --git a/ydb/docs/ru/core/changelog-server.md b/ydb/docs/ru/core/changelog-server.md index 7ca7659da0a..8cd5b2451de 100644 --- a/ydb/docs/ru/core/changelog-server.md +++ b/ydb/docs/ru/core/changelog-server.md @@ -538,7 +538,7 @@ * Исключены неиспользуемые сообщения и методы из `QueryService`. * Добавлена сортировка по `Rack` в `/nodes` во `viewer backend`. * Исправлена ошибка, при которой запрос с сортировкой возвращает ошибку при убывании. -* Исправлено взаимодействие `KQP` с `NodeWhiteboard`. +* Исправлено взаимодействие `QP` с `NodeWhiteboard`. * Удалена поддержка старых форматов параметров. * Исправлена ошибка, при которой `DefineBox` не применялся для дисков, на которых есть статическая группа. * Исправлена ошибка `SIGSEGV` в диннодах при импорте `CSV` через `YDB CLI`. diff --git a/ydb/docs/ru/core/concepts/glossary.md b/ydb/docs/ru/core/concepts/glossary.md index 73d11ae60c9..8777625e466 100644 --- a/ydb/docs/ru/core/concepts/glossary.md +++ b/ydb/docs/ru/core/concepts/glossary.md @@ -779,7 +779,7 @@ PDisk содержит планировщик, который обеспечив #### Транзакционные прокси {#transaction-proxy} -**Транзакционные прокси**, **transaction proxy** или `TX_PROXY` — это сервис, который оркестрирует выполнение многих [распределённых транзакций](#transactions): последовательные фазы, выполнение фаз, планирование и агрегацию результатов. В случае прямой оркестрации другими акторами (например, KQP data transactions), он используется для кэширования и выделения уникальных [TxID](#txid). +**Транзакционные прокси**, **transaction proxy** или `TX_PROXY` — это сервис, который оркестрирует выполнение многих [распределённых транзакций](#transactions): последовательные фазы, выполнение фаз, планирование и агрегацию результатов. В случае прямой оркестрации другими акторами (например, QP data transactions), он используется для кэширования и выделения уникальных [TxID](#txid). #### Флаги транзакции {#txflags} @@ -807,9 +807,9 @@ PDisk содержит планировщик, который обеспечив MiniKQL — это язык низкого уровня. Конечные пользователи системы видят только запросы на языке [YQL](#yql), который опирается на MiniKQL в своей реализации. -#### KQP {#kqp} +#### Query Processor {#kqp} -**KQP** — это компонент {{ ydb-short-name }}, отвечающий за оркестрацию выполнения пользовательских запросов и генерацию окончательного ответа. +**Query Processor** или **QP** (ранее **KQP**) — это компонент {{ ydb-short-name }}, отвечающий за оркестрацию выполнения пользовательских запросов и генерацию окончательного ответа. ### Глобальная схема {#global-schema} diff --git a/ydb/docs/ru/core/contributor/datashard-distributed-txs.md b/ydb/docs/ru/core/contributor/datashard-distributed-txs.md index f3c74fe0dfa..5d0fc199fab 100644 --- a/ydb/docs/ru/core/contributor/datashard-distributed-txs.md +++ b/ydb/docs/ru/core/contributor/datashard-distributed-txs.md @@ -4,7 +4,7 @@ В случае, когда выполнение транзакции зависит от состояния других участников, участники обмениваются данными между собой с помощью так называемых ReadSet'ов, представляющих из себя персистентное сообщение от одного участника другому, с семантикой доставки "как минимум один раз". В этом случае выполнение транзакции на каждом из участников делится на три дополнительные фазы: -1. **Фаза чтения**. Участник производит чтение, фиксацию и отправку данных, которые необходимы другим участникам. Сейчас на коммите KQP транзакций (тип транзакции `TX_KIND_DATA` с заполненным полем `TDataTransaction.KqpTransaction` и типом `KQP_TX_TYPE_DATA`) в этой фазе происходит только проверка оптимистичных блокировок, если результат этой проверки нужен другим участникам. В более старых MiniKQL транзакциях (тип транзакции `TX_KIND_DATA` с заполненным полем `TDataTransaction.MiniKQL`) выполняется чтение и отправка произвольных данных. Другой пример, где происходит чтение в этой фазе - распределённая транзакция удаления строк по TTL, которая используется для фильтрации подходящих под условие строк и одновременного их удаления из основной таблицы и индексов. +1. **Фаза чтения**. Участник производит чтение, фиксацию и отправку данных, которые необходимы другим участникам. Сейчас на коммите QP транзакций (тип транзакции `TX_KIND_DATA` с заполненным полем `TDataTransaction.KqpTransaction` и типом `KQP_TX_TYPE_DATA`) в этой фазе происходит только проверка оптимистичных блокировок, если результат этой проверки нужен другим участникам. В более старых MiniKQL транзакциях (тип транзакции `TX_KIND_DATA` с заполненным полем `TDataTransaction.MiniKQL`) выполняется чтение и отправка произвольных данных. Другой пример, где происходит чтение в этой фазе - распределённая транзакция удаления строк по TTL, которая используется для фильтрации подходящих под условие строк и одновременного их удаления из основной таблицы и индексов. 2. **Фаза ожидания**. Участник ждёт получения необходимых ему данных от других участников. 3. **Фаза выполнения**. Участник на основе локальных и полученных с других участников данных принимает решение о выполнении, либо отмене транзакции, формирует и применяет эффекты в соответствии с телом транзакции. Тело транзакции написано таким образом, что участники принимают решение на одинаковых данных, и либо все принимают решение о выполнении, либо все принимают решение об отмене транзакции. @@ -63,7 +63,7 @@ В отличие от персистентных транзакций, волатильные распределённые транзакции сохраняются исключительно в памяти, в текущей реализации исчезая вместе с рестартом шарда (в будущем может появиться возможность их миграции во время штатных рестартов). Протокол предусматривает, что волатильные транзакции могут быть отменены в любой момент по инициативе любого участвующего шарда до их окончательного выполнения на этом шарде. Например, шарды пользуются этим для быстрой отмены транзакций с началом изменения партиционирования, или при появлении схемной операции, не дожидаясь окончания таймаута планирования. -В теле распределённой транзакции должно быть достаточно информации о других участниках этой транзакции, для формирования и отправки ReadSet'ов, а также для их правильного ожидания. В используемых сейчас KQP транзакциях это так или иначе связано с проверкой блокировок и передаётся через структуру [TKqpLocks](https://github.com/ydb-platform/ydb/blob/a833a4359ba77706f9b1fe4104741ef0acfbc83b/ydb/core/protos/data_events.proto#L18), которая заполняется актором `TKqpDataExecutor`. Там указываются наборы шардов: +В теле распределённой транзакции должно быть достаточно информации о других участниках этой транзакции, для формирования и отправки ReadSet'ов, а также для их правильного ожидания. В используемых сейчас QP транзакциях это так или иначе связано с проверкой блокировок и передаётся через структуру [TKqpLocks](https://github.com/ydb-platform/ydb/blob/a833a4359ba77706f9b1fe4104741ef0acfbc83b/ydb/core/protos/data_events.proto#L18), которая заполняется актором `TKqpDataExecutor`. Там указываются наборы шардов: * `SendingShards` - шарды из этого множества отправляют ReadSet'ы на все шарды из множества `ReceivingShards` * `ReceivingShards` - шарды из этого множества ожидают получение ReadSet'ов от всех шардов из множества `SendingShards` @@ -92,11 +92,11 @@ DataShard обрабатывает сообщения `TEvTxProcessing::TEvPlanS ## Фаза выполнения в таблетке DataShard -Шаг выполнения [PlanQueue](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/plan_queue_unit.cpp#L44) разрешает запуск следующей распределённой транзакции в соответствии с увеличением `(Step, TxId)` и после опциональной загрузки тела транзакции с диска (для персистентных транзакций) KQP транзакция финализирует [план выполнения](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/datashard_active_transaction.cpp#L667) и попадает в шаг выполнения [BuildAndWaitDependencies](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp#L72). На этом шаге анализируются ключи, которые заявлены для чтения и записи в теле транзакции, на основе которых между транзакциями возникают зависимости. Например, если транзакция `A` пишет по ключу `K`, а более поздняя транзакция `B` читает по ключу `K`, то у транзакции `B` возникает зависимость на транзакцию `A` и транзакция `B` не может быть выполнена до завершения выполнения транзакции `A`. Транзакция выходит из шага `BuildAndWaitDependencies` только когда у неё не остаётся прямых зависимостей от других транзакций. +Шаг выполнения [PlanQueue](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/plan_queue_unit.cpp#L44) разрешает запуск следующей распределённой транзакции в соответствии с увеличением `(Step, TxId)` и после опциональной загрузки тела транзакции с диска (для персистентных транзакций) QP транзакция финализирует [план выполнения](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/datashard_active_transaction.cpp#L667) и попадает в шаг выполнения [BuildAndWaitDependencies](https://github.com/ydb-platform/ydb/blob/3fa95b9777601584da35d5925d7908f283f671a9/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp#L72). На этом шаге анализируются ключи, которые заявлены для чтения и записи в теле транзакции, на основе которых между транзакциями возникают зависимости. Например, если транзакция `A` пишет по ключу `K`, а более поздняя транзакция `B` читает по ключу `K`, то у транзакции `B` возникает зависимость на транзакцию `A` и транзакция `B` не может быть выполнена до завершения выполнения транзакции `A`. Транзакция выходит из шага `BuildAndWaitDependencies` только когда у неё не остаётся прямых зависимостей от других транзакций. -Перед выполнением персистентная KQP транзакция выполняет фазу чтений с формированием исходящих OutReadSet'ов (шаг [BuildKqpDataTxOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/build_kqp_data_tx_out_rs_unit.cpp#L44)), куда входит в том числе проверка оптимистичных блокировок. Далее на шаге [StoreAndSendOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L42) исходящие OutReadSet'ы и лог проверки блокировок сохраняются на диск. Если блокировки содержали незакомиченные изменения, у них [выставляется флаг `Frozen`](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L67) для предотвращения их отмены до завершения транзакции, в противном случае корректность обеспечивается через правильный порядок выполнения конфликтующих транзакций. Операция, которая формирует исходящие OutReadSet'ы либо проверяет блокировки, [добавляется в `Incomplete` множество](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L79): конфликтующие транзакции должны обеспечить корректность уже произошедших чтений (например, выбирая MVCC версию для новых пишущих операций, которая больше чем версия операции), но при этом новые чтения могут не блокироваться на ожидании завершения этой операции и продолжать читать с версией, которая меньше чем версия операции. +Перед выполнением персистентная QP транзакция выполняет фазу чтений с формированием исходящих OutReadSet'ов (шаг [BuildKqpDataTxOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/build_kqp_data_tx_out_rs_unit.cpp#L44)), куда входит в том числе проверка оптимистичных блокировок. Далее на шаге [StoreAndSendOutRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L42) исходящие OutReadSet'ы и лог проверки блокировок сохраняются на диск. Если блокировки содержали незакомиченные изменения, у них [выставляется флаг `Frozen`](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L67) для предотвращения их отмены до завершения транзакции, в противном случае корректность обеспечивается через правильный порядок выполнения конфликтующих транзакций. Операция, которая формирует исходящие OutReadSet'ы либо проверяет блокировки, [добавляется в `Incomplete` множество](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/store_and_send_out_rs_unit.cpp#L79): конфликтующие транзакции должны обеспечить корректность уже произошедших чтений (например, выбирая MVCC версию для новых пишущих операций, которая больше чем версия операции), но при этом новые чтения могут не блокироваться на ожидании завершения этой операции и продолжать читать с версией, которая меньше чем версия операции. -Наконец, персистентные KQP транзакции подготавливают структуры данных для ожидания входящих InReadSet'ов (шаг [PrepareKqpDataTxInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/prepare_kqp_data_tx_in_rs_unit.cpp#L31)) и переходят к ожиданию всех необходимых ReadSet'ов от других участников (шаг [LoadAndWaitInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/load_and_wait_in_rs_unit.cpp#L36)). В некоторых случаях, например слепая запись в несколько шардов без проверки блокировок, может происходить без обмена ReadSet'ами, и в этом случае шаги по обработки ReadSet'ов ничего не делают и пропускаются. В качестве исключения для волатильных транзакций шаги работы с ReadSet'ами также ничего не делают и пропускаются. +Наконец, персистентные QP транзакции подготавливают структуры данных для ожидания входящих InReadSet'ов (шаг [PrepareKqpDataTxInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/prepare_kqp_data_tx_in_rs_unit.cpp#L31)) и переходят к ожиданию всех необходимых ReadSet'ов от других участников (шаг [LoadAndWaitInRS](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/load_and_wait_in_rs_unit.cpp#L36)). В некоторых случаях, например слепая запись в несколько шардов без проверки блокировок, может происходить без обмена ReadSet'ами, и в этом случае шаги по обработки ReadSet'ов ничего не делают и пропускаются. В качестве исключения для волатильных транзакций шаги работы с ReadSet'ами также ничего не делают и пропускаются. Наконец, операция переходит к фазе выполнения (шаг [ExecuteKqpDataTx](https://github.com/ydb-platform/ydb/blob/6e0ff4ff86f8dd5ac589b83de59c8bb377fe38c5/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L59)), ещё раз проверяет локальные блокировки (на этот раз используя сохранённый ранее `AccessLog`), проверяет ReadSet'ы, полученные от других участников, и в случае успеха выполняет тело транзакции и завершается успешно. Если проверка блокировок (локальных или удалённых) не проходит успешно и обнаруживается конфликт, то операция завершается с ошибкой `ABORTED`. diff --git a/ydb/docs/ru/core/contributor/datashard-locks-and-change-visibility.md b/ydb/docs/ru/core/contributor/datashard-locks-and-change-visibility.md index 58f978c9559..9fa3c424288 100644 --- a/ydb/docs/ru/core/contributor/datashard-locks-and-change-visibility.md +++ b/ydb/docs/ru/core/contributor/datashard-locks-and-change-visibility.md @@ -6,9 +6,9 @@ YQL запросам может требоваться прочитать дан ## Высокоуровневая схема работы -YQL транзакции могут разбиваться на несколько «фаз» в [KQP](https://github.com/ydb-platform/ydb/tree/main/ydb/core/kqp), используя результат одной фазы в качестве входа для последующих фаз. Это происходит либо для «сложных» транзакций, состоящих из нескольких подзапросов, либо «интерактивных», где клиент начинает транзакцию и выполняет запросы без коммита. Например, если YQL запрос содержит `JOIN`, первая фаза может прочитать левую таблицу, а затем во второй фазе использовать этот результат для выполнения точечных чтений по правой таблице. +YQL транзакции могут разбиваться на несколько «фаз» в [Query Processor](https://github.com/ydb-platform/ydb/tree/main/ydb/core/kqp), используя результат одной фазы в качестве входа для последующих фаз. Это происходит либо для «сложных» транзакций, состоящих из нескольких подзапросов, либо «интерактивных», где клиент начинает транзакцию и выполняет запросы без коммита. Например, если YQL запрос содержит `JOIN`, первая фаза может прочитать левую таблицу, а затем во второй фазе использовать этот результат для выполнения точечных чтений по правой таблице. -Для читающих запросов KQP использует глобальный [MVCC](../concepts/mvcc.md) снимок для обеспечения консистентности между подзапросами. Для пишуших запросов нужно также убедиться во время коммита, что [serializable](https://en.wikipedia.org/wiki/Serializability) изоляция не нарушается. Это обеспечивается с помощью [Оптимистического управления параллелизмом](https://en.wikipedia.org/wiki/Optimistic_concurrency_control), где чтения добавляют оптимистические блокировки для прочитанных диапазонов, а запись в других транзакциях «ломает» эти блокировки во время их коммита. Транзакция может успешно закоммититься только если ни одна из её блокировок не была сломана другой транзакцией. В противном случае транзакция завершится с ошибкой «transaction locks invalidated». +Для читающих запросов QP использует глобальный [MVCC](../concepts/mvcc.md) снимок для обеспечения консистентности между подзапросами. Для пишуших запросов нужно также убедиться во время коммита, что [serializable](https://en.wikipedia.org/wiki/Serializability) изоляция не нарушается. Это обеспечивается с помощью [Оптимистического управления параллелизмом](https://en.wikipedia.org/wiki/Optimistic_concurrency_control), где чтения добавляют оптимистические блокировки для прочитанных диапазонов, а запись в других транзакциях «ломает» эти блокировки во время их коммита. Транзакция может успешно закоммититься только если ни одна из её блокировок не была сломана другой транзакцией. В противном случае транзакция завершится с ошибкой «transaction locks invalidated». Транзакция может сделать несколько чтений используя временные метки чтения, пока другие транзакции параллельно пишут в те же таблицы и шарды. Это может быть как один глобальный MVCC снимок, так и несколько временных меток, разные для каждого чтения. Когда транзакция коммитится ей назначается единое время коммита в глобальном порядке выполнения. Если все чтения можно повторить в точке времени коммита, без изменения видимых результатов, такая транзакция могла бы целиком выполниться в точке с временем коммита. Не сломанная оптимистическая блокировка показывает транзакции, что эти чтения можно переместить в более позднюю точку с временем коммита. @@ -16,7 +16,7 @@ YQL транзакции могут разбиваться на нескольк ## Как блокировки используются во время чтений -Подготавливаемым на DataShard'ах операциям обычно назначают глобально уникальный 64-битный `TxId`. Они выделяются достаточно большими батчами с помощью глобальных таблеток [TxAllocator](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/tx_allocator/txallocator.h). Когда KQP начинает первое чтение в многофазной транзакции, он также использует этот `TxId` в качестве идентификатора блокировки `LockTxId`, который в дальнейшем используется во всех запросах в той же YQL транзакции. DataShard добавляет новые блокировки, если в операции указан ненулевой `LockTxId`: +Подготавливаемым на DataShard'ах операциям обычно назначают глобально уникальный 64-битный `TxId`. Они выделяются достаточно большими батчами с помощью глобальных таблеток [TxAllocator](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/tx_allocator/txallocator.h). Когда QP начинает первое чтение в многофазной транзакции, он также использует этот `TxId` в качестве идентификатора блокировки `LockTxId`, который в дальнейшем используется во всех запросах в той же YQL транзакции. DataShard добавляет новые блокировки, если в операции указан ненулевой `LockTxId`: * См. поле [LockTxId](https://github.com/ydb-platform/ydb/blob/3444af692d32224288c41ba8c21e416d5fd4996c/ydb/core/protos/tx_datashard.proto#L1612) в читающих `TEvRead` запросах * См. поле [LockTxId](https://github.com/ydb-platform/ydb/blob/bcf764f1aa71683e3871616abe6f16b47cec42e4/ydb/core/protos/data_events.proto#L83) в пишущих `TEvWrite` запросах @@ -24,7 +24,7 @@ YQL транзакции могут разбиваться на нескольк Также используется поле `LockNodeId`, в котором указывается идентификатор ноды с источником блокировки. DataShard использует это поле для подписки на статус блокировки и зачистки блокировок, которые перестают использоваться. -`LockTxId` — это просто уникальное число, которое используется множеством операций в одной и той же YQL транзакции, в то время как `TxId` уникальный для каждой операции на одном DataShard'е. Использование первого `TxId` в качестве `LockTxId` не обязательно, но т.к. KQP уже получил глобально уникальное число с выделением `TxId`, а `LockTxId` не пересекается с `TxId` по использованию, это экономит аллокацию. +`LockTxId` — это просто уникальное число, которое используется множеством операций в одной и той же YQL транзакции, в то время как `TxId` уникальный для каждой операции на одном DataShard'е. Использование первого `TxId` в качестве `LockTxId` не обязательно, но т.к. QP уже получил глобально уникальное число с выделением `TxId`, а `LockTxId` не пересекается с `TxId` по использованию, это экономит аллокацию. Таблица блокировок (см. [datashard_locks.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/datashard/datashard_locks.h) и [datashard_locks.cpp](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tx/datashard/datashard_locks.cpp)) индексирует блокировки по диапазонам первичного ключа через дерево регионов, позволяя находить и «ломать» их по точечным ключам. В простом случае читающие операции добавляют диапазон с помощью метода [SetLock](https://github.com/ydb-platform/ydb/blob/207ac81618e05ade724a8a8193bc9125d466bd06/ydb/core/tx/datashard/datashard_locks.h#L831), а пишущие операции ломают другие блокировки по записанному ключу используя метод [BreakLocks](https://github.com/ydb-platform/ydb/blob/207ac81618e05ade724a8a8193bc9125d466bd06/ydb/core/tx/datashard/datashard_locks.h#L834). @@ -33,20 +33,20 @@ YQL транзакции могут разбиваться на нескольк В успешном сценарии, когда пока блокировка существует и не сломана, поля `Generation` и `Counter` не меняются. В неуспешных сценариях ранее установленные блокировки инвалидируются. Например, в случае инвалидации блокировки при рестарте изменяется значение `Generation`, а `Counter` может менять при явном статусе ошибки или при инвалидации и пересоздании блокировки в том же поколении. -Первые `Generation` и `Counter` для каждого шарда запоминаются в KQP. Если во время жизни транзакции они изменились, это сигнализируют о неконсистентности и нарушении serializable изоляции. Пишущие транзакции, либо транзакции которые не используют глобальный MVCC снимок для эффективности, проверяют значения `Generation` и `Counter` блокировок при финальный коммите. Коммит может завершиться успехом только если все значения всех блокировок совпадают. +Первые `Generation` и `Counter` для каждого шарда запоминаются в Query Processor. Если во время жизни транзакции они изменились, это сигнализируют о неконсистентности и нарушении serializable изоляции. Пишущие транзакции, либо транзакции которые не используют глобальный MVCC снимок для эффективности, проверяют значения `Generation` и `Counter` блокировок при финальный коммите. Коммит может завершиться успехом только если все значения всех блокировок совпадают. При использовании глобального MVCC снимка все чтения с этим снимком гарантированно консистентны. Тем не менее, они происходят со взятием блокировок на случай, если транзакция в дальнейшем окажется пишущей. DataShard при этом дополнительно проверяет наличие конфликтующих данных, закомиченных поверх читаемого снимка. При обнаружении конфликта, чтение не завершается с ошибкой, однако поле `Counter` блокировки выставляется равным [ErrorAlreadyBroken](https://github.com/ydb-platform/ydb/blob/b07264456a2e8b5929901f258ad60399bb64678a/ydb/core/tx/datashard/sys_tables.h#L107). Это сигнализирует о том, что блокировку взять не удалось и записать что-то в этой транзакции в дальнейшем не получится. Если окажется, что вся транзакция целиком выполняла только чтения, то она завершится успешно. Однако, при любой попытке что-либо записать такая транзакция сразу же завершится с ошибкой, так как коммит будет гарантированно не возможен. ## Как блокировки используются для записи изменений -Когда KQP необходимо сделать незакомиченные изменения в рамках YQL транзакции, в операции записи на DataShard'е также указывается ненулевой `LockTxId`. Помимо установки блокировок DataShard использует этот `LockTxId` в качестве `TxId` для записи незакомиченных изменений. Эти изменения будут храниться пока блокировка остаётся валидной. Блокировки с незакомиченными изменениями называются пишущими блокировками (write locks), а информация по ним сохраняется в специальных таблицах (см. таблицу [Locks](https://github.com/ydb-platform/ydb/blob/5aecdb67595db1a47c933b7d8da2cb662a50e185/ydb/core/tx/datashard/datashard_impl.h#L879) и связанные таблицы ниже), что позволяет им переживать рестарты DataShard'ов. +Когда Query Processor необходимо сделать незакомиченные изменения в рамках YQL транзакции, в операции записи на DataShard'е также указывается ненулевой `LockTxId`. Помимо установки блокировок DataShard использует этот `LockTxId` в качестве `TxId` для записи незакомиченных изменений. Эти изменения будут храниться пока блокировка остаётся валидной. Блокировки с незакомиченными изменениями называются пишущими блокировками (write locks), а информация по ним сохраняется в специальных таблицах (см. таблицу [Locks](https://github.com/ydb-platform/ydb/blob/5aecdb67595db1a47c933b7d8da2cb662a50e185/ydb/core/tx/datashard/datashard_impl.h#L879) и связанные таблицы ниже), что позволяет им переживать рестарты DataShard'ов. При использовании операций записи незакомиченных изменений есть несколько ограничений: * Операция должна выполняться в режиме immediate, таким образом нельзя записать незакомиченные изменения распределённой транзакцией. Вместо этого изменения пишутся независимо на каждый шард. * В операции должен быть указан `LockNodeId` с нодой, через которую DataShard подписывается на статус блокировки и автоматически удаляет изменения, если блокировка пропадает. Например, блокировка пропадает, если транзакция отменяется нештатно или нода с состоянием транзакции не отвечает. * У операции должен быть указан правильный MVCC снимок, который используется для чтений и поиска конфликтов. Ожидается, что в рамках одной YQL транзакции используется один и тот же MVCC снимок во всех операциях чтения и записи. -* Существующая блокировка должна быть валидна и не сломана. В противном случае для указанного `LockTxId` не должно быть уже имеющихся нескомпакченных данных в LocalDB. Это защищает от нештатных ситуаций, когда транзакция отменяется на шарде (например, на основе статуса блокировки), а KQP пытается продолжить в ней писать. +* Существующая блокировка должна быть валидна и не сломана. В противном случае для указанного `LockTxId` не должно быть уже имеющихся нескомпакченных данных в LocalDB. Это защищает от нештатных ситуаций, когда транзакция отменяется на шарде (например, на основе статуса блокировки), а QP пытается продолжить в ней писать. При чтениях YQL транзакция должна указывать тот же `LockTxId`. При этом чтения через LocalDB будут использовать особую карту транзакций, в которой `LockTxId` как-будто уже закоммичен. Это позволяет транзакции видеть собственные изменения, но не изменения других незакомиченных транзакций. В карте транзакций добавляется особая запись `[LockTxId] => v{min}`, позволяя видеть собственные изменения независимо от значения конкретного MVCC снепшота. @@ -87,7 +87,7 @@ YQL транзакции могут разбиваться на нескольк ## Коммит изменений -Для коммита ранее записанных изменений, KQP запускает на шардах транзакцию, которая коммитит ранее захваченные блокировки. У такой транзакции не указывается `LockTxId`, так как такой коммит не захватывает новые блокировки. В списке [Locks](https://github.com/ydb-platform/ydb/blob/b07264456a2e8b5929901f258ad60399bb64678a/ydb/core/protos/tx_datashard.proto#L219) перечисляются все ранее установленные блокировки, а в поле `Op` указывается [Commit](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L26). Сама транзакция коммита на шардах может быть либо immediate (если затрагивает только один шард), либо подготовлена как распределённая транзакция на нескольких участниках. +Для коммита ранее записанных изменений, Query Processor запускает на шардах транзакцию, которая коммитит ранее захваченные блокировки. У такой транзакции не указывается `LockTxId`, так как такой коммит не захватывает новые блокировки. В списке [Locks](https://github.com/ydb-platform/ydb/blob/b07264456a2e8b5929901f258ad60399bb64678a/ydb/core/protos/tx_datashard.proto#L219) перечисляются все ранее установленные блокировки, а в поле `Op` указывается [Commit](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L26). Сама транзакция коммита на шардах может быть либо immediate (если затрагивает только один шард), либо подготовлена как распределённая транзакция на нескольких участниках. Для поддержки распределённых транзакций все шарды, которые проверяют блокировки, включаются в список [SendingShards](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L20), а все шарды, применяющие эффекты, включаются в список [ReceivingShards](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L21). Во время валидации отправляющие шарды подготавливают персистентные readset'ы и отправляют их на все принимающие шарды. Принимающие же шарды после валидации ждут получения readset'ов перед тем как начинать выполнение транзакции. Во время выполнения, в случае если все результаты валидации были успешными, блокировки коммитятся через вызов [KqpCommitLocks](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L228). В противном случае, тело транзакции не выполняется, а блокировка удаляется вместе с отменой всех незакомиченных изменений через вызов [KqpEraseLocks](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/tx/datashard/execute_kqp_data_tx_unit.cpp#L190). Так как в случае ошибки коммита изменения отменяются, отдельно коммит ретраить нельзя. @@ -97,7 +97,7 @@ YQL транзакции могут разбиваться на нескольк {% endnote %} -В транзакции коммита также могут быть дополнительные изменения, которые атомарно применяются сразу после коммита блокировки. Для уменьшения задержек KQP старается аккумулировать изменения в памяти либо до момента их коммита, либо до необходимости чтения этих изменений в той же транзакции. Далее KQP отправляет накопленные изменения вместе с транзацией коммита. В случае, если удаётся накопить все изменения до момента коммита, незакомиченных изменений не происходит, а блокировки при необходимости берутся только на чтение. +В транзакции коммита также могут быть дополнительные изменения, которые атомарно применяются сразу после коммита блокировки. Для уменьшения задержек QP старается аккумулировать изменения в памяти либо до момента их коммита, либо до необходимости чтения этих изменений в той же транзакции. Далее QP отправляет накопленные изменения вместе с транзацией коммита. В случае, если удаётся накопить все изменения до момента коммита, незакомиченных изменений не происходит, а блокировки при необходимости берутся только на чтение. При необходимости явной отмены изменений YQL транзакция запускает пустую транзакцию на шардах с указаем [Rollback](https://github.com/ydb-platform/ydb/blob/d31477e5ed13679dd3b409b100623cc81a5e0964/ydb/core/protos/data_events.proto#L27) в качестве операции блокировки. Если по какой-то причине этого не происходит, при разрушении [TLockHandle](https://github.com/ydb-platform/ydb/blob/0db14d1168517ecacab106e7abfe7af663020829/ydb/core/tx/long_tx_service/public/lock_handle.h#L15) все подписанные даташарды автоматически чистят блокировки через внутреннюю транзакцию [TxRemoveLock](https://github.com/ydb-platform/ydb/blob/0db14d1168517ecacab106e7abfe7af663020829/ydb/core/tx/datashard/remove_locks.cpp#L24). Явная отмена предпочтительна, т.к. незакомиченные изменения потребляют ресурсы и в случае асинхронной очистки через `TLockHandle` нет гарантии, что эти ресурсы освободятся до того, как новые транзакции попытаются записать ещё больше изменений. diff --git a/ydb/docs/ru/core/reference/configuration/memory_controller_config.md b/ydb/docs/ru/core/reference/configuration/memory_controller_config.md index 8b4bf535b73..a8228648826 100644 --- a/ydb/docs/ru/core/reference/configuration/memory_controller_config.md +++ b/ydb/docs/ru/core/reference/configuration/memory_controller_config.md @@ -12,7 +12,7 @@ config: --- sankey-beta -Activity Components,"KQP", 20 +Activity Components,"QP", 20 Activity Components,Compaction, 10 Cache Components,Shared cache, 40 @@ -30,7 +30,7 @@ YDB process memory,Other,10 - [Общий кеш](../../concepts/glossary.md#shared-cache): хранит недавно доступные страницы данных, считанные из [распределённого хранилища](../../concepts/glossary.md#distributed-storage), чтобы уменьшить количество операций ввода-вывода с диска и ускорить получение данных. - [MemTable](../../concepts/glossary.md#memtable): содержит данные, которые ещё не были записаны в [SST](../../concepts/glossary.md#sst). -- [KQP](../../concepts/glossary.md#kqp): хранит промежуточные результаты обработки запросов. +- [Query Processor](../../concepts/glossary.md#kqp): хранит промежуточные результаты обработки запросов. - [Compaction](../../concepts/glossary.md#compaction): процесс упорядочивания и очистки данных, который выполняется автоматически (в «фоновом» режиме) для оптимизации объёма хранения данных. - Кеши аллокатора: хранят блоки памяти, которые были освобождены, но ещё не возвращены операционной системе. @@ -104,7 +104,7 @@ memory_controller_config: К компонентам-активностям относятся: -- KQP; +- Query Processor; - Компактизация. Лимит памяти для каждого из компонентов-активностей указывает максимальное количество памяти, которое он может попытаться использовать. Однако, чтобы предотвратить превышение процессом {{ ydb-short-name }} мягкого лимита памяти, общее потребление компонентов-активностей ограничивается дополнительным лимитом, называемым лимитом памяти для активностей. Если общее использование памяти активными компонентами превышает этот лимит, любые дополнительные запросы на память будут отклонены. Когда выполнение запросов приближается к лимитам памяти, {{ ydb-short-name }} активирует [спиллинг](../../concepts/spilling.md) для временного сохранения промежуточных данных на диск, предотвращая нарушение лимитов памяти. @@ -113,7 +113,7 @@ memory_controller_config: Существуют и другие компоненты-активности, которые в настоящее время не имеют каких-либо индивидуальных лимитов памяти. -Пример секции `memory_controller_config` с указанным лимитом для KQP: +Пример секции `memory_controller_config` с указанным лимитом для QP: ```yaml memory_controller_config: @@ -144,5 +144,5 @@ $Max(shared\_cache\_min\_percent * hard\_limit\_bytes / 100, shared\_cache\_min\ | `shared_cache_max_percent` /<br/>`shared_cache_max_bytes` | 50% | Максимальный порог для лимита памяти общего кеша. | | `mem_table_min_percent` /<br/>`mem_table_min_bytes` | 1% | Минимальный порог для лимита памяти MemTable. | | `mem_table_max_percent` /<br/>`mem_table_max_bytes` | 3% | Максимальный порог для лимита памяти MemTable. | -| `query_execution_limit_percent` /<br/>`query_execution_limit_bytes` | 20% | Лимит памяти для KQP. | +| `query_execution_limit_percent` /<br/>`query_execution_limit_bytes` | 20% | Лимит памяти для QP. | | `compaction_limit_percent` /<br/>`compaction_limit_bytes` | 10% | Лимит памяти для компактизации. | |
