diff --git a/conf.py b/conf.py index e744a54436..4267a42585 100644 --- a/conf.py +++ b/conf.py @@ -62,7 +62,6 @@ 'book/connectors/__*', 'book/replication/*_1.rst', 'book/replication/*_2.rst', - 'book/box/engines/vinyl.rst', 'getting_started/using_package_manager.rst', 'getting_started/using_docker.rst', 'dev_guide/box_protocol.rst', diff --git a/doc/book/box/engines/index.rst b/doc/book/box/engines/index.rst index c9304407b1..c14e047f0a 100644 --- a/doc/book/box/engines/index.rst +++ b/doc/book/box/engines/index.rst @@ -1,44 +1,34 @@ .. _engines-chapter: -******************************************************************************** Storage engines -******************************************************************************** +=============== -A storage engine is a set of very-low-level routines which actually store and -retrieve tuple values. Tarantool offers a choice of two storage engines: +A storage engine is a set of low-level routines which actually store and +retrieve :term:`tuple ` values. Tarantool offers a choice of two storage engines: -* memtx (the in-memory storage engine) is the default and was the first to - arrive. +* :doc:`memtx ` is the in-memory storage engine used by default. +* :doc:`vinyl ` is the on-disk storage engine. -* vinyl (the on-disk storage engine) is a working key-value engine and will - especially appeal to users who like to see data go directly to disk, so that - recovery time might be shorter and database size might be larger. +Below you can find comparing of the two engines in brief. +All the details on how each engine works you can find in the dedicated +sections: - On the other hand, vinyl lacks some functions and options that are available - with memtx. Where that is the case, the relevant description in this manual - contains a note beginning with the words "Note re storage engine". +.. toctree:: + :maxdepth: 1 -Further in this section we discuss the details of storing data using -the vinyl storage engine. - -To specify that the engine should be vinyl, add the clause ``engine = 'vinyl'`` -when creating a space, for example: - -.. code-block:: lua - - space = box.schema.space.create('name', {engine='vinyl'}) + memtx + vinyl .. _vinyl_diff: -================================================================================ -Differences between memtx and vinyl storage engines -================================================================================ +Difference between memtx and vinyl storage engines +-------------------------------------------------- -The primary difference between memtx and vinyl is that memtx is an "in-memory" -engine while vinyl is an "on-disk" engine. An in-memory storage engine is +The primary difference between memtx and vinyl is that memtx is an in-memory +engine while vinyl is an on-disk engine. An in-memory storage engine is generally faster (each query is usually run under 1 ms), and the memtx engine -is justifiably the default for Tarantool, but on-disk engine such as vinyl is -preferable when the database is larger than the available memory and adding more +is justifiably the default for Tarantool. But on-disk engine such as vinyl is +preferable when the database is larger than the available memory, and adding more memory is not a realistic option. .. container:: table @@ -69,5 +59,3 @@ memory is not a realistic option. | yield | Does not yield on the select requests unless the | Yields on the select requests or on its equivalents: | | | transaction is committed to WAL | get() or pairs() | +---------------------------------------------+------------------------------------------------------+------------------------------------------------------+ - -.. include:: vinyl.rst diff --git a/doc/book/box/engines/memtx.rst b/doc/book/box/engines/memtx.rst new file mode 100644 index 0000000000..58b8418485 --- /dev/null +++ b/doc/book/box/engines/memtx.rst @@ -0,0 +1,161 @@ +.. _engines-memtx: + +Storing data with memtx +======================= + +The ``memtx`` storage engine is used in Tarantool by default. It keeps all data in random-access memory (RAM), and therefore has very low read latency. + +The obvious question here is: +if all the data is stored in memory, how can you prevent the data loss in case of emergency such as outage or Tarantool instance failure? + +First of all, Tarantool persists all data changes by writing requests to the write-ahead log (WAL) that is stored on disk. +Read more about that in the :ref:`memtx-persist` section. +In case of a distributed application, there is an option of synchronous replication that ensures keeping the data consistent on a quorum of replicas. +Although replication is not directly a storage engine topic, it is a part of the answer regarding data safety. Read more in the :ref:`memtx-replication` section. + +In this chapter, the following topics are discussed in brief with the references to other chapters that explain the subject matter in details. + +.. contents:: + :local: + :depth: 1 + +.. _memtx-memory: + +Memory model +------------ + +There is a fixed number of independent :ref:`execution threads `. +The threads don't share state. Instead they exchange data using low-overhead message queues. +While this approach limits the number of cores that the instance uses, +it removes competition for the memory bus and ensures peak scalability of memory access and network throughput. + +Only one thread, namely, the **transaction processor thread** (further, **TX thread**) +can access the database, and there is only one TX thread for each Tarantool instance. +In this thread, transactions are executed in a strictly consecutive order. +Multi-statement transactions exist to provide isolation: +each transaction sees a consistent database state and commits all its changes atomically. +At commit time, a yield happens and all transaction changes are written to :ref:`WAL ` in a single batch. +In case of errors during transaction execution, a transaction is rolled-back completely. +Read more in the following sections: :ref:`atomic-transactions`, :ref:`atomic-transactional-manager`. + +Within the TX thread, there is a memory area allocated for Tarantool to store data. It's called **Arena**. + +.. image:: memtx/arena2.svg + +Data is stored in :term:`spaces `. Spaces contain database records—:term:`tuples `. +To access and manipulate the data stored in spaces and tuples, Tarantool builds :doc:`indexes `. + +Special `allocators `__ manage memory allocations for spaces, tuples, and indexes within the Arena. +The slab allocator is the main allocator used to store tuples. +Tarantool has a built-in module called ``box.slab`` which provides the slab allocator statistics +that can be used to monitor the total memory usage and memory fragmentation. +For details, see the ``box.slab`` module :doc:`reference `. + +.. image:: memtx/spaces_indexes.svg + +Also inside the TX thread, there is an event loop. Within the event loop, there are a number of :ref:`fibers `. +Fibers are cooperative primitives that allows interaction with spaces, that is, reading and writting the data. +Fibers can interact with the event loop and between each other directly or by using special primitives called channels. +Due to the usage of fibers and :ref:`cooperative multitasking `, the ``memtx`` engine is lock-free in typical situations. + +.. image:: memtx/fibers-channels.svg + +To interact with external users, there is a separate :ref:`network thread ` also called the **iproto thread**. +The iproto thread receives a request from the network, parses and checks the statement, +and transforms it into a special structure—a message containing an executable statement and its options. +Then the iproto thread ships this message to the TX thread and runs the user's request in a separate fiber. + +.. image:: memtx/iproto.svg + +.. _memtx-persist: + +Data persistence +---------------- + +To ensure :ref:`data persistence `, Tarantool does two things. + +* After executing data change requests in memory, Tarantool writes each such request to the :ref:`write-ahead log (WAL) ` files (``.xlog``) + that are stored on disk. Tarantool does this via a separate thread called the **WAL thread**. + +.. image:: memtx/wal.svg + +* Tarantool periodically takes the entire :doc:`database snapshot ` and saves it on disk. + It is necessary for accelerating instance's restart because when there are too many WAL files, it can be difficult for Tarantool to restart quickly. + + To save a snapshot, there is a special fiber called the **snapshot daemon**. + It reads the consistent content of the entire Arena and writes it on disk into a snapshot file (``.snap``). + Due of the cooperative multitasking, Tarantool cannot write directly on disk because it is a locking operation. + That is why Tarantool interacts with disk via a separate pool of threads from the :doc:`fio ` library. + +.. image:: memtx/snapshot03.svg + +So, even in emergency situations such as an outage or a Tarantool instance failure, +when the in-memory database is lost, the data can be restored fully during Tarantool restart. + +What happens during the restart: + +1. Tarantool finds the latest snapshot file and reads it. +2. Tarantool finds all the WAL files created after that snapshot and reads them as well. +3. When the snapshot and WAL files have been read, there is a fully recovered in-memory data set + corresponding to the state when the Tarantool instance stopped. +4. While reading the snapshot and WAL files, Tarantool is building the primary indexes. +5. When all the data is in memory again, Tarantool is building the secondary indexes. +6. Tarantool runs the application. + +.. _memtx-indexes: + +Accessing data +-------------- + +To access and manipulate the data stored in memory, Tarantool builds indexes. +Indexes are also stored in memory within the Arena. + +Tarantool supports a number of :ref:`index types ` intended for different usage scenarios. +The possible types are TREE, HASH, BITSET, and RTREE. + +Select query are possible against secondary index keys as well as primary keys. +Indexes can have multi-part keys. + +For detailed information about indexes, refer to the :doc:`/book/box/indexes` page. + +.. _memtx-replication: + +Replicating data +---------------- + +Although this topic is not directly related to the ``memtx`` engine, it completes the overall picture of how Tarantool works in case of a distributed application. + +Replication allows multiple Tarantool instances to work on copies of the same database. +The copies are kept in sync because each instance can communicate its changes to all the other instances. +It is implemented via WAL replication. + +To send data to a replica, Tarantool runs another thread called **relay**. +Its purpose is to read the WAL files and send them to replicas. +On a replica, the fiber called **applier** is run. It receives the changes from a remote node and applies them to the replica's Arena. +All the changes are being written to WAL files via the replica's WAL thread as if they are done locally. + +.. image:: memtx/replica-xlogs.svg + +By default, :ref:`replication ` in Tarantool is asynchronous: if a transaction +is committed locally on a master node, it does not mean it is replicated onto any +replicas. + +:ref:`Synchronous replication ` exists to solve this problem. Synchronous transactions +are not considered committed and are not responded to a client until they are +replicated onto some number of replicas. + +For more information on replication, refer to the :doc:`corresponding chapter `. + +.. _memtx-summary: + +Summary +-------- + +The main key points describing how the in-memory storage engine works can be summarized in the following way: + +* All data is in RAM. +* Access to data is from one thread. +* Tarantool writes all data change requests in WAL. +* Data snapshots are taken periodically. +* Indexes are build to access the data. +* WAL can be replicated. diff --git a/doc/book/box/engines/memtx/arena2.svg b/doc/book/box/engines/memtx/arena2.svg new file mode 100644 index 0000000000..ebca26d03b --- /dev/null +++ b/doc/book/box/engines/memtx/arena2.svg @@ -0,0 +1,3 @@ + + +T
TX
thread
TX...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/doc/book/box/engines/memtx/fibers-channels.svg b/doc/book/box/engines/memtx/fibers-channels.svg new file mode 100644 index 0000000000..3dc76102d7 --- /dev/null +++ b/doc/book/box/engines/memtx/fibers-channels.svg @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + fio + + + + + + + + + + snapshot + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/box/engines/memtx/iproto.svg b/doc/book/box/engines/memtx/iproto.svg new file mode 100644 index 0000000000..0564ceaa1a --- /dev/null +++ b/doc/book/box/engines/memtx/iproto.svg @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + fio + + + + + + + + + + snapshot + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/box/engines/memtx/replica-xlogs.svg b/doc/book/box/engines/memtx/replica-xlogs.svg new file mode 100644 index 0000000000..de3dbf98bd --- /dev/null +++ b/doc/book/box/engines/memtx/replica-xlogs.svg @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snapshot + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + + fio + + + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + diff --git a/doc/book/box/engines/memtx/snapshot03.svg b/doc/book/box/engines/memtx/snapshot03.svg new file mode 100644 index 0000000000..2230404040 --- /dev/null +++ b/doc/book/box/engines/memtx/snapshot03.svg @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snapshot + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + + fio + + + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/box/engines/memtx/spaces_indexes.svg b/doc/book/box/engines/memtx/spaces_indexes.svg new file mode 100644 index 0000000000..c488bcb6f6 --- /dev/null +++ b/doc/book/box/engines/memtx/spaces_indexes.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + fio + + + + + + + + + + snapshot + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/box/engines/memtx/wal.svg b/doc/book/box/engines/memtx/wal.svg new file mode 100644 index 0000000000..655914b6ac --- /dev/null +++ b/doc/book/box/engines/memtx/wal.svg @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + TX + + + + + + Arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPROTO + + + + + + + + + + + + EV + + + + + + + f + + + + + + f + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snap + + + daemon + + + + + + + + + + fio + + + + + + + + + + snapshot + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + RELAY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + applier + + + + + + + + + IPROTO + + + + + + + + + + WAL + + + + + + + xlog + + + + + + + xlog + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/box/indexes.rst b/doc/book/box/indexes.rst index d2654358b7..1b27a3dd9f 100644 --- a/doc/book/box/indexes.rst +++ b/doc/book/box/indexes.rst @@ -251,6 +251,8 @@ then it also changes the index keys defined for the tuple. restrictions. Read more about index operations in reference for :doc:`box.index submodule `. +.. _index-types: + -------------------------------------------------------------------------------- Index types -------------------------------------------------------------------------------- diff --git a/locale/ru/LC_MESSAGES/book/box/engines/index.po b/locale/ru/LC_MESSAGES/book/box/engines/index.po index 37a874258e..cd5b874343 100644 --- a/locale/ru/LC_MESSAGES/book/box/engines/index.po +++ b/locale/ru/LC_MESSAGES/book/box/engines/index.po @@ -3,75 +3,46 @@ msgid "Storage engines" msgstr "Движки базы данных" msgid "" -"A storage engine is a set of very-low-level routines which actually store " -"and retrieve tuple values. Tarantool offers a choice of two storage engines:" +"A storage engine is a set of low-level routines which actually store and " +"retrieve :term:`tuple ` values. Tarantool offers a choice of two " +"storage engines:" msgstr "" -"Движок базы данных представляет собой набор очень низкоуровневых процессов, " -"которые фактически хранят и получают значения в кортежах. Tarantool " -"предлагает два движка базы данных на выбор:" +"Движок базы данных — это набор низкоуровневых процессов, которые фактически " +"хранят и получают значения :term:`кортежей `. Tarantool предлагает " +"выбор из двух движков базы данных:" -msgid "" -"memtx (the in-memory storage engine) is the default and was the first to " -"arrive." -msgstr "" -"memtx (in-memory движок базы данных) используется по умолчанию, который был " -"первым." - -msgid "" -"vinyl (the on-disk storage engine) is a working key-value engine and will " -"especially appeal to users who like to see data go directly to disk, so that" -" recovery time might be shorter and database size might be larger." -msgstr "" -"vinyl (движок для хранения данных на диске) -- это рабочий движок на основе " -"пар ключ-значение, который особенно понравится пользователям, предпочитающим" -" записывать данные напрямую на диск, чтобы сократить время восстановления и " -"увеличить размер базы данных." - -msgid "" -"On the other hand, vinyl lacks some functions and options that are available" -" with memtx. Where that is the case, the relevant description in this manual" -" contains a note beginning with the words \"Note re storage engine\"." +msgid ":doc:`memtx ` is the in-memory storage engine used by default." msgstr "" -"С другой стороны, vinyl'у не хватает некоторых функций и параметров, " -"доступных в memtx'е. В соответствующих случаях дается дополнительное " -"описание в виде примечания, которое начинается со слов **Примечание про " -"движок базы данных**." +":doc:`memtx ` — in-memory движок базы данных, используемый по " +"умолчанию." -msgid "" -"Further in this section we discuss the details of storing data using the " -"vinyl storage engine." -msgstr "" -"Далее в разделе рассмотрим подробнее метод хранения данных с помощью движка " -"базы данных vinyl." +msgid ":doc:`vinyl ` is the on-disk storage engine." +msgstr ":doc:`vinyl ` — дисковый движок базы данных." msgid "" -"To specify that the engine should be vinyl, add the clause ``engine = " -"'vinyl'`` when creating a space, for example:" +"Below you can find comparing of the two engines in brief. All the details on" +" how each engine works you can find in the dedicated sections:" msgstr "" -"Чтобы указать, что следует использовать именно vinyl, необходимо при " -"создании спейса добавить оператор ``engine = 'vinyl'``, например:" - -msgid "space = box.schema.space.create('name', {engine='vinyl'})" -msgstr "space = box.schema.space.create('name', {engine='vinyl'})" +"Ниже вы можете найти краткое сравнение этих двух движков. Все подробности о " +"том, как работает каждый движок, вы можете найти в следующих разделах:" -msgid "Differences between memtx and vinyl storage engines" -msgstr "Различия между движками memtx и vinyl" +msgid "Difference between memtx and vinyl storage engines" +msgstr "Различие между движками memtx и vinyl" msgid "" -"The primary difference between memtx and vinyl is that memtx is an \"in-" -"memory\" engine while vinyl is an \"on-disk\" engine. An in-memory storage " -"engine is generally faster (each query is usually run under 1 ms), and the " -"memtx engine is justifiably the default for Tarantool, but on-disk engine " -"such as vinyl is preferable when the database is larger than the available " -"memory and adding more memory is not a realistic option." +"The primary difference between memtx and vinyl is that memtx is an in-memory" +" engine while vinyl is an on-disk engine. An in-memory storage engine is " +"generally faster (each query is usually run under 1 ms), and the memtx " +"engine is justifiably the default for Tarantool. But on-disk engine such as " +"vinyl is preferable when the database is larger than the available memory, " +"and adding more memory is not a realistic option." msgstr "" -"Основным различием между движками memtx и vinyl является то, что memtx " -"представляет собой \"in-memory\" движок, тогда как vinyl -- это \"дисковый\"" -" движок. Как правило, in-memory движок быстрее (каждый запрос обычно " -"выполняется меньше, чем за 1 мс), и движок memtx по праву используется в " -"Tarantool по умолчанию, но если база данных больше объема доступной памяти, " -"а добавление дополнительной памяти не представляется возможным, " -"рекомендуется использовать дисковый движок, то есть vinyl." +"Основное различие между движками memtx и vinyl в том, что memtx — in-memory " +"движок, тогда как vinyl — это дисковый движок. Обычно in-memory движок " +"быстрее: время выполнения запроса, как правило, менее 1 мс. Поэтому движок " +"memtx используется в Tarantool по умолчанию. Однако если база данных не " +"помещается в доступную память, а дополнительную память добавить невозможно, " +"то лучше использовать дисковый движок, в данном случае vinyl." msgid "Option" msgstr "Характеристика" @@ -151,1477 +122,3 @@ msgstr "" msgid "Yields on the select requests or on its equivalents: get() or pairs()" msgstr "" "Передает управление на запросах выборки или аналогичных: get() или pairs()" - -msgid "Storing data with vinyl" -msgstr "Хранение данных с помощью vinyl" - -msgid "" -"Tarantool is a transactional and persistent DBMS that maintains 100% of its " -"data in RAM. The greatest advantages of in-memory databases are their speed " -"and ease of use: they demonstrate consistently high performance, but you " -"never need to tune them." -msgstr "" -"Tarantool -- это транзакционная, персистентная СУБД, которая хранит 100% " -"данных в оперативной памяти. Основными преимущества хранения данных " -"оперативной памяти являются скорость и простота использования: нет " -"необходимости в оптимизации, однако производительность остается стабильно " -"высокой." - -msgid "" -"A few years ago we decided to extend the product by implementing a classical" -" storage engine similar to those used by regular DBMSs: it uses RAM for " -"caching, while the bulk of its data is stored on disk. We decided to make it" -" possible to set a storage engine independently for each table in the " -"database, which is the same way that MySQL approaches it, but we also wanted" -" to support transactions from the very beginning." -msgstr "" -"Несколько лет назад мы решили расширить продукт путем реализации " -"классической технологии хранения как в обычных СУБД: в оперативной памяти " -"хранится лишь кэш данных, а основной объем данных находится на диске. Мы " -"решили, что движок хранения можно будет выбирать независимо для каждой " -"таблицы, как это реализовано в MySQL, но при этом с самого начала будет " -"реализована поддержка транзакций." - -msgid "" -"The first question we needed to answer was whether to create our own storage" -" engine or use an existing library. The open-source community offered a few " -"viable solutions. The RocksDB library was the fastest growing open-source " -"library and is currently one of the most prominent out there. There were " -"also several lesser-known libraries to consider, such as WiredTiger, " -"ForestDB, NestDB, and LMDB." -msgstr "" -"Первый вопрос, на который нужен был ответ: создавать свой движок или " -"использовать уже существующую библиотеку? Сообщество разработчиков открытого" -" ПО предлагает готовые библиотеки на выбор. Активнее всего развивалась " -"библиотека RocksDB, которая к настоящему времени стала одной из самых " -"популярных. Есть также несколько менее известных библиотек: WiredTiger, " -"ForestDB, NestDB, LMDB." - -msgid "" -"Nevertheless, after studying the source code of existing libraries and " -"considering the pros and cons, we opted for our own storage engine. One " -"reason is that the existing third-party libraries expected requests to come " -"from multiple operating system threads and thus contained complex " -"synchronization primitives for controlling parallel data access. If we had " -"decided to embed one of these in Tarantool, we would have made our users " -"bear the overhead of a multithreaded application without getting anything in" -" return. The thing is, Tarantool has an actor-based architecture. The way it" -" processes transactions in a dedicated thread allows it to do away with the " -"unnecessary locks, interprocess communication, and other overhead that " -"accounts for up to 80% of processor time in multithreaded DBMSs." -msgstr "" -"Тем не менее, изучив исходный код существующих библиотек и взвесив все " -"\"за\" и \"против\", мы решили написать свой движок. Одна из причин -- все " -"существующие сторонние библиотеки предполагают, что запросы к данным могут " -"поступать из множества потоков операционной системы, и поэтому содержат " -"сложные примитивы синхронизации для управления одновременным доступом к " -"данным. Если бы мы решили встраивать одну из них в Tarantool, то " -"пользователи были бы вынуждены нести издержки многопоточных приложений, не " -"получая ничего взамен. Дело в том, что в основе Tarantool лежит архитектура " -"на основе акторов. Обработка транзакций в выделенном потоке позволяет " -"обойтись без лишних блокировок, межпроцессного взаимодействия и других " -"затрат ресурсов, которые забирают до 80% процессорного времени в " -"многопоточных СУБД." - -msgid "*The Tarantool process consists of a fixed number of \"actor\" threads*" -msgstr "*Процесс в Tarantool состоит из заданного количества потоков*" - -msgid "" -"If you design a database engine with cooperative multitasking in mind right " -"from the start, it not only significantly speeds up the development process," -" but also allows the implementation of certain optimization tricks that " -"would be too complex for multithreaded engines. In short, using a third-" -"party solution wouldn’t have yielded the best result." -msgstr "" -"Если изначально проектировать движок с учетом кооперативной многозадачности," -" можно не только существенно ускорить работу, но и реализовать приемы " -"оптимизации, слишком сложные для многопоточных движков. В общем, " -"использование стороннего решения не привело бы к лучшему результату." - -msgid "Algorithm" -msgstr "Алгоритм" - -msgid "" -"Once the idea of using an existing library was off the table, we needed to " -"pick an architecture to build upon. There are two competing approaches to " -"on-disk data storage: the older one relies on B-trees and their variations; " -"the newer one advocates the use of log-structured merge-trees, or \"LSM\" " -"trees. MySQL, PostgreSQL, and Oracle use B-trees, while Cassandra, MongoDB, " -"and CockroachDB have adopted LSM trees." -msgstr "" -"Отказавшись от идеи внедрения существующих библиотек, необходимо было " -"выбрать архитектуру для использования в качестве основы. Есть два " -"альтернативных подхода к хранению данных на диске: старая модель с " -"использованием B-деревьев и их разновидностей и новая -- на основе " -"журнально-структурированных деревьев со слиянием, или LSM-деревьев (Log " -"Structured Merge Tree). MySQL, PostgreSQL и Oracle используют B-деревья, а " -"Cassandra, MongoDB и CockroachDB уже используют LSM-деревья." - -msgid "" -"B-trees are considered better suited for reads and LSM trees—for writes. " -"However, with SSDs becoming more widespread and the fact that SSDs have read" -" throughput that’s several times greater than write throughput, the " -"advantages of LSM trees in most scenarios was more obvious to us." -msgstr "" -"Считается, что B-деревья более эффективны для чтения, а LSM-деревья -- для " -"записи. Тем не менее, с распространением SSD-дисков, у которых в несколько " -"раз выше производительность чтения по сравнению с производительностью " -"записи, преимущества LSM-деревьев стали очевидны в большинстве сценариев." - -msgid "" -"Before dissecting LSM trees in Tarantool, let’s take a look at how they " -"work. To do that, we’ll begin by analyzing a regular B-tree and the issues " -"it faces. A B-tree is a balanced tree made up of blocks, which contain " -"sorted lists of key- value pairs. (Topics such as filling and balancing a " -"B-tree or splitting and merging blocks are outside of the scope of this " -"article and can easily be found on Wikipedia). As a result, we get a " -"container sorted by key, where the smallest element is stored in the " -"leftmost node and the largest one in the rightmost node. Let’s have a look " -"at how insertions and searches in a B-tree happen." -msgstr "" -"Прежде чем разбираться с LSM-деревьями в Tarantool'е, посмотрим, как они " -"работают. Для этого разберем устройство обычного B-дерева и связанные с ним " -"проблемы. \"B\" в слове B-tree означает \"Block\", то есть это " -"сбалансированное дерево, состоящее из блоков, которые содержат " -"отсортированные списки пар ключ-значение. Вопросы наполнения дерева, " -"балансировки, разбиения и слияния блоков выходят за рамки данной статьи, " -"подробности вы сможете прочитать в Википедии. В итоге мы получаем " -"отсортированный по возрастанию ключа контейнер, минимальный элемент которого" -" хранится в крайнем левом узле, а максимальный -- в крайнем правом. " -"Посмотрим, как в B-дереве осуществляется поиск и вставка данных." - -msgid "*Classical B-tree*" -msgstr "*Классическое B-дерево*" - -msgid "" -"If you need to find an element or check its membership, the search starts at" -" the root, as usual. If the key is found in the root block, the search " -"stops; otherwise, the search visits the rightmost block holding the largest " -"element that’s not larger than the key being searched (recall that elements " -"at each level are sorted). If the first level yields no results, the search " -"proceeds to the next level. Finally, the search ends up in one of the leaves" -" and probably locates the needed key. Blocks are stored and read into RAM " -"one by one, meaning the algorithm reads :math:`logB(N)` blocks in a single " -"search, where N is the number of elements in the B-tree. In the simplest " -"case, writes are done similarly: the algorithm finds the block that holds " -"the necessary element and updates (inserts) its value." -msgstr "" -"Если необходимо найти элемент или проверить его наличие, поиск начинается, " -"как обычно, с вершины. Если ключ обнаружен в корневом блоке, поиск " -"заканчивается; в противном случае, переходим в блок с наибольшим меньшим " -"ключом, то есть в самый правый блок, в котором еще есть элементы меньше " -"искомого (элементы на всех уровнях расположены по возрастанию). Если и там " -"элемент не найден, снова переходим на уровень ниже. В конце концов окажемся " -"в одном из листьев и, возможно, обнаружим искомый элемент. Блоки дерева " -"хранятся на диске и читаются в оперативную память по одному, то есть в " -"рамках одного поиска алгоритм считывает :math:`logB(N)` блоков, где N -- это" -" количество элементов в B-дереве. Запись в самом простом случае " -"осуществляется аналогично: алгоритм находит блок, который содержит " -"необходимый элемент, и обновляет (вставляет) его значение." - -msgid "" -"To better understand the data structure, let’s consider a practical example:" -" say we have a B-tree with 100,000,000 nodes, a block size of 4096 bytes, " -"and an element size of 100 bytes. Thus each block will hold up to 40 " -"elements (all overhead considered), and the B-tree will consist of around " -"2,570,000 blocks and 5 levels: the first four will have a size of 256 Mb, " -"while the last one will grow up to 10 Gb. Obviously, any modern computer " -"will be able to store all of the levels except the last one in filesystem " -"cache, so read requests will require just a single I/O operation." -msgstr "" -"Чтобы наглядно представить себе эту структуру данных, возьмем B-дерево на " -"100 000 000 узлов и предположим, что размер блока равен 4096 байтов, а " -"размер элемента -- 100 байтов. Таким образом, в каждом блоке можно будет " -"разместить до 40 элементов с учетом накладных расходов, а в B-дереве будет " -"около 2 570 000 блоков, пять уровней, при этом первые четыре займут по 256 " -"МБ, а последний -- до 10 ГБ. Очевидно, что на любом современном компьютере " -"все уровни, кроме последнего, успешно попадут в кэш файловой системы, и " -"фактически любая операция чтения будет требовать не более одной операции " -"ввода-вывода." - -msgid "" -"But if we change our perspective —B-trees don’t look so good anymore. " -"Suppose we need to update a single element. Since working with B-trees " -"involves reading and writing whole blocks, we would have to read in one " -"whole block, change our 100 bytes out of 4096, and then write the whole " -"updated block to disk. In other words,we were forced to write 40 times more " -"data than we actually modified!" -msgstr "" -"Ситуация выглядит существенно менее радужно при смене точки зрения. " -"Предположим, что необходимо обновить один элемент дерева. Так как операции с" -" B-деревьями работают через чтение и запись целых блоков, приходится " -"прочитать 1 блок в память, изменить 100 байт из 4096, а затем записать " -"обновленный блок на диск. Таким образом, нам пришлось записать в 40 раз " -"больше, чем реальный объем измененных данных!" - -msgid "" -"If you take into account the fact that an SSD block has a size of 64 Kb+ and" -" not every modification changes a whole element, the extra disk workload can" -" be greater still." -msgstr "" -"Принимая во внимание, что внутренний размер блока в SSD-дисках может быть 64" -" КБ и больше, и не любое изменение элемента меняет его целиком, объем " -"\"паразитной\" нагрузки на диск может быть еще выше." - -msgid "" -"Authors of specialized literature and blogs dedicated to on-disk data " -"storage have coined two terms for these phenomena: extra reads are referred " -"to as \"read amplification\" and writes as \"write amplification\"." -msgstr "" -"Феномен таких \"паразитных\" чтений в литературе и блогах, посвященных " -"хранению на диске, называется read amplification (усложнение чтения), а " -"феномен \"паразитной\" записи -- write amplification (усложнение записи)." - -msgid "" -"The amplification factor (multiplication coefficient) is calculated as the " -"ratio of the size of actual read (or written) data to the size of data " -"needed (or actually changed). In our B-tree example, the amplification " -"factor would be around 40 for both reads and writes." -msgstr "" -"Коэффициент усложнения, то есть коэффициент умножения, вычисляется как " -"отношение размера фактически прочитанных (или записанных) данных к реально " -"необходимому (или измененному) размеру. В нашем примере с B-деревом " -"коэффициент составит около 40 как для чтения, так и для записи." - -msgid "" -"The huge number of extra I/O operations associated with updating data is one" -" of the main issues addressed by LSM trees. Let’s see how they work." -msgstr "" -"Объем \"паразитных\" операций ввода-вывода при обновлении данных является " -"одной из основных проблем, которую решают LSM-деревья. Рассмотрим, как это " -"работает." - -msgid "" -"The key difference between LSM trees and regular B-trees is that LSM trees " -"don’t just store data (keys and values), but also data operations: " -"insertions and deletions." -msgstr "" -"Ключевое отличие LSM-деревьев от классических B-деревьев заключается в том, " -"что LSM-деревья не просто хранят данные (ключи и значения), а также операции" -" с данными: вставки и удаления." - -msgid "|br|" -msgstr "|br|" - -msgid "LSM tree:" -msgstr "LSM-дерево:" - -msgid "Stores statements, not values:" -msgstr "Хранит операторы, а не значения:" - -msgid "REPLACE" -msgstr "REPLACE" - -msgid "DELETE" -msgstr "DELETE" - -msgid "UPSERT" -msgstr "UPSERT" - -msgid "" -"Every statement is marked by LSN Append-only files, garbage is collected " -"after a checkpoint" -msgstr "" -"Для каждого оператора назначается LSN Обновление файлов происходит только " -"путем присоединения новых записей, сборка мусора проводится после " -"контрольной точки" - -msgid "Transactional log of all filesystem changes: vylog" -msgstr "Журнал транзакций при любых изменениях в системе: vylog" - -msgid "" -"For example, an element corresponding to an insertion operation has, apart " -"from a key and a value, an extra byte with an operation code (\"REPLACE\" in" -" the image above). An element representing the deletion operation contains a" -" key (since storing a value is unnecessary) and the corresponding operation " -"code—\"DELETE\". Also, each LSM tree element has a log sequence number " -"(LSN), which is the value of a monotonically increasing sequence that " -"uniquely identifies each operation. The whole tree is first ordered by key " -"in ascending order, and then, within a single key scope, by LSN in " -"descending order." -msgstr "" -"Например, элемент для операции вставки, помимо ключа и значения, содержит " -"дополнительный байт с кодом операции -- обозначенный выше как REPLACE. " -"Элемент для операции удаления содержит ключ элемента (хранить значение нет " -"необходимости) и соответствующий код операции -- DELETE. Также каждый " -"элемент LSM-дерева содержит порядковый номер операции (log sequence number " -"-- LSN), то есть значение монотонно возрастающей последовательности, которое" -" уникально идентифицирует каждую операцию. Таким образом, всё дерево " -"упорядочено сначала по возрастанию ключа, а в пределах одного ключа -- по " -"убыванию LSN." - -msgid "*A single level of an LSM tree*" -msgstr "*Один уровень LSM-дерева*" - -msgid "Filling an LSM tree" -msgstr "Наполнение LSM-дерева" - -msgid "" -"Unlike a B-tree, which is stored completely on disk and can be partly cached" -" in RAM, when using an LSM tree, memory is explicitly separated from disk " -"right from the start. The issue of volatile memory and data persistence is " -"beyond the scope of the storage algorithm and can be solved in various " -"ways—for example, by logging changes." -msgstr "" -"В отличие от B-дерева, которое полностью хранится на диске и может частично " -"кэшироваться в оперативной памяти, в LSM-дереве разделение между памятью и " -"диском явно присутствует с самого начала. При этом проблема сохранности " -"данных, расположенных в энергозависимой памяти, выносится за рамки алгоритма" -" хранения: ее можно решить разными способами, например, журналированием " -"изменений." - -msgid "" -"The part of an LSM tree that’s stored in RAM is called L0 (level zero). The " -"size of RAM is limited, so L0 is allocated a fixed amount of memory. For " -"example, in Tarantool, the L0 size is controlled by the ``vinyl_memory`` " -"parameter. Initially, when an LSM tree is empty, operations are written to " -"L0. Recall that all elements are ordered by key in ascending order, and then" -" within a single key scope, by LSN in descending order, so when a new value " -"associated with a given key gets inserted, it’s easy to locate the older " -"value and delete it. L0 can be structured as any container capable of " -"storing a sorted sequence of elements. For example, in Tarantool, L0 is " -"implemented as a B+*-tree. Lookups and insertions are standard operations " -"for the data structure underlying L0, so I won’t dwell on those." -msgstr "" -"Часть дерева, расположенную в оперативной памяти, называют L0 (level zero --" -" уровень ноль). Объем оперативной памяти ограничен, поэтому для L0 отводится" -" фиксированная область. В конфигурации Tarantool'а, например, размер L0 " -"задается с помощью параметра ``vinyl_memory``. В начале, когда LSM-дерево не" -" содержит элементов, операции записываются в L0. Следует отметить, что " -"элементы в дереве упорядочены по возрастанию ключа, а затем по убыванию LSN," -" так что в случае вставки нового значения по данному ключу легко обнаружить " -"и удалить предыдущее значение. L0 может быть представлен любым контейнером, " -"который сохраняет упорядоченность элементов. Например, для хранения L0 " -"Tarantool использует B+*-дерево. Операции поиска и вставки -- это " -"стандартные операции структуры данных, используемой для представления L0, и " -"мы их подробно рассматривать не будем." - -msgid "" -"Sooner or later the number of elements in an LSM tree exceeds the L0 size " -"and that’s when L0 gets written to a file on disk (called a \"run\") and " -"then cleared for storing new elements. This operation is called a \"dump\"." -msgstr "" -"Рано или поздно количество элементов в дереве превысит размер L0. Тогда L0 " -"записывается в файл на диске (который называется забегом -- \"run\") и " -"освобождается под новые элементы. Эта операция называется \"дамп\" (dump)." - -msgid "" -"Dumps on disk form a sequence ordered by LSN: LSN ranges in different runs " -"don’t overlap, and the leftmost runs (at the head of the sequence) hold " -"newer operations. Think of these runs as a pyramid, with the newest ones " -"closer to the top. As runs keep getting dumped, the pyramid grows higher. " -"Note that newer runs may contain deletions or replacements for existing " -"keys. To remove older data, it’s necessary to perform garbage collection " -"(this process is sometimes called \"merge\" or \"compaction\") by combining " -"several older runs into a new one. If two versions of the same key are " -"encountered during a compaction, only the newer one is retained; however, if" -" a key insertion is followed by a deletion, then both operations can be " -"discarded." -msgstr "" -"Все дампы на диске образуют последовательность, упорядоченную по LSN: " -"диапазоны LSN в файлах не пересекаются, а ближе к началу последовательности " -"находятся файлы с более новыми операциями. Представим эти файлы в виде " -"пирамиды, где новые файлы расположены вверху, а старые внизу. По мере " -"появления новых файлов забегов, высота пирамиды растет. При этом более " -"свежие файлы могут содержать операции удаления или замены для существующих " -"ключей. Для удаления старых данных необходимо производиться сборку мусора " -"(этот процесс иногда называется \"слияние\" -- в английском языке \"merge\" " -"или \"compaction\"), объединяя нескольких старых файлов в новый. Если при " -"слиянии мы встречаем две версии одного и того же ключа, то достаточно " -"оставить только более новую версию, а если после вставки ключа он был " -"удален, то из результата можно исключить обе операции." - -msgid "" -"The key choices determining an LSM tree’s efficiency are which runs to " -"compact and when to compact them. Suppose an LSM tree stores a monotonically" -" increasing sequence of keys (1, 2, 3, ...,) with no deletions. In this " -"case, compacting runs would be useless: all of the elements are sorted, the " -"tree doesn’t have any garbage, and the location of any key can unequivocally" -" be determined. On the other hand, if an LSM tree contains many deletions, " -"doing a compaction would free up some disk space. However, even if there are" -" no deletions, but key ranges in different runs overlap a lot, compacting " -"such runs could speed up lookups as there would be fewer runs to scan. In " -"this case, it might make sense to compact runs after each dump. But keep in " -"mind that a compaction causes all data stored on disk to be overwritten, so " -"with few reads it’s recommended to perform it less often." -msgstr "" -"Ключевым фактором эффективности LSM-дерева является то, в какой момент и для" -" каких файлов делается слияние. Представим, что LSM-дерево в качестве ключей" -" хранит монотонную последовательность вида 1, 2, 3 …, и операций удаления " -"нет. В этом случае слияние будет бесполезным -- все элементы уже " -"отсортированы, дерево не содержит мусор и можно однозначно определить, в " -"каком файле находится каждый ключ. Напротив, если LSM-дерево содержит много " -"операций удаления, слияние позволит освободить место на диске. Но даже если " -"удалений нет, а диапазоны ключей в разных файлах сильно пересекаются, " -"слияние может ускорить поиск, так как сократит число просматриваемых файлов." -" В этом случае имеет смысл выполнять слияние после каждого дампа. Однако " -"следует отметить, что такое слияние приведет к перезаписи всех данных на " -"диске, поэтому если чтений мало, то лучше делать слияния реже." - -msgid "" -"To ensure it’s optimally configurable for any of the scenarios above, an LSM" -" tree organizes all runs into a pyramid: the newer the data operations, the " -"higher up the pyramid they are located. During a compaction, the algorithm " -"picks two or more neighboring runs of approximately equal size, if possible." -msgstr "" -"Для оптимальной конфигурации под любой из описанных выше сценариев в LSM-" -"дереве все файлы организованы в пирамиду: чем новее операции с данными, тем " -"выше они находятся в пирамиде. При этом в слиянии участвуют два или " -"несколько соседних файлов в пирамиде; по возможности выбираются файлы " -"примерно одинакового размера." - -msgid "Multi-level compaction can span any number of levels" -msgstr "Многоуровневое слияние может охватить любое количество уровней" - -msgid "A level can contain multiple runs" -msgstr "Уровень может содержать несколько файлов" - -msgid "" -"All of the neighboring runs of approximately equal size constitute an LSM " -"tree level on disk. The ratio of run sizes at different levels determines " -"the pyramid’s proportions, which allows optimizing the tree for write-" -"intensive or read-intensive scenarios." -msgstr "" -"Все соседние файлы примерно одинакового размера составляют уровень LSM-" -"дерева на диске. Соотношение размеров файлов на различных уровнях определяет" -" пропорции пирамиды, что позволяет оптимизировать дерево под интенсивные " -"вставки, либо интенсивные чтения." - -msgid "" -"Suppose the L0 size is 100 Mb, the ratio of run sizes at each level (the " -"``vinyl_run_size_ratio`` parameter) is 5, and there can be no more than 2 " -"runs per level (the ``vinyl_run_count_per_level`` parameter). After the " -"first 3 dumps, the disk will contain 3 runs of 100 Mb each—which constitute " -"L1 (level one). Since 3 > 2, the runs will be compacted into a single 300 Mb" -" run, with the older ones being deleted. After 2 more dumps, there will be " -"another compaction, this time of 2 runs of 100 Mb each and the 300 Mb run, " -"which will produce one 500 Mb run. It will be moved to L2 (recall that the " -"run size ratio is 5), leaving L1 empty. The next 10 dumps will result in L2 " -"having 3 runs of 500 Mb each, which will be compacted into a single 1500 Mb " -"run. Over the course of 10 more dumps, the following will happen: 3 runs of " -"100 Mb each will be compacted twice, as will two 100 Mb runs and one 300 Mb " -"run, which will yield 2 new 500 Mb runs in L2. Since L2 now has 3 runs, they" -" will also be compacted: two 500 Mb runs and one 1500 Mb run will produce a " -"2500 Mb run that will be moved to L3, given its size." -msgstr "" -"Предположим, что размер L0 составляет 100 МБ, а соотношение размеров файлов " -"на каждом уровне (параметр ``vinyl_run_size_ratio``) равно 5, и на каждом " -"уровне может быть не более 2 файлов (параметр " -"``vinyl_run_count_per_level``). После первых трех дампов на диске появятся 3" -" файла по 100 МБ, эти файлы образуют уровень L1. Так как 3 > 2, запустится " -"слияние файлов в новый файл размером 300 МБ, а старые будут удалены. Спустя " -"еще 2 дампа снова запустится слияние, на этот раз файлов в 100, 100 и 300 " -"МБ, в результате файл размером 500 МБ переместится на уровень L2 (вспомним, " -"что соотношение размеров уровней равно 5), а уровень L1 останется пустым. " -"Пройдут еще 10 дампов, и получим 3 файла по 500 МБ на уровне L2, в " -"результате чего будет создан один файл размером 1500 МБ. Спустя еще 10 " -"дампов произойдет следующее: 2 раза произведем слияние 3 файлов по 100 МБ, а" -" также 2 раза слияние файлов по 100, 100 и 300 МБ, что приведет к созданию " -"двух файлов на уровне L2 по 500 МБ. Поскольку на уровне L2 уже есть три " -"файла, запустится слияние двух файлов по 500 МБ и одного файла в 1500 МБ. " -"Полученный в результате файл в 2500 МБ, в силу своего размера, переедет на " -"уровень L3." - -msgid "" -"This can go on infinitely, but if an LSM tree contains lots of deletions, " -"the resulting compacted run can be moved not only down, but also up the " -"pyramid due to its size being smaller than the sizes of the original runs " -"that were compacted. In other words, it’s enough to logically track which " -"level a certain run belongs to, based on the run size and the smallest and " -"greatest LSN among all of its operations." -msgstr "" -"Процесс может продолжаться до бесконечности, а если в потоке операций с LSM-" -"деревом будет много удалений, образовавшийся в результате слияния файл может" -" переместиться не только вниз по пирамиде, но и вверх, так как окажется " -"меньше исходных файлов, использовавшихся при слиянии. Иными словами, " -"принадлежность файла к уровню достаточно отслеживать логически на основе " -"размера файла и минимального и максимального LSN среди всех хранящихся в нем" -" операций." - -msgid "Controlling the form of an LSM tree" -msgstr "Управление формой LSM-дерева" - -msgid "" -"If it’s necessary to reduce the number of runs for lookups, then the run " -"size ratio can be increased, thus bringing the number of levels down. If, on" -" the other hand, you need to minimize the compaction-related overhead, then " -"the run size ratio can be decreased: the pyramid will grow higher, and even " -"though runs will be compacted more often, they will be smaller, which will " -"reduce the total amount of work done. In general, write amplification in an " -"LSM tree is described by this formula: :math:`log_{x}(\\frac {N} {L0}) × x` " -"or, alternatively, :math:`x × \\frac {ln (\\frac {N} {C0})} {ln(x)}`, where " -"N is the total size of all tree elements, L0 is the level zero size, and x " -"is the level size ratio (the ``level_size_ratio`` parameter). At " -":math:`\\frac {N} {C0}` = 40 (the disk-to- memory ratio), the plot would " -"look something like this:" -msgstr "" -"Если число файлов для поиска нужно уменьшить, то соотношение размеров файлов" -" на разных уровнях можно увеличить, и, как следствие, уменьшается число " -"уровней. Если, напротив, необходимо снизить затраты ресурсов, вызванные " -"слиянием, то можно уменьшить соотношение размеров уровней: пирамида будет " -"более высокой, а слияние хотя и выполняется чаще, но работает в среднем с " -"файлами меньшего размера, за счет чего суммарно выполняет меньше работы. В " -"целом, \"паразитная запись\" в LSM-дереве описывается формулой " -":math:`log_{x}(\\\\frac {N} {L0}) × x` или :math:`x × \\\\frac {ln (\\\\frac" -" {N} {C0})} {ln(x)}`, где N -- это общий размер всех элементов дерева, L0 --" -" это размер уровня ноль, а x -- это соотношение размеров уровней (параметр " -"``level_size_ratio``). Если :math:`\\\\frac {N} {C0}` = 40 (соотношение " -"диск-память), график выглядит примерно вот так:" - -msgid "" -"As for read amplification, it’s proportional to the number of levels. The " -"lookup cost at each level is no greater than that for a B-tree. Getting back" -" to the example of a tree with 100,000,000 elements: given 256 Mb of RAM and" -" the default values of ``vinyl_run_size_ratio`` and " -"``vinyl_run_count_per_level``, write amplification would come out to about " -"13, while read amplification could be as high as 150. Let’s try to figure " -"out why this happens." -msgstr "" -"\"Паразитное\" чтение при этом пропорционально количеству уровней. Стоимость" -" поиска на каждом уровне не превышает стоимости поиска в B-дереве. " -"Возвращаясь к нашему примеру дерева в 100 000 000 элементов: при наличии 256" -" МБ оперативной памяти и стандартных значений параметров " -"``vinyl_run_size_ratio`` и ``vinyl_run_count_per_level``, получим " -"коэффициент \"паразитной\" записи равным примерно 13, коэффициент " -"\"паразитной\" записи может доходить до 150. Разберемся, почему это " -"происходит." - -msgid "Search" -msgstr "Поиск" - -msgid "" -"When doing a lookup in an LSM tree, what we need to find is not the element " -"itself, but the most recent operation associated with it. If it’s a " -"deletion, then the tree doesn’t contain this element. If it’s an insertion, " -"we need to grab the topmost value in the pyramid, and the search can be " -"stopped after finding the first matching key. In the worst-case scenario, " -"that is if the tree doesn’t hold the needed element, the algorithm will have" -" to sequentially visit all of the levels, starting from L0." -msgstr "" -"При поиске в LSM-дереве нам необходимо найти не сам элемент, а последнюю " -"операцию с ним. Если это операция удаления, искомый элемент отсутствует в " -"дереве. Если это операция вставки, то искомому элементу соответствует самое " -"верхнее значение в LSM-пирамиде, и поиск можно остановить при первом " -"совпадении ключа. В худшем случае значение в дереве изначально " -"отсутствовало. Тогда поиск вынужден последовательно перебрать все уровни " -"дерева, начиная с L0." - -msgid "" -"Unfortunately, this scenario is quite common in real life. For example, when" -" inserting a value into a tree, it’s necessary to make sure there are no " -"duplicates among primary/unique keys. So to speed up membership checks, LSM " -"trees use a probabilistic data structure called a \"Bloom filter\", which " -"will be covered a bit later, in a section on how vinyl works under the hood." -msgstr "" -"К сожалению, на практике этот худший случай довольно распространен. " -"Например, при вставке в дерево необходимо убедиться в отсутствии дубликатов " -"для первичного или уникального ключа. Поэтому для ускорения поиска " -"несуществующих значений в LSM-деревьях применяется вероятностная структура " -"данных, которая называется \"фильтр Блума\". О нем мы поговорим более " -"детально в разделе, посвященном внутреннему устройству vinyl." - -msgid "Range searching" -msgstr "Поиск по диапазону" - -msgid "" -"In the case of a single-key search, the algorithm stops after encountering " -"the first match. However, when searching within a certain key range (for " -"example, looking for all the users with the last name \"Ivanov\"), it’s " -"necessary to scan all tree levels." -msgstr "" -"Если при поиске по одному ключу алгоритм завершается после первого " -"совпадения, то для поиска всех значений в диапазоне (например, всех " -"пользователей с фамилией \"Иванов\") необходимо просматривать все уровни " -"дерева." - -msgid "*Searching within a range of [24,30)*" -msgstr "*Поиск по диапазону [24,30)*" - -msgid "" -"The required range is formed the same way as when compacting several runs: " -"the algorithm picks the key with the largest LSN out of all the sources, " -"ignoring the other associated operations, then moves on to the next key and " -"repeats the procedure." -msgstr "" -"Формирование искомого диапазона при этом происходит так же, как и при " -"слиянии нескольких файлов: из всех источников алгоритм выбирает ключ с " -"максимальным LSN, отбрасывает остальные операции по этому ключу, сдвигает " -"позицию поиска на следующий ключ и повторяет процедуру." - -msgid "Deletion" -msgstr "Удаление" - -msgid "" -"Why would one store deletions? And why doesn’t it lead to a tree overflow in" -" the case of for i=1,10000000 put(i) delete(i) end?" -msgstr "" -"Зачем вообще хранить операции удаления? И почему это не приводит к " -"переполнению дерева, например, в сценарии for i=1,10000000 put(i) delete(i) " -"end?" - -msgid "" -"With regards to lookups, deletions signal the absence of a value being " -"searched; with compactions, they clear the tree of \"garbage\" records with " -"older LSNs." -msgstr "" -"Роль операций удаления при поиске -- сообщать об отсутствии искомого " -"значения, а при слиянии -- очищать дерево от \"мусорных\" записей с более " -"старыми LSN." - -msgid "" -"While the data is in RAM only, there’s no need to store deletions. " -"Similarly, you don’t need to keep them following a compaction if they " -"affect, among other things, the lowest tree level, which contains the oldest" -" dump. Indeed, if a value can’t be found at the lowest level, then it " -"doesn’t exist in the tree." -msgstr "" -"Пока данные хранятся только в оперативной памяти, нет необходимости хранить " -"операции удаления. Также нет необходимости сохранять операции удаления после" -" слияния, если оно затрагивает в том числе самый нижний уровень дерева -- на" -" нем находятся данные самого старого дампа. Действительно, отсутствие " -"значения на последнем уровне означает, что оно отсутствует в дереве." - -msgid "We can't delete from append-only files" -msgstr "" -"Нельзя производить удаление из файлов, которые обновляются только путем " -"присоединения новых записей" - -msgid "Tombstones (delete markers) are inserted into L0 instead" -msgstr "" -"Вместо этого на уровень L0 вносятся маркеры удаленных записей (tombstones)" - -msgid "*Deletion, step 1: a tombstone is inserted into L0*" -msgstr "*Удаление, шаг 1: вставка удаленной записи в L0*" - -msgid "*Deletion, step 2: the tombstone passes through intermediate levels*" -msgstr "" -"*Удаление, шаг 2: удаленная запись проходит через промежуточные уровни*" - -msgid "" -"*Deletion, step 3: in the case of a major compaction, the tombstone is " -"removed from the tree*" -msgstr "" -"*Удаление, шаг 3: при значительном слиянии удаленная запись удаляется из " -"дерева*" - -msgid "" -"If a deletion is known to come right after the insertion of a unique value, " -"which is often the case when modifying a value in a secondary index, then " -"the deletion can safely be filtered out while compacting intermediate tree " -"levels. This optimization is implemented in vinyl." -msgstr "" -"Если мы знаем, что удаление следует сразу за вставкой уникального значения " -"-- а это частый случай при изменении значения во вторичном индексе -- то " -"операцию удаления можно отфильтровывать уже при слиянии промежуточных " -"уровней. Эта оптимизация реализована в vinyl'е." - -msgid "Advantages of an LSM tree" -msgstr "Преимущества LSM-дерева" - -msgid "" -"Apart from decreasing write amplification, the approach that involves " -"periodically dumping level L0 and compacting levels L1-Lk has a few " -"advantages over the approach to writes adopted by B-trees:" -msgstr "" -"Помимо снижения \"паразитной\" записи, подход с периодическими дампами " -"уровня L0 и слиянием уровней L1-Lk имеет ряд преимуществ перед подходом к " -"записи, используемым в B-деревьях:" - -msgid "" -"Dumps and compactions write relatively large files: typically, the L0 size " -"is 50-100 Mb, which is thousands of times larger than the size of a B-tree " -"block." -msgstr "" -"При дампах и слиянии создаются относительно большие файлы: стандартный " -"размер L0 составляет 50-100 MБ, что в тысячи раз превышает размер блока " -"B-дерева." - -msgid "" -"This large size allows efficiently compressing data before writing it. " -"Tarantool compresses data automatically, which further decreases write " -"amplification." -msgstr "" -"Большой размер позволяет эффективно сжимать данные перед записью. В " -"Tarantool'е сжатие происходит автоматически, что позволяет еще больше " -"уменьшить \"паразитную\" запись." - -msgid "" -"There is no fragmentation overhead, since there’s no padding/empty space " -"between the elements inside a run." -msgstr "" -"Издержки фрагментации отсутствуют, потому что в файле элементы следуют друг " -"за другом без пустот/заполнений." - -msgid "" -"All operations create new runs instead of modifying older data in place. " -"This allows avoiding those nasty locks that everyone hates so much. Several " -"operations can run in parallel without causing any conflicts. This also " -"simplifies making backups and moving data to replicas." -msgstr "" -"Все операции создают новые файлы, а не заменяют старые данные. Это позволяет" -" избавиться от столь ненавистных нам блокировок, при этом несколько операций" -" могут идти параллельно, не приводя к конфликтам. Это также упрощает " -"создание резервных копий и перенос данных на реплику." - -msgid "" -"Storing older versions of data allows for the efficient implementation of " -"transaction support by using multiversion concurrency control." -msgstr "" -"Хранение старых версий данных позволяет эффективно реализовать поддержку " -"транзакций, используя подход управления параллельным доступом с помощью " -"многоверсионности." - -msgid "Disadvantages of an LSM tree and how to deal with them" -msgstr "Недостатки LSM-дерева и их устранение" - -msgid "" -"One of the key advantages of the B-tree as a search data structure is its " -"predictability: all operations take no longer than :math:`log_{B}(N)` to " -"run. Conversely, in a classical LSM tree, both read and write speeds can " -"differ by a factor of hundreds (best case scenario) or even thousands (worst" -" case scenario). For example, adding just one element to L0 can cause it to " -"overflow, which can trigger a chain reaction in levels L1, L2, and so on. " -"Lookups may find the needed element in L0 or may need to scan all of the " -"tree levels. It’s also necessary to optimize reads within a single level to " -"achieve speeds comparable to those of a B-tree. Fortunately, most " -"disadvantages can be mitigated or even eliminated with additional algorithms" -" and data structures. Let’s take a closer look at these disadvantages and " -"how they’re dealt with in Tarantool." -msgstr "" -"Одним из ключевых преимуществ B-дерева как структуры данных для поиска " -"является предсказуемость: любая операция занимает не более чем " -":math:`log_{B}(N)`. В классическом LSM-дереве скорость как чтения, так и " -"записи могут может отличаться в лучшем и худшем случае в сотни и тысячи раз." -" Например, добавление всего лишь одного элемента в L0 может привести к его " -"переполнению, что в свою очередь, может привести к переполнению L1, L2 и " -"т.д. Процесс чтения может обнаружить исходный элемент в L0, а может " -"задействовать все уровни. Чтение в пределах одного уровня также необходимо " -"оптимизировать, чтобы добиться скорости, сравнимой с B-деревом. К счастью, " -"многие недостатки можно скрасить или полностью устранить с помощью " -"вспомогательных алгоритмов и структур данных. Систематизируем эти недостатки" -" и опишем способы борьбы с ними, используемые в Tarantool'е." - -msgid "Unpredictable write speed" -msgstr "Непредсказуемая скорость записи" - -msgid "" -"In an LSM tree, insertions almost always affect L0 only. How do you avoid " -"idle time when the memory area allocated for L0 is full?" -msgstr "" -"Вставка данных в LSM-дерево почти всегда задействует исключительно L0. Как " -"избежать простоя, если заполнена область оперативной памяти, отведенная под " -"L0?" - -msgid "" -"Clearing L0 involves two lengthy operations: writing to disk and memory " -"deallocation. To avoid idle time while L0 is being dumped, Tarantool uses " -"writeaheads. Suppose the L0 size is 256 Mb. The disk write speed is 10 Mbps." -" Then it would take 26 seconds to dump L0. The insertion speed is 10,000 " -"RPS, with each key having a size of 100 bytes. While L0 is being dumped, " -"it’s necessary to reserve 26 Mb of RAM, effectively slicing the L0 size down" -" to 230 Mb." -msgstr "" -"Освобождение L0 подразумевает две долгих операции: запись на диск и " -"освобождение памяти. Чтобы избежать простоя во время записи L0 на диск, " -"Tarantool использует упреждающую запись. Допустим, размер L0 составляет 256 " -"MБ. Скорость записи на диск составляет 10 МБ/с. Тогда для записи L0 на диск " -"понадобится 26 секунд. Скорость вставки данных составляет 10 000 запросов в " -"секунду, а размер одного ключа -- 100 байтов. На время записи необходимо " -"зарезервировать около 26 MБ доступной оперативной памяти, сократив реальный " -"полезный размер L0 до 230 MБ." - -msgid "" -"Tarantool does all of these calculations automatically, constantly updating " -"the rolling average of the DBMS workload and the histogram of the disk " -"speed. This allows using L0 as efficiently as possible and it prevents write" -" requests from timing out. But in the case of workload surges, some wait " -"time is still possible. That’s why we also introduced an insertion timeout " -"(the ``vinyl_timeout`` parameter), which is set to 60 seconds by default. " -"The write operation itself is executed in dedicated threads. The number of " -"these threads (2 by default) is controlled by the ``vinyl_write_threads`` " -"parameter. The default value of 2 allows doing dumps and compactions in " -"parallel, which is also necessary for ensuring system predictability." -msgstr "" -"Все эти расчеты Tarantool делает автоматически, постоянно поддерживая " -"скользящее среднее значение нагрузки на СУБД и гистограмму скорости работы " -"диска. Это позволяет максимально эффективно использовать L0 и избежать " -"истечения времени ожидания доступной памяти для операций записи. При резком " -"всплеске нагрузки ожидание все же возможно, поэтому также существует время " -"ожидания операции вставки (параметр ``vinyl_timeout``), значение которого по" -" умолчанию составляет 60 секунд. Сама запись осуществляется в выделенных " -"потоках, число которых (2 по умолчанию) задается в параметре " -"``vinyl_write_threads``. Используемое по умолчанию значение 2 позволяет " -"выполнять дамп параллельно со слиянием, что также необходимо для " -"предсказуемой работы системы." - -msgid "" -"In Tarantool, compactions are always performed independently of dumps, in a " -"separate execution thread. This is made possible by the append-only nature " -"of an LSM tree: after dumps runs are never changed, and compactions simply " -"create new runs." -msgstr "" -"Слияния в Tarantool'е всегда выполняются независимо от дампов, в отдельном " -"потоке выполнения. Это возможно благодаря природе LSM-дерева -- после записи" -" файлы в дереве никогда не меняются, а слияние лишь создает новый файл." - -msgid "" -"Delays can also be caused by L0 rotation and the deallocation of memory " -"dumped to disk: during a dump, L0 memory is owned by two operating system " -"threads, a transaction processing thread and a write thread. Even though no " -"elements are being added to the rotated L0, it can still be used for " -"lookups. To avoid read locks when doing lookups, the write thread doesn’t " -"deallocate the dumped memory, instead delegating this task to the " -"transaction processor thread. Following a dump, memory deallocation itself " -"happens instantaneously: to achieve this, L0 uses a special allocator that " -"deallocates all of the memory with a single operation." -msgstr "" -"К задержкам также может приводить ротация L0 и освобождение памяти, " -"записанной на диск: в процессе записи памятью L0 владеют два потока " -"операционной системы -- поток обработки транзакций и поток записи. Хотя в L0" -" во время ротации элементы не добавляются, он может участвовать в поиске. " -"Чтобы избежать блокировок на чтение во время поиска, поток записи не " -"освобождает записанную память, а оставляет эту задачу потоку обработки " -"транзакций. Само освобождение после завершения дампа происходит мгновенно: " -"для этого в L0 используется специализированный механизм распределения, " -"позволяющий освободить всю память за одну операцию." - -msgid "anticipatory dump" -msgstr "упреждающий дамп" - -msgid "throttling" -msgstr "загрузка" - -msgid "" -"The dump is performed from the so-called \"shadow\" L0 without blocking new " -"insertions and lookups" -msgstr "" -"Дамп происходит из так называемого \"теневого\" L0, не блокируя новые " -"вставки и чтения" - -msgid "Unpredictable read speed" -msgstr "Непредсказуемая скорость чтений" - -msgid "" -"Optimizing reads is the most difficult optimization task with regards to LSM" -" trees. The main complexity factor here is the number of levels: any " -"optimization causes not only much slower lookups, but also tends to require " -"significantly larger RAM resources. Fortunately, the append-only nature of " -"LSM trees allows us to address these problems in ways that would be " -"nontrivial for traditional data structures." -msgstr "" -"Чтение -- самая сложная задача для оптимизации в LSM-деревьях. Главным " -"фактором сложности является большое количество уровней: это не только " -"значительно замедляет поиск, но и потенциально значительно увеличивает " -"требования к оперативной памяти при почти любых попытках оптимизации. К " -"счастью, природа LSM-деревьев, где файлы обновляются только путем " -"присоединения новых записей, позволяет решать эти проблемы нестандартными " -"для традиционных структур данных способами." - -msgid "page index" -msgstr "постраничный индекс" - -msgid "bloom filters" -msgstr "фильтры Блума" - -msgid "tuple range cache" -msgstr "кэш диапазона кортежей" - -msgid "multi-level compaction" -msgstr "многоуровневое слияние" - -msgid "Compression and page index" -msgstr "Сжатие и постраничный индекс" - -msgid "" -"In B-trees, data compression is either the hardest problem to crack or a " -"great marketing tool—rather than something really useful. In LSM trees, " -"compression works as follows:" -msgstr "" -"Сжатие данных в B-деревьях -- это либо сложнейшая в реализации задача, либо " -"больше средство маркетинга, чем действительно полезный инструмент. Сжатие в " -"LSM-деревьях работает следующим образом:" - -msgid "" -"During a dump or compaction all of the data within a single run is split " -"into pages. The page size (in bytes) is controlled by the " -"``vinyl_page_size`` parameter and can be set separately for each index. A " -"page doesn’t have to be exactly of ``vinyl_page_size`` size—depending on the" -" data it holds, it can be a little bit smaller or larger. Because of this, " -"pages never have any empty space inside." -msgstr "" -"При любом дампе или слиянии мы разбиваем все данные в одном файле на " -"страницы. Размер страницы в байтах задается в параметре ``vinyl_page_size``," -" который можно менять отдельно для каждого индекса. Страница не обязана " -"занимать строго то количество байт, которое прописано ``vinyl_page_size`` --" -" она может быть чуть больше или чуть меньше, в зависимости от хранящихся в " -"ней данных. Благодаря этому страница никогда не содержит пустот." - -msgid "" -"Data is compressed by `Facebook’s streaming algorithm " -"`_ called \"zstd\". The first key of each " -"page, along with the page offset, is added to a \"page index\", which is a " -"separate file that allows the quick retrieval of any page. After a dump or " -"compaction, the page index of the created run is also written to disk." -msgstr "" -"Для сжатия используется `потоковый алгоритм Facebook " -"`_ под названием \"zstd\". Первый ключ " -"каждой страницы и смещение страницы в файле добавляются в так называемый " -"постраничный индекс (page index) -- отдельный файл, который позволяет быстро" -" найти нужную страницу. После дампа или слияния постраничный индекс " -"созданного файла также записывается на диск." - -msgid "" -"All `.index` files are cached in RAM, which allows finding the necessary " -"page with a single lookup in a `.run` file (in vinyl, this is the extension " -"of files resulting from a dump or compaction). Since data within a page is " -"sorted, after it’s read and decompressed, the needed key can be found using " -"a regular binary search. Decompression and reads are handled by separate " -"threads, and are controlled by the ``vinyl_read_threads`` parameter." -msgstr "" -"Все файлы типа `.index` кэшируются в оперативной памяти, что позволяет " -"найти нужную страницу за одно чтение из файла `.run` (такое расширение имени" -" файла используется в vinyl'е для файлов, полученных в результате дампа или " -"слияния). Поскольку данные в странице отсортированы, после чтения и " -"декомпрессии нужный ключ можно найти с помощью простого бинарного поиска. За" -" чтение и декомпрессию отвечают отдельные потоки, их количество определяется" -" в параметре ``vinyl_read_threads``." - -msgid "" -"Tarantool uses a universal file format: for example, the format of a `.run` " -"file is no different from that of an `.xlog` file (log file). This " -"simplifies backup and recovery as well as the usage of external tools." -msgstr "" -"Tarantool использует единый формат файлов: например, формат данных в файле " -"`.run` ничем не отличается от формата файла `.xlog` (файл журнала). Это " -"упрощает резервное копирование и восстановление, а также работу внешних " -"инструментов." - -msgid "Bloom filters" -msgstr "Фильтры Блума" - -msgid "" -"Even though using a page index enables scanning fewer pages per run when " -"doing a lookup, it’s still necessary to traverse all of the tree levels. " -"There’s a special case, which involves checking if particular data is absent" -" when scanning all of the tree levels and it’s unavoidable: I’m talking " -"about insertions into a unique index. If the data being inserted already " -"exists, then inserting the same data into a unique index should lead to an " -"error. The only way to throw an error in an LSM tree before a transaction is" -" committed is to do a search before inserting the data. Such reads form a " -"class of their own in the DBMS world and are called \"hidden\" or " -"\"parasitic\" reads." -msgstr "" -"Хотя постраничный индекс позволяет уменьшить количество страниц, " -"просматриваемых при поиске в одном файле, он не отменяет необходимости " -"искать на всех уровнях дерева. Есть важный частный случай, когда необходимо " -"проверить отсутствие данных, и тогда просмотр всех уровней неизбежен: " -"вставка в уникальный индекс. Если данные уже существуют, то вставка в " -"уникальный индекс должна завершиться с ошибкой. Единственный способ вернуть " -"ошибку до завершения транзакции в LSM-дереве -- произвести поиск перед " -"вставкой. Такого рода чтения в СУБД образуют целый класс, называемый " -"\"скрытыми\" или \"паразитными\" чтениями." - -msgid "" -"Another operation leading to hidden reads is updating a value in a field on " -"which a secondary index is defined. Secondary keys are regular LSM trees " -"that store differently ordered data. In most cases, in order not to have to " -"store all of the data in all of the indexes, a value associated with a given" -" key is kept in whole only in the primary index (any index that stores both " -"a key and a value is called \"covering\" or \"clustered\"), whereas the " -"secondary index only stores the fields on which a secondary index is " -"defined, and the values of the fields that are part of the primary index. " -"Thus, each time a change is made to a value in a field on which a secondary " -"index is defined, it’s necessary to first remove the old key from the " -"secondary index—and only then can the new key be inserted. At update time, " -"the old value is unknown, and it is this value that needs to be read in from" -" the primary key \"under the hood\"." -msgstr "" -"Другая операция, приводящая к скрытым чтениям, -- обновление значения, по " -"которому построен вторичный индекс. Вторичные ключи представляют собой " -"обычные LSM-деревья, в которых данные хранятся в другом порядке. Чаще всего," -" чтобы не хранить все данные во всех индексах, значение, соответствующее " -"данному ключу, целиком сохраняется только в первичном индексе (любой индекс," -" хранящий и ключ, и значение, называется покрывающим или кластерным), а во " -"вторичном индексе сохраняются лишь поля, по которым построен вторичный " -"индекс, и значения полей, участвующих в первичном индексе. Тогда при любом " -"изменении значения, по которому построен вторичный ключ, приходится сначала " -"удалять из вторичного индекса старый ключ, и только потом вставлять новый. " -"Старое значение во время обновления неизвестно -- именно его и нужно читать " -"из первичного ключа с точки зрения внутреннего устройства." - -msgid "For example:" -msgstr "Например:" - -msgid "update t1 set city=’Moscow’ where id=1" -msgstr "update t1 set city=’Moscow’ where id=1" - -msgid "" -"To minimize the number of disk reads, especially for nonexistent data, " -"nearly all LSM trees use probabilistic data structures, and Tarantool is no " -"exception. A classical Bloom filter is made up of several (usually 3-to-5) " -"bit arrays. When data is written, several hash functions are calculated for " -"each key in order to get corresponding array positions. The bits at these " -"positions are then set to 1. Due to possible hash collisions, some bits " -"might be set to 1 twice. We’re most interested in the bits that remain 0 " -"after all keys have been added. When looking for an element within a run, " -"the same hash functions are applied to produce bit positions in the arrays. " -"If any of the bits at these positions is 0, then the element is definitely " -"not in the run. The probability of a false positive in a Bloom filter is " -"calculated using Bayes’ theorem: each hash function is an independent random" -" variable, so the probability of a collision simultaneously occurring in all" -" of the bit arrays is infinitesimal." -msgstr "" -"Чтобы уменьшить количество чтений с диска, особенно для несуществующих " -"значений, практически все LSM-деревья используют вероятностные структуры " -"данных. Tarantool не исключение. Классический фильтр Блума -- это набор из " -"нескольких (обычно 3-5) битовых массивов. При записи для каждого ключа " -"вычисляется несколько хеш-функций, и в каждом массиве выставляется бит, " -"соответствующий значению хеша. При хешировании могут возникнуть коллизии, " -"поэтому некоторые биты могут быть проставлены дважды. Интерес представляют " -"биты, которые оказались не проставлены после записи всех ключей. При поиске " -"также вычисляются выбранные хеш-функции. Если хотя бы в одном из битовых " -"массивов бит не стоит, то значение в файле отсутствует. Вероятность " -"срабатывания фильтра Блума определяется теоремой Байеса: каждая хеш-функция " -"представляет собой независимую случайную величину, благодаря чему " -"вероятность того, что во всех битовых массивах одновременно произойдет " -"коллизия, очень мала." - -msgid "" -"The key advantage of Bloom filters in Tarantool is that they’re easily " -"configurable. The only parameter that can be specified separately for each " -"index is called ``vinyl_bloom_fpr`` (FPR stands for \"false positive " -"ratio\") and it has the default value of 0.05, which translates to a 5% FPR." -" Based on this parameter, Tarantool automatically creates Bloom filters of " -"the optimal size for partial- key and full-key searches. The Bloom filters " -"are stored in the `.index` file, along with the page index, and are cached " -"in RAM." -msgstr "" -"Ключевым преимуществом реализации фильтров Блума в Tarantool'е является " -"простота настройки. Единственный параметр, который можно менять независимо " -"для каждого индекса, называется ``vinyl_bloom_fpr`` (FPR в данном случае " -"означает сокращение от \"false positive ratio\" -- коэффициент " -"ложноположительного срабатывания), который по умолчанию равен 0,05, или 5%. " -"На основе этого параметра Tarantool автоматически строит фильтры Блума " -"оптимального размера для поиска как по полному ключу, так и по компонентам " -"ключа. Сами фильтры Блума хранятся вместе с постраничным индексом в файле " -"`.index` и кэшируются в оперативной памяти." - -msgid "Caching" -msgstr "Кэширование" - -msgid "" -"A lot of people think that caching is a silver bullet that can help with any" -" performance issue. \"When in doubt, add more cache\". In vinyl, caching is " -"viewed rather as a means of reducing the overall workload and consequently, " -"of getting a more stable response time for those requests that don’t hit the" -" cache. vinyl boasts a unique type of cache among transactional systems " -"called a \"range tuple cache\". Unlike, say, RocksDB or MySQL, this cache " -"doesn’t store pages, but rather ranges of index values obtained from disk, " -"after having performed a compaction spanning all tree levels. This allows " -"the use of caching for both single-key and key-range searches. Since this " -"method of caching stores only hot data and not, say, pages (you may need " -"only some data from a page), RAM is used in the most efficient way possible." -" The cache size is controlled by the ``vinyl_cache`` parameter." -msgstr "" -"Многие привыкли считать кэширование панацеей от всех проблем с " -"производительностью: \"В любой непонятной ситуации добавляй кэш\". В vinyl'е" -" мы смотрим на кэш скорее как на средство снижения общей нагрузки на диск, " -"и, как следствие, получения более предсказуемого времени ответов на запросы," -" которые не попали в кэш. В vinyl'е реализован уникальный для транзакционных" -" систем вид кэша под названием \"кэш диапазона кортежей\" (range tuple " -"cache). В отличие от RocksDB, например, или MySQL, этот кэш хранит не " -"страницы, а уже готовые диапазоны значений индекса, после их чтения с диска " -"и слияния всех уровней. Это позволяет использовать кэш для запросов как по " -"одному ключу, так и по диапазону ключей. Поскольку в кэше хранятся только " -"горячие данные, а не, скажем, страницы (в странице может быть востребована " -"лишь часть данных), оперативная память используется наиболее оптимально. " -"Размер кэша задается в параметре ``vinyl_cache``." - -msgid "Garbage collection control" -msgstr "Управление сборкой мусора" - -msgid "" -"Chances are that by now you’ve started losing focus and need a well-deserved" -" dopamine reward. Feel free to take a break, since working through the rest " -"of the article is going to take some serious mental effort." -msgstr "" -"Возможно, добравшись до этого места вы уже начали терять концентрацию и " -"нуждаетесь в заслуженной дозе допамина. Самое время сделать перерыв, так как" -" для того, чтобы разобраться с оставшейся частью, понадобятся серьезные " -"усилия." - -msgid "" -"An LSM tree in vinyl is just a small piece of the puzzle. Even with a single" -" table (or so-called \"space\"), vinyl creates and maintains several LSM " -"trees, one for each index. But even a single index can be comprised of " -"dozens of LSM trees. Let’s try to understand why this might be necessary." -msgstr "" -"В vinyl'е устройство одного LSM-дерева -- это лишь фрагмент мозаики. Vinyl " -"создает и обслуживает несколько LSM-деревьев даже для одной таблицы (так " -"называемого спейса) -- по одному дереву на каждый индекс. Но даже один " -"единственный индекс может состоять из десятков LSM-деревьев. Попробуем " -"разобраться, зачем." - -msgid "" -"Recall our example with a tree containing 100,000,000 records, 100 bytes " -"each. As time passes, the lowest LSM level may end up holding a 10 Gb run. " -"During compaction, a temporary run of approximately the same size will be " -"created. Data at intermediate levels takes up some space as well, since the " -"tree may store several operations associated with a single key. In total, " -"storing 10 Gb of actual data may require up to 30 Gb of free space: 10 Gb " -"for the last tree level, 10 Gb for a temporary run, and 10 Gb for the " -"remaining data. But what if the data size is not 10 Gb, but 1 Tb? Requiring " -"that the available disk space always be several times greater than the " -"actual data size is financially unpractical, not to mention that it may take" -" dozens of hours to create a 1 Tb run. And in the case of an emergency " -"shutdown or system restart, the process would have to be started from " -"scratch." -msgstr "" -"Рассмотрим наш стандартный пример: 100 000 000 записей по 100 байтов каждая." -" Через некоторое время на самом нижнем уровне LSM у нас может оказаться файл" -" размером 10 ГБ. Во время слияния последнего уровня мы создадим временный " -"файл, который также будет занимать около 10 ГБ. Данные на промежуточных " -"уровнях тоже занимают место: по одному и тому же ключу дерево может хранить " -"несколько операций. Суммарно для хранения 10 ГБ полезных данных нам может " -"потребоваться до 30 ГБ свободного места: 10 ГБ на последний уровень, 10 ГБ " -"на временный файл и 10 ГБ на всё остальное. А если данных не 1 ГБ, а 1 ТБ? " -"Требовать, чтобы количество свободного места на диске всегда в несколько раз" -" превышало объем полезных данных, экономически нецелесообразно, да и " -"создание файла в 1ТБ может занимать десятки часов. При любой аварии или " -"перезапуске системы операцию придется начинать заново." - -msgid "" -"Here’s another scenario. Suppose the primary key is a monotonically " -"increasing sequence—for example, a time series. In this case, most " -"insertions will fall into the right part of the key range, so it wouldn’t " -"make much sense to do a compaction just to append a few million more records" -" to an already huge run." -msgstr "" -"Рассмотрим другую проблему. Представим, что первичный ключ дерева -- это " -"монотонная последовательность, например, временной ряд. В этом случае " -"основные вставки будут приходиться на правую часть диапазона ключей. Нет " -"смысла заново производить слияние лишь для того, чтобы дописать в конец и " -"без того огромного файла еще несколько миллионов записей." - -msgid "" -"But what if writes predominantly occur in a particular region of the key " -"range, whereas most reads take place in a different region? How do you " -"optimize the form of the LSM tree in this case? If it’s too high, read " -"performance is impacted; if it’s too low—write speed is reduced." -msgstr "" -"А если вставки происходят, в основном, в одну часть диапазона ключей, а " -"чтения -- из другой части? Как в этом случае оптимизировать форму дерева? " -"Если оно будет слишком высоким, пострадают чтения, если слишком низким -- " -"запись." - -msgid "" -"Tarantool \"factorizes\" this problem by creating multiple LSM trees for " -"each index. The approximate size of each subtree may be controlled by the " -":ref:`vinyl_range_size ` configuration " -"parameter. We call such subtrees \"ranges\"." -msgstr "" -"Tarantool \"факторизует\" проблему, создавая не одно, а множество LSM-" -"деревьев для каждого индекса. Примерный размер каждого поддерева можно " -"задать в конфигурационном параметре ``vinyl_range_size``. Такие поддеревья " -"называется диапазонами (\"range\")." - -msgid "Factorizing large LSM trees via ranging" -msgstr "Факторизация больших LSM-деревьев с помощью диапазонов" - -msgid "Ranges reflect a static layout of sorted runs" -msgstr "Диапазоны отражают статичную структуру упорядоченных файлов" - -msgid "Slices connect a sorted run into a range" -msgstr "Срезы объединяют упорядоченный файл в диапазон" - -msgid "" -"Initially, when the index has few elements, it consists of a single range. " -"As more elements are added, its total size may exceed :ref:`the maximum " -"range size `. In that case a special operation" -" called \"split\" divides the tree into two equal parts. The tree is split " -"at the middle element in the range of keys stored in the tree. For example, " -"if the tree initially stores the full range of -inf…+inf, then after " -"splitting it at the middle key X, we get two subtrees: one that stores the " -"range of -inf...X, and the other storing the range of X…+inf. With this " -"approach, we always know which subtree to use for writes and which one for " -"reads. If the tree contained deletions and each of the neighboring ranges " -"grew smaller as a result, the opposite operation called \"coalesce\" " -"combines two neighboring trees into one." -msgstr "" -"Изначально, пока в индексе мало элементов, он состоит из одного диапазона. " -"По мере добавления элементов суммарный объем может превысить " -":ref:`максимальный размер диапазона `. В таком" -" случае выполняется операция под названием \"разделение\" (split), которая " -"делит дерево на две равные части. Разделение происходит по срединному " -"элементу диапазона ключей, хранящихся в дереве. Например, если изначально " -"дерево хранит полный диапазон -inf… +inf, то после разделения по срединному " -"ключу X получим два поддерева: одно будет хранить все ключи от -inf до X, " -"другое -- от X до +inf. Таким образом, при вставке или чтении мы однозначно " -"знаем, к какому поддереву обращаться. Если в дереве были удаления и каждый " -"из соседних диапазонов уменьшился, выполняется обратная операция под " -"названием \"объединение\" (coalesce). Она объединяет два соседних дерева в " -"одно." - -msgid "" -"Split and coalesce don’t entail a compaction, the creation of new runs, or " -"other resource-intensive operations. An LSM tree is just a collection of " -"runs. vinyl has a special metadata log that helps keep track of which run " -"belongs to which subtree(s). This has the `.vylog` extension and its format " -"is compatible with an .xlog file. Similarly to an `.xlog` file, the metadata" -" log gets rotated at each checkpoint. To avoid the creation of extra runs " -"with split and coalesce, we have also introduced an auxiliary entity called " -"\"slice\". It’s a reference to a run containing a key range and it’s stored " -"only in the metadata log. Once the reference counter drops to zero, the " -"corresponding file gets removed. When it’s necessary to perform a split or " -"to coalesce, Tarantool creates slice objects for each new tree, removes " -"older slices, and writes these operations to the metadata log, which " -"literally stores records that look like this: ```` or " -"````." -msgstr "" -"Разделение и объединение не приводят к слиянию, созданию новых файлов и " -"прочим тяжеловесным операциям. LSM-дерево -- это лишь набор файлов. В " -"vinyl'е мы реализовали специальный журнал метаданных, позволяющий легко " -"отслеживать, какой файл принадлежит какому поддереву или поддеревьям. Журнал" -" имеет расширение `.vylog`, по формату он совместим с файлом `.xlog`. Как и " -"файл `.xlog`, происходит автоматическая ротация файла при каждой контрольной" -" точке. Чтобы избежать повторного создания файлов при разделении и " -"объединении, мы ввели промежуточную сущность -- срез (slice). Это ссылка на " -"файл с указанием диапазона значений ключа, которая хранится исключительно в " -"журнале метаданных. Когда число ссылок на файл становится равным нулю, файл " -"удаляется. А когда необходимо произвести разделение или объединение, " -"Tarantool создает срезы для каждого нового дерева, старые срезы удаляет, и " -"записывает эти операции в журнал метаданных. Буквально, журнал метаданных " -"хранит записи вида <идентификатор дерева, идентификатор среза> или " -"<идентификатор среза, идентификатор файла, мин, макс>." - -msgid "" -"This way all of the heavy lifting associated with splitting a tree into two " -"subtrees is postponed until a compaction and then is performed " -"automatically. A huge advantage of dividing all of the keys into ranges is " -"the ability to independently control the L0 size as well as the dump and " -"compaction processes for each subtree, which makes these processes " -"manageable and predictable. Having a separate metadata log also simplifies " -"the implementation of both \"truncate\" and \"drop\". In vinyl, they’re " -"processed instantly, since they only work with the metadata log, while " -"garbage collection is done in the background." -msgstr "" -"Таким образом, непосредственно тяжелая работа по разбиению дерева на два поддерева, откладывается до слияния и выполняется автоматически.\n" -"Огромным преимуществом подхода с разделением всего диапазона ключей на диапазоны является возможность независимо управлять размером L0, а также процессом создания дампов и слиянием для каждого поддерева. В результате эти процессы являются управляемыми и предсказуемыми. Наличие отдельного журнала метаданных также упрощает выполнение таких операций, как усечение и удаление -- в vinyl'е они обрабатываются мгновенно, потому что работают исключительно с журналом метаданных, а удаление мусора выполняется в фоне." - -msgid "Advanced features of vinyl" -msgstr "Расширенные возможности vinyl'а" - -msgid "Upsert" -msgstr "Upsert (обновление и вставка)" - -msgid "" -"In the previous sections, we mentioned only two operations stored by an LSM " -"tree: deletion and replacement. Let’s take a look at how all of the other " -"operations can be represented. An insertion can be represented via a " -"replacement—you just need to make sure there are no other elements with the " -"specified key. To perform an update, it’s necessary to read the older value " -"from the tree, so it’s easier to represent this operation as a replacement " -"as well—this speeds up future read requests by the key. Besides, an update " -"must return the new value, so there’s no avoiding hidden reads." -msgstr "" -"В предыдущих разделах упоминались лишь две операции, которые хранит LSM-" -"дерево: удаление и замена. Давайте рассмотрим, как представлены все " -"остальные. Вставку можно представить с помощью замены -- необходимо лишь " -"предварительно убедиться в отсутствии элемента указанным ключом. Для " -"выполнения обновления необходимо предварительно считывать старое значение из" -" дерева, так что и эту операцию проще записать в дерево как замену -- это " -"ускорит будущие чтения по этому ключу. Кроме того, обновление должно вернуть" -" новое значение, так что скрытых чтений никак не избежать." - -msgid "" -"In B-trees, the cost of hidden reads is negligible: to update a block, it " -"first needs to be read from disk anyway. Creating a special update operation" -" for an LSM tree that doesn’t cause any hidden reads is really tempting." -msgstr "" -"В B-деревьях скрытые чтения почти ничего не стоят: чтобы обновить блок, его " -"в любом случае необходимо прочитать с диска. Для LSM-деревьев идея создания " -"специальной операции обновления, которая не приводила бы к скрытым чтениям, " -"выглядит очень заманчивой." - -msgid "" -"Such an operation must contain not only a default value to be inserted if a " -"key has no value yet, but also a list of update operations to perform if a " -"value does exist." -msgstr "" -"Такая операция должна содержать как значение по умолчанию, которое нужно " -"вставить, если данных по ключу еще нет, так и список операций обновления, " -"которые нужно выполнить, если значение существует." - -msgid "" -"At transaction execution time, Tarantool just saves the operation in an LSM " -"tree, then \"executes\" it later, during a compaction." -msgstr "" -"На этапе выполнения транзакции Tarantool лишь сохраняет всю операцию в LSM-" -"дереве, а \"выполняет\" ее уже только во время слияния." - -msgid "The upsert operation:" -msgstr "Операция обновления и вставки:" - -msgid "space:upsert(tuple, {{operator, field, value}, ... })" -msgstr "space:upsert(tuple, {{operator, field, value}, ... })" - -msgid "Non-reading update or insert" -msgstr "Обновление без чтения или вставка" - -msgid "Delayed execution" -msgstr "Отложенное выполнение" - -msgid "Background upsert squashing prevents upserts from piling up" -msgstr "" -"Фоновое сжатие операций обновления и вставки предотвращает накапливание " -"операций" - -msgid "" -"Unfortunately, postponing the operation execution until a compaction doesn’t" -" leave much leeway in terms of error handling. That’s why Tarantool tries to" -" validate upserts as fully as possible before writing them to an LSM tree. " -"However, some checks are only possible with older data on hand, for example " -"when the update operation is trying to add a number to a string or to remove" -" a field that doesn’t exist." -msgstr "" -"К сожалению, если откладывать выполнение операции на этап слияния, " -"возможностей для обработки ошибок не остается. Поэтому Tarantool стремится " -"максимально проверять операции обновления и вставки upsert перед записью в " -"дерево. Тем не менее, некоторые проверки можно выполнить лишь имея старые " -"данные на руках. Например, если обновление прибавляет число к строке или " -"удаляет несуществующее поле." - -msgid "" -"A semantically similar operation exists in many products including " -"PostgreSQL and MongoDB. But anywhere you look, it’s just syntactic sugar " -"that combines the update and replace operations without avoiding hidden " -"reads. Most probably, the reason is that LSM trees as data storage " -"structures are relatively new." -msgstr "" -"Операция с похожей семантикой присутствует во многих продуктах, в том числе " -"в PostgreSQL и MongoDB. Но везде она представляет собой лишь синтаксический " -"сахар, объединяющий обновление и вставку, не избавляя СУБД от необходимости " -"выполнять скрытые чтения. Скорее всего, причиной этого является " -"относительная новизна LSM-деревьев в качестве структур данных для хранения." - -msgid "" -"Even though an upsert is a very important optimization and implementing it " -"cost us a lot of blood, sweat, and tears, we must admit that it has limited " -"applicability. If a table contains secondary keys or triggers, hidden reads " -"can’t be avoided. But if you have a scenario where secondary keys are not " -"required and the update following the transaction completion will certainly " -"not cause any errors, then the operation is for you." -msgstr "" -"Хотя обновление и вставка upsert представляет собой очень важную " -"оптимизацию, и ее реализация стоила нам долгой напряженной работы, следует " -"признать, что ее применимость ограничена. Если в таблице есть вторичные " -"ключи или триггеры, скрытых чтений не избежать. А если у вас есть сценарии, " -"для которых не нужны вторичные ключи и обновление после завершения " -"транзакции однозначно не приведет к ошибкам -- эта операция для вас." - -msgid "" -"I’d like to tell you a short story about an upsert. It takes place back when" -" vinyl was only beginning to \"mature\" and we were using an upsert in " -"production for the first time. We had what seemed like an ideal environment " -"for it: we had tons of keys, the current time was being used as values; " -"update operations were inserting keys or modifying the current time; and we " -"had few reads. Load tests yielded great results." -msgstr "" -"Небольшая история, связанная с этим оператором: vinyl только начинал " -"\"взрослеть\", и мы впервые запустили операцию обновления и вставки upsert " -"на рабочие серверы. Казалось бы, идеальные условия: огромный набор ключей, " -"текущее время в качестве значения, операции обновления либо вставляют ключ, " -"либо обновляют текущее время, редкие операции чтения. Нагрузочные тесты " -"показали отличные результаты." - -msgid "" -"Nevertheless, after a couple of days, the Tarantool process started eating " -"up 100% of our CPU, and the system performance dropped close to zero." -msgstr "" -"Тем не менее, после пары дней работы процесс Tarantool'а начал потреблять " -"100 % CPU, а производительность системы упала практически до нуля." - -msgid "" -"We started digging into the issue and found out that the distribution of " -"requests across keys was significantly different from what we had seen in " -"the test environment. It was...well, quite nonuniform. Most keys were " -"updated once or twice a day, so the database was idle for the most part, but" -" there were much hotter keys with tens of thousands of updates per day. " -"Tarantool handled those just fine. But in the case of lookups by key with " -"tens of thousands of upserts, things quickly went downhill. To return the " -"most recent value, Tarantool had to read and \"replay\" the whole history " -"consisting of all of the upserts. When designing upserts, we had hoped this " -"would happen automatically during a compaction, but the process never even " -"got to that stage: the L0 size was more than enough, so there were no dumps." -msgstr "" -"Начали подробно изучать проблему. Оказалось, что распределение запросов по " -"ключам существенно отличалось от того, что мы видели в тестовом окружении. " -"Оно было… очень неравномерное. Большая часть ключей обновлялась 1-2 раза за " -"сутки, и база для них не была нагружена. Но были ключи гораздо более горячие" -" -- десятки тысяч обновлений в сутки. Tarantool прекрасно справлялся с этим " -"потоком обновлений. А вот когда по ключу с десятком тысяч операций " -"обновления и вставки upsert происходило чтение, всё шло под откос. Чтобы " -"вернуть последнее значение, Tarantool'у приходилось каждый раз прочитать и " -"\"проиграть\" историю из десятков тысяч команд обновления и вставки upsert. " -"На стадии проекта мы надеялись, что это произойдет автоматически во время " -"слияния уровней, но до слияния дело даже не доходило: памяти L0 было " -"предостаточно, и дампы не создавались." - -msgid "" -"We solved the problem by adding a background process that performed " -"readaheads on any keys that had more than a few dozen upserts piled up, so " -"all those upserts were squashed and substituted with the read value." -msgstr "" -"Решили мы проблему добавлением фонового процесса, осуществляющего " -"упреждающие чтения для ключей, по которым накопилось больше нескольких " -"десятков операций обновления и вставки upsert с последующей заменой на " -"прочитанное значение." - -msgid "Secondary keys" -msgstr "Вторичные ключи" - -msgid "" -"Update is not the only operation where optimizing hidden reads is critical. " -"Even the replace operation, given secondary keys, has to read the older " -"value: it needs to be independently deleted from the secondary indexes, and " -"inserting a new element might not do this, leaving some garbage behind." -msgstr "" -"Не только для операции обновления остро стоит проблема оптимизации скрытых " -"чтений. Даже операция замены при наличии вторичных ключей вынуждена читать " -"старое значение: его нужно независимо удалить из вторичных индексов, а " -"вставка нового элемента может этого не сделать, оставив в индексе мусор." - -msgid "" -"If secondary indexes are not unique, then collecting \"garbage\" from them " -"can be put off until a compaction, which is what we do in Tarantool. The " -"append-only nature of LSM trees allowed us to implement full-blown " -"serializable transactions in vinyl. Read-only requests use older versions of" -" data without blocking any writes. The transaction manager itself is fairly " -"simple for now: in classical terms, it implements the MVTO (multiversion " -"timestamp ordering) class, whereby the winning transaction is the one that " -"finished earlier. There are no locks and associated deadlocks. Strange as it" -" may seem, this is a drawback rather than an advantage: with parallel " -"execution, you can increase the number of successful transactions by simply " -"holding some of them on lock when necessary. We’re planning to improve the " -"transaction manager soon. In the current release, we focused on making the " -"algorithm behave 100% correctly and predictably. For example, our " -"transaction manager is one of the few on the NoSQL market that supports so-" -"called \"gap locks\"." -msgstr "" -"Если вторичные индексы не уникальны, то удаление из них \"мусора\" также " -"можно перенести в фазу слияния, что мы и делаем в Tarantool'е. Природа LSM-" -"дерева, в котором файлы обновляются путем присоединения новых записей, " -"позволила нам реализовать в vinyl'е полноценные сериализуемые транзакции. " -"Запросы только для чтения при этом используют старые версии данных и не " -"блокируют запись. Сам менеджер транзакций пока довольно простой: в " -"традиционной классификации он реализует класс MVTO (multiversion timestamp " -"ordering -- упорядочение временных меток на основе многоверсионности), при " -"этом в конфликте побеждает та транзакция, что завершилась первой. Блокировок" -" и свойственных им взаимоблокировок нет. Как ни странно, это скорее " -"недостаток, чем преимущество: при параллельном выполнении можно повысить " -"количество успешных транзакций, задерживая некоторые из них в нужный момент " -"на блокировке. Развитие менеджера транзакций в наших ближайших планах. В " -"текущей версии мы сфокусировались на том, чтобы сделать алгоритм корректным " -"и предсказуемым на 100%. Например, наш менеджер транзакций -- один из " -"немногих в NoSQL-среде, поддерживающих так называемые \"блокировки " -"разрывов\" (gap locks)." diff --git a/locale/ru/LC_MESSAGES/book/box/engines/memtx.po b/locale/ru/LC_MESSAGES/book/box/engines/memtx.po new file mode 100644 index 0000000000..308c09dfdc --- /dev/null +++ b/locale/ru/LC_MESSAGES/book/box/engines/memtx.po @@ -0,0 +1,372 @@ + +msgid "Storing data with memtx" +msgstr "Хранение данных с помощью memtx" + +msgid "" +"The ``memtx`` storage engine is used in Tarantool by default. It keeps all " +"data in random-access memory (RAM), and therefore has very low read latency." +msgstr "" +"Движок базы данных ``memtx`` используется в Tarantool по умолчанию. Он " +"хранит все данные в оперативной памяти (RAM), поэтому значение задержки " +"чтения у него очень низкое." + +msgid "" +"The obvious question here is: if all the data is stored in memory, how can " +"you prevent the data loss in case of emergency such as outage or Tarantool " +"instance failure?" +msgstr "" +"Очевидный вопрос: если все данные хранятся в памяти, как можно предотвратить" +" их потерю в случае чрезвычайной ситуации, например при отключении " +"электропитания или сбое экземпляра Tarantool?" + +msgid "" +"First of all, Tarantool persists all data changes by writing requests to the" +" write-ahead log (WAL) that is stored on disk. Read more about that in the " +":ref:`memtx-persist` section. In case of a distributed application, there is" +" an option of synchronous replication that ensures keeping the data " +"consistent on a quorum of replicas. Although replication is not directly a " +"storage engine topic, it is a part of the answer regarding data safety. Read" +" more in the :ref:`memtx-replication` section." +msgstr "" +"Прежде всего, Tarantool сохраняет все изменения данных, записывая запросы в " +"журнал упреждающей записи (WAL), хранящийся на диске. Подробнее это описано " +"в разделе :ref:`memtx-persist`. В случае распределенного приложения возможна" +" синхронная репликация, которая обеспечивают согласованность данных в " +"кворуме реплик. Хотя репликация напрямую не относится к механизму хранения, " +"она отчасти способствует безопасности данных. Подробности можно найти в " +"разделе :ref:`memtx-replication`." + +msgid "" +"In this chapter, the following topics are discussed in brief with the " +"references to other chapters that explain the subject matter in details." +msgstr "" +"Ниже указаны темы, которые обсуждаются в этой главе. В тексте вы также " +"найдете ссылки на главы с подробными сведениями по каждой из тем." + +msgid "Memory model" +msgstr "Модель памяти" + +msgid "" +"There is a fixed number of independent :ref:`execution threads `. The threads don't share state. Instead they " +"exchange data using low-overhead message queues. While this approach limits " +"the number of cores that the instance uses, it removes competition for the " +"memory bus and ensures peak scalability of memory access and network " +"throughput." +msgstr "" +"Есть фиксированное количество независимых :ref:`потоков выполнения `. У этих потоков нет общего состояния. Вместо этого " +"они обмениваются данными через очереди сообщений с низкими накладными " +"расходами. Хотя такой подход ограничивает количество ядер, которое может " +"использовать экземпляр, он устраняет конкуренцию за шину памяти и " +"обеспечивает максимальную масштабируемость доступа к памяти и пропускной " +"способности сети." + +msgid "" +"Only one thread, namely, the **transaction processor thread** (further, **TX" +" thread**) can access the database, and there is only one TX thread for each" +" Tarantool instance. In this thread, transactions are executed in a strictly" +" consecutive order. Multi-statement transactions exist to provide isolation:" +" each transaction sees a consistent database state and commits all its " +"changes atomically. At commit time, a yield happens and all transaction " +"changes are written to :ref:`WAL ` in a single batch. In case" +" of errors during transaction execution, a transaction is rolled-back " +"completely. Read more in the following sections: :ref:`atomic-transactions`," +" :ref:`atomic-transactional-manager`." +msgstr "" +"Обращаться к базе данных может только **поток обработчика транзакций** " +"(далее — **поток TX**). В каждом экземпляре Tarantool есть только один такой" +" поток. Транзакции в этом потоке выполняются строго последовательно. " +"Транзакции, состоящие из нескольких инструкций, обеспечивают изоляцию: " +"каждая транзакция видит согласованное состояние базы данных и применяет " +"коммит со всеми своими изменениями атомарно. Во время коммита происходит " +"передача управления, и все изменения транзакции записываются в :ref:`WAL-" +"файл ` одним пакетом. Если во время выполнения транзакции " +"произошли ошибки, она полностью отменяется. Подробности можно найти в " +"следующих разделах: :ref:`atomic-transactions`, :ref:`atomic-transactional-" +"manager`." + +msgid "" +"Within the TX thread, there is a memory area allocated for Tarantool to " +"store data. It's called **Arena**." +msgstr "" +"Внутри потока TX есть область памяти, в которой Tarantool хранит данные. Эта" +" область называется **Arena**." + +msgid "" +"Data is stored in :term:`spaces `. Spaces contain database " +"records—:term:`tuples `. To access and manipulate the data stored in " +"spaces and tuples, Tarantool builds :doc:`indexes `." +msgstr "" +"Данные хранятся в :term:`спейсах `. Спейсы содержат записи базы " +"данных — :term:`кортежи `. Чтобы обращаться к данным, хранящимся в " +"спейсах и кортежах, и изменять их, Tarantool создаёт :doc:`индексы " +"`." + +msgid "" +"Special `allocators `__ manage memory " +"allocations for spaces, tuples, and indexes within the Arena. The slab " +"allocator is the main allocator used to store tuples. Tarantool has a built-" +"in module called ``box.slab`` which provides the slab allocator statistics " +"that can be used to monitor the total memory usage and memory fragmentation." +" For details, see the ``box.slab`` module :doc:`reference " +"`." +msgstr "" +"Распределением памяти для спейсов, кортежей и индексов внутри области Arena " +"управляют специальные `аллокаторы `__. " +"Для хранения кортежей главным образом используется аллокатор slab. В " +"Tarantool встроен модуль под названием ``box.slab``, предоставляющий " +"статистику распределения slab. С помощью этой статистики можно отслеживать " +"общее использование памяти и ее фрагментацию. Подробности см. в :doc:` " +"руководстве ` по модулю ``box.slab``." + +msgid "" +"Also inside the TX thread, there is an event loop. Within the event loop, " +"there are a number of :ref:`fibers `. Fibers are cooperative " +"primitives that allows interaction with spaces, that is, reading and " +"writting the data. Fibers can interact with the event loop and between each " +"other directly or by using special primitives called channels. Due to the " +"usage of fibers and :ref:`cooperative multitasking `, the ``memtx`` engine is lock-free in typical " +"situations." +msgstr "" +"Внутри потока TX также есть цикл событий. Этот цикл содержит несколько " +":ref:`файберов ` — кооперативных примитивов, позволяющих " +"взаимодействовать со спейсами, то есть читать и записывать данные. Файберы " +"могут обращаться к циклу событий и друг к другу как напрямую, так и " +"посредством специальных примитивов, называемых каналами. Благодаря " +"использованию файберов и :ref:`кооперативной многозадачности ` движок ``memtx``, как правило, свободен от " +"блокировок." + +msgid "" +"To interact with external users, there is a separate :ref:`network thread " +"` also called the **iproto thread**. The " +"iproto thread receives a request from the network, parses and checks the " +"statement, and transforms it into a special structure—a message containing " +"an executable statement and its options. Then the iproto thread ships this " +"message to the TX thread and runs the user's request in a separate fiber." +msgstr "" +"Чтобы взаимодействовать с внешними пользователями, используется отдельный " +":ref:`сетевой поток `, называемый также " +"**поток iproto**. Поток iproto получает запрос из сети, разбирает и " +"проверяет инструкцию из него, а затем преобразует ее в специальную структуру" +" — сообщение, содержащее исполнимую инструкцию с параметрами. Затем iproto " +"доставляет это сообщение в поток TX и исполняет запрос пользователя в " +"отдельном файбере." + +msgid "Data persistence" +msgstr "Персистентность данных" + +msgid "" +"To ensure :ref:`data persistence `, Tarantool does " +"two things." +msgstr "" +"Чтобы обеспечить :ref:`персистентность данных `, " +"Tarantool выполняет следующие действия." + +msgid "" +"After executing data change requests in memory, Tarantool writes each such " +"request to the :ref:`write-ahead log (WAL) ` files " +"(``.xlog``) that are stored on disk. Tarantool does this via a separate " +"thread called the **WAL thread**." +msgstr "" +"Исполнив в памяти запросы на изменение данных, Tarantool записывает все эти " +"запросы в файлы :ref:`журнала упреждающей записи (WAL) ` (с " +"расширением ``.xlog``), хранящиеся на диске. Это делается в отдельном " +"потоке, называемом **поток WAL**." + +msgid "" +"Tarantool periodically takes the entire :doc:`database snapshot " +"` and saves it on disk. It is " +"necessary for accelerating instance's restart because when there are too " +"many WAL files, it can be difficult for Tarantool to restart quickly." +msgstr "" +"Tarantool периодически делает :doc:`снимок всей базы данных " +"` и сохраняет его на диск. Это " +"необходимо для ускорения перезапуска экземпляра, так как если файлов WAL " +"слишком много, то Tarantool не сможет быстро перезапуститься." + +msgid "" +"To save a snapshot, there is a special fiber called the **snapshot daemon**." +" It reads the consistent content of the entire Arena and writes it on disk " +"into a snapshot file (``.snap``). Due of the cooperative multitasking, " +"Tarantool cannot write directly on disk because it is a locking operation. " +"That is why Tarantool interacts with disk via a separate pool of threads " +"from the :doc:`fio ` library." +msgstr "" +"Специальный файбер под названием **демон снимков** (**snapshot daemon**) " +"позволяет сохранять снимки. Он читает консистентное содержимое всей области " +"Arena и записывает его на диск в файл снимка (с расширением ``.snap``). Из-" +"за кооперативной многозадачности Tarantool не может записывать данные " +"непосредственно на диск, так как это блокирующая операция. Поэтому Tarantool" +" взаимодействует с диском через отдельный пул потоков из библиотеки " +":doc:`fio `." + +msgid "" +"So, even in emergency situations such as an outage or a Tarantool instance " +"failure, when the in-memory database is lost, the data can be restored fully" +" during Tarantool restart." +msgstr "" +"Таким образом, при перезапуске Tarantool данные можно полностью восстановить" +" даже в аварийных ситуациях, например при отключении питания или падении " +"экземпляра Tarantool, когда хранящаяся в оперативной памяти база данных " +"утеряна." + +msgid "What happens during the restart:" +msgstr "Что происходит при перезапуске:" + +msgid "Tarantool finds the latest snapshot file and reads it." +msgstr "Tarantool находит и читает последний файл снимка." + +msgid "" +"Tarantool finds all the WAL files created after that snapshot and reads them" +" as well." +msgstr "" +"Tarantool также находит и читает все файлы WAL, созданные после этого " +"снимка." + +msgid "" +"When the snapshot and WAL files have been read, there is a fully recovered " +"in-memory data set corresponding to the state when the Tarantool instance " +"stopped." +msgstr "" +"Как только снимок и файлы WAL будут прочитаны, набор данных в памяти будет " +"полностью восстановлен. Он будет соответствовать состоянию экземпляра " +"Tarantool на момент, когда тот прекратил работу." + +msgid "" +"While reading the snapshot and WAL files, Tarantool is building the primary " +"indexes." +msgstr "" +"Во время чтения снимка и файлов WAL Tarantool строит первичные индексы." + +msgid "" +"When all the data is in memory again, Tarantool is building the secondary " +"indexes." +msgstr "Когда все данные снова в памяти, Tarantool строит вторичные индексы." + +msgid "Tarantool runs the application." +msgstr "Tarantool запускает приложение." + +msgid "Accessing data" +msgstr "Доступ к данным" + +msgid "" +"To access and manipulate the data stored in memory, Tarantool builds " +"indexes. Indexes are also stored in memory within the Arena." +msgstr "" +"Чтобы обращаться к данным, хранящимся в оперативной памяти, и работать с " +"ними, Tarantool строит индексы, которые хранятся внутри области памяти " +"Arena." + +msgid "" +"Tarantool supports a number of :ref:`index types ` intended for" +" different usage scenarios. The possible types are TREE, HASH, BITSET, and " +"RTREE." +msgstr "" +"Tarantool поддерживает несколько :ref:`типов индексов `: TREE, " +"HASH, BITSET, RTREE. Все они предназначены для разных сценариев " +"использования." + +msgid "" +"Select query are possible against secondary index keys as well as primary " +"keys. Indexes can have multi-part keys." +msgstr "" +"Можно выполнять SELECT-запросы как по первичным, так и по вторичным ключам " +"индекса. Ключи могут быть составными." + +msgid "" +"For detailed information about indexes, refer to the " +":doc:`/book/box/indexes` page." +msgstr "" +"Подробности про индексы можно найти на странице :doc:`/book/box/indexes`." + +msgid "Replicating data" +msgstr "Репликация данных" + +msgid "" +"Although this topic is not directly related to the ``memtx`` engine, it " +"completes the overall picture of how Tarantool works in case of a " +"distributed application." +msgstr "" +"Хотя эта тема не имеет прямого отношения к движку ``memtx``, она дополняет " +"общую картину того, как работает Tarantool, когда приложение распределенное." + +msgid "" +"Replication allows multiple Tarantool instances to work on copies of the " +"same database. The copies are kept in sync because each instance can " +"communicate its changes to all the other instances. It is implemented via " +"WAL replication." +msgstr "" +"Репликация позволяет нескольким экземплярам Tarantool работать с копиями " +"одной и той же базы данных. Эти копии остаются синхронизированными благодаря" +" тому, что каждый экземпляр может сообщать другим экземплярам о совершенных " +"им изменениях. Для этого используется WAL-репликация." + +msgid "" +"To send data to a replica, Tarantool runs another thread called **relay**. " +"Its purpose is to read the WAL files and send them to replicas. On a " +"replica, the fiber called **applier** is run. It receives the changes from a" +" remote node and applies them to the replica's Arena. All the changes are " +"being written to WAL files via the replica's WAL thread as if they are done " +"locally." +msgstr "" +"Чтобы отправить данные на реплику, Tarantool запускает еще один поток, " +"называемый **relay**. Этот поток читает файлы WAL и отправляет их репликам. " +"На каждой реплике выполняется файбер под названием **applier**. Он получает " +"изменения от удаленного узла и применяет их к области Arena реплики. Все " +"изменения записываются в файлы WAL через поток WAL реплики так же, как если " +"бы они были сделаны локально." + +msgid "" +"By default, :ref:`replication ` in Tarantool is " +"asynchronous: if a transaction is committed locally on a master node, it " +"does not mean it is replicated onto any replicas." +msgstr "" +"В Tarantool :ref:`репликация ` по умолчанию " +"асинхронна: то, что транзакция проходит коммит локально на главном узле, не " +"означает, что она отправляется на какие-то другие реплики." + +msgid "" +":ref:`Synchronous replication ` exists to solve this problem. " +"Synchronous transactions are not considered committed and are not responded " +"to a client until they are replicated onto some number of replicas." +msgstr "" +"Эту проблему решает :ref:`синхронная репликация `. Каждая " +"синхронная транзакция проходит коммит лишь после репликации на некотором " +"количестве экземпляров, и только тогда клиенту приходит ответ о завершении " +"транзакции." + +msgid "" +"For more information on replication, refer to the :doc:`corresponding " +"chapter `." +msgstr "" +"Более подробные сведения вы найдете в :doc:`главе о репликации " +"`." + +msgid "Summary" +msgstr "Ключевые сведения" + +msgid "" +"The main key points describing how the in-memory storage engine works can be" +" summarized in the following way:" +msgstr "Вот главные принципы, по которым работает движок:" + +msgid "All data is in RAM." +msgstr "Все данные находятся в оперативной памяти." + +msgid "Access to data is from one thread." +msgstr "Доступ к данным производится только из одного потока." + +msgid "Tarantool writes all data change requests in WAL." +msgstr "Tarantool записывает все изменения данных в файлы WAL." + +msgid "Data snapshots are taken periodically." +msgstr "Периодически создаются снимки данных." + +msgid "Indexes are build to access the data." +msgstr "Для доступа к данным создаются индексы." + +msgid "WAL can be replicated." +msgstr "Файлы WAL можно реплицировать." diff --git a/locale/ru/LC_MESSAGES/book/box/engines/vinyl.po b/locale/ru/LC_MESSAGES/book/box/engines/vinyl.po new file mode 100644 index 0000000000..4395c2ed1a --- /dev/null +++ b/locale/ru/LC_MESSAGES/book/box/engines/vinyl.po @@ -0,0 +1,1474 @@ + +msgid "Storing data with vinyl" +msgstr "Хранение данных с помощью vinyl" + +msgid "" +"Tarantool is a transactional and persistent DBMS that maintains 100% of its " +"data in RAM. The greatest advantages of in-memory databases are their speed " +"and ease of use: they demonstrate consistently high performance, but you " +"never need to tune them." +msgstr "" +"Tarantool -- это транзакционная, персистентная СУБД, которая хранит 100% " +"данных в оперативной памяти. Основными преимущества хранения данных " +"оперативной памяти являются скорость и простота использования: нет " +"необходимости в оптимизации, однако производительность остается стабильно " +"высокой." + +msgid "" +"A few years ago we decided to extend the product by implementing a classical" +" storage engine similar to those used by regular DBMSs: it uses RAM for " +"caching, while the bulk of its data is stored on disk. We decided to make it" +" possible to set a storage engine independently for each table in the " +"database, which is the same way that MySQL approaches it, but we also wanted" +" to support transactions from the very beginning." +msgstr "" +"Несколько лет назад мы решили расширить продукт путем реализации " +"классической технологии хранения как в обычных СУБД: в оперативной памяти " +"хранится лишь кэш данных, а основной объем данных находится на диске. Мы " +"решили, что движок хранения можно будет выбирать независимо для каждой " +"таблицы, как это реализовано в MySQL, но при этом с самого начала будет " +"реализована поддержка транзакций." + +msgid "" +"The first question we needed to answer was whether to create our own storage" +" engine or use an existing library. The open-source community offered a few " +"viable solutions. The RocksDB library was the fastest growing open-source " +"library and is currently one of the most prominent out there. There were " +"also several lesser-known libraries to consider, such as WiredTiger, " +"ForestDB, NestDB, and LMDB." +msgstr "" +"Первый вопрос, на который нужен был ответ: создавать свой движок или " +"использовать уже существующую библиотеку? Сообщество разработчиков открытого" +" ПО предлагает готовые библиотеки на выбор. Активнее всего развивалась " +"библиотека RocksDB, которая к настоящему времени стала одной из самых " +"популярных. Есть также несколько менее известных библиотек: WiredTiger, " +"ForestDB, NestDB, LMDB." + +msgid "" +"Nevertheless, after studying the source code of existing libraries and " +"considering the pros and cons, we opted for our own storage engine. One " +"reason is that the existing third-party libraries expected requests to come " +"from multiple operating system threads and thus contained complex " +"synchronization primitives for controlling parallel data access. If we had " +"decided to embed one of these in Tarantool, we would have made our users " +"bear the overhead of a multithreaded application without getting anything in" +" return. The thing is, Tarantool has an actor-based architecture. The way it" +" processes transactions in a dedicated thread allows it to do away with the " +"unnecessary locks, interprocess communication, and other overhead that " +"accounts for up to 80% of processor time in multithreaded DBMSs." +msgstr "" +"Тем не менее, изучив исходный код существующих библиотек и взвесив все " +"\"за\" и \"против\", мы решили написать свой движок. Одна из причин -- все " +"существующие сторонние библиотеки предполагают, что запросы к данным могут " +"поступать из множества потоков операционной системы, и поэтому содержат " +"сложные примитивы синхронизации для управления одновременным доступом к " +"данным. Если бы мы решили встраивать одну из них в Tarantool, то " +"пользователи были бы вынуждены нести издержки многопоточных приложений, не " +"получая ничего взамен. Дело в том, что в основе Tarantool лежит архитектура " +"на основе акторов. Обработка транзакций в выделенном потоке позволяет " +"обойтись без лишних блокировок, межпроцессного взаимодействия и других " +"затрат ресурсов, которые забирают до 80% процессорного времени в " +"многопоточных СУБД." + +msgid "*The Tarantool process consists of a fixed number of \"actor\" threads*" +msgstr "*Процесс в Tarantool состоит из заданного количества потоков*" + +msgid "" +"If you design a database engine with cooperative multitasking in mind right " +"from the start, it not only significantly speeds up the development process," +" but also allows the implementation of certain optimization tricks that " +"would be too complex for multithreaded engines. In short, using a third-" +"party solution wouldn’t have yielded the best result." +msgstr "" +"Если изначально проектировать движок с учетом кооперативной многозадачности," +" можно не только существенно ускорить работу, но и реализовать приемы " +"оптимизации, слишком сложные для многопоточных движков. В общем, " +"использование стороннего решения не привело бы к лучшему результату." + +msgid "Algorithm" +msgstr "Алгоритм" + +msgid "" +"Once the idea of using an existing library was off the table, we needed to " +"pick an architecture to build upon. There are two competing approaches to " +"on-disk data storage: the older one relies on B-trees and their variations; " +"the newer one advocates the use of log-structured merge-trees, or \"LSM\" " +"trees. MySQL, PostgreSQL, and Oracle use B-trees, while Cassandra, MongoDB, " +"and CockroachDB have adopted LSM trees." +msgstr "" +"Отказавшись от идеи внедрения существующих библиотек, необходимо было " +"выбрать архитектуру для использования в качестве основы. Есть два " +"альтернативных подхода к хранению данных на диске: старая модель с " +"использованием B-деревьев и их разновидностей и новая -- на основе " +"журнально-структурированных деревьев со слиянием, или LSM-деревьев (Log " +"Structured Merge Tree). MySQL, PostgreSQL и Oracle используют B-деревья, а " +"Cassandra, MongoDB и CockroachDB уже используют LSM-деревья." + +msgid "" +"B-trees are considered better suited for reads and LSM trees—for writes. " +"However, with SSDs becoming more widespread and the fact that SSDs have read" +" throughput that’s several times greater than write throughput, the " +"advantages of LSM trees in most scenarios was more obvious to us." +msgstr "" +"Считается, что B-деревья более эффективны для чтения, а LSM-деревья -- для " +"записи. Тем не менее, с распространением SSD-дисков, у которых в несколько " +"раз выше производительность чтения по сравнению с производительностью " +"записи, преимущества LSM-деревьев стали очевидны в большинстве сценариев." + +msgid "" +"Before dissecting LSM trees in Tarantool, let’s take a look at how they " +"work. To do that, we’ll begin by analyzing a regular B-tree and the issues " +"it faces. A B-tree is a balanced tree made up of blocks, which contain " +"sorted lists of key- value pairs. (Topics such as filling and balancing a " +"B-tree or splitting and merging blocks are outside of the scope of this " +"article and can easily be found on Wikipedia). As a result, we get a " +"container sorted by key, where the smallest element is stored in the " +"leftmost node and the largest one in the rightmost node. Let’s have a look " +"at how insertions and searches in a B-tree happen." +msgstr "" +"Прежде чем разбираться с LSM-деревьями в Tarantool'е, посмотрим, как они " +"работают. Для этого разберем устройство обычного B-дерева и связанные с ним " +"проблемы. \"B\" в слове B-tree означает \"Block\", то есть это " +"сбалансированное дерево, состоящее из блоков, которые содержат " +"отсортированные списки пар ключ-значение. Вопросы наполнения дерева, " +"балансировки, разбиения и слияния блоков выходят за рамки данной статьи, " +"подробности вы сможете прочитать в Википедии. В итоге мы получаем " +"отсортированный по возрастанию ключа контейнер, минимальный элемент которого" +" хранится в крайнем левом узле, а максимальный -- в крайнем правом. " +"Посмотрим, как в B-дереве осуществляется поиск и вставка данных." + +msgid "*Classical B-tree*" +msgstr "*Классическое B-дерево*" + +msgid "" +"If you need to find an element or check its membership, the search starts at" +" the root, as usual. If the key is found in the root block, the search " +"stops; otherwise, the search visits the rightmost block holding the largest " +"element that’s not larger than the key being searched (recall that elements " +"at each level are sorted). If the first level yields no results, the search " +"proceeds to the next level. Finally, the search ends up in one of the leaves" +" and probably locates the needed key. Blocks are stored and read into RAM " +"one by one, meaning the algorithm reads :math:`logB(N)` blocks in a single " +"search, where N is the number of elements in the B-tree. In the simplest " +"case, writes are done similarly: the algorithm finds the block that holds " +"the necessary element and updates (inserts) its value." +msgstr "" +"Если необходимо найти элемент или проверить его наличие, поиск начинается, " +"как обычно, с вершины. Если ключ обнаружен в корневом блоке, поиск " +"заканчивается; в противном случае, переходим в блок с наибольшим меньшим " +"ключом, то есть в самый правый блок, в котором еще есть элементы меньше " +"искомого (элементы на всех уровнях расположены по возрастанию). Если и там " +"элемент не найден, снова переходим на уровень ниже. В конце концов окажемся " +"в одном из листьев и, возможно, обнаружим искомый элемент. Блоки дерева " +"хранятся на диске и читаются в оперативную память по одному, то есть в " +"рамках одного поиска алгоритм считывает :math:`logB(N)` блоков, где N -- это" +" количество элементов в B-дереве. Запись в самом простом случае " +"осуществляется аналогично: алгоритм находит блок, который содержит " +"необходимый элемент, и обновляет (вставляет) его значение." + +msgid "" +"To better understand the data structure, let’s consider a practical example:" +" say we have a B-tree with 100,000,000 nodes, a block size of 4096 bytes, " +"and an element size of 100 bytes. Thus each block will hold up to 40 " +"elements (all overhead considered), and the B-tree will consist of around " +"2,570,000 blocks and 5 levels: the first four will have a size of 256 Mb, " +"while the last one will grow up to 10 Gb. Obviously, any modern computer " +"will be able to store all of the levels except the last one in filesystem " +"cache, so read requests will require just a single I/O operation." +msgstr "" +"Чтобы наглядно представить себе эту структуру данных, возьмем B-дерево на " +"100 000 000 узлов и предположим, что размер блока равен 4096 байтов, а " +"размер элемента -- 100 байтов. Таким образом, в каждом блоке можно будет " +"разместить до 40 элементов с учетом накладных расходов, а в B-дереве будет " +"около 2 570 000 блоков, пять уровней, при этом первые четыре займут по 256 " +"МБ, а последний -- до 10 ГБ. Очевидно, что на любом современном компьютере " +"все уровни, кроме последнего, успешно попадут в кэш файловой системы, и " +"фактически любая операция чтения будет требовать не более одной операции " +"ввода-вывода." + +msgid "" +"But if we change our perspective —B-trees don’t look so good anymore. " +"Suppose we need to update a single element. Since working with B-trees " +"involves reading and writing whole blocks, we would have to read in one " +"whole block, change our 100 bytes out of 4096, and then write the whole " +"updated block to disk. In other words,we were forced to write 40 times more " +"data than we actually modified!" +msgstr "" +"Ситуация выглядит существенно менее радужно при смене точки зрения. " +"Предположим, что необходимо обновить один элемент дерева. Так как операции с" +" B-деревьями работают через чтение и запись целых блоков, приходится " +"прочитать 1 блок в память, изменить 100 байт из 4096, а затем записать " +"обновленный блок на диск. Таким образом, нам пришлось записать в 40 раз " +"больше, чем реальный объем измененных данных!" + +msgid "" +"If you take into account the fact that an SSD block has a size of 64 Kb+ and" +" not every modification changes a whole element, the extra disk workload can" +" be greater still." +msgstr "" +"Принимая во внимание, что внутренний размер блока в SSD-дисках может быть 64" +" КБ и больше, и не любое изменение элемента меняет его целиком, объем " +"\"паразитной\" нагрузки на диск может быть еще выше." + +msgid "" +"Authors of specialized literature and blogs dedicated to on-disk data " +"storage have coined two terms for these phenomena: extra reads are referred " +"to as \"read amplification\" and writes as \"write amplification\"." +msgstr "" +"Феномен таких \"паразитных\" чтений в литературе и блогах, посвященных " +"хранению на диске, называется read amplification (усложнение чтения), а " +"феномен \"паразитной\" записи -- write amplification (усложнение записи)." + +msgid "" +"The amplification factor (multiplication coefficient) is calculated as the " +"ratio of the size of actual read (or written) data to the size of data " +"needed (or actually changed). In our B-tree example, the amplification " +"factor would be around 40 for both reads and writes." +msgstr "" +"Коэффициент усложнения, то есть коэффициент умножения, вычисляется как " +"отношение размера фактически прочитанных (или записанных) данных к реально " +"необходимому (или измененному) размеру. В нашем примере с B-деревом " +"коэффициент составит около 40 как для чтения, так и для записи." + +msgid "" +"The huge number of extra I/O operations associated with updating data is one" +" of the main issues addressed by LSM trees. Let’s see how they work." +msgstr "" +"Объем \"паразитных\" операций ввода-вывода при обновлении данных является " +"одной из основных проблем, которую решают LSM-деревья. Рассмотрим, как это " +"работает." + +msgid "" +"The key difference between LSM trees and regular B-trees is that LSM trees " +"don’t just store data (keys and values), but also data operations: " +"insertions and deletions." +msgstr "" +"Ключевое отличие LSM-деревьев от классических B-деревьев заключается в том, " +"что LSM-деревья не просто хранят данные (ключи и значения), а также операции" +" с данными: вставки и удаления." + +msgid "|br|" +msgstr "|br|" + +msgid "LSM tree:" +msgstr "LSM-дерево:" + +msgid "Stores statements, not values:" +msgstr "Хранит операторы, а не значения:" + +msgid "REPLACE" +msgstr "REPLACE" + +msgid "DELETE" +msgstr "DELETE" + +msgid "UPSERT" +msgstr "UPSERT" + +msgid "" +"Every statement is marked by LSN Append-only files, garbage is collected " +"after a checkpoint" +msgstr "" +"Для каждого оператора назначается LSN Обновление файлов происходит только " +"путем присоединения новых записей, сборка мусора проводится после " +"контрольной точки" + +msgid "Transactional log of all filesystem changes: vylog" +msgstr "Журнал транзакций при любых изменениях в системе: vylog" + +msgid "" +"For example, an element corresponding to an insertion operation has, apart " +"from a key and a value, an extra byte with an operation code (\"REPLACE\" in" +" the image above). An element representing the deletion operation contains a" +" key (since storing a value is unnecessary) and the corresponding operation " +"code—\"DELETE\". Also, each LSM tree element has a log sequence number " +"(LSN), which is the value of a monotonically increasing sequence that " +"uniquely identifies each operation. The whole tree is first ordered by key " +"in ascending order, and then, within a single key scope, by LSN in " +"descending order." +msgstr "" +"Например, элемент для операции вставки, помимо ключа и значения, содержит " +"дополнительный байт с кодом операции -- обозначенный выше как REPLACE. " +"Элемент для операции удаления содержит ключ элемента (хранить значение нет " +"необходимости) и соответствующий код операции -- DELETE. Также каждый " +"элемент LSM-дерева содержит порядковый номер операции (log sequence number " +"-- LSN), то есть значение монотонно возрастающей последовательности, которое" +" уникально идентифицирует каждую операцию. Таким образом, всё дерево " +"упорядочено сначала по возрастанию ключа, а в пределах одного ключа -- по " +"убыванию LSN." + +msgid "*A single level of an LSM tree*" +msgstr "*Один уровень LSM-дерева*" + +msgid "Filling an LSM tree" +msgstr "Наполнение LSM-дерева" + +msgid "" +"Unlike a B-tree, which is stored completely on disk and can be partly cached" +" in RAM, when using an LSM tree, memory is explicitly separated from disk " +"right from the start. The issue of volatile memory and data persistence is " +"beyond the scope of the storage algorithm and can be solved in various " +"ways—for example, by logging changes." +msgstr "" +"В отличие от B-дерева, которое полностью хранится на диске и может частично " +"кэшироваться в оперативной памяти, в LSM-дереве разделение между памятью и " +"диском явно присутствует с самого начала. При этом проблема сохранности " +"данных, расположенных в энергозависимой памяти, выносится за рамки алгоритма" +" хранения: ее можно решить разными способами, например, журналированием " +"изменений." + +msgid "" +"The part of an LSM tree that’s stored in RAM is called L0 (level zero). The " +"size of RAM is limited, so L0 is allocated a fixed amount of memory. For " +"example, in Tarantool, the L0 size is controlled by the ``vinyl_memory`` " +"parameter. Initially, when an LSM tree is empty, operations are written to " +"L0. Recall that all elements are ordered by key in ascending order, and then" +" within a single key scope, by LSN in descending order, so when a new value " +"associated with a given key gets inserted, it’s easy to locate the older " +"value and delete it. L0 can be structured as any container capable of " +"storing a sorted sequence of elements. For example, in Tarantool, L0 is " +"implemented as a B+*-tree. Lookups and insertions are standard operations " +"for the data structure underlying L0, so I won’t dwell on those." +msgstr "" +"Часть дерева, расположенную в оперативной памяти, называют L0 (level zero --" +" уровень ноль). Объем оперативной памяти ограничен, поэтому для L0 отводится" +" фиксированная область. В конфигурации Tarantool'а, например, размер L0 " +"задается с помощью параметра ``vinyl_memory``. В начале, когда LSM-дерево не" +" содержит элементов, операции записываются в L0. Следует отметить, что " +"элементы в дереве упорядочены по возрастанию ключа, а затем по убыванию LSN," +" так что в случае вставки нового значения по данному ключу легко обнаружить " +"и удалить предыдущее значение. L0 может быть представлен любым контейнером, " +"который сохраняет упорядоченность элементов. Например, для хранения L0 " +"Tarantool использует B+*-дерево. Операции поиска и вставки -- это " +"стандартные операции структуры данных, используемой для представления L0, и " +"мы их подробно рассматривать не будем." + +msgid "" +"Sooner or later the number of elements in an LSM tree exceeds the L0 size " +"and that’s when L0 gets written to a file on disk (called a \"run\") and " +"then cleared for storing new elements. This operation is called a \"dump\"." +msgstr "" +"Рано или поздно количество элементов в дереве превысит размер L0. Тогда L0 " +"записывается в файл на диске (который называется забегом -- \"run\") и " +"освобождается под новые элементы. Эта операция называется \"дамп\" (dump)." + +msgid "" +"Dumps on disk form a sequence ordered by LSN: LSN ranges in different runs " +"don’t overlap, and the leftmost runs (at the head of the sequence) hold " +"newer operations. Think of these runs as a pyramid, with the newest ones " +"closer to the top. As runs keep getting dumped, the pyramid grows higher. " +"Note that newer runs may contain deletions or replacements for existing " +"keys. To remove older data, it’s necessary to perform garbage collection " +"(this process is sometimes called \"merge\" or \"compaction\") by combining " +"several older runs into a new one. If two versions of the same key are " +"encountered during a compaction, only the newer one is retained; however, if" +" a key insertion is followed by a deletion, then both operations can be " +"discarded." +msgstr "" +"Все дампы на диске образуют последовательность, упорядоченную по LSN: " +"диапазоны LSN в файлах не пересекаются, а ближе к началу последовательности " +"находятся файлы с более новыми операциями. Представим эти файлы в виде " +"пирамиды, где новые файлы расположены вверху, а старые внизу. По мере " +"появления новых файлов забегов, высота пирамиды растет. При этом более " +"свежие файлы могут содержать операции удаления или замены для существующих " +"ключей. Для удаления старых данных необходимо производиться сборку мусора " +"(этот процесс иногда называется \"слияние\" -- в английском языке \"merge\" " +"или \"compaction\"), объединяя нескольких старых файлов в новый. Если при " +"слиянии мы встречаем две версии одного и того же ключа, то достаточно " +"оставить только более новую версию, а если после вставки ключа он был " +"удален, то из результата можно исключить обе операции." + +msgid "" +"The key choices determining an LSM tree’s efficiency are which runs to " +"compact and when to compact them. Suppose an LSM tree stores a monotonically" +" increasing sequence of keys (1, 2, 3, ...,) with no deletions. In this " +"case, compacting runs would be useless: all of the elements are sorted, the " +"tree doesn’t have any garbage, and the location of any key can unequivocally" +" be determined. On the other hand, if an LSM tree contains many deletions, " +"doing a compaction would free up some disk space. However, even if there are" +" no deletions, but key ranges in different runs overlap a lot, compacting " +"such runs could speed up lookups as there would be fewer runs to scan. In " +"this case, it might make sense to compact runs after each dump. But keep in " +"mind that a compaction causes all data stored on disk to be overwritten, so " +"with few reads it’s recommended to perform it less often." +msgstr "" +"Ключевым фактором эффективности LSM-дерева является то, в какой момент и для" +" каких файлов делается слияние. Представим, что LSM-дерево в качестве ключей" +" хранит монотонную последовательность вида 1, 2, 3 …, и операций удаления " +"нет. В этом случае слияние будет бесполезным -- все элементы уже " +"отсортированы, дерево не содержит мусор и можно однозначно определить, в " +"каком файле находится каждый ключ. Напротив, если LSM-дерево содержит много " +"операций удаления, слияние позволит освободить место на диске. Но даже если " +"удалений нет, а диапазоны ключей в разных файлах сильно пересекаются, " +"слияние может ускорить поиск, так как сократит число просматриваемых файлов." +" В этом случае имеет смысл выполнять слияние после каждого дампа. Однако " +"следует отметить, что такое слияние приведет к перезаписи всех данных на " +"диске, поэтому если чтений мало, то лучше делать слияния реже." + +msgid "" +"To ensure it’s optimally configurable for any of the scenarios above, an LSM" +" tree organizes all runs into a pyramid: the newer the data operations, the " +"higher up the pyramid they are located. During a compaction, the algorithm " +"picks two or more neighboring runs of approximately equal size, if possible." +msgstr "" +"Для оптимальной конфигурации под любой из описанных выше сценариев в LSM-" +"дереве все файлы организованы в пирамиду: чем новее операции с данными, тем " +"выше они находятся в пирамиде. При этом в слиянии участвуют два или " +"несколько соседних файлов в пирамиде; по возможности выбираются файлы " +"примерно одинакового размера." + +msgid "Multi-level compaction can span any number of levels" +msgstr "Многоуровневое слияние может охватить любое количество уровней" + +msgid "A level can contain multiple runs" +msgstr "Уровень может содержать несколько файлов" + +msgid "" +"All of the neighboring runs of approximately equal size constitute an LSM " +"tree level on disk. The ratio of run sizes at different levels determines " +"the pyramid’s proportions, which allows optimizing the tree for write-" +"intensive or read-intensive scenarios." +msgstr "" +"Все соседние файлы примерно одинакового размера составляют уровень LSM-" +"дерева на диске. Соотношение размеров файлов на различных уровнях определяет" +" пропорции пирамиды, что позволяет оптимизировать дерево под интенсивные " +"вставки, либо интенсивные чтения." + +msgid "" +"Suppose the L0 size is 100 Mb, the ratio of run sizes at each level (the " +"``vinyl_run_size_ratio`` parameter) is 5, and there can be no more than 2 " +"runs per level (the ``vinyl_run_count_per_level`` parameter). After the " +"first 3 dumps, the disk will contain 3 runs of 100 Mb each—which constitute " +"L1 (level one). Since 3 > 2, the runs will be compacted into a single 300 Mb" +" run, with the older ones being deleted. After 2 more dumps, there will be " +"another compaction, this time of 2 runs of 100 Mb each and the 300 Mb run, " +"which will produce one 500 Mb run. It will be moved to L2 (recall that the " +"run size ratio is 5), leaving L1 empty. The next 10 dumps will result in L2 " +"having 3 runs of 500 Mb each, which will be compacted into a single 1500 Mb " +"run. Over the course of 10 more dumps, the following will happen: 3 runs of " +"100 Mb each will be compacted twice, as will two 100 Mb runs and one 300 Mb " +"run, which will yield 2 new 500 Mb runs in L2. Since L2 now has 3 runs, they" +" will also be compacted: two 500 Mb runs and one 1500 Mb run will produce a " +"2500 Mb run that will be moved to L3, given its size." +msgstr "" +"Предположим, что размер L0 составляет 100 МБ, а соотношение размеров файлов " +"на каждом уровне (параметр ``vinyl_run_size_ratio``) равно 5, и на каждом " +"уровне может быть не более 2 файлов (параметр " +"``vinyl_run_count_per_level``). После первых трех дампов на диске появятся 3" +" файла по 100 МБ, эти файлы образуют уровень L1. Так как 3 > 2, запустится " +"слияние файлов в новый файл размером 300 МБ, а старые будут удалены. Спустя " +"еще 2 дампа снова запустится слияние, на этот раз файлов в 100, 100 и 300 " +"МБ, в результате файл размером 500 МБ переместится на уровень L2 (вспомним, " +"что соотношение размеров уровней равно 5), а уровень L1 останется пустым. " +"Пройдут еще 10 дампов, и получим 3 файла по 500 МБ на уровне L2, в " +"результате чего будет создан один файл размером 1500 МБ. Спустя еще 10 " +"дампов произойдет следующее: 2 раза произведем слияние 3 файлов по 100 МБ, а" +" также 2 раза слияние файлов по 100, 100 и 300 МБ, что приведет к созданию " +"двух файлов на уровне L2 по 500 МБ. Поскольку на уровне L2 уже есть три " +"файла, запустится слияние двух файлов по 500 МБ и одного файла в 1500 МБ. " +"Полученный в результате файл в 2500 МБ, в силу своего размера, переедет на " +"уровень L3." + +msgid "" +"This can go on infinitely, but if an LSM tree contains lots of deletions, " +"the resulting compacted run can be moved not only down, but also up the " +"pyramid due to its size being smaller than the sizes of the original runs " +"that were compacted. In other words, it’s enough to logically track which " +"level a certain run belongs to, based on the run size and the smallest and " +"greatest LSN among all of its operations." +msgstr "" +"Процесс может продолжаться до бесконечности, а если в потоке операций с LSM-" +"деревом будет много удалений, образовавшийся в результате слияния файл может" +" переместиться не только вниз по пирамиде, но и вверх, так как окажется " +"меньше исходных файлов, использовавшихся при слиянии. Иными словами, " +"принадлежность файла к уровню достаточно отслеживать логически на основе " +"размера файла и минимального и максимального LSN среди всех хранящихся в нем" +" операций." + +msgid "Controlling the form of an LSM tree" +msgstr "Управление формой LSM-дерева" + +msgid "" +"If it’s necessary to reduce the number of runs for lookups, then the run " +"size ratio can be increased, thus bringing the number of levels down. If, on" +" the other hand, you need to minimize the compaction-related overhead, then " +"the run size ratio can be decreased: the pyramid will grow higher, and even " +"though runs will be compacted more often, they will be smaller, which will " +"reduce the total amount of work done. In general, write amplification in an " +"LSM tree is described by this formula: :math:`log_{x}(\\frac {N} {L0}) × x` " +"or, alternatively, :math:`x × \\frac {ln (\\frac {N} {C0})} {ln(x)}`, where " +"N is the total size of all tree elements, L0 is the level zero size, and x " +"is the level size ratio (the ``level_size_ratio`` parameter). At " +":math:`\\frac {N} {C0}` = 40 (the disk-to- memory ratio), the plot would " +"look something like this:" +msgstr "" +"Если число файлов для поиска нужно уменьшить, то соотношение размеров файлов" +" на разных уровнях можно увеличить, и, как следствие, уменьшается число " +"уровней. Если, напротив, необходимо снизить затраты ресурсов, вызванные " +"слиянием, то можно уменьшить соотношение размеров уровней: пирамида будет " +"более высокой, а слияние хотя и выполняется чаще, но работает в среднем с " +"файлами меньшего размера, за счет чего суммарно выполняет меньше работы. В " +"целом, \"паразитная запись\" в LSM-дереве описывается формулой " +":math:`log_{x}(\\\\frac {N} {L0}) × x` или :math:`x × \\\\frac {ln (\\\\frac" +" {N} {C0})} {ln(x)}`, где N -- это общий размер всех элементов дерева, L0 --" +" это размер уровня ноль, а x -- это соотношение размеров уровней (параметр " +"``level_size_ratio``). Если :math:`\\\\frac {N} {C0}` = 40 (соотношение " +"диск-память), график выглядит примерно вот так:" + +msgid "" +"As for read amplification, it’s proportional to the number of levels. The " +"lookup cost at each level is no greater than that for a B-tree. Getting back" +" to the example of a tree with 100,000,000 elements: given 256 Mb of RAM and" +" the default values of ``vinyl_run_size_ratio`` and " +"``vinyl_run_count_per_level``, write amplification would come out to about " +"13, while read amplification could be as high as 150. Let’s try to figure " +"out why this happens." +msgstr "" +"\"Паразитное\" чтение при этом пропорционально количеству уровней. Стоимость" +" поиска на каждом уровне не превышает стоимости поиска в B-дереве. " +"Возвращаясь к нашему примеру дерева в 100 000 000 элементов: при наличии 256" +" МБ оперативной памяти и стандартных значений параметров " +"``vinyl_run_size_ratio`` и ``vinyl_run_count_per_level``, получим " +"коэффициент \"паразитной\" записи равным примерно 13, коэффициент " +"\"паразитной\" записи может доходить до 150. Разберемся, почему это " +"происходит." + +msgid "Search" +msgstr "Поиск" + +msgid "" +"When doing a lookup in an LSM tree, what we need to find is not the element " +"itself, but the most recent operation associated with it. If it’s a " +"deletion, then the tree doesn’t contain this element. If it’s an insertion, " +"we need to grab the topmost value in the pyramid, and the search can be " +"stopped after finding the first matching key. In the worst-case scenario, " +"that is if the tree doesn’t hold the needed element, the algorithm will have" +" to sequentially visit all of the levels, starting from L0." +msgstr "" +"При поиске в LSM-дереве нам необходимо найти не сам элемент, а последнюю " +"операцию с ним. Если это операция удаления, искомый элемент отсутствует в " +"дереве. Если это операция вставки, то искомому элементу соответствует самое " +"верхнее значение в LSM-пирамиде, и поиск можно остановить при первом " +"совпадении ключа. В худшем случае значение в дереве изначально " +"отсутствовало. Тогда поиск вынужден последовательно перебрать все уровни " +"дерева, начиная с L0." + +msgid "" +"Unfortunately, this scenario is quite common in real life. For example, when" +" inserting a value into a tree, it’s necessary to make sure there are no " +"duplicates among primary/unique keys. So to speed up membership checks, LSM " +"trees use a probabilistic data structure called a \"Bloom filter\", which " +"will be covered a bit later, in a section on how vinyl works under the hood." +msgstr "" +"К сожалению, на практике этот худший случай довольно распространен. " +"Например, при вставке в дерево необходимо убедиться в отсутствии дубликатов " +"для первичного или уникального ключа. Поэтому для ускорения поиска " +"несуществующих значений в LSM-деревьях применяется вероятностная структура " +"данных, которая называется \"фильтр Блума\". О нем мы поговорим более " +"детально в разделе, посвященном внутреннему устройству vinyl." + +msgid "Range searching" +msgstr "Поиск по диапазону" + +msgid "" +"In the case of a single-key search, the algorithm stops after encountering " +"the first match. However, when searching within a certain key range (for " +"example, looking for all the users with the last name \"Ivanov\"), it’s " +"necessary to scan all tree levels." +msgstr "" +"Если при поиске по одному ключу алгоритм завершается после первого " +"совпадения, то для поиска всех значений в диапазоне (например, всех " +"пользователей с фамилией \"Иванов\") необходимо просматривать все уровни " +"дерева." + +msgid "*Searching within a range of [24,30)*" +msgstr "*Поиск по диапазону [24,30)*" + +msgid "" +"The required range is formed the same way as when compacting several runs: " +"the algorithm picks the key with the largest LSN out of all the sources, " +"ignoring the other associated operations, then moves on to the next key and " +"repeats the procedure." +msgstr "" +"Формирование искомого диапазона при этом происходит так же, как и при " +"слиянии нескольких файлов: из всех источников алгоритм выбирает ключ с " +"максимальным LSN, отбрасывает остальные операции по этому ключу, сдвигает " +"позицию поиска на следующий ключ и повторяет процедуру." + +msgid "Deletion" +msgstr "Удаление" + +msgid "" +"Why would one store deletions? And why doesn’t it lead to a tree overflow in" +" the case of for i=1,10000000 put(i) delete(i) end?" +msgstr "" +"Зачем вообще хранить операции удаления? И почему это не приводит к " +"переполнению дерева, например, в сценарии for i=1,10000000 put(i) delete(i) " +"end?" + +msgid "" +"With regards to lookups, deletions signal the absence of a value being " +"searched; with compactions, they clear the tree of \"garbage\" records with " +"older LSNs." +msgstr "" +"Роль операций удаления при поиске -- сообщать об отсутствии искомого " +"значения, а при слиянии -- очищать дерево от \"мусорных\" записей с более " +"старыми LSN." + +msgid "" +"While the data is in RAM only, there’s no need to store deletions. " +"Similarly, you don’t need to keep them following a compaction if they " +"affect, among other things, the lowest tree level, which contains the oldest" +" dump. Indeed, if a value can’t be found at the lowest level, then it " +"doesn’t exist in the tree." +msgstr "" +"Пока данные хранятся только в оперативной памяти, нет необходимости хранить " +"операции удаления. Также нет необходимости сохранять операции удаления после" +" слияния, если оно затрагивает в том числе самый нижний уровень дерева -- на" +" нем находятся данные самого старого дампа. Действительно, отсутствие " +"значения на последнем уровне означает, что оно отсутствует в дереве." + +msgid "We can't delete from append-only files" +msgstr "" +"Нельзя производить удаление из файлов, которые обновляются только путем " +"присоединения новых записей" + +msgid "Tombstones (delete markers) are inserted into L0 instead" +msgstr "" +"Вместо этого на уровень L0 вносятся маркеры удаленных записей (tombstones)" + +msgid "*Deletion, step 1: a tombstone is inserted into L0*" +msgstr "*Удаление, шаг 1: вставка удаленной записи в L0*" + +msgid "*Deletion, step 2: the tombstone passes through intermediate levels*" +msgstr "" +"*Удаление, шаг 2: удаленная запись проходит через промежуточные уровни*" + +msgid "" +"*Deletion, step 3: in the case of a major compaction, the tombstone is " +"removed from the tree*" +msgstr "" +"*Удаление, шаг 3: при значительном слиянии удаленная запись удаляется из " +"дерева*" + +msgid "" +"If a deletion is known to come right after the insertion of a unique value, " +"which is often the case when modifying a value in a secondary index, then " +"the deletion can safely be filtered out while compacting intermediate tree " +"levels. This optimization is implemented in vinyl." +msgstr "" +"Если мы знаем, что удаление следует сразу за вставкой уникального значения " +"-- а это частый случай при изменении значения во вторичном индексе -- то " +"операцию удаления можно отфильтровывать уже при слиянии промежуточных " +"уровней. Эта оптимизация реализована в vinyl'е." + +msgid "Advantages of an LSM tree" +msgstr "Преимущества LSM-дерева" + +msgid "" +"Apart from decreasing write amplification, the approach that involves " +"periodically dumping level L0 and compacting levels L1-Lk has a few " +"advantages over the approach to writes adopted by B-trees:" +msgstr "" +"Помимо снижения \"паразитной\" записи, подход с периодическими дампами " +"уровня L0 и слиянием уровней L1-Lk имеет ряд преимуществ перед подходом к " +"записи, используемым в B-деревьях:" + +msgid "" +"Dumps and compactions write relatively large files: typically, the L0 size " +"is 50-100 Mb, which is thousands of times larger than the size of a B-tree " +"block." +msgstr "" +"При дампах и слиянии создаются относительно большие файлы: стандартный " +"размер L0 составляет 50-100 MБ, что в тысячи раз превышает размер блока " +"B-дерева." + +msgid "" +"This large size allows efficiently compressing data before writing it. " +"Tarantool compresses data automatically, which further decreases write " +"amplification." +msgstr "" +"Большой размер позволяет эффективно сжимать данные перед записью. В " +"Tarantool'е сжатие происходит автоматически, что позволяет еще больше " +"уменьшить \"паразитную\" запись." + +msgid "" +"There is no fragmentation overhead, since there’s no padding/empty space " +"between the elements inside a run." +msgstr "" +"Издержки фрагментации отсутствуют, потому что в файле элементы следуют друг " +"за другом без пустот/заполнений." + +msgid "" +"All operations create new runs instead of modifying older data in place. " +"This allows avoiding those nasty locks that everyone hates so much. Several " +"operations can run in parallel without causing any conflicts. This also " +"simplifies making backups and moving data to replicas." +msgstr "" +"Все операции создают новые файлы, а не заменяют старые данные. Это позволяет" +" избавиться от столь ненавистных нам блокировок, при этом несколько операций" +" могут идти параллельно, не приводя к конфликтам. Это также упрощает " +"создание резервных копий и перенос данных на реплику." + +msgid "" +"Storing older versions of data allows for the efficient implementation of " +"transaction support by using multiversion concurrency control." +msgstr "" +"Хранение старых версий данных позволяет эффективно реализовать поддержку " +"транзакций, используя подход управления параллельным доступом с помощью " +"многоверсионности." + +msgid "Disadvantages of an LSM tree and how to deal with them" +msgstr "Недостатки LSM-дерева и их устранение" + +msgid "" +"One of the key advantages of the B-tree as a search data structure is its " +"predictability: all operations take no longer than :math:`log_{B}(N)` to " +"run. Conversely, in a classical LSM tree, both read and write speeds can " +"differ by a factor of hundreds (best case scenario) or even thousands (worst" +" case scenario). For example, adding just one element to L0 can cause it to " +"overflow, which can trigger a chain reaction in levels L1, L2, and so on. " +"Lookups may find the needed element in L0 or may need to scan all of the " +"tree levels. It’s also necessary to optimize reads within a single level to " +"achieve speeds comparable to those of a B-tree. Fortunately, most " +"disadvantages can be mitigated or even eliminated with additional algorithms" +" and data structures. Let’s take a closer look at these disadvantages and " +"how they’re dealt with in Tarantool." +msgstr "" +"Одним из ключевых преимуществ B-дерева как структуры данных для поиска " +"является предсказуемость: любая операция занимает не более чем " +":math:`log_{B}(N)`. В классическом LSM-дереве скорость как чтения, так и " +"записи могут может отличаться в лучшем и худшем случае в сотни и тысячи раз." +" Например, добавление всего лишь одного элемента в L0 может привести к его " +"переполнению, что в свою очередь, может привести к переполнению L1, L2 и " +"т.д. Процесс чтения может обнаружить исходный элемент в L0, а может " +"задействовать все уровни. Чтение в пределах одного уровня также необходимо " +"оптимизировать, чтобы добиться скорости, сравнимой с B-деревом. К счастью, " +"многие недостатки можно скрасить или полностью устранить с помощью " +"вспомогательных алгоритмов и структур данных. Систематизируем эти недостатки" +" и опишем способы борьбы с ними, используемые в Tarantool'е." + +msgid "Unpredictable write speed" +msgstr "Непредсказуемая скорость записи" + +msgid "" +"In an LSM tree, insertions almost always affect L0 only. How do you avoid " +"idle time when the memory area allocated for L0 is full?" +msgstr "" +"Вставка данных в LSM-дерево почти всегда задействует исключительно L0. Как " +"избежать простоя, если заполнена область оперативной памяти, отведенная под " +"L0?" + +msgid "" +"Clearing L0 involves two lengthy operations: writing to disk and memory " +"deallocation. To avoid idle time while L0 is being dumped, Tarantool uses " +"writeaheads. Suppose the L0 size is 256 Mb. The disk write speed is 10 Mbps." +" Then it would take 26 seconds to dump L0. The insertion speed is 10,000 " +"RPS, with each key having a size of 100 bytes. While L0 is being dumped, " +"it’s necessary to reserve 26 Mb of RAM, effectively slicing the L0 size down" +" to 230 Mb." +msgstr "" +"Освобождение L0 подразумевает две долгих операции: запись на диск и " +"освобождение памяти. Чтобы избежать простоя во время записи L0 на диск, " +"Tarantool использует упреждающую запись. Допустим, размер L0 составляет 256 " +"MБ. Скорость записи на диск составляет 10 МБ/с. Тогда для записи L0 на диск " +"понадобится 26 секунд. Скорость вставки данных составляет 10 000 запросов в " +"секунду, а размер одного ключа -- 100 байтов. На время записи необходимо " +"зарезервировать около 26 MБ доступной оперативной памяти, сократив реальный " +"полезный размер L0 до 230 MБ." + +msgid "" +"Tarantool does all of these calculations automatically, constantly updating " +"the rolling average of the DBMS workload and the histogram of the disk " +"speed. This allows using L0 as efficiently as possible and it prevents write" +" requests from timing out. But in the case of workload surges, some wait " +"time is still possible. That’s why we also introduced an insertion timeout " +"(the ``vinyl_timeout`` parameter), which is set to 60 seconds by default. " +"The write operation itself is executed in dedicated threads. The number of " +"these threads (2 by default) is controlled by the ``vinyl_write_threads`` " +"parameter. The default value of 2 allows doing dumps and compactions in " +"parallel, which is also necessary for ensuring system predictability." +msgstr "" +"Все эти расчеты Tarantool делает автоматически, постоянно поддерживая " +"скользящее среднее значение нагрузки на СУБД и гистограмму скорости работы " +"диска. Это позволяет максимально эффективно использовать L0 и избежать " +"истечения времени ожидания доступной памяти для операций записи. При резком " +"всплеске нагрузки ожидание все же возможно, поэтому также существует время " +"ожидания операции вставки (параметр ``vinyl_timeout``), значение которого по" +" умолчанию составляет 60 секунд. Сама запись осуществляется в выделенных " +"потоках, число которых (2 по умолчанию) задается в параметре " +"``vinyl_write_threads``. Используемое по умолчанию значение 2 позволяет " +"выполнять дамп параллельно со слиянием, что также необходимо для " +"предсказуемой работы системы." + +msgid "" +"In Tarantool, compactions are always performed independently of dumps, in a " +"separate execution thread. This is made possible by the append-only nature " +"of an LSM tree: after dumps runs are never changed, and compactions simply " +"create new runs." +msgstr "" +"Слияния в Tarantool'е всегда выполняются независимо от дампов, в отдельном " +"потоке выполнения. Это возможно благодаря природе LSM-дерева -- после записи" +" файлы в дереве никогда не меняются, а слияние лишь создает новый файл." + +msgid "" +"Delays can also be caused by L0 rotation and the deallocation of memory " +"dumped to disk: during a dump, L0 memory is owned by two operating system " +"threads, a transaction processing thread and a write thread. Even though no " +"elements are being added to the rotated L0, it can still be used for " +"lookups. To avoid read locks when doing lookups, the write thread doesn’t " +"deallocate the dumped memory, instead delegating this task to the " +"transaction processor thread. Following a dump, memory deallocation itself " +"happens instantaneously: to achieve this, L0 uses a special allocator that " +"deallocates all of the memory with a single operation." +msgstr "" +"К задержкам также может приводить ротация L0 и освобождение памяти, " +"записанной на диск: в процессе записи памятью L0 владеют два потока " +"операционной системы -- поток обработки транзакций и поток записи. Хотя в L0" +" во время ротации элементы не добавляются, он может участвовать в поиске. " +"Чтобы избежать блокировок на чтение во время поиска, поток записи не " +"освобождает записанную память, а оставляет эту задачу потоку обработки " +"транзакций. Само освобождение после завершения дампа происходит мгновенно: " +"для этого в L0 используется специализированный механизм распределения, " +"позволяющий освободить всю память за одну операцию." + +msgid "anticipatory dump" +msgstr "упреждающий дамп" + +msgid "throttling" +msgstr "загрузка" + +msgid "" +"The dump is performed from the so-called \"shadow\" L0 without blocking new " +"insertions and lookups" +msgstr "" +"Дамп происходит из так называемого \"теневого\" L0, не блокируя новые " +"вставки и чтения" + +msgid "Unpredictable read speed" +msgstr "Непредсказуемая скорость чтений" + +msgid "" +"Optimizing reads is the most difficult optimization task with regards to LSM" +" trees. The main complexity factor here is the number of levels: any " +"optimization causes not only much slower lookups, but also tends to require " +"significantly larger RAM resources. Fortunately, the append-only nature of " +"LSM trees allows us to address these problems in ways that would be " +"nontrivial for traditional data structures." +msgstr "" +"Чтение -- самая сложная задача для оптимизации в LSM-деревьях. Главным " +"фактором сложности является большое количество уровней: это не только " +"значительно замедляет поиск, но и потенциально значительно увеличивает " +"требования к оперативной памяти при почти любых попытках оптимизации. К " +"счастью, природа LSM-деревьев, где файлы обновляются только путем " +"присоединения новых записей, позволяет решать эти проблемы нестандартными " +"для традиционных структур данных способами." + +msgid "page index" +msgstr "постраничный индекс" + +msgid "bloom filters" +msgstr "фильтры Блума" + +msgid "tuple range cache" +msgstr "кэш диапазона кортежей" + +msgid "multi-level compaction" +msgstr "многоуровневое слияние" + +msgid "Compression and page index" +msgstr "Сжатие и постраничный индекс" + +msgid "" +"In B-trees, data compression is either the hardest problem to crack or a " +"great marketing tool—rather than something really useful. In LSM trees, " +"compression works as follows:" +msgstr "" +"Сжатие данных в B-деревьях -- это либо сложнейшая в реализации задача, либо " +"больше средство маркетинга, чем действительно полезный инструмент. Сжатие в " +"LSM-деревьях работает следующим образом:" + +msgid "" +"During a dump or compaction all of the data within a single run is split " +"into pages. The page size (in bytes) is controlled by the " +"``vinyl_page_size`` parameter and can be set separately for each index. A " +"page doesn’t have to be exactly of ``vinyl_page_size`` size—depending on the" +" data it holds, it can be a little bit smaller or larger. Because of this, " +"pages never have any empty space inside." +msgstr "" +"При любом дампе или слиянии мы разбиваем все данные в одном файле на " +"страницы. Размер страницы в байтах задается в параметре ``vinyl_page_size``," +" который можно менять отдельно для каждого индекса. Страница не обязана " +"занимать строго то количество байт, которое прописано ``vinyl_page_size`` --" +" она может быть чуть больше или чуть меньше, в зависимости от хранящихся в " +"ней данных. Благодаря этому страница никогда не содержит пустот." + +msgid "" +"Data is compressed by `Facebook’s streaming algorithm " +"`_ called \"zstd\". The first key of each " +"page, along with the page offset, is added to a \"page index\", which is a " +"separate file that allows the quick retrieval of any page. After a dump or " +"compaction, the page index of the created run is also written to disk." +msgstr "" +"Для сжатия используется `потоковый алгоритм Facebook " +"`_ под названием \"zstd\". Первый ключ " +"каждой страницы и смещение страницы в файле добавляются в так называемый " +"постраничный индекс (page index) -- отдельный файл, который позволяет быстро" +" найти нужную страницу. После дампа или слияния постраничный индекс " +"созданного файла также записывается на диск." + +msgid "" +"All `.index` files are cached in RAM, which allows finding the necessary " +"page with a single lookup in a `.run` file (in vinyl, this is the extension " +"of files resulting from a dump or compaction). Since data within a page is " +"sorted, after it’s read and decompressed, the needed key can be found using " +"a regular binary search. Decompression and reads are handled by separate " +"threads, and are controlled by the ``vinyl_read_threads`` parameter." +msgstr "" +"Все файлы типа `.index` кэшируются в оперативной памяти, что позволяет " +"найти нужную страницу за одно чтение из файла `.run` (такое расширение имени" +" файла используется в vinyl'е для файлов, полученных в результате дампа или " +"слияния). Поскольку данные в странице отсортированы, после чтения и " +"декомпрессии нужный ключ можно найти с помощью простого бинарного поиска. За" +" чтение и декомпрессию отвечают отдельные потоки, их количество определяется" +" в параметре ``vinyl_read_threads``." + +msgid "" +"Tarantool uses a universal file format: for example, the format of a `.run` " +"file is no different from that of an `.xlog` file (log file). This " +"simplifies backup and recovery as well as the usage of external tools." +msgstr "" +"Tarantool использует единый формат файлов: например, формат данных в файле " +"`.run` ничем не отличается от формата файла `.xlog` (файл журнала). Это " +"упрощает резервное копирование и восстановление, а также работу внешних " +"инструментов." + +msgid "Bloom filters" +msgstr "Фильтры Блума" + +msgid "" +"Even though using a page index enables scanning fewer pages per run when " +"doing a lookup, it’s still necessary to traverse all of the tree levels. " +"There’s a special case, which involves checking if particular data is absent" +" when scanning all of the tree levels and it’s unavoidable: I’m talking " +"about insertions into a unique index. If the data being inserted already " +"exists, then inserting the same data into a unique index should lead to an " +"error. The only way to throw an error in an LSM tree before a transaction is" +" committed is to do a search before inserting the data. Such reads form a " +"class of their own in the DBMS world and are called \"hidden\" or " +"\"parasitic\" reads." +msgstr "" +"Хотя постраничный индекс позволяет уменьшить количество страниц, " +"просматриваемых при поиске в одном файле, он не отменяет необходимости " +"искать на всех уровнях дерева. Есть важный частный случай, когда необходимо " +"проверить отсутствие данных, и тогда просмотр всех уровней неизбежен: " +"вставка в уникальный индекс. Если данные уже существуют, то вставка в " +"уникальный индекс должна завершиться с ошибкой. Единственный способ вернуть " +"ошибку до завершения транзакции в LSM-дереве -- произвести поиск перед " +"вставкой. Такого рода чтения в СУБД образуют целый класс, называемый " +"\"скрытыми\" или \"паразитными\" чтениями." + +msgid "" +"Another operation leading to hidden reads is updating a value in a field on " +"which a secondary index is defined. Secondary keys are regular LSM trees " +"that store differently ordered data. In most cases, in order not to have to " +"store all of the data in all of the indexes, a value associated with a given" +" key is kept in whole only in the primary index (any index that stores both " +"a key and a value is called \"covering\" or \"clustered\"), whereas the " +"secondary index only stores the fields on which a secondary index is " +"defined, and the values of the fields that are part of the primary index. " +"Thus, each time a change is made to a value in a field on which a secondary " +"index is defined, it’s necessary to first remove the old key from the " +"secondary index—and only then can the new key be inserted. At update time, " +"the old value is unknown, and it is this value that needs to be read in from" +" the primary key \"under the hood\"." +msgstr "" +"Другая операция, приводящая к скрытым чтениям, -- обновление значения, по " +"которому построен вторичный индекс. Вторичные ключи представляют собой " +"обычные LSM-деревья, в которых данные хранятся в другом порядке. Чаще всего," +" чтобы не хранить все данные во всех индексах, значение, соответствующее " +"данному ключу, целиком сохраняется только в первичном индексе (любой индекс," +" хранящий и ключ, и значение, называется покрывающим или кластерным), а во " +"вторичном индексе сохраняются лишь поля, по которым построен вторичный " +"индекс, и значения полей, участвующих в первичном индексе. Тогда при любом " +"изменении значения, по которому построен вторичный ключ, приходится сначала " +"удалять из вторичного индекса старый ключ, и только потом вставлять новый. " +"Старое значение во время обновления неизвестно -- именно его и нужно читать " +"из первичного ключа с точки зрения внутреннего устройства." + +msgid "For example:" +msgstr "Например:" + +msgid "update t1 set city=’Moscow’ where id=1" +msgstr "update t1 set city=’Moscow’ where id=1" + +msgid "" +"To minimize the number of disk reads, especially for nonexistent data, " +"nearly all LSM trees use probabilistic data structures, and Tarantool is no " +"exception. A classical Bloom filter is made up of several (usually 3-to-5) " +"bit arrays. When data is written, several hash functions are calculated for " +"each key in order to get corresponding array positions. The bits at these " +"positions are then set to 1. Due to possible hash collisions, some bits " +"might be set to 1 twice. We’re most interested in the bits that remain 0 " +"after all keys have been added. When looking for an element within a run, " +"the same hash functions are applied to produce bit positions in the arrays. " +"If any of the bits at these positions is 0, then the element is definitely " +"not in the run. The probability of a false positive in a Bloom filter is " +"calculated using Bayes’ theorem: each hash function is an independent random" +" variable, so the probability of a collision simultaneously occurring in all" +" of the bit arrays is infinitesimal." +msgstr "" +"Чтобы уменьшить количество чтений с диска, особенно для несуществующих " +"значений, практически все LSM-деревья используют вероятностные структуры " +"данных. Tarantool не исключение. Классический фильтр Блума -- это набор из " +"нескольких (обычно 3-5) битовых массивов. При записи для каждого ключа " +"вычисляется несколько хеш-функций, и в каждом массиве выставляется бит, " +"соответствующий значению хеша. При хешировании могут возникнуть коллизии, " +"поэтому некоторые биты могут быть проставлены дважды. Интерес представляют " +"биты, которые оказались не проставлены после записи всех ключей. При поиске " +"также вычисляются выбранные хеш-функции. Если хотя бы в одном из битовых " +"массивов бит не стоит, то значение в файле отсутствует. Вероятность " +"срабатывания фильтра Блума определяется теоремой Байеса: каждая хеш-функция " +"представляет собой независимую случайную величину, благодаря чему " +"вероятность того, что во всех битовых массивах одновременно произойдет " +"коллизия, очень мала." + +msgid "" +"The key advantage of Bloom filters in Tarantool is that they’re easily " +"configurable. The only parameter that can be specified separately for each " +"index is called ``vinyl_bloom_fpr`` (FPR stands for \"false positive " +"ratio\") and it has the default value of 0.05, which translates to a 5% FPR." +" Based on this parameter, Tarantool automatically creates Bloom filters of " +"the optimal size for partial- key and full-key searches. The Bloom filters " +"are stored in the `.index` file, along with the page index, and are cached " +"in RAM." +msgstr "" +"Ключевым преимуществом реализации фильтров Блума в Tarantool'е является " +"простота настройки. Единственный параметр, который можно менять независимо " +"для каждого индекса, называется ``vinyl_bloom_fpr`` (FPR в данном случае " +"означает сокращение от \"false positive ratio\" -- коэффициент " +"ложноположительного срабатывания), который по умолчанию равен 0,05, или 5%. " +"На основе этого параметра Tarantool автоматически строит фильтры Блума " +"оптимального размера для поиска как по полному ключу, так и по компонентам " +"ключа. Сами фильтры Блума хранятся вместе с постраничным индексом в файле " +"`.index` и кэшируются в оперативной памяти." + +msgid "Caching" +msgstr "Кэширование" + +msgid "" +"A lot of people think that caching is a silver bullet that can help with any" +" performance issue. \"When in doubt, add more cache\". In vinyl, caching is " +"viewed rather as a means of reducing the overall workload and consequently, " +"of getting a more stable response time for those requests that don’t hit the" +" cache. vinyl boasts a unique type of cache among transactional systems " +"called a \"range tuple cache\". Unlike, say, RocksDB or MySQL, this cache " +"doesn’t store pages, but rather ranges of index values obtained from disk, " +"after having performed a compaction spanning all tree levels. This allows " +"the use of caching for both single-key and key-range searches. Since this " +"method of caching stores only hot data and not, say, pages (you may need " +"only some data from a page), RAM is used in the most efficient way possible." +" The cache size is controlled by the ``vinyl_cache`` parameter." +msgstr "" +"Многие привыкли считать кэширование панацеей от всех проблем с " +"производительностью: \"В любой непонятной ситуации добавляй кэш\". В vinyl'е" +" мы смотрим на кэш скорее как на средство снижения общей нагрузки на диск, " +"и, как следствие, получения более предсказуемого времени ответов на запросы," +" которые не попали в кэш. В vinyl'е реализован уникальный для транзакционных" +" систем вид кэша под названием \"кэш диапазона кортежей\" (range tuple " +"cache). В отличие от RocksDB, например, или MySQL, этот кэш хранит не " +"страницы, а уже готовые диапазоны значений индекса, после их чтения с диска " +"и слияния всех уровней. Это позволяет использовать кэш для запросов как по " +"одному ключу, так и по диапазону ключей. Поскольку в кэше хранятся только " +"горячие данные, а не, скажем, страницы (в странице может быть востребована " +"лишь часть данных), оперативная память используется наиболее оптимально. " +"Размер кэша задается в параметре ``vinyl_cache``." + +msgid "Garbage collection control" +msgstr "Управление сборкой мусора" + +msgid "" +"Chances are that by now you’ve started losing focus and need a well-deserved" +" dopamine reward. Feel free to take a break, since working through the rest " +"of the article is going to take some serious mental effort." +msgstr "" +"Возможно, добравшись до этого места вы уже начали терять концентрацию и " +"нуждаетесь в заслуженной дозе допамина. Самое время сделать перерыв, так как" +" для того, чтобы разобраться с оставшейся частью, понадобятся серьезные " +"усилия." + +msgid "" +"An LSM tree in vinyl is just a small piece of the puzzle. Even with a single" +" table (or so-called \"space\"), vinyl creates and maintains several LSM " +"trees, one for each index. But even a single index can be comprised of " +"dozens of LSM trees. Let’s try to understand why this might be necessary." +msgstr "" +"В vinyl'е устройство одного LSM-дерева -- это лишь фрагмент мозаики. Vinyl " +"создает и обслуживает несколько LSM-деревьев даже для одной таблицы (так " +"называемого спейса) -- по одному дереву на каждый индекс. Но даже один " +"единственный индекс может состоять из десятков LSM-деревьев. Попробуем " +"разобраться, зачем." + +msgid "" +"Recall our example with a tree containing 100,000,000 records, 100 bytes " +"each. As time passes, the lowest LSM level may end up holding a 10 Gb run. " +"During compaction, a temporary run of approximately the same size will be " +"created. Data at intermediate levels takes up some space as well, since the " +"tree may store several operations associated with a single key. In total, " +"storing 10 Gb of actual data may require up to 30 Gb of free space: 10 Gb " +"for the last tree level, 10 Gb for a temporary run, and 10 Gb for the " +"remaining data. But what if the data size is not 10 Gb, but 1 Tb? Requiring " +"that the available disk space always be several times greater than the " +"actual data size is financially unpractical, not to mention that it may take" +" dozens of hours to create a 1 Tb run. And in the case of an emergency " +"shutdown or system restart, the process would have to be started from " +"scratch." +msgstr "" +"Рассмотрим наш стандартный пример: 100 000 000 записей по 100 байтов каждая." +" Через некоторое время на самом нижнем уровне LSM у нас может оказаться файл" +" размером 10 ГБ. Во время слияния последнего уровня мы создадим временный " +"файл, который также будет занимать около 10 ГБ. Данные на промежуточных " +"уровнях тоже занимают место: по одному и тому же ключу дерево может хранить " +"несколько операций. Суммарно для хранения 10 ГБ полезных данных нам может " +"потребоваться до 30 ГБ свободного места: 10 ГБ на последний уровень, 10 ГБ " +"на временный файл и 10 ГБ на всё остальное. А если данных не 1 ГБ, а 1 ТБ? " +"Требовать, чтобы количество свободного места на диске всегда в несколько раз" +" превышало объем полезных данных, экономически нецелесообразно, да и " +"создание файла в 1ТБ может занимать десятки часов. При любой аварии или " +"перезапуске системы операцию придется начинать заново." + +msgid "" +"Here’s another scenario. Suppose the primary key is a monotonically " +"increasing sequence—for example, a time series. In this case, most " +"insertions will fall into the right part of the key range, so it wouldn’t " +"make much sense to do a compaction just to append a few million more records" +" to an already huge run." +msgstr "" +"Рассмотрим другую проблему. Представим, что первичный ключ дерева -- это " +"монотонная последовательность, например, временной ряд. В этом случае " +"основные вставки будут приходиться на правую часть диапазона ключей. Нет " +"смысла заново производить слияние лишь для того, чтобы дописать в конец и " +"без того огромного файла еще несколько миллионов записей." + +msgid "" +"But what if writes predominantly occur in a particular region of the key " +"range, whereas most reads take place in a different region? How do you " +"optimize the form of the LSM tree in this case? If it’s too high, read " +"performance is impacted; if it’s too low—write speed is reduced." +msgstr "" +"А если вставки происходят, в основном, в одну часть диапазона ключей, а " +"чтения -- из другой части? Как в этом случае оптимизировать форму дерева? " +"Если оно будет слишком высоким, пострадают чтения, если слишком низким -- " +"запись." + +msgid "" +"Tarantool \"factorizes\" this problem by creating multiple LSM trees for " +"each index. The approximate size of each subtree may be controlled by the " +":ref:`vinyl_range_size ` configuration " +"parameter. We call such subtrees \"ranges\"." +msgstr "" +"Tarantool \"факторизует\" проблему, создавая не одно, а множество LSM-" +"деревьев для каждого индекса. Примерный размер каждого поддерева можно " +"задать в конфигурационном параметре ``vinyl_range_size``. Такие поддеревья " +"называется диапазонами (\"range\")." + +msgid "Factorizing large LSM trees via ranging" +msgstr "Факторизация больших LSM-деревьев с помощью диапазонов" + +msgid "Ranges reflect a static layout of sorted runs" +msgstr "Диапазоны отражают статичную структуру упорядоченных файлов" + +msgid "Slices connect a sorted run into a range" +msgstr "Срезы объединяют упорядоченный файл в диапазон" + +msgid "" +"Initially, when the index has few elements, it consists of a single range. " +"As more elements are added, its total size may exceed :ref:`the maximum " +"range size `. In that case a special operation" +" called \"split\" divides the tree into two equal parts. The tree is split " +"at the middle element in the range of keys stored in the tree. For example, " +"if the tree initially stores the full range of -inf…+inf, then after " +"splitting it at the middle key X, we get two subtrees: one that stores the " +"range of -inf...X, and the other storing the range of X…+inf. With this " +"approach, we always know which subtree to use for writes and which one for " +"reads. If the tree contained deletions and each of the neighboring ranges " +"grew smaller as a result, the opposite operation called \"coalesce\" " +"combines two neighboring trees into one." +msgstr "" +"Изначально, пока в индексе мало элементов, он состоит из одного диапазона. " +"По мере добавления элементов суммарный объем может превысить " +":ref:`максимальный размер диапазона `. В таком" +" случае выполняется операция под названием \"разделение\" (split), которая " +"делит дерево на две равные части. Разделение происходит по срединному " +"элементу диапазона ключей, хранящихся в дереве. Например, если изначально " +"дерево хранит полный диапазон -inf… +inf, то после разделения по срединному " +"ключу X получим два поддерева: одно будет хранить все ключи от -inf до X, " +"другое -- от X до +inf. Таким образом, при вставке или чтении мы однозначно " +"знаем, к какому поддереву обращаться. Если в дереве были удаления и каждый " +"из соседних диапазонов уменьшился, выполняется обратная операция под " +"названием \"объединение\" (coalesce). Она объединяет два соседних дерева в " +"одно." + +msgid "" +"Split and coalesce don’t entail a compaction, the creation of new runs, or " +"other resource-intensive operations. An LSM tree is just a collection of " +"runs. vinyl has a special metadata log that helps keep track of which run " +"belongs to which subtree(s). This has the `.vylog` extension and its format " +"is compatible with an .xlog file. Similarly to an `.xlog` file, the metadata" +" log gets rotated at each checkpoint. To avoid the creation of extra runs " +"with split and coalesce, we have also introduced an auxiliary entity called " +"\"slice\". It’s a reference to a run containing a key range and it’s stored " +"only in the metadata log. Once the reference counter drops to zero, the " +"corresponding file gets removed. When it’s necessary to perform a split or " +"to coalesce, Tarantool creates slice objects for each new tree, removes " +"older slices, and writes these operations to the metadata log, which " +"literally stores records that look like this: ```` or " +"````." +msgstr "" +"Разделение и объединение не приводят к слиянию, созданию новых файлов и " +"прочим тяжеловесным операциям. LSM-дерево -- это лишь набор файлов. В " +"vinyl'е мы реализовали специальный журнал метаданных, позволяющий легко " +"отслеживать, какой файл принадлежит какому поддереву или поддеревьям. Журнал" +" имеет расширение `.vylog`, по формату он совместим с файлом `.xlog`. Как и " +"файл `.xlog`, происходит автоматическая ротация файла при каждой контрольной" +" точке. Чтобы избежать повторного создания файлов при разделении и " +"объединении, мы ввели промежуточную сущность -- срез (slice). Это ссылка на " +"файл с указанием диапазона значений ключа, которая хранится исключительно в " +"журнале метаданных. Когда число ссылок на файл становится равным нулю, файл " +"удаляется. А когда необходимо произвести разделение или объединение, " +"Tarantool создает срезы для каждого нового дерева, старые срезы удаляет, и " +"записывает эти операции в журнал метаданных. Буквально, журнал метаданных " +"хранит записи вида <идентификатор дерева, идентификатор среза> или " +"<идентификатор среза, идентификатор файла, мин, макс>." + +msgid "" +"This way all of the heavy lifting associated with splitting a tree into two " +"subtrees is postponed until a compaction and then is performed " +"automatically. A huge advantage of dividing all of the keys into ranges is " +"the ability to independently control the L0 size as well as the dump and " +"compaction processes for each subtree, which makes these processes " +"manageable and predictable. Having a separate metadata log also simplifies " +"the implementation of both \"truncate\" and \"drop\". In vinyl, they’re " +"processed instantly, since they only work with the metadata log, while " +"garbage collection is done in the background." +msgstr "" +"Таким образом, непосредственно тяжелая работа по разбиению дерева на два поддерева, откладывается до слияния и выполняется автоматически.\n" +"Огромным преимуществом подхода с разделением всего диапазона ключей на диапазоны является возможность независимо управлять размером L0, а также процессом создания дампов и слиянием для каждого поддерева. В результате эти процессы являются управляемыми и предсказуемыми. Наличие отдельного журнала метаданных также упрощает выполнение таких операций, как усечение и удаление -- в vinyl'е они обрабатываются мгновенно, потому что работают исключительно с журналом метаданных, а удаление мусора выполняется в фоне." + +msgid "Advanced features of vinyl" +msgstr "Расширенные возможности vinyl'а" + +msgid "Upsert" +msgstr "Upsert (обновление и вставка)" + +msgid "" +"In the previous sections, we mentioned only two operations stored by an LSM " +"tree: deletion and replacement. Let’s take a look at how all of the other " +"operations can be represented. An insertion can be represented via a " +"replacement—you just need to make sure there are no other elements with the " +"specified key. To perform an update, it’s necessary to read the older value " +"from the tree, so it’s easier to represent this operation as a replacement " +"as well—this speeds up future read requests by the key. Besides, an update " +"must return the new value, so there’s no avoiding hidden reads." +msgstr "" +"В предыдущих разделах упоминались лишь две операции, которые хранит LSM-" +"дерево: удаление и замена. Давайте рассмотрим, как представлены все " +"остальные. Вставку можно представить с помощью замены -- необходимо лишь " +"предварительно убедиться в отсутствии элемента указанным ключом. Для " +"выполнения обновления необходимо предварительно считывать старое значение из" +" дерева, так что и эту операцию проще записать в дерево как замену -- это " +"ускорит будущие чтения по этому ключу. Кроме того, обновление должно вернуть" +" новое значение, так что скрытых чтений никак не избежать." + +msgid "" +"In B-trees, the cost of hidden reads is negligible: to update a block, it " +"first needs to be read from disk anyway. Creating a special update operation" +" for an LSM tree that doesn’t cause any hidden reads is really tempting." +msgstr "" +"В B-деревьях скрытые чтения почти ничего не стоят: чтобы обновить блок, его " +"в любом случае необходимо прочитать с диска. Для LSM-деревьев идея создания " +"специальной операции обновления, которая не приводила бы к скрытым чтениям, " +"выглядит очень заманчивой." + +msgid "" +"Such an operation must contain not only a default value to be inserted if a " +"key has no value yet, but also a list of update operations to perform if a " +"value does exist." +msgstr "" +"Такая операция должна содержать как значение по умолчанию, которое нужно " +"вставить, если данных по ключу еще нет, так и список операций обновления, " +"которые нужно выполнить, если значение существует." + +msgid "" +"At transaction execution time, Tarantool just saves the operation in an LSM " +"tree, then \"executes\" it later, during a compaction." +msgstr "" +"На этапе выполнения транзакции Tarantool лишь сохраняет всю операцию в LSM-" +"дереве, а \"выполняет\" ее уже только во время слияния." + +msgid "The upsert operation:" +msgstr "Операция обновления и вставки:" + +msgid "space:upsert(tuple, {{operator, field, value}, ... })" +msgstr "space:upsert(tuple, {{operator, field, value}, ... })" + +msgid "Non-reading update or insert" +msgstr "Обновление без чтения или вставка" + +msgid "Delayed execution" +msgstr "Отложенное выполнение" + +msgid "Background upsert squashing prevents upserts from piling up" +msgstr "" +"Фоновое сжатие операций обновления и вставки предотвращает накапливание " +"операций" + +msgid "" +"Unfortunately, postponing the operation execution until a compaction doesn’t" +" leave much leeway in terms of error handling. That’s why Tarantool tries to" +" validate upserts as fully as possible before writing them to an LSM tree. " +"However, some checks are only possible with older data on hand, for example " +"when the update operation is trying to add a number to a string or to remove" +" a field that doesn’t exist." +msgstr "" +"К сожалению, если откладывать выполнение операции на этап слияния, " +"возможностей для обработки ошибок не остается. Поэтому Tarantool стремится " +"максимально проверять операции обновления и вставки upsert перед записью в " +"дерево. Тем не менее, некоторые проверки можно выполнить лишь имея старые " +"данные на руках. Например, если обновление прибавляет число к строке или " +"удаляет несуществующее поле." + +msgid "" +"A semantically similar operation exists in many products including " +"PostgreSQL and MongoDB. But anywhere you look, it’s just syntactic sugar " +"that combines the update and replace operations without avoiding hidden " +"reads. Most probably, the reason is that LSM trees as data storage " +"structures are relatively new." +msgstr "" +"Операция с похожей семантикой присутствует во многих продуктах, в том числе " +"в PostgreSQL и MongoDB. Но везде она представляет собой лишь синтаксический " +"сахар, объединяющий обновление и вставку, не избавляя СУБД от необходимости " +"выполнять скрытые чтения. Скорее всего, причиной этого является " +"относительная новизна LSM-деревьев в качестве структур данных для хранения." + +msgid "" +"Even though an upsert is a very important optimization and implementing it " +"cost us a lot of blood, sweat, and tears, we must admit that it has limited " +"applicability. If a table contains secondary keys or triggers, hidden reads " +"can’t be avoided. But if you have a scenario where secondary keys are not " +"required and the update following the transaction completion will certainly " +"not cause any errors, then the operation is for you." +msgstr "" +"Хотя обновление и вставка upsert представляет собой очень важную " +"оптимизацию, и ее реализация стоила нам долгой напряженной работы, следует " +"признать, что ее применимость ограничена. Если в таблице есть вторичные " +"ключи или триггеры, скрытых чтений не избежать. А если у вас есть сценарии, " +"для которых не нужны вторичные ключи и обновление после завершения " +"транзакции однозначно не приведет к ошибкам -- эта операция для вас." + +msgid "" +"I’d like to tell you a short story about an upsert. It takes place back when" +" vinyl was only beginning to \"mature\" and we were using an upsert in " +"production for the first time. We had what seemed like an ideal environment " +"for it: we had tons of keys, the current time was being used as values; " +"update operations were inserting keys or modifying the current time; and we " +"had few reads. Load tests yielded great results." +msgstr "" +"Небольшая история, связанная с этим оператором: vinyl только начинал " +"\"взрослеть\", и мы впервые запустили операцию обновления и вставки upsert " +"на рабочие серверы. Казалось бы, идеальные условия: огромный набор ключей, " +"текущее время в качестве значения, операции обновления либо вставляют ключ, " +"либо обновляют текущее время, редкие операции чтения. Нагрузочные тесты " +"показали отличные результаты." + +msgid "" +"Nevertheless, after a couple of days, the Tarantool process started eating " +"up 100% of our CPU, and the system performance dropped close to zero." +msgstr "" +"Тем не менее, после пары дней работы процесс Tarantool'а начал потреблять " +"100 % CPU, а производительность системы упала практически до нуля." + +msgid "" +"We started digging into the issue and found out that the distribution of " +"requests across keys was significantly different from what we had seen in " +"the test environment. It was...well, quite nonuniform. Most keys were " +"updated once or twice a day, so the database was idle for the most part, but" +" there were much hotter keys with tens of thousands of updates per day. " +"Tarantool handled those just fine. But in the case of lookups by key with " +"tens of thousands of upserts, things quickly went downhill. To return the " +"most recent value, Tarantool had to read and \"replay\" the whole history " +"consisting of all of the upserts. When designing upserts, we had hoped this " +"would happen automatically during a compaction, but the process never even " +"got to that stage: the L0 size was more than enough, so there were no dumps." +msgstr "" +"Начали подробно изучать проблему. Оказалось, что распределение запросов по " +"ключам существенно отличалось от того, что мы видели в тестовом окружении. " +"Оно было… очень неравномерное. Большая часть ключей обновлялась 1-2 раза за " +"сутки, и база для них не была нагружена. Но были ключи гораздо более горячие" +" -- десятки тысяч обновлений в сутки. Tarantool прекрасно справлялся с этим " +"потоком обновлений. А вот когда по ключу с десятком тысяч операций " +"обновления и вставки upsert происходило чтение, всё шло под откос. Чтобы " +"вернуть последнее значение, Tarantool'у приходилось каждый раз прочитать и " +"\"проиграть\" историю из десятков тысяч команд обновления и вставки upsert. " +"На стадии проекта мы надеялись, что это произойдет автоматически во время " +"слияния уровней, но до слияния дело даже не доходило: памяти L0 было " +"предостаточно, и дампы не создавались." + +msgid "" +"We solved the problem by adding a background process that performed " +"readaheads on any keys that had more than a few dozen upserts piled up, so " +"all those upserts were squashed and substituted with the read value." +msgstr "" +"Решили мы проблему добавлением фонового процесса, осуществляющего " +"упреждающие чтения для ключей, по которым накопилось больше нескольких " +"десятков операций обновления и вставки upsert с последующей заменой на " +"прочитанное значение." + +msgid "Secondary keys" +msgstr "Вторичные ключи" + +msgid "" +"Update is not the only operation where optimizing hidden reads is critical. " +"Even the replace operation, given secondary keys, has to read the older " +"value: it needs to be independently deleted from the secondary indexes, and " +"inserting a new element might not do this, leaving some garbage behind." +msgstr "" +"Не только для операции обновления остро стоит проблема оптимизации скрытых " +"чтений. Даже операция замены при наличии вторичных ключей вынуждена читать " +"старое значение: его нужно независимо удалить из вторичных индексов, а " +"вставка нового элемента может этого не сделать, оставив в индексе мусор." + +msgid "" +"If secondary indexes are not unique, then collecting \"garbage\" from them " +"can be put off until a compaction, which is what we do in Tarantool. The " +"append-only nature of LSM trees allowed us to implement full-blown " +"serializable transactions in vinyl. Read-only requests use older versions of" +" data without blocking any writes. The transaction manager itself is fairly " +"simple for now: in classical terms, it implements the MVTO (multiversion " +"timestamp ordering) class, whereby the winning transaction is the one that " +"finished earlier. There are no locks and associated deadlocks. Strange as it" +" may seem, this is a drawback rather than an advantage: with parallel " +"execution, you can increase the number of successful transactions by simply " +"holding some of them on lock when necessary. We’re planning to improve the " +"transaction manager soon. In the current release, we focused on making the " +"algorithm behave 100% correctly and predictably. For example, our " +"transaction manager is one of the few on the NoSQL market that supports so-" +"called \"gap locks\"." +msgstr "" +"Если вторичные индексы не уникальны, то удаление из них \"мусора\" также " +"можно перенести в фазу слияния, что мы и делаем в Tarantool'е. Природа LSM-" +"дерева, в котором файлы обновляются путем присоединения новых записей, " +"позволила нам реализовать в vinyl'е полноценные сериализуемые транзакции. " +"Запросы только для чтения при этом используют старые версии данных и не " +"блокируют запись. Сам менеджер транзакций пока довольно простой: в " +"традиционной классификации он реализует класс MVTO (multiversion timestamp " +"ordering -- упорядочение временных меток на основе многоверсионности), при " +"этом в конфликте побеждает та транзакция, что завершилась первой. Блокировок" +" и свойственных им взаимоблокировок нет. Как ни странно, это скорее " +"недостаток, чем преимущество: при параллельном выполнении можно повысить " +"количество успешных транзакций, задерживая некоторые из них в нужный момент " +"на блокировке. Развитие менеджера транзакций в наших ближайших планах. В " +"текущей версии мы сфокусировались на том, чтобы сделать алгоритм корректным " +"и предсказуемым на 100%. Например, наш менеджер транзакций -- один из " +"немногих в NoSQL-среде, поддерживающих так называемые \"блокировки " +"разрывов\" (gap locks)." diff --git a/locale/ru/LC_MESSAGES/release.po b/locale/ru/LC_MESSAGES/release.po index cb18d216c2..36d4aaa76f 100644 --- a/locale/ru/LC_MESSAGES/release.po +++ b/locale/ru/LC_MESSAGES/release.po @@ -1,6 +1,6 @@ msgid "Release notes" -msgstr "Описания версий" +msgstr "Примечания к версиям" msgid "" "Since version 2.10, there's a :doc:`new release policy for Tarantool " @@ -31,18 +31,19 @@ msgstr "" "версионирования `:" msgid "MAJOR_VERSION.RELEASE_SERIES.RELEASE" -msgstr "MAJOR_VERSION.RELEASE_SERIES.RELEASE" +msgstr "ОСНОВНАЯ_ВЕРСИЯ.СЕРИЯ_ВЫПУСКОВ.ВЫПУСК" msgid "" "Below is the table listing all Tarantool versions starting from 1.10.0 up to" " the current latest versions. Each link leads to the release notes page of " "the corresponding version:" msgstr "" -"В таблице ниже перечислены все версии Tarantool с 1.10.0 до последних " -"актуальных. Каждая ссылка ведёт на страницу описания соответствующей версии." +"Ниже приводится таблица, в которой перечислены все версии Tarantool, начиная" +" с версии 1.10.0 и заканчивая действующими последними версиями. Каждая " +"ссылка ведёт на страницу примечаний к соответствующей версии:" msgid "Release Series" -msgstr "Серия" +msgstr "Серия выпусков" msgid "Alpha" msgstr "Альфа" @@ -51,7 +52,7 @@ msgid "Beta" msgstr "Бета" msgid "Release" -msgstr "Релиз" +msgstr "Выпуск" msgid "2.10" msgstr "2.10" @@ -63,7 +64,7 @@ msgid "2.10.0-beta1" msgstr "2.10.0-beta1" msgid "not released yet" -msgstr "еще не состоялся" +msgstr "выпуск еще не состоялся" msgid "2.8" msgstr "2.8" @@ -182,7 +183,7 @@ msgstr "" "GitHub." msgid "Release notes for series before 1.10 are also available:" -msgstr "Также доступны описания серий ранее 1.10:" +msgstr "Также доступны примечания к версиям ниже 1.10:" msgid ":doc:`release/1.9`" msgstr ":doc:`release/1.9`"