|  | // Licensed to the Apache Software Foundation (ASF) under one or more | 
|  | // contributor license agreements.  See the NOTICE file distributed with | 
|  | // this work for additional information regarding copyright ownership. | 
|  | // The ASF licenses this file to You under the Apache License, Version 2.0 | 
|  | // (the "License"); you may not use this file except in compliance with | 
|  | // the License.  You may obtain a copy of the License at | 
|  | // | 
|  | // http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | = Cluster Snapshots | 
|  |  | 
|  | == Overview | 
|  |  | 
|  | Ignite provides an ability to create full and incremental cluster snapshots for deployments using | 
|  | link:persistence/native-persistence[Ignite Persistence]. An Ignite snapshot includes a consistent cluster-wide copy of | 
|  | all data records persisted on disk and some other files needed for a restore procedure. | 
|  |  | 
|  | The snapshot structure is similar to the layout of the | 
|  | link:persistence/native-persistence#configuring-persistent-storage-directory[Ignite Persistence storage directory], | 
|  | with several exceptions. Let's take this snapshot as an example to review the structure: | 
|  | [source,shell] | 
|  | ---- | 
|  | work | 
|  | └── snapshots | 
|  | └── backup23012020 | 
|  | ├── increments | 
|  | │        └── 0000000000000001 | 
|  | └── db | 
|  | ├── binary_meta | 
|  | │         ├── node1 | 
|  | │         ├── node2 | 
|  | │         └── node3 | 
|  | ├── marshaller | 
|  | │         └── classname0 | 
|  | ├── node1 | 
|  | │    └── my-sample-cache | 
|  | │        ├── cache_data.dat | 
|  | │        ├── part-3.bin | 
|  | │        ├── part-4.bin | 
|  | │        └── part-6.bin | 
|  | ├── node2 | 
|  | │    └── my-sample-cache | 
|  | │        ├── cache_data.dat | 
|  | │        ├── part-1.bin | 
|  | │        ├── part-5.bin | 
|  | │        └── part-7.bin | 
|  | └── node3 | 
|  | └── my-sample-cache | 
|  | ├── cache_data.dat | 
|  | ├── part-0.bin | 
|  | └── part-2.bin | 
|  | ---- | 
|  | * The snapshot is located under the `work\snapshots` directory and named as `backup23012020` where `work` is Ignite's work | 
|  | directory. | 
|  | * The snapshot is created for a 3-node cluster with all the nodes running on the same machine. In this example, | 
|  | the nodes are named as `node1`, `node2`, and `node3`, while in practice, the names are equal to nodes' | 
|  | link:https://cwiki.apache.org/confluence/display/IGNITE/Ignite+Persistent+Store+-+under+the+hood#IgnitePersistentStoreunderthehood-SubfoldersGeneration[consistent IDs]. | 
|  | * The snapshot keeps a copy of the `my-sample-cache` cache. | 
|  | * The `db` folder keeps a copy of data records in `part-N.bin` and `cache_data.dat` files. Write-ahead and checkpointing | 
|  | are not added into the snapshot as long as those are not required for the full snapshot restore procedure. | 
|  | * The `binary_meta` and `marshaller` directories store metadata and marshaller-specific information. | 
|  | * The `increments` directory stores incremental snapshots based on the full snapshot `backup23012020`, in this example | 
|  | there is a single increment `0000000000000001`. It contains `wal` directory that stores the compressed WAL segments, `binary_meta` and `marshaller` directories. | 
|  |  | 
|  | [NOTE] | 
|  | ==== | 
|  | [discrete] | 
|  | === Usually Snapshot is Spread Across the Cluster | 
|  |  | 
|  | The previous example shows the snapshot created for the cluster running on the same physical machine. Thus, the whole | 
|  | snapshot is located in a single place. While in practice, all the nodes will be running on different machines having the | 
|  | snapshot data spread across the cluster. Each node keeps a segment of the snapshot with the data belonging to this particular node. | 
|  | The link:snapshots/snapshots#restoring-from-snapshot[restore procedure] explains how to tether together all the segments during recovery. | 
|  | ==== | 
|  |  | 
|  | == Incremental snapshots | 
|  |  | 
|  | The low RPO (Recovery Point Object), e.g. a few minutes, can hardly be achieved using full snapshots. They require additional resources | 
|  | to create and store all partitions data. Instead, you can use incremental snapshots: | 
|  |  | 
|  | 1. to store the data changes happened since previous full or incremental snapshot was created | 
|  | 2. to provide a lightweight creation process and can be run concurrently with runtime load. | 
|  |  | 
|  | [NOTE] | 
|  | ==== | 
|  |  | 
|  | Incremental snapshots consist of compressed WAL segments, which are collected in the background without pressure on cluster resources. | 
|  | ==== | 
|  |  | 
|  | There are some prerequisites for using incremental snapshots: | 
|  |  | 
|  | * Incremental snapshots are based on existing full snapshot. | 
|  | * link:persistence/native-persistence#wal-archive-compaction[WAL archive compaction] has to be enabled. | 
|  | * Incremental snapshots has to be created on the same media drive where WAL archives are stored. | 
|  |  | 
|  | During incremental snapshot restore procedure the full snapshot is restored first and after that all increments are restored sequentially. | 
|  |  | 
|  | Please refer to the sections link:snapshots/snapshots#consistency-guarantees[Consistency Guarantees] and | 
|  | link:snapshots/snapshots#current-limitations[Current Limitations] below for more details about incremental snapshots. | 
|  |  | 
|  | == Configuration | 
|  |  | 
|  | === Snapshot Directory | 
|  |  | 
|  | By default, a segment of the snapshot is stored in the work directory of a respective Ignite node and uses the same storage | 
|  | media where Ignite Persistence keeps data, index, WAL, and other files. Since the snapshot can consume as much space as | 
|  | already taken by the persistence files and can affect your application's performance by sharing the disk I/O with the | 
|  | Ignite Persistence routines, it's suggested to store the snapshot and persistence files on different media. | 
|  |  | 
|  | See the link:persistence/snapshot-directory#configuring-snapshot-directory[Configuring Snapshot Directory] page for | 
|  | configuration examples. | 
|  |  | 
|  | === Snapshot Execution Pool | 
|  |  | 
|  | By default, the snapshot thread pool size has a value of `4`. Decreasing the number of threads involved in the snapshot creation process | 
|  | increases the total amount of time for taking a snapshot. However, this keeps the disk load within reasonable limits. | 
|  |  | 
|  | See the link:perf-and-troubleshooting/thread-pools-tuning[Ignite Snapshot Execution Pool,window=_blank] page for more details. | 
|  |  | 
|  | === Distributed properties | 
|  |  | 
|  | The distributed properties listed in the table below allow you to configure snapshots at runtime: | 
|  |  | 
|  | [cols="1,3,1",opts="header"] | 
|  | |=== | 
|  | |Parameter | Description | Default Value | 
|  | |`snapshotTransferRate`| Snapshot transfer rate limit in bytes/sec. | 0 | 
|  | |=== | 
|  |  | 
|  | === System properties | 
|  |  | 
|  | The system properties listed in the table below allow you to configure snapshots: | 
|  |  | 
|  | [cols="1,1,3,1",opts="header"] | 
|  | |=== | 
|  | |Property | Type | Description | Default Value | 
|  | |`IGNITE_SNAPSHOT_SEQUENTIAL_WRITE`| Boolean | Flag to indicate that disk writes during snapshot process should be in a | 
|  | sequential manner when possible. This generates extra disk space usage. | True | 
|  | |=== | 
|  |  | 
|  | == Creating Snapshot | 
|  |  | 
|  | Ignite provides several APIs for the snapshot creation. Let's review all the options. | 
|  |  | 
|  | === Using Control Script | 
|  |  | 
|  | Ignite ships the link:tools/control-script[Control Script] that supports snapshots-related commands listed below: | 
|  |  | 
|  | [source,shell] | 
|  | ---- | 
|  | # Create a cluster snapshot named "snapshot_09062021" in the background: | 
|  | control.(sh|bat) --snapshot create snapshot_09062021 | 
|  |  | 
|  | # Create a cluster snapshot named "snapshot_09062021" and wait for the entire operation to complete: | 
|  | control.(sh|bat) --snapshot create snapshot_09062021 --sync | 
|  |  | 
|  | # Create a cluster snapshot named "snapshot_09062021" in the "/tmp/ignite/snapshots" folder (the full path to the snapshot files will be /tmp/ignite/snapshots/snapshot_09062021): | 
|  | control.(sh|bat) --snapshot create snapshot_09062021 --dest /tmp/ignite/snapshots | 
|  |  | 
|  | # Create an incremental snapshot based on full snapshot "snapshot_09062021": | 
|  | control.(sh|bat) --snapshot create snapshot_09062021 --incremental | 
|  | ---- | 
|  |  | 
|  | === Using JMX | 
|  |  | 
|  | Use the `SnapshotMXBean` interface to perform the snapshot-specific procedures via JMX: | 
|  |  | 
|  | [cols="1,1",opts="header"] | 
|  | |=== | 
|  | |Method | Description | 
|  | |createSnapshot(String snpName, String snpPath) | Create a snapshot. | 
|  | |createIncrementalSnapshot(String snpName, String snpPath) | Create an incremental snapshot. | 
|  | |=== | 
|  |  | 
|  | === Using Java API | 
|  |  | 
|  | Also, it's possible to create a snapshot programmatically in Java: | 
|  |  | 
|  | [tabs] | 
|  | -- | 
|  | tab:Java[] | 
|  |  | 
|  | [source, java] | 
|  | ---- | 
|  | include::{javaCodeDir}/Snapshots.java[tags=create, indent=0] | 
|  | ---- | 
|  | -- | 
|  |  | 
|  | == Checking Snapshot Consistency | 
|  |  | 
|  | Usually all the cluster nodes run on different machines and have the snapshot data spread across the cluster. | 
|  | Each node stores its own snapshot segment, so in some cases it may be necessary to check the snapshot for completeness | 
|  | of data and for data consistency across the cluster before restoring from the snapshot. | 
|  |  | 
|  | For such cases, Apache Ignite is delivered with built-in snapshot consistency check commands that enable you to verify | 
|  | internal data consistency, calculate data partitions hashes and pages checksums, and print out the result if a | 
|  | problem is found. The check command also compares hashes of a primary partitions with corresponding backup partitions | 
|  | and reports any differences. | 
|  |  | 
|  | See the link:tools/control-script#checking-snapshot-consistency[Control Script] that supports snapshots-related checking | 
|  | commands. | 
|  |  | 
|  | == Restoring From Snapshot | 
|  |  | 
|  | A snapshot can be restored either manually on a stopped cluster or automatically on an active cluster. | 
|  | Both procedures are described below, however, it is preferable to use the restore command from Control Script only. | 
|  |  | 
|  | === Manual Snapshot Restore Procedure | 
|  |  | 
|  | The snapshot structure is similar to the layout of the Ignite Native Persistence. Therefore, to restore the manual snapshot, you must | 
|  | restore a snapshot only on the same cluster with the same node `consistentId` and on the same topology on which a snapshot | 
|  | was taken. Only the full snapshot can be restored. If you need to restore a snapshot on a different cluster, or on a different | 
|  | cluster topology, or restore incremental snapshots use the link:snapshots/snapshots#automatic-snapshot-restore-procedure[Automatic Snapshot Restore Procedure]. | 
|  |  | 
|  | In general, stop the cluster, then replace the persistence data and other files using the data from the snapshot, and restart the nodes. | 
|  |  | 
|  | The detailed procedure looks as follows: | 
|  |  | 
|  | . Stop the cluster you intend to restore | 
|  | . Remove all files from the checkpoint `$IGNITE_HOME/work/cp` directory | 
|  | . Do the following on each node: | 
|  | - Remove the files related to the `{consistentId}` from the `$IGNITE_HOME/work/db/binary_meta` directory. | 
|  | - Remove the files related to the `{consistentId}` from the `$IGNITE_HOME/work/db/marshaller` directory. | 
|  | - Remove the files and sub-directories related to the `{consistentId}` under your `$IGNITE_HOME/work/db` directory. Clean the link:persistence/native-persistence#configuring-persistent-storage-directory[`db/{consistentId}`] directory separately if it's not located under the Ignite `work` dir. | 
|  | - Copy the files belonging to a node with the `{consistentId}` from the snapshot into the `$IGNITE_HOME/work/` directory. If the `db/{consistentId}` directory is not located under the Ignite `work` dir then you need to copy data files there. | 
|  | . Restart the cluster | 
|  |  | 
|  | === Automatic Snapshot Restore Procedure | 
|  |  | 
|  | The automatic restore procedure allows the user to restore cache groups from a snapshot on an active cluster by using the Java API or link:tools/control-script[command line script]. | 
|  |  | 
|  | Currently, this procedure has several limitations, that will be resolved in future releases: | 
|  |  | 
|  | * Restoring is possible only if all parts of the snapshot are present in the cluster. Each node looks for a local snapshot data in the configured snapshot path by the given snapshot name and consistent node ID. | 
|  | * The restore procedure can be applied only to cache groups created by the user. | 
|  | * Cache groups to be restored from the snapshot must not be present in the cluster. If they are present, they must be link:key-value-api/basic-cache-operations#destroying-caches[destroyed] by the user before starting this operation. | 
|  | * Concurrent restore operations are not allowed. Thus, if one operation has been started, the other can only be started after the first is completed. | 
|  |  | 
|  | ==== Restoring Cache Group from the Snapshot | 
|  |  | 
|  | The following code snippet demonstrates how to restore an individual cache group from a snapshot. | 
|  |  | 
|  | [tabs] | 
|  | -- | 
|  | tab:Java[] | 
|  |  | 
|  | [source, java] | 
|  | ---- | 
|  | include::{javaCodeDir}/Snapshots.java[tags=restore, indent=0] | 
|  | ---- | 
|  |  | 
|  | tab:CLI[] | 
|  | [source,shell] | 
|  | ---- | 
|  | # Restore cache group "snapshot-cache" from the snapshot "snapshot_02092020". | 
|  | control.(sh|bat) --snapshot restore snapshot_02092020 --groups snapshot-cache | 
|  |  | 
|  | # Restore cache group "snapshot-cache" from the snapshot "snapshot_02092020" and its increment with index 1. | 
|  | control.(sh|bat) --snapshot restore snapshot_02092020 --groups snapshot-cache --increment 1 | 
|  |  | 
|  | ---- | 
|  | -- | 
|  |  | 
|  | ==== Using CLI to control restore operation | 
|  | The `control.sh|bat` script provides the ability to start and stop the restore operation. | 
|  |  | 
|  | [source,shell] | 
|  | ---- | 
|  | # Start restoring all user-created cache groups from the snapshot "snapshot_09062021" in the background. | 
|  | control.(sh|bat) --snapshot restore snapshot_09062021 | 
|  |  | 
|  | # Start restoring all user-created cache groups from the snapshot "snapshot_09062021" and wait for the entire operation to complete. | 
|  | control.(sh|bat) --snapshot restore snapshot_09062021 --sync | 
|  |  | 
|  | # Start restoring all user-created cache groups from the snapshot "snapshot_09062021" located in the "/tmp/ignite/snapshots" folder (the full path to the snapshot files should be /tmp/ignite/snapshots/snapshot_09062021): | 
|  | control.(sh|bat) --snapshot restore snapshot_09062021 --src /tmp/ignite/snapshots | 
|  |  | 
|  | # Start restoring only "cache-group1" and "cache-group2" from the snapshot "snapshot_09062021" in the background. | 
|  | control.(sh|bat) --snapshot restore snapshot_09062021 --groups cache-group1,cache-group2 | 
|  |  | 
|  | # Start restoring all user-created cache groups from the snapshot "snapshot_09062021" and its increment with index 1. | 
|  | control.(sh|bat) --snapshot restore snapshot_09062021 --increment 1 | 
|  | ---- | 
|  |  | 
|  | == Getting Snapshot Operation Status | 
|  |  | 
|  | The status of the current snapshot operation in the cluster can be obtained using the `control.sh|bat` script or JMX interface: | 
|  |  | 
|  | [tabs] | 
|  | -- | 
|  | tab:Unix[] | 
|  | [source,shell] | 
|  | ---- | 
|  | # Get the status of the snapshot operation. | 
|  | control.sh --snapshot status | 
|  | ---- | 
|  |  | 
|  | tab:Windows[] | 
|  | [source,shell] | 
|  | ---- | 
|  | # Get the status of the snapshot operation. | 
|  | control.bat --snapshot status | 
|  | ---- | 
|  |  | 
|  | tab:JMX[] | 
|  | You can also get the current snapshot status via the `SnapshotMXBean` interface: | 
|  | [source,java] | 
|  | ---- | 
|  | SnapshotMXBean mxBean = ...; | 
|  |  | 
|  | // The status of a current snapshot operation in the cluster. | 
|  | String status = mxBean.status(); | 
|  | ---- | 
|  | -- | 
|  |  | 
|  | == Cancelling Snapshot Operation | 
|  |  | 
|  | To abort create/restore snapshot operation you need to obtain an `operation request ID`. | 
|  | This identifier is displayed when you start a snapshot operation using the CLI. It can also be obtained using the status command and from snapshot metrics. | 
|  |  | 
|  | [tabs] | 
|  | -- | 
|  | tab:Unix[] | 
|  | [source,shell] | 
|  | ---- | 
|  | # Cancel a running snapshot operation with ID "9ec229f1-e0df-41ff-9434-6f08ba7d05bd": | 
|  | control.sh --snapshot cancel --id 9ec229f1-e0df-41ff-9434-6f08ba7d05bd | 
|  |  | 
|  | # Kill a running snapshot operation with ID "9ec229f1-e0df-41ff-9434-6f08ba7d05bd": | 
|  | control.sh --kill SNAPSHOT 9ec229f1-e0df-41ff-9434-6f08ba7d05bd | 
|  | ---- | 
|  |  | 
|  | tab:Windows[] | 
|  | [source,shell] | 
|  | ---- | 
|  | # Cancel a running snapshot operation with ID "9ec229f1-e0df-41ff-9434-6f08ba7d05bd": | 
|  | control.bat --snapshot cancel --id 9ec229f1-e0df-41ff-9434-6f08ba7d05bd | 
|  |  | 
|  | # Kill a running snapshot operation with ID "9ec229f1-e0df-41ff-9434-6f08ba7d05bd": | 
|  | control.bat --kill SNAPSHOT 9ec229f1-e0df-41ff-9434-6f08ba7d05bd | 
|  | ---- | 
|  |  | 
|  | tab:JMX[] | 
|  | You can also abort a snapshot operation via the `SnapshotMXBean` interface: | 
|  | [source,java] | 
|  | ---- | 
|  | SnapshotMXBean mxBean = ...; | 
|  |  | 
|  | // Cancel a running snapshot operation with ID "9ec229f1-e0df-41ff-9434-6f08ba7d05bd": | 
|  | mxBean.cancelSnapshotOperation("9ec229f1-e0df-41ff-9434-6f08ba7d05bd"); | 
|  | ---- | 
|  | -- | 
|  |  | 
|  | == Consistency Guarantees | 
|  |  | 
|  | All snapshots are fully consistent in terms of concurrent cluster-wide operations as well as ongoing changes with Ignite. | 
|  | Persistence data, index, schema, binary metadata, marshaller and other files on nodes. | 
|  |  | 
|  | The cluster-wide snapshot consistency is achieved by triggering the link:https://cwiki.apache.org/confluence/display/IGNITE/%28Partition+Map%29+Exchange+-+under+the+hood[Partition-Map-Exchange] | 
|  | procedure. By doing that, the cluster will eventually get to the point in time when all previously started transactions are completed, and new | 
|  | ones are paused. Once this happens, the cluster initiates the snapshot creation procedure. The PME procedure ensures | 
|  | that the snapshot includes primary and backup in a consistent state. | 
|  |  | 
|  | The consistency between the Ignite Persistence files and their snapshot copies is achieved by copying the original | 
|  | files to the destination snapshot directory with tracking all concurrent ongoing changes. The tracking of the changes | 
|  | might require extra space on the Ignite Persistence storage media (up to the 1x size of the storage media). | 
|  |  | 
|  | === Incremental snapshot consistency guarantees | 
|  |  | 
|  | Incremental snapshots uses different non-blocking approach for achieving transactional consistency based on the Consistent Cut algorithm. | 
|  | This allows you to start incremental snapshots concurrently with the runtime load without affecting performance. But it doesn't guarantee consistency | 
|  | for atomic caches. It's highly recommended to verify these caches after restoring with the `idle_verify` | 
|  | command. If necessary, it's possible to repair inconsistent partitions with the `consistency` command. Please, check the | 
|  | link:tools/control-script[Control Script] section for more information about these commands. | 
|  |  | 
|  | == Current Limitations | 
|  |  | 
|  | The snapshot procedure has some limitations that you should be aware of before using the feature in your production environment: | 
|  |  | 
|  | * Snapshotting of specific caches/tables is unsupported. You always create a full cluster snapshot. | 
|  | * Caches/tables that are not persisted in Ignite Persistence are not included into the snapshot. | 
|  | * Encrypted caches in the snapshot must be encrypted with the same master key. | 
|  | * You can have only one snapshotting operation running at a time. | 
|  | * The snapshot operation is prohibited during a master key change and/or cache group key change. | 
|  | * The snapshot procedure is interrupted if a server node leaves the cluster. | 
|  | * Concurrent updates from link:../data-streaming.adoc#_limitations[DataStreamer] with default setting 'allowOverwrite' | 
|  | (false) into a persistent cache can cause that cache data stored inconsistent. | 
|  |  | 
|  | If any of these limitations prevent you from using Apache Ignite, then select alternate snapshotting implementations for | 
|  | Ignite provided by enterprise vendors. | 
|  |  | 
|  | === Incremental snapshot limitations | 
|  |  | 
|  | Incremental snapshots can't be created in the following cases: | 
|  |  | 
|  | * Encrypted caches are presented in a cluster. | 
|  | * Caches are created, changed or destroyed after full snapshot was created. | 
|  | * After link:data-rebalancing[data has been rebalanced] in the cluster. | 
|  |  | 
|  | Ignite automatically monitors these events and prevents the incremental snapshot creation. It's required to create a new | 
|  | full snapshot and after that creation of incremental snapshots becomes available again. | 
|  |  |