Browse Source

Memory Controller documentation (#7376)

Co-authored-by: Ivan Blinkov <ivan@ydb.tech>
kungurtsev 7 months ago
parent
commit
702825de0b

+ 1 - 1
ydb/docs/en/core/concepts/cluster/_includes/common_scheme_ydb/tablets.md

@@ -12,7 +12,7 @@ User logic is located between the basic tablet and the user and lets you process
 
 ### How does a tablet store data and what are they like? {#storage}
 
-A basic tablet is an LSM tree that holds all of its table data. One level below the basic tablet is BlobStorage that, roughly speaking, is KeyValue storage that stores binary large objects (blobs). *BLOB* is a binary fragment from 1 byte to 10 MB in size, which has a fixed ID (that is usually called *BlobId* and is of the TLogoBlobID type) and contains related data. Storage is immutable, meaning that only one value corresponds to each ID and it cannot change over time. You can write and read a blob and then delete it when you no longer need it.
+A basic tablet is an [LSM tree](../../../glossary.md#lsm-tree) that holds all of its table data. One level below the basic tablet is BlobStorage that, roughly speaking, is KeyValue storage that stores binary large objects (blobs). *BLOB* is a binary fragment from 1 byte to 10 MB in size, which has a fixed ID (that is usually called *BlobId* and is of the TLogoBlobID type) and contains related data. Storage is immutable, meaning that only one value corresponds to each ID and it cannot change over time. You can write and read a blob and then delete it when you no longer need it.
 
 To learn more about blobs and distributed storages, see [here](../../distributed_storage.md).
 

+ 25 - 3
ydb/docs/en/core/concepts/glossary.md

@@ -217,7 +217,7 @@ An **actor system** is a C++ library with {{ ydb-short-name }}'s [implementation
 
 #### Actor service {#actor-service}
 
-An **actor service** is an actor that has a well-known name and is usually run in a single instance on a [node](#node).
+An **actor service** is an [actor](#actor) that has a well-known name and is usually run in a single instance on a [node](#node).
 
 #### ActorId {#actorid}
 
@@ -272,6 +272,20 @@ A **tablet generation** is a number identifying the reincarnation of the tablet
 
 A **tablet local database** or **local database** is a set of data structures and related code that manages the tablet's state and the data it stores. Logically, the local database state is represented by a set of tables very similar to relational tables. Modification of the state of the local database is performed by local tablet transactions generated by the tablet's user actor.
 
+Each local database table is stored using the [LSM tree](#lsm-tree) data structure.
+
+#### Log-structured merge-tree {#lsm-tree}
+
+A **[log-structured merge-tree](https://en.wikipedia.org/wiki/Log-structured_merge-tree)** or **LSM tree**, is a data structure designed to optimize write and read performance in storage systems. It is used in {{ ydb-short-name }} for storing [local database](#local-database) tables and [VDisks](#vdisk) data.
+
+#### MemTable {#memtable}
+
+All data written to a [local database](#local-database) tables is initially stored in an in-memory data structure called a **MemTable**. When the MemTable reaches a predefined size, it is flushed to disk as an immutable [SST](#sst).
+
+#### Sorted string table {#sst}
+
+A **sorted string table** or **SST** is an immutable data structure that stores table rows sorted by key, facilitating efficient key lookups and range queries. Each SST is composed of a contiguous series of small data pages, typically around 7 KiB in size each, which further optimizes the process of reading data from disk. An SST typically represents a part of [LSM tree](#lsm-tree).
+
 #### Tablet pipe {#tablet-pipe}
 
 A **Tablet pipe** or **TabletPipe** is a virtual connection that can be established with a tablet. It includes resolving the [tablet leader](#tablet-leader) by [TabletID](#tabletid). It is the recommended way to work with the tablet. The term **open a pipe to a tablet** describes the process of resolving (searching) a tablet in a cluster and establishing a virtual communication channel with it.
@@ -284,6 +298,14 @@ A **TabletID** is a cluster-wide unique [tablet](#tablet) identifier.
 
 The **bootstrapper** is the primary mechanism for launching tablets, used for service tablets (for example, for [Hive](#hive), [DS controller](#ds-controller), root [SchemeShard](#scheme-shard)). The [Hive](#hive) tablet initializes the rest of the tablets.
 
+### Shared cache {#shared-cache}
+
+A **shared cache** is an [actor](#actor) that stores data pages recently accessed and read from [distributed storage](#distributed-storage). Caching these pages reduces disk I/O operations and accelerates data retrieval, enhancing overall system performance.
+
+### Memory controller {#memory-controller}
+
+A **memory controller** is an [actor](#actor) that manages {{ ydb-short-name }} [memory limits](../deploy/configuration/config.md#memory-controller).
+
 ### Tablet types {#tablet-types}
 
 [Tablets](#tablet) can be considered a framework for building reliable components operating in a distributed system. {{ ydb-short-name }} has multiple components implemented using this framework, listed below.
@@ -353,7 +375,7 @@ Due to its nature, the state storage service operates in a best-effort manner. F
 
 #### Compaction {#compaction}
 
-**Compaction** is the internal background process of rebuilding [LSM tree](https://en.wikipedia.org/wiki/Log-structured_merge-tree) data. The data in [VDisks](#vdisk) and [local databases](#local-database) are organized in the form of an LSM tree. Therefore, there is a distinction between **VDisk compaction** and **Tablet compaction**. The compaction process is usually quite resource-intensive, so efforts are made to minimize the overhead associated with it, for example, by limiting the number of concurrent compactions.
+**Compaction** is the internal background process of rebuilding [LSM tree](#lsm-tree) data. The data in [VDisks](#vdisk) and [local databases](#local-database) are organized in the form of an LSM tree. Therefore, there is a distinction between **VDisk compaction** and **Tablet compaction**. The compaction process is usually quite resource-intensive, so efforts are made to minimize the overhead associated with it, for example, by limiting the number of concurrent compactions.
 
 #### gRPC proxy {#grpc-proxy}
 
@@ -405,7 +427,7 @@ PDisk contains a scheduler that provides device bandwidth sharing between severa
 
 #### Skeleton {#skeleton}
 
-A **Skeleton** is an actor that provides an interface to a [VDisk](#vdisk).
+A **Skeleton** is an [actor](#actor) that provides an interface to a [VDisk](#vdisk).
 
 #### SkeletonFront {#skeletonfront}
 

+ 4 - 4
ydb/docs/en/core/concepts/mvcc.md

@@ -20,7 +20,7 @@ A simple and naive way of adding MVCC to a sorted KV store is to store multiple
 
 ## Why YDB needs MVCC
 
-YDB table shards store data in a sorted KV store, implemented as a write-optimized LSM-tree (Log-Structured Merge-tree), and historically they did not use MVCC. Since the order of transactions is predetermined externally (using Coordinators, somewhat similar to sequencers in the original Calvin paper), YDB heavily relies on reordering transaction execution at each participant, which is correct as long as such reordering cannot be observed externally, and it doesn't change the final outcome. Without MVCC reordering is impeded by read-write conflicts, e.g. when a write cannot start execution until a particularly wide read is complete. With MVCC writes no longer need to wait for conflicting reads to complete, and reads only ever need to wait for preceding conflicting writes to commit. This makes the out-of-order engine's job easier and improves the overall throughput.
+YDB table shards store data in a sorted KV store, implemented as a write-optimized [LSM tree](glossary.md#lsm-tree), and historically they did not use MVCC. Since the order of transactions is predetermined externally (using Coordinators, somewhat similar to sequencers in the original Calvin paper), YDB heavily relies on reordering transaction execution at each participant, which is correct as long as such reordering cannot be observed externally, and it doesn't change the final outcome. Without MVCC reordering is impeded by read-write conflicts, e.g. when a write cannot start execution until a particularly wide read is complete. With MVCC writes no longer need to wait for conflicting reads to complete, and reads only ever need to wait for preceding conflicting writes to commit. This makes the out-of-order engine's job easier and improves the overall throughput.
 
 | Timestamp | Statement | Without MVCC | With MVCC | Description |
 | --- | --- | --- | --- | --- |
@@ -37,9 +37,9 @@ After implementing MVCC using global versions (shared with deterministic distrib
 
 ## How YDB stores MVCC data
 
-DataShard tablets currently store a single table partition in a write-optimized LSM-tree, where for each primary key we store row operation with a set of column updates. During searches, we merge updates from multiple levels and get the final row state. Compactions similarly merge updates from multiple levels and write a resulting aggregate row update.
+DataShard tablets currently store a single table partition in a write-optimized LSM tree, where for each primary key we store row operation with a set of column updates. During searches, we merge updates from multiple levels and get the final row state. Compactions similarly merge updates from multiple levels and write a resulting aggregate row update.
 
-One of our design goals when adding MVCC was minimal degradation to existing workloads, and that meant queries, especially range queries, with the most recent version needed to be fast. That meant using common approaches like adding a version suffix to keys was out of the question. Instead, when a row in an SST (sorted string table, part of an LSM-tree) has multiple versions we only store the most recent version in the main data page, marking it with a flag signaling "history" data is present. Older row versions are stored in a special "history" companion SST, where for each marked row id we store row versions in descending order. When we read from a snapshot, we detect if the most recent row version is too recent, and perform a binary search in the history SST instead. Once we found a row version corresponding to a snapshot we apply its updates to the final row state. We also use the fact that LSM-tree levels roughly correspond to their write time, allowing us to stop searching once the first matching row is found for a given snapshot. For each level below that we only need to apply the most recent row to the final row state, which limits the number of merges to at most the number of levels, which is usually small.
+One of our design goals when adding MVCC was minimal degradation to existing workloads, and that meant queries, especially range queries, with the most recent version needed to be fast. That meant using common approaches like adding a version suffix to keys was out of the question. Instead, when a row in an [SST](glossary.md#sst) (sorted string table, part of an LSM tree) has multiple versions we only store the most recent version in the main data page, marking it with a flag signaling "history" data is present. Older row versions are stored in a special "history" companion SST, where for each marked row id we store row versions in descending order. When we read from a snapshot, we detect if the most recent row version is too recent, and perform a binary search in the history SST instead. Once we found a row version corresponding to a snapshot we apply its updates to the final row state. We also use the fact that LSM tree levels roughly correspond to their write time, allowing us to stop searching once the first matching row is found for a given snapshot. For each level below that we only need to apply the most recent row to the final row state, which limits the number of merges to at most the number of levels, which is usually small.
 
 ![Compacted SSTs](_assets/mvcc_compacted_ssts.png)
 
@@ -47,7 +47,7 @@ Rows in SSTs are effectively deltas, nonetheless, they are stored as pre-merged
 
 ![Search result by version](_assets/mvcc_result_by_version.png)
 
-Eventually, we mark version ranges as deleted and no longer readable, after which compactions allow us to garbage collect unnecessary row versions automatically (unreachable versions are skipped over and not emitted when writing new SSTs). We also store a small per-version histogram for each SST, so we can detect when too much unnecessary data accumulates in the LSM-tree and trigger additional compactions for garbage collection.
+Eventually, we mark version ranges as deleted and no longer readable, after which compactions allow us to garbage collect unnecessary row versions automatically (unreachable versions are skipped over and not emitted when writing new SSTs). We also store a small per-version histogram for each SST, so we can detect when too much unnecessary data accumulates in the LSM tree and trigger additional compactions for garbage collection.
 
 ## How YDB uses MVCC
 

+ 3 - 3
ydb/docs/en/core/contributor/localdb-uncommitted-txs.md

@@ -1,6 +1,6 @@
 # LocalDB: persistent uncommitted changes
 
-Tablets may need to store a potentially large amount of data over a potentially long time, and then either commit or rollback all accumulated changes atomically without keeping them in-memory. To support this [LocalDB](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_database.h) allows table changes to be marked with a unique 64-bit transaction id (TxId), which are stored in the given table alongside committed data, but not visible until the given TxId is committed. The commit or rollback itself is atomic and very cheap, with committed data eventually integrated into the table as if written normally in the first place.
+Tablets may need to store a potentially large amount of data over a potentially long time, and then either commit or rollback all accumulated changes atomically without keeping them in-memory. To support this [LocalDB](../concepts/glossary.md#local-database) allows table changes to be marked with a unique 64-bit transaction id (TxId), which are stored in the given table alongside committed data, but not visible until the given TxId is committed. The commit or rollback itself is atomic and very cheap, with committed data eventually integrated into the table as if written normally in the first place.
 
 This feature is used as a building block for various other features:
 
@@ -26,7 +26,7 @@ Redo log (see [flat_redo_writer.h](https://github.com/ydb-platform/ydb/blob/main
 
 ## Storing uncommitted changes in MemTables
 
-[MemTable](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_mem_warm.h#L180) in LocalDB is a relatively small in-memory sorted tree that maps table keys to values. MemTable value is a chain of MVCC (partial) rows, each tagged with a row version (a pair of Step and TxId which is a global timestamp). Rows are normally pre-merged across the given MemTable. For example, let's suppose there have been the following operations for some key K:
+[MemTable](../concepts/glossary.md#memtable) in LocalDB is a relatively small in-memory sorted tree that maps table keys to values. MemTable value is a chain of MVCC (partial) rows, each tagged with a row version (a pair of Step and TxId which is a global timestamp). Rows are normally pre-merged across the given MemTable. For example, let's suppose there have been the following operations for some key K:
 
 | Version | Operation |
 --- | ---
@@ -86,7 +86,7 @@ Notice how the new record has its state pre-merged, including the previously com
 
 ## Compacting uncommitted changes
 
-Compaction takes some parts from the table, merges them in a sorted order, and writes as a new SST, which replaces compacted data. When compacting MemTable it also implies compacting the relevant redo log, and includes `EvRemoveTx`/`EvCommitTx` events, which affect change visibility and must also end up in persistent storage. LocalDB writes TxStatus blobs (see [flat_page_txstatus.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_txstatus.h)), which store a list of committed and removed transactions, and replace the compacted redo log in regard to `EvRemoveTx`/`EvCommitTx` events. Compaction uses the latest transaction status maps, but it filters them leaving only those transactions that are mentioned in the relevant MemTables or previous TxStatus pages, so that it matches the compacted redo log.
+Compaction takes some parts from the table, merges them in a sorted order, and writes as a new [SST](../concepts/glossary.md#sst), which replaces compacted data. When compacting MemTable it also implies compacting the relevant redo log, and includes `EvRemoveTx`/`EvCommitTx` events, which affect change visibility and must also end up in persistent storage. LocalDB writes TxStatus blobs (see [flat_page_txstatus.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_txstatus.h)), which store a list of committed and removed transactions, and replace the compacted redo log in regard to `EvRemoveTx`/`EvCommitTx` events. Compaction uses the latest transaction status maps, but it filters them leaving only those transactions that are mentioned in the relevant MemTables or previous TxStatus pages, so that it matches the compacted redo log.
 
 Data pages (see [flat_page_data.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_data.h)) store uncommitted deltas from MemTables (or other SSTs) aggregated by their TxId in the same order just before the primary record. Records may have MVCC flags (HasHistory, IsVersioned, IsErased), which specify whether there is MVCC fields and data present. Delta records have an [IsDelta flag](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_page_data.h#L98), which is really a HasHistory flag without other MVCC flags. Since it was never used by previous versions (HasHistory flag was only ever used together with IsVersioned flag, you could not have history rows without a verioned record), it clearly identifies record as an uncommitted delta. Delta records have a [TDelta](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_page_data.h#L66) info immediately after the fixed record data, which specifies TxId of the uncommitted delta.
 

+ 122 - 0
ydb/docs/en/core/deploy/configuration/config.md

@@ -456,6 +456,128 @@ actor_system_config:
 | `progress_threshold` | The actor system supports requesting message sending scheduled for a later point in time. The system might fail to send all scheduled messages at some point. In this case, it starts sending them in "virtual time" by handling message sending in each loop over a period that doesn't exceed the `progress_threshold` value in microseconds and shifting the virtual time by the `progress_threshold` value until it reaches real time. |
 | `resolution` | When making a schedule for sending messages, discrete time slots are used. The slot duration is set by the `resolution` parameter in microseconds. |
 
+## Memory controller {#memory-controller}
+
+There are many components inside {{ ydb-short-name }} [database nodes](../../concepts/glossary.md#database-node) that utilize memory. Most of them need a fixed amount, but some are flexible and can use varying amounts of memory, typically to improve performance. If {{ ydb-short-name }} components allocate more memory than is physically available, the operating system is likely to [terminate](https://en.wikipedia.org/wiki/Out_of_memory#Recovery) the entire {{ ydb-short-name }} process, which is undesirable. The memory controller's goal is to allow {{ ydb-short-name }} to avoid out-of-memory situations while still efficiently using the available memory.
+
+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.
+- Allocator caches: keep memory blocks that have been released but not yet returned to the operating system.
+
+Memory limits can be configured to control overall memory usage, ensuring the database operates efficiently within the available resources.
+
+### Hard memory limit {#hard-memory-limit}
+
+The hard memory limit specifies the total amount of memory available to {{ ydb-short-name }} process.
+
+By default, the hard memory limit for {{ ydb-short-name }} process is set to its [cgroups](https://en.wikipedia.org/wiki/Cgroups) memory limit.
+
+In environments without a cgroups memory limit, the default hard memory limit equals to the host's total available memory. This configuration allows the database to utilize all available resources but may lead to resource competition with other processes on the same host. Although the memory controller attempts to account for this external consumption, such a setup is not recommended.
+
+Additionally, the hard memory limit can be specified in the configuration. Note that the database process may still exceed this limit. Therefore, it is highly recommended to use cgroups memory limits in production environments to enforce strict memory control.
+
+Most of other memory limits can be configured either in absolute bytes or as a percentage relative to the hard memory limit. Using percentages is advantageous for managing clusters with nodes of varying capacities. If both absolute byte and percentage limits are specified, the memory controller uses a combination of both (maximum for lower limits and minimum for upper limits).
+
+Example of the `memory_controller_config` section with a specified hard memory limit:
+
+```yaml
+memory_controller_config:
+  hard_limit_bytes: 16106127360
+```
+
+### Soft memory limit {#soft-memory-limit}
+
+The soft memory limit specifies a dangerous threshold that should not be exceeded by {{ ydb-short-name }} process under normal circumstances.
+
+If the soft limit is exceeded, {{ ydb-short-name }} gradually reduces the [shared cache](../../concepts/glossary.md#shared-cache) size to zero. Therefore, more database nodes should be added to the cluster as soon as possible, or per-component memory limits should be reduced.
+
+### Target memory utilization {#target-memory-utilization}
+
+The target memory utilization specifies a threshold for {{ ydb-short-name }} process memory usage that is considered optimal.
+
+Flexible cache sizes are calculated according to their limit thresholds to keep process consumption around this value.
+
+For example, in a database that consumes a little memory on query execution, caches consume memory around this threshold, and other memory stays free. If query execution consumes more memory, caches start to reduce their sizes to their minimum threshold.
+
+### Per-component memory limits
+
+There are two different types of components within {{ ydb-short-name }}.
+
+The first type, known as cache components, functions as caches, for example, by storing the most recently used data. Each cache component has minimum and maximum memory limit thresholds, allowing them to adjust their capacity dynamically based on the current {{ ydb-short-name }} process consumption.
+
+The second type, known as activity components, allocates memory for specific activities, such as query execution or the [compaction](../../concepts/glossary.md#compaction) process. Each activity component has a fixed memory limit. Additionally, there is a total memory limit for these activities from which they attempt to draw the required memory.
+
+Many other auxiliary components and processes operate alongside the {{ ydb-short-name }} process, consuming memory. Currently, these components do not have any memory limits.
+
+#### Cache components memory limits
+
+The cache components include:
+
+- Shared cache
+- MemTable
+
+Each cache component's limits are dynamically recalculated every second to ensure that each component consumes memory proportionally to its limit thresholds while the total consumed memory stays close to the target memory utilization.
+
+The minimum memory limit threshold for cache components isn't reserved, meaning the memory remains available until it is actually used. However, once this memory is filled, the components typically retain the data, operating within their current memory limit. Consequently, the sum of the minimum memory limits for cache components is expected to be less than the target memory utilization.
+
+If needed, both the minimum and maximum thresholds should be overridden; otherwise, any missing threshold will have a default value.
+
+Example of the `memory_controller_config` section with specified shared cache limits:
+
+```yaml
+memory_controller_config:
+  shared_cache_min_percent: 10
+  shared_cache_max_percent: 30
+```
+
+#### Activity components memory limits
+
+The activity components include:
+
+- KQP
+
+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.
+
+As a result, while the combined individual limits of the activity components might collectively exceed the activities memory limit, each component's individual limit should be less than this overall cap. Additionally, the sum of the minimum memory limits for the cache components, plus the activities memory limit, must be less than the soft memory limit.
+
+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:
+
+```yaml
+memory_controller_config:
+  query_execution_limit_percent: 25
+```
+
+### Configuration parameters
+
+Each configuration parameter applies within the context of a single database node.
+
+As mentioned above, the sum of the minimum memory limits for the cache components plus the activities memory limit should be less than the soft memory limit.
+
+This restriction can be expressed in a simplified form:
+
+$shared\_cache\_min\_percent + mem\_table\_min\_percent + activities\_limit\_percent < soft\_limit\_percent$
+
+Or in a detailed form:
+
+$Max(shared\_cache\_min\_percent * hard\_limit\_bytes / 100, shared\_cache\_min\_bytes) + Max(mem\_table\_min\_percent * hard\_limit\_bytes / 100, mem\_table\_min\_bytes) + Min(activities\_limit\_percent * hard\_limit\_bytes / 100, activities\_limit\_bytes) < Min(soft\_limit\_percent * hard\_limit\_bytes / 100, soft\_limit\_bytes)$
+
+| Parameter | Default | Description |
+| --- | --- | --- |
+| `hard_limit_bytes` | CGroup&nbsp;memory&nbsp;limit&nbsp;/<br/>Host memory | Hard memory usage limit. |
+| `soft_limit_percent`&nbsp;/<br/>`soft_limit_bytes` | 75% | Soft memory usage limit. |
+| `target_utilization_percent`&nbsp;/<br/>`target_utilization_bytes` | 50% | Target memory utilization. |
+| `activities_limit_percent`&nbsp;/<br/>`activities_limit_bytes` | 30% | Activities memory limit. |
+| `shared_cache_min_percent`&nbsp;/<br/>`shared_cache_min_bytes` | 20% | Minimum threshold for the shared cache memory limit. |
+| `shared_cache_max_percent`&nbsp;/<br/>`shared_cache_max_bytes` | 50% | Maximum threshold for the shared cache memory limit. |
+| `mem_table_min_percent`&nbsp;/<br/>`mem_table_min_bytes` | 1% | Minimum threshold for the MemTable memory limit. |
+| `mem_table_max_percent`&nbsp;/<br/>`mem_table_max_bytes` | 3% | Maximum threshold for the MemTable memory limit. |
+| `query_execution_limit_percent`&nbsp;/<br/>`query_execution_limit_bytes` | 20% | KQP memory limit. |
+
 ## blob_storage_config: Static cluster group {#blob-storage-config}
 
 Specify a static cluster group's configuration. A static group is necessary for the operation of the basic cluster tablets, including `Hive`, `SchemeShard`, and `BlobstorageContoller`.

+ 5 - 3
ydb/docs/en/core/maintenance/manual/dynamic-config.md

@@ -125,12 +125,14 @@ This mechanism prevents concurrent configuration modifications and makes updates
 Some system settings are updated without restarting nodes. To change them, upload a new configuration and wait for it to propagate across the cluster.
 
 List of dynamically updated settings:
-* `log_config`
+
 * `immediate_controls_config`
-* `table_service_config`
+* `log_config`
+* `memory_controller_config`
 * `monitoring_config`
-* `tracing_config.sampling`
+* `table_service_config`
 * `tracing_config.external_throttling`
+* `tracing_config.sampling`
 
 The list may be expanded in the future.
 

+ 1 - 1
ydb/docs/ru/core/concepts/cluster/_includes/common_scheme_ydb/tablets.md

@@ -12,7 +12,7 @@
 
 ### Как таблетка хранит данные и какие они {#storage}
 
-Базовая таблетка представляет собой LSM-дерево, в котором находятся все данные ее таблицы. Уровнем ниже базовой таблетки находится BlobStorage, который, грубо говоря, является KeyValue-хранилищем, в котором лежат блобы. *Блоб* -- это бинарный фрагмент размером от 1 байта до 10 мегабайт, который имеет идентификатор фиксированной структуры (обычно он называется *BlobId* и имеет тип TLogoBlobID) и связанные с ним данные. Хранилище иммутабельное, то есть каждому идентификатору соответствует только одно значение, которое не может меняться со временем. Блоб можно записать, прочитать и затем удалить, когда он станет не нужен.
+Базовая таблетка представляет собой [LSM-дерево](../../../glossary.md#lsm-tree), в котором находятся все данные ее таблицы. Уровнем ниже базовой таблетки находится BlobStorage, который, грубо говоря, является KeyValue-хранилищем, в котором лежат блобы. *Блоб* -- это бинарный фрагмент размером от 1 байта до 10 мегабайт, который имеет идентификатор фиксированной структуры (обычно он называется *BlobId* и имеет тип TLogoBlobID) и связанные с ним данные. Хранилище иммутабельное, то есть каждому идентификатору соответствует только одно значение, которое не может меняться со временем. Блоб можно записать, прочитать и затем удалить, когда он станет не нужен.
 
 Подробнее о блобах и распределенном хранилище можно прочитать [здесь](../../distributed_storage.md).
 

+ 26 - 4
ydb/docs/ru/core/concepts/glossary.md

@@ -36,7 +36,7 @@
 
 #### Гибридный узел {#hybrid-mode}
 
-**Гибридный узел** — это процесс, который одновременно выполняет обе роли [узла базы данных](#database-node) и [узла хранения](#storage-node). Гибридные узлы часто используются в целях разработки. Например, вы можете запустить контейнер с полнофункциональным {{ ydb-short-name }}, содержащим только один процесс `ydbd` в гибридном режиме. В производственных средах они используются редко.
+**Гибридный узел** — это процесс, который одновременно выполняет обе роли [узла базы данных](#database-node) и [узла хранения](#storage-node). Гибридные узлы часто используются в целях разработки. Например, вы можете запустить контейнер с полнофункциональным {{ ydb-short-name }}, содержащим только один процесс `ydbd` в гибридном режиме. В производственных окружениях они используются редко.
 
 #### Статический узел {#static-node}
 
@@ -224,7 +224,7 @@
 
 #### Акторный сервис {#actor-service}
 
-**Акторный сервис** или **actor service** — это актор, который имеет известное имя и обычно выполняется в единственном экземпляре на [узле](#node).
+**Акторный сервис** или **actor service** — это [актор](#actor), который имеет известное имя и обычно выполняется в единственном экземпляре на [узле](#node).
 
 #### ActorId {#actorid}
 
@@ -279,6 +279,20 @@
 
 **Локальная база данных таблетки**, **локальная база данных**, **tablet local database** или **local database** — это набор структур данных и связанного кода, которые управляют состоянием таблетки и хранимыми ей данными. Логически состояние локальной базы данных представлено набором таблиц, очень похожих на реляционные таблицы. Модификация состояния локальной базы данных осуществляется локальными транзакциями таблетки, создаваемыми пользовательским актором таблетки.
 
+Каждая таблица локальной базы данных хранится как [LSM-дерево](#lsm-tree).
+
+#### Log-structured merge-tree {#lsm-tree}
+
+**[Log-structured merge-tree](https://ru.wikipedia.org/wiki/LSM-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE)** или **LSM-дерево** — это структура данных, разработанная для оптимизации производительности записи и чтения в системах хранения. Она используется в {{ ydb-short-name }} для хранения таблиц [локальной базы](#local-database) и данных [VDisks](#vdisk).
+
+#### MemTable {#memtable}
+
+Все данные, записанные в таблицы [локальной базы](#local-database), изначально хранятся в структуре данных в оперативной памяти, называемой **MemTable**. Когда MemTable достигает заданного размера, она сбрасывается на диск как неизменяемая структура данных [SST](#sst).
+
+#### Sorted string table {#sst}
+
+**Sorted string table** или **SST** — это неизменяемая структура данных, которая хранит строки таблицы, отсортированные по ключу, что облегчает эффективный поиск ключей и работу с диапазонами ключей. Каждая SST состоит из непрерывной серии маленьких страниц данных, обычно размером около 7 КиБ каждая, что дополнительно оптимизирует процесс чтения данных с диска. Обычно SST представляет собой часть [LSM-дерева](#lsm-tree).
+
 #### Пайп таблетки {#tablet-pipe}
 
 **Пайп таблетки**, **tablet pipe** или **TabletPipe** — это виртуальное соединение, которое может быть установлено с таблеткой. Оно включает поиск [лидера таблетки](#tablet-leader) по [TabletID](#tabletid). Это рекомендуемый способ работы с таблеткой. Термин **открыть пайп к таблетке** описывает процесс разрешения (поиска) таблетки в кластере и установления с ней виртуального канала связи.
@@ -291,6 +305,14 @@
 
 **Bootstrapper** — это основной механизм запуска таблеток, используемый для системных таблеток (например, для [Hive](#hive), [DS controller](#ds-controller), корневого [SchemeShard](#scheme-shard)). [Hive](#hive) инициализирует остальные таблетки.
 
+### Общий кеш {#shared-cache}
+
+**Общий кеш** или **shared cache** — это [актор](#actor), который хранит страницы данных, недавно прочитанные из [распределённого хранилища](#distributed-storage). Кеширование этих страниц снижает количество операций ввода-вывода с диска и ускоряет получение данных, повышая общую производительность системы.
+
+### Контроллер памяти {#memory-controller}
+
+**Контроллер памяти** или **memory controller**— это [актор](#actor), который управляет [лимитами памяти](../deploy/configuration/config.md#memory-controller) {{ ydb-short-name }}.
+
 ### Типы таблеток {#tablet-types}
 
 [Таблетки](#tablet) можно рассматривать как фреймворк для создания надёжных компонентов, работающих в распределённой системе. Многие компоненты {{ ydb-short-name }} реализованы с использованием этого фреймворка, они перечислены ниже.
@@ -360,7 +382,7 @@
 
 #### Компакшн {#compaction}
 
-**Компакшн**, **комактизация** или **compaction** — это внутренний фоновый процесс перестройки данных [дерева LSM](https://en.wikipedia.org/wiki/Log-structured_merge-tree). Данные в [VDisk](#vdisk) и [локальных базах данных](#local-database) организованы в виде LSM-деревьев. Поэтому различают **компакшн VDisk** и **таблеточный компакшн**. Процесс компакшна обычно довольно ресурсоёмкий, поэтому принимаются меры по минимизации накладных расходов, связанных с ним, например, путём ограничения числа одновременно исполняемых компакшнов.
+**Компакшн**, **комактизация** или **compaction** — это внутренний фоновый процесс перестройки данных [LSM-дерева](#lsm-tree). Данные в [VDisk](#vdisk) и [локальных базах данных](#local-database) организованы в виде LSM-деревьев. Поэтому различают **компакшн VDisk** и **таблеточный компакшн**. Процесс компакшна обычно довольно ресурсоёмкий, поэтому принимаются меры по минимизации накладных расходов, связанных с ним, например, путём ограничения числа одновременно исполняемых компакшнов.
 
 #### gRPC-прокси {#grpc-proxy}
 
@@ -412,7 +434,7 @@ PDisk содержит планировщик, который обеспечив
 
 #### Skeleton {#skeleton}
 
-**Skeleton** — это актор, который предоставляет интерфейс к [VDisk](#vdisk).
+**Skeleton** — это [актор](#actor), который предоставляет интерфейс к [VDisk](#vdisk).
 
 #### SkeletonFront {#skeletonfront}
 

File diff suppressed because it is too large
+ 0 - 0
ydb/docs/ru/core/concepts/mvcc.md


+ 3 - 3
ydb/docs/ru/core/contributor/localdb-uncommitted-txs.md

@@ -1,6 +1,6 @@
 # LocalDB: персистентные незакомиченные изменения
 
-Таблеткам может понадобиться сохранять большое количество изменений на протяжении длительного времени, а затем целиком закоммитить или отменить их. Для поддержки этого сценария [LocalDB](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_database.h) позволяет маркировать незакомиченные изменения в таблицах уникальным 64-битным идентификатором транзакции (`TxId`).  Эти данные сохраняются в таблице рядом с закомиченными данными, но не видны для остальных запросов до коммита. Коммит или отмена транзакции атомарная и дешёвая, а со временем эти данные интегрируются в таблицу в обычном закомиченном виде. Таким образом, незакомиченные данные не хранятся в оперативной памяти длительное время и не ограничены её объемом.
+Таблеткам может понадобиться сохранять большое количество изменений на протяжении длительного времени, а затем целиком закоммитить или отменить их. Для поддержки этого сценария [LocalDB](../concepts/glossary.md#local-database) позволяет маркировать незакомиченные изменения в таблицах уникальным 64-битным идентификатором транзакции (`TxId`).  Эти данные сохраняются в таблице рядом с закомиченными данными, но не видны для остальных запросов до коммита. Коммит или отмена транзакции атомарная и дешёвая, а со временем эти данные интегрируются в таблицу в обычном закомиченном виде. Таким образом, незакомиченные данные не хранятся в оперативной памяти длительное время и не ограничены её объемом.
 
 Этот механизм используется в качестве основы для следующей функциональности:
 
@@ -26,7 +26,7 @@
 
 ## Хранение незакомиченных изменений в MemTable
 
-[MemTable](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_mem_warm.h#L180) в LocalDB — это небольшое отсортированное по ключу дерево недавно сделанных изменений, которое хранится в памяти. В качестве ключа в этом дереве используется ключ таблицы, а в качестве значения — указатель на цепочку изменений для соответствующего ключа. Для каждого изменения указывается MVCC версия этого изменения (пара `Step`/`TxId` с глобальным временем коммита). Строки в цепочке изменений смержены в рамках одного MemTable. Например, представим что у нас были следующие операции для ключа K:
+[MemTable](../concepts/glossary.md#memtable) в LocalDB — это небольшое отсортированное по ключу дерево недавно сделанных изменений, которое хранится в памяти. В качестве ключа в этом дереве используется ключ таблицы, а в качестве значения — указатель на цепочку изменений для соответствующего ключа. Для каждого изменения указывается MVCC версия этого изменения (пара `Step`/`TxId` с глобальным временем коммита). Строки в цепочке изменений смержены в рамках одного MemTable. Например, представим что у нас были следующие операции для ключа K:
 
 | Версия | Операция |
 --- | ---
@@ -86,7 +86,7 @@
 
 ## Компакшен незакомиченных изменений
 
-Компакшен берёт часть данных таблицы, мёржит их в отсортированном порядке и пишет в виде новой Sorted String Table (SST), которая заменяет собой скомпакченные данные. Если в компакшене участвует MemTable, то это подразумевает также компакшен части лога изменений. В скомпакшенном логе могут встречаться сообщения `EvRemoveTx`/`EvCommitTx`, которые меняют таблицу закомиченных транзакций — они также должны оказаться в персистентном сторадже. Это реализовано с помощью записи `TxStatus` блобов (см. [flat_page_txstatus.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_txstatus.h)), которые LocalDB сохраняет наравне с записью SST с данными. В этих блобах сохраняется текущий список закомиченных и удалённых транзакций, который заменяют собой весь ранее записанный лог в части `EvRemoveTx`/`EvCommitTx` событий. На вход в компакшен передаётся ссылка на всю текущую таблицу, но во время записи таблица фильтруется, сохраняя только те транзакции, которые упоминались в компактящихся MemTable или предыдущих `TxStatus` страницах.
+Компакшен берёт часть данных таблицы, мёржит их в отсортированном порядке и пишет в виде новой [SST](../concepts/glossary.md#sst), которая заменяет собой скомпакченные данные. Если в компакшене участвует MemTable, то это подразумевает также компакшен части лога изменений. В скомпакшенном логе могут встречаться сообщения `EvRemoveTx`/`EvCommitTx`, которые меняют таблицу закомиченных транзакций — они также должны оказаться в персистентном сторадже. Это реализовано с помощью записи `TxStatus` блобов (см. [flat_page_txstatus.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_txstatus.h)), которые LocalDB сохраняет наравне с записью SST с данными. В этих блобах сохраняется текущий список закомиченных и удалённых транзакций, который заменяют собой весь ранее записанный лог в части `EvRemoveTx`/`EvCommitTx` событий. На вход в компакшен передаётся ссылка на всю текущую таблицу, но во время записи таблица фильтруется, сохраняя только те транзакции, которые упоминались в компактящихся MemTable или предыдущих `TxStatus` страницах.
 
 На уровне страниц с данными (см. [flat_page_data.h](https://github.com/ydb-platform/ydb/blob/main/ydb/core/tablet_flat/flat_page_data.h)) незакомиченные изменения из MemTable (или других SST) агрегируются по `TxId` с сохранением их относительного порядка и добавляются перед основной записью в виде незакомиченных дельта записей. У записи есть MVCC флаги (`HasHistory`, `IsVersioned`, `IsErased`), которые говорят о наличии по ключу MVCC истории и наличии полей с MVCC версией строки. Для дельта записей используется особый [флаг IsDelta](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_page_data.h#L98), который представляет из себя флаг `HasHistory` без указания других MVCC флагов. Для строк с дельта флагом после фиксированной части в полях расширения хранится структура [TDelta](https://github.com/ydb-platform/ydb/blob/0adff98ae52cb826f7fb9705503e430b9812994f/ydb/core/tablet_flat/flat_page_data.h#L66), в которой указывается `TxId` незакомиченной на момент компакшена транзакции.
 

Some files were not shown because too many files changed in this diff