From 3f4c39ac2e52389a6c2a6869af7d9a42564e1f3c Mon Sep 17 00:00:00 2001 From: Josip Mrden Date: Tue, 29 Apr 2025 09:00:55 +0200 Subject: [PATCH 01/13] Add clustering faq page --- pages/clustering/_meta.ts | 3 ++- pages/clustering/faq.mdx | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 pages/clustering/faq.mdx diff --git a/pages/clustering/_meta.ts b/pages/clustering/_meta.ts index 51e038a9e..b23cf6082 100644 --- a/pages/clustering/_meta.ts +++ b/pages/clustering/_meta.ts @@ -1,5 +1,6 @@ export default { "high-availability": "High availability", - "replication": "Replication" + "replication": "Replication", + "faq": "FAQ" } \ No newline at end of file diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx new file mode 100644 index 000000000..948495b9e --- /dev/null +++ b/pages/clustering/faq.mdx @@ -0,0 +1,16 @@ +--- +title: Frequently asked questions about clustering +description: Explore the documentation page for Memgraph and access the FAQ section to find solutions to common queries and concerns. Discover essential information and insights now. +--- +import { CommunityLinks } from '/components/social-card/CommunityLinks' + + +# Frequently asked questions + +## High availability + +### High availability with K8s + + + + \ No newline at end of file From 90fe9a06348dbaa90ea90c1a013fc07f8880b442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Thu, 16 Oct 2025 15:52:48 +0200 Subject: [PATCH 02/13] Add more pages to the FAQ --- pages/clustering/_meta.ts | 3 +- pages/clustering/bolt-routing.mdx | 275 ++++++++++++++++ pages/clustering/faq.mdx | 10 +- pages/clustering/ha-commands-reference.mdx | 346 +++++++++++++++++++++ 4 files changed, 631 insertions(+), 3 deletions(-) create mode 100644 pages/clustering/bolt-routing.mdx create mode 100644 pages/clustering/ha-commands-reference.mdx diff --git a/pages/clustering/_meta.ts b/pages/clustering/_meta.ts index b23cf6082..0516356f1 100644 --- a/pages/clustering/_meta.ts +++ b/pages/clustering/_meta.ts @@ -1,6 +1,7 @@ export default { "high-availability": "High availability", + "bolt-routing": "Bolt+routing protocol", + "ha-commands-reference": "High availability reference queries", "replication": "Replication", "faq": "FAQ" } - \ No newline at end of file diff --git a/pages/clustering/bolt-routing.mdx b/pages/clustering/bolt-routing.mdx new file mode 100644 index 000000000..17567a14c --- /dev/null +++ b/pages/clustering/bolt-routing.mdx @@ -0,0 +1,275 @@ +--- +title: Bolt+routing protocol +description: Learn how to use the bolt+routing protocol to connect to Memgraph high availability clusters with automatic failover and load balancing. +--- + +import { Callout } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + +# Bolt+routing protocol + +The bolt+routing protocol is Memgraph's solution for connecting to high availability clusters. It automatically routes queries to the appropriate instances and handles failover seamlessly, ensuring your applications remain connected even when cluster topology changes. + +## Overview + +In a high availability cluster, directly connecting to the main instance isn't recommended because the main instance can change due to various failures. The bolt+routing protocol solves this by providing intelligent routing that: + +- **Automatically routes write queries** to the current main instance +- **Distributes read queries** across available replicas +- **Handles failover** without application changes +- **Prevents split-brain scenarios** by ensuring clients never write to old main instances + +## How bolt+routing works + +### Connection flow + +1. **Client connects** to any coordinator instance using `neo4j://` scheme +2. **Coordinator responds** with a routing table containing: + - Instances from which data can be read + - The instance where data can be written + - Instances acting as routers +3. **Client uses routing table** to direct subsequent queries appropriately + +### Routing table structure + +The routing table contains three types of entries: + +| Entry Type | Description | Usage | +|------------|-------------|-------| +| **Read instances** | Replica instances available for read queries | Load balancing read operations | +| **Write instance** | Current main instance for write queries | All write operations | +| **Router instances** | Coordinator instances for routing requests | Future routing requests | + +## Connection strings + +### Standard vs HA connections + +**Standard connection (single instance):** +``` +bolt://: +``` + +**HA connection with routing:** +``` +neo4j://: +``` + +### Connection examples + +```javascript +// Standard connection +const driver = neo4j.driver("bolt://localhost:7687", auth); + +// HA connection with routing +const driver = neo4j.driver("neo4j://localhost:7691", auth); +``` + +## Client-side routing + +Bolt+routing is a **client-side routing protocol**, meaning network endpoint resolution happens inside the drivers. This provides several benefits: + +- **Transparent failover**: Applications don't need to handle connection changes +- **Automatic load balancing**: Read queries are distributed across replicas +- **Consistent routing**: All clients receive the same routing information +- **Reliability**: Raft consensus ensures accurate routing data + +## Cluster roles and routing + +### Instance roles in routing + +| Role | Function | Query Types | +|------|----------|-------------| +| **Main instance** | Primary writable instance | Write queries only (by default) | +| **Replica instances** | Read-only instances | Read queries | +| **Coordinator instances** | Routing and cluster management | Routing requests only | + +### Routing behavior + +- **Write queries**: Always routed to the current main instance +- **Read queries**: Distributed across available replica instances +- **Routing requests**: Handled by coordinator instances +- **Failover**: Automatic promotion of replica to main when needed + +## Configuration options + +### Enable reads on main + +By default, the main instance only handles write queries. You can enable read queries on the main instance: + +```cypher +SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'; +``` + +**Parameters:** +- `'enabled_reads_on_main'` (string): Setting name +- `'true'` (string): Enable reads on main instance + +### Replica read lag control + +Control the maximum allowed replica lag for read consistency: + +```cypher +SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10'; +``` + +**Parameters:** +- `'max_replica_read_lag_'` (string): Setting name +- `'10'` (string): Maximum transaction lag as string + +**Behavior:** +- Replicas behind by more than this threshold are excluded from read routing +- Ensures data freshness for read operations + +## Connection examples by language + +### Python + +```python +from neo4j import GraphDatabase + +# HA connection +driver = GraphDatabase.driver("neo4j://localhost:7691", auth=("username", "password")) + +# Use the driver normally - routing is handled automatically +with driver.session() as session: + result = session.run("MATCH (n) RETURN count(n)") + print(result.single()[0]) +``` + +### JavaScript/Node.js + +```javascript +const neo4j = require('neo4j-driver'); + +// HA connection +const driver = neo4j.driver("neo4j://localhost:7691", + neo4j.auth.basic("username", "password")); + +// Use the driver normally +const session = driver.session(); +session.run("MATCH (n) RETURN count(n)") + .then(result => console.log(result.records[0].get(0))); +``` + +### Java + +```java +import org.neo4j.driver.*; + +// HA connection +Driver driver = GraphDatabase.driver("neo4j://localhost:7691", + AuthTokens.basic("username", "password")); + +// Use the driver normally +try (Session session = driver.session()) { + Result result = session.run("MATCH (n) RETURN count(n)"); + System.out.println(result.single().get(0)); +} +``` + +### C# + +```csharp +using Neo4j.Driver; + +// HA connection +using var driver = GraphDatabase.Driver("neo4j://localhost:7691", + AuthTokens.Basic("username", "password")); + +// Use the driver normally +using var session = driver.Session(); +var result = session.Run("MATCH (n) RETURN count(n)"); +Console.WriteLine(result.Single()[0]); +``` + +## Best practices + +### Connection management + +1. **Use connection pooling**: Most drivers provide built-in connection pooling +2. **Handle connection failures**: Implement retry logic for transient failures +3. **Monitor connection health**: Use driver health check features when available + +### Query optimization + +1. **Use read replicas**: Distribute read queries across replicas for better performance +2. **Minimize cross-database queries**: Keep queries within the same database when possible +3. **Use appropriate transaction types**: Read transactions for queries, write transactions for modifications + +### Error handling + +```python +from neo4j import GraphDatabase +from neo4j.exceptions import ServiceUnavailable + +def execute_with_retry(driver, query, max_retries=3): + for attempt in range(max_retries): + try: + with driver.session() as session: + return session.run(query) + except ServiceUnavailable as e: + if attempt == max_retries - 1: + raise e + time.sleep(2 ** attempt) # Exponential backoff +``` + +## Troubleshooting + +### Common issues + +**Connection refused errors:** +- Verify coordinator instances are running +- Check firewall settings for coordinator ports +- Ensure proper network connectivity + +**Routing table errors:** +- Verify cluster state with `SHOW INSTANCES` +- Check coordinator health and leadership +- Ensure proper cluster configuration + +**Query routing issues:** +- Verify instance roles (main/replica) +- Check replication lag settings +- Monitor cluster health metrics + +### Debugging connections + +1. **Check cluster state:** + ```cypher + SHOW INSTANCES; + ``` + +2. **Verify coordinator settings:** + ```cypher + SHOW COORDINATOR SETTINGS; + ``` + +3. **Monitor replication lag:** + ```cypher + SHOW REPLICATION LAG; + ``` + +## Limitations and considerations + +### Cluster setup restrictions + +- **Setup commands must use bolt://**: Cluster management commands (registration, coordinator setup) require direct `bolt://` connections +- **Routing only for data queries**: `neo4j://` connections only handle data-oriented queries, not cluster management + +### Network requirements + +- **Stable network**: Requires reliable network connectivity between instances +- **Port accessibility**: All coordinator and data instance ports must be accessible +- **DNS resolution**: Use DNS names instead of IP addresses for better reliability + +### Performance considerations + +- **Routing overhead**: Small additional latency for routing table requests +- **Connection pooling**: May need to adjust pool sizes for HA workloads +- **Load balancing**: Read distribution depends on replica availability + + +For detailed examples of bolt+routing usage in different programming languages, check the [Memgraph drivers repository](https://github.com/memgraph/memgraph/tree/master/tests/drivers). + + + diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx index 948495b9e..5680b07fd 100644 --- a/pages/clustering/faq.mdx +++ b/pages/clustering/faq.mdx @@ -7,10 +7,16 @@ import { CommunityLinks } from '/components/social-card/CommunityLinks' # Frequently asked questions -## High availability +## High availability (general) + + + +### High availability with Docker + +### High availability with Docker Compose ### High availability with K8s - \ No newline at end of file + diff --git a/pages/clustering/ha-commands-reference.mdx b/pages/clustering/ha-commands-reference.mdx new file mode 100644 index 000000000..84def6991 --- /dev/null +++ b/pages/clustering/ha-commands-reference.mdx @@ -0,0 +1,346 @@ +--- +title: High availability reference queries +description: Complete reference guide for all high availability commands in Memgraph, including cluster management, instance operations, and monitoring queries. +--- + +import { Callout } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + +# High availability reference queries + +This page provides a comprehensive reference for all commands available in Memgraph's high availability cluster management. + +## Cluster setup commands + +### ADD COORDINATOR + +Adds a coordinator instance to the cluster. + +```cypher +ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer, "management_server": managementServer}; +``` + +**Parameters:** +- `coordinatorId` (integer): Unique identifier for the coordinator +- `bolt_server` (string): External bolt server endpoint for client connections +- `coordinator_server` (string): Server endpoint for Raft communication +- `management_server` (string): Server endpoint for health checks and cluster management + +**Example:** +```cypher +ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; +``` + + +This command needs to be run for all coordinators in the cluster. The order of adding coordinators and data instances doesn't matter. + + +### REGISTER INSTANCE + +Registers a data instance to the cluster. + +```cypher +REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; +``` + +**Parameters:** +- `instanceName` (string): Unique name for the data instance +- `AS ASYNC | AS STRICT_SYNC` (string, optional): Optional replication mode (defaults to SYNC) +- `bolt_server` (string): External bolt server endpoint +- `management_server` (string): Server endpoint for coordinator communication +- `replication_server` (string): Server endpoint for data replication + +**Replication modes:** +- `ASYNC`: Asynchronous replication (fastest, potential data loss) +- `SYNC`: Synchronous replication (balanced, minimal data loss) +- `STRICT_SYNC`: Strict synchronous replication (slowest, no data loss) + +**Example:** +```cypher +REGISTER INSTANCE instance_1 AS SYNC WITH CONFIG {"bolt_server": "localhost:7687", "management_server": "instance1:13011", "replication_server": "instance1:10001"}; +``` + +## Instance management commands + +### SET INSTANCE TO MAIN + +Promotes a data instance to become the main (writable) instance. + +```cypher +SET INSTANCE instanceName TO main; +``` + +**Parameters:** +- `instanceName` (string): Name of the instance to promote + +**Behavior:** +- Registers all other instances as replicas to the new main +- Fails if the target instance is unavailable +- Fails if there's already a main instance in the cluster +- Results in writing to the Raft log + +**Example:** +```cypher +SET INSTANCE instance_3 TO main; +``` + +### DEMOTE INSTANCE + +Demotes the current main instance to replica status. + +```cypher +DEMOTE INSTANCE instanceName; +``` + +**Parameters:** +- `instanceName` (string): Name of the instance to demote + +**Behavior:** +- Manually demotes the main instance to replica +- Requires manual promotion of another instance to main +- Results in writing to the Raft log + + +Combining `DEMOTE INSTANCE` and `SET INSTANCE TO MAIN` provides manual failover capability, useful during maintenance work. + + +### UNREGISTER INSTANCE + +Removes a data instance from the cluster. + +```cypher +UNREGISTER INSTANCE instanceName; +``` + +**Parameters:** +- `instanceName` (string): Name of the instance to remove + +**Requirements:** +- The instance being unregistered must NOT be the main instance +- The cluster must have an alive main instance during unregistration +- The instance will be removed from the current main's replica set + +**Example:** +```cypher +UNREGISTER INSTANCE instance_2; +``` + +### REMOVE COORDINATOR + +Removes a coordinator instance from the cluster. + +```cypher +REMOVE COORDINATOR coordinatorId; +``` + +**Parameters:** +- `coordinatorId` (integer): ID of the coordinator to remove + +**Restrictions:** +- Can only be executed on the leader coordinator +- Cannot remove the current leader (prohibited by NuRaft) +- To remove the current leader, first trigger a leadership change + +**Example:** +```cypher +REMOVE COORDINATOR 2; +``` + +## Cluster state management + +### FORCE RESET CLUSTER STATE + +Forces a reset of the cluster state when the cluster gets stuck. + +```cypher +FORCE RESET CLUSTER STATE; +``` + +**Actions performed:** +1. Demotes each alive instance to replica +2. Chooses a new main instance from alive instances +3. Instances that are down will be demoted to replicas when they come back up + +**Usage:** +- Execute on the leader coordinator +- Results in writing to the Raft log +- Use only when the cluster is in an inconsistent state + +## Monitoring and information commands + +### SHOW INSTANCES + +Displays the state of all instances in the cluster. + +```cypher +SHOW INSTANCES; +``` + +**Information displayed:** +- Network endpoints for cluster management +- Health state of each server +- Role (main, replica, LEADER, FOLLOWER, or unknown) +- Time since last response to leader's health ping + +**Behavior:** +- Can be run on leader or followers +- Followers forward the request to the leader for accurate information +- If leader is unavailable, followers return instances with "down" health state + +**Example output:** +``` +| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | +| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | +| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | +| instance_1 | localhost:7687 | "" | localhost:13011 | up | replica | 39 | +| instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | +``` + +### SHOW INSTANCE + +Shows information about the current coordinator instance. + +```cypher +SHOW INSTANCE; +``` + +**Information returned:** +- Instance name +- External bolt server endpoint +- Coordinator server for Raft communication +- Management server for inter-coordinator communication +- Cluster role (leader or follower) + +**Note:** If `ADD COORDINATOR` wasn't run for the current instance, the bolt server value will be empty. + +### SHOW REPLICATION LAG + +Displays the current replication lag for each instance. + +```cypher +SHOW REPLICATION LAG; +``` + +**Information provided:** +- Replication lag expressed as number of committed transactions +- Made durable through snapshots and WALs +- Useful for manual failover to check data loss risk + +**Usage:** +- Run on the cluster's leader +- Helps assess data consistency before failover operations + +## Configuration commands + +### SET COORDINATOR SETTING + +Configures various cluster settings at runtime. + +#### Enable reads on main + +```cypher +SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false'; +``` + +**Parameters:** +- `'enabled_reads_on_main'` (string): Setting name +- `'true'/'false'` (string): Boolean value as string + +Controls whether read queries are allowed on the main instance (default: false). + +#### Sync failover only + +```cypher +SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false'; +``` + +**Parameters:** +- `'sync_failover_only'` (string): Setting name +- `'true'/'false'` (string): Boolean value as string + +Controls whether failover to async replicas is allowed (default: true). + +#### Maximum failover replica lag + +```cypher +SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10'; +``` + +**Parameters:** +- `'max_failover_replica_lag'` (string): Setting name +- `'10'` (string): Numeric value as string representing transaction count + +Sets the maximum transaction lag allowed during failover. Replicas behind by more than this threshold become ineligible for failover. + +#### Maximum replica read lag + +```cypher +SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10'; +``` + +**Parameters:** +- `'max_replica_read_lag_'` (string): Setting name +- `'10'` (string): Numeric value as string representing transaction count + +Controls the maximum allowed replica lag for read consistency. Replicas behind by more than this threshold are excluded from read query routing. + +### SHOW COORDINATOR SETTINGS + +Displays all current coordinator configuration settings. + +```cypher +SHOW COORDINATOR SETTINGS; +``` + +Returns all runtime configuration options and their current values. + +## Connection and routing + +### Bolt+routing protocol + +When using high availability, connect to coordinators using the `neo4j://` scheme instead of `bolt://`: + +**Standard connection:** +``` +bolt:// +``` + +**HA connection with routing:** +``` +neo4j:// +``` + +**Benefits:** +- Automatic routing to current main instance +- Prevents split-brain scenarios +- Seamless failover handling +- Write queries always go to the current main +- Read queries can be distributed across replicas + + +Cluster setup commands (registration, coordinator management) must be done using standard `bolt://` connections, not `neo4j://` routing connections. + + +## Best practices + +### Command execution order + +1. **Start all instances** (coordinators and data instances) +2. **Add coordinators** to the cluster +3. **Register data instances** to the cluster +4. **Set one instance as main** +5. **Verify cluster state** with `SHOW INSTANCES` + +### Health monitoring + +- Use `SHOW INSTANCES` regularly to monitor cluster health +- Check `SHOW REPLICATION LAG` before manual failovers +- Monitor coordinator settings with `SHOW COORDINATOR SETTINGS` + +### Failover considerations + +- Use `SHOW REPLICATION LAG` to assess data loss risk +- Consider replication modes when planning failovers +- Test failover procedures in non-production environments + + From 55b0272746e1a925d954d1bbba7716313e93ba24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Mon, 20 Oct 2025 16:28:34 +0200 Subject: [PATCH 03/13] Add concepts of replication, and revamp community replication guide --- pages/clustering.mdx | 64 ++- pages/clustering/_meta.ts | 3 +- .../concepts/how-replication-works.mdx | 259 +++++++++ .../ha-commands-reference.mdx | 0 .../querying-the-cluster.mdx} | 6 +- pages/clustering/replication.mdx | 540 +----------------- pages/clustering/replication/_meta.ts | 7 + .../clustering/replication/best-practices.mdx | 66 +++ .../replication-commands-reference.mdx | 272 +++++++++ .../setup-replication-cluster-docker.mdx | 226 ++++++++ .../setup-replication-cluster-k8s.mdx | 27 + .../replication/system-replication.mdx | 35 +- pages/deployment/environments/aws.mdx | 15 + 13 files changed, 969 insertions(+), 551 deletions(-) create mode 100644 pages/clustering/concepts/how-replication-works.mdx rename pages/clustering/{ => high-availability}/ha-commands-reference.mdx (100%) rename pages/clustering/{bolt-routing.mdx => high-availability/querying-the-cluster.mdx} (97%) create mode 100644 pages/clustering/replication/_meta.ts create mode 100644 pages/clustering/replication/best-practices.mdx create mode 100644 pages/clustering/replication/replication-commands-reference.mdx create mode 100644 pages/clustering/replication/setup-replication-cluster-docker.mdx create mode 100644 pages/clustering/replication/setup-replication-cluster-k8s.mdx diff --git a/pages/clustering.mdx b/pages/clustering.mdx index 23c3f70ff..8efdcfa41 100644 --- a/pages/clustering.mdx +++ b/pages/clustering.mdx @@ -3,30 +3,64 @@ title: Clustering description: Learn all about replication and high availability features in Memgraph. --- -import {CommunityLinks} from '/components/social-card/CommunityLinks' +import { Callout } from 'nextra/components' +import { CommunityLinks } from '/components/social-card/CommunityLinks' # Clustering -To create a cluster, you can [replicate data](/clustering/replication) across -several instances. One instance is the MAIN instance and others are either SYNC -or ASYNC replicas. With Memgraph Community, to achieve high availability, you -need to manage automatic failover. On the other hand, Memgraph Enterprise has -[high availability](/clustering/high-availability) features included in the +To create a cluster, you can replicate data across several instances. Memgraph operates replication with: +- one writer instance (MAIN) +- one or more read-only instances (REPLICA) + +Replication can be configured in three replication modes: +- SYNC replication mode +- STRICT_SYNC replication mode +- ASYNC replication mode + + + +**We strongly suggest that user reads the guide on [how replication works](/clustering/concepts/how-replication-works) +in Memgraph on a logical level, before moving to the part of setting the cluster up.** +Choosing the appropriate number of Memgraph instances, as well as the replication mode on each +of them is crucial to understand, as that impacts performance and availability of the cluster based on your needs. + + + +With Memgraph Community, you gain [replication](/clustering/replication) capabilities out of the box. +However, to achieve high availability, you need to manage automatic failover. + +On the other hand, Memgraph Enterprise has [high availability](/clustering/high-availability) features included in the offering to ease the management of Memgraph clusters. In such case, the cluster -consists of MAIN instance, REPLICA instances and COORDINATOR instances which, -backed up by Raft protocol, manage the cluster state. +consists of: +- MAIN instance +- REPLICA instances +- COORDINATOR instances (backed up by Raft protocol, manage the cluster state and perform leader election) + + + +Replication and high availability currently **work only in the [in-memory +transactional storage mode](/fundamentals/storage-memory-usage#in-memory-transactional-storage-mode-default)**. + + + +## [How replication works](/clustering/concepts/how-replication-works) + +Learn about the underlying implementation and theoretical concepts behind Memgraph replication, including CAP theorem, replication modes, and synchronization mechanisms. -Replication and high availability currently **work only in the in-memory -transactional [storage mode](/fundamentals/storage-memory-usage)**. +## [Replication cluster setup (Community)](/clustering/replication) +Learn how to set up a replication cluster with Memgraph. +**Replication is included in Memgraph Community**, making it accessible to all users who want to create data replicas across multiple instances. +Memgraph Community however does not ensure high availability itself, as **automatic failover is not included**. Community users are encouraged to +perform the necessary steps themselves for keeping the replication cluster up and running. -## [High availability](/clustering/high-availability) +## [High availability cluster setup (Enterprise)](/clustering/high-availability) -Learn how to utilize high availability features and all the important under the -hood information. +Learn how to setup and manage a high availability cluster with Memgraph. +This guide is for users of **Memgraph Enterprise** who want to achieve clustering and 24/7 uptime. -## [Replication](/clustering/replication) +## [FAQ](/clustering/faq) -Learn how replication is achieved in Memgraph and how to set it up. +Frequently asked questions about clustering, replication, and high availability in Memgraph. \ No newline at end of file diff --git a/pages/clustering/_meta.ts b/pages/clustering/_meta.ts index 0516356f1..3d59275d6 100644 --- a/pages/clustering/_meta.ts +++ b/pages/clustering/_meta.ts @@ -1,7 +1,6 @@ export default { + "concepts": "Concepts", "high-availability": "High availability", - "bolt-routing": "Bolt+routing protocol", - "ha-commands-reference": "High availability reference queries", "replication": "Replication", "faq": "FAQ" } diff --git a/pages/clustering/concepts/how-replication-works.mdx b/pages/clustering/concepts/how-replication-works.mdx new file mode 100644 index 000000000..15dab93bf --- /dev/null +++ b/pages/clustering/concepts/how-replication-works.mdx @@ -0,0 +1,259 @@ +--- +title: How replication works +description: Learn about the underlying implementation and theoretical concepts behind Memgraph replication, including CAP theorem, replication modes, and synchronization mechanisms. +--- + +import { Callout } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + +# How replication works in Memgraph + +Uninterrupted data and operational availability in production systems are +critical and can be achieved in many ways. In Memgraph we opted for replication. + +In distributed systems theory the CAP theorem, also named Brewer's theorem, +states that any distributed system can simultaneously guarantee two out of the +three properties: + +1. **Consistency** (C) - every node has the same view of data at a given point in + time +2. **Availability** (A) - all clients can find a replica of the data, even in the + case of a partial node failure +3. **Partition tolerance** (P) - the system continues to work as expected despite a + partial network failure + +![](/pages/clustering/replication/memgraph-replication-CAP-theorem.png) + +Most of the Memgraph use cases do not benefit from well-known algorithms that +strive to achieve all three CAP properties, such as Raft, because due to their +complexity, they produce performance issues. Memgraph use-cases are based on +running analytical graph workloads on real-time data, demanding a simpler +concept such as **replication**. + +Replication consists of replicating data from one storage to one or several +other storages. The downside of its simplicity is that only two out of three CAP +properties can be achieved. + +### Replication implementation in Memgraph + +To enable replication, there must be at least two instances of Memgraph in a +cluster. Each instance has one of two roles: **MAIN** or **REPLICA**. + + + +The MAIN instance can accept read and write queries to the database, while the REPLICA instances accept only +read queries. + + + +The way MAIN instance replicates data to the REPLICA instances can be carried out in a +**SYNC**, **ASYNC**, or **STRICT_SYNC** mode. +The replication mode defines the terms by which the MAIN instance can commit the +changes to the database, thus modifying the system to prioritize either +consistency or availability. +- **STRICT_SYNC mode** - After committing a transaction, the MAIN instance will communicate the +changes to all REPLICA instances and wait until it receives a response or information that a timeout is reached. +The STRICT_SYNC mode ensures consistency and partition tolerance (CP), but not availability for writes. +If the primary database has multiple replicas, the system is highly available for reads. But, when a replica fails, +the MAIN instance can’t process the write due to the nature of synchronous replication. It is implemented as +two-phase commit protocol. +- **SYNC mode** - After committing a transaction, the MAIN instance will communicate the changes to all +REPLICA instances and wait until it receives a response or information that a timeout is reached. +It is different from STRICT_SYNC mode because it the MAIN can continue committing even in situations when +SYNC replica is down. +- **ASYNC mode** - The MAIN instance will commit a transaction without receiving confirmation from +REPLICA instances that they have received the same transaction. ASYNC mode ensures system availability +and partition tolerance (AP), while data can only be eventually consistent. + +By using the timestamp, the MAIN instance knows the current state of the +REPLICA. If the REPLICA is not synchronized (lagging behind) with the MAIN instance, the MAIN +instance sends the correct data for synchronization as WAL files. When all the WAL files have been +successfully transferred to the REPLICA instance, the system is then considered to be in-sync. +This procedure is similar to [how PostgreSQL does replication](https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION). + +If the REPLICA is so far behind the MAIN instance that the synchronization using +WAL files is impossible, Memgraph will use snapshots. + +### Replication modes + +Replication mode defines the terms by which the MAIN instance can commit the +changes to the database, thus modifying the system to prioritize either +consistency or availability. There are two possible replication modes +implemented in Memgraph replication: + +- SYNC +- ASYNC + +![](/pages/clustering/replication/memgraph-replication-async-sync.png) + +When a REPLICA instance is registered and added to the cluster, it will start +replicating to catch up to the current state of the MAIN instance. Initial replication +when a REPLICA instance is registered is handled in ASYNC mode by design decision. + + +When the REPLICA instance synchronizes with the MAIN +instance, the replication mode will change according to the mode defined during +registration. + +#### SYNC replication mode + +SYNC mode is the most straightforward replication mode in which the main storage +thread waits for the response and cannot continue until the response is +received or a timeout is reached. + +The following diagrams express the behavior of the MAIN instance in cases when +SYNC REPLICA doesn't answer within the expected timeout. + +**SYNC REPLICA going down when creating index, uniqueness constraint or existence constraint** + +![](/pages/clustering/replication/workflow_diagram_data_definition_creation.drawio.png) + +**SYNC REPLICA going down when dropping index, uniqueness constraint or existence constraint** + +![](/pages/clustering/replication/workflow_diagram_data_definition_dropping.drawio.png) + +**SYNC REPLICA going down adding/updating/deleting data** + +![](/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png) + + +#### STRICT_SYNC replication mode + +The STRICT_SYNC replication mode behaves very similarly to a +SYNC mode except that MAIN **won't commit a transaction locally in a situation in +which one of STRICT_SYNC replicas is down**. To achieve that, all instances run +together a *two-phase commit* protocol which allows you such a synchronization. This +reduces the throughout but such a mode is super useful in a high-availability +scenario in which a failover is the most operation to support. Such a mode then +allows you a failover **without the fear of experiencing a data loss**. + +STRICT_SYNC mode ensures consistency and partition tolerance. + +#### ASYNC replication mode + +In the ASYNC replication mode, the MAIN instance will commit a transaction +without receiving confirmation from REPLICA instances that they have received +the same transaction. This means that the **MAIN instance does not wait for the +response from the REPLICA instances** in the main thread but in some other thread. + +Each REPLICA instance has one permanent thread connecting it with +the MAIN instance for ASYNC replication. Using this background thread, the MAIN instance pushes +replication tasks to the REPLICA instance, creates a custom thread pool pattern, +and receives confirmations of successful replication from the REPLICATION +instance. + +![](/pages/clustering/replication/memgraph-replication-async.png) + +ASYNC mode ensures system availability and partition tolerance. + +### Synchronizing instances + +By comparing timestamps, the MAIN instance knows when a REPLICA instance is not +synchronized and is missing some earlier transactions. The REPLICA instance is +then set into a RECOVERY state, where it remains until it is fully synchronized +with the MAIN instance. + +**The missing data changes can be sent as snapshots or WAL files, which are the main +data durability files for Memgraph.** Snapshot files represent an image of the current state of +the database and are much larger than the WAL files, which only contain the changes, deltas. +Because of the difference in file size, Memgraph favors the WAL files. + +While the REPLICA instance is in the RECOVERY state, the MAIN instance +calculates the optimal synchronization path based on the REPLICA instance's +timestamp and the current state of the durability files while keeping the +overall size of the files necessary for synchronization to a minimum. + +![](/pages/clustering/replication/memgraph-replication-sync-process.png) + +Imagine there were 5 changes made to the database. Each change is saved in a WAL +file, so there are 5 WAL files, and the snapshot was created after 3 changes. +The REPLICA instance can be synchronized using a snapshot and the 2 latest WAL +files or using 5 WAL files. Both options would correctly synchronize the +instances, but 5 WAL files are much smaller. + +The durability files are constantly being created, deleted, and updated. Also, +each replica could need a different set of files to sync. There are several ways +to ensure that the necessary files persist and that instances can read the WAL +files currently being updated without affecting the performance of the rest of +the database. + +#### Locking durability files + +Durability files are also used for recovery and are periodically deleted to +eliminate redundant data. The problem is that they can be deleted while they are +being used to synchronize a REPLICA with the MAIN instance. + +To delay the file deletion, Memgraph uses a file retainer that consists of +multiple lockers. Threads can store and lock the files they found while +searching for the optimal recovery path in the lockers, thus ensuring the files +will still exist once they are sent to the REPLICA instance as a part of the +synchronization process. If another part of the system sends a deletion +request for a certain file, the file retainer first checks if that file is +locked in a locker. If it is not, it is deleted immediately. If the file is +locked, the file retainer adds the file to the deletion queue. The file retainer +will periodically clean the queue by deleting the files that are no longer +locked inside the locker. + +#### Writing and reading files simultaneously + +Memgraph internal file buffer is used when writing deltas to WAL files, and +mid-writing, the content of one WAL file can be divided across two locations. If +at that point that WAL file is used to synchronize the REPLICA instance, once +the data is being read from the internal buffer, the buffer can be flushed, and +the REPLICA could receive an invalid WAL file because it is missing a chunk of +data. It could also happen that the WAL file is sent before all the transactions +are written to the internal buffer. + +To avoid these issues, flushing of that internal buffer is disabled while the +current WAL is sent to a REPLICA instance. To get all the data necessary for the +synchronization, the replication thread reads the content directly from the WAL +file, then reads how many bytes are written in the buffer and copies the data to +another location. Then the flushing is enabled again, and the transaction is +replicated using the copied buffer. Because the access to the internal buffer +was not blocked, new data can be written. The content of the buffer (including +any new data) is then written in a new WAL file that will be sent in the next +synchronization process. + +![](/pages/clustering/replication/memgraph-replication-buffer.png) + +#### Fixing timestamp consistency + +Timestamps are used to compare the state of the REPLICA instance in comparison +to the MAIN instance. + +At first, we used the current timestamp without increasing its value for global +operations, like creating an index or creating a constraint. By using a single +timestamp, it was impossible to know which operations the REPLICA had applied +because sequential global operations had the same timestamp. To avoid this +issue, a unique timestamp is assigned to each global operation. + +As replicas allow read queries, each of those queries was assigned with its own +timestamp. Those timestamps caused issues when the replicated write transactions +were assigned an older timestamp. A read transaction would return different data +from the same read query if a transaction was replicated between those two read +transactions which obstructed the snapshot isolation. To avoid this problem, the +**timestamp on REPLICA instances isn't increased** because the read transactions +don't produce any changes, so no deltas need to be timestamped. + +#### Incompatible instances + +To avoid issues when the durability files of two different database instances +are stored in the same folder, a unique ID is assigned to each storage instance. +The same ID is then assigned to the durability files. Replication uses the +instance ID to validate that the files and the database are compatible. + +A unique ID `epoch_id` is also assigned each time an instance is run as the MAIN +instance in the replication cluster to check if the data is compatible for +replication. The `epoch_id` is necessary when the original MAIN instance fails, +a REPLICA instance becomes a new MAIN, and after some time, the original MAIN +instance is brought back online. If no transactions were run on the original +MAIN instance, the difference in timestamps will indicate that it is behind the +new MAIN, and it would be impossible to set the original MAIN-REPLICA +relationship. But if the transactions were run on the original MAIN after it was +brought back online, the timestamp would be of no help, but the `epoch_id` would +indicate incomparability, thus preventing the original MAIN from reclaiming its +original role. + +![](/pages/clustering/replication/memgraph-replication-ids.png) + + diff --git a/pages/clustering/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx similarity index 100% rename from pages/clustering/ha-commands-reference.mdx rename to pages/clustering/high-availability/ha-commands-reference.mdx diff --git a/pages/clustering/bolt-routing.mdx b/pages/clustering/high-availability/querying-the-cluster.mdx similarity index 97% rename from pages/clustering/bolt-routing.mdx rename to pages/clustering/high-availability/querying-the-cluster.mdx index 17567a14c..be0a8d546 100644 --- a/pages/clustering/bolt-routing.mdx +++ b/pages/clustering/high-availability/querying-the-cluster.mdx @@ -1,12 +1,12 @@ --- -title: Bolt+routing protocol -description: Learn how to use the bolt+routing protocol to connect to Memgraph high availability clusters with automatic failover and load balancing. +title: Querying the cluster +description: Learn how to query Memgraph high availability clusters using the bolt+routing protocol with automatic failover and load balancing. --- import { Callout } from 'nextra/components' import {CommunityLinks} from '/components/social-card/CommunityLinks' -# Bolt+routing protocol +# Querying the cluster The bolt+routing protocol is Memgraph's solution for connecting to high availability clusters. It automatically routes queries to the appropriate instances and handles failover seamlessly, ensuring your applications remain connected even when cluster topology changes. diff --git a/pages/clustering/replication.mdx b/pages/clustering/replication.mdx index d4c66ee81..519b2c1b3 100644 --- a/pages/clustering/replication.mdx +++ b/pages/clustering/replication.mdx @@ -5,48 +5,19 @@ description: Dive into the documentation page for Memgraph and learn how to conf import { Callout } from 'nextra/components' -# Replication +# How to setup replication with Memgraph (Community) - - -Instances need to remember their role and configuration details in a replication -cluster upon restart, and the `--replication-restore-state-on-startup` needs to -be set to `true` when first initializing the instances and remain `true` -throughout the instances' lifetime for replication to work correctly. If the -flag is set to `false`, MAIN can't communicate with instance, because each -REPLICA has a UUID of MAIN which can communicate with it, and it is set up only -on instance registration. In case the flag is set to `false`, the way to go -forward is first to unregister the instance on MAIN and register it again. - -When reinstating a cluster, it is advised first to initialize the MAIN instance, -then the REPLICA instances. - -Data replication currently **works only in the in-memory transactional [storage -mode](/fundamentals/storage-memory-usage)**. + -If you're using in-memory analytical storage mode for the fast import, please first import your data, then set up the replication. +This guide is for **Memgraph Community** users who want to set up data replication across multiple instances. +If you have a **Memgraph Enterprise** license, we recommend using the [high availability features](/clustering/high-availability) instead, which provide automatic failover, +load balancing, and comprehensive cluster management capabilities. -When distributing data across several instances, Memgraph uses replication to -provide a satisfying ratio of the following properties, known from the CAP -theorem: - -1. **Consistency** (C) - every node has the same view of data at a given point - in time -2. **Availability** (A) - all clients can find a replica of the data, even in - the case of a partial node failure -3. **Partition tolerance** (P) - the system continues to work as expected - despite a partial network failure - -In the replication process, the data is replicated from one storage (MAIN -instance) to another (REPLICA instances). - - + -From version 2.4 it is no longer possible to specify a timeout when registering -a sync replica. To mimic this behavior in higher releases, please use ASYNC -replication instead. +**Users are advised to first read the guide on [how replication works](/clustering/concepts/how-replication-works).** @@ -57,76 +28,26 @@ cluster, one instance has to be chosen as the MAIN instance. The rest of the instances have to be demoted to REPLICA roles and have a port defined using a Cypher query. - - - -For replication, ensure all machines (Main and Replica instances) have exactly -the same amount of RAM and the same CPU. This uniformity is crucial for -consistent performance and reliability. - - - -If you want instances to remember their role and configuration in a replication -cluster upon restart, they need to be initialized with the -`--replication-restore-state-on-startup` set to `true` and remain `true` -throughout the instances' lifetime. Otherwise and by default, restarted -instances will start as MAIN instances disconnected from any replication -cluster. - -Once demoted to REPLICA instances, they will no longer accept write queries. In -order to start the replication, each REPLICA instance needs to be registered -from the MAIN instance by setting a replication mode (SYNC, ASYNC or -STRICT_SYNC) and specifying the REPLICA instance's socket address. - -The replication mode defines the terms by which the MAIN instance can commit the -changes to the database, thus modifying the system to prioritize either -consistency or availability: - - -- **STRICT_SYNC** - After committing a transaction, the MAIN instance will -communicate the changes to all REPLICA instances and wait until it receives a -response or information that a timeout is reached. The STRICT_SYNC mode ensures -consistency and partition tolerance (CP), but not availability for writes. If -the primary database has multiple replicas, the system is highly available for -reads. But, when a replica fails, the MAIN instance can't process the write due -to the nature of synchronous replication. It is implemented as two-phase commit -protocol. - - -- **SYNC** - After committing a transaction, the MAIN instance will communicate -the changes to all REPLICA instances and wait until it receives a response or -information that a timeout is reached. It is different from **STRICT_SYNC** mode -because it the MAIN can continue committing even in situations when **SYNC** -replica is down. - - -- **ASYNC** - The MAIN instance will commit a transaction without receiving - confirmation from REPLICA instances that they have received the same - transaction. ASYNC mode ensures system availability and partition tolerance - (AP), while data can only be eventually consistent. - - - - -Users are advised to use the same value for configuration flag -`--storage-wal-file-flush-every-n-txn` on MAIN and SYNC REPLICAs. Otherwise, the -situation could occur in which there is a data which is fsynced on REPLICA and -not on MAIN. In the case MAIN crashes, this could leave to conflicts in system -that would need to be manually resolved by users. - - +The MAIN instance can accept read and write queries, while the REPLICA instance can only accept +reads. Once an instance has been demoted to a REPLICA instance, it will no longer accept write queries. +In order to start the replication, each REPLICA instance needs to be registered +from the MAIN instance by setting a [replication mode](/clustering/concepts/how-replication-works#replication-modes) +(SYNC, ASYNC or STRICT_SYNC) and specifying the REPLICA instance's socket address. Once the REPLICA instances are registered, data storage of the MAIN instance is replicated and synchronized using transaction timestamps and durability files -(snapshot files and WALs). Memgraph does not support replication of -authentication configurations, query and authentication modules, and audit logs. +(snapshot files and WALs). When we talk about data storage, we strictly mean the graph +itself, along with the complementary performance and correctness data structures, such as nodes, +relationships, properties, indices, constraints, triggers, and streams. +For replication support of non-graph data, such as authentication configurations, multi-tenant data, please refer +to the [system replication reference](/clustering/replication/system-replication). By using the timestamp, the MAIN instance knows the current state of the REPLICA. If the REPLICA is not synchronized with the MAIN instance, the MAIN -instance sends the correct data for synchronization kept as deltas within WAL +instance sends the correct data for synchronization kept as delta objects within WAL files. Deltas are the smallest possible updates of the database, but they carry -enough information to synchronize the data on a REPLICA. Memgraph stores only -`remove` actions as deltas, for example, `REMOVE key:value ON node_id`. +enough information to synchronize the data on a REPLICA. For more information about delta objects, +please refer to the [in-memory transactional storage mode guides](/fundamentals/storage-memory-usage#in-memory-analytical-storage-mode). If the REPLICA is so far behind the MAIN instance that the synchronization using WAL files and deltas within it is impossible, Memgraph will use snapshots to @@ -138,31 +59,7 @@ also reflects on the replication. The mechanism that is used is a unique identifier that which MAIN instance sends to all REPLICAs when REPLICA is first registered on a MAIN. A REPLICA stores the UUID of the MAIN instance it listens to. The MAIN's UUID is also stored on a disk, in case of restart of an instance -to continue listening to the correct MAIN instance. When REPLICA restarts, -`--replication-restore-state-on-startup` must be set to `true` to continue -getting updates from the MAIN. - -## Auth data replication (Enterprise) - -If you are using a Memgraph Enterprise license, all authentication/authorization -data, including users, roles, and associated permissions, will be replicated. - -## Auth modules replication (Enterprise) - -Authentication modules are not replicated and must be configured manually by the -administrator. - -## Multi-tenant data replication (Enterprise) - -When you are using a Memgraph Enterprise license, multi-tenant commands are -replicated as any other data command. Database manipulation is allowed only on -MAIN. However, REPLICAs have the ability to use databases and read data -contained in them. - -When dropping a database used on a REPLICA, the REPLICA will receive the command -and will partially drop the database. It will hide the database and prevent any -new usage. Once all clients have released the database, it will be deleted -entirely. +to continue listening to the correct MAIN instance. @@ -215,7 +112,7 @@ you can run Memgraph with Docker, but if you are using volumes, they need to be called differently and each instance needs to be exposed via a different port. Check the example of creating [a replication -cluster](#set-up-a-replication-cluster). +cluster](/clustering/replication/setup-replication-cluster-docker). ## Assigning roles @@ -372,396 +269,3 @@ To drop a replica, run the following query: ```plaintext DROP REPLICA ; ``` - -## MAIN and REPLICA synchronization - -By comparing timestamps, the MAIN instance knows when a REPLICA instance is not -synchronized and is missing some earlier transactions. The REPLICA instance is -then set into a RECOVERY state, where it remains until it is fully synchronized -with the MAIN instance#synchronizing-instances. - -The missing data changes can be sent as snapshots or WAL files. Snapshot files -represent an image of the current state of the database and are much larger than -the WAL files, which only contain the changes, deltas. Because of the difference -in file size, Memgraph favors the WAL files. It is important to note that -replicas receive only changes which are made durable on the MAIN instance, in -other words changes which are already fsynced. - -While the REPLICA instance is in the RECOVERY state, the MAIN instance -calculates the optimal synchronization path based on the REPLICA instance's -timestamp and the current state of the durability files while keeping the -overall size of the files necessary for synchronization to a minimum. - -## Set up a replication cluster - -In the replication process, the data is replicated from one storage (MAIN -instance) to another (REPLICA instances), thus providing a combination of -consistency, availability and partition tolerance when distributing data over -several instances. - -This example demonstrates how to create a simple cluster of nodes running -Memgraph instances, and set up replication using various replication modes. - -### Cluster topology - -The cluster will consist of three nodes, one MAIN instance and two REPLICA -instances. In order to showcase the creation of REPLICA instances with different -replication modes, we will create: - -- The MAIN instance - contains the original data that will be replicated to - REPLICA instances -- REPLICA instance 1 - replication in the SYNC mode -- REPLICA instance 2 - replication in the ASYNC mode - -### Run multiple instances - -If you are running multiple instances, each on its own machine, run Memgraph as -you usually would. - -If you are exploring replication and running multiple instances on one machine, -you need expose different ports for each instance. - -The MAIN instance: - -``` -docker run -p 7687:7687 memgraph/memgraph-mage --data-recovery-on-startup=true -``` - -REPLICA instance 1: - -``` -docker run -p 7688:7687 memgraph/memgraph-mage --data-recovery-on-startup=true -``` - -REPLICA instance 2: - -``` -docker run -p 7689:7687 memgraph/memgraph-mage --data-recovery-on-startup=true -``` - -You can connect to each instance using the Memgraph Lab desktop application, or any -other external application by changing the port: - -- the MAIN instance - `localhost:7687` -- REPLICA instance 1 - `localhost:7688` -- REPLICA instance 2 - `localhost:7689` - -If you need to define volumes, each volume needs to be called differently. - -### Demote an instance to a REPLICA role - -Run the following query in both REPLICA instances to demote them to the -REPLICA role: - -``` -SET REPLICATION ROLE TO REPLICA WITH PORT 10000; -``` - -If you set the port of each REPLICA instance to `10000`, it will be easier to -register replicas later on because the query for registering replicas uses port -`10000` as the default one. - -Otherwise, you can use any unassigned port between 1000 and 10000. - -### Register REPLICA instances - -To register a REPLICA instance, you need to find out the IP address of each -instance. - -The IP addresses will probably be: - -- the MAIN instance - `172.17.0.2` -- REPLICA instance 1 - `172.17.0.3` -- REPLICA instance 2 - `172.17.0.4` - -If they are not, please change the IP addresses in the following queries to -match the [IP addresses on your cluster](/getting-started/install-memgraph/docker#issues-with-the-ip-address). - -Then, run the following queries from the MAIN instance to register REPLICA -instances: - -1. REPLICA instance 1 at `172.17.0.3` - - ``` - REGISTER REPLICA REP1 SYNC TO "172.17.0.3"; - ``` - - REPLICA instance 1 is called REP1, its replication mode is SYNC, and it is - located at IP address `172.17.0.3.` with port `10000`. - - Once the MAIN instance commits a transaction, it will communicate the changes - to all REPLICA instances running in SYNC mode and wait until it receives a response that the changes have been applied to the REPLICAs or that a timeout has been reached. - - If you used any port other than `10000` while demoting a REPLICA instance, - you will need to specify it like this: "172.17.0.3:5000" - -2. REPLICA instance 2 at `172.17.0.4` - - ``` - REGISTER REPLICA REP2 ASYNC TO "172.17.0.4"; - ``` - - REPLICA instance 2 is called REP2, its replication mode is ASYNC, and it is - located at IP address `172.17.0.4.` with port `10000`. - - When the REPLICA instance is running in ASYNC mode, the MAIN instance will - commit a transaction without receiving confirmation from REPLICA instances - that they have received the same transaction. ASYNC mode ensures system - availability and partition tolerance. - - If you used any port other than `10000` while demoting a REPLICA instance, - you will need to specify it like this: "172.17.0.4:5000" - -### Check info about registered REPLICA instances - -Check REPLICA instances by running the following query from the MAIN -instance: - -``` -SHOW REPLICAS; -``` - -The result has information regarding each individual replica: -1. replica's name -2. address -3. type (sync/async) -4. system information -5. multi-tenant information (for each database, we provide the current timestamp, how many tick is the replica's version behind and the current status) - -## Underlying implementation - -Uninterrupted data and operational availability in production systems are -critical and can be achieved in many ways. In Memgraph we opted for replication. - -In distributed systems theory the CAP theorem, also named Brewer's theorem, -states that any distributed system can simultaneously guarantee two out of the -three properties: - -1. **Consistency** (C) - every node has the same view of data at a given point in - time -2. **Availability** (A) - all clients can find a replica of the data, even in the - case of a partial node failure -3. **Partition tolerance** (P) - the system continues to work as expected despite a - partial network failure - -![](/pages/clustering/replication/memgraph-replication-CAP-theorem.png) - -Most of the Memgraph use cases do not benefit from well-known algorithms that -strive to achieve all three CAP properties, such as Raft, because due to their -complexity, they produce performance issues. Memgraph use-cases are based on -running analytical graph workloads on real-time data, demanding a simpler -concept such as **replication**. - -Replication consists of replicating data from one storage to one or several -other storages. The downside of its simplicity is that only two out of three CAP -properties can be achieved. - -### Replication implementation in Memgraph - -To enable replication, there must be at least two instances of Memgraph in a -cluster. Each instance has one of two roles: MAIN or REPLICA. The MAIN instance -accepts read and write queries to the database and REPLICA instances accept only -read queries. - -The changes or state of the MAIN instance are replicated to the REPLICA -instances in a SYNC, STRICT_SYNC or ASYNC mode. The STRICT_SYNC mode ensures consistency and -partition tolerance (CP), but not availability for writes. The ASYNC mode -ensures system availability and partition tolerance (AP), while data can only be -eventually consistent. The SYNC mode is something in between because it waits -for writes to be accepted on replicas but MAIN can still commit even in situations -when one of REPLICAs is down. - -By using the timestamp, the MAIN instance knows the current state of the -REPLICA. If the REPLICA is not synchronized with the MAIN instance, the MAIN -instance sends the correct data for synchronization as WAL files. - -If the REPLICA is so far behind the MAIN instance that the synchronization using -WAL files is impossible, Memgraph will use snapshots. - -### Replication modes - - - -From version 2.4 it is no longer possible to specify a timeout when registering -a SYNC replica. To mimic this behavior in higher releases, please use ASYNC -replication instead. - - - -Replication mode defines the terms by which the MAIN instance can commit the -changes to the database, thus modifying the system to prioritize either -consistency or availability. There are two possible replication modes -implemented in Memgraph replication: - -- SYNC -- ASYNC - -![](/pages/clustering/replication/memgraph-replication-async-sync.png) - -When a REPLICA instance is registered and added to the cluster, it will start -replicating in ASYNC mode. That will allow it to catch up to the current state -of the MAIN instance. When the REPLICA instance synchronizes with the MAIN -instance, the replication mode will change according to the mode defined during -registration. - -#### SYNC replication mode - -SYNC mode is the most straightforward replication mode in which the main storage -thread waits for the response and cannot continue until the response is -received or a timeout is reached. - -The following diagrams express the behavior of the MAIN instance in cases when -SYNC REPLICA doesn't answer within the expected timeout. - -**SYNC REPLICA going down when creating index, uniqueness constraint or existence constraint** - -![](/pages/clustering/replication/workflow_diagram_data_definition_creation.drawio.png) - -**SYNC REPLICA going down when dropping index, uniqueness constraint or existence constraint** - -![](/pages/clustering/replication/workflow_diagram_data_definition_dropping.drawio.png) - -**SYNC REPLICA going down adding/updating/deleting data** - -![](/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png) - - -#### STRICT_SYNC replication mode - -The STRICT_SYNC replication mode behaves very similarly to a -SYNC mode except that MAIN won't commit a transaction locally in a situation in -which one of STRICT_SYNC replicas is down. To achieve that, all instances run -together a two-commit protocol which allows you such a synchronization. This -reduces the throughout but such a mode is super useful in a high-availability -scenario in which a failover is the most operation to support. Such a mode then -allows you a failover without the fear of experiencing a data loss. - -#### ASYN replication mode - -In the ASYNC replication mode, the MAIN instance will commit a transaction -without receiving confirmation from REPLICA instances that they have received -the same transaction. This means that the MAIN instance does not wait for the -response from the REPLICA instances in the main thread but in some other thread. - -A new thread can be created every time a transaction needs to be replicated to -the REPLICA instance, but because transactions are committed often and use a lot -of resources, each REPLICA instance has one permanent thread connecting it with -the MAIN instance. Using this background thread, the MAIN instance pushes -replication tasks to the REPLICA instance, creates a custom thread pool pattern, -and receives confirmations of successful replication from the REPLICATION -instance. - -![](/pages/clustering/replication/memgraph-replication-async.png) - -ASYNC mode ensures system availability and partition tolerance. - - -### Synchronizing instances - -By comparing timestamps, the MAIN instance knows when a REPLICA instance is not -synchronized and is missing some earlier transactions. The REPLICA instance is -then set into a RECOVERY state, where it remains until it is fully synchronized -with the MAIN instance. - -The missing data changes can be sent as snapshots or WAL files. Snapshot files -represent an image of the current state of the database and are much larger than -the WAL files, which only contain the changes, deltas. Because of the difference -in file size, Memgraph favors the WAL files. - -While the REPLICA instance is in the RECOVERY state, the MAIN instance -calculates the optimal synchronization path based on the REPLICA instance's -timestamp and the current state of the durability files while keeping the -overall size of the files necessary for synchronization to a minimum. - -![](/pages/clustering/replication/memgraph-replication-sync-process.png) - -Imagine there were 5 changes made to the database. Each change is saved in a WAL -file, so there are 5 WAL files, and the snapshot was created after 2 changes. -The REPLICA instance can be synchronized using a snapshot and the 3 latest WAL -files or using 5 WAL files. Both options would correctly synchronize the -instances, but 5 WAL files are much smaller. - -The durability files are constantly being created, deleted, and updated. Also, -each replica could need a different set of files to sync. There are several ways -to ensure that the necessary files persist and that instances can read the WAL -files currently being updated without affecting the performance of the rest of -the database. - -#### Locking durability files - -Durability files are also used for recovery and are periodically deleted to -eliminate redundant data. The problem is that they can be deleted while they are -being used to synchronize a REPLICA with the MAIN instance. - -To delay the file deletion, Memgraph uses a file retainer that consists of -multiple lockers. Threads can store and lock the files they found while -searching for the optimal recovery path in the lockers, thus ensuring the files -will still exist once they are sent to the REPLICA instance as a part of the -synchronization process. If another part of the system sends a deletion -request for a certain file, the file retainer first checks if that file is -locked in a locker. If it is not, it is deleted immediately. If the file is -locked, the file retainer adds the file to the deletion queue. The file retainer -will periodically clean the queue by deleting the files that are no longer -locked inside the locker. - -#### Writing and reading files simultaneously - -Memgraph internal file buffer is used when writing deltas to WAL files, and -mid-writing, the content of one WAL file can be divided across two locations. If -at that point that WAL file is used to synchronize the REPLICA instance, once -the data is being read from the internal buffer, the buffer can be flushed, and -the REPLICA could receive an invalid WAL file because it is missing a chunk of -data. It could also happen that the WAL file is sent before all the transactions -are written to the internal buffer. - -To avoid these issues, flushing of that internal buffer is disabled while the -current WAL is sent to a REPLICA instance. To get all the data necessary for the -synchronization, the replication thread reads the content directly from the WAL -file, then reads how many bytes are written in the buffer and copies the data to -another location. Then the flushing is enabled again, and the transaction is -replicated using the copied buffer. Because the access to the internal buffer -was not blocked, new data can be written. The content of the buffer (including -any new data) is then written in a new WAL file that will be sent in the next -synchronization process. - -![](/pages/clustering/replication/memgraph-replication-buffer.png) - -#### Fixing timestamp consistency - -Timestamps are used to compare the state of the REPLICA instance in comparison -to the MAIN instance. - -At first, we used the current timestamp without increasing its value for global -operations, like creating an index or creating a constraint. By using a single -timestamp, it was impossible to know which operations the REPLICA had applied -because sequential global operations had the same timestamp. To avoid this -issue, a unique timestamp is assigned to each global operation. - -As replicas allow read queries, each of those queries was assigned with its own -timestamp. Those timestamps caused issues when the replicated write transactions -were assigned an older timestamp. A read transaction would return different data -from the same read query if a transaction was replicated between those two read -transactions which obstructed the snapshot isolation. To avoid this problem, the -timestamp on REPLICA instances isn't increased because the read transactions -don't produce any changes, so no deltas need to be timestamped. - -#### Incompatible instances - -To avoid issues when the durability files of two different database instances -are stored in the same folder, a unique ID is assigned to each storage instance. -The same ID is then assigned to the durability files. Replication uses the -instance ID to validate that the files and the database are compatible. - -A unique ID `epoch_id` is also assigned each time an instance is run as the MAIN -instance in the replication cluster to check if the data is compatible for -replication. The `epoch_id` is necessary when the original MAIN instance fails, -a REPLICA instance becomes a new MAIN, and after some time, the original MAIN -instance is brought back online. If no transactions were run on the original -MAIN instance, the difference in timestamps will indicate that it is behind the -new MAIN, and it would be impossible to set the original MAIN-REPLICA -relationship. But if the transactions were run on the original MAIN after it was -brought back online, the timestamp would be of no help, but the `epoch_id` would -indicate incomparability, thus preventing the original MAIN from reclaiming its -original role. - -![](/pages/clustering/replication/memgraph-replication-ids.png) diff --git a/pages/clustering/replication/_meta.ts b/pages/clustering/replication/_meta.ts new file mode 100644 index 000000000..3c251fb7c --- /dev/null +++ b/pages/clustering/replication/_meta.ts @@ -0,0 +1,7 @@ +export default { + "setup-replication-cluster-docker": "Setup replication cluster with Docker", + "setup-replication-cluster-k8s": "Setup replication cluster with K8s", + "best-practices": "Best practices", + "replication-commands-reference": "Reference commands", + "system-replication": "System replication" +} diff --git a/pages/clustering/replication/best-practices.mdx b/pages/clustering/replication/best-practices.mdx new file mode 100644 index 000000000..df97fab5d --- /dev/null +++ b/pages/clustering/replication/best-practices.mdx @@ -0,0 +1,66 @@ +--- +title: Best practices when setting up replication +description: Various things for database administrators to bear in mind when deploying replication with Memgraph. +--- + +import { Callout } from 'nextra/components' + +# Best practices when setting up replication + + + +This guide is for **Memgraph Community** users who want to set up data replication across multiple instances. +If you have a **Memgraph Enterprise** license, we recommend using the [high availability features](/clustering/high-availability) instead, which provide automatic failover, +load balancing, and comprehensive cluster management capabilities. + + + +## Which storage mode to use? + +Data replication currently **works only in the in-memory transactional [storage +mode](/fundamentals/storage-memory-usage)**. + +If you're using in-memory analytical storage mode for the fast import: +1. import your data +2. switch to in-memory transactional storage mode +3. then and only then set up replication + +## Hardware requirements +For replication, ensure all machines (MAIN and REPLICA instances) have exactly the same amount of +RAM and the same CPU. This uniformity is crucial for consistent performance and reliability. + + +## Which command line flags should I use? + +#### Data recovery on startup + +By default, Memgraph sets the data recovery on startup to true + +```bash +--data_recovery_on_startup=true +``` +The flag controls whether Memgraph will recover the persisted data during startup. It's necessary +to keep this value to true so instances which have temporarily shut down can recover their data when +they get back up. + +#### Restoring replication state on startup +Instances need to remember their role and configuration details in a replication +cluster upon restart, and that is by default enforced with the flag: + +```bash +--replication-restore-state-on-startup=true +``` +The flag should remain `true` throughout the instances' lifetime for replication to work correctly. +If the flag is set to `false`, MAIN can't communicate with instance, because each +REPLICA has a UUID of MAIN which can communicate with it, and it is set up only +on instance registration. In case the flag is set to `false`, the way to go +forward is first to unregister the instance on MAIN and register it again. + +#### Storage WAL file flush +Users are advised to use the same value for configuration flag +```bash +--storage-wal-file-flush-every-n-txn +``` +on MAIN and SYNC REPLICAs. Otherwise, the situation could occur in which there is a data which is +fsynced on REPLICA and not on MAIN. In the case MAIN crashes, this could leave to conflicts in system +that would need to be manually resolved by users. diff --git a/pages/clustering/replication/replication-commands-reference.mdx b/pages/clustering/replication/replication-commands-reference.mdx new file mode 100644 index 000000000..8184d8fc3 --- /dev/null +++ b/pages/clustering/replication/replication-commands-reference.mdx @@ -0,0 +1,272 @@ +--- +title: Replication commands reference +description: Complete reference guide for all replication commands in Memgraph Community Edition, including role management, replica registration, and cluster monitoring. +--- + +import { Callout } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + +# Replication commands reference + +This page provides a comprehensive reference for all commands available in Memgraph Community +Edition replication. + + + +This reference is for **Memgraph Community** users. If you have a **Memgraph Enterprise** +license, we recommend using the [high availability features](/clustering/high-availability) +instead, which provide automatic failover, load balancing, and comprehensive cluster management +capabilities. + + + +## Role management commands + +### SET REPLICATION ROLE TO REPLICA + +Demotes an instance to the REPLICA role and sets the replication port. + +```cypher +SET REPLICATION ROLE TO REPLICA WITH PORT ; +``` + +**Parameters:** +- `port_number` (integer): Port number for replication communication (1000-10000) + +**Behavior:** +- Demotes the current instance from MAIN to REPLICA +- Sets the replication port for communication with the MAIN instance +- REPLICA instances can only accept read queries +- Default port 10000 is recommended for easier registration (used implicitly in other commands) + +**Example:** +```cypher +SET REPLICATION ROLE TO REPLICA WITH PORT 10000; +``` + +**When to use:** +Use this as a first command on the instances you have chosen to be replicas. + +### SET REPLICATION ROLE TO MAIN + +Promotes a REPLICA instance to become the MAIN instance. + +```cypher +SET REPLICATION ROLE TO MAIN; +``` + +**Behavior:** +- Promotes the current REPLICA instance to MAIN +- If the instance is already MAIN, command will make an exception +- Only one MAIN instance should exist in a replication cluster (pay close attention when managing this) +- If the original MAIN is still alive, conflicts may occur +- Requires manual conflict resolution if multiple MAINs exist + +**When to use:** +Memgraph when being run first time is always thinking it's main, so there's no real need to run this query at the start. +Only time you would need this query is to perform manual leader election. + +### SHOW REPLICATION ROLE + +Displays the current replication role of the instance. + +```cypher +SHOW REPLICATION ROLE; +``` + +**Returns:** +- Current replication role: "main" or "replica" + +**Example output:** +```nocopy ++------------------+ +| replication role | ++------------------+ +| "replica" | ++------------------+ +``` + +**When to use:** +Since there is no out of the box routing mechanism in Memgraph Community, you can use this command to determine which instance is the MAIN instance. +It should give you enough information to decide on which instance you can perform writes or reads. + +## Replica registration commands + +### REGISTER REPLICA (SYNC) + +Registers a REPLICA instance with synchronous replication mode. + +```cypher +REGISTER REPLICA name SYNC TO ; +``` + +**Parameters:** +- `name` (string): Unique name for the replica +- `socket_address` (string): Network address in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"` or `"IP_ADDRESS|DNS_NAME"` (default port `10000`) + +**Behavior:** +- MAIN will register a REPLICA instance under SYNC replication mode and sync its own data with the REPLICA + +**Implications:** +- MAIN waits for confirmation from SYNC replicas before committing transactions +- if SYNC replica is down, MAIN can still commit and move on (unlike STRICT_SYNC), + while the REPLICAs are expected to recover and catch-up eventually +- ensures data consistency, but with slower write performance +- there is a minimal chance for data loss, in which case manual intervention is needed to recover the data + +**Example:** +```cypher +REGISTER REPLICA REP1 SYNC TO "172.17.0.3:10000"; +``` + +### REGISTER REPLICA (ASYNC) + +Registers a REPLICA instance with asynchronous replication mode. + +```cypher +REGISTER REPLICA name ASYNC TO ; +``` + +**Parameters:** +- `name` (string): Unique name for the replica +- `socket_address` (string): Network address in format "IP_ADDRESS|DNS_NAME:PORT_NUMBER" or "IP_ADDRESS|DNS_NAME" (default port 10000) + +**Behavior:** +- MAIN will register a REPLICA instance under ASYNC replication mode and sync its own data with the REPLICA + +**Implications:** +- MAIN commits transactions without waiting for replica confirmation, as data is replicated using a background thread +- ensures high availability and partition tolerance +- data is eventually consistent +- best performance but potential data loss on failover + +**Example:** +```cypher +REGISTER REPLICA REP2 ASYNC TO "172.17.0.4"; +``` + +### REGISTER REPLICA (STRICT_SYNC) + +Registers a REPLICA instance with strict synchronous replication mode. + +```cypher +REGISTER REPLICA name STRICT_SYNC TO ; +``` + +**Parameters:** +- `name` (string): Unique name for the replica +- `socket_address` (string): Network address in format "IP_ADDRESS|DNS_NAME:PORT_NUMBER" or "IP_ADDRESS|DNS_NAME" (default port 10000) + +**Behavior:** +- MAIN will register a REPLICA instance under STRICT_SYNC replication mode and sync its own data with the REPLICA + +**Implications:** +- uses two-phase commit protocol (2PC) +- MAIN cannot commit if STRICT_SYNC replica is down +- ensures no data loss but reduces throughput because of 2PC +- best for high-availability scenarios requiring zero data loss + +**Example:** +```cypher +REGISTER REPLICA REP3 STRICT_SYNC TO "172.17.0.5:10000"; +``` + +### DROP REPLICA + +Removes a REPLICA instance from the replication cluster. + +```cypher +DROP REPLICA ; +``` + +**Parameters:** +- `name` (string): Name of the replica to remove + +**Behavior:** +- unregisters the replica from the MAIN instance +- stops replication to the specified replica +- replica instance continues running as REPLICA but is no longer part of the cluster + +**Example:** +```cypher +DROP REPLICA REP1; +``` + +**When to use:** +If all else fails, and the REPLICA can not recover, you can always drop and re-register the REPLICA to start fresh. We advise `DROP REPLICA` +followed by `REGISTER REPLICA` after which the recovery process should start, and the REPLICA should again catch up with the MAIN. + +## Monitoring commands + +### SHOW REPLICAS + +Lists all registered REPLICA instances and their details. + +```cypher +SHOW REPLICAS; +``` + +**Returns:** +- replica name +- network address of the REPLICA + port of the replication server +- replication mode (SYNC/ASYNC/STRICT_SYNC) +- system information +- tenant information (lag, status, timestamp) + +**Example output:** +```nocopy ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| name | socket_address | sync_mode | system_info | data_info | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| "REP1" | "172.17.0.3:10000" | "sync" | Null | {memgraph: {behind: 0, status: "ready", ts: 0}} | +| "REP2" | "172.17.0.4:10000" | "async" | Null | {memgraph: {behind: 0, status: "ready", ts: 0}} | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +``` + +## Socket address formats + +### IP address format + +```cypher +"IP_ADDRESS|DNS_NAME:PORT_NUMBER" +``` + +**Example:** +```cypher +"172.17.0.4:10050" +``` + +### IP address with default port + +```cypher +"IP_ADDRESS" +``` + +**Example:** +```cypher +"172.17.0.5" +``` + +### DNS name format + +```cypher +"DNS_NAME:PORT_NUMBER" +``` + +**Example:** +```cypher +"memgraph-replica.memgraph.net:10050" +``` + +### DNS name with default port + +```cypher +"DNS_NAME" +``` + +**Example:** +```cypher +"memgraph-replica.memgraph.net" +``` + + diff --git a/pages/clustering/replication/setup-replication-cluster-docker.mdx b/pages/clustering/replication/setup-replication-cluster-docker.mdx new file mode 100644 index 000000000..87c83effc --- /dev/null +++ b/pages/clustering/replication/setup-replication-cluster-docker.mdx @@ -0,0 +1,226 @@ +--- +title: Setup replication cluster with Docker +description: See how one can setup a replication cluster with Docker inside the Memgraph Community Edition. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' + +# Setup replication cluster with Docker (Community) + + + +This guide is for **Memgraph Community** users who want to set up data replication across multiple instances. +If you have a **Memgraph Enterprise** license, we recommend using the [high availability features](/clustering/high-availability) instead, which provide automatic failover, +load balancing, and comprehensive cluster management capabilities. + + + +This example demonstrates how to create a simple cluster of nodes running +Memgraph Community instances, and set up replication using various replication modes. + +### Cluster topology + +The cluster will consist of three nodes, one MAIN instance and two REPLICA +instances. In order to showcase the creation of REPLICA instances with different +replication modes, we will create: + +- The MAIN instance - contains the original data that will be replicated to + REPLICA instances +- REPLICA instance 1 - replication in the SYNC mode +- REPLICA instance 2 - replication in the ASYNC mode + + + +The example is made on the local server, which poses a single point of failure if the server goes down. In production, +it is best advised to deploy one Memgraph instance per server, to ensure robustness. + + + + + +### Run multiple instances + +This examples sets up replication on a single instance, so every Bolt port for receiving queries will need to be +distinct on the host. + +The MAIN instance: + +``` +docker run -p 7687:7687 memgraph/memgraph-mage --also-log-to-stderr=true +``` + +REPLICA instance 1: + +``` +docker run -p 7688:7687 memgraph/memgraph-mage --also-log-to-stderr=true +``` + +REPLICA instance 2: + +``` +docker run -p 7689:7687 memgraph/memgraph-mage --also-log-to-stderr=true +``` + +Memgraph by default [sets all the required flags](/clustering/replication/best-practices#which-command-line-flags-should-i-use) +start replication without changing any configuration. + +You can connect to each instance using the Memgraph Lab, mgconsole, or a database driver, by changing the port: + +- MAIN instance - `localhost:7687` +- REPLICA instance 1 - `localhost:7688` +- REPLICA instance 2 - `localhost:7689` + +If you need to define volumes, each volume needs to be called differently. + +### Demote an instance to a REPLICA role + +Run the following query in both REPLICA instances to demote them to the +REPLICA role: + +``` +SET REPLICATION ROLE TO REPLICA WITH PORT 10000; +``` + +This command does 2 things: +- the instance is now aware that it is a REPLICA instance, and is no longer allowed to execute write queries +- a replication server is started at port 10000, which receives data for the REPLICA + +The port 10000 is the default one in some of the replication commands, so the best practice is to use exactly +that port for setting up the replication server. + +Otherwise, you can use any unassigned port between 1000 and 10000. + +### Register REPLICA instances + +To register a REPLICA instance, you need to find out the IP address of each +instance. The container's IP address can be read by using the following command: + +```bash +docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' +``` + +The IP addresses will probably be: + +- MAIN instance - `172.17.0.2` +- REPLICA instance 1 - `172.17.0.3` +- REPLICA instance 2 - `172.17.0.4` + +If they are not, please change the IP addresses in the following queries to +match the [IP addresses on your cluster](/getting-started/install-memgraph/docker#issues-with-the-ip-address). + +Then, run the following queries from the MAIN instance to register REPLICA +instances: + +1. REPLICA instance 1 at `172.17.0.3` + + ``` + REGISTER REPLICA REP1 SYNC TO "172.17.0.3"; + ``` + + The command can be interpreted as following: + - REPLICA instance 1 is called REP1 + - REP1 is registered using SYNC replication mode + - REP1 is located at the IP address `172.17.0.3.` + - REP1 has the replication server port `10000` open (it is the default one) + + Once the MAIN instance commits a transaction, it will communicate the changes + to all REPLICA instances running in SYNC mode and wait until it receives a response that the changes have been applied to the REPLICAs or that a timeout has been reached. + + If you used any port other than `10000` while demoting a REPLICA instance, + you will need to specify it like this: "172.17.0.3:5000" + +2. REPLICA instance 2 at `172.17.0.4` + + ``` + REGISTER REPLICA REP2 ASYNC TO "172.17.0.4"; + ``` + + REPLICA instance 2 is called REP2, its replication mode is ASYNC, and it is + located at IP address `172.17.0.4.` with port `10000`. + + When the REPLICA instance is running in ASYNC mode, the MAIN instance will + commit a transaction without receiving confirmation from REPLICA instances + that they have received the same transaction. ASYNC mode ensures system + availability and partition tolerance. + + If you used any port other than `10000` while demoting a REPLICA instance (e.g. 5000), + you will need to specify it like this: "172.17.0.4:5000" + +### Check info about registered REPLICA instances + +Check REPLICA instances by running the following query from the MAIN +instance: + +``` +SHOW REPLICAS; +``` + +```nocopy ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| name | socket_address | sync_mode | system_info | data_info | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| "REP1" | "172.17.0.3:10000" | "sync" | Null | {memgraph: {behind: 0, status: "ready", ts: 0}} | +| "REP2" | "172.17.0.4:10000" | "async" | Null | {memgraph: {behind: 0, status: "ready", ts: 0}} | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +``` + +The result has information regarding each individual replica: +1. replica's name +2. IP address where the REPLICA is reachable and the port where its replication server is open +3. replication mode (sync/asyncs/trict_sync) +4. system information +5. tenant information (for each database, we provide the current timestamp, how many tick is the replica's version behind and the current status) + +### Create a node on MAIN + +On the MAIN instance, execute a write query + +```cypher +CREATE (:Node); +``` + +### Observe the replicated data + +By showing replicas, we can see that the timestamp data info for the database `memgraph` changed. +Replicas are not behind (`behind` is 0), and they're in a `ready` state. This means data has been +successfully replicated. + +``` +SHOW REPLICAS; +``` + +```nocopy ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| name | socket_address | sync_mode | system_info | data_info | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +| "REP1" | "172.17.0.3:10000" | "sync" | Null | {memgraph: {behind: 0, status: "ready", ts: 2}} | +| "REP2" | "172.17.0.4:10000" | "async" | Null | {memgraph: {behind: 0, status: "ready", ts: 2}} | ++--------+--------------------+-----------+-------------+-------------------------------------------------+ +``` + +If we now log into the REPLICA and execute: + +```cypher +MATCH (n) RETURN n; +``` + +We get the replicated data: + + +```nocopy ++---------+ +| n | ++---------+ +| (:Node) | ++---------+ +``` + +And that's it! You have successfully executed your first query on a replicated Memgraph server! + + +### Next steps + +We suggest you check our [supported replication queries in the +Memgraph community version](/clustering/replication/replication-commands-reference), +so that you can become an expert in managing a replicated Memgraph cluster. \ No newline at end of file diff --git a/pages/clustering/replication/setup-replication-cluster-k8s.mdx b/pages/clustering/replication/setup-replication-cluster-k8s.mdx new file mode 100644 index 000000000..5c75fab6b --- /dev/null +++ b/pages/clustering/replication/setup-replication-cluster-k8s.mdx @@ -0,0 +1,27 @@ +--- +title: Setup replication cluster with K8s +description: See how one can setup a replication cluster with K8s inside the Memgraph Community Edition. +--- + +import { Callout } from 'nextra/components' + +# Setup replication cluster with Kubernetes (Community) + + + +This guide is for **Memgraph Community** users who want to set up data replication across multiple instances. +If you have a **Memgraph Enterprise** license, we recommend using the [high availability features](/clustering/high-availability) instead, which provide automatic failover, +load balancing, and comprehensive cluster management capabilities. + + + + + +Memgraph does not offer Helm charts compatible with Memgraph replication in Community Edition. +Memgraph currently only supports Helm charts with the [high availability +Enterprise edition](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-high-availability). +If you want to set up replication with Community Memgraph using Helm charts, you are encouraged to create +the setup on your own, by [reusing the Docker replication guide](/clustering/replication/setup-replication-cluster-docker) +for setting up the cluster. + + diff --git a/pages/clustering/replication/system-replication.mdx b/pages/clustering/replication/system-replication.mdx index d96fd47e8..862d2140b 100644 --- a/pages/clustering/replication/system-replication.mdx +++ b/pages/clustering/replication/system-replication.mdx @@ -16,24 +16,33 @@ When using system replication features, the user can now have a more complete duplicate of MAIN. MAIN will automatically replicate any database creation/drop and any changes to the auth setup. -## Replication implementation basics +## Audit logs -Please refer to [Replication](/clustering/replication) for the basics of replication. +Audit logs are currently not replicated inside Memgraph. -## Auth data replication +## Auth data replication (Enterprise) -All authentication/authorization data are now replicated. This includes users, -roles, and all of the permissions associated with them. +If you are using a Memgraph Enterprise license, all authentication/authorization +data, including users, roles, and associated permissions, will be replicated. -Auth modules are not replicated at this time and must be set up by the admin. +**Memgraph Community does not replicate users and roles.** It only ensures data replication +(nodes, relationships, indices, constraints, and other graph constructs). -## Multi-tenant data replication +## Auth modules replication -Multi-tenant commands are now replicated as any other data command. -Database manipulation is allowed only on MAIN. However, REPLICAs have the -ability to use databases and read data contained in them. +Authentication modules are not replicated and must be configured manually by the +administrator. + +## Multi-tenant data replication (Enterprise) + +When you are using a Memgraph Enterprise license, multi-tenant commands are +replicated as any other data command. + +Database manipulation is allowed only on MAIN. +REPLICA instances have the ability to use databases and read data +contained in them. When dropping a database used on a REPLICA, the REPLICA will receive the command -and will partially drop the database. It will hide it and not allow any new -usage of the database but will wait for every client to release the database -before deleting it entirely. +and will partially drop the database. It will hide the database and prevent any +new usage. Once all clients have released the database, it will be deleted +entirely. \ No newline at end of file diff --git a/pages/deployment/environments/aws.mdx b/pages/deployment/environments/aws.mdx index e52ed9e29..d4d931491 100644 --- a/pages/deployment/environments/aws.mdx +++ b/pages/deployment/environments/aws.mdx @@ -192,6 +192,21 @@ Depending on what you are using, you can follow the [Linux](./linux.mdx) or [Docker](./docker.mdx) deployment guide for more information on how to manage the Memgraph deployment. +## Deploying Memgraph with High Availability + +For production environments requiring high availability, we recommend running Memgraph under Kubernetes, as that is currently the most widely used method of HA deployment. +Other methods of deployment include connecting your HA cluster with Memgraph built from source, as well as using plain Docker images. + +### High Availability on AWS EKS + +The recommended approach for deploying Memgraph with high availability on AWS is to use Amazon Elastic Kubernetes Service (EKS) with our Helm charts. This provides: + +For detailed instructions on deploying Memgraph high availability on AWS EKS, follow our +[Helm charts guide for AWS](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-high-availability/aws). + +To understand how Memgraph high availability works, including cluster setup, replication modes, and failover procedures, refer to our comprehensive +[high availability documentation](/clustering/high-availability). + ## Where to next? From 1f7185643489a8e75030754f98db0b2ba8c70c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Wed, 22 Oct 2025 15:09:01 +0200 Subject: [PATCH 04/13] Update replication + new images --- pages/clustering.mdx | 4 +- .../concepts/how-replication-works.mdx | 161 ++++++++--- pages/clustering/faq.mdx | 11 +- pages/clustering/replication.mdx | 254 +----------------- .../clustering/replication/best-practices.mdx | 91 ++++++- .../setup-replication-cluster-k8s.mdx | 1 + .../memgraph-replication-async-sync.png | Bin 48089 -> 0 bytes .../replication/replication-modes.png | Bin 0 -> 30116 bytes ...iagram_data_definition_creation.drawio.png | Bin 27280 -> 0 bytes ...iagram_data_definition_dropping.drawio.png | Bin 25554 -> 0 bytes ...kflow_diagram_data_manipulation.drawio.png | Bin 40327 -> 0 bytes 11 files changed, 237 insertions(+), 285 deletions(-) delete mode 100644 public/pages/clustering/replication/memgraph-replication-async-sync.png create mode 100644 public/pages/clustering/replication/replication-modes.png delete mode 100644 public/pages/clustering/replication/workflow_diagram_data_definition_creation.drawio.png delete mode 100644 public/pages/clustering/replication/workflow_diagram_data_definition_dropping.drawio.png delete mode 100644 public/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png diff --git a/pages/clustering.mdx b/pages/clustering.mdx index 8efdcfa41..07335b0ba 100644 --- a/pages/clustering.mdx +++ b/pages/clustering.mdx @@ -47,14 +47,14 @@ transactional storage mode](/fundamentals/storage-memory-usage#in-memory-transac Learn about the underlying implementation and theoretical concepts behind Memgraph replication, including CAP theorem, replication modes, and synchronization mechanisms. -## [Replication cluster setup (Community)](/clustering/replication) +## [Replication guide (Community)](/clustering/replication) Learn how to set up a replication cluster with Memgraph. **Replication is included in Memgraph Community**, making it accessible to all users who want to create data replicas across multiple instances. Memgraph Community however does not ensure high availability itself, as **automatic failover is not included**. Community users are encouraged to perform the necessary steps themselves for keeping the replication cluster up and running. -## [High availability cluster setup (Enterprise)](/clustering/high-availability) +## [High availability guide (Enterprise)](/clustering/high-availability) Learn how to setup and manage a high availability cluster with Memgraph. This guide is for users of **Memgraph Enterprise** who want to achieve clustering and 24/7 uptime. diff --git a/pages/clustering/concepts/how-replication-works.mdx b/pages/clustering/concepts/how-replication-works.mdx index 15dab93bf..d550b3734 100644 --- a/pages/clustering/concepts/how-replication-works.mdx +++ b/pages/clustering/concepts/how-replication-works.mdx @@ -46,21 +46,29 @@ read queries. +During the initial startup, all instances are MAIN by default. When creating a replication cluster, +one instance has to be chosen as the MAIN instance. +The rest of the instances have to be **demoted to REPLICA roles**. Replicas receive data by creating an RPC +replication server which is listening on an arbitrary port. + The way MAIN instance replicates data to the REPLICA instances can be carried out in a **SYNC**, **ASYNC**, or **STRICT_SYNC** mode. The replication mode defines the terms by which the MAIN instance can commit the changes to the database, thus modifying the system to prioritize either consistency or availability. -- **STRICT_SYNC mode** - After committing a transaction, the MAIN instance will communicate the -changes to all REPLICA instances and wait until it receives a response or information that a timeout is reached. + +- **STRICT_SYNC mode** - Replication is implemented as a two-phase commit protocol. +After committing a transaction, the MAIN instance will communicate the changes to all REPLICA instances +and wait until it receives a response or information that a timeout is reached. The STRICT_SYNC mode ensures consistency and partition tolerance (CP), but not availability for writes. If the primary database has multiple replicas, the system is highly available for reads. But, when a replica fails, -the MAIN instance can’t process the write due to the nature of synchronous replication. It is implemented as -two-phase commit protocol. +the MAIN instance can’t process the write due to the nature of synchronous replication. + - **SYNC mode** - After committing a transaction, the MAIN instance will communicate the changes to all REPLICA instances and wait until it receives a response or information that a timeout is reached. It is different from STRICT_SYNC mode because it the MAIN can continue committing even in situations when SYNC replica is down. + - **ASYNC mode** - The MAIN instance will commit a transaction without receiving confirmation from REPLICA instances that they have received the same transaction. ASYNC mode ensures system availability and partition tolerance (AP), while data can only be eventually consistent. @@ -83,14 +91,14 @@ implemented in Memgraph replication: - SYNC - ASYNC +- STRICT_SYNC -![](/pages/clustering/replication/memgraph-replication-async-sync.png) +![](/pages/clustering/replication/replication-modes.png) When a REPLICA instance is registered and added to the cluster, it will start replicating to catch up to the current state of the MAIN instance. Initial replication when a REPLICA instance is registered is handled in ASYNC mode by design decision. - When the REPLICA instance synchronizes with the MAIN instance, the replication mode will change according to the mode defined during registration. @@ -99,23 +107,16 @@ registration. SYNC mode is the most straightforward replication mode in which the main storage thread waits for the response and cannot continue until the response is -received or a timeout is reached. +received or a timeout is reached. If the REPLICA fails, MAIN instance will still commit +the data and move forward. This behaviour does not block writes on REPLICA failure, and still +ensures other REPLICAs to receive new data. The following diagrams express the behavior of the MAIN instance in cases when SYNC REPLICA doesn't answer within the expected timeout. -**SYNC REPLICA going down when creating index, uniqueness constraint or existence constraint** - -![](/pages/clustering/replication/workflow_diagram_data_definition_creation.drawio.png) - -**SYNC REPLICA going down when dropping index, uniqueness constraint or existence constraint** - -![](/pages/clustering/replication/workflow_diagram_data_definition_dropping.drawio.png) - -**SYNC REPLICA going down adding/updating/deleting data** - -![](/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png) - +**SYNC replication ensures consistency and partition tolerance (CP).** +However, there is an extremely minimal chance of data loss. For complete consistency without data loss, +Memgraph offers STRICT_SYNC replication mode. #### STRICT_SYNC replication mode @@ -124,10 +125,10 @@ SYNC mode except that MAIN **won't commit a transaction locally in a situation i which one of STRICT_SYNC replicas is down**. To achieve that, all instances run together a *two-phase commit* protocol which allows you such a synchronization. This reduces the throughout but such a mode is super useful in a high-availability -scenario in which a failover is the most operation to support. Such a mode then +scenario in which a failover is the most critical operation to support. Such a mode then allows you a failover **without the fear of experiencing a data loss**. -STRICT_SYNC mode ensures consistency and partition tolerance. +**STRICT_SYNC mode ensures consistency and partition tolerance (CP).** #### ASYNC replication mode @@ -142,21 +143,66 @@ replication tasks to the REPLICA instance, creates a custom thread pool pattern, and receives confirmations of successful replication from the REPLICATION instance. +**ASYNC mode ensures system availability and partition tolerance (AP).** + ![](/pages/clustering/replication/memgraph-replication-async.png) -ASYNC mode ensures system availability and partition tolerance. +### REPLICA state + +There are 5 states in which replica can be at a point in time: +- **READY** - replica is not lagging behind and all the data is replicated +- **REPLICATING** - state the REPLICA is in when it's receiving transaction commits. +If this action succeeds, the replica will again move to READY state. If it fails, it will move to INVALID. +- **INVALID/BEHIND** - replica is behind, and needs to be synced with MAIN +- **RECOVERY** - after MAIN detects that a REPLICA is invalid/behind, the REPLICA state is changed to RECOVERY. +At this point, the transfer of durability files is performed in order for the REPLICA to catch up with MAIN +- **DIVERGED** - this is a state in which REPLICA can be found if you're performing manual failover. Manual conflict +resolution and recovery of the cluster is needed in order for this state to convert to READY. + +Based on RPC heartbeats, MAIN decides in which state the REPLICA is in at a point in time. REPLICA doesn't know by itself +in which state it is in. It doesn't need to know that, as MAIN is the sole initiator of synchronization mechanisms when +performing replication or recovery. + +// state diagram + +### How are instances synchronized? + +To understand how individual instances are keeping the state of the data in sync, we need to +understand the basic durability entities which are replicated from MAIN: +- **Snapshots** - Point-in-time images of the full database state. Snapshots are the largest durability objects + that are replicated +- **WALs (write-ahead logs)** - Append-only durability files that store sequences of committed deltas. + Because WALs are much smaller than snapshots, Memgraph prefers them for recovery when possible. +- **Delta objects** - The smallest atomic updates produced when MAIN commits a transaction + (e.g., create/update/delete of nodes/edges/properties). A single transaction can have multiple deltas that need to be replicated + on commit. If the REPLICA is fully in sync, only Delta objects will be replicated during the commit time. + For more information about delta objects, please refer to the + [in-memory transactional storage mode guides](/fundamentals/storage-memory-usage#in-memory-analytical-storage-mode). + + + +To learn more about durability in Memgraph, check out the [data durability fundamentals](/fundamentals/data-durability). + + + +Each transaction in Memgraph has an auto-incrementing timestamp which acts as a time variable. -### Synchronizing instances +In the ideal scenario, the MAIN will just send the Delta objects to the REPLICA. In that case, REPLICA will +transfer from READY to REPLICATING state, and then come back again to the READY state. Transfer of delta objects +in real-time is the optimal approach, because they're the smallest units to be transferred over the network. +This happy flow ensures the REPLICA is always in-sync with MAIN. -By comparing timestamps, the MAIN instance knows when a REPLICA instance is not -synchronized and is missing some earlier transactions. The REPLICA instance is +There are a variety of scenarios when that happy flow can not be maintained, such as network issues, or failing of +the instance. By comparing timestamps, the MAIN instance knows when a REPLICA instance is not +synchronized and is missing some earlier transactions. **If the REPLICA is behind (INVALID replica state), +it will have a lower timestamp than the MAIN instance.** The REPLICA instance is then set into a RECOVERY state, where it remains until it is fully synchronized with the MAIN instance. **The missing data changes can be sent as snapshots or WAL files, which are the main -data durability files for Memgraph.** Snapshot files represent an image of the current state of -the database and are much larger than the WAL files, which only contain the changes, deltas. -Because of the difference in file size, Memgraph favors the WAL files. +data durability files for Memgraph.** Because of the difference in file size, +Memgraph favors to send the WAL files over, rather than the snapshots. After all the +necessary durability files have been sent over, REPLICA can then move to READY state. While the REPLICA instance is in the RECOVERY state, the MAIN instance calculates the optimal synchronization path based on the REPLICA instance's @@ -171,7 +217,48 @@ The REPLICA instance can be synchronized using a snapshot and the 2 latest WAL files or using 5 WAL files. Both options would correctly synchronize the instances, but 5 WAL files are much smaller. -The durability files are constantly being created, deleted, and updated. Also, +If the RECOVERY did not succeed, the REPLICA again moves back and forth the INVALID and RECOVERY +states. Reason for this can again be network issues, but also data corruption. If you believe the +system is not able to recover at all, please contact our Enterprise support or Discord channel. + +### Replication of multi-tenant data (Enterprise) + + + +Memgraph's multi-tenancy offers management of multiple logically isolated databases. The word *database* here is a synonym +to a *tenant*. Learn more about this in our [multi-tenancy documentation page](/database-management/multi-tenancy). + + + +When running multi-tenancy, there can be multiple durability files sent over the network for +each database. To ensure correct mapping between the MAIN and REPLICA databases, each database has its +own database UUID. When creating a new database on MAIN, the database is also replicated to the REPLICAs, +as well as the identical UUIDs of the databases. This ensures there is a mapping between the set of MAIN +databases and the set of REPLICA databases. + +When sending replication data over the network, durability files are also assigned +the database UUID. It serves as a unique location of which database to apply the durability +files to in the replicas. + + + +Ensure replication / high-availability at the very beginning in order to make sure the correct information is replicated +from MAIN to REPLICA. In this particular case, if you created databases respectively on the standalone +instances, and then connected the cluster, it would not work because UUIDs are generated randomly. +The operation would end up in a mismatch of database UUIDs, and you would not be able to recover the cluster. + + + +### Advanced replication topics + + + +The following section explains highly technical topics, dedicated to those who would +like to know more about technical implementations of replication in Memgraph. + + + +The durability files are constantly being created, deleted, and appended to. Also, each replica could need a different set of files to sync. There are several ways to ensure that the necessary files persist and that instances can read the WAL files currently being updated without affecting the performance of the rest of @@ -235,12 +322,7 @@ transactions which obstructed the snapshot isolation. To avoid this problem, the **timestamp on REPLICA instances isn't increased** because the read transactions don't produce any changes, so no deltas need to be timestamped. -#### Incompatible instances - -To avoid issues when the durability files of two different database instances -are stored in the same folder, a unique ID is assigned to each storage instance. -The same ID is then assigned to the durability files. Replication uses the -instance ID to validate that the files and the database are compatible. +#### Epoch ID as a complement to timestamp ID A unique ID `epoch_id` is also assigned each time an instance is run as the MAIN instance in the replication cluster to check if the data is compatible for @@ -256,4 +338,13 @@ original role. ![](/pages/clustering/replication/memgraph-replication-ids.png) +#### System data replication + +We have outlined in the main section of this guide how graph data replication works. +When we talk about data storage, we strictly mean the graph itself, along with the complementary +performance and correctness data structures, such as nodes, relationships, properties, indices, +constraints, triggers, and streams. +For replication support of non-graph data, such as authentication configurations, multi-tenant data, please refer +to the [system replication reference](/clustering/replication/system-replication). + diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx index 5680b07fd..21d1f3590 100644 --- a/pages/clustering/faq.mdx +++ b/pages/clustering/faq.mdx @@ -9,7 +9,16 @@ import { CommunityLinks } from '/components/social-card/CommunityLinks' ## High availability (general) - +#### Does Memgraph support chaining REPLICA instances? +Memgraph at the moment doesn't support chaining REPLICA instances, that is, a REPLICA +instance cannot be replicated on another REPLICA instance. + +#### Can a REPLICA listen to multiple MAIN instances? +When starting any Memgraph instance, it is assigned a unique UUID of the instance. This is communicated +when a replica is registered, to ensure REPLICA does not receive replication data from another MAIN instance. +A REPLICA stores the UUID of the MAIN instance it listens to. +The instance UUID of each Memgraph is persisted on disk across restarts, so this behaviour is enforced throughout the +cluster lifecycle. ### High availability with Docker diff --git a/pages/clustering/replication.mdx b/pages/clustering/replication.mdx index 519b2c1b3..b36eb3e50 100644 --- a/pages/clustering/replication.mdx +++ b/pages/clustering/replication.mdx @@ -4,6 +4,7 @@ description: Dive into the documentation page for Memgraph and learn how to conf --- import { Callout } from 'nextra/components' +import { CommunityLinks } from '/components/social-card/CommunityLinks' # How to setup replication with Memgraph (Community) @@ -21,251 +22,16 @@ load balancing, and comprehensive cluster management capabilities. -## Data replication implementation basics +## [Setup replication cluster (Docker)](/clustering/replication/setup-replication-cluster-docker) +Learn how to connect a Memgraph replication cluster using Docker images. -In Memgraph, all instances are MAIN upon starting. When creating a replication -cluster, one instance has to be chosen as the MAIN instance. The rest of the -instances have to be demoted to REPLICA roles and have a port defined using a -Cypher query. +## [Setup replication cluster (K8s)](/clustering/replication/setup-replication-cluster-k8s) +Memgraph currently does not support Helm charts for Community edition. -The MAIN instance can accept read and write queries, while the REPLICA instance can only accept -reads. Once an instance has been demoted to a REPLICA instance, it will no longer accept write queries. -In order to start the replication, each REPLICA instance needs to be registered -from the MAIN instance by setting a [replication mode](/clustering/concepts/how-replication-works#replication-modes) -(SYNC, ASYNC or STRICT_SYNC) and specifying the REPLICA instance's socket address. +## [Replication best practices](/clustering/replication/best-practices) +Learn about what things to watch for, when creating a Memgraph replication cluster. -Once the REPLICA instances are registered, data storage of the MAIN instance is -replicated and synchronized using transaction timestamps and durability files -(snapshot files and WALs). When we talk about data storage, we strictly mean the graph -itself, along with the complementary performance and correctness data structures, such as nodes, -relationships, properties, indices, constraints, triggers, and streams. -For replication support of non-graph data, such as authentication configurations, multi-tenant data, please refer -to the [system replication reference](/clustering/replication/system-replication). +## [Replication commands reference guide](/clustering/replication/replication-commands-reference) +Queries at your disposal to manage Memgraph cluster. -By using the timestamp, the MAIN instance knows the current state of the -REPLICA. If the REPLICA is not synchronized with the MAIN instance, the MAIN -instance sends the correct data for synchronization kept as delta objects within WAL -files. Deltas are the smallest possible updates of the database, but they carry -enough information to synchronize the data on a REPLICA. For more information about delta objects, -please refer to the [in-memory transactional storage mode guides](/fundamentals/storage-memory-usage#in-memory-analytical-storage-mode). - -If the REPLICA is so far behind the MAIN instance that the synchronization using -WAL files and deltas within it is impossible, Memgraph will use snapshots to -synchronize the REPLICA to the state of the MAIN instance. - -From Memgraph version 2.15, a REPLICA instance has integrated support to only -listen to one MAIN. This part is introduced to support the high availability but -also reflects on the replication. The mechanism that is used is a unique -identifier that which MAIN instance sends to all REPLICAs when REPLICA is first -registered on a MAIN. A REPLICA stores the UUID of the MAIN instance it listens -to. The MAIN's UUID is also stored on a disk, in case of restart of an instance -to continue listening to the correct MAIN instance. - - - -As of Memgraph v3.5 replication queries (such as `REGISTER REPLICA`, `SHOW -REPLICAS`, `DROP REPLICA`, etc.) target the default "memgraph" database and -require access to it. The recommendation is to use the default "memgraph" -database as an admin/system database and store graphs under other databases. - - - -### Requirements for replication queries - -To execute replication queries, users must have: -1. The `REPLICATION` privilege -2. **AND** access to the default "memgraph" database - -### Impact on multi-tenant environments - -In multi-tenant environments where users might not have access to the "memgraph" -database, replication management operations will fail. This reinforces the -recommendation to treat the "memgraph" database as an administrative/system -database. - -{

Example: Admin user with replication privileges

} - -```cypher --- Create admin role with replication privileges -CREATE ROLE replication_admin; -GRANT REPLICATION TO replication_admin; -GRANT DATABASE memgraph TO replication_admin; - --- Create user with replication admin role -CREATE USER repl_admin IDENTIFIED BY 'admin_password'; -SET ROLE FOR repl_admin TO replication_admin; -``` - -In this setup, `repl_admin` can: -- Execute all replication queries (`REGISTER REPLICA`, `SHOW REPLICAS`, etc.) -- Access the "memgraph" database for administrative operations -- Manage the replication cluster configuration - - -## Running multiple instances - -When running multiple instances, each on its own machine, run Memgraph as you -usually would. - -If you are exploring replication and running multiple instances on one machine, -you can run Memgraph with Docker, but if you are using volumes, they need to be -called differently and each instance needs to be exposed via a different port. - -Check the example of creating [a replication -cluster](/clustering/replication/setup-replication-cluster-docker). - -## Assigning roles - -Each Memgraph instance has the role of the MAIN instance when it is first -started. - -Also, by default, each crashed instance restarts with its previous role (MAIN as -MAIN, REPLICA as REPLICA). To change this behavior, set the -`--replication-restore-state-on-startup` to `false` when first initializing the -instance. In this way, all instances will get restarted as MAIN. - -### Assigning the REPLICA role - -Once you decide what instance will be the MAIN instance, all the other instances -that will serve as REPLICA instances need to be demoted and have the port set -using the following query: - -```plaintext -SET REPLICATION ROLE TO REPLICA WITH PORT ; -``` - -If you set the port of each REPLICA instance to `10000`, it will be easier to -register replicas later on because the query for registering replicas uses a -port 10000 as the default one. - -Otherwise, you can use any unassigned port between 1000 and 10000. - -### Assigning the MAIN role - -The replication cluster should only have one MAIN instance in order to avoid -errors in the replication system. If the original MAIN instance fails, you can -promote a REPLICA instance to be the new MAIN instance by running the following -query: - -```plaintext -SET REPLICATION ROLE TO MAIN; -``` - -If the original instance was still alive when you promoted a new MAIN, you need -to resolve any conflicts and manage replication manually. - -If you demote the new MAIN instance back to the REPLICA role, it will not -retrieve its original function. You need to [drop -it](#dropping-a-replica-instance) from the MAIN and register it again. - -If the crashed MAIN instance goes back online once a new MAIN is already -assigned, it cannot reclaim its previous role. It can be cleaned and demoted to -become a REPLICA instance of the new MAIN instance. - -### Checking the assigned role - -To check the replication role of an instance, run the following query: - -```plaintext -SHOW REPLICATION ROLE; -``` - -## Registering REPLICA instances - -Once all the nodes in the cluster are assigned with appropriate roles, you can -enable replication in the MAIN instance by registering REPLICA instances, -setting a replication mode (SYNC and ASYNC), and specifying the REPLICA -instance's socket address. Memgraph doesn't support chaining REPLICA instances, -that is, a REPLICA instance cannot be replicated on another REPLICA instance. - -If you want to register a REPLICA instance with a SYNC replication mode, run the -following query: - -```plaintext -REGISTER REPLICA name SYNC TO ; -``` - -If you want to register a REPLICA instance with an ASYNC replication mode, run -the following query: - -```plaintext -REGISTER REPLICA name ASYNC TO ; -``` - - -If you want to register a REPLICA instance with an STRICT_SYNC replication mode, -run the following query: - -```plaintext -REGISTER REPLICA name STRICT_SYNC TO ; -``` - -The socket address must be a string value as follows: - -```plaintext -"IP_ADDRESS:PORT_NUMBER" -``` - -where `IP_ADDRESS` is a valid IP address, and `PORT_NUMBER` is a valid port -number, for example: - -```plaintext -"172.17.0.4:10050" -``` - -The default value of the `PORT_NUMBER` is `10000`, so if you set REPLICA roles -using that port, you can define the socket address specifying only the valid IP -address: - -```plaintext -"IP_ADDRESS" -``` - -Example of a `` using only `IP_ADDRESS`: - -```plaintext -"172.17.0.5" -``` - -Also, you can register REPLICA instances using DNS names. In that case, the -socket address must be a string value as follows: - -```plaintext -"DOMAIN_NAME:PORT_NUMBER" -``` - -where `DOMAIN_NAME` is a valid domain name, and `PORT_NUMBER` is a valid port -number, for example: - -```plaintext -"memgraph-replica.memgraph.net:10050" -``` - -If you set REPLICA roles using port `10000`, you can define the socket address -specifying only the valid domain name, for example: - -```plaintext -"memgraph-replica.memgraph.net" -``` - -When a REPLICA instance is registered, it will start replication in ASYNC mode -until it synchronizes to the current state of the database. Upon -synchronization, REPLICA instances will either continue working in the ASYNC, -STRICT_SYNC or SYNC mode. - -### Listing all registered REPLICA instances - -You can check all the registered REPLICA instances and their details by running -the following query: - -```plaintext -SHOW REPLICAS; -``` - -### Dropping a REPLICA instance - -To drop a replica, run the following query: - -```plaintext -DROP REPLICA ; -``` + \ No newline at end of file diff --git a/pages/clustering/replication/best-practices.mdx b/pages/clustering/replication/best-practices.mdx index df97fab5d..04d468f6b 100644 --- a/pages/clustering/replication/best-practices.mdx +++ b/pages/clustering/replication/best-practices.mdx @@ -29,12 +29,24 @@ If you're using in-memory analytical storage mode for the fast import: For replication, ensure all machines (MAIN and REPLICA instances) have exactly the same amount of RAM and the same CPU. This uniformity is crucial for consistent performance and reliability. +## Deployment requirements +When running multiple instances, each on its own machine, run Memgraph as you +usually would. + +If you are exploring replication and running multiple instances on one machine, +you can run Memgraph with Docker, but if you are using volumes, they need to be +called differently and each instance needs to be exposed via a different port. + +Check the example of creating [a replication +cluster](/clustering/replication/setup-replication-cluster-docker). + + ## Which command line flags should I use? #### Data recovery on startup -By default, Memgraph sets the data recovery on startup to true +**By default, Memgraph sets the data recovery on startup to true:** ```bash --data_recovery_on_startup=true @@ -43,9 +55,11 @@ The flag controls whether Memgraph will recover the persisted data during startu to keep this value to true so instances which have temporarily shut down can recover their data when they get back up. +**Advice:** Do nothing since this is enforced by default. + #### Restoring replication state on startup Instances need to remember their role and configuration details in a replication -cluster upon restart, and that is by default enforced with the flag: +cluster upon restart, and that is **by default enforced** with the flag: ```bash --replication-restore-state-on-startup=true @@ -56,11 +70,82 @@ REPLICA has a UUID of MAIN which can communicate with it, and it is set up only on instance registration. In case the flag is set to `false`, the way to go forward is first to unregister the instance on MAIN and register it again. +**Advice:** Do nothing since this is enforced by default. + #### Storage WAL file flush Users are advised to use the same value for configuration flag ```bash --storage-wal-file-flush-every-n-txn ``` on MAIN and SYNC REPLICAs. Otherwise, the situation could occur in which there is a data which is -fsynced on REPLICA and not on MAIN. In the case MAIN crashes, this could leave to conflicts in system +*fsynced* on REPLICA and not on MAIN. In the case MAIN crashes, this could leave to conflicts in system that would need to be manually resolved by users. + +**Advice:** Do nothing since this the value is identical for all instances by default. If you change the value +for the flag, change it for all the respective instances accordingly. + +## Permissions to run replication queries + +As of Memgraph v3.5 replication queries (such as `REGISTER REPLICA`, `SHOW +REPLICAS`, `DROP REPLICA`, etc.) target the default "memgraph" database and +require access to it. The recommendation is to use the default "memgraph" +database as an admin/system database and store graphs under other databases. + +**In Memgraph community, every user is an admin user and there are no roles or privileges, so +users will be able to execute any replication query.** + +### Requirements for replication queries (Enterprise) + +To execute replication queries, users must have: +1. The `REPLICATION` privilege +2. **AND** access to the default "memgraph" database + +**In Memgraph Enterprise edition, the very first created user is an admin user, which will be able to execute +any replication query.** + +{

Example: Admin user with replication privileges

} + +```cypher +-- Create admin role with replication privileges +CREATE ROLE replication_admin; +GRANT REPLICATION TO replication_admin; +GRANT DATABASE memgraph TO replication_admin; + +-- Create user with replication admin role +CREATE USER repl_admin IDENTIFIED BY 'admin_password'; +SET ROLE FOR repl_admin TO replication_admin; +``` + +In this setup, `repl_admin` can: +- Execute all replication queries (`REGISTER REPLICA`, `SHOW REPLICAS`, etc.) +- Access the "memgraph" database for administrative operations +- Manage the replication cluster configuration + +## How to manage replication with Memgraph Community Edition? + +### Manual failover + +**Leader election / automatic failover** is a part of Memgraph Enterprise Edition. For Memgraph +Community edition, users need to perform manual failover routines. + +The replication cluster should only have one MAIN instance in order to avoid +errors in the replication system. If the original MAIN instance fails, you can +promote a REPLICA instance to be the new MAIN instance by running the following +query: + +```plaintext +SET REPLICATION ROLE TO MAIN; +``` + +If the original instance was still alive when you promoted a new MAIN, you need +to resolve any conflicts and manage replication manually. + +If you demote the new MAIN instance back to the REPLICA role, it will not +retrieve its original function. You need to [drop +it](/clustering/replication/replication-commands-reference#drop-replica) from the MAIN and +[register it](/clustering/replication/replication-commands-reference#replica-registration-commands) again. + +If the crashed MAIN instance goes back online once a new MAIN is already +assigned, it cannot reclaim its previous role. It needs to be cleaned and demoted to +become a REPLICA instance of the new MAIN instance. In the worst case, restarting that instance +clean with new fresh storage is needed, in order for the REPLICA registration to pass successfully. diff --git a/pages/clustering/replication/setup-replication-cluster-k8s.mdx b/pages/clustering/replication/setup-replication-cluster-k8s.mdx index 5c75fab6b..c71e1b136 100644 --- a/pages/clustering/replication/setup-replication-cluster-k8s.mdx +++ b/pages/clustering/replication/setup-replication-cluster-k8s.mdx @@ -22,6 +22,7 @@ Memgraph currently only supports Helm charts with the [high availability Enterprise edition](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-high-availability). If you want to set up replication with Community Memgraph using Helm charts, you are encouraged to create the setup on your own, by [reusing the Docker replication guide](/clustering/replication/setup-replication-cluster-docker) +and [Memgraph standalone Helm Charts](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph) for setting up the cluster.
diff --git a/public/pages/clustering/replication/memgraph-replication-async-sync.png b/public/pages/clustering/replication/memgraph-replication-async-sync.png deleted file mode 100644 index cc524e7ce2369d66d52d843cafb1a98ae3018c75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48089 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 TC#W*ai_1tVN)*0&`{jQDDC1(h diff --git a/public/pages/clustering/replication/replication-modes.png b/public/pages/clustering/replication/replication-modes.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c5d2dcf7abeec0217a9a9f32b8ab8a41a0505e GIT binary patch literal 30116 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%0DuyMNzOmgR@lf>cxR4aDOo) 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 diff --git a/public/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png b/public/pages/clustering/replication/workflow_diagram_data_manipulation.drawio.png deleted file mode 100644 index a7c1de5513a1f72f3efc6d85d5d56d99f7601db2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40327 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≥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�q{h$Ww8l^qbK-y5l}H|^g)$D}+Tyt8R$2+_HX;`vVONIwJC0NnA; zdvWOYz=dXd?`Y?<7fMhzST#2jZJh0h<9V@rDP!eKry)lSNs^eOh{ZL7F=Wn6N#F*o zDGATUUZrG#Q3_6IvC>w*Alj43v$j_`i$J|>dh7;8@|>;KVK|Tg^5+mEQ43xkUM1;@nRzt%E(W>f(Z4tc8uCy$CHcHs;)CXhegfVLWTv$|cwvA58KKQSe%6N< zuVC}dBf}4sKPyQu38&qaUR;RwDqS1J62g9P1JAE6uX{m~BcWr*P*~i`lVca^8#g{;y-N4ai(8Ld z55cDZA2%c$P;iWTMv-yMes?j5z;a1WOQRc>PHUC Date: Wed, 29 Oct 2025 16:00:07 +0100 Subject: [PATCH 05/13] Partial how HA works --- pages/clustering.mdx | 29 +- pages/clustering/concepts/_meta.ts | 4 + .../concepts/how-high-availability-works.mdx | 779 ++++++++++ .../concepts/how-replication-works.mdx | 6 +- pages/clustering/faq.mdx | 18 + pages/clustering/high-availability.mdx | 1253 +---------------- pages/clustering/high-availability/_meta.ts | 8 + .../high-availability/best-practices.mdx | 12 + .../setup-ha-cluster-docker-compose.mdx | 306 ++++ .../setup-ha-cluster-docker.mdx | 205 +++ .../setup-ha-cluster-k8s.mdx | 251 ++++ .../clustering/replication/best-practices.mdx | 24 +- .../replication/multi-tenant-replication.png | Bin 0 -> 50833 bytes .../replication/replication-state-diagram.png | Bin 0 -> 109720 bytes 14 files changed, 1639 insertions(+), 1256 deletions(-) create mode 100644 pages/clustering/concepts/_meta.ts create mode 100644 pages/clustering/concepts/how-high-availability-works.mdx create mode 100644 pages/clustering/high-availability/_meta.ts create mode 100644 pages/clustering/high-availability/best-practices.mdx create mode 100644 pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx create mode 100644 pages/clustering/high-availability/setup-ha-cluster-docker.mdx create mode 100644 pages/clustering/high-availability/setup-ha-cluster-k8s.mdx create mode 100644 public/pages/clustering/replication/multi-tenant-replication.png create mode 100644 public/pages/clustering/replication/replication-state-diagram.png diff --git a/pages/clustering.mdx b/pages/clustering.mdx index 07335b0ba..3fd82ca17 100644 --- a/pages/clustering.mdx +++ b/pages/clustering.mdx @@ -8,25 +8,11 @@ import { CommunityLinks } from '/components/social-card/CommunityLinks' # Clustering -To create a cluster, you can replicate data across several instances. Memgraph operates replication with: -- one writer instance (MAIN) -- one or more read-only instances (REPLICA) - -Replication can be configured in three replication modes: -- SYNC replication mode -- STRICT_SYNC replication mode -- ASYNC replication mode - - - -**We strongly suggest that user reads the guide on [how replication works](/clustering/concepts/how-replication-works) -in Memgraph on a logical level, before moving to the part of setting the cluster up.** -Choosing the appropriate number of Memgraph instances, as well as the replication mode on each -of them is crucial to understand, as that impacts performance and availability of the cluster based on your needs. - - +To ensure redundancy and increase uptime, you can set up a cluster of Memgraph instances which can +guarantee you 24/7 uptime and availability of your graph dependent services. With Memgraph Community, you gain [replication](/clustering/replication) capabilities out of the box. +You can set up a MAIN instance (writes and reads) with as many REPLICA instances (reads) as you want. However, to achieve high availability, you need to manage automatic failover. On the other hand, Memgraph Enterprise has [high availability](/clustering/high-availability) features included in the @@ -36,6 +22,15 @@ consists of: - REPLICA instances - COORDINATOR instances (backed up by Raft protocol, manage the cluster state and perform leader election) + + +**We strongly suggest that user reads the guide on [how replication works](/clustering/concepts/how-replication-works) +in Memgraph on a logical level, before moving to the part of setting the cluster up.** +Choosing the appropriate number of Memgraph instances, as well as the replication mode on each +of them is crucial to understand, as that impacts performance and availability of the cluster based on your needs. + + + Replication and high availability currently **work only in the [in-memory diff --git a/pages/clustering/concepts/_meta.ts b/pages/clustering/concepts/_meta.ts new file mode 100644 index 000000000..6e30e36bb --- /dev/null +++ b/pages/clustering/concepts/_meta.ts @@ -0,0 +1,4 @@ +export default { + "how-replication-works": "How replication works", + "how-high-availability-works": "How high availability works", +} diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx new file mode 100644 index 000000000..efe9a8e7d --- /dev/null +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -0,0 +1,779 @@ +--- +title: How high availability works +description: Learn about the underlying implementation and theoretical concepts behind Memgraph's high availability. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + + +# How high availability works (Enterprise) + + + +This guide is a continuation of [how replication works](/clustering/concepts/how-replication-works). +We recommend reading it first, before moving to the high availability concepts. + + + +A cluster is considered highly available if, at any point, there is some instance that can respond to a user query. +Our high availability relies on replication and automatic failover. The cluster consists of: +- The MAIN instance on which the user can execute write queries +- REPLICA instances that can only respond to read queries +- COORDINATOR instances that manage the cluster state. + +MAIN and REPLICA instances can also be called **data instances** in this context, as each data instance can +interchange the role of a MAIN or replica during the course of cluster lifecycle. Data instances are the ones that +are holding the graph data which is being replicated. + +**The coordinator instance is a new addition** to enable the high availability feature and orchestrates data +instances to ensure that there is always one main instance in the cluster. Coordinator instances are much smaller +than the data instances, since the sole purpose of them is to manage the cluster. + +## High availability implementation + +For achieving high availability, Memgraph uses Raft consensus protocol, which is very similar to Paxos in terms of performance and fault-tolerance but with +a significant advantage that it is much easier to understand. It's important to say that Raft isn't a +Byzantine fault-tolerant algorithm. You can learn more about Raft in the paper [In Search of an Understandable Consensus Algorithm](https://raft.github.io/raft.pdf). +**As a design decision, Memgraph uses an industry-proven library [NuRaft](https://github.com/eBay/NuRaft) for the implementation of the Raft +protocol.** + +Typical Memgraph's highly available cluster consists of: +- 3 data instances (1 MAIN and 2 REPLICAs) +- 3 coordinator instances (1 leader and 2 followers) + +// typical memgraph HA setup + +Minimal setup for data instances is 1 MAIN and 1 REPLICA. + +// minimal memgraph HA setup + +The constraint for number coordinators is only that it needs to be an **odd number of them, greater than 1** (3, 5, 7, ...). +Users can create more than 3 coordinators, but the replication factor (RF) of 3 is a de facto standard in distributed databases. + + + +The Raft consensus algorithm ensures that all nodes in a distributed system +agree on a single source of truth, even in the presence of failures, by electing +a leader to manage a replicated log. It simplifies the management of the +replicated log across the cluster, providing a way to achieve consistency and +coordination in a fault-tolerant manner. **Users are advised to use an odd number of coordinator instances** +since Raft, as a consensus algorithm, works by forming a majority in the decision making. + + + +One coordinator instance is the leader whose job is to always ensure there is exactly one MAIN, or one writeable instance. +The other two coordinator instances, called also follower coordinators, replicate changes the leader coordinator did in its own Raft log. +Operations saved into the Raft log are those that are related to cluster management. + +You can start the coordinator instance by specifying `--coordinator-id`, +`--coordinator-port` and `--management-port` flags. Followers ping the leader on the `--management-port` to get health state of the cluster. The coordinator instance only responds to +queries related to high availability, so you cannot execute any data-oriented query on it. The coordinator port is used for the Raft protocol, which +all coordinators use to ensure the consistency of the cluster's state. Data instances are distinguished from coordinator instances by +specifying only `--management-port` flag. This port is used for RPC network communication between the coordinator and data +instances. When started by default, the data instance is MAIN by default. The coordinator will ensure that no data +inconsistency can happen during and after the instance's restart. Once all instances are started, the user can start +adding data instances to the cluster. + +## Observability + +Monitoring the cluster state is very important and tracking various metrics can provide us with a valuable information. Currently, we track +metrics which reveal us p50, p90 and p99 latencies of RPC messages, the duration of recovery process and the time needed to react to changes +in the cluster. We are also counting the number of different RPC messages exchanged and the number of failed requests since this can give +us information about parts of the cluster that need further care. You can see the full list of metrics +[on the system metrics monitoring page](/database-management/monitoring#system-metrics). + +## How to query the cluster? (Bolt+routing) + +When we talk about standalone instances, the most straightforward way to connect is by using the `bolt://` protocol. +This is not optimal if you are running a cluster of Memgraph instances for multiple reasons: +- you need to connect to each instance separately +- you don't know which instance is MAIN due to automatic failovers which can happen at any time + +Because of that, users can use the **Bolt + routing (`neo4j://`)** protocol, which ensures that write queries are always sent to +the current MAIN instance. This prevents split-brain scenarios, as clients never +write to the old main but are automatically routed to the new main after a failover. + +The routing protocol works as follows: the client sends a `ROUTE` Bolt +message to any coordinator instance. The coordinator responds with a **routing +table** containing three entries: + +1. Instances from which data can be read (REPLICAs + optionally MAIN, depending on system configuration) +2. The instance where data can be written (MAIN) +3. Instances acting as routers (COORDINATORs) + +When a client connects directly to the cluster leader, the leader immediately +returns the current routing table. Thanks to the Raft consensus protocol, the +leader always has the most up-to-date cluster state. If a follower receives a +routing request, it forwards the request to the current leader, ensuring the +client always gets accurate routing information. + +This ensures: + +- **Consistency**: All clients receive the same routing information, regardless of +their entry point. +- **Reliability**: The Raft consensus protocol ensures data accuracy on the leader +node. +- **Transparency**: Client requests are handled seamlessly, whether connected to +leaders or followers. + +// routing drawing + +**Bolt+routing is a client-side routing protocol**, meaning network endpoint +resolution happens inside the database drivers. +For more details about the Bolt messages involved in the communication, check [the following +link](https://neo4j.com/docs/bolt/current/bolt/message/#messages-route). + + + +Memgraph currently does not implement server-side routing. + + + +Users only need to change the scheme they use for connecting to coordinators. +This means instead of using `bolt://,` you should use +`neo4j://` to get an active connection to the current +main instance in the cluster. You can find examples of how to use bolt+routing +in different programming languages +[here](https://github.com/memgraph/memgraph/tree/master/tests/drivers). + +It is important to note that setting up the cluster on one coordinator +(registration of data instances and coordinators, setting main) must be done +using bolt connection since bolt+routing is only used for routing data-related +queries, not coordinator-based queries. + +## System configuration + + +When deploying coordinators to servers, you can use the instance of almost any size. Instances of 4GiB or 8GiB will suffice since coordinators' +job mainly involves network communication and storing Raft metadata. Coordinators and data instances can be deployed on same servers (pairwise) +but from the availability perspective, it is better to separate them physically. + +When setting up disk space, you should always make sure that there is at least space for `--snapshot-retention-count+1` snapshots + few WAL files. That's +because we first create (N+1)th snapshot and then delete the oldest one so we could guarantee that the creation of a new snapshot ended successfully. This is +especially important when using Memgraph HA in K8s, since in K8s there is usually a limit set on the disk space used. + + + +Important note if you're using native Memgraph deployment with Red Hat. + +Red Hat uses SELinux to enforce security policies. +SELinux (Security-Enhanced Linux) is a security mechanism for implementing mandatory access control (MAC) in the Linux kernel. +It restricts programs, users, and processes to only the resources they require, following a least-privilege model. +When deploying Memgraph with high availability (HA), consider checking out this attribute for instance visibility and +setting the level of security mechanism to permissive. + +This rule could also apply to CentOS and Fedora, but at the moment it's not tested and verified. + + +## Authentication + +User accounts exist exclusively on data instances - coordinators do not manage user authentication. Therefore, coordinator instances prohibit: + - Environment variables `MEMGRAPH_USER` and `MEMGRAPH_PASSWORD`. + - Authentication queries such as `CREATE USER`. + +When using the **bolt+routing protocol**, provide credentials for users that exist on the data instances. The authentication flow works as follows: + +1. Client connects to a **coordinator**. +2. Coordinator responds with the **routing table** (without authenticating). +3. Client connects to the **designated data instance** using the **same credentials**. +4. Data instance **authenticates the user and processes the request**. + +This architecture separates routing coordination from the user management, ensuring that authentication occurs only where user data resides. + + +## Starting instances + +You can start the data and coordinator instances using environment flags or configuration flags. +The main difference between data instance and coordinator is that data instances have `--management-port`, +whereas coordinators must have `--coordinator-id` and `--coordinator-port`. + +### Configuration Flags + +#### Data instance + +Memgraph data instance must use flag `--management-port=`. This flag is tied to the high availability feature, enables the coordinator to connect to the data instance, +and allows the Memgraph data instance to use the high availability feature. The flag `--storage-wal-enabled` must be enabled, otherwise data instance won't be started. + +``` +docker run --name instance1 -p 7687:7687 -p 7444:7444 memgraph/memgraph-mage +--management-port=13011 \ +--bolt-port=7692 \ +``` + +#### Coordinator instance + +``` +docker run --name coord1 -p 7691:7691 -p 7445:7444 memgraph/memgraph-mage +--coordinator-port=10111 +--bolt-port=7691 +--coordinator-id=1 +--coordinator-hostname=localhost +--management-port=12121 +``` + +Coordinator IDs serve as identifiers, the coordinator port is used for synchronization and log replication between coordinators and management port is used to get health state of +cluster from leader coordinator. Coordinator IDs, coordinator ports and management ports must be different for all coordinators. + +Configuration option `--coordinator-hostname` must be set on all coordinator instances. It is used on followers to ping the leader coordinator on the correct IP address and return +the health state about the cluster. You can set this configuration flag to the IP address, the fully qualified domain name (FQDN), or even the DNS name. +The suggested approach is to use DNS, otherwise, in case the IP address changes, network communication between instances in the cluster will stop working. + +When testing on a local setup, the flag `--coordinator-hostname` should be set to `localhost` for each instance. + +It is important that in the host you set the bolt ports distinct for every instance, regardless of them being a data instance, or a coordinator instance. + +### Env flags + +There is an additional way to set high availability instances using environment variables. It is important to say that for the following configuration options, you can either use +environment variables or configuration flags: + +- bolt port +- coordinator port +- coordinator id +- management port +- path to nuraft log file +- coordinator hostname + +#### Data instances + +Here are the environment variables you need to use to set data instance using only environment variables: + +``` +export MEMGRAPH_MANAGEMENT_PORT=13011 +export MEMGRAPH_BOLT_PORT=7692 +``` + +When using any of these environment variables, flags `--bolt-port` and `--management-port` will be ignored. + + +#### Coordinator instances + +``` +export MEMGRAPH_COORDINATOR_PORT=10111 +export MEMGRAPH_COORDINATOR_ID=1 +export MEMGRAPH_BOLT_PORT=7687 +export MEMGRAPH_NURAFT_LOG_FILE="" +export MEMGRAPH_COORDINATOR_HOSTNAME="localhost" +export MEMGRAPH_MANAGEMENT_PORT=12121 +``` + +When using any of these environment variables, flags for `--bolt-port`, `--coordinator-port`, `--coordinator-id` and `--coordinator-hostname` will be ignored. + + +There is an additional environment variable you can use to set the path to the file with cypher queries used to start a high availability cluster. +Here, you can use queries we define in the next chapter called User API. + +``` +export MEMGRAPH_HA_CLUSTER_INIT_QUERIES= +``` +After the coordinator instance is started, Memgraph will run queries one by one from this file to set up a high availability cluster. + +## User API + +### Register instance + +Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. + +Register instance query will result in several actions: +1. The coordinator instance will connect to the data instance on the `management_server` network address. +2. The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. +3. Data instance will be demoted from main to replica. +4. Data instance will start the replication server on `replication_server`. + +```plaintext +REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; +``` + +This operation will result in writing to the Raft log. + +In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. Constructs ( AS ASYNC | AS STRICT_SYNC ) serve to specify +instance's replication mode when the instance behaves as replica. You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` +and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. + + +### Add coordinator instance + +The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, +the order isn't important. + +```plaintext +ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer}; +``` + + + +`ADD COORDINATOR` query needs to be run for all coordinators in the cluster. + +``` +ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; +ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "127.0.0.1:7692", "coordinator_server": "127.0.0.1:10112", "management_server": "127.0.0.1:12112"}; +ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "127.0.0.1:7693", "coordinator_server": "127.0.0.1:10113", "management_server": "127.0.0.1:12113"}; +``` + + + +### Remove coordinator instance + +If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, `REMOVE COORDINATOR` query can be used. +Only on leader can this query be executed in order to remove followers. Current cluster's leader cannot be removed since this is prohibited +by NuRaft. In order to remove the current leader, you first need to trigger leadership change. + +```plaintext +REMOVE COORDINATOR ; +``` + + +### Set instance to main + +Once all data instances are registered, one data instance should be promoted to main. This can be achieved by using the following query: + +```plaintext +SET INSTANCE instanceName to main; +``` + +This query will register all other instances as replicas to the new main. If one of the instances is unavailable, setting the instance to main will not succeed. +If there is already a main instance in the cluster, this query will fail. + +This operation will result in writing to the Raft log. + +### Demote instance + +Demote instance query can be used by an admin to demote the current main to replica. In this case, the leader coordinator won't perform a failover, but as a user, +you should choose promote one of the data instances to main using the `SET INSTANCE `instance` TO main` query. + +```plaintext +DEMOTE INSTANCE instanceName; +``` + +This operation will result in writing to the Raft log. + + + +By combining the functionalities of queries `DEMOTE INSTANCE instanceName` and `SET INSTANCE instanceName TO main` you get the manual failover capability. This can be useful +e.g during a maintenance work on the instance where the current main is deployed. + + + + +### Unregister instance + +There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. The hardware can be broken, +network communication could be set up incorrectly, etc. The user can remove the instance from the cluster using the following query: + +```plaintext +UNREGISTER INSTANCE instanceName; +``` + +When unregistering an instance, ensure that the instance being unregistered is +**not** the main instance. Unregistering main can lead to an inconsistent +cluster state. Additionally, the cluster must have an **alive** main instance +during the unregistration process. If no main instance is available, the +operation cannot be guaranteed to succeed. + +The instance requested to be unregistered will also be unregistered from the current main's replica set. + +### Force reset cluster state + +In case the cluster gets stuck there is an option to do the force reset of the cluster. You need to execute a command on the leader coordinator. +This command will result in the following actions: + +1. The coordinator instance will demote each alive instance to replica. +2. From the alive instance it will choose a new main instance. +3. Instances that are down will be demoted to replicas once they come back up. + +```plaintext +FORCE RESET CLUSTER STATE; +``` + +This operation will result in writing to the Raft log. + +### Show instances + +You can check the state of the whole cluster using the `SHOW INSTANCES` query. The query will display all the Memgraph servers visible in the cluster. With +each server you can see the following information: + 1. Network endpoints they are using for managing cluster state + 2. Health state of server + 3. Role - main, replica, LEADER, FOLLOWER or unknown if not alive + 4. The time passed since the last response time to the leader's health ping + +This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state and last response time, +followers will execute actions in this exact order: + 1. Try contacting the leader to get the health state of the cluster, since the leader has all the information. + If the leader responds, the follower will return the result as if the `SHOW INSTANCES` query was run on the leader. + 2. When the leader doesn't respond or currently there is no leader, the follower will return all the Memgraph servers + with the health state set to "down". + +```plaintext +SHOW INSTANCES; +``` + + +### Show instance + +You can check the state of the current coordinator to which you are connected by running the following query: + +```plaintext +SHOW INSTANCE; +``` + +This query will return the information about: +1. instance name +2. external bolt server to which you can connect using Memgraph clients +3. coordinator server over which Raft communication is done +4. management server which is also used for inter-coordinators communication and +5. cluster role: whether the coordinator is currently a leader of the follower. + +If the query `ADD COORDINATOR` wasn't run for the current instance, the value of the bolt server will be "". + +### Show replication lag + +The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. The replication lag is expressed with +the number of committed transactions. Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. The information +about the replication lag can be useful when manually performing a failover to check whether there is a risk of a data loss. + +```plaintext +SHOW REPLICATION LAG; +``` + + +## Setting config for highly-available cluster + +There are several flags that you can use for managing the cluster. Flag `--management-port` is used by both data instances +and coordinators. The provided flag needs to be unique. Setting a flag will create an RPC server on instances capable of +responding to the coordinator's RPC messages. + + + +RPC (Remote Procedure Call) is a protocol for executing functions on a remote +system. RPC enables direct communication in distributed systems and is crucial +for replication and high availability tasks. + + + +Flags `--coordinator-id`, `--coordinator-port` and `--management-port` need to be unique and specified on coordinator instances. They will cause the creation of a Raft +server that coordinator instances use for communication. Flag `--instance-health-check-frequency-sec` specifies how often should leader coordinator +check the status of the replication instance to update its status. Flag `--instance-down-timeout-sec` gives the user the ability to control how much time should +pass before the coordinator starts considering the instance to be down. + +There is a configuration option for specifying whether reads from the main are enabled. The configuration value is by default false but can be changed in run-time +using the following query: + +``` +SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false' ; +``` + +Users can also choose whether failover to the async replica is allowed by using the following query: + +``` +SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false' ; +``` + +Users can control the maximum transaction lag allowed during failover through configuration. If a replica is behind the main instance by more than the configured threshold, +that replica becomes ineligible for failover. This prevents data loss beyond the user's acceptable limits. + +To implement this functionality, we employ a caching mechanism on the cluster leader that tracks replicas' lag. The cache gets updated with each StateCheckRpc response from +replicas. During the brief failover window on the cooordinators' side, the new cluster leader may not have the current lag information for all data instances and in that case, +any replica can become main. This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety guarantees +in the large majority of situations. + + +The configuration value can be controlled using the query: + +``` +SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10' ; +``` + + + + +By default, the value is `true`, which means that only sync replicas are candidates in the election. When the value is set to `false`, the async replica is also considered, but +there is an additional risk of experiencing data loss. However, failover to an async replica may be necessary when other sync replicas are down and you want to +manually perform a failover. + + +Users can control the maximum allowed replica lag to maintain read consistency. When a replica falls behind the current main by more than `max_replica_read_lag_` transactions, the +bolt+routing protocol will exclude that replica from read query routing to ensure data freshness. + +The configuration value can be controlled using the query: + + +``` +SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10' ; +``` + +All run-time configuration options can be retrieved using: + +``` +SHOW COORDINATOR SETTINGS ; +``` + + + + +Consider the instance to be down only if several consecutive pings fail because a single ping can fail because of a large number of different reasons in distributed systems. + + + +### RPC timeouts + +For the majority of RPC messages, Memgraph uses a default timeout of 10s. This is to ensure that when sending a RPC request, the client +will not block indefinitely before receiving a response if the communication between the client and the server is broken. The list of RPC messages +for which the timeout is used is the following: + +- ShowInstancesReq -> coordinator sending to coordinator +- DemoteMainToReplicaReq -> coordinator sending to data instances +- PromoteToMainReq -> coordinator sending to data instances +- RegisterReplicaOnMainReq -> coordinator sending to data instances +- UnregisterReplicaReq -> coordinator sending to data instances +- EnableWritingOnMainReq -> coordinator sending to data instances +- GetInstanceUUIDReq -> coordinator sending to data instances +- GetDatabaseHistoriesReq -> coordinator sending to data instances +- StateCheckReq -> coordinator sending to data instances. The timeout is set to 5s. +- SwapMainUUIDReq -> coordinator sending to data instances +- FrequentHeartbeatReq -> main sending to replica. The timeout is set to 5s. +- HeartbeatReq -> main sending to replica +- TimestampReq -> main sending to replica +- SystemHeartbeatReq -> main sending to replica +- ForceResetStorageReq -> main sending to replica. The timeout is set to 60s. +- SystemRecoveryReq -> main sending to replica. The timeout is set to 5s. +- FinalizeCommitReq -> main sending to replica. The timeout is set to 10s. + + +For RPC messages which are sending the variable number of storage deltas — PrepareCommitRpc, CurrentWalRpc, and +WalFilesRpc — it is not practical to set a strict execution timeout. The +processing time on the replica side is directly proportional to the number of +deltas being transferred. To handle this, the replica sends periodic progress +updates to the main instance after processing every 100,000 deltas. Since +processing 100,000 deltas is expected to take a relatively consistent amount of +time, we can enforce a timeout based on this interval. The default timeout for +these RPC messages is 30 seconds, though in practice, processing 100,000 deltas +typically takes less than 3 seconds. + +SnapshotRpc is also a replication-related RPC message, but its execution time +is tracked a bit differently from RPC messages shipping deltas. The replica sends an update to the main instance after +completing 1,000,000 units of work. The work units are assigned as follows: + +- Processing nodes, edges, or indexed entities (label index, label-property index, + edge type index, edge type property index) = 1 unit +- Processing a node inside a point or text index = 10 units +- Processing a node inside a vector index (most computationally expensive) = + 1,000 units + +With this unit-based tracking system, the replica is expected to report progress +every 2–3 seconds. Given this, a timeout of 60 seconds is set to avoid +unnecessary network instability while ensuring responsiveness. + +Except for timeouts on read and write operations, Memgraph also has a timeout of 5s +for sockets when establishing a connection. Such a timeout helps in having a low p99 +latencies when using the RPC stack, which manifests for users as smooth and predictable +network communication between instances. + + +## Failover + +### Determining instance's health + +Every `--instance-health-check-frequency-sec` seconds, the coordinator contacts each instance. +The instance is not considered to be down unless `--instance-down-timeout-sec` has passed and the instance hasn't responded to the coordinator in the meantime. +Users must set `--instance-health-check-frequency-sec` to be less or equal to the `--instance-down-timeout-sec` but we advise users to set `--instance-down-timeout-sec` to +a multiplier of `--instance-health-check-frequency-sec`. Set the multiplier coefficient to be N>=2. +For example, set `--instance-down-timeout-sec=5` and `--instance-health-check-frequency-sec=1` which will result in coordinator contacting each instance every second and +the instance is considered dead after it doesn't respond 5 times (5 seconds / 1 second). + +In case a replica doesn't respond to a health check, the leader coordinator will try to contact it again every `--instance-health-check-frequency-sec`. +When the replica instance rejoins the cluster (comes back up), it always rejoins as replica. For main instance, there are two options. +If it is down for less than `--instance-down-timeout-sec`, it will rejoin as main because it is still considered alive. If it is down for more than `--instance-down-timeout-sec`, +the failover procedure is initiated. Whether main will rejoin as main depends on the success of the failover procedure. If the failover procedure succeeds, now old main +will rejoin as replica. If failover doesn't succeed, main will rejoin as main once it comes back up. + +### Failover procedure - high level description + +From alive replicas coordinator chooses a new potential main and writes a log to the Raft storage about the new main. On the next leader's ping to the instance, +it will send to the instance an RPC request to the new main, which is still in replica state, to promote itself to the main instance with info +about other replicas to which it will replicate data. Once that request succeeds, the new main can start replication to the other instances and accept write queries. + +### Choosing new main from available replicas + + +During failover, the coordinator must select a new main instance from available replicas, as some may be offline. The leader coordinator queries each live replica to +retrieve the committed transaction count for every database. + +The selection algorithm prioritizes data recency using a two-phase approach: + +1. **Database majority rule**: The coordinator identifies which replica has the highest committed transaction count for each database. The replica that leads in the most +databases becomes the preferred candidate. +2. **Total transaction tiebreaker**: If multiple replicas tie for leading the most databases, the coordinator sums each replica's committed transactions across all databases. +The replica with the highest total becomes the new main. + +This approach ensures the new main instance has the most up-to-date data across the cluster while maintaining consistency guarantees. + +### Old main rejoining to the cluster + +Once the old main gets back up, the coordinator sends an RPC request to demote the old main to replica. The coordinator tracks at all times which instance was the last main. + +The leader coordinator sends two RPC requests in the given order to demote old main to replica: +1. Demote main to replica RPC request +2. A request to store the UUID of the current main, which the old main, now acting as a replica instance, must listen to. + +### How replica knows which main to listen + +Each replica has a UUID of main it listens to. If a network partition happens where main can talk to a replica but the coordinator can't talk to the main, from the coordinator's +point of view that main is down. From replica's point of view, the main instance is still alive. The coordinator will start the failover procedure, and we can end up with multiple mains +where replicas can listen to both mains. To prevent such an issue, each replica gets a new UUID that no current main has. The coordinator generates the new UUID, +which the new main will get to use on its promotion to main. + +If replica was down at one point, main could have changed. When replica gets back up, it doesn't listen to any main until the coordinator sends an RPC request to replica to start +listening to main with the given UUID. + +### Replication concerns + +#### Force sync of data + +During a failover event, Memgraph selects the most up-to-date, alive instance to +become the new main. The selection process works as follows: +1. From the list of available replica instances, Memgraph chooses the one with +the latest commit timestamp for the default database. +2. If an instance that had more recent data was down during this selection +process, it will not be considered for promotion to main. + +If a previously down instance had more up-to-date data but was unavailable +during failover, it will go through a specific recovery process upon rejoining +the cluster: +- The replica will reset its storage. +- The replica will receive all commits from the new main to + synchronize its state. +- The replica's old durability files will be preserved in a `.old` directory in + `data_directory/snapshots` and `data_directory/wal` folders, allowing admins + to manually recover data if needed. + +Depending on the replication mode used, there are different levels of data loss +that can happen upon the failover. With the default `SYNC` replication mode, +Memgraph prioritizes availability over strict consistency and can result in +a non-zero Recovery Point Objective (RPO), that is, the loss of committed data, because: +- The promoted main might not have received all commits from the previous main + before the failure. +- This design ensures that the main remains writable for the maximum possible + time. + +With `ASYNC` replication mode, you also risk losing some data upon the failover because +main can freely continue commiting no matter the status of ASYNC replicas. + +The `STRICT_SYNC` replication mode allows users experiencing a failover without any data loss +in all situations. It comes with reduced throughput because of the cost of running two-phase commit protocol. + + +## Actions on follower coordinators + +From follower coordinators you can only execute `SHOW INSTANCES`. Registration of data instance, unregistration of data instances, demoting instance, setting instance to main and +force resetting cluster state are all disabled. + + +## Instances' restart + +### Data instances' restart + +Data instances can fail both as main and as replica. When an instance that was replica comes back, it won't accept updates from any instance until the coordinator updates its +responsible peer. This should happen automatically when the coordinator's ping to the instance passes. When the main instance comes back, any writing to the main instance will be +forbidden until a ping from the coordinator passes. + +### Coordinator instances restart + +In case the coordinator instance dies and it is restarted, it will not lose any data from the RAFT log or RAFT snapshots, since coordinator data is always backed-up by a durable storage. +For more details read about high availability durability in the durability chapter. + + +## Durability + +All NuRaft data is made durable by default. This includes all Raft logs, Raft snapshots and information about cluster connectivity. +The details about the cluster connectivity are made durable since without that information, the coordinator can't rejoin the cluster on its restart. + +Information about logs and snapshots is stored under one RocksDB instance in the `high_availability/raft_data/logs` directory stored under +the top-level `--data-directory` folder. All the data stored there is recovered in case the coordinator restarts. + +Data about other coordinators is recovered from the `high_availability/raft_data/network` directory stored under +the top-level `--data-directory` folder. When the coordinator rejoins, it will reestablish the communication with other coordinators and receive updates from the current leader. + +### First start + +On the first start of coordinators, each will store the current version of the `logs` and `network` durability store. From that point on, +each RAFT log that is sent to the coordinator is also stored on disk. For every new coordinator instance, the server config is updated. Logs are created +for each user action and failover action. Snapshots are created every N (N currently being 5) logs. + + +### Restart of coordinator + +In case of the coordinator's failure, on the restart, it will read information about other coordinators stored under `high_availability/raft_data/network` directory. + +From the `network` directory we will recover the server state before the coordinator stopped, including the current term, for whom the coordinator voted, and whether +election timer is allowed. + +It will also recover the following server config information: +- other servers, including their endpoints, id, and auxiliary data +- ID of the previous log +- ID of the current log +- additional data needed by nuRaft + +The following information will be recovered from a common RocksDB `logs` instance: +- current version of `logs` durability store +- snapshots found with `snapshot_id_` prefix in database: + - coordinator cluster state - all data instances with their role (main or replica), all coordinator instances and UUID of main instance which replica is listening to + - last log idx + - last log term + - last cluster config +- logs found in the interval between the start index and the last log index + - data - each log holds data on what has changed since the last state + - term - nuRAFT term + - log type - nuRAFT log type + + +### Handling of durability errors + +If snapshots are not correctly stored, the exception is thrown and left for the nuRAFT library to handle the issue. Logs can be missed and not stored since they are compacted and +deleted every two snapshots and will be removed relatively fast. + +Memgraph throws an error when failing to store cluster config, which is updated in the `high_availability/raft_data/network` folder. +If this happens, it will happen only on the first cluster start when coordinators are connecting since +coordinators are configured only once at the start of the whole cluster. This is a non-recoverable error since in case the coordinator rejoins the cluster and has +the wrong state of other clusters, it can become a leader without being connected to other coordinators. + + +## Recovering from errors + +Distributed systems can fail in numerous ways. Memgraph processes are resilient to network +failures, omission faults and independent machine failures. Byzantine failures aren't tolerated since the Raft consensus protocol cannot deal with them either. + +Recovery Time Objective (RTO) is an often used term for measuring the maximum tolerable length of time that an instance or cluster can be down. +Since every highly available Memgraph cluster has two types of instances, we need to analyze the failures of each separately. + +Raft is a quorum-based protocol and it needs a majority of instances alive in order to stay functional. Hence, with just one coordinator instance down, RTO is 0 since +the cluster stays available. With 2+ coordinator instances down +(in a cluster with RF = 3), the RTO depends on the time needed for instances to come back. + +Depending on the replica's replication mode, its failure can lead to different situations. If the replica was registered with STRICT_SYNC mode, then on its failure, writing +on main will be disabled. On the other hand, if replica was registered as ASYNC or SYNC, further writes on main are still allowed. In both cases, reads are still allowed from +main and other replicas. + + +The most important thing to analyze is what happens when main gets down. In that case, the leader coordinator uses +user-controllable parameters related to the frequency of health checks from the leader to replication instances (`--instance-health-check-frequency-sec`) +and the time needed to realize the instance is down (`--instance-down-timeout-sec`). After collecting enough evidence, the leader concludes the main is down and performs failover +using just a handful of RPC messages (correct time depends on the distance between instances). It is important to mention that the whole failover is performed without the loss of committed data +if the newly chosen main (previously replica) had all up-to-date data. + +## Raft configuration parameters + +Several Raft-related parameters are important for the correct functioning of the cluster. The leader coordinator sends a heartbeat +message to other coordinators every second to determine their health. This configuration option is connected with leader election timeout which +is a randomized value from the interval [2000ms, 4000ms] and which is used by followers to decide when to trigger new election process. Leadership +expiration is set to 2000ms so that cluster can never get into situation where multiple leaders exist. These specific values give a cluster +the ability to survive occasional network hiccups without triggering leadership changes. + + +## Data center failure + +The architecture we currently use allows us to deploy coordinators in 3 data centers and hence tolerate a failure of the whole data center. Data instances can be freely +distributed in any way you want between data centers. The failover time will be slightly increased due to the network communication needed. + + diff --git a/pages/clustering/concepts/how-replication-works.mdx b/pages/clustering/concepts/how-replication-works.mdx index d550b3734..2dfd35380 100644 --- a/pages/clustering/concepts/how-replication-works.mdx +++ b/pages/clustering/concepts/how-replication-works.mdx @@ -57,7 +57,7 @@ The replication mode defines the terms by which the MAIN instance can commit the changes to the database, thus modifying the system to prioritize either consistency or availability. -- **STRICT_SYNC mode** - Replication is implemented as a two-phase commit protocol. +- **STRICT_SYNC mode** - Replication is implemented as a [two-phase commit protocol (2PC)](https://en.wikipedia.org/wiki/Two-phase_commit_protocol). After committing a transaction, the MAIN instance will communicate the changes to all REPLICA instances and wait until it receives a response or information that a timeout is reached. The STRICT_SYNC mode ensures consistency and partition tolerance (CP), but not availability for writes. @@ -163,7 +163,7 @@ Based on RPC heartbeats, MAIN decides in which state the REPLICA is in at a poin in which state it is in. It doesn't need to know that, as MAIN is the sole initiator of synchronization mechanisms when performing replication or recovery. -// state diagram +![](/pages/clustering/replication/replication-state-diagram.png) ### How are instances synchronized? @@ -240,6 +240,8 @@ When sending replication data over the network, durability files are also assign the database UUID. It serves as a unique location of which database to apply the durability files to in the replicas. +![](/pages/clustering/replication/multi-tenant-replication.png) + Ensure replication / high-availability at the very beginning in order to make sure the correct information is replicated diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx index 21d1f3590..da8c5cad9 100644 --- a/pages/clustering/faq.mdx +++ b/pages/clustering/faq.mdx @@ -14,12 +14,30 @@ Memgraph at the moment doesn't support chaining REPLICA instances, that is, a RE instance cannot be replicated on another REPLICA instance. #### Can a REPLICA listen to multiple MAIN instances? +Memgraph enforces the behaviour that REPLICA can only listen to exactly one MAIN instance. When starting any Memgraph instance, it is assigned a unique UUID of the instance. This is communicated when a replica is registered, to ensure REPLICA does not receive replication data from another MAIN instance. A REPLICA stores the UUID of the MAIN instance it listens to. The instance UUID of each Memgraph is persisted on disk across restarts, so this behaviour is enforced throughout the cluster lifecycle. +#### Can a REPLICA create snapshots by itself? +No. REPLICA can only receive snapshots during the recovery phase. + +#### Can a REPLICA create WALs by itself? +Actually, this is being done in the system. When a MAIN is committing, it is sending the Delta objects to the REPLICA. +Here the replica is doing two things: +- it is applying the Delta objects from MAIN to catch up +- it is writing the Delta objects to its own WAL files + +Why is this important? +Picture the following scenario. REPLICA is up to date with the MAIN. MAIN is constantly sending delta objects to the REPLICA. +After a while, the MAIN goes down and REPLICA is promoted to be the "new MAIN". The new MAIN would not have any durability +files, if it didn't write WALs during its period of being a REPLICA. If the old MAIN rises, the new MAIN would perhaps have +insufficient information to be sent to the new REPLICA. That's why REPLICA always needs to write down in WALs what it's +being received. + + ### High availability with Docker ### High availability with Docker Compose diff --git a/pages/clustering/high-availability.mdx b/pages/clustering/high-availability.mdx index 92307249d..2feb69b53 100644 --- a/pages/clustering/high-availability.mdx +++ b/pages/clustering/high-availability.mdx @@ -1,1253 +1,36 @@ --- title: High availability -description: Dive into the documentation page for Memgraph and learn how to configure a cluster of Memgraph instances to achieve high availability. +description: Dive into the documentation page for Memgraph and learn how to configure high availability for data redundancy, DR and 24/7 uptime. --- import { Callout } from 'nextra/components' -import { Steps } from 'nextra/components' -import {CommunityLinks} from '/components/social-card/CommunityLinks' +import { CommunityLinks } from '/components/social-card/CommunityLinks' +# How to setup high availability with Memgraph (Eterprise) -# High availability (Enterprise) - -A cluster is considered highly available if, at any point, there is some instance that can respond to a user query. Our high availability -relies on replication. The cluster consists of: -- The main instance on which the user can execute write queries -- replica instances that can only respond to read queries -- COORDINATOR instances that manage the cluster state. - -Depending on how configuration flags are set, Memgraph can run as a data instance or coordinator instance. -The coordinator instance is a new addition to enable the high availability feature and orchestrates data instances to ensure that there is always one main instance in the cluster. - -## Cluster management - -For achieving high availability, Memgraph uses Raft consensus protocol, which is very similar to Paxos in terms of performance and fault-tolerance but with -a significant advantage that it is much easier to understand. It's important to say that Raft isn't a -Byzantine fault-tolerant algorithm. You can learn more about Raft in the paper [In Search of an Understandable Consensus Algorithm](https://raft.github.io/raft.pdf). - -Typical Memgraph's highly available cluster consists of 3 data instances (1 main and 2 replicaS) and 3 coordinator instances backed up by Raft protocol. -Users can create more than 3 coordinators, but the replication factor (RF) of 3 is a de facto standard in distributed databases. - -One coordinator instance is the leader whose job is to always ensure one writeable data instance (main). The other two coordinator instances replicate -changes the leader coordinator did in its own Raft log. Operations saved into the Raft log are those that are related to cluster management. Memgraph doesn't have its -implementation of the Raft protocol. For this task, Memgraph uses an industry-proven library [NuRaft](https://github.com/eBay/NuRaft). - -You can start the coordinator instance by specifying `--coordinator-id`, -`--coordinator-port` and `--management-port` flags. Followers ping the leader on the `--management-port` to get health state of the cluster. The coordinator instance only responds to -queries related to high availability, so you cannot execute any data-oriented query on it. The coordinator port is used for the Raft protocol, which -all coordinators use to ensure the consistency of the cluster's state. Data instances are distinguished from coordinator instances by -specifying only `--management-port` flag. This port is used for RPC network communication between the coordinator and data -instances. When started by default, the data instance is main. The coordinator will ensure that no data inconsistency can happen during and after the instance's -restart. Once all instances are started, the user can start adding data instances to the cluster. - - - - -The Raft consensus algorithm ensures that all nodes in a distributed system -agree on a single source of truth, even in the presence of failures, by electing -a leader to manage a replicated log. It simplifies the management of the -replicated log across the cluster, providing a way to achieve consistency and -coordination in a fault-tolerant manner. Users are advised to use an odd number of instances -since Raft, as a consensus algorithm, works by forming a majority in the decision making. - - - -## Observability - -Monitoring the cluster state is very important and tracking various metrics can provide us with a valuable information. Currently, we track -metrics which reveal us p50, p90 and p99 latencies of RPC messages, the duration of recovery process and the time needed to react to changes -in the cluster. We are also counting the number of different RPC messages exchanged and the number of failed requests since this can give -us information about parts of the cluster that need further care. You can see the full list of metrics [here](/database-management/monitoring#system-metrics). - -## Bolt+routing - -Directly connecting to the main instance isn't preferred in the HA cluster since -the main instance changes due to various failures. Because of that, users can -use **Bolt with routing**, which ensures that write queries are always sent to -the current main instance. This prevents split-brain scenarios, as clients never -write to the old main but are automatically routed to the new main after a -failover. -The routing protocol works as follows: the client sends a `ROUTE` Bolt -message to any coordinator instance. The coordinator responds with a **routing -table** containing three entries: - -1. Instances from which data can be read -2. The instance where data can be written -3. Instances acting as routers - -When a client connects directly to the cluster leader, the leader immediately -returns the current routing table. Thanks to the Raft consensus protocol, the -leader always has the most up-to-date cluster state. If a follower receives a -routing request, it forwards the request to the current leader, ensuring the -client always gets accurate routing information. - -This ensures: - -- **Consistency**: All clients receive the same routing information, regardless of -their entry point. -- **Reliability**: The Raft consensus protocol ensures data accuracy on the leader -node. -- **Transparency**: Client requests are handled seamlessly, whether connected to -leaders or followers. - -In the Memgraph HA cluster: - -- The **main instance** is the only writable instance -- **Replicas** are readable instances -- **Coordinators** act as routers - -However, the cluster can be configured in such a way that main can also be used -for reading. Check this -[paragraph](#setting-config-for-highly-available-cluster) for more info. -Bolt+routing is the client-side routing protocol, meaning network endpoint -resolution happens inside drivers. For more details about the Bolt messages -involved in the communication, check [the following -link](https://neo4j.com/docs/bolt/current/bolt/message/#messages-route). - -Users only need to change the scheme they use for connecting to coordinators. -This means instead of using `bolt://,` you should use -`neo4j://` to get an active connection to the current -main instance in the cluster. You can find examples of how to use bolt+routing -in different programming languages -[here](https://github.com/memgraph/memgraph/tree/master/tests/drivers). - -It is important to note that setting up the cluster on one coordinator -(registration of data instances and coordinators, setting main) must be done -using bolt connection since bolt+routing is only used for routing data-related -queries, not coordinator-based queries. - -## System configuration - - -When deploying coordinators to servers, you can use the instance of almost any size. Instances of 4GiB or 8GiB will suffice since coordinators' -job mainly involves network communication and storing Raft metadata. Coordinators and data instances can be deployed on same servers (pairwise) -but from the availability perspective, it is better to separate them physically. - -When setting up disk space, you should always make sure that there is at least space for `--snapshot-retention-count+1` snapshots + few WAL files. That's -because we first create (N+1)th snapshot and then delete the oldest one so we could guarantee that the creation of a new snapshot ended successfully. This is -especially important when using Memgraph HA in K8s, since in K8s there is usually a limit set on the disk space used. - - - -Important note if you're using native Memgraph deployment with Red Hat. - -Red Hat uses SELinux to enforce security policies. -SELinux (Security-Enhanced Linux) is a security mechanism for implementing mandatory access control (MAC) in the Linux kernel. -It restricts programs, users, and processes to only the resources they require, following a least-privilege model. -When deploying Memgraph with high availability (HA), consider checking out this attribute for instance visibility and -setting the level of security mechanism to permissive. - -This rule could also apply to CentOS and Fedora, but at the moment it's not tested and verified. - - -## Authentication - -User accounts exist exclusively on data instances - coordinators do not manage user authentication. Therefore, coordinator instances prohibit: - - Environment variables `MEMGRAPH_USER` and `MEMGRAPH_PASSWORD`. - - Authentication queries such as `CREATE USER`. - -When using the **bolt+routing protocol**, provide credentials for users that exist on the data instances. The authentication flow works as follows: - -1. Client connects to a **coordinator**. -2. Coordinator responds with the **routing table** (without authenticating). -3. Client connects to the **designated data instance** using the **same credentials**. -4. Data instance **authenticates the user and processes the request**. - -This architecture separates routing coordination from the user management, ensuring that authentication occurs only where user data resides. - - -## Starting instances - -You can start the data and coordinator instances using environment flags or configuration flags. -The main difference between data instance and coordinator is that data instances have `--management-port`, -whereas coordinators must have `--coordinator-id` and `--coordinator-port`. - -### Configuration Flags - -#### Data instance - -Memgraph data instance must use flag `--management-port=`. This flag is tied to the high availability feature, enables the coordinator to connect to the data instance, -and allows the Memgraph data instance to use the high availability feature. The flag `--storage-wal-enabled` must be enabled, otherwise data instance won't be started. - -``` -docker run --name instance1 -p 7687:7687 -p 7444:7444 memgraph/memgraph-mage ---management-port=13011 \ ---bolt-port=7692 \ -``` - -#### Coordinator instance - -``` -docker run --name coord1 -p 7691:7691 -p 7445:7444 memgraph/memgraph-mage ---coordinator-port=10111 ---bolt-port=7691 ---coordinator-id=1 ---coordinator-hostname=localhost ---management-port=12121 -``` - -Coordinator IDs serve as identifiers, the coordinator port is used for synchronization and log replication between coordinators and management port is used to get health state of -cluster from leader coordinator. Coordinator IDs, coordinator ports and management ports must be different for all coordinators. - -Configuration option `--coordinator-hostname` must be set on all coordinator instances. It is used on followers to ping the leader coordinator on the correct IP address and return -the health state about the cluster. You can set this configuration flag to the IP address, the fully qualified domain name (FQDN), or even the DNS name. -The suggested approach is to use DNS, otherwise, in case the IP address changes, network communication between instances in the cluster will stop working. - -When testing on a local setup, the flag `--coordinator-hostname` should be set to `localhost` for each instance. - -It is important that in the host you set the bolt ports distinct for every instance, regardless of them being a data instance, or a coordinator instance. - -### Env flags - -There is an additional way to set high availability instances using environment variables. It is important to say that for the following configuration options, you can either use -environment variables or configuration flags: - -- bolt port -- coordinator port -- coordinator id -- management port -- path to nuraft log file -- coordinator hostname - -#### Data instances - -Here are the environment variables you need to use to set data instance using only environment variables: - -``` -export MEMGRAPH_MANAGEMENT_PORT=13011 -export MEMGRAPH_BOLT_PORT=7692 -``` - -When using any of these environment variables, flags `--bolt-port` and `--management-port` will be ignored. - - -#### Coordinator instances - -``` -export MEMGRAPH_COORDINATOR_PORT=10111 -export MEMGRAPH_COORDINATOR_ID=1 -export MEMGRAPH_BOLT_PORT=7687 -export MEMGRAPH_NURAFT_LOG_FILE="" -export MEMGRAPH_COORDINATOR_HOSTNAME="localhost" -export MEMGRAPH_MANAGEMENT_PORT=12121 -``` - -When using any of these environment variables, flags for `--bolt-port`, `--coordinator-port`, `--coordinator-id` and `--coordinator-hostname` will be ignored. - - -There is an additional environment variable you can use to set the path to the file with cypher queries used to start a high availability cluster. -Here, you can use queries we define in the next chapter called User API. - -``` -export MEMGRAPH_HA_CLUSTER_INIT_QUERIES= -``` -After the coordinator instance is started, Memgraph will run queries one by one from this file to set up a high availability cluster. - -## User API - -### Register instance - -Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. - -Register instance query will result in several actions: -1. The coordinator instance will connect to the data instance on the `management_server` network address. -2. The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. -3. Data instance will be demoted from main to replica. -4. Data instance will start the replication server on `replication_server`. - -```plaintext -REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; -``` - -This operation will result in writing to the Raft log. - -In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. Constructs ( AS ASYNC | AS STRICT_SYNC ) serve to specify -instance's replication mode when the instance behaves as replica. You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` -and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. - - -### Add coordinator instance - -The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, -the order isn't important. - -```plaintext -ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer}; -``` - - - -`ADD COORDINATOR` query needs to be run for all coordinators in the cluster. - -``` -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "127.0.0.1:7692", "coordinator_server": "127.0.0.1:10112", "management_server": "127.0.0.1:12112"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "127.0.0.1:7693", "coordinator_server": "127.0.0.1:10113", "management_server": "127.0.0.1:12113"}; -``` - - - -### Remove coordinator instance - -If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, `REMOVE COORDINATOR` query can be used. -Only on leader can this query be executed in order to remove followers. Current cluster's leader cannot be removed since this is prohibited -by NuRaft. In order to remove the current leader, you first need to trigger leadership change. - -```plaintext -REMOVE COORDINATOR ; -``` - - -### Set instance to main - -Once all data instances are registered, one data instance should be promoted to main. This can be achieved by using the following query: - -```plaintext -SET INSTANCE instanceName to main; -``` - -This query will register all other instances as replicas to the new main. If one of the instances is unavailable, setting the instance to main will not succeed. -If there is already a main instance in the cluster, this query will fail. - -This operation will result in writing to the Raft log. - -### Demote instance - -Demote instance query can be used by an admin to demote the current main to replica. In this case, the leader coordinator won't perform a failover, but as a user, -you should choose promote one of the data instances to main using the `SET INSTANCE `instance` TO main` query. - -```plaintext -DEMOTE INSTANCE instanceName; -``` - -This operation will result in writing to the Raft log. - - - -By combining the functionalities of queries `DEMOTE INSTANCE instanceName` and `SET INSTANCE instanceName TO main` you get the manual failover capability. This can be useful -e.g during a maintenance work on the instance where the current main is deployed. - - - - -### Unregister instance - -There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. The hardware can be broken, -network communication could be set up incorrectly, etc. The user can remove the instance from the cluster using the following query: - -```plaintext -UNREGISTER INSTANCE instanceName; -``` - -When unregistering an instance, ensure that the instance being unregistered is -**not** the main instance. Unregistering main can lead to an inconsistent -cluster state. Additionally, the cluster must have an **alive** main instance -during the unregistration process. If no main instance is available, the -operation cannot be guaranteed to succeed. - -The instance requested to be unregistered will also be unregistered from the current main's replica set. - -### Force reset cluster state - -In case the cluster gets stuck there is an option to do the force reset of the cluster. You need to execute a command on the leader coordinator. -This command will result in the following actions: - -1. The coordinator instance will demote each alive instance to replica. -2. From the alive instance it will choose a new main instance. -3. Instances that are down will be demoted to replicas once they come back up. - -```plaintext -FORCE RESET CLUSTER STATE; -``` - -This operation will result in writing to the Raft log. - -### Show instances - -You can check the state of the whole cluster using the `SHOW INSTANCES` query. The query will display all the Memgraph servers visible in the cluster. With -each server you can see the following information: - 1. Network endpoints they are using for managing cluster state - 2. Health state of server - 3. Role - main, replica, LEADER, FOLLOWER or unknown if not alive - 4. The time passed since the last response time to the leader's health ping - -This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state and last response time, -followers will execute actions in this exact order: - 1. Try contacting the leader to get the health state of the cluster, since the leader has all the information. - If the leader responds, the follower will return the result as if the `SHOW INSTANCES` query was run on the leader. - 2. When the leader doesn't respond or currently there is no leader, the follower will return all the Memgraph servers - with the health state set to "down". - -```plaintext -SHOW INSTANCES; -``` - - -### Show instance - -You can check the state of the current coordinator to which you are connected by running the following query: - -```plaintext -SHOW INSTANCE; -``` - -This query will return the information about: -1. instance name -2. external bolt server to which you can connect using Memgraph clients -3. coordinator server over which Raft communication is done -4. management server which is also used for inter-coordinators communication and -5. cluster role: whether the coordinator is currently a leader of the follower. - -If the query `ADD COORDINATOR` wasn't run for the current instance, the value of the bolt server will be "". - -### Show replication lag - -The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. The replication lag is expressed with -the number of committed transactions. Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. The information -about the replication lag can be useful when manually performing a failover to check whether there is a risk of a data loss. - -```plaintext -SHOW REPLICATION LAG; -``` - - -## Setting config for highly-available cluster - -There are several flags that you can use for managing the cluster. Flag `--management-port` is used by both data instances -and coordinators. The provided flag needs to be unique. Setting a flag will create an RPC server on instances capable of -responding to the coordinator's RPC messages. - - - -RPC (Remote Procedure Call) is a protocol for executing functions on a remote -system. RPC enables direct communication in distributed systems and is crucial -for replication and high availability tasks. - - - -Flags `--coordinator-id`, `--coordinator-port` and `--management-port` need to be unique and specified on coordinator instances. They will cause the creation of a Raft -server that coordinator instances use for communication. Flag `--instance-health-check-frequency-sec` specifies how often should leader coordinator -check the status of the replication instance to update its status. Flag `--instance-down-timeout-sec` gives the user the ability to control how much time should -pass before the coordinator starts considering the instance to be down. - -There is a configuration option for specifying whether reads from the main are enabled. The configuration value is by default false but can be changed in run-time -using the following query: - -``` -SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false' ; -``` - -Users can also choose whether failover to the async replica is allowed by using the following query: - -``` -SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false' ; -``` - -Users can control the maximum transaction lag allowed during failover through configuration. If a replica is behind the main instance by more than the configured threshold, -that replica becomes ineligible for failover. This prevents data loss beyond the user's acceptable limits. - -To implement this functionality, we employ a caching mechanism on the cluster leader that tracks replicas' lag. The cache gets updated with each StateCheckRpc response from -replicas. During the brief failover window on the cooordinators' side, the new cluster leader may not have the current lag information for all data instances and in that case, -any replica can become main. This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety guarantees -in the large majority of situations. - - -The configuration value can be controlled using the query: - -``` -SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10' ; -``` - - - - -By default, the value is `true`, which means that only sync replicas are candidates in the election. When the value is set to `false`, the async replica is also considered, but -there is an additional risk of experiencing data loss. However, failover to an async replica may be necessary when other sync replicas are down and you want to -manually perform a failover. - - -Users can control the maximum allowed replica lag to maintain read consistency. When a replica falls behind the current main by more than `max_replica_read_lag_` transactions, the -bolt+routing protocol will exclude that replica from read query routing to ensure data freshness. - -The configuration value can be controlled using the query: - - -``` -SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10' ; -``` - -All run-time configuration options can be retrieved using: - -``` -SHOW COORDINATOR SETTINGS ; -``` - - - - -Consider the instance to be down only if several consecutive pings fail because a single ping can fail because of a large number of different reasons in distributed systems. - - - -### RPC timeouts - -For the majority of RPC messages, Memgraph uses a default timeout of 10s. This is to ensure that when sending a RPC request, the client -will not block indefinitely before receiving a response if the communication between the client and the server is broken. The list of RPC messages -for which the timeout is used is the following: - -- ShowInstancesReq -> coordinator sending to coordinator -- DemoteMainToReplicaReq -> coordinator sending to data instances -- PromoteToMainReq -> coordinator sending to data instances -- RegisterReplicaOnMainReq -> coordinator sending to data instances -- UnregisterReplicaReq -> coordinator sending to data instances -- EnableWritingOnMainReq -> coordinator sending to data instances -- GetInstanceUUIDReq -> coordinator sending to data instances -- GetDatabaseHistoriesReq -> coordinator sending to data instances -- StateCheckReq -> coordinator sending to data instances. The timeout is set to 5s. -- SwapMainUUIDReq -> coordinator sending to data instances -- FrequentHeartbeatReq -> main sending to replica. The timeout is set to 5s. -- HeartbeatReq -> main sending to replica -- TimestampReq -> main sending to replica -- SystemHeartbeatReq -> main sending to replica -- ForceResetStorageReq -> main sending to replica. The timeout is set to 60s. -- SystemRecoveryReq -> main sending to replica. The timeout is set to 5s. -- FinalizeCommitReq -> main sending to replica. The timeout is set to 10s. - - -For RPC messages which are sending the variable number of storage deltas — PrepareCommitRpc, CurrentWalRpc, and -WalFilesRpc — it is not practical to set a strict execution timeout. The -processing time on the replica side is directly proportional to the number of -deltas being transferred. To handle this, the replica sends periodic progress -updates to the main instance after processing every 100,000 deltas. Since -processing 100,000 deltas is expected to take a relatively consistent amount of -time, we can enforce a timeout based on this interval. The default timeout for -these RPC messages is 30 seconds, though in practice, processing 100,000 deltas -typically takes less than 3 seconds. - -SnapshotRpc is also a replication-related RPC message, but its execution time -is tracked a bit differently from RPC messages shipping deltas. The replica sends an update to the main instance after -completing 1,000,000 units of work. The work units are assigned as follows: - -- Processing nodes, edges, or indexed entities (label index, label-property index, - edge type index, edge type property index) = 1 unit -- Processing a node inside a point or text index = 10 units -- Processing a node inside a vector index (most computationally expensive) = - 1,000 units - -With this unit-based tracking system, the replica is expected to report progress -every 2–3 seconds. Given this, a timeout of 60 seconds is set to avoid -unnecessary network instability while ensuring responsiveness. - -Except for timeouts on read and write operations, Memgraph also has a timeout of 5s -for sockets when establishing a connection. Such a timeout helps in having a low p99 -latencies when using the RPC stack, which manifests for users as smooth and predictable -network communication between instances. - - -## Failover - -### Determining instance's health - -Every `--instance-health-check-frequency-sec` seconds, the coordinator contacts each instance. -The instance is not considered to be down unless `--instance-down-timeout-sec` has passed and the instance hasn't responded to the coordinator in the meantime. -Users must set `--instance-health-check-frequency-sec` to be less or equal to the `--instance-down-timeout-sec` but we advise users to set `--instance-down-timeout-sec` to -a multiplier of `--instance-health-check-frequency-sec`. Set the multiplier coefficient to be N>=2. -For example, set `--instance-down-timeout-sec=5` and `--instance-health-check-frequency-sec=1` which will result in coordinator contacting each instance every second and -the instance is considered dead after it doesn't respond 5 times (5 seconds / 1 second). - -In case a replica doesn't respond to a health check, the leader coordinator will try to contact it again every `--instance-health-check-frequency-sec`. -When the replica instance rejoins the cluster (comes back up), it always rejoins as replica. For main instance, there are two options. -If it is down for less than `--instance-down-timeout-sec`, it will rejoin as main because it is still considered alive. If it is down for more than `--instance-down-timeout-sec`, -the failover procedure is initiated. Whether main will rejoin as main depends on the success of the failover procedure. If the failover procedure succeeds, now old main -will rejoin as replica. If failover doesn't succeed, main will rejoin as main once it comes back up. - -### Failover procedure - high level description - -From alive replicas coordinator chooses a new potential main and writes a log to the Raft storage about the new main. On the next leader's ping to the instance, -it will send to the instance an RPC request to the new main, which is still in replica state, to promote itself to the main instance with info -about other replicas to which it will replicate data. Once that request succeeds, the new main can start replication to the other instances and accept write queries. - -### Choosing new main from available replicas - - -During failover, the coordinator must select a new main instance from available replicas, as some may be offline. The leader coordinator queries each live replica to -retrieve the committed transaction count for every database. - -The selection algorithm prioritizes data recency using a two-phase approach: - -1. **Database majority rule**: The coordinator identifies which replica has the highest committed transaction count for each database. The replica that leads in the most -databases becomes the preferred candidate. -2. **Total transaction tiebreaker**: If multiple replicas tie for leading the most databases, the coordinator sums each replica's committed transactions across all databases. -The replica with the highest total becomes the new main. - -This approach ensures the new main instance has the most up-to-date data across the cluster while maintaining consistency guarantees. - -### Old main rejoining to the cluster - -Once the old main gets back up, the coordinator sends an RPC request to demote the old main to replica. The coordinator tracks at all times which instance was the last main. - -The leader coordinator sends two RPC requests in the given order to demote old main to replica: -1. Demote main to replica RPC request -2. A request to store the UUID of the current main, which the old main, now acting as a replica instance, must listen to. - -### How replica knows which main to listen - -Each replica has a UUID of main it listens to. If a network partition happens where main can talk to a replica but the coordinator can't talk to the main, from the coordinator's -point of view that main is down. From replica's point of view, the main instance is still alive. The coordinator will start the failover procedure, and we can end up with multiple mains -where replicas can listen to both mains. To prevent such an issue, each replica gets a new UUID that no current main has. The coordinator generates the new UUID, -which the new main will get to use on its promotion to main. - -If replica was down at one point, main could have changed. When replica gets back up, it doesn't listen to any main until the coordinator sends an RPC request to replica to start -listening to main with the given UUID. - -### Replication concerns - -#### Force sync of data - -During a failover event, Memgraph selects the most up-to-date, alive instance to -become the new main. The selection process works as follows: -1. From the list of available replica instances, Memgraph chooses the one with -the latest commit timestamp for the default database. -2. If an instance that had more recent data was down during this selection -process, it will not be considered for promotion to main. - -If a previously down instance had more up-to-date data but was unavailable -during failover, it will go through a specific recovery process upon rejoining -the cluster: -- The replica will reset its storage. -- The replica will receive all commits from the new main to - synchronize its state. -- The replica's old durability files will be preserved in a `.old` directory in - `data_directory/snapshots` and `data_directory/wal` folders, allowing admins - to manually recover data if needed. - -Depending on the replication mode used, there are different levels of data loss -that can happen upon the failover. With the default `SYNC` replication mode, -Memgraph prioritizes availability over strict consistency and can result in -a non-zero Recovery Point Objective (RPO), that is, the loss of committed data, because: -- The promoted main might not have received all commits from the previous main - before the failure. -- This design ensures that the main remains writable for the maximum possible - time. - -With `ASYNC` replication mode, you also risk losing some data upon the failover because -main can freely continue commiting no matter the status of ASYNC replicas. - -The `STRICT_SYNC` replication mode allows users experiencing a failover without any data loss -in all situations. It comes with reduced throughput because of the cost of running two-phase commit protocol. - - -## Actions on follower coordinators - -From follower coordinators you can only execute `SHOW INSTANCES`. Registration of data instance, unregistration of data instances, demoting instance, setting instance to main and -force resetting cluster state are all disabled. - - -## Instances' restart - -### Data instances' restart - -Data instances can fail both as main and as replica. When an instance that was replica comes back, it won't accept updates from any instance until the coordinator updates its -responsible peer. This should happen automatically when the coordinator's ping to the instance passes. When the main instance comes back, any writing to the main instance will be -forbidden until a ping from the coordinator passes. - -### Coordinator instances restart - -In case the coordinator instance dies and it is restarted, it will not lose any data from the RAFT log or RAFT snapshots, since coordinator data is always backed-up by a durable storage. -For more details read about high availability durability in the durability chapter. - - -## Durability - -All NuRaft data is made durable by default. This includes all Raft logs, Raft snapshots and information about cluster connectivity. -The details about the cluster connectivity are made durable since without that information, the coordinator can't rejoin the cluster on its restart. - -Information about logs and snapshots is stored under one RocksDB instance in the `high_availability/raft_data/logs` directory stored under -the top-level `--data-directory` folder. All the data stored there is recovered in case the coordinator restarts. - -Data about other coordinators is recovered from the `high_availability/raft_data/network` directory stored under -the top-level `--data-directory` folder. When the coordinator rejoins, it will reestablish the communication with other coordinators and receive updates from the current leader. - -### First start - -On the first start of coordinators, each will store the current version of the `logs` and `network` durability store. From that point on, -each RAFT log that is sent to the coordinator is also stored on disk. For every new coordinator instance, the server config is updated. Logs are created -for each user action and failover action. Snapshots are created every N (N currently being 5) logs. - - -### Restart of coordinator - -In case of the coordinator's failure, on the restart, it will read information about other coordinators stored under `high_availability/raft_data/network` directory. - -From the `network` directory we will recover the server state before the coordinator stopped, including the current term, for whom the coordinator voted, and whether -election timer is allowed. - -It will also recover the following server config information: -- other servers, including their endpoints, id, and auxiliary data -- ID of the previous log -- ID of the current log -- additional data needed by nuRaft - -The following information will be recovered from a common RocksDB `logs` instance: -- current version of `logs` durability store -- snapshots found with `snapshot_id_` prefix in database: - - coordinator cluster state - all data instances with their role (main or replica), all coordinator instances and UUID of main instance which replica is listening to - - last log idx - - last log term - - last cluster config -- logs found in the interval between the start index and the last log index - - data - each log holds data on what has changed since the last state - - term - nuRAFT term - - log type - nuRAFT log type - - -### Handling of durability errors - -If snapshots are not correctly stored, the exception is thrown and left for the nuRAFT library to handle the issue. Logs can be missed and not stored since they are compacted and -deleted every two snapshots and will be removed relatively fast. - -Memgraph throws an error when failing to store cluster config, which is updated in the `high_availability/raft_data/network` folder. -If this happens, it will happen only on the first cluster start when coordinators are connecting since -coordinators are configured only once at the start of the whole cluster. This is a non-recoverable error since in case the coordinator rejoins the cluster and has -the wrong state of other clusters, it can become a leader without being connected to other coordinators. - - -## Recovering from errors - -Distributed systems can fail in numerous ways. Memgraph processes are resilient to network -failures, omission faults and independent machine failures. Byzantine failures aren't tolerated since the Raft consensus protocol cannot deal with them either. - -Recovery Time Objective (RTO) is an often used term for measuring the maximum tolerable length of time that an instance or cluster can be down. -Since every highly available Memgraph cluster has two types of instances, we need to analyze the failures of each separately. - -Raft is a quorum-based protocol and it needs a majority of instances alive in order to stay functional. Hence, with just one coordinator instance down, RTO is 0 since -the cluster stays available. With 2+ coordinator instances down -(in a cluster with RF = 3), the RTO depends on the time needed for instances to come back. - -Depending on the replica's replication mode, its failure can lead to different situations. If the replica was registered with STRICT_SYNC mode, then on its failure, writing -on main will be disabled. On the other hand, if replica was registered as ASYNC or SYNC, further writes on main are still allowed. In both cases, reads are still allowed from -main and other replicas. - - -The most important thing to analyze is what happens when main gets down. In that case, the leader coordinator uses -user-controllable parameters related to the frequency of health checks from the leader to replication instances (`--instance-health-check-frequency-sec`) -and the time needed to realize the instance is down (`--instance-down-timeout-sec`). After collecting enough evidence, the leader concludes the main is down and performs failover -using just a handful of RPC messages (correct time depends on the distance between instances). It is important to mention that the whole failover is performed without the loss of committed data -if the newly chosen main (previously replica) had all up-to-date data. - -## Raft configuration parameters - -Several Raft-related parameters are important for the correct functioning of the cluster. The leader coordinator sends a heartbeat -message to other coordinators every second to determine their health. This configuration option is connected with leader election timeout which -is a randomized value from the interval [2000ms, 4000ms] and which is used by followers to decide when to trigger new election process. Leadership -expiration is set to 2000ms so that cluster can never get into situation where multiple leaders exist. These specific values give a cluster -the ability to survive occasional network hiccups without triggering leadership changes. - - -## Data center failure - -The architecture we currently use allows us to deploy coordinators in 3 data centers and hence tolerate a failure of the whole data center. Data instances can be freely -distributed in any way you want between data centers. The failover time will be slightly increased due to the network communication needed. - -## Kubernetes - -We support deploying Memgraph HA as part of the Kubernetes cluster through Helm charts. -You can see example configurations [here](/getting-started/install-memgraph/kubernetes#memgraph-high-availability-helm-chart). - -## In-Service Software Upgrade (ISSU) - -Memgraph’s **High Availability** supports in-service software upgrades (ISSU). -This guide explains the process when using [HA Helm -charts]((/getting-started/install-memgraph/kubernetes#memgraph-high-availability-helm-chart)). -The procedure is very similar for native deployments. - - - -**Important**: Although the upgrade process is designed to complete -successfully, unexpected issues may occur. We strongly recommend doing a backup -of your `lib` directory on all of your `StatefulSets` or native instances -depending on the deployment type. + +**Users are advised to first read the guide on [how replication works](/clustering/concepts/how-replication-works), followed +by the guide on [how high availability works](/clustering/concepts/how-high-availability-works)**. +## [Setup HA cluster (Docker)](/clustering/high-availability/setup-ha-cluster-docker) +Learn how to setup a high availability cluster with Docker. -{

Prerequisites

} - -If you are using **HA Helm charts**, set the following configuration before -doing any upgrade. - - ```yaml - updateStrategy.type: OnDelete - ``` - - Depending on the infrastructure on which you have your Memgraph cluster, the -details will differ a bit, but the backbone is the same. - -Prepare a backup of all data from all instances. This ensures you can safely -downgrade cluster to the last stable version you had. - - - For **native deployments**, tools like `cp` or `rsync` are sufficient. - - For **Kubernetes**, create a `VolumeSnapshotClass`with the yaml file fimilar - to this: - - ```yaml - apiVersion: snapshot.storage.k8s.io/v1 - kind: VolumeSnapshotClass - metadata: - name: csi-azure-disk-snapclass - driver: disk.csi.azure.com - deletionPolicy: Delete - ``` - - Apply it: - - ```bash - kubectl apply -f azure_class.yaml - ``` - - - On **Google Kubernetes Engine**, the default CSI driver is - `pd.csi.storage.gke.io` so make sure to change the field `driver`. - - On **AWS EKS**, refer to the [AWS snapshot controller - docs](https://docs.aws.amazon.com/eks/latest/userguide/csi-snapshot-controller.html). - - -{

Create snapshots

} - -Now you can create a `VolumeSnapshot` of the lib directory using the yaml file: - -```yaml -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshot -metadata: - name: coord-3-snap # Use a unique name for each instance - namespace: default -spec: - volumeSnapshotClassName: csi-azure-disk-snapclass - source: - persistentVolumeClaimName: memgraph-coordinator-3-lib-storage-memgraph-coordinator-3-0 -``` - -Apply it: - -```bash -kubectl apply -f azure_snapshot.yaml -``` - -Repeat for every instance in the cluster. - - -{

Update configuration

} - -Next you should update `image.tag` field in the `values.yaml` configuration file -to the version to which you want to upgrade your cluster. - -1. In your `values.yaml`, update the image version: - - ```yaml - image: - tag: - ``` -2. Apply the upgrade: - - ```bash - helm upgrade -f - ``` - - Since we are using `updateStrategy.type=OnDelete`, this step will not restart - any pod, rather it will just prepare pods for running the new version. - - For **native deployments**, ensure the new binary is available. - - -{

Upgrade procedure (zero downtime)

} - -Our procedure for achieving zero-downtime upgrades consists of restarting one -instance at a time. Memgraph uses **primary–secondary replication**. To avoid -downtime: - -1. Upgrade **replicas** first. -2. Upgrade the **main** instance. -3. Upgrade **coordinator followers**, then the **leader**. - -In order to find out on which pod/server the current main and the current -cluster leader sits, run: - -```cypher -SHOW INSTANCES; -``` - - -{

Upgrade replicas

} - -If you are using K8s, the upgrade can be performed by deleting the pod. Start by -deleting the replica pod (in this example replica is running on the pod -`memgraph-data-1-0`): - -```bash -kubectl delete pod memgraph-data-1-0 -``` - -**Native deployment:** stop the old binary and start the new one. - -Before starting the upgrade of the next pod, it is important to wait until all -pods are ready. Otherwise, you may end up with a data loss. On K8s you can -easily achieve that by running: - -```bash -kubectl wait --for=condition=ready pod --all -``` - -For the native deployment, check if all your instances are alived manually. - -This step should be repeated for all of your replicas in the cluster. - - -{

Upgrade the main

} - -Before deleting the main pod, check replication lag to see whether replicas are -behind MAIN: - -```cypher -SHOW REPLICATION LAG; -``` - -If replicas are behind, your upgrade will be prone to a data loss. In order to -achieve zero-downtime upgrade without any data loss, either: - - - Use `STRICT_SYNC` mode (writes will be blocked during upgrade), or - - Wait until replicas are fully caught up, then pause writes. This way, you -can use any replication mode. Read queries should however work without any -issues independently from the replica type you are using. - -Upgrade the main pod: - -```bash -kubectl delete pod memgraph-data-0-0 -kubectl wait --for=condition=ready pod --all -``` - - -{

Upgrade coordinators

} - -The upgrade of coordinators is done in exactly the same way. Start by upgrading -followers and finish with deleting the leader pod: - -```bash -kubectl delete pod memgraph-coordinator-3-0 -kubectl wait --for=condition=ready pod --all - -kubectl delete pod memgraph-coordinator-2-0 -kubectl wait --for=condition=ready pod --all - -kubectl delete pod memgraph-coordinator-1-0 -kubectl wait --for=condition=ready pod --all -``` -
- - -{

Verify upgrade

} - -Your upgrade should be finished now, to check that everything works, run: - -```cypher -SHOW VERSION; -``` - -It should show you the new Memgraph version. - - -{

Rollback

} - -If during the upgrade, you figured out that an error happened or even after -upgrading all of your pods something doesn't work (e.g. write queries don't -pass), you can safely downgrade your cluster to the previous version using -`VolumeSnapshots` you took on K8s or file backups for native deployments. - -- **Kubernetes:** - - ```bash - helm uninstall - ``` - - In `values.yaml`, for all instances set: - - ```yaml - restoreDataFromSnapshot: true - ``` - - Make sure to set correct name of the snapshot you will use to recover your -instances. - -- **Native deployments:** restore from your file backups. - - - - -If you're doing an upgrade on `minikube`, it is important to make sure that the -snapshot resides on the same node on which the `StatefulSet` is installed. -Otherwise, it won't be able to restore `StatefulSet's` attached -PersistentVolumeClaim from the `VolumeSnapshot`. - - - -## Docker Compose - -The following example shows you how to setup Memgraph cluster using Docker Compose. The cluster will use user-defined bridge network. - -License file `license.cypherl` should be in the format: - -``` - -SET DATABASE SETTING 'organization.name' TO ''; -SET DATABASE SETTING 'enterprise.license' TO ''; - -``` - -You can directly use initialization file `HA_register.cypherl`: - -``` - -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "localhost:7691", "coordinator_server": "coord1:10111", "management_server": "coord1:12121"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "localhost:7692", "coordinator_server": "coord2:10112", "management_server": "coord2:12122"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "localhost:7693", "coordinator_server": "coord3:10113", "management_server": "coord3:12123"}; - -REGISTER INSTANCE instance_1 WITH CONFIG {"bolt_server": "localhost:7687", "management_server": "instance1:13011", "replication_server": "instance1:10001"}; -REGISTER INSTANCE instance_2 WITH CONFIG {"bolt_server": "localhost:7688", "management_server": "instance2:13012", "replication_server": "instance2:10002"}; -REGISTER INSTANCE instance_3 WITH CONFIG {"bolt_server": "localhost:7689", "management_server": "instance3:13013", "replication_server": "instance3:10003"}; -SET INSTANCE instance_3 TO main; - -``` - -Since the host can't resolve the IP for coordinators and data instances, Bolt -servers in Docker Compose setup require `bolt_server` set to `localhost:`. - -You can directly use the following `docker-compose.yml` to start the cluster using `docker compose up`: - -``` -volumes: - mg_lib1: - mg_lib2: - mg_lib3: - mg_lib4: - mg_lib5: - mg_lib6: - mg_log1: - mg_log2: - mg_log3: - mg_log4: - mg_log5: - mg_log6: - -networks: - memgraph_ha: - name: memgraph_ha - driver: bridge - ipam: - driver: default - config: - - subnet: "172.21.0.0/16" - -services: - coord1: - image: "memgraph/memgraph" - container_name: coord1 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - ./HA_register.cypherl:/tmp/init/HA_register.cypherl:ro - - mg_lib1:/var/lib/memgraph - - mg_log1:/var/log/memgraph - environment: - - MEMGRAPH_HA_CLUSTER_INIT_QUERIES=/tmp/init/HA_register.cypherl - command: [ "--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7691", "--coordinator-id=1", "--coordinator-port=10111", "--management-port=12121", "--coordinator-hostname=coord1", "--nuraft-log-file=/var/log/memgraph/nuraft"] - networks: - memgraph_ha: - ipv4_address: 172.21.0.4 - ports: - - "7691:7691" - depends_on: - - instance1 - - instance2 - - instance3 - - coord2: - image: "memgraph/memgraph" - container_name: coord2 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - mg_lib2:/var/lib/memgraph - - mg_log2:/var/log/memgraph - command: [ "--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7692", "--coordinator-id=2", "--coordinator-port=10112", "--management-port=12122", "--coordinator-hostname=coord2" , "--nuraft-log-file=/var/log/memgraph/nuraft"] - networks: - memgraph_ha: - ipv4_address: 172.21.0.2 - ports: - - "7692:7692" - depends_on: - - instance1 - - instance2 - - instance3 - - coord3: - image: "memgraph/memgraph" - container_name: coord3 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - mg_lib3:/var/lib/memgraph - - mg_log3:/var/log/memgraph - command: [ "--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7693", "--coordinator-id=3", "--coordinator-port=10113", "--management-port=12123", "--coordinator-hostname=coord3" , "--nuraft-log-file=/var/log/memgraph/nuraft"] - - networks: - memgraph_ha: - ipv4_address: 172.21.0.3 - ports: - - "7693:7693" - depends_on: - - instance1 - - instance2 - - instance3 - - instance1: - image: "memgraph/memgraph" - container_name: instance1 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - mg_lib4:/var/lib/memgraph - - mg_log4:/var/log/memgraph - command: ["--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7687", "--management-port=13011"] - networks: - memgraph_ha: - ipv4_address: 172.21.0.6 - ports: - - "7687:7687" - - instance2: - image: "memgraph/memgraph" - container_name: instance2 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - mg_lib5:/var/lib/memgraph - - mg_log5:/var/log/memgraph - command: ["--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7688", "--management-port=13012"] - networks: - memgraph_ha: - ipv4_address: 172.21.0.7 - ports: - - "7688:7688" - - instance3: - image: "memgraph/memgraph" - container_name: instance3 - volumes: - - ./license.cypherl:/tmp/init/license.cypherl:ro - - mg_lib6:/var/lib/memgraph - - mg_log6:/var/log/memgraph - command: ["--init-file=/tmp/init/license.cypherl", "--log-level=TRACE", "--also-log-to-stderr", "--bolt-port=7689", "--management-port=13013"] - networks: - memgraph_ha: - ipv4_address: 172.21.0.8 - ports: - - "7689:7689" -``` - -Cluster can be shut-down using `docker compose down`. - -## Manual Docker setup - -This example will show how to set up a highly available cluster in Memgraph using three coordinators and 3 data instances. - - - -### Start all instances - -1. Start coordinator1: -```plaintext -docker run --name coord1 --network=host -p 7691:7691 -p 7444:7444 -v mg_lib1:/var/lib/memgraph -v mg_log1:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7691 --log-level=TRACE --also-log-to-stderr --coordinator-id=1 --coordinator-port=10111 --management-port=12121--coordinator-hostname=localhost --nuraft-log-file=/var/log/memgraph/nuraft -``` - -2. Start coordinator2: -```plaintext -docker run --name coord2 --network=host -p 7692:7692 -p 7445:7444 -v mg_lib2:/var/lib/memgraph -v mg_log2:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7692 --log-level=TRACE --also-log-to-stderr --coordinator-id=2 --coordinator-port=10112 --management-port=12122--coordinator-hostname=localhost --nuraft-log-file=/var/log/memgraph/nuraft -``` - -3. Start coordinator3: -```plaintext -docker run --name coord3 --network=host -p 7693:7693 -p 7446:7444 -v mg_lib3:/var/lib/memgraph -v mg_log3:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7693 --log-level=TRACE --also-log-to-stderr --coordinator-id=3 --coordinator-port=10113 --management-port=12123--coordinator-hostname=localhost --nuraft-log-file=/var/log/memgraph/nuraft -``` - -4. Start instance1: -```plaintext -docker run --name instance1 --network=host -p 7687:7687 -p 7447:7444 -v mg_lib4:/var/lib/memgraph -v mg_log4:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7687 --log-level=TRACE --also-log-to-stderr --management-port=13011 -``` - -5. Start instance2: -```plaintext -docker run --name instance2 --network=host -p 7688:7688 -p 7448:7444 -v mg_lib5:/var/lib/memgraph -v mg_log5:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7688 --log-level=TRACE --also-log-to-stderr --management-port=13012 -``` - -6. Start instance3: -```plaintext -docker run --name instance3 --network=host -p 7689:7689 -p 7449:7444 -v mg_lib6:/var/lib/memgraph -v mg_log6:/var/log/memgraph -e MEMGRAPH_ORGANIZATION_NAME= -e MEMGRAPH_ENTERPRISE_LICENSE="" memgraph/memgraph --bolt-port=7689 --log-level=TRACE --also-log-to-stderr --management-port=13013 -``` - -### Register instances - -1. Start communication with any Memgraph client on any coordinator. Here we chose coordinator 1. -```plaintext -mgconsole --port=7691 -``` -2. Add coordinator instances to the cluster. - -```plaintext -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "localhost:7691", "coordinator_server": "localhost:10111", "management_server": "localhost:12121"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "localhost:7692", "coordinator_server": "localhost:10112", "management_server": "localhost:12122"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "localhost:7693", "coordinator_server": "localhost:10113", "management_server": "localhost:12123"}; -``` - -3. Register 3 data instances as part of the cluster: - - - -Replace `` with the container's IP address. This is necessary for Docker deployments where instances are not on the local host. - - - -```plaintext -REGISTER INSTANCE instance_1 WITH CONFIG {"bolt_server": "localhost:7687", "management_server": "localhost:13011", "replication_server": "localhost:10001"}; -REGISTER INSTANCE instance_2 WITH CONFIG {"bolt_server": "localhost:7688", "management_server": "localhost:13012", "replication_server": "localhost:10002"}; -REGISTER INSTANCE instance_3 WITH CONFIG {"bolt_server": "localhost:7689", "management_server": "localhost:13013", "replication_server": "localhost:10003"}; -``` - -4. Set instance_3 as main: - -```plaintext -SET INSTANCE instance_3 TO main; -``` - -5. Connect to the leader coordinator and check cluster state with `SHOW INSTANCES`; - -| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | -| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | -| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | -| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 16 | -| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 25 | -| instance_1 | localhost:7687 | "" | localhost:13011 | up | replica | 39 | -| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 21 | -| instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | +## [Setup HA cluster (Docker Compose)](/clustering/high-availability/setup-ha-cluster-docker-compose) +Learn how to setup a high availability cluster with Docker Compose. -### Check automatic failover +## [Setup HA cluster (Kubernetes)](/clustering/high-availability/setup-ha-cluster-k8s) +Learn how to setup a high availability cluster with K8s and Helm Charts. -Let's say that the current main instance is down for some reason. After `--instance-down-timeout-sec` seconds, the coordinator will realize -that and automatically promote the first alive replica to become the new main. The output of running `SHOW INSTANCES` on the leader coordinator could then look like: +## [Querying the cluster](/clustering/high-availability/querying-the-cluster) +Learn how to query the cluster via the Bolt+routing protocol. -| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | -| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ------------------| -| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | -| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 34 | -| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 28 | -| instance_1 | localhost:7687 | "" | localhost:13011 | up | main | 61 | -| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 74 | -| instance_3 | localhost:7689 | "" | localhost:13013 | down | unknown | 71222 | +## [Best practices](/clustering/high-availability/best-practices) +Introduce yourselves to the advices we give you in order to run a reliable cluster with Memgraph. - +## [HA commands reference guide](/clustering/high-availability/ha-commands-reference) +The complete list of HA queries at your disposal. diff --git a/pages/clustering/high-availability/_meta.ts b/pages/clustering/high-availability/_meta.ts new file mode 100644 index 000000000..47919c1c3 --- /dev/null +++ b/pages/clustering/high-availability/_meta.ts @@ -0,0 +1,8 @@ +export default { + "setup-ha-cluster-docker": "Setup HA cluster with Docker", + "setup-ha-cluster-docker-compose": "Setup HA cluster with Docker Compose", + "setup-ha-cluster-k8s": "Setup HA cluster with K8s", + "querying-the-cluster": "Querying the cluster", + "best-practices": "Best practices", + "ha-commands-reference": "Reference commands", +} diff --git a/pages/clustering/high-availability/best-practices.mdx b/pages/clustering/high-availability/best-practices.mdx new file mode 100644 index 000000000..e3207e766 --- /dev/null +++ b/pages/clustering/high-availability/best-practices.mdx @@ -0,0 +1,12 @@ +--- +title: Best practices when setting up high availability +description: Various things for database administrators to bear in mind when deploying high availability with Memgraph. +--- + +import { Callout } from 'nextra/components' + +# Best practices when setting up high availability + +## How can I run data instances or coordinator instances? + +Depending on how configuration flags are set, Memgraph can run as a data instance or coordinator instance. diff --git a/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx new file mode 100644 index 000000000..3397a1b1c --- /dev/null +++ b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx @@ -0,0 +1,306 @@ +--- +title: Setup high availability cluster with Docker Compose +description: See how one can setup a high availability cluster with Docker Compose. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' + +# Setup high availability cluster with Docker Compose (Enterprise) + +## Docker Compose + +The following example shows you how to setup Memgraph cluster using Docker Compose. +The cluster will use user-defined bridge network. + + + +**In production, it is always advised to run each instance on its dedicated server.** The setup however is +very similar. Make sure that the IPs of the machines are accessible inside the cluster in order to do proper +registration of the cluster. + + + + + +### Start the Docker Compose + +You can directly use the following `docker-compose.yml` to start the cluster using `docker compose up`. +The only thing you need to modify is put your license organization name, and the enterprise key. + +``` +services: + coord1: + image: "memgraph/memgraph" + container_name: coord1 + volumes: + - mg_lib1:/var/lib/memgraph + - mg_log1:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7691", + "--coordinator-id=1", + "--coordinator-port=10111", + "--management-port=12121", + "--coordinator-hostname=coord1", + "--nuraft-log-file=/var/log/memgraph/nuraft" + ] + networks: + memgraph_ha: + ipv4_address: 172.21.0.4 + ports: + - "7691:7691" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + depends_on: + - instance1 + - instance2 + - instance3 + + coord2: + image: "memgraph/memgraph" + container_name: coord2 + volumes: + - mg_lib2:/var/lib/memgraph + - mg_log2:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7692", + "--coordinator-id=2", + "--coordinator-port=10112", + "--management-port=12122", + "--coordinator-hostname=coord2", + "--nuraft-log-file=/var/log/memgraph/nuraft" + ] + networks: + memgraph_ha: + ipv4_address: 172.21.0.2 + ports: + - "7692:7692" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + depends_on: + - instance1 + - instance2 + - instance3 + + coord3: + image: "memgraph/memgraph" + container_name: coord3 + volumes: + - mg_lib3:/var/lib/memgraph + - mg_log3:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7693", + "--coordinator-id=3", + "--coordinator-port=10113", + "--management-port=12123", + "--coordinator-hostname=coord3", + "--nuraft-log-file=/var/log/memgraph/nuraft" + ] + + networks: + memgraph_ha: + ipv4_address: 172.21.0.3 + ports: + - "7693:7693" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + depends_on: + - instance1 + - instance2 + - instance3 + + instance1: + image: "memgraph/memgraph" + container_name: instance1 + volumes: + - mg_lib4:/var/lib/memgraph + - mg_log4:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7687", + "--management-port=13011" + ] + networks: + memgraph_ha: + ipv4_address: 172.21.0.6 + ports: + - "7687:7687" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + + instance2: + image: "memgraph/memgraph" + container_name: instance2 + volumes: + - mg_lib5:/var/lib/memgraph + - mg_log5:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7688", + "--management-port=13012" + ] + networks: + memgraph_ha: + ipv4_address: 172.21.0.7 + ports: + - "7688:7688" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + + instance3: + image: "memgraph/memgraph" + container_name: instance3 + volumes: + - mg_lib6:/var/lib/memgraph + - mg_log6:/var/log/memgraph + command: [ + "--log-level=TRACE", + "--also-log-to-stderr=true", + "--bolt-port=7689", + "--management-port=13013" + ] + networks: + memgraph_ha: + ipv4_address: 172.21.0.8 + ports: + - "7689:7689" + environment: + - MEMGRAPH_ORGANIZATION_NAME= + - MEMGRAPH_ENTERPRISE_LICENSE= + +volumes: + mg_lib1: + mg_lib2: + mg_lib3: + mg_lib4: + mg_lib5: + mg_lib6: + mg_log1: + mg_log2: + mg_log3: + mg_log4: + mg_log5: + mg_log6: + +networks: + memgraph_ha: + name: memgraph_ha + driver: bridge + ipam: + driver: default + config: + - subnet: "172.21.0.0/16" +``` + +### Validate license is correctly set + +All the following queries can be run by querying directly coordinator 1, which we can conventionally +assume to be the leader for the cluster. + +First, let's validate that the license has been correctly set, by executing the following query: + +``` +SHOW LICENSE INFO; +``` + +```nocopy +``` + +### Register the coordinator instances + +Next, we proceed first by registering all the coordinators in the cluster. + +The following query is a self-registration of coordinator 1, which also needs to be executed: +``` +ADD COORDINATOR 1 WITH CONFIG { + "bolt_server": "localhost:7691", + "coordinator_server": "coord1:10111", + "management_server": "coord1:12121" +}; +``` + +Next up, we register the two other coordinators in the cluster: +``` +ADD COORDINATOR 2 WITH CONFIG { + "bolt_server": "localhost:7692", + "coordinator_server": "coord2:10112", + "management_server": "coord2:12122" +}; +ADD COORDINATOR 3 WITH CONFIG { + "bolt_server": "localhost:7693", + "coordinator_server": "coord3:10113", + "management_server": "coord3:12123" +}; +``` + +We can see the state of the cluster by executing the following query: +``` +SHOW INSTANCES +``` + +```nocopy +``` + +We observe that there is indeed one leader and two followers in the cluster: + +### Register the data instances + +We continue by registering the 3 data instances: +``` +REGISTER INSTANCE instance_1 WITH CONFIG { + "bolt_server": "localhost:7687", + "management_server": "instance1:13011", + "replication_server": "instance1:10001" +}; +REGISTER INSTANCE instance_2 WITH CONFIG { + "bolt_server": "localhost:7688", + "management_server": "instance2:13012", + "replication_server": "instance2:10002" +}; +REGISTER INSTANCE instance_3 WITH CONFIG { + "bolt_server": "localhost:7689", + "management_server": "instance3:13013", + "replication_server": "instance3:10003" +}; +``` + +### Setup one of the instances as MAIN + +We promote one of the instances as MAIN. The rest of them will serve as REPLICAs. + +``` +SET INSTANCE instance_3 TO main; +``` + +### Observe the state of the cluster + +By issuing again the command: + +``` +SHOW INSTANCES; +``` + +We can observe that there is indeed one MAIN instance and 2 REPLICA instances: + +```nocopy +``` + +Since the host can't resolve the IP for coordinators and data instances, Bolt +servers in Docker Compose setup require `bolt_server` set to `localhost:`. + +Cluster can be shut-down using `docker compose down`. + + \ No newline at end of file diff --git a/pages/clustering/high-availability/setup-ha-cluster-docker.mdx b/pages/clustering/high-availability/setup-ha-cluster-docker.mdx new file mode 100644 index 000000000..f1a4ec9b7 --- /dev/null +++ b/pages/clustering/high-availability/setup-ha-cluster-docker.mdx @@ -0,0 +1,205 @@ +--- +title: Setup high availability cluster with Docker +description: See how one can setup a high availability cluster with Docker. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' + +# Setup high availability cluster with Docker (Enterprise) + +This example will show how to set up a highly available cluster in Memgraph using +3 coordinators and 3 data instances. This setup example has been created locally using one server. + + + +**In production, it is always advised to run each instance on its dedicated server.** The setup however is +very similar. Make sure that the IPs of the machines are accessible inside the cluster in order to do proper +registration of the cluster. + + + + + +### Start all instances + +1. Start coordinator1: +```plaintext +docker run --name coord1 --network=host -p 7691:7691 -p 7444:7444 + -v mg_lib1:/var/lib/memgraph + -v mg_log1:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7691 + --log-level=TRACE + --also-log-to-stderr + --coordinator-id=1 + --coordinator-port=10111 + --management-port=12121 + --coordinator-hostname=localhost + --nuraft-log-file=/var/log/memgraph/nuraft +``` + +2. Start coordinator2: +```plaintext +docker run --name coord2 --network=host -p 7692:7692 -p 7445:7444 + -v mg_lib2:/var/lib/memgraph + -v mg_log2:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7692 + --log-level=TRACE + --also-log-to-stderr + --coordinator-id=2 + --coordinator-port=10112 + --management-port=12122 + --coordinator-hostname=localhost + --nuraft-log-file=/var/log/memgraph/nuraft +``` + +3. Start coordinator3: +```plaintext +docker run --name coord3 --network=host -p 7693:7693 -p 7446:7444 + -v mg_lib3:/var/lib/memgraph + -v mg_log3:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7693 + --log-level=TRACE + --also-log-to-stderr + --coordinator-id=3 + --coordinator-port=10113 + --management-port=12123 + --coordinator-hostname=localhost + --nuraft-log-file=/var/log/memgraph/nuraft +``` + +4. Start instance1: +```plaintext +docker run --name instance1 --network=host -p 7687:7687 -p 7447:7444 + -v mg_lib4:/var/lib/memgraph + -v mg_log4:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7687 + --log-level=TRACE + --also-log-to-stderr + --management-port=13011 +``` + +5. Start instance2: +```plaintext +docker run --name instance2 --network=host -p 7688:7688 -p 7448:7444 + -v mg_lib5:/var/lib/memgraph + -v mg_log5:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7688 + --log-level=TRACE + --also-log-to-stderr + --management-port=13012 +``` + +6. Start instance3: +```plaintext +docker run --name instance3 --network=host -p 7689:7689 -p 7449:7444 + -v mg_lib6:/var/lib/memgraph + -v mg_log6:/var/log/memgraph + -e MEMGRAPH_ORGANIZATION_NAME= + -e MEMGRAPH_ENTERPRISE_LICENSE="" + memgraph/memgraph-mage + --bolt-port=7689 + --log-level=TRACE + --also-log-to-stderr + --management-port=13013 +``` + +### Register instances + +1. Start communication with any Memgraph client on any coordinator. Here we chose coordinator 1. +```plaintext +mgconsole --port=7691 +``` +2. Add coordinator instances to the cluster. + +```plaintext +ADD COORDINATOR 1 WITH CONFIG { + "bolt_server": "localhost:7691", + "coordinator_server": "localhost:10111", + "management_server": "localhost:12121" +}; +ADD COORDINATOR 2 WITH CONFIG { + "bolt_server": "localhost:7692", + "coordinator_server": "localhost:10112", + "management_server": "localhost:12122" +}; +ADD COORDINATOR 3 WITH CONFIG { + "bolt_server": "localhost:7693", + "coordinator_server": "localhost:10113", + "management_server": "localhost:12123" +}; +``` + +3. Register 3 data instances as part of the cluster: + + + +Replace `` with the container's IP address. This is necessary for Docker deployments where instances are not on the local host. + + + +```plaintext +REGISTER INSTANCE instance_1 WITH CONFIG { + "bolt_server": "localhost:7687", + "management_server": "localhost:13011", + "replication_server": "localhost:10001" +}; +REGISTER INSTANCE instance_2 WITH CONFIG { + "bolt_server": "localhost:7688", + "management_server": "localhost:13012", + "replication_server": "localhost:10002" +}; +REGISTER INSTANCE instance_3 WITH CONFIG { + "bolt_server": "localhost:7689", + "management_server": "localhost:13013", + "replication_server": "localhost:10003" +}; +``` + +4. Set instance_3 as MAIN: + +```plaintext +SET INSTANCE instance_3 TO MAIN; +``` + +5. Connect to the leader coordinator and check cluster state with `SHOW INSTANCES`; + +| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | +| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | +| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | +| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 16 | +| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 25 | +| instance_1 | localhost:7687 | "" | localhost:13011 | up | replica | 39 | +| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 21 | +| instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | + +### Check automatic failover + +Let's say that the current main instance is down for some reason. After `--instance-down-timeout-sec` seconds, the coordinator will realize +that and automatically promote the first alive replica to become the new main. The output of running `SHOW INSTANCES` on the leader coordinator could then look like: + +| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | +| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ------------------| +| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | +| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 34 | +| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 28 | +| instance_1 | localhost:7687 | "" | localhost:13011 | up | main | 61 | +| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 74 | +| instance_3 | localhost:7689 | "" | localhost:13013 | down | unknown | 71222 | + + diff --git a/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx b/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx new file mode 100644 index 000000000..ab99b6431 --- /dev/null +++ b/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx @@ -0,0 +1,251 @@ +--- +title: Setup high availability cluster with Kubernetes +description: See how one can setup a high availability cluster with Kubernetes. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' + +# Setup high availability cluster with K8s (Enterprise) + + +## Kubernetes + +We support deploying Memgraph HA as part of the Kubernetes cluster through Helm charts. +You can see example configurations [here](/getting-started/install-memgraph/kubernetes#memgraph-high-availability-helm-chart). + +## In-Service Software Upgrade (ISSU) + +Memgraph’s **High Availability** supports in-service software upgrades (ISSU). +This guide explains the process when using [HA Helm +charts]((/getting-started/install-memgraph/kubernetes#memgraph-high-availability-helm-chart)). +The procedure is very similar for native deployments. + + + +**Important**: Although the upgrade process is designed to complete +successfully, unexpected issues may occur. We strongly recommend doing a backup +of your `lib` directory on all of your `StatefulSets` or native instances +depending on the deployment type. + + + + + +{

Prerequisites

} + +If you are using **HA Helm charts**, set the following configuration before +doing any upgrade. + + ```yaml + updateStrategy.type: OnDelete + ``` + + Depending on the infrastructure on which you have your Memgraph cluster, the +details will differ a bit, but the backbone is the same. + +Prepare a backup of all data from all instances. This ensures you can safely +downgrade cluster to the last stable version you had. + + - For **native deployments**, tools like `cp` or `rsync` are sufficient. + - For **Kubernetes**, create a `VolumeSnapshotClass`with the yaml file fimilar + to this: + + ```yaml + apiVersion: snapshot.storage.k8s.io/v1 + kind: VolumeSnapshotClass + metadata: + name: csi-azure-disk-snapclass + driver: disk.csi.azure.com + deletionPolicy: Delete + ``` + + Apply it: + + ```bash + kubectl apply -f azure_class.yaml + ``` + + - On **Google Kubernetes Engine**, the default CSI driver is + `pd.csi.storage.gke.io` so make sure to change the field `driver`. + - On **AWS EKS**, refer to the [AWS snapshot controller + docs](https://docs.aws.amazon.com/eks/latest/userguide/csi-snapshot-controller.html). + + +{

Create snapshots

} + +Now you can create a `VolumeSnapshot` of the lib directory using the yaml file: + +```yaml +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + name: coord-3-snap # Use a unique name for each instance + namespace: default +spec: + volumeSnapshotClassName: csi-azure-disk-snapclass + source: + persistentVolumeClaimName: memgraph-coordinator-3-lib-storage-memgraph-coordinator-3-0 +``` + +Apply it: + +```bash +kubectl apply -f azure_snapshot.yaml +``` + +Repeat for every instance in the cluster. + + +{

Update configuration

} + +Next you should update `image.tag` field in the `values.yaml` configuration file +to the version to which you want to upgrade your cluster. + +1. In your `values.yaml`, update the image version: + + ```yaml + image: + tag: + ``` +2. Apply the upgrade: + + ```bash + helm upgrade -f + ``` + + Since we are using `updateStrategy.type=OnDelete`, this step will not restart + any pod, rather it will just prepare pods for running the new version. + - For **native deployments**, ensure the new binary is available. + + +{

Upgrade procedure (zero downtime)

} + +Our procedure for achieving zero-downtime upgrades consists of restarting one +instance at a time. Memgraph uses **primary–secondary replication**. To avoid +downtime: + +1. Upgrade **replicas** first. +2. Upgrade the **main** instance. +3. Upgrade **coordinator followers**, then the **leader**. + +In order to find out on which pod/server the current main and the current +cluster leader sits, run: + +```cypher +SHOW INSTANCES; +``` + + +{

Upgrade replicas

} + +If you are using K8s, the upgrade can be performed by deleting the pod. Start by +deleting the replica pod (in this example replica is running on the pod +`memgraph-data-1-0`): + +```bash +kubectl delete pod memgraph-data-1-0 +``` + +**Native deployment:** stop the old binary and start the new one. + +Before starting the upgrade of the next pod, it is important to wait until all +pods are ready. Otherwise, you may end up with a data loss. On K8s you can +easily achieve that by running: + +```bash +kubectl wait --for=condition=ready pod --all +``` + +For the native deployment, check if all your instances are alived manually. + +This step should be repeated for all of your replicas in the cluster. + + +{

Upgrade the main

} + +Before deleting the main pod, check replication lag to see whether replicas are +behind MAIN: + +```cypher +SHOW REPLICATION LAG; +``` + +If replicas are behind, your upgrade will be prone to a data loss. In order to +achieve zero-downtime upgrade without any data loss, either: + + - Use `STRICT_SYNC` mode (writes will be blocked during upgrade), or + - Wait until replicas are fully caught up, then pause writes. This way, you +can use any replication mode. Read queries should however work without any +issues independently from the replica type you are using. + +Upgrade the main pod: + +```bash +kubectl delete pod memgraph-data-0-0 +kubectl wait --for=condition=ready pod --all +``` + + +{

Upgrade coordinators

} + +The upgrade of coordinators is done in exactly the same way. Start by upgrading +followers and finish with deleting the leader pod: + +```bash +kubectl delete pod memgraph-coordinator-3-0 +kubectl wait --for=condition=ready pod --all + +kubectl delete pod memgraph-coordinator-2-0 +kubectl wait --for=condition=ready pod --all + +kubectl delete pod memgraph-coordinator-1-0 +kubectl wait --for=condition=ready pod --all +``` +
+ + +{

Verify upgrade

} + +Your upgrade should be finished now, to check that everything works, run: + +```cypher +SHOW VERSION; +``` + +It should show you the new Memgraph version. + + +{

Rollback

} + +If during the upgrade, you figured out that an error happened or even after +upgrading all of your pods something doesn't work (e.g. write queries don't +pass), you can safely downgrade your cluster to the previous version using +`VolumeSnapshots` you took on K8s or file backups for native deployments. + +- **Kubernetes:** + + ```bash + helm uninstall + ``` + + In `values.yaml`, for all instances set: + + ```yaml + restoreDataFromSnapshot: true + ``` + + Make sure to set correct name of the snapshot you will use to recover your +instances. + +- **Native deployments:** restore from your file backups. + + + + +If you're doing an upgrade on `minikube`, it is important to make sure that the +snapshot resides on the same node on which the `StatefulSet` is installed. +Otherwise, it won't be able to restore `StatefulSet's` attached +PersistentVolumeClaim from the `VolumeSnapshot`. + + diff --git a/pages/clustering/replication/best-practices.mdx b/pages/clustering/replication/best-practices.mdx index 04d468f6b..9aa682a1b 100644 --- a/pages/clustering/replication/best-practices.mdx +++ b/pages/clustering/replication/best-practices.mdx @@ -15,6 +15,28 @@ load balancing, and comprehensive cluster management capabilities. +## Which replication mode should I use? +If your critical requirement is **performance**, and you're okay with being **eventually consistent**, then you should +**use ASYNC replication mode**, as that replication mode replicates using a background thread, and doesn't wait +for responses or timeouts when committing. + +If your critical requirement is **no data loss** - **use STRICT_SYNC replication mode**, +as it implements two-phase commit protocol to ensure no data loss replication. + +The most commonly used replication mode is SYNC. It ensures decent performance along with consistency. +There is, however, a minimal probability of a data loss. + +For **cross data center deployment, it is best to use ASYNC replication mode** as in the most cases the replication latency +requirements are relaxed in that case. + +### Combining different replication modes +You're well welcome to combine different replication modes for respective replicas. However, you can not pair SYNC with +STRICT_SYNC replicas, because SYNC implies that MAIN can continue the commit synchronously, +while STRICT_SYNC doesn't allow that. +Possible pairs are: +- SYNC + ASYNC replicas +- STRICT_SYNC + ASYNC replicas + ## Which storage mode to use? Data replication currently **works only in the in-memory transactional [storage @@ -40,8 +62,6 @@ called differently and each instance needs to be exposed via a different port. Check the example of creating [a replication cluster](/clustering/replication/setup-replication-cluster-docker). - - ## Which command line flags should I use? #### Data recovery on startup diff --git a/public/pages/clustering/replication/multi-tenant-replication.png b/public/pages/clustering/replication/multi-tenant-replication.png new file mode 100644 index 0000000000000000000000000000000000000000..f043c4c81c9d3a8c85f5d5fb5013348b2079b9f2 GIT binary patch literal 50833 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%0AA4YeX`v>y=7sanlfe*v-}v75Iaz-DSi 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

SI2O)`m}p6EKT^Pp%nL~MbA##_&D!) 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 R`!lDGe>L@P7im~M{a@YnUCsai literal 0 HcmV?d00001 From 2867954bf3824d1e49c5cebac45208d33a583351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Tue, 11 Nov 2025 16:36:48 +0100 Subject: [PATCH 06/13] Add general guidance on HA --- pages/clustering/concepts/_meta.ts | 1 + .../concepts/how-high-availability-works.mdx | 708 +++++------------- ...rying-the-cluster-in-high-availability.mdx | 117 +++ pages/clustering/faq.mdx | 6 + pages/clustering/high-availability.mdx | 8 +- pages/clustering/high-availability/_meta.ts | 1 - .../high-availability/best-practices.mdx | 228 +++++- .../ha-commands-reference.mdx | 362 +++------ .../querying-the-cluster.mdx | 275 ------- .../setup-ha-cluster-docker-compose.mdx | 41 +- .../setup-ha-cluster-docker.mdx | 18 +- .../setup-ha-cluster-k8s.mdx | 464 +++++++++++- .../install-memgraph/kubernetes.mdx | 470 +----------- .../high-availability/bolt_routing_reads.png | Bin 0 -> 40955 bytes .../high-availability/bolt_routing_writes.png | Bin 0 -> 44169 bytes .../high-availability/minimal_ha_cluster.png | Bin 0 -> 27594 bytes .../high-availability/typical_ha_cluster.png | Bin 0 -> 28714 bytes 17 files changed, 1111 insertions(+), 1588 deletions(-) create mode 100644 pages/clustering/concepts/querying-the-cluster-in-high-availability.mdx delete mode 100644 pages/clustering/high-availability/querying-the-cluster.mdx create mode 100644 public/pages/clustering/high-availability/bolt_routing_reads.png create mode 100644 public/pages/clustering/high-availability/bolt_routing_writes.png create mode 100644 public/pages/clustering/high-availability/minimal_ha_cluster.png create mode 100644 public/pages/clustering/high-availability/typical_ha_cluster.png diff --git a/pages/clustering/concepts/_meta.ts b/pages/clustering/concepts/_meta.ts index 6e30e36bb..10a2974c5 100644 --- a/pages/clustering/concepts/_meta.ts +++ b/pages/clustering/concepts/_meta.ts @@ -1,4 +1,5 @@ export default { "how-replication-works": "How replication works", "how-high-availability-works": "How high availability works", + "querying-the-cluster-in-high-availability": "Querying the cluster in HA" } diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx index efe9a8e7d..e283db756 100644 --- a/pages/clustering/concepts/how-high-availability-works.mdx +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -27,13 +27,13 @@ MAIN and REPLICA instances can also be called **data instances** in this context interchange the role of a MAIN or replica during the course of cluster lifecycle. Data instances are the ones that are holding the graph data which is being replicated. -**The coordinator instance is a new addition** to enable the high availability feature and orchestrates data -instances to ensure that there is always one main instance in the cluster. Coordinator instances are much smaller -than the data instances, since the sole purpose of them is to manage the cluster. +**The coordinator instances are neccessary to orchestrate the data instances and ensure that there is always one +main instance in the cluster.** Coordinator instances are much smaller than the data instances, since the sole +purpose of them is to manage the cluster. -## High availability implementation +## How is high availability achieved? -For achieving high availability, Memgraph uses Raft consensus protocol, which is very similar to Paxos in terms of performance and fault-tolerance but with +**For achieving high availability, Memgraph uses Raft consensus protocol**, which is very similar to Paxos in terms of performance and fault-tolerance but with a significant advantage that it is much easier to understand. It's important to say that Raft isn't a Byzantine fault-tolerant algorithm. You can learn more about Raft in the paper [In Search of an Understandable Consensus Algorithm](https://raft.github.io/raft.pdf). **As a design decision, Memgraph uses an industry-proven library [NuRaft](https://github.com/eBay/NuRaft) for the implementation of the Raft @@ -43,15 +43,16 @@ Typical Memgraph's highly available cluster consists of: - 3 data instances (1 MAIN and 2 REPLICAs) - 3 coordinator instances (1 leader and 2 followers) -// typical memgraph HA setup - -Minimal setup for data instances is 1 MAIN and 1 REPLICA. - -// minimal memgraph HA setup +![](/pages/clustering/high-availability/typical_ha_cluster.png) The constraint for number coordinators is only that it needs to be an **odd number of them, greater than 1** (3, 5, 7, ...). Users can create more than 3 coordinators, but the replication factor (RF) of 3 is a de facto standard in distributed databases. +Minimal setup for data instances is 1 MAIN and 1 REPLICA. If the MAIN fails, the coordinators will elect the REPLICA as the new main +instance. + +![](/pages/clustering/high-availability/minimal_ha_cluster.png) + The Raft consensus algorithm ensures that all nodes in a distributed system @@ -64,485 +65,82 @@ since Raft, as a consensus algorithm, works by forming a majority in the decisio One coordinator instance is the leader whose job is to always ensure there is exactly one MAIN, or one writeable instance. -The other two coordinator instances, called also follower coordinators, replicate changes the leader coordinator did in its own Raft log. -Operations saved into the Raft log are those that are related to cluster management. - -You can start the coordinator instance by specifying `--coordinator-id`, -`--coordinator-port` and `--management-port` flags. Followers ping the leader on the `--management-port` to get health state of the cluster. The coordinator instance only responds to -queries related to high availability, so you cannot execute any data-oriented query on it. The coordinator port is used for the Raft protocol, which -all coordinators use to ensure the consistency of the cluster's state. Data instances are distinguished from coordinator instances by -specifying only `--management-port` flag. This port is used for RPC network communication between the coordinator and data -instances. When started by default, the data instance is MAIN by default. The coordinator will ensure that no data -inconsistency can happen during and after the instance's restart. Once all instances are started, the user can start -adding data instances to the cluster. - -## Observability - -Monitoring the cluster state is very important and tracking various metrics can provide us with a valuable information. Currently, we track -metrics which reveal us p50, p90 and p99 latencies of RPC messages, the duration of recovery process and the time needed to react to changes -in the cluster. We are also counting the number of different RPC messages exchanged and the number of failed requests since this can give -us information about parts of the cluster that need further care. You can see the full list of metrics -[on the system metrics monitoring page](/database-management/monitoring#system-metrics). - -## How to query the cluster? (Bolt+routing) - -When we talk about standalone instances, the most straightforward way to connect is by using the `bolt://` protocol. -This is not optimal if you are running a cluster of Memgraph instances for multiple reasons: -- you need to connect to each instance separately -- you don't know which instance is MAIN due to automatic failovers which can happen at any time - -Because of that, users can use the **Bolt + routing (`neo4j://`)** protocol, which ensures that write queries are always sent to -the current MAIN instance. This prevents split-brain scenarios, as clients never -write to the old main but are automatically routed to the new main after a failover. - -The routing protocol works as follows: the client sends a `ROUTE` Bolt -message to any coordinator instance. The coordinator responds with a **routing -table** containing three entries: - -1. Instances from which data can be read (REPLICAs + optionally MAIN, depending on system configuration) -2. The instance where data can be written (MAIN) -3. Instances acting as routers (COORDINATORs) - -When a client connects directly to the cluster leader, the leader immediately -returns the current routing table. Thanks to the Raft consensus protocol, the -leader always has the most up-to-date cluster state. If a follower receives a -routing request, it forwards the request to the current leader, ensuring the -client always gets accurate routing information. - -This ensures: - -- **Consistency**: All clients receive the same routing information, regardless of -their entry point. -- **Reliability**: The Raft consensus protocol ensures data accuracy on the leader -node. -- **Transparency**: Client requests are handled seamlessly, whether connected to -leaders or followers. - -// routing drawing - -**Bolt+routing is a client-side routing protocol**, meaning network endpoint -resolution happens inside the database drivers. -For more details about the Bolt messages involved in the communication, check [the following -link](https://neo4j.com/docs/bolt/current/bolt/message/#messages-route). - - - -Memgraph currently does not implement server-side routing. - - - -Users only need to change the scheme they use for connecting to coordinators. -This means instead of using `bolt://,` you should use -`neo4j://` to get an active connection to the current -main instance in the cluster. You can find examples of how to use bolt+routing -in different programming languages -[here](https://github.com/memgraph/memgraph/tree/master/tests/drivers). - -It is important to note that setting up the cluster on one coordinator -(registration of data instances and coordinators, setting main) must be done -using bolt connection since bolt+routing is only used for routing data-related -queries, not coordinator-based queries. - -## System configuration - - -When deploying coordinators to servers, you can use the instance of almost any size. Instances of 4GiB or 8GiB will suffice since coordinators' -job mainly involves network communication and storing Raft metadata. Coordinators and data instances can be deployed on same servers (pairwise) -but from the availability perspective, it is better to separate them physically. - -When setting up disk space, you should always make sure that there is at least space for `--snapshot-retention-count+1` snapshots + few WAL files. That's -because we first create (N+1)th snapshot and then delete the oldest one so we could guarantee that the creation of a new snapshot ended successfully. This is -especially important when using Memgraph HA in K8s, since in K8s there is usually a limit set on the disk space used. - - - -Important note if you're using native Memgraph deployment with Red Hat. - -Red Hat uses SELinux to enforce security policies. -SELinux (Security-Enhanced Linux) is a security mechanism for implementing mandatory access control (MAC) in the Linux kernel. -It restricts programs, users, and processes to only the resources they require, following a least-privilege model. -When deploying Memgraph with high availability (HA), consider checking out this attribute for instance visibility and -setting the level of security mechanism to permissive. - -This rule could also apply to CentOS and Fedora, but at the moment it's not tested and verified. - - -## Authentication - -User accounts exist exclusively on data instances - coordinators do not manage user authentication. Therefore, coordinator instances prohibit: - - Environment variables `MEMGRAPH_USER` and `MEMGRAPH_PASSWORD`. - - Authentication queries such as `CREATE USER`. - -When using the **bolt+routing protocol**, provide credentials for users that exist on the data instances. The authentication flow works as follows: - -1. Client connects to a **coordinator**. -2. Coordinator responds with the **routing table** (without authenticating). -3. Client connects to the **designated data instance** using the **same credentials**. -4. Data instance **authenticates the user and processes the request**. - -This architecture separates routing coordination from the user management, ensuring that authentication occurs only where user data resides. - - -## Starting instances - -You can start the data and coordinator instances using environment flags or configuration flags. -The main difference between data instance and coordinator is that data instances have `--management-port`, -whereas coordinators must have `--coordinator-id` and `--coordinator-port`. - -### Configuration Flags - -#### Data instance - -Memgraph data instance must use flag `--management-port=`. This flag is tied to the high availability feature, enables the coordinator to connect to the data instance, -and allows the Memgraph data instance to use the high availability feature. The flag `--storage-wal-enabled` must be enabled, otherwise data instance won't be started. - -``` -docker run --name instance1 -p 7687:7687 -p 7444:7444 memgraph/memgraph-mage ---management-port=13011 \ ---bolt-port=7692 \ -``` - -#### Coordinator instance - -``` -docker run --name coord1 -p 7691:7691 -p 7445:7444 memgraph/memgraph-mage ---coordinator-port=10111 ---bolt-port=7691 ---coordinator-id=1 ---coordinator-hostname=localhost ---management-port=12121 -``` - -Coordinator IDs serve as identifiers, the coordinator port is used for synchronization and log replication between coordinators and management port is used to get health state of -cluster from leader coordinator. Coordinator IDs, coordinator ports and management ports must be different for all coordinators. - -Configuration option `--coordinator-hostname` must be set on all coordinator instances. It is used on followers to ping the leader coordinator on the correct IP address and return -the health state about the cluster. You can set this configuration flag to the IP address, the fully qualified domain name (FQDN), or even the DNS name. -The suggested approach is to use DNS, otherwise, in case the IP address changes, network communication between instances in the cluster will stop working. - -When testing on a local setup, the flag `--coordinator-hostname` should be set to `localhost` for each instance. - -It is important that in the host you set the bolt ports distinct for every instance, regardless of them being a data instance, or a coordinator instance. - -### Env flags - -There is an additional way to set high availability instances using environment variables. It is important to say that for the following configuration options, you can either use -environment variables or configuration flags: - -- bolt port -- coordinator port -- coordinator id -- management port -- path to nuraft log file -- coordinator hostname - -#### Data instances - -Here are the environment variables you need to use to set data instance using only environment variables: - -``` -export MEMGRAPH_MANAGEMENT_PORT=13011 -export MEMGRAPH_BOLT_PORT=7692 -``` - -When using any of these environment variables, flags `--bolt-port` and `--management-port` will be ignored. - - -#### Coordinator instances - -``` -export MEMGRAPH_COORDINATOR_PORT=10111 -export MEMGRAPH_COORDINATOR_ID=1 -export MEMGRAPH_BOLT_PORT=7687 -export MEMGRAPH_NURAFT_LOG_FILE="" -export MEMGRAPH_COORDINATOR_HOSTNAME="localhost" -export MEMGRAPH_MANAGEMENT_PORT=12121 -``` - -When using any of these environment variables, flags for `--bolt-port`, `--coordinator-port`, `--coordinator-id` and `--coordinator-hostname` will be ignored. - - -There is an additional environment variable you can use to set the path to the file with cypher queries used to start a high availability cluster. -Here, you can use queries we define in the next chapter called User API. - -``` -export MEMGRAPH_HA_CLUSTER_INIT_QUERIES= -``` -After the coordinator instance is started, Memgraph will run queries one by one from this file to set up a high availability cluster. - -## User API - -### Register instance - -Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. - -Register instance query will result in several actions: -1. The coordinator instance will connect to the data instance on the `management_server` network address. -2. The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. -3. Data instance will be demoted from main to replica. -4. Data instance will start the replication server on `replication_server`. - -```plaintext -REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; -``` - -This operation will result in writing to the Raft log. - -In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. Constructs ( AS ASYNC | AS STRICT_SYNC ) serve to specify -instance's replication mode when the instance behaves as replica. You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` -and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. - - -### Add coordinator instance - -The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, -the order isn't important. - -```plaintext -ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer}; -``` - - - -`ADD COORDINATOR` query needs to be run for all coordinators in the cluster. - -``` -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "127.0.0.1:7692", "coordinator_server": "127.0.0.1:10112", "management_server": "127.0.0.1:12112"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "127.0.0.1:7693", "coordinator_server": "127.0.0.1:10113", "management_server": "127.0.0.1:12113"}; -``` - - - -### Remove coordinator instance - -If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, `REMOVE COORDINATOR` query can be used. -Only on leader can this query be executed in order to remove followers. Current cluster's leader cannot be removed since this is prohibited -by NuRaft. In order to remove the current leader, you first need to trigger leadership change. - -```plaintext -REMOVE COORDINATOR ; -``` - - -### Set instance to main - -Once all data instances are registered, one data instance should be promoted to main. This can be achieved by using the following query: - -```plaintext -SET INSTANCE instanceName to main; -``` - -This query will register all other instances as replicas to the new main. If one of the instances is unavailable, setting the instance to main will not succeed. -If there is already a main instance in the cluster, this query will fail. - -This operation will result in writing to the Raft log. - -### Demote instance - -Demote instance query can be used by an admin to demote the current main to replica. In this case, the leader coordinator won't perform a failover, but as a user, -you should choose promote one of the data instances to main using the `SET INSTANCE `instance` TO main` query. +Other two coordinator instances are called FOLLOWER coordinators. +The follower coordinators replicate changes the leader coordinator did in its own Raft log. +Operations saved into the Raft log are those that are related to cluster management. **With this setup, coordinators are also +highly available, therefore making the whole cluster highly available.** -```plaintext -DEMOTE INSTANCE instanceName; -``` +### Data instance implementation -This operation will result in writing to the Raft log. +The data instance is your usual Memgraph standalone instance, with one key flag added: +- `--management-port` - used to get the **health state** of the data instance from the leader coordinator - +### Coordinator instance implementation -By combining the functionalities of queries `DEMOTE INSTANCE instanceName` and `SET INSTANCE instanceName TO main` you get the manual failover capability. This can be useful -e.g during a maintenance work on the instance where the current main is deployed. +The coordinator is a small orchestration instance which is shipped in the same Memgraph binary as the data instance itself. For the system +to be aware that its role is COORDINATOR, the user needs to specify three flags: +- `--coordinator-id` - serves as a **unique identifier** of the coordinator +- `--coordinator-port` - used for **synchronization and log replication** between coordinators +- `--coordinator-hostname` - used on followers to ping the leader on the correct IP address (or FQDN/DNS name) +- `--management-port` - used to get the **health state** of the respective coordinator instance from the leader coordinator + +The COORDINATOR instance is a very restricted instance, and it will not respond to any queries that are not related to management of the cluster. +That means, you can not run any data queries on the coordinator directly (we will talk more about routing data queries in the next sections). +#### How heavy are coordinator instances? -### Unregister instance - -There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. The hardware can be broken, -network communication could be set up incorrectly, etc. The user can remove the instance from the cluster using the following query: - -```plaintext -UNREGISTER INSTANCE instanceName; -``` - -When unregistering an instance, ensure that the instance being unregistered is -**not** the main instance. Unregistering main can lead to an inconsistent -cluster state. Additionally, the cluster must have an **alive** main instance -during the unregistration process. If no main instance is available, the -operation cannot be guaranteed to succeed. - -The instance requested to be unregistered will also be unregistered from the current main's replica set. - -### Force reset cluster state - -In case the cluster gets stuck there is an option to do the force reset of the cluster. You need to execute a command on the leader coordinator. -This command will result in the following actions: - -1. The coordinator instance will demote each alive instance to replica. -2. From the alive instance it will choose a new main instance. -3. Instances that are down will be demoted to replicas once they come back up. - -```plaintext -FORCE RESET CLUSTER STATE; -``` - -This operation will result in writing to the Raft log. - -### Show instances - -You can check the state of the whole cluster using the `SHOW INSTANCES` query. The query will display all the Memgraph servers visible in the cluster. With -each server you can see the following information: - 1. Network endpoints they are using for managing cluster state - 2. Health state of server - 3. Role - main, replica, LEADER, FOLLOWER or unknown if not alive - 4. The time passed since the last response time to the leader's health ping - -This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state and last response time, -followers will execute actions in this exact order: - 1. Try contacting the leader to get the health state of the cluster, since the leader has all the information. - If the leader responds, the follower will return the result as if the `SHOW INSTANCES` query was run on the leader. - 2. When the leader doesn't respond or currently there is no leader, the follower will return all the Memgraph servers - with the health state set to "down". - -```plaintext -SHOW INSTANCES; -``` - - -### Show instance - -You can check the state of the current coordinator to which you are connected by running the following query: - -```plaintext -SHOW INSTANCE; -``` - -This query will return the information about: -1. instance name -2. external bolt server to which you can connect using Memgraph clients -3. coordinator server over which Raft communication is done -4. management server which is also used for inter-coordinators communication and -5. cluster role: whether the coordinator is currently a leader of the follower. - -If the query `ADD COORDINATOR` wasn't run for the current instance, the value of the bolt server will be "". - -### Show replication lag - -The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. The replication lag is expressed with -the number of committed transactions. Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. The information -about the replication lag can be useful when manually performing a failover to check whether there is a risk of a data loss. - -```plaintext -SHOW REPLICATION LAG; -``` - - -## Setting config for highly-available cluster +When deploying coordinators to servers, you can use the instance of almost any size. Instances of 4GiB or 8GiB will suffice since coordinators' +job mainly involves network communication and storing Raft metadata. Coordinators and data instances can in theory be deployed on +same servers (pairwise) but from the availability perspective, it is better to separate them physically. -There are several flags that you can use for managing the cluster. Flag `--management-port` is used by both data instances -and coordinators. The provided flag needs to be unique. Setting a flag will create an RPC server on instances capable of -responding to the coordinator's RPC messages. +### RPC messages sent through the cluster - RPC (Remote Procedure Call) is a protocol for executing functions on a remote system. RPC enables direct communication in distributed systems and is crucial for replication and high availability tasks. - - - -Flags `--coordinator-id`, `--coordinator-port` and `--management-port` need to be unique and specified on coordinator instances. They will cause the creation of a Raft -server that coordinator instances use for communication. Flag `--instance-health-check-frequency-sec` specifies how often should leader coordinator -check the status of the replication instance to update its status. Flag `--instance-down-timeout-sec` gives the user the ability to control how much time should -pass before the coordinator starts considering the instance to be down. - -There is a configuration option for specifying whether reads from the main are enabled. The configuration value is by default false but can be changed in run-time -using the following query: - -``` -SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false' ; -``` - -Users can also choose whether failover to the async replica is allowed by using the following query: - -``` -SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false' ; -``` - -Users can control the maximum transaction lag allowed during failover through configuration. If a replica is behind the main instance by more than the configured threshold, -that replica becomes ineligible for failover. This prevents data loss beyond the user's acceptable limits. - -To implement this functionality, we employ a caching mechanism on the cluster leader that tracks replicas' lag. The cache gets updated with each StateCheckRpc response from -replicas. During the brief failover window on the cooordinators' side, the new cluster leader may not have the current lag information for all data instances and in that case, -any replica can become main. This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety guarantees -in the large majority of situations. - - -The configuration value can be controlled using the query: - -``` -SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10' ; -``` - - - - -By default, the value is `true`, which means that only sync replicas are candidates in the election. When the value is set to `false`, the async replica is also considered, but -there is an additional risk of experiencing data loss. However, failover to an async replica may be necessary when other sync replicas are down and you want to -manually perform a failover. - - -Users can control the maximum allowed replica lag to maintain read consistency. When a replica falls behind the current main by more than `max_replica_read_lag_` transactions, the -bolt+routing protocol will exclude that replica from read query routing to ensure data freshness. - -The configuration value can be controlled using the query: - - -``` -SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10' ; -``` - -All run-time configuration options can be retrieved using: - -``` -SHOW COORDINATOR SETTINGS ; -``` - - - - -Consider the instance to be down only if several consecutive pings fail because a single ping can fail because of a large number of different reasons in distributed systems. - -### RPC timeouts +#### Types of RPC messages + +Memgraph is ensuring a consistent state of the cluster using RPC messages. Below is a full list of RPC messages and their purpose. +Each + +- `ShowInstancesRpc` - sent by the follower coordinator to the leader coordinator if the user executed `SHOW INSTANCES` through the follower + coordinator +- `DemoteMainToReplicaRpc` - sent by the leader coordinator to the old MAIN in order to demote it to REPLICA +- `PromoteToMainRpc` - sent by the leader coordinator to a REPLICA in order to promote it to MAIN +- `RegisterReplicaOnMainRpc` - sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN +- `UnregisterReplicaRpc` - sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN +- `EnableWritingOnMainRpc` - sent by the leader coordinator to MAIN to enable writing on that MAIN +- `GetDatabaseHistoriesRpc` - sent by the leader coordinator to all REPLICA instances in order to select new MAIN + during the failover process +- `StateCheckRpc` - sent by the leader coordinator to all data instances for liveness check +- `SwapMainUUIDRpc` - sent by the leader coordinator to REPLICA instances to set which MAIN to listen to +- `FrequentHeartbeatRpc` - sent by the MAIN instance to a REPLICA for liveness check +- `HeartbeatRpc` - sent by the MAIN instance to a REPLICA instance for timestamp/epoch/transaction/commit information +- `SystemRecoveryRpc` - sent by the MAIN instance to a REPLICA instance for system replication queries (auth, multi-tenancy) + and other non-graph information +- `PrepareCommitRpc` - main replici (prva faza u strict syncu ili jedina faza u ostalima), pošalje delta stream +- `FinalizeCommitRpc` - samo za strict sync za 2pc, s maina na replice ako su sve strict sync replice odgovorile pozitivno za commitat +- `SnapshotRpc` - sent by the MAIN to a REPLICA for snapshot recovery to catch-up with the MAIN instance +- `WalFilesRpc` - sent by the MAIN to a REPLICA for WAL recovery to catch-up with the MAIN instance +- `CurrentWalRpc` - sent by the MAIN to a REPLICA for current/latest/unfinished WAL file recovery to catch-up with the MAIN instance + +#### RPC timeouts + +##### Default RPC timeouts For the majority of RPC messages, Memgraph uses a default timeout of 10s. This is to ensure that when sending a RPC request, the client will not block indefinitely before receiving a response if the communication between the client and the server is broken. The list of RPC messages for which the timeout is used is the following: -- ShowInstancesReq -> coordinator sending to coordinator -- DemoteMainToReplicaReq -> coordinator sending to data instances -- PromoteToMainReq -> coordinator sending to data instances -- RegisterReplicaOnMainReq -> coordinator sending to data instances -- UnregisterReplicaReq -> coordinator sending to data instances -- EnableWritingOnMainReq -> coordinator sending to data instances -- GetInstanceUUIDReq -> coordinator sending to data instances -- GetDatabaseHistoriesReq -> coordinator sending to data instances -- StateCheckReq -> coordinator sending to data instances. The timeout is set to 5s. -- SwapMainUUIDReq -> coordinator sending to data instances -- FrequentHeartbeatReq -> main sending to replica. The timeout is set to 5s. -- HeartbeatReq -> main sending to replica -- TimestampReq -> main sending to replica -- SystemHeartbeatReq -> main sending to replica -- ForceResetStorageReq -> main sending to replica. The timeout is set to 60s. -- SystemRecoveryReq -> main sending to replica. The timeout is set to 5s. -- FinalizeCommitReq -> main sending to replica. The timeout is set to 10s. - - -For RPC messages which are sending the variable number of storage deltas — PrepareCommitRpc, CurrentWalRpc, and -WalFilesRpc — it is not practical to set a strict execution timeout. The +##### RPC timeout during replication of data + +For RPC messages which are sending the variable number of storage deltas — `PrepareCommitRpc`, `CurrentWalRpc`, and +`WalFilesRpc` — it is not practical to set a strict execution timeout, as the processing time on the replica side is directly proportional to the number of deltas being transferred. To handle this, the replica sends periodic progress updates to the main instance after processing every 100,000 deltas. Since @@ -551,7 +149,9 @@ time, we can enforce a timeout based on this interval. The default timeout for these RPC messages is 30 seconds, though in practice, processing 100,000 deltas typically takes less than 3 seconds. -SnapshotRpc is also a replication-related RPC message, but its execution time +##### RPC timeout during replica recovery + +`SnapshotRpc` is also a replication-related RPC message, but its execution time is tracked a bit differently from RPC messages shipping deltas. The replica sends an update to the main instance after completing 1,000,000 units of work. The work units are assigned as follows: @@ -561,45 +161,97 @@ completing 1,000,000 units of work. The work units are assigned as follows: - Processing a node inside a vector index (most computationally expensive) = 1,000 units -With this unit-based tracking system, the replica is expected to report progress -every 2–3 seconds. Given this, a timeout of 60 seconds is set to avoid -unnecessary network instability while ensuring responsiveness. +With this unit-based tracking system, the REPLICA is expected to report progress +approximately every 2–3 seconds. Given this, a timeout of 60 seconds is set to avoid +unnecessary network instability while ensuring responsiveness. On every report of the progress +by the REPLICA, the timeout of 60 seconds will be restarted, as the state of recovery is considered to be stable. Except for timeouts on read and write operations, Memgraph also has a timeout of 5s for sockets when establishing a connection. Such a timeout helps in having a low p99 latencies when using the RPC stack, which manifests for users as smooth and predictable network communication between instances. +In the table below, we have the full outline of the RPC messages that are sent in the cluster to ensure high availability, with timeouts. + +| RPC message request | source | target | timeout | +|--------------------------|-------------|----------------| -----------------| +| ShowInstancesReq | Coordinator | Coordinator | | +| DemoteMainToReplicaReq | Coordinator | Data instance | | +| PromoteToMainReq | Coordinator | Data instance | | +| RegisterReplicaOnMainReq | Coordinator | Data instance | | +| UnregisterReplicaReq | Coordinator | Data instance | | +| EnableWritingOnMainReq | Coordinator | Data instance | | +| GetDatabaseHistoriesReq | Coordinator | Data instance | | +| StateCheckReq | Coordinator | Data instance | 5s | +| SwapMainUUIDReq | Coordinator | Data instance | | +| FrequentHeartbeatReq | Main | Replica | 5s | +| HeartbeatReq | Main | Replica | | +| SystemRecoveryReq | Main | Replica | 5s | +| PrepareCommitRpc | Main | Replica | proportional | +| FinalizeCommitReq | Main | Replica | 10s | +| SnapshotRpc | Main | Replica | proportional | +| WalFilesRpc | Main | Replica | proportional | +| CurrentWalRpc | Main | Replica | proportional | + +## Automatic failover -## Failover +### High level description -### Determining instance's health +Automatic failover can be performed based on health checks that the leader coordinator performs to the data instances. A data instance is considered +to be *alive* if it responds to health checks. If it doesn't respond to health checks, it is considered to be *down*. -Every `--instance-health-check-frequency-sec` seconds, the coordinator contacts each instance. -The instance is not considered to be down unless `--instance-down-timeout-sec` has passed and the instance hasn't responded to the coordinator in the meantime. -Users must set `--instance-health-check-frequency-sec` to be less or equal to the `--instance-down-timeout-sec` but we advise users to set `--instance-down-timeout-sec` to -a multiplier of `--instance-health-check-frequency-sec`. Set the multiplier coefficient to be N>=2. -For example, set `--instance-down-timeout-sec=5` and `--instance-health-check-frequency-sec=1` which will result in coordinator contacting each instance every second and -the instance is considered dead after it doesn't respond 5 times (5 seconds / 1 second). +**If the instance which was down was a REPLICA instance**, it will always rejoin the cluster as a REPLICA. -In case a replica doesn't respond to a health check, the leader coordinator will try to contact it again every `--instance-health-check-frequency-sec`. -When the replica instance rejoins the cluster (comes back up), it always rejoins as replica. For main instance, there are two options. -If it is down for less than `--instance-down-timeout-sec`, it will rejoin as main because it is still considered alive. If it is down for more than `--instance-down-timeout-sec`, -the failover procedure is initiated. Whether main will rejoin as main depends on the success of the failover procedure. If the failover procedure succeeds, now old main -will rejoin as replica. If failover doesn't succeed, main will rejoin as main once it comes back up. +**If the instance which was down was a MAIN instance**, the coordinator might perform a failover procedure to choose the new MAIN from the alive REPLICAs. -### Failover procedure - high level description +From alive replicas coordinator chooses a new potential main and writes a log to the Raft storage about the new main. +On the next leader's ping to the instance, it will send to the instance an RPC request (`PromoteToMainReq`) +to the new main, which is still in replica state, to promote itself to the main instance with info about other replicas +to which it will replicate data. Once that request succeeds, the new main can start replication to the other instances +and accept write queries. -From alive replicas coordinator chooses a new potential main and writes a log to the Raft storage about the new main. On the next leader's ping to the instance, -it will send to the instance an RPC request to the new main, which is still in replica state, to promote itself to the main instance with info -about other replicas to which it will replicate data. Once that request succeeds, the new main can start replication to the other instances and accept write queries. -### Choosing new main from available replicas +### Instance health checks + +Every second (set by the flag --instance-health-check-frequency-sec`), the coordinator contacts each instance. +The instance is not considered to be down unless the health check timeouts (set by the flag `--instance-down-timeout-sec`), +and the instance hasn't responded to the coordinator in the meantime. + +For example, set `--instance-down-timeout-sec=5` and `--instance-health-check-frequency-sec=1` which will result in coordinator +contacting each instance every second (`StateCheckRpc`) and the instance is considered dead after it doesn't respond 5 times (5 seconds / 1 second). +Usually, the health check reports instantly, and only in severe cases of network failure, it will timeout in 30 seconds. + +Depending on the data instance role, we have 2 scenarios: +1. In case a **REPLICA instance doesn't respond to a health check**, the leader coordinator will try to contact it again on the next scheduled interval. + **Replica instance will always rejoin the cluster as a replica.** + +??? flowchart diagram + +2. In case a **MAIN instance doesn't respond to a health check**, there are two options: + - If it is down for less than `--instance-down-timeout-sec` interval, it will rejoin as MAIN because it is still considered alive. + - If it is down for more than `--instance-down-timeout-sec` interval, the failover procedure is initiated. Whether main will + rejoin as main depends on the success of the failover procedure. + - If the failover procedure succeeds, now old main will rejoin as REPLICA. + - If failover doesn't succeed, MAIN will rejoin as MAIN once it comes back up. + +??? flowchart diagram + + +You can check the [best practices](/clustering/high-availability/best-practices) if you want to see more about instance health check configuration. + + +### Choosing new MAIN from available REPLICAs During failover, the coordinator must select a new main instance from available replicas, as some may be offline. The leader coordinator queries each live replica to retrieve the committed transaction count for every database. + +*For every database* in this terminology, means if you're using [multi-tenancy](/database-management/multi-tenancy), +to isolate different graphs/databases under one instance. If you're not using multi-tenancy, the retrieved committed transaction +count will just be retrieved for the default *memgraph* database. + + The selection algorithm prioritizes data recency using a two-phase approach: 1. **Database majority rule**: The coordinator identifies which replica has the highest committed transaction count for each database. The replica that leads in the most @@ -609,42 +261,43 @@ The replica with the highest total becomes the new main. This approach ensures the new main instance has the most up-to-date data across the cluster while maintaining consistency guarantees. -### Old main rejoining to the cluster +### Old MAIN rejoining to the cluster -Once the old main gets back up, the coordinator sends an RPC request to demote the old main to replica. The coordinator tracks at all times which instance was the last main. +Once the old MAIN gets back up, the coordinator sends an RPC request to demote the old MAIN to REPLICA (`DemoteMainToReplicaReq`). +The coordinator tracks at all times which instance was the last main. -The leader coordinator sends two RPC requests in the given order to demote old main to replica: -1. Demote main to replica RPC request -2. A request to store the UUID of the current main, which the old main, now acting as a replica instance, must listen to. +The leader coordinator sends two RPC requests in the given order to demote old MAIN to REPLICA: +1. Demote MAIN to REPLICA RPC request +2. A request to store the machine UUID of the current MAIN, which the old MAIN, now acting as a REPLICA instance, must listen to. -### How replica knows which main to listen +### How REPLICA knows which MAIN to listen -Each replica has a UUID of main it listens to. If a network partition happens where main can talk to a replica but the coordinator can't talk to the main, from the coordinator's -point of view that main is down. From replica's point of view, the main instance is still alive. The coordinator will start the failover procedure, and we can end up with multiple mains -where replicas can listen to both mains. To prevent such an issue, each replica gets a new UUID that no current main has. The coordinator generates the new UUID, -which the new main will get to use on its promotion to main. +Each replica has a UUID of MAIN it listens to. If a network partition happens where MAIN can talk to a REPLICA but the coordinator can't +talk to the MAIN, from the coordinator's point of view that MAIN is down. From REPLICA's point of view, the MAIN instance is still +alive. The coordinator will start the failover procedure, and we can end up with multiple MAINs where REPLICAs can listen to both +MAINs. To prevent such an issue, each REPLICA gets a new UUID that no current MAIN has. The coordinator generates the new UUID, +which the new MAIN will get to use on its promotion to MAIN. -If replica was down at one point, main could have changed. When replica gets back up, it doesn't listen to any main until the coordinator sends an RPC request to replica to start -listening to main with the given UUID. +If REPLICA was down at one point, MAIN could have changed. When REPLICA gets back up, coordinator will initiate an +RPC request (`SwapMainUUIDRpc` message), in order to set the UUID of the MAIN to which the REPLICA should listen to. -### Replication concerns +### Replication scenarios -#### Force sync of data +#### Force sync of data -During a failover event, Memgraph selects the most up-to-date, alive instance to -become the new main. The selection process works as follows: -1. From the list of available replica instances, Memgraph chooses the one with -the latest commit timestamp for the default database. -2. If an instance that had more recent data was down during this selection -process, it will not be considered for promotion to main. +We have outlined above how Memgraph +[selectes the most up-to-date alive instance](/clustering/concepts/how-high-availability-works#choosing-new-main-from-available-replicas). + +However, there might be another instance which might have had a more up-to-date state, but was down at the time of the failover process. +**This scenario is called force sync of REPLICA instance.** If a previously down instance had more up-to-date data but was unavailable during failover, it will go through a specific recovery process upon rejoining the cluster: -- The replica will reset its storage. -- The replica will receive all commits from the new main to +- The REPLICA will reset its storage. +- The REPLICA will receive all commits from the new main to synchronize its state. -- The replica's old durability files will be preserved in a `.old` directory in +- The REPLICA's old durability files will be preserved in a `.old` directory in `data_directory/snapshots` and `data_directory/wal` folders, allowing admins to manually recover data if needed. @@ -660,9 +313,13 @@ a non-zero Recovery Point Objective (RPO), that is, the loss of committed data, With `ASYNC` replication mode, you also risk losing some data upon the failover because main can freely continue commiting no matter the status of ASYNC replicas. -The `STRICT_SYNC` replication mode allows users experiencing a failover without any data loss +The `STRICT_SYNC` replication mode allows users experiencing a failover **without any data loss** in all situations. It comes with reduced throughput because of the cost of running two-phase commit protocol. + +Learn more about implications of [different replication modes](/clustering/concepts/how-replication-works/replication-modes). + + ## Actions on follower coordinators @@ -674,17 +331,20 @@ force resetting cluster state are all disabled. ### Data instances' restart -Data instances can fail both as main and as replica. When an instance that was replica comes back, it won't accept updates from any instance until the coordinator updates its -responsible peer. This should happen automatically when the coordinator's ping to the instance passes. When the main instance comes back, any writing to the main instance will be -forbidden until a ping from the coordinator passes. +Data instances can fail both as main and as replica. When an instance that was replica comes back, it will listen for +the MAIN instance based on the UUID provided from the coordinator (`SwapMainUUIDReq` message). +This should happen automatically when the coordinator's ping to the instance passes. When the main instance +comes back, any writing to the main instance will be forbidden until a ping from the coordinator passes +(`EnableWritingOnMainRpc` message). ### Coordinator instances restart -In case the coordinator instance dies and it is restarted, it will not lose any data from the RAFT log or RAFT snapshots, since coordinator data is always backed-up by a durable storage. -For more details read about high availability durability in the durability chapter. +In case the coordinator instance dies and it is restarted, it will not lose any data from the RAFT log or RAFT snapshots, +since coordinator data is always backed-up by a durable storage. +We talk more about this in the [RAFT implementation](#raft-implementation). -## Durability +## RAFT implementation All NuRaft data is made durable by default. This includes all Raft logs, Raft snapshots and information about cluster connectivity. The details about the cluster connectivity are made durable since without that information, the coordinator can't rejoin the cluster on its restart. @@ -699,7 +359,7 @@ the top-level `--data-directory` folder. When the coordinator rejoins, it will r On the first start of coordinators, each will store the current version of the `logs` and `network` durability store. From that point on, each RAFT log that is sent to the coordinator is also stored on disk. For every new coordinator instance, the server config is updated. Logs are created -for each user action and failover action. Snapshots are created every N (N currently being 5) logs. +for each user action and failover action. Snapshots are created every N (currently set to 5) logs. ### Restart of coordinator @@ -770,10 +430,4 @@ is a randomized value from the interval [2000ms, 4000ms] and which is used by fo expiration is set to 2000ms so that cluster can never get into situation where multiple leaders exist. These specific values give a cluster the ability to survive occasional network hiccups without triggering leadership changes. - -## Data center failure - -The architecture we currently use allows us to deploy coordinators in 3 data centers and hence tolerate a failure of the whole data center. Data instances can be freely -distributed in any way you want between data centers. The failover time will be slightly increased due to the network communication needed. - diff --git a/pages/clustering/concepts/querying-the-cluster-in-high-availability.mdx b/pages/clustering/concepts/querying-the-cluster-in-high-availability.mdx new file mode 100644 index 000000000..836ebfc33 --- /dev/null +++ b/pages/clustering/concepts/querying-the-cluster-in-high-availability.mdx @@ -0,0 +1,117 @@ +--- +title: Querying the cluster in high availability +description: Learn about the underlying implementation of routing throughout the cluster. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + + +# Querying the cluster in high availability (Enterprise) + + + +Please read the guides on [how replication works](/clustering/concepts/how-replication-works) and +[how high availability works](/clustering/concepts/how-high-availability-works) in Memgraph to get +introduced to the replication and high availability concepts. + + + +## Why bolt protocol is not enough? + +When we talk about standalone instances, the most straightforward way to connect is by using the `bolt://` protocol. +This is not optimal if you are running a cluster of Memgraph instances for multiple reasons: +1. Bolt protocol is a simple protocol for interacting with one instance. You need to connect to each instance separately in a cluster +in order to forward queries to that specific instance. We already have 5 instances in a typical Memgraph cluster with 2 data instances +and 3 coordinator instances. +3. You don't know which instance is MAIN due to automatic failovers which can happen at any time. If you issue a WRITE query to +a REPLICA, the query will fail as the REPLICA is not allowed to write. + +## Introducing bolt+routing + +Because of that, users can use the **Bolt + routing (`neo4j://`)** protocol, which ensures that write queries are always sent to +the current MAIN instance, and reads are routed arbitrarily to a MAIN or one of the REPLICAs. +This prevents split-brain scenarios, as clients never write to the old main but are automatically +routed to the new main after a failover. + +The routing protocol works as follows: +1. The client sends a `ROUTE` Bolt message to any coordinator instance +2. The coordinator responds with a **routing table** containing three entries: + - Instances from which data can be read (REPLICAs + optionally MAIN, depending on system configuration) + - The instance where data can be written (MAIN) + - Instances acting as routers (COORDINATORs) +3. Client proceeds by picking the correct route to forward the query again. + +When a client connects directly to the cluster leader, the leader immediately +returns the current routing table. Thanks to the Raft consensus protocol, the +leader always has the most up-to-date cluster state. If a follower receives a +routing request, it forwards the request to the current leader, ensuring the +client always gets accurate routing information. + +This ensures: + +- **Consistency**: All clients receive the same routing information, regardless of +their entry point. +- **Reliability**: The Raft consensus protocol ensures data accuracy on the leader +node. +- **Transparency**: Client requests are handled seamlessly, whether connected to +leaders or followers. + +On the image below, we can see the effect of executing a WRITE query with bolt+routing protocol on a coordinator. +The query is routed towards the MAIN instance. +![](/pages/clustering/high-availability/bolt_routing_writes.png) + +On the image below, we can see the effect of executing a READ query with bolt+routing protocol on a coordinator. +The query is routed towards the REPLICA instance. +![](/pages/clustering/high-availability/bolt_routing_reads.png) + +**Bolt+routing is a client-side routing protocol**, meaning network endpoint +resolution happens inside the database drivers. +For more details about the Bolt messages involved in the communication, check [the following +link](https://neo4j.com/docs/bolt/current/bolt/message/#messages-route). + + +Memgraph currently does not implement server-side routing. + + +Users only need to change the scheme they use for connecting to coordinators. +This means instead of using `bolt://,` you should use +`neo4j://` to get an active connection to the current +main instance in the cluster. You can find examples of how to use bolt+routing +in different programming languages +[here](https://github.com/memgraph/memgraph/tree/master/tests/drivers). + + + +**Bolt+routing protocol should only be used to connect to any of the coordinators in order to +execute data queries.** + +**Bolt+routing should not be used in order to setup the cluster (register coordinators and data instances).** +In that case, users should connect to COORDINATOR using the plain old `bolt` protocol. + + + +## Authentication + +User accounts exist exclusively on data instances - coordinators do not manage user authentication. Therefore, coordinator instances prohibit: + - Environment variables `MEMGRAPH_USER` and `MEMGRAPH_PASSWORD`. + - Authentication queries such as `CREATE USER`. + +When using the **bolt+routing protocol**, provide credentials for users that exist on the data instances. The authentication flow works as follows: + +1. Client connects to a **coordinator**. +2. Coordinator responds with the **routing table** (without authenticating). +3. Client connects to the **designated data instance** using the **same credentials**. +4. Data instance **authenticates the user and processes the request**. + +This architecture separates routing coordination from the user management, ensuring that authentication occurs only where user data resides. + + +1. You can connect to a coordinator via the bolt protocol without any authentication. +2. You need to pass in credentials when using bolt+routing protocol, as the authentication will be performed against + the respective data instance. + + + + diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx index da8c5cad9..23547164e 100644 --- a/pages/clustering/faq.mdx +++ b/pages/clustering/faq.mdx @@ -47,3 +47,9 @@ being received. + + +Validate license is correctly set +All the following queries can be run by querying directly coordinator 1, which we can conventionally assume to be the leader for the cluster. + +First, let’s validate that the license has been correctly set, by executing the following query: \ No newline at end of file diff --git a/pages/clustering/high-availability.mdx b/pages/clustering/high-availability.mdx index 2feb69b53..fc1453ee1 100644 --- a/pages/clustering/high-availability.mdx +++ b/pages/clustering/high-availability.mdx @@ -6,12 +6,13 @@ description: Dive into the documentation page for Memgraph and learn how to conf import { Callout } from 'nextra/components' import { CommunityLinks } from '/components/social-card/CommunityLinks' -# How to setup high availability with Memgraph (Eterprise) +# How to setup high availability with Memgraph (Enterprise) **Users are advised to first read the guide on [how replication works](/clustering/concepts/how-replication-works), followed -by the guide on [how high availability works](/clustering/concepts/how-high-availability-works)**. +by the guide on [how high availability works](/clustering/concepts/how-high-availability-works)**, and +how to [query the cluster](/clustering/concepts/querying-the-cluster-in-high-availability). @@ -24,9 +25,6 @@ Learn how to setup a high availability cluster with Docker Compose. ## [Setup HA cluster (Kubernetes)](/clustering/high-availability/setup-ha-cluster-k8s) Learn how to setup a high availability cluster with K8s and Helm Charts. -## [Querying the cluster](/clustering/high-availability/querying-the-cluster) -Learn how to query the cluster via the Bolt+routing protocol. - ## [Best practices](/clustering/high-availability/best-practices) Introduce yourselves to the advices we give you in order to run a reliable cluster with Memgraph. diff --git a/pages/clustering/high-availability/_meta.ts b/pages/clustering/high-availability/_meta.ts index 47919c1c3..0556a8494 100644 --- a/pages/clustering/high-availability/_meta.ts +++ b/pages/clustering/high-availability/_meta.ts @@ -2,7 +2,6 @@ export default { "setup-ha-cluster-docker": "Setup HA cluster with Docker", "setup-ha-cluster-docker-compose": "Setup HA cluster with Docker Compose", "setup-ha-cluster-k8s": "Setup HA cluster with K8s", - "querying-the-cluster": "Querying the cluster", "best-practices": "Best practices", "ha-commands-reference": "Reference commands", } diff --git a/pages/clustering/high-availability/best-practices.mdx b/pages/clustering/high-availability/best-practices.mdx index e3207e766..52c9c0efd 100644 --- a/pages/clustering/high-availability/best-practices.mdx +++ b/pages/clustering/high-availability/best-practices.mdx @@ -7,6 +7,230 @@ import { Callout } from 'nextra/components' # Best practices when setting up high availability -## How can I run data instances or coordinator instances? +## Hardware requirements -Depending on how configuration flags are set, Memgraph can run as a data instance or coordinator instance. +### Coordinator RAM space + +When deploying coordinators to servers, you can use the instance of almost any size. Instances of 4GiB or +8GiB will suffice since coordinators' job mainly involves network communication and storing Raft metadata. Coordinators +and data instances can in theory be deployed on same servers (pairwise) but from the availability perspective, it is +better to separate them physically. + +### Coordinator disk space + +When setting up disk space, you should always make sure that there is at least space for `--snapshot-retention-count+1` +snapshots + few WAL files. That's because we first create (N+1)th snapshot and then delete the oldest one so we +could guarantee that the creation of a new snapshot ended successfully. This is especially important when using Memgraph HA in +K8s, since in K8s there is usually a limit set on the disk space used. + +## Which command line flags should I set? + +### Data instance command line flags + +#### management port +The flag `--management-port` is a novelty with respect to a Memgraph standalone instance. It serves for the leader coordinator +to ping the health status of the data instance (`StateCheckRpc`). If you plan on using HA, then this flag needs to be configured. +Since the best advice is to set every data instance on its own machine, you can set each of the data instances' management port +to be identical for easier management. Setting this flag will create an RPC server on instances capable of responding +to the coordinator’s RPC messages. + + +**Example:** `--management-port=10000` + +#### storage wal enabled +The flag `--storage-wal-enabled` needs to be set to `true` (enforced by default, so no need to configure). +The flag controls whether WAL files will be created. WAL files are essential for replication, and it doesn't make sense to +run any replication / HA without the flag. Memgraph will make an exception if the cluster tries to register an instance with +`--storage-wal-enabled=false` + +**Example:** `--storage-wal-enabled=true` + +### Coordinator command line flags + +#### coordinator id +The flag `--cordinator-id` is a unique identifier of a coordinator. For each coordinator, set this to a different ID integer. + +**Example:** `--coordinator-id=1` for the first coordinator, +`--coordinator-id=2` for the second coordinator, and `--coordinator-id=3` for the third coordinator. + +#### coordinator port + +The flag `--coordinator-port` is used for synchronization and log replication between the coordinators. Consider using the +same identical port on every coordinator. + +**Example: `--coordinator-port=12000`** + +#### coordinator hostname + +`--coordinator-hostname` is used for followers to ping the leader coordinator on the correct IP address and return +the health state about the cluster. You can set this configuration flag to the IP address, the fully +qualified domain name (FQDN), or even the DNS name. The suggested approach is to use DNS, otherwise, in case the IP address changes, +network communication between instances in the cluster will stop working. + +If you're working with K8s especially, you should use DNS/FQDN, as the IP addresses are ephemeral. + +When testing on a local setup, the flag `--coordinator-hostname` should be set to `localhost` for each instance. + +#### management port + +The flag `--management-port` on the coordinator instance is used for the leader coordinator to get the health state from each of +the other coordinators. Advice is to always use the same management port on all the instances. Setting this flag will create +an RPC server on instances capable of responding to the coordinator’s RPC messages. + +**Example:** `--management-port=10000` + +#### instance health check frequency sec + +Flag `--instance-health-check-frequency-sec` is by default set to one second, meaning the coordinator will ping for the data instance +liveness every second. There is no specific need to change this behaviour. + +**Example:** `--instance-health-check-frequency-sec=1` + +#### instance down timeout sec + +Flag `--instance-down-timeout-sec` is by default set to 5, meaning after 5 seconds of not receiving a successful health check, the +data instance will be considered to be *down* by the coordinator. There is no specific need to change this behaviour. + +**Example:** `--instance-down-timeout-sec=1` + +### Health check behaviour + +Every `--instance-health-check-frequency-sec` seconds, the coordinator contacts each instance. +The instance is not considered to be down unless `--instance-down-timeout-sec` has passed and the instance hasn't responded to +the coordinator in the meantime. +Users must set `--instance-health-check-frequency-sec` to be less or equal to the `--instance-down-timeout-sec` but we advise +users to set `--instance-down-timeout-sec` to +a multiplier of `--instance-health-check-frequency-sec`. Set the multiplier coefficient to be N>=2. +For example, set `--instance-down-timeout-sec=5` and `--instance-health-check-frequency-sec=1` which will result in coordinator +contacting each instance every second and +the instance is considered dead after it doesn't respond 5 times (5 seconds / 1 second). + + +## Which environment variables should I use? + +There is an additional way to set high availability instances using environment variables. +It is important to say that for the following configuration options, **you can either use +environment variables or configuration flags**: + +- bolt port (`MEMGRAPH_BOLT_PORT`) +- coordinator port (`MEMGRAPH_COORDINATOR_PORT`) +- coordinator id (`MEMGRAPH_COORDINATOR_ID`) +- management port (`MEMGRAPH_MANAGEMENT_PORT`) +- path to nuraft log file (`MEMGRAPH_NURAFT_LOG_FILE`) +- coordinator hostname (`MEMGRAPH_COORDINATOR_HOSTNAME`) + +#### Data instances + +Here are the environment variables you need to use to set data instance using only environment variables: + +``` +export MEMGRAPH_MANAGEMENT_PORT=13011 +export MEMGRAPH_BOLT_PORT=7692 +``` + +When using any of these environment variables, flags `--bolt-port` and `--management-port` will be ignored. + + +#### Coordinator instances + +``` +export MEMGRAPH_COORDINATOR_PORT=10111 +export MEMGRAPH_COORDINATOR_ID=1 +export MEMGRAPH_BOLT_PORT=7687 +export MEMGRAPH_NURAFT_LOG_FILE="" +export MEMGRAPH_COORDINATOR_HOSTNAME="localhost" +export MEMGRAPH_MANAGEMENT_PORT=12121 +``` + +When using any of these environment variables, flags for `--bolt-port`, `--coordinator-port`, `--coordinator-id` and +`--coordinator-hostname` will be ignored. + + +There is an additional environment variable you can use to set the path to the file with cypher queries used to start a +high availability cluster. Here, you can use queries we define in the next chapter called User API. + +``` +export MEMGRAPH_HA_CLUSTER_INIT_QUERIES= +``` +After the coordinator instance is started, Memgraph will run queries one by one from this file to set up a high availability cluster. + + +You should either use the command line arguments, or the environment variables. Bear in mind that **environment variables +have precedence over command line arguments**, and any set environment variable will override the command line argument. + + + +## Coordinator settings + +### enabled reads on main + +There is a configuration option for specifying whether reads from the main are enabled. The configuration value is by +default false but can be changed in run-time using the following query: + +``` +SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false' ; +``` + +### sync failover only + +Users can also choose whether failover to the async replica is allowed by using the following query: + +``` +SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false' ; +``` + +### max failover replica lag + +Users can control the maximum transaction lag allowed during failover through configuration. If a replica is behind the main instance by more than the configured threshold, +that replica becomes ineligible for failover. This prevents data loss beyond the user's acceptable limits. + +To implement this functionality, we employ a caching mechanism on the cluster leader that tracks replicas' lag. The cache gets updated with each StateCheckRpc response from +replicas. During the brief failover window on the cooordinators' side, the new cluster leader may not have the current lag information for all data instances and in that case, +any replica can become main. This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety guarantees +in the large majority of situations. + + +The configuration value can be controlled using the query: + +``` +SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10' ; +``` + +By default, the value is `true`, which means that only sync replicas are candidates in the election. When the value is set to `false`, the async replica is also considered, but +there is an additional risk of experiencing data loss. However, failover to an async replica may be necessary when other sync replicas are down and you want to +manually perform a failover. + +### max_replica_read_lag_ ??? + + +Users can control the maximum allowed replica lag to maintain read consistency. When a replica falls behind the current main by more than `max_replica_read_lag_` transactions, the +bolt+routing protocol will exclude that replica from read query routing to ensure data freshness. + +The configuration value can be controlled using the query: + +``` +SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10' ; +``` + +## Observability + +Monitoring the cluster state is very important and tracking various metrics can provide us with a valuable information. +Some of the important metrics that we collect on the cluster level are: +- latencies RPC messages (p50, p90 and p99) +- duration of the recovery process +- time needed to react to changes in the cluster +- number of different RPC messages exchanged +- number of failed requests + +and many more. + +The aforementioned metrics are contained inside Memgraph's system metrics, which are available as a part of Memgraph Enterprise Edition. +Memgraph exposes an HTTP port for these system metrics, and also offers a [Prometheus exporter](https://github.com/memgraph/prometheus-exporter) +in order to forward these system metrics to Prometheus. The Prometheus exporter is also [enabled for helm charts, and can be configured within +the values file](https://github.com/memgraph/helm-charts/blob/main/charts/memgraph-high-availability/values.yaml). +You can see the full list of metrics [on the system metrics monitoring page](/database-management/monitoring#system-metrics). + +## Data center failure + +The architecture we currently use allows us to deploy coordinators in 3 data centers and hence tolerate a failure of the whole data center. Data instances can be freely +distributed in any way you want between data centers. The failover time will be slightly increased due to the network communication needed. diff --git a/pages/clustering/high-availability/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx index 84def6991..abc616039 100644 --- a/pages/clustering/high-availability/ha-commands-reference.mdx +++ b/pages/clustering/high-availability/ha-commands-reference.mdx @@ -10,337 +10,171 @@ import {CommunityLinks} from '/components/social-card/CommunityLinks' This page provides a comprehensive reference for all commands available in Memgraph's high availability cluster management. -## Cluster setup commands +## User API -### ADD COORDINATOR +### Register instance -Adds a coordinator instance to the cluster. +Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. -```cypher -ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer, "management_server": managementServer}; -``` - -**Parameters:** -- `coordinatorId` (integer): Unique identifier for the coordinator -- `bolt_server` (string): External bolt server endpoint for client connections -- `coordinator_server` (string): Server endpoint for Raft communication -- `management_server` (string): Server endpoint for health checks and cluster management - -**Example:** -```cypher -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; -``` - - -This command needs to be run for all coordinators in the cluster. The order of adding coordinators and data instances doesn't matter. - - -### REGISTER INSTANCE - -Registers a data instance to the cluster. +Register instance query will result in several actions: +1. The coordinator instance will connect to the data instance on the `management_server` network address. +2. The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. +3. Data instance will be demoted from main to replica. +4. Data instance will start the replication server on `replication_server`. -```cypher +```plaintext REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; ``` -**Parameters:** -- `instanceName` (string): Unique name for the data instance -- `AS ASYNC | AS STRICT_SYNC` (string, optional): Optional replication mode (defaults to SYNC) -- `bolt_server` (string): External bolt server endpoint -- `management_server` (string): Server endpoint for coordinator communication -- `replication_server` (string): Server endpoint for data replication - -**Replication modes:** -- `ASYNC`: Asynchronous replication (fastest, potential data loss) -- `SYNC`: Synchronous replication (balanced, minimal data loss) -- `STRICT_SYNC`: Strict synchronous replication (slowest, no data loss) - -**Example:** -```cypher -REGISTER INSTANCE instance_1 AS SYNC WITH CONFIG {"bolt_server": "localhost:7687", "management_server": "instance1:13011", "replication_server": "instance1:10001"}; -``` - -## Instance management commands +This operation will result in writing to the Raft log. -### SET INSTANCE TO MAIN +In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. Constructs ( AS ASYNC | AS STRICT_SYNC ) serve to specify +instance's replication mode when the instance behaves as replica. You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` +and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. -Promotes a data instance to become the main (writable) instance. -```cypher -SET INSTANCE instanceName TO main; -``` +### Add coordinator instance -**Parameters:** -- `instanceName` (string): Name of the instance to promote +The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, +the order isn't important. -**Behavior:** -- Registers all other instances as replicas to the new main -- Fails if the target instance is unavailable -- Fails if there's already a main instance in the cluster -- Results in writing to the Raft log - -**Example:** -```cypher -SET INSTANCE instance_3 TO main; -``` - -### DEMOTE INSTANCE - -Demotes the current main instance to replica status. - -```cypher -DEMOTE INSTANCE instanceName; +```plaintext +ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer}; ``` -**Parameters:** -- `instanceName` (string): Name of the instance to demote - -**Behavior:** -- Manually demotes the main instance to replica -- Requires manual promotion of another instance to main -- Results in writing to the Raft log - -Combining `DEMOTE INSTANCE` and `SET INSTANCE TO MAIN` provides manual failover capability, useful during maintenance work. - -### UNREGISTER INSTANCE +`ADD COORDINATOR` query needs to be run for all coordinators in the cluster. -Removes a data instance from the cluster. - -```cypher -UNREGISTER INSTANCE instanceName; ``` - -**Parameters:** -- `instanceName` (string): Name of the instance to remove - -**Requirements:** -- The instance being unregistered must NOT be the main instance -- The cluster must have an alive main instance during unregistration -- The instance will be removed from the current main's replica set - -**Example:** -```cypher -UNREGISTER INSTANCE instance_2; +ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; +ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "127.0.0.1:7692", "coordinator_server": "127.0.0.1:10112", "management_server": "127.0.0.1:12112"}; +ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "127.0.0.1:7693", "coordinator_server": "127.0.0.1:10113", "management_server": "127.0.0.1:12113"}; ``` -### REMOVE COORDINATOR - -Removes a coordinator instance from the cluster. - -```cypher -REMOVE COORDINATOR coordinatorId; -``` + -**Parameters:** -- `coordinatorId` (integer): ID of the coordinator to remove +### Remove coordinator instance -**Restrictions:** -- Can only be executed on the leader coordinator -- Cannot remove the current leader (prohibited by NuRaft) -- To remove the current leader, first trigger a leadership change +If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, `REMOVE COORDINATOR` query can be used. +Only on leader can this query be executed in order to remove followers. Current cluster's leader cannot be removed since this is prohibited +by NuRaft. In order to remove the current leader, you first need to trigger leadership change. -**Example:** -```cypher -REMOVE COORDINATOR 2; +```plaintext +REMOVE COORDINATOR ; ``` -## Cluster state management -### FORCE RESET CLUSTER STATE +### Set instance to main -Forces a reset of the cluster state when the cluster gets stuck. +Once all data instances are registered, one data instance should be promoted to main. This can be achieved by using the following query: -```cypher -FORCE RESET CLUSTER STATE; +```plaintext +SET INSTANCE instanceName to main; ``` -**Actions performed:** -1. Demotes each alive instance to replica -2. Chooses a new main instance from alive instances -3. Instances that are down will be demoted to replicas when they come back up - -**Usage:** -- Execute on the leader coordinator -- Results in writing to the Raft log -- Use only when the cluster is in an inconsistent state +This query will register all other instances as replicas to the new main. If one of the instances is unavailable, setting the instance to main will not succeed. +If there is already a main instance in the cluster, this query will fail. -## Monitoring and information commands - -### SHOW INSTANCES - -Displays the state of all instances in the cluster. - -```cypher -SHOW INSTANCES; -``` +This operation will result in writing to the Raft log. -**Information displayed:** -- Network endpoints for cluster management -- Health state of each server -- Role (main, replica, LEADER, FOLLOWER, or unknown) -- Time since last response to leader's health ping +### Demote instance -**Behavior:** -- Can be run on leader or followers -- Followers forward the request to the leader for accurate information -- If leader is unavailable, followers return instances with "down" health state +Demote instance query can be used by an admin to demote the current main to replica. In this case, the leader coordinator won't perform a failover, but as a user, +you should choose promote one of the data instances to main using the `SET INSTANCE `instance` TO main` query. -**Example output:** -``` -| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | -| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | -| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | -| instance_1 | localhost:7687 | "" | localhost:13011 | up | replica | 39 | -| instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | +```plaintext +DEMOTE INSTANCE instanceName; ``` -### SHOW INSTANCE +This operation will result in writing to the Raft log. -Shows information about the current coordinator instance. + -```cypher -SHOW INSTANCE; -``` +By combining the functionalities of queries `DEMOTE INSTANCE instanceName` and `SET INSTANCE instanceName TO main` you get the manual failover capability. This can be useful +e.g during a maintenance work on the instance where the current main is deployed. -**Information returned:** -- Instance name -- External bolt server endpoint -- Coordinator server for Raft communication -- Management server for inter-coordinator communication -- Cluster role (leader or follower) + -**Note:** If `ADD COORDINATOR` wasn't run for the current instance, the bolt server value will be empty. -### SHOW REPLICATION LAG +### Unregister instance -Displays the current replication lag for each instance. +There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. The hardware can be broken, +network communication could be set up incorrectly, etc. The user can remove the instance from the cluster using the following query: -```cypher -SHOW REPLICATION LAG; +```plaintext +UNREGISTER INSTANCE instanceName; ``` -**Information provided:** -- Replication lag expressed as number of committed transactions -- Made durable through snapshots and WALs -- Useful for manual failover to check data loss risk - -**Usage:** -- Run on the cluster's leader -- Helps assess data consistency before failover operations +When unregistering an instance, ensure that the instance being unregistered is +**not** the main instance. Unregistering main can lead to an inconsistent +cluster state. Additionally, the cluster must have an **alive** main instance +during the unregistration process. If no main instance is available, the +operation cannot be guaranteed to succeed. -## Configuration commands +The instance requested to be unregistered will also be unregistered from the current main's replica set. -### SET COORDINATOR SETTING +### Force reset cluster state -Configures various cluster settings at runtime. +In case the cluster gets stuck there is an option to do the force reset of the cluster. You need to execute a command on the leader coordinator. +This command will result in the following actions: -#### Enable reads on main +1. The coordinator instance will demote each alive instance to replica. +2. From the alive instance it will choose a new main instance. +3. Instances that are down will be demoted to replicas once they come back up. -```cypher -SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false'; -``` - -**Parameters:** -- `'enabled_reads_on_main'` (string): Setting name -- `'true'/'false'` (string): Boolean value as string - -Controls whether read queries are allowed on the main instance (default: false). - -#### Sync failover only - -```cypher -SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false'; +```plaintext +FORCE RESET CLUSTER STATE; ``` -**Parameters:** -- `'sync_failover_only'` (string): Setting name -- `'true'/'false'` (string): Boolean value as string - -Controls whether failover to async replicas is allowed (default: true). - -#### Maximum failover replica lag - -```cypher -SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10'; -``` +This operation will result in writing to the Raft log. -**Parameters:** -- `'max_failover_replica_lag'` (string): Setting name -- `'10'` (string): Numeric value as string representing transaction count +### Show instances -Sets the maximum transaction lag allowed during failover. Replicas behind by more than this threshold become ineligible for failover. +You can check the state of the whole cluster using the `SHOW INSTANCES` query. The query will display all the Memgraph servers visible in the cluster. With +each server you can see the following information: + 1. Network endpoints they are using for managing cluster state + 2. Health state of server + 3. Role - main, replica, LEADER, FOLLOWER or unknown if not alive + 4. The time passed since the last response time to the leader's health ping -#### Maximum replica read lag +This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state and last response time, +followers will execute actions in this exact order: + 1. Try contacting the leader to get the health state of the cluster, since the leader has all the information. + If the leader responds, the follower will return the result as if the `SHOW INSTANCES` query was run on the leader. + 2. When the leader doesn't respond or currently there is no leader, the follower will return all the Memgraph servers + with the health state set to "down". -```cypher -SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10'; +```plaintext +SHOW INSTANCES; ``` -**Parameters:** -- `'max_replica_read_lag_'` (string): Setting name -- `'10'` (string): Numeric value as string representing transaction count - -Controls the maximum allowed replica lag for read consistency. Replicas behind by more than this threshold are excluded from read query routing. -### SHOW COORDINATOR SETTINGS +### Show instance -Displays all current coordinator configuration settings. +You can check the state of the current coordinator to which you are connected by running the following query: -```cypher -SHOW COORDINATOR SETTINGS; +```plaintext +SHOW INSTANCE; ``` -Returns all runtime configuration options and their current values. - -## Connection and routing +This query will return the information about: +1. instance name +2. external bolt server to which you can connect using Memgraph clients +3. coordinator server over which Raft communication is done +4. management server which is also used for inter-coordinators communication and +5. cluster role: whether the coordinator is currently a leader of the follower. -### Bolt+routing protocol +If the query `ADD COORDINATOR` wasn't run for the current instance, the value of the bolt server will be "". -When using high availability, connect to coordinators using the `neo4j://` scheme instead of `bolt://`: +### Show replication lag -**Standard connection:** -``` -bolt:// -``` +The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. The replication lag is expressed with +the number of committed transactions. Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. The information +about the replication lag can be useful when manually performing a failover to check whether there is a risk of a data loss. -**HA connection with routing:** -``` -neo4j:// +```plaintext +SHOW REPLICATION LAG; ``` -**Benefits:** -- Automatic routing to current main instance -- Prevents split-brain scenarios -- Seamless failover handling -- Write queries always go to the current main -- Read queries can be distributed across replicas - - -Cluster setup commands (registration, coordinator management) must be done using standard `bolt://` connections, not `neo4j://` routing connections. - - -## Best practices - -### Command execution order - -1. **Start all instances** (coordinators and data instances) -2. **Add coordinators** to the cluster -3. **Register data instances** to the cluster -4. **Set one instance as main** -5. **Verify cluster state** with `SHOW INSTANCES` - -### Health monitoring - -- Use `SHOW INSTANCES` regularly to monitor cluster health -- Check `SHOW REPLICATION LAG` before manual failovers -- Monitor coordinator settings with `SHOW COORDINATOR SETTINGS` - -### Failover considerations - -- Use `SHOW REPLICATION LAG` to assess data loss risk -- Consider replication modes when planning failovers -- Test failover procedures in non-production environments - diff --git a/pages/clustering/high-availability/querying-the-cluster.mdx b/pages/clustering/high-availability/querying-the-cluster.mdx deleted file mode 100644 index be0a8d546..000000000 --- a/pages/clustering/high-availability/querying-the-cluster.mdx +++ /dev/null @@ -1,275 +0,0 @@ ---- -title: Querying the cluster -description: Learn how to query Memgraph high availability clusters using the bolt+routing protocol with automatic failover and load balancing. ---- - -import { Callout } from 'nextra/components' -import {CommunityLinks} from '/components/social-card/CommunityLinks' - -# Querying the cluster - -The bolt+routing protocol is Memgraph's solution for connecting to high availability clusters. It automatically routes queries to the appropriate instances and handles failover seamlessly, ensuring your applications remain connected even when cluster topology changes. - -## Overview - -In a high availability cluster, directly connecting to the main instance isn't recommended because the main instance can change due to various failures. The bolt+routing protocol solves this by providing intelligent routing that: - -- **Automatically routes write queries** to the current main instance -- **Distributes read queries** across available replicas -- **Handles failover** without application changes -- **Prevents split-brain scenarios** by ensuring clients never write to old main instances - -## How bolt+routing works - -### Connection flow - -1. **Client connects** to any coordinator instance using `neo4j://` scheme -2. **Coordinator responds** with a routing table containing: - - Instances from which data can be read - - The instance where data can be written - - Instances acting as routers -3. **Client uses routing table** to direct subsequent queries appropriately - -### Routing table structure - -The routing table contains three types of entries: - -| Entry Type | Description | Usage | -|------------|-------------|-------| -| **Read instances** | Replica instances available for read queries | Load balancing read operations | -| **Write instance** | Current main instance for write queries | All write operations | -| **Router instances** | Coordinator instances for routing requests | Future routing requests | - -## Connection strings - -### Standard vs HA connections - -**Standard connection (single instance):** -``` -bolt://: -``` - -**HA connection with routing:** -``` -neo4j://: -``` - -### Connection examples - -```javascript -// Standard connection -const driver = neo4j.driver("bolt://localhost:7687", auth); - -// HA connection with routing -const driver = neo4j.driver("neo4j://localhost:7691", auth); -``` - -## Client-side routing - -Bolt+routing is a **client-side routing protocol**, meaning network endpoint resolution happens inside the drivers. This provides several benefits: - -- **Transparent failover**: Applications don't need to handle connection changes -- **Automatic load balancing**: Read queries are distributed across replicas -- **Consistent routing**: All clients receive the same routing information -- **Reliability**: Raft consensus ensures accurate routing data - -## Cluster roles and routing - -### Instance roles in routing - -| Role | Function | Query Types | -|------|----------|-------------| -| **Main instance** | Primary writable instance | Write queries only (by default) | -| **Replica instances** | Read-only instances | Read queries | -| **Coordinator instances** | Routing and cluster management | Routing requests only | - -### Routing behavior - -- **Write queries**: Always routed to the current main instance -- **Read queries**: Distributed across available replica instances -- **Routing requests**: Handled by coordinator instances -- **Failover**: Automatic promotion of replica to main when needed - -## Configuration options - -### Enable reads on main - -By default, the main instance only handles write queries. You can enable read queries on the main instance: - -```cypher -SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'; -``` - -**Parameters:** -- `'enabled_reads_on_main'` (string): Setting name -- `'true'` (string): Enable reads on main instance - -### Replica read lag control - -Control the maximum allowed replica lag for read consistency: - -```cypher -SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10'; -``` - -**Parameters:** -- `'max_replica_read_lag_'` (string): Setting name -- `'10'` (string): Maximum transaction lag as string - -**Behavior:** -- Replicas behind by more than this threshold are excluded from read routing -- Ensures data freshness for read operations - -## Connection examples by language - -### Python - -```python -from neo4j import GraphDatabase - -# HA connection -driver = GraphDatabase.driver("neo4j://localhost:7691", auth=("username", "password")) - -# Use the driver normally - routing is handled automatically -with driver.session() as session: - result = session.run("MATCH (n) RETURN count(n)") - print(result.single()[0]) -``` - -### JavaScript/Node.js - -```javascript -const neo4j = require('neo4j-driver'); - -// HA connection -const driver = neo4j.driver("neo4j://localhost:7691", - neo4j.auth.basic("username", "password")); - -// Use the driver normally -const session = driver.session(); -session.run("MATCH (n) RETURN count(n)") - .then(result => console.log(result.records[0].get(0))); -``` - -### Java - -```java -import org.neo4j.driver.*; - -// HA connection -Driver driver = GraphDatabase.driver("neo4j://localhost:7691", - AuthTokens.basic("username", "password")); - -// Use the driver normally -try (Session session = driver.session()) { - Result result = session.run("MATCH (n) RETURN count(n)"); - System.out.println(result.single().get(0)); -} -``` - -### C# - -```csharp -using Neo4j.Driver; - -// HA connection -using var driver = GraphDatabase.Driver("neo4j://localhost:7691", - AuthTokens.Basic("username", "password")); - -// Use the driver normally -using var session = driver.Session(); -var result = session.Run("MATCH (n) RETURN count(n)"); -Console.WriteLine(result.Single()[0]); -``` - -## Best practices - -### Connection management - -1. **Use connection pooling**: Most drivers provide built-in connection pooling -2. **Handle connection failures**: Implement retry logic for transient failures -3. **Monitor connection health**: Use driver health check features when available - -### Query optimization - -1. **Use read replicas**: Distribute read queries across replicas for better performance -2. **Minimize cross-database queries**: Keep queries within the same database when possible -3. **Use appropriate transaction types**: Read transactions for queries, write transactions for modifications - -### Error handling - -```python -from neo4j import GraphDatabase -from neo4j.exceptions import ServiceUnavailable - -def execute_with_retry(driver, query, max_retries=3): - for attempt in range(max_retries): - try: - with driver.session() as session: - return session.run(query) - except ServiceUnavailable as e: - if attempt == max_retries - 1: - raise e - time.sleep(2 ** attempt) # Exponential backoff -``` - -## Troubleshooting - -### Common issues - -**Connection refused errors:** -- Verify coordinator instances are running -- Check firewall settings for coordinator ports -- Ensure proper network connectivity - -**Routing table errors:** -- Verify cluster state with `SHOW INSTANCES` -- Check coordinator health and leadership -- Ensure proper cluster configuration - -**Query routing issues:** -- Verify instance roles (main/replica) -- Check replication lag settings -- Monitor cluster health metrics - -### Debugging connections - -1. **Check cluster state:** - ```cypher - SHOW INSTANCES; - ``` - -2. **Verify coordinator settings:** - ```cypher - SHOW COORDINATOR SETTINGS; - ``` - -3. **Monitor replication lag:** - ```cypher - SHOW REPLICATION LAG; - ``` - -## Limitations and considerations - -### Cluster setup restrictions - -- **Setup commands must use bolt://**: Cluster management commands (registration, coordinator setup) require direct `bolt://` connections -- **Routing only for data queries**: `neo4j://` connections only handle data-oriented queries, not cluster management - -### Network requirements - -- **Stable network**: Requires reliable network connectivity between instances -- **Port accessibility**: All coordinator and data instance ports must be accessible -- **DNS resolution**: Use DNS names instead of IP addresses for better reliability - -### Performance considerations - -- **Routing overhead**: Small additional latency for routing table requests -- **Connection pooling**: May need to adjust pool sizes for HA workloads -- **Load balancing**: Read distribution depends on replica availability - - -For detailed examples of bolt+routing usage in different programming languages, check the [Memgraph drivers repository](https://github.com/memgraph/memgraph/tree/master/tests/drivers). - - - diff --git a/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx index 3397a1b1c..52f9511ac 100644 --- a/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx +++ b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx @@ -205,20 +205,6 @@ networks: - subnet: "172.21.0.0/16" ``` -### Validate license is correctly set - -All the following queries can be run by querying directly coordinator 1, which we can conventionally -assume to be the leader for the cluster. - -First, let's validate that the license has been correctly set, by executing the following query: - -``` -SHOW LICENSE INFO; -``` - -```nocopy -``` - ### Register the coordinator instances Next, we proceed first by registering all the coordinators in the cluster. @@ -246,14 +232,6 @@ ADD COORDINATOR 3 WITH CONFIG { }; ``` -We can see the state of the cluster by executing the following query: -``` -SHOW INSTANCES -``` - -```nocopy -``` - We observe that there is indeed one leader and two followers in the cluster: ### Register the data instances @@ -293,14 +271,23 @@ By issuing again the command: SHOW INSTANCES; ``` -We can observe that there is indeed one MAIN instance and 2 REPLICA instances: +We can observe that there is indeed one MAIN instance, 2 REPLICA instances, 1 leader coordinator, and 2 follower +coordinators in the cluster: ```nocopy +| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | +| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | +| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | +| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 16 | +| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 25 | +| instance_1 | localhost:7687 | "" | localhost:13011 | up | replica | 39 | +| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 21 | +| instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | ``` + +For localhost development: Since the host can't resolve the IP for coordinators and data instances, Bolt -servers in Docker Compose setup require `bolt_server` set to `localhost:`. - -Cluster can be shut-down using `docker compose down`. - +servers in Docker Compose setup require `bolt_server` set to `localhost:`. ??? + \ No newline at end of file diff --git a/pages/clustering/high-availability/setup-ha-cluster-docker.mdx b/pages/clustering/high-availability/setup-ha-cluster-docker.mdx index f1a4ec9b7..063229874 100644 --- a/pages/clustering/high-availability/setup-ha-cluster-docker.mdx +++ b/pages/clustering/high-availability/setup-ha-cluster-docker.mdx @@ -177,7 +177,9 @@ REGISTER INSTANCE instance_3 WITH CONFIG { SET INSTANCE instance_3 TO MAIN; ``` -5. Connect to the leader coordinator and check cluster state with `SHOW INSTANCES`; +### Check cluster state + +Connect to the leader coordinator and check cluster state with `SHOW INSTANCES`; | name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | | ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ---------------- | @@ -188,18 +190,4 @@ SET INSTANCE instance_3 TO MAIN; | instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 21 | | instance_3 | localhost:7689 | "" | localhost:13013 | up | main | 91 | -### Check automatic failover - -Let's say that the current main instance is down for some reason. After `--instance-down-timeout-sec` seconds, the coordinator will realize -that and automatically promote the first alive replica to become the new main. The output of running `SHOW INSTANCES` on the leader coordinator could then look like: - -| name | bolt_server | coordinator_server | management_server | health | role | last_succ_resp_ms | -| ------------- | -------------- | ------------------ | ----------------- | ------ | -------- | ------------------| -| coordinator_1 | localhost:7691 | localhost:10111 | localhost:12121 | up | leader | 0 | -| coordinator_2 | localhost:7692 | localhost:10112 | localhost:12122 | up | follower | 34 | -| coordinator_3 | localhost:7693 | localhost:10113 | localhost:12123 | up | follower | 28 | -| instance_1 | localhost:7687 | "" | localhost:13011 | up | main | 61 | -| instance_2 | localhost:7688 | "" | localhost:13012 | up | replica | 74 | -| instance_3 | localhost:7689 | "" | localhost:13013 | down | unknown | 71222 | - diff --git a/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx b/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx index ab99b6431..46e69231f 100644 --- a/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx +++ b/pages/clustering/high-availability/setup-ha-cluster-k8s.mdx @@ -8,11 +8,469 @@ import { Steps } from 'nextra/components' # Setup high availability cluster with K8s (Enterprise) + +**Users are advised to first read the guide on [how replication works](/clustering/concepts/how-replication-works), followed +by the guide on [how high availability works](/clustering/concepts/how-high-availability-works)**, and +how to [query the cluster](/clustering/concepts/querying-the-cluster-in-high-availability). + + +### Installing the Memgraph HA Helm chart + +To include Memgraph HA cluster as a part of your Kubernetes cluster, you need to +[add the repository](#add-the-repository-1) and [install +Memgraph](#install-memgraph-ha). + +#### Add the repository + +Add the Memgraph Helm chart repository to your local Helm setup by running the +following command: + +``` +helm repo add memgraph https://memgraph.github.io/helm-charts +``` + +Make sure to update the repository to fetch the latest Helm charts available: + +``` +helm repo update +``` + +#### Install Memgraph HA + +Since Memgraph HA requires an [Enterprise license](/database-management/enabling-memgraph-enterprise), you need to provide the license and organization name during the installation. + +``` +helm install memgraph/memgraph-high-availability --set env.MEMGRAPH_ENTERPRISE_LICENSE=,env.MEMGRAPH_ORGANIZATION_NAME= +``` + +Replace `` with a name of your choice for the release and set the +Enterprise license. + + + +When installing a chart, it's best practice to specify the exact version you +want to use. Using the latest tag can lead to issues, as a pod restart may pull +a newer image, potentially causing unexpected changes or incompatibilities. + + +### Install Memgraph HA chart with `minikube` + +If you are installing Memgraph HA chart locally with `minikube`, we are strongly recommending to enable `csi-hostpath-driver` and use its storage class. Otherwise, +you could have problems with attaching PVCs to pods. + +1. Enable `csi-hostpath-driver` +``` +minikube addons disable storage-provisioner +minikube addons disable default-storageclass +minikube addons enable volumesnapshots +minikube addons enable csi-hostpath-driver +``` + +2. Create a storage class with `csi-hostpath-driver` as a provider (file sc.yaml) + +``` +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: csi-hostpath-delayed +provisioner: hostpath.csi.k8s.io +volumeBindingMode: WaitForFirstConsumer +reclaimPolicy: Delete +``` + +3. `kubectl apply -f sc.yaml` + +4. Set `libStorageClassName` to `csi-hostpath-delayed` in `values.yaml` + + +### Changing the default chart values + +To change the default chart values, run the command with the specified set of +flags: +``` +helm install memgraph/memgraph-high-availability --set =,=,... +``` +Or you can modify a `values.yaml` file and override the desired values: +``` +helm install memgraph/memgraph-high-availability -f values.yaml +``` + +### Upgrade Helm chart + +To upgrade the helm chart you can use: +``` +helm upgrade memgraph/memgraph-high-availability --set =,= +``` + +Again it is possible use both `--set` and values.yaml to set configuration options. + +If you're using `IngressNginx` and performing an upgrade, the attached public IP +should remain the same. It will only change if the release includes specific +updates that modify it—and such changes will be documented. + + +### Uninstall Helm chart + +Uninstallation is done with: + +``` +helm uninstall +``` + +Uninstalling the chart won't trigger deletion of persistent volume claims (PVCs) which means that even if the reclaim policy of the default storage class is set to 'Delete' +(which often is), the data from persistent volumes (PVs) won't be lost. However, we advise users to set the reclaim policy to 'Retain' as suggested in the +[Storage chapter](#high-availability-storage). + +### Security context + +All instances are started as `StatefulSet` with one pod. The pod has two or three containers depending on whether the sysctlInitContainer.enabled is used. The **memgraph-coordinator** container is the one which +actually runs Memgraph image. The process is run by non-root **memgraph** user without any Linux capabilities. Privileges cannot escalate. + +### High availability storage + +Memgraph HA chart will always use persistent volume claims (PVCs) for storing data and logs. By default they will use **1Gi** so most likely you will need to set this parameter to a +higher value. Access mode is by default set to `ReadWriteOnce` (RWO) and can be changed to one of values: `ReadWriteOnce`, `ReadOnlyMany`, `ReadWriteMany` and +`ReadWriteOncePod`. All PVCs will use a default storage class. You can use parameters `libStorageClassName` and `logStorageClassName` to specify which storage classes will +be used for storing data and logs on data and coordinator instances. Default storage classes usually have a reclaim policy set to `Delete` which means that if you delete PVCs, +attached PVs will also get deleted. We advise users to set the reclaim policy to `Retain` One of the ways to achieve this is to run the following script after starting your cluster: + +```bash +#!/bin/bash + +# Get all Persistent Volume names +PVS=$(kubectl get pv --no-headers -o custom-columns=":metadata.name") + +# Loop through each PV and patch it +for pv in $PVS; do + echo "Patching PV: $pv" + kubectl patch pv $pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' +done + +echo "All PVs have been patched." +``` + + +Kubernetes uses a concept called "Storage Object in Use Protection", which +delays the deletion of PersistentVolumeClaims (PVCs) until the pods using them +are deleted. Similarly, PersistentVolumes (PVs) won't be deleted until their +associated PVCs are removed. + +If PVC deletion is stuck, you can try removing its finalizers by running: + +```bash +kubectl patch pvc PVC_NAME -p '{"metadata":{"finalizers": []}}' --type=merge +``` + + +### Network configuration + +All instances which are part of Memgraph HA cluster use the internal Cluster IP network for communicating between themselves. By default, management port is on all instances opened on +10000, replication port on data instances is opened on 20000 while coordinator port is opened on 12000. You can change this configuration by specifying `ports.managementPort`, +`ports.replicationPort` and `ports.coordinatorPort`. + +#### External network configuration + +Since Memgraph HA works with client-side routing, the resolution of all DNS entries happens outside internal Cluster IP network. Because of that, we need one more type of network +which will be used for clients accessing instances inside the cluster. + +- `IngressNginx`: Using only one load balancer you can access all instances from outside. +- `NodePort`: The cheapest option because it will open port on each node. For this to work, you need to enable public IPs on each node. +- `LoadBalancer`: This option will use one load balancer for each instance in the cluster. Load balancer is mostly interesting here because it comes with public IP out of the box. + +For coordinators, there is an additional option of using `CommonLoadBalancer`. In this scenario, there is one load balancer sitting in front of coordinators. You can save the cost +of two load balancers compared to `LoadBalancer` option since usually you don't need to distinguish specific coordinators while using Memgraph capabilities. The default Bolt port +is opened on 7687 but you can change it by setting `ports.boltPort`. + +Read more in the [guide](#using-memgraph-ha-chart-with-ingressnginx-resource) for installing Memgraph HA with `IngressNginx`. + +By default, no configuration is provided for external network access so users can customize their settings in an easier manner. + +### Node affinity + +Since HA Memgraph deploys multiple pods, you can control on which nodes pods get +distributed in the cluster. + +The Memgraph HA Helm chart provides the following node affinity options: + +- `default`: Default affinity will try to schedule the data pods and + coordinator pods on the nodes where there is no other pod with the same role. + If there is no such node, the pods will still be scheduled on the same node, + and deployment will not fail. +- `unique`: This is achieved with the `affinity.unique` set to `true`. + This option will try to deploy the data pods and coordinator pods on different + nodes in the cluster so that each pod is on a unique node. If there are no + sufficient nodes, this deployment will fail. +- `parity`: This is achieved with the `affinity.parity` set to `true`. + This option will try to deploy the data pods and coordinator pods on the same node + with maximum one coordinator and one data pod on the node. If there are no + sufficient nodes to deploy the pods, this deployment will fail. Coordinators + get scheduled first. After that, data pods are looking for the nodes with + coordinators. +- `nodeSelection`: This is achieved with the `affinity.nodeSelection` + set to `true`. This option will try to deploy the data pods and coordinator + pods on the nodes with specific labels. You can set the labels with the + `affinity.dataNodeLabelValue` and + `affinity.coordinatorNodeLabelValue` parameters. If all the nodes + with labels are occupied by the pods with the same role, the deployment will + fail. + + +During the usage of `nodeSelection` affinity, make sure that the nodes are +properly labeled, the default key for the role label is `role`, and default +values are `data-node` and `coordinator-node`. Labels can be added to nodes +using the `kubectl label nodes =` command. +[Here](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-high-availability/aks) +is an example of how to deploy Memgraph HA cluster in AKS. + + + +### Sysctl options + +You can use `sysctlInitContainer` configuration parameter to [increase the `vm_max_map_count`](/database-management/system-configuration#increasing-memory-map-areas) which is necessary for high memory loads in Memgraph. + + +### Authentication + +By default, there is no user or password configured for Memgraph instances. You can use `secrets` configuration parameter +to create the user with the password. The secret can be created in the following way: + +``` +kubectl create secret generic memgraph-secrets --from-literal=USER=memgraph --from-literal=PASSWORD=memgraph +``` + +The same user will then be created on all coordinator and data instances through Memgraph's environment variables. + +### Setting up the cluster + +Although there are many configuration options you can use to set up HA cluster (especially for networking), the set-up process +stays always the same: + +**1.** Provision the cluster + +**2.** Label nodes based on the affinity strategy + +**3.** Install `memgraph/memgraph-high-availability` chart using `helm install` + +**4.** Install any other auxiliary resources, e.g `ingress-nginx` if you are using that type of external network configuration. + +**5.** Connect instances to form the cluster + +The last step, connecting instances, needs to be done manually to provide +information to instances about their external addresses on which they are +available. Otherwise, client-side routing wouldn't work. To connect instances, +we use the following queries and execute them against any coordinator: + +```cypher +ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-1.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-1.default.svc.cluster.local:12000"}; +ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-2.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-2.default.svc.cluster.local:12000"}; +ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-3.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-3.default.svc.cluster.local:12000"}; +REGISTER INSTANCE instance_0 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-data-0.default.svc.cluster.local:10000", "replication_server": "memgraph-data-0.default.svc.cluster.local:20000"}; +REGISTER INSTANCE instance_1 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-data-1.default.svc.cluster.local:10000", "replication_server": "memgraph-data-1.default.svc.cluster.local:20000"}; +SET INSTANCE instance_1 TO MAIN; +``` + +Note that the only part which you need to change from the above template is the +Bolt server address. The value of the Bolt server address depends on the type of +the external network you are using for accessing instances from outside. + +For more details, see our documentation on the Memgraph HA +[User API](/clustering/high-availability#user-api), including how to add +coordinators and register data instances. + +#### Using Memgraph HA chart with `IngressNginx` resource + +The most cost-friendly way to manage a Memgraph HA cluster in K8s is using a `IngressNginx` controller. This controller is capable of routing TCP messages on Bolt level protocol +to the K8s Memgraph services. To achieve this, it uses only a single `LoadBalancer` which means there is only a single external IP for connecting to the cluster. Users can connect +to any coordinator or data instance by distinguishing Bolt ports. The only step required is to install Memgraph HA chart: + +``` +helm install mem-ha-test ./charts/memgraph-high-availability --set \ +env.MEMGRAPH_ENTERPRISE_LICENSE=,\ +env.MEMGRAPH_ORGANIZATION_NAME=,affinity.nodeSelection=true,\ +externalAccessConfig.dataInstance.serviceType=IngressNginx,externalAccessConfig.coordinator.serviceType=IngressNginx +``` + +The chart will also install `IngressNginx` automatically with all required configuration. + +### Probes + +Memgraph HA chart uses startup, readiness and liveness probes. The startup probe +is used to determine when a container application has started. The liveness +probe is used to determine when a container should be restarted. The readiness +probe is used to determine when a container is ready to start accepting traffic. +The startup probe will succeed only after the recovery of the Memgraph has +finished. Liveness and readiness probes will start after the startup probe +succeeds. By default, the startup probe on data instances has to succeed within 2 hours. If the +recovery from backup takes longer than that, update the configuration to the +value that is high enough. The liveness and readiness probe have to succeed at +least once in 5 minutes for a pod to be considered ready on data instances. +Coordinators have their own probe configuration and receive pings on the NuRaft +server, whereas data instances receive pings on the Bolt server. + + +### Monitoring + +Memgraph supports cluster monitoring with the help of [kube-prometheus-stack chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) and +[Memgraph's Prometheus exporter](https://github.com/memgraph/prometheus-exporter). +The chart `kube-prometheus-stack` should be installed independently from HA chart with the following command: + +```bash +helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -f kube_prometheus_stack_values.yaml --namespace monitoring --create-namespace +``` + +The file `kube_prometheus_stack_values.yaml` can but doesn't need to be included. The template of the file can be found [here](https://github.com/prometheus-community/helm-charts/blob/main/charts/kube-prometheus-stack/values.yaml). +If you are installing `kube-prometheus-stack` chart in a namespace different than the `default`, make sure to allow cross-namespace metric scraping. You can allow this +by adding the following configuration to your `kube_prometheus_stack_values.yaml` file: + +``` +prometheus: + prometheusSpec: + serviceMonitorSelectorNilUsesHelmValues: false +``` + +To enable monitoring when installing Memgraph's HA chart, there are several options you can use listed here: + +``` +prometheus: + enabled: true + namespace: monitoring + memgraphExporter: + port: 9115 + pullFrequencySeconds: 5 + repository: memgraph/mg-exporter + tag: 0.2.1 + serviceMonitor: + kubePrometheusStackReleaseName: kube-prometheus-stack + interval: 15s +``` + +By setting `prometheus.enabled` false, all resources from `charts/memgraph-high-availability/templates/mg-exporter.yaml` will get installed in the namespace `monitoring`. +Check the table below to find the explanation for each of the configuration parameters. + + +To uninstall the `kube-prometheus-stack` use: + +``` +helm uninstall kube-prometheus-stack --namespace monitoring +``` + +CRDs aren't removed by default and they should be manually cleaned up: + +``` +kubectl delete crd alertmanagerconfigs.monitoring.coreos.com +kubectl delete crd alertmanagers.monitoring.coreos.com +kubectl delete crd podmonitors.monitoring.coreos.com +kubectl delete crd probes.monitoring.coreos.com +kubectl delete crd prometheusagents.monitoring.coreos.com +kubectl delete crd prometheuses.monitoring.coreos.com +kubectl delete crd prometheusrules.monitoring.coreos.com +kubectl delete crd scrapeconfigs.monitoring.coreos.com +kubectl delete crd servicemonitors.monitoring.coreos.com +kubectl delete crd thanosrulers.monitoring.coreos.com +``` + + -## Kubernetes +### Configuration options + +The following table lists the configurable parameters of the Memgraph HA chart and their default values. + + +| Parameter | Description | Default | +| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------ | +| `image.repository` | Memgraph Docker image repository | `memgraph/memgraph` | +| `image.tag` | Specific tag for the Memgraph Docker image. Overrides the image tag whose default is chart version. | `3.1.0` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `env.MEMGRAPH_ENTERPRISE_LICENSE` | Memgraph enterprise license | `` | +| `env.MEMGRAPH_ORGANIZATION_NAME` | Organization name | `` | +| `memgraphUserId` | The user id that is hardcoded in Memgraph and Mage images | `101` | +| `memgraphGroupId` | The group id that is hardcoded in Memgraph and Mage images | `103` | +| `storage.libPVCSize` | Size of the storage PVC | `1Gi` | +| `storage.libStorageClassName` | The name of the storage class used for storing data. | `""` | +| `storage.libStorageAccessMode` | Access mode used for lib storage. | `ReadWriteOnce` | +| `storage.logPVCSize` | Size of the log PVC | `1Gi` | +| `storage.logStorageClassName` | The name of the storage class used for storing logs. | `""` | +| `storage.logStorageAccessMode` | Access mode used for log storage. | `ReadWriteOnce` | +| `externalAccess.coordinator.serviceType` | IngressNginx, NodePort, CommonLoadBalancer or LoadBalancer. By default, no external service will be created. | `""` | +| `externalAccess.coordinator.annotations` | Annotations for external services attached to coordinators. | `{}` | +| `externalAccess.dataInstance.serviceType` | IngressNginx, NodePort or LoadBalancer. By default, no external service will be created. | `""` | +| `externalAccess.dataInstance.annotations` | Annotations for external services attached to data instances. | `{}` | +| `headlessService.enabled` | Specifies whether headless services will be used inside K8s network on all instances. | `false` | +| `ports.boltPort` | Bolt port used on coordinator and data instances. | `7687` | +| `ports.managementPort` | Management port used on coordinator and data instances. | `10000` | +| `ports.replicationPort` | Replication port used on data instances. | `20000` | +| `ports.coordinatorPort` | Coordinator port used on coordinators. | `12000` | +| `affinity.unique` | Schedule pods on different nodes in the cluster | `false` | +| `affinity.parity` | Schedule pods on the same node with maximum one coordinator and one data node | `false` | +| `affinity.nodeSelection` | Schedule pods on nodes with specific labels | `false` | +| `affinity.roleLabelKey` | Label key for node selection | `role` | +| `affinity.dataNodeLabelValue` | Label value for data nodes | `data-node` | +| `affinity.coordinatorNodeLabelValue` | Label value for coordinator nodes | `coordinator-node` | +| `container.data.livenessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | +| `container.data.livenessProbe.failureThreshold` | Failure threshold for liveness probe | `20` | +| `container.data.livenessProbe.timeoutSeconds` | Timeout for liveness probe | `10` | +| `container.data.livenessProbe.periodSeconds` | Period seconds for readiness probe | `5` | +| `container.data.readinessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | +| `container.data.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `20` | +| `container.data.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `10` | +| `container.data.readinessProbe.periodSeconds` | Period seconds for readiness probe | `5` | +| `container.data.startupProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | +| `container.data.startupProbe.failureThreshold` | Failure threshold for startup probe | `1440` | +| `container.data.startupProbe.timeoutSeconds` | Timeout for probe | `10` | +| `container.data.startupProbe.periodSeconds` | Period seconds for startup probe | `10` | +| `container.coordinators.livenessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | +| `container.coordinators.livenessProbe.failureThreshold` | Failure threshold for liveness probe | `20` | +| `container.coordinators.livenessProbe.timeoutSeconds` | Timeout for liveness probe | `10` | +| `container.coordinators.livenessProbe.periodSeconds` | Period seconds for readiness probe | `5` | +| `container.coordinators.readinessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | +| `container.coordinators.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `20` | +| `container.coordinators.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `10` | +| `container.coordinators.readinessProbe.periodSeconds` | Period seconds for readiness probe | `5` | +| `container.coordinators.startupProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | +| `container.coordinators.startupProbe.failureThreshold` | Failure threshold for startup probe | `1440` | +| `container.coordinators.startupProbe.timeoutSeconds` | Timeout for probe | `10` | +| `container.coordinators.startupProbe.periodSeconds` | Period seconds for startup probe | `10` | +| `data` | Configuration for data instances | See `data` section | +| `coordinators` | Configuration for coordinator instances | See `coordinators` section | +| `sysctlInitContainer.enabled` | Enable the init container to set sysctl parameters | `true` | +| `sysctlInitContainer.maxMapCount` | Value for `vm.max_map_count` to be set by the init container | `262144` | +| `secrets.enabled` | Enable the use of Kubernetes secrets for Memgraph credentials | `false` | +| `secrets.name` | The name of the Kubernetes secret containing Memgraph credentials | `memgraph-secrets` | +| `secrets.userKey` | The key in the Kubernetes secret for the Memgraph user, the value is passed to the `MEMGRAPH_USER` env. | `USER` | +| `secrets.passwordKey` | The key in the Kubernetes secret for the Memgraph password, the value is passed to the `MEMGRAPH_PASSWORD`. | `PASSWORD` | +| `resources.coordinators` | CPU/Memory resource requests/limits. Left empty by default. | `{}` | +| `resources.data` | CPU/Memory resource requests/limits. Left empty by default. | `{}` | +| `prometheus.enabled` | If set to `true`, K8s resources representing Memgraph's Prometheus exporter will be deployed. | `false` | +| `prometheus.namespace` | The namespace in which `kube-prometheus-stack` and Memgraph's Prometheus exporter are installed. | `monitoring` | +| `prometheus.memgraphExporter.port` | The port on which Memgraph's Prometheus exporter is available. | `9115` | +| `prometheus.memgraphExporter.pullFrequencySeconds` | How often will Memgraph's Prometheus exporter pull data from Memgraph instances. | `5` | +| `prometheus.memgraphExporter.repository` | The repository where Memgraph's Prometheus exporter image is available. | `memgraph/prometheus-exporter` | +| `prometheus.memgraphExporter.tag` | The tag of Memgraph's Prometheus exporter image. | `0.2.1` | +| `prometheus.serviceMonitor.enabled` | If enabled, a `ServiceMonitor` object will be deployed. | `true` | +| `prometheus.serviceMonitor.kubePrometheusStackReleaseName` | The release name under which `kube-prometheus-stack` chart is installed. | `kube-prometheus-stack` | +| `prometheus.serviceMonitor.interval` | How often will Prometheus pull data from Memgraph's Prometheus exporter. | `15s` | +| `labels.coordinators.podLabels` | Enables you to set labels on a pod level. | `{}` | +| `labels.coordinators.statefulSetLabels` | Enables you to set labels on a stateful set level. | `{}` | +| `labels.coordinators.serviceLabels` | Enables you to set labels on a service level. | `{}` | +| `updateStrategy.type` | Update strategy for StatefulSets. Possible values are `RollingUpdate` and `OnDelete` | `RollingUpdate` | +| `extraEnv.data` | Env variables that users can define and are applied to data instances | `[]` | +| `extraEnv.coordinators` | Env variables that users can define and are applied to coordinators | `[]` | +| `initContainers.data` | Init containers that users can define that will be applied to data instances. | `[]` | +| `initContainers.coordinators` | Init containers that users can define that will be applied to coordinators. | `[]` | + + +For the `data` and `coordinators` sections, each item in the list has the following parameters: + +| Parameter | Description | Default | +|---------------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------| +| `id` | ID of the instance | `0` for data, `1` for coordinators | +| `args` | List of arguments for the instance | See `args` section | + +The `args` section contains a list of arguments for the instance. + +For all available database settings, refer to the [configuration settings +docs](/database-management/configuration). -We support deploying Memgraph HA as part of the Kubernetes cluster through Helm charts. -You can see example configurations [here](/getting-started/install-memgraph/kubernetes#memgraph-high-availability-helm-chart). ## In-Service Software Upgrade (ISSU) diff --git a/pages/getting-started/install-memgraph/kubernetes.mdx b/pages/getting-started/install-memgraph/kubernetes.mdx index 93c67e752..c72710682 100644 --- a/pages/getting-started/install-memgraph/kubernetes.mdx +++ b/pages/getting-started/install-memgraph/kubernetes.mdx @@ -324,477 +324,9 @@ reference guide](/database-management/configuration). - ## Memgraph high availability Helm chart -A Helm chart for deploying Memgraph in [high availability (HA) -setup](/clustering/high-availability). This helm chart requires [Memgraph -Enterprise license](/database-management/enabling-memgraph-enterprise). We recommend reading -the documentation about [high availability](https://memgraph.com/docs/clustering/high-availability) in Memgraph. - -Memgraph HA cluster includes 3 coordinators and 2 data instances by default. Since -multiple Memgraph instances are used, it is advised to use multiple workers nodes in Kubernetes. -Our advice is that each Memgraph instance gets on its own node. The size of nodes on which -data pods will reside depends on the computing power and the memory you need to store data. -Coordinator nodes can be smaller and machines with basic requirements met (8-16 GB of RAM) will be enough. - - -### Installing the Memgraph HA Helm chart - -To include Memgraph HA cluster as a part of your Kubernetes cluster, you need to -[add the repository](#add-the-repository-1) and [install -Memgraph](#install-memgraph-ha). - -#### Add the repository - -Add the Memgraph Helm chart repository to your local Helm setup by running the -following command: - -``` -helm repo add memgraph https://memgraph.github.io/helm-charts -``` - -Make sure to update the repository to fetch the latest Helm charts available: - -``` -helm repo update -``` - -#### Install Memgraph HA - -Since Memgraph HA requires an [Enterprise license](/database-management/enabling-memgraph-enterprise), you need to provide the license and organization name during the installation. - -``` -helm install memgraph/memgraph-high-availability --set env.MEMGRAPH_ENTERPRISE_LICENSE=,env.MEMGRAPH_ORGANIZATION_NAME= -``` - -Replace `` with a name of your choice for the release and set the -Enterprise license. - - - -When installing a chart, it's best practice to specify the exact version you -want to use. Using the latest tag can lead to issues, as a pod restart may pull -a newer image, potentially causing unexpected changes or incompatibilities. - - -### Install Memgraph HA chart with `minikube` - -If you are installing Memgraph HA chart locally with `minikube`, we are strongly recommending to enable `csi-hostpath-driver` and use its storage class. Otherwise, -you could have problems with attaching PVCs to pods. - -1. Enable `csi-hostpath-driver` -``` -minikube addons disable storage-provisioner -minikube addons disable default-storageclass -minikube addons enable volumesnapshots -minikube addons enable csi-hostpath-driver -``` - -2. Create a storage class with `csi-hostpath-driver` as a provider (file sc.yaml) - -``` -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: csi-hostpath-delayed -provisioner: hostpath.csi.k8s.io -volumeBindingMode: WaitForFirstConsumer -reclaimPolicy: Delete -``` - -3. `kubectl apply -f sc.yaml` - -4. Set `libStorageClassName` to `csi-hostpath-delayed` in `values.yaml` - - -### Changing the default chart values - -To change the default chart values, run the command with the specified set of -flags: -``` -helm install memgraph/memgraph-high-availability --set =,=,... -``` -Or you can modify a `values.yaml` file and override the desired values: -``` -helm install memgraph/memgraph-high-availability -f values.yaml -``` - -### Upgrade Helm chart - -To upgrade the helm chart you can use: -``` -helm upgrade memgraph/memgraph-high-availability --set =,= -``` - -Again it is possible use both `--set` and values.yaml to set configuration options. - -If you're using `IngressNginx` and performing an upgrade, the attached public IP -should remain the same. It will only change if the release includes specific -updates that modify it—and such changes will be documented. - - -### Uninstall Helm chart - -Uninstallation is done with: - -``` -helm uninstall -``` - -Uninstalling the chart won't trigger deletion of persistent volume claims (PVCs) which means that even if the reclaim policy of the default storage class is set to 'Delete' -(which often is), the data from persistent volumes (PVs) won't be lost. However, we advise users to set the reclaim policy to 'Retain' as suggested in the -[Storage chapter](#high-availability-storage). - -### Security context - -All instances are started as `StatefulSet` with one pod. The pod has two or three containers depending on whether the sysctlInitContainer.enabled is used. The **memgraph-coordinator** container is the one which -actually runs Memgraph image. The process is run by non-root **memgraph** user without any Linux capabilities. Privileges cannot escalate. - -### High availability storage - -Memgraph HA chart will always use persistent volume claims (PVCs) for storing data and logs. By default they will use **1Gi** so most likely you will need to set this parameter to a -higher value. Access mode is by default set to `ReadWriteOnce` (RWO) and can be changed to one of values: `ReadWriteOnce`, `ReadOnlyMany`, `ReadWriteMany` and -`ReadWriteOncePod`. All PVCs will use a default storage class. You can use parameters `libStorageClassName` and `logStorageClassName` to specify which storage classes will -be used for storing data and logs on data and coordinator instances. Default storage classes usually have a reclaim policy set to `Delete` which means that if you delete PVCs, -attached PVs will also get deleted. We advise users to set the reclaim policy to `Retain` One of the ways to achieve this is to run the following script after starting your cluster: - -```bash -#!/bin/bash - -# Get all Persistent Volume names -PVS=$(kubectl get pv --no-headers -o custom-columns=":metadata.name") - -# Loop through each PV and patch it -for pv in $PVS; do - echo "Patching PV: $pv" - kubectl patch pv $pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' -done - -echo "All PVs have been patched." -``` - - -Kubernetes uses a concept called "Storage Object in Use Protection", which -delays the deletion of PersistentVolumeClaims (PVCs) until the pods using them -are deleted. Similarly, PersistentVolumes (PVs) won't be deleted until their -associated PVCs are removed. - -If PVC deletion is stuck, you can try removing its finalizers by running: - -```bash -kubectl patch pvc PVC_NAME -p '{"metadata":{"finalizers": []}}' --type=merge -``` - - -### Network configuration - -All instances which are part of Memgraph HA cluster use the internal Cluster IP network for communicating between themselves. By default, management port is on all instances opened on -10000, replication port on data instances is opened on 20000 while coordinator port is opened on 12000. You can change this configuration by specifying `ports.managementPort`, -`ports.replicationPort` and `ports.coordinatorPort`. - -#### External network configuration - -Since Memgraph HA works with client-side routing, the resolution of all DNS entries happens outside internal Cluster IP network. Because of that, we need one more type of network -which will be used for clients accessing instances inside the cluster. - -- `IngressNginx`: Using only one load balancer you can access all instances from outside. -- `NodePort`: The cheapest option because it will open port on each node. For this to work, you need to enable public IPs on each node. -- `LoadBalancer`: This option will use one load balancer for each instance in the cluster. Load balancer is mostly interesting here because it comes with public IP out of the box. - -For coordinators, there is an additional option of using `CommonLoadBalancer`. In this scenario, there is one load balancer sitting in front of coordinators. You can save the cost -of two load balancers compared to `LoadBalancer` option since usually you don't need to distinguish specific coordinators while using Memgraph capabilities. The default Bolt port -is opened on 7687 but you can change it by setting `ports.boltPort`. - -Read more in the [guide](#using-memgraph-ha-chart-with-ingressnginx-resource) for installing Memgraph HA with `IngressNginx`. - -By default, no configuration is provided for external network access so users can customize their settings in an easier manner. - -### Node affinity - -Since HA Memgraph deploys multiple pods, you can control on which nodes pods get -distributed in the cluster. - -The Memgraph HA Helm chart provides the following node affinity options: - -- `default`: Default affinity will try to schedule the data pods and - coordinator pods on the nodes where there is no other pod with the same role. - If there is no such node, the pods will still be scheduled on the same node, - and deployment will not fail. -- `unique`: This is achieved with the `affinity.unique` set to `true`. - This option will try to deploy the data pods and coordinator pods on different - nodes in the cluster so that each pod is on a unique node. If there are no - sufficient nodes, this deployment will fail. -- `parity`: This is achieved with the `affinity.parity` set to `true`. - This option will try to deploy the data pods and coordinator pods on the same node - with maximum one coordinator and one data pod on the node. If there are no - sufficient nodes to deploy the pods, this deployment will fail. Coordinators - get scheduled first. After that, data pods are looking for the nodes with - coordinators. -- `nodeSelection`: This is achieved with the `affinity.nodeSelection` - set to `true`. This option will try to deploy the data pods and coordinator - pods on the nodes with specific labels. You can set the labels with the - `affinity.dataNodeLabelValue` and - `affinity.coordinatorNodeLabelValue` parameters. If all the nodes - with labels are occupied by the pods with the same role, the deployment will - fail. - - -During the usage of `nodeSelection` affinity, make sure that the nodes are -properly labeled, the default key for the role label is `role`, and default -values are `data-node` and `coordinator-node`. Labels can be added to nodes -using the `kubectl label nodes =` command. -[Here](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-high-availability/aks) -is an example of how to deploy Memgraph HA cluster in AKS. - - - -### Sysctl options - -You can use `sysctlInitContainer` configuration parameter to [increase the `vm_max_map_count`](/database-management/system-configuration#increasing-memory-map-areas) which is necessary for high memory loads in Memgraph. - - -### Authentication - -By default, there is no user or password configured for Memgraph instances. You can use `secrets` configuration parameter -to create the user with the password. The secret can be created in the following way: - -``` -kubectl create secret generic memgraph-secrets --from-literal=USER=memgraph --from-literal=PASSWORD=memgraph -``` - -The same user will then be created on all coordinator and data instances through Memgraph's environment variables. - -### Setting up the cluster - -Although there are many configuration options you can use to set up HA cluster (especially for networking), the set-up process -stays always the same: - -**1.** Provision the cluster - -**2.** Label nodes based on the affinity strategy - -**3.** Install `memgraph/memgraph-high-availability` chart using `helm install` - -**4.** Install any other auxiliary resources, e.g `ingress-nginx` if you are using that type of external network configuration. - -**5.** Connect instances to form the cluster - -The last step, connecting instances, needs to be done manually to provide -information to instances about their external addresses on which they are -available. Otherwise, client-side routing wouldn't work. To connect instances, -we use the following queries and execute them against any coordinator: - -```cypher -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-1.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-1.default.svc.cluster.local:12000"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-2.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-2.default.svc.cluster.local:12000"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-coordinator-3.default.svc.cluster.local:10000", "coordinator_server": "memgraph-coordinator-3.default.svc.cluster.local:12000"}; -REGISTER INSTANCE instance_0 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-data-0.default.svc.cluster.local:10000", "replication_server": "memgraph-data-0.default.svc.cluster.local:20000"}; -REGISTER INSTANCE instance_1 WITH CONFIG {"bolt_server": "", "management_server": "memgraph-data-1.default.svc.cluster.local:10000", "replication_server": "memgraph-data-1.default.svc.cluster.local:20000"}; -SET INSTANCE instance_1 TO MAIN; -``` - -Note that the only part which you need to change from the above template is the -Bolt server address. The value of the Bolt server address depends on the type of -the external network you are using for accessing instances from outside. - -For more details, see our documentation on the Memgraph HA -[User API](/clustering/high-availability#user-api), including how to add -coordinators and register data instances. - -#### Using Memgraph HA chart with `IngressNginx` resource - -The most cost-friendly way to manage a Memgraph HA cluster in K8s is using a `IngressNginx` controller. This controller is capable of routing TCP messages on Bolt level protocol -to the K8s Memgraph services. To achieve this, it uses only a single `LoadBalancer` which means there is only a single external IP for connecting to the cluster. Users can connect -to any coordinator or data instance by distinguishing Bolt ports. The only step required is to install Memgraph HA chart: - -``` -helm install mem-ha-test ./charts/memgraph-high-availability --set \ -env.MEMGRAPH_ENTERPRISE_LICENSE=,\ -env.MEMGRAPH_ORGANIZATION_NAME=,affinity.nodeSelection=true,\ -externalAccessConfig.dataInstance.serviceType=IngressNginx,externalAccessConfig.coordinator.serviceType=IngressNginx -``` - -The chart will also install `IngressNginx` automatically with all required configuration. - -### Probes - -Memgraph HA chart uses startup, readiness and liveness probes. The startup probe -is used to determine when a container application has started. The liveness -probe is used to determine when a container should be restarted. The readiness -probe is used to determine when a container is ready to start accepting traffic. -The startup probe will succeed only after the recovery of the Memgraph has -finished. Liveness and readiness probes will start after the startup probe -succeeds. By default, the startup probe on data instances has to succeed within 2 hours. If the -recovery from backup takes longer than that, update the configuration to the -value that is high enough. The liveness and readiness probe have to succeed at -least once in 5 minutes for a pod to be considered ready on data instances. -Coordinators have their own probe configuration and receive pings on the NuRaft -server, whereas data instances receive pings on the Bolt server. - - -### Monitoring - -Memgraph supports cluster monitoring with the help of [kube-prometheus-stack chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) and -[Memgraph's Prometheus exporter](https://github.com/memgraph/prometheus-exporter). -The chart `kube-prometheus-stack` should be installed independently from HA chart with the following command: - -```bash -helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -f kube_prometheus_stack_values.yaml --namespace monitoring --create-namespace -``` - -The file `kube_prometheus_stack_values.yaml` can but doesn't need to be included. The template of the file can be found [here](https://github.com/prometheus-community/helm-charts/blob/main/charts/kube-prometheus-stack/values.yaml). -If you are installing `kube-prometheus-stack` chart in a namespace different than the `default`, make sure to allow cross-namespace metric scraping. You can allow this -by adding the following configuration to your `kube_prometheus_stack_values.yaml` file: - -``` -prometheus: - prometheusSpec: - serviceMonitorSelectorNilUsesHelmValues: false -``` - -To enable monitoring when installing Memgraph's HA chart, there are several options you can use listed here: - -``` -prometheus: - enabled: true - namespace: monitoring - memgraphExporter: - port: 9115 - pullFrequencySeconds: 5 - repository: memgraph/mg-exporter - tag: 0.2.1 - serviceMonitor: - kubePrometheusStackReleaseName: kube-prometheus-stack - interval: 15s -``` - -By setting `prometheus.enabled` false, all resources from `charts/memgraph-high-availability/templates/mg-exporter.yaml` will get installed in the namespace `monitoring`. -Check the table below to find the explanation for each of the configuration parameters. - - -To uninstall the `kube-prometheus-stack` use: - -``` -helm uninstall kube-prometheus-stack --namespace monitoring -``` - -CRDs aren't removed by default and they should be manually cleaned up: - -``` -kubectl delete crd alertmanagerconfigs.monitoring.coreos.com -kubectl delete crd alertmanagers.monitoring.coreos.com -kubectl delete crd podmonitors.monitoring.coreos.com -kubectl delete crd probes.monitoring.coreos.com -kubectl delete crd prometheusagents.monitoring.coreos.com -kubectl delete crd prometheuses.monitoring.coreos.com -kubectl delete crd prometheusrules.monitoring.coreos.com -kubectl delete crd scrapeconfigs.monitoring.coreos.com -kubectl delete crd servicemonitors.monitoring.coreos.com -kubectl delete crd thanosrulers.monitoring.coreos.com -``` - - - -### Configuration options - -The following table lists the configurable parameters of the Memgraph HA chart and their default values. - - -| Parameter | Description | Default | -| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------ | -| `image.repository` | Memgraph Docker image repository | `memgraph/memgraph` | -| `image.tag` | Specific tag for the Memgraph Docker image. Overrides the image tag whose default is chart version. | `3.1.0` | -| `image.pullPolicy` | Image pull policy | `IfNotPresent` | -| `env.MEMGRAPH_ENTERPRISE_LICENSE` | Memgraph enterprise license | `` | -| `env.MEMGRAPH_ORGANIZATION_NAME` | Organization name | `` | -| `memgraphUserId` | The user id that is hardcoded in Memgraph and Mage images | `101` | -| `memgraphGroupId` | The group id that is hardcoded in Memgraph and Mage images | `103` | -| `storage.libPVCSize` | Size of the storage PVC | `1Gi` | -| `storage.libStorageClassName` | The name of the storage class used for storing data. | `""` | -| `storage.libStorageAccessMode` | Access mode used for lib storage. | `ReadWriteOnce` | -| `storage.logPVCSize` | Size of the log PVC | `1Gi` | -| `storage.logStorageClassName` | The name of the storage class used for storing logs. | `""` | -| `storage.logStorageAccessMode` | Access mode used for log storage. | `ReadWriteOnce` | -| `externalAccess.coordinator.serviceType` | IngressNginx, NodePort, CommonLoadBalancer or LoadBalancer. By default, no external service will be created. | `""` | -| `externalAccess.coordinator.annotations` | Annotations for external services attached to coordinators. | `{}` | -| `externalAccess.dataInstance.serviceType` | IngressNginx, NodePort or LoadBalancer. By default, no external service will be created. | `""` | -| `externalAccess.dataInstance.annotations` | Annotations for external services attached to data instances. | `{}` | -| `headlessService.enabled` | Specifies whether headless services will be used inside K8s network on all instances. | `false` | -| `ports.boltPort` | Bolt port used on coordinator and data instances. | `7687` | -| `ports.managementPort` | Management port used on coordinator and data instances. | `10000` | -| `ports.replicationPort` | Replication port used on data instances. | `20000` | -| `ports.coordinatorPort` | Coordinator port used on coordinators. | `12000` | -| `affinity.unique` | Schedule pods on different nodes in the cluster | `false` | -| `affinity.parity` | Schedule pods on the same node with maximum one coordinator and one data node | `false` | -| `affinity.nodeSelection` | Schedule pods on nodes with specific labels | `false` | -| `affinity.roleLabelKey` | Label key for node selection | `role` | -| `affinity.dataNodeLabelValue` | Label value for data nodes | `data-node` | -| `affinity.coordinatorNodeLabelValue` | Label value for coordinator nodes | `coordinator-node` | -| `container.data.livenessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | -| `container.data.livenessProbe.failureThreshold` | Failure threshold for liveness probe | `20` | -| `container.data.livenessProbe.timeoutSeconds` | Timeout for liveness probe | `10` | -| `container.data.livenessProbe.periodSeconds` | Period seconds for readiness probe | `5` | -| `container.data.readinessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | -| `container.data.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `20` | -| `container.data.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `10` | -| `container.data.readinessProbe.periodSeconds` | Period seconds for readiness probe | `5` | -| `container.data.startupProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `7687` | -| `container.data.startupProbe.failureThreshold` | Failure threshold for startup probe | `1440` | -| `container.data.startupProbe.timeoutSeconds` | Timeout for probe | `10` | -| `container.data.startupProbe.periodSeconds` | Period seconds for startup probe | `10` | -| `container.coordinators.livenessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | -| `container.coordinators.livenessProbe.failureThreshold` | Failure threshold for liveness probe | `20` | -| `container.coordinators.livenessProbe.timeoutSeconds` | Timeout for liveness probe | `10` | -| `container.coordinators.livenessProbe.periodSeconds` | Period seconds for readiness probe | `5` | -| `container.coordinators.readinessProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | -| `container.coordinators.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `20` | -| `container.coordinators.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `10` | -| `container.coordinators.readinessProbe.periodSeconds` | Period seconds for readiness probe | `5` | -| `container.coordinators.startupProbe.tcpSocket.port` | Port used for TCP connection. Should be the same as bolt port. | `12000` | -| `container.coordinators.startupProbe.failureThreshold` | Failure threshold for startup probe | `1440` | -| `container.coordinators.startupProbe.timeoutSeconds` | Timeout for probe | `10` | -| `container.coordinators.startupProbe.periodSeconds` | Period seconds for startup probe | `10` | -| `data` | Configuration for data instances | See `data` section | -| `coordinators` | Configuration for coordinator instances | See `coordinators` section | -| `sysctlInitContainer.enabled` | Enable the init container to set sysctl parameters | `true` | -| `sysctlInitContainer.maxMapCount` | Value for `vm.max_map_count` to be set by the init container | `262144` | -| `secrets.enabled` | Enable the use of Kubernetes secrets for Memgraph credentials | `false` | -| `secrets.name` | The name of the Kubernetes secret containing Memgraph credentials | `memgraph-secrets` | -| `secrets.userKey` | The key in the Kubernetes secret for the Memgraph user, the value is passed to the `MEMGRAPH_USER` env. | `USER` | -| `secrets.passwordKey` | The key in the Kubernetes secret for the Memgraph password, the value is passed to the `MEMGRAPH_PASSWORD`. | `PASSWORD` | -| `resources.coordinators` | CPU/Memory resource requests/limits. Left empty by default. | `{}` | -| `resources.data` | CPU/Memory resource requests/limits. Left empty by default. | `{}` | -| `prometheus.enabled` | If set to `true`, K8s resources representing Memgraph's Prometheus exporter will be deployed. | `false` | -| `prometheus.namespace` | The namespace in which `kube-prometheus-stack` and Memgraph's Prometheus exporter are installed. | `monitoring` | -| `prometheus.memgraphExporter.port` | The port on which Memgraph's Prometheus exporter is available. | `9115` | -| `prometheus.memgraphExporter.pullFrequencySeconds` | How often will Memgraph's Prometheus exporter pull data from Memgraph instances. | `5` | -| `prometheus.memgraphExporter.repository` | The repository where Memgraph's Prometheus exporter image is available. | `memgraph/prometheus-exporter` | -| `prometheus.memgraphExporter.tag` | The tag of Memgraph's Prometheus exporter image. | `0.2.1` | -| `prometheus.serviceMonitor.enabled` | If enabled, a `ServiceMonitor` object will be deployed. | `true` | -| `prometheus.serviceMonitor.kubePrometheusStackReleaseName` | The release name under which `kube-prometheus-stack` chart is installed. | `kube-prometheus-stack` | -| `prometheus.serviceMonitor.interval` | How often will Prometheus pull data from Memgraph's Prometheus exporter. | `15s` | -| `labels.coordinators.podLabels` | Enables you to set labels on a pod level. | `{}` | -| `labels.coordinators.statefulSetLabels` | Enables you to set labels on a stateful set level. | `{}` | -| `labels.coordinators.serviceLabels` | Enables you to set labels on a service level. | `{}` | -| `updateStrategy.type` | Update strategy for StatefulSets. Possible values are `RollingUpdate` and `OnDelete` | `RollingUpdate` | -| `extraEnv.data` | Env variables that users can define and are applied to data instances | `[]` | -| `extraEnv.coordinators` | Env variables that users can define and are applied to coordinators | `[]` | -| `initContainers.data` | Init containers that users can define that will be applied to data instances. | `[]` | -| `initContainers.coordinators` | Init containers that users can define that will be applied to coordinators. | `[]` | - - -For the `data` and `coordinators` sections, each item in the list has the following parameters: - -| Parameter | Description | Default | -|---------------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------| -| `id` | ID of the instance | `0` for data, `1` for coordinators | -| `args` | List of arguments for the instance | See `args` section | - -The `args` section contains a list of arguments for the instance. - -For all available database settings, refer to the [configuration settings -docs](/database-management/configuration). +Please continue on our [Memgraph high availability Helm chart setup](/clustering/high-availability/setup-ha-cluster-k8s). ## Memgraph Lab Helm chart diff --git a/public/pages/clustering/high-availability/bolt_routing_reads.png b/public/pages/clustering/high-availability/bolt_routing_reads.png new file mode 100644 index 0000000000000000000000000000000000000000..657d93fb28711f5e53c37058e170acbb90ac976a GIT binary patch literal 40955 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¥*A+_}PMZM|J~BWu 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 d{l^+aj(=UVrBwg` literal 0 HcmV?d00001 diff --git a/public/pages/clustering/high-availability/minimal_ha_cluster.png b/public/pages/clustering/high-availability/minimal_ha_cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..7edd78df59de03be98db3e6ee8539233748c7e06 GIT binary patch literal 27594 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⋉q>~0}$GQZGYn2hM#H+aAR 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 literal 0 HcmV?d00001 diff --git a/public/pages/clustering/high-availability/typical_ha_cluster.png b/public/pages/clustering/high-availability/typical_ha_cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..2e882e54ee60e136db4f4d04f20e960686bcfbcc GIT binary patch literal 28714 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 Date: Wed, 12 Nov 2025 11:18:45 +0100 Subject: [PATCH 07/13] Update faq and reference commands --- pages/clustering/faq.mdx | 76 ++++++++++++++++--- .../ha-commands-reference.mdx | 7 +- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/pages/clustering/faq.mdx b/pages/clustering/faq.mdx index 23547164e..f91394214 100644 --- a/pages/clustering/faq.mdx +++ b/pages/clustering/faq.mdx @@ -9,9 +9,23 @@ import { CommunityLinks } from '/components/social-card/CommunityLinks' ## High availability (general) +#### Do I need Memgraph Enterprise license for replication / HA? +Memgraph offers replication-only features within the community edition. However, you need to perform failover +techniques manually, or keep the system as-is and ensure that the instances are not down at any time. + +For automatic failover, ensuring high availability, and observability of the whole cluster, +you do need an Enterprise License, as it is a quality-of-life improvement, and requires little to no management. + +Enterprise license can be validated if injected correctly by issueing the following command: +``` +SHOW LICENSE INFO; +``` + #### Does Memgraph support chaining REPLICA instances? Memgraph at the moment doesn't support chaining REPLICA instances, that is, a REPLICA -instance cannot be replicated on another REPLICA instance. +instance cannot be replicated on another REPLICA instance. As the role of the instance is very +distinct, the instance at a point in time can just be a MAIN instance, or a REPLICA instance, and +can't serve as both. #### Can a REPLICA listen to multiple MAIN instances? Memgraph enforces the behaviour that REPLICA can only listen to exactly one MAIN instance. @@ -22,7 +36,8 @@ The instance UUID of each Memgraph is persisted on disk across restarts, so this cluster lifecycle. #### Can a REPLICA create snapshots by itself? -No. REPLICA can only receive snapshots during the recovery phase. +No. REPLICA can only receive snapshots during the recovery phase. REPLICA instance is ensuring durability by +receiving replication data from MAIN, and writing to its own disk storage. #### Can a REPLICA create WALs by itself? Actually, this is being done in the system. When a MAIN is committing, it is sending the Delta objects to the REPLICA. @@ -37,19 +52,62 @@ files, if it didn't write WALs during its period of being a REPLICA. If the old insufficient information to be sent to the new REPLICA. That's why REPLICA always needs to write down in WALs what it's being received. +#### What is the difference between SYNC and STRICT_SYNC replication mode? +In SYNC mode, if a REPLICA does not commit, MAIN will still continue and commit its own data. This is to ensure at least some +availability, because if the commit didn't pass, the whole system would be stuck on writes. However, this doesn't guarantee +data consistency across instances, as MAIN instance can be ahead of a SYNC replica. -### High availability with Docker +Because of this behaviour, Memgraph also supports STRICT_SYNC, which will commit the changes only if all instances agreed to +commit. This ensures data consistency, but if any instance fails to commit, writes will not pass through MAIN. -### High availability with Docker Compose +### High availability (setting up the cluster) -### High availability with K8s +#### Which instance should I use to register the cluster? +Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. +#### Can I combine all three replication modes for registering REPLICAs in the cluster? +You can only have 2 combinations of different replication modes: +- `STRICT_SYNC` and `ASYNC` replicas +- `SYNC` and `ASYNC` replicas +Combining `STRICT_SYNC` and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. Reason for this +is because MAIN will advance to commit the change in `SYNC` mode, while in the `STRICT_SYNC` mode it will fail. - +### High availability (architecture) + +#### Which replication mode should I use for achieving no data loss? +For achieving no data loss, users should use the STRICT_SYNC replication mode, which is performing the two phase commit (2PC) +protocol during the commit stage. +#### Which replication mode should I use for achieving maximum performance? +For achieving maximum performance, users should use the ASYNC replication mode, which is using a background thread to replicate +data. This mode is eventually consistent, but the MAIN instance does not wait for the REPLICAs to commit their changes. -Validate license is correctly set -All the following queries can be run by querying directly coordinator 1, which we can conventionally assume to be the leader for the cluster. +#### Which replication mode should I use for cross datacenter deployment? +This again depends on whether you're okay with data loss, or eventual consistency: +- no data-loss is a must: STRICT_SYNC +- eventual consistency is fine: ASYNC +- performance: ASYNC +- no specific requirements: SYNC (default) -First, let’s validate that the license has been correctly set, by executing the following query: \ No newline at end of file +### High availability with K8s + +#### Log files are filling up my disk space, what should I do? +Memgraph currently does not support log retention. The best way currently to deal with this, is to specify the following +two flags: +- `--also-log-to-stderr=true` +- `--log-file=` (yes, empty value) + +on every data and coordinator instance. +Additional thing you can do is to tail the container logs into a log aggregator, such as [OpenSearch](https://opensearch.org/), +with which you will gain even more searching capabilities when troubleshooting. + +If you don't have a log aggregator, the user is expected to periodically clean the log files, in order to manage the disk space, +or reduce the log level of the instances. + +Log levels are a setting which can be changed at runtime, with the command: +``` +SET DATABASE SETTING `log.level` TO 'INFO'; +``` + + diff --git a/pages/clustering/high-availability/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx index abc616039..4f4f783c2 100644 --- a/pages/clustering/high-availability/ha-commands-reference.mdx +++ b/pages/clustering/high-availability/ha-commands-reference.mdx @@ -28,8 +28,11 @@ REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bol This operation will result in writing to the Raft log. -In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. Constructs ( AS ASYNC | AS STRICT_SYNC ) serve to specify -instance's replication mode when the instance behaves as replica. You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` +In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. +If a replication mode is not specified, REPLICA will be registered in `SYNC` replication mode. +Constructs `( AS ASYNC | AS STRICT_SYNC )` serve to specify a different replication mode other than `SYNC`. + +You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. From 733730ef476ecea8dcf94fe148fbe6d95cc8358a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Wed, 12 Nov 2025 12:02:38 +0100 Subject: [PATCH 08/13] Add reference commands --- .../high-availability/best-practices.mdx | 14 +- .../ha-commands-reference.mdx | 279 ++++++++++++------ 2 files changed, 205 insertions(+), 88 deletions(-) diff --git a/pages/clustering/high-availability/best-practices.mdx b/pages/clustering/high-availability/best-practices.mdx index 52c9c0efd..9ad276a01 100644 --- a/pages/clustering/high-availability/best-practices.mdx +++ b/pages/clustering/high-availability/best-practices.mdx @@ -67,10 +67,22 @@ the health state about the cluster. You can set this configuration flag to the I qualified domain name (FQDN), or even the DNS name. The suggested approach is to use DNS, otherwise, in case the IP address changes, network communication between instances in the cluster will stop working. -If you're working with K8s especially, you should use DNS/FQDN, as the IP addresses are ephemeral. +**Local development** When testing on a local setup, the flag `--coordinator-hostname` should be set to `localhost` for each instance. +**K8s/Helm charts** + +If you're working with K8s especially, you should use DNS/FQDN, as the IP addresses are ephemeral. + +If you're using namespaces, you might need to change the `values.yaml` in the Helm Charts, as they specify the +oordinator hostname for the default namespace. Below is the specification for coordinator 1: +``` +- "--coordinator-hostname=memgraph-coordinator-1.default.svc.cluster.local" +``` +The parameter should be changed to `memgraph-coordinator-1..svc.cluster.local` insted of providing the `default` +namespace. This needs to be applied on all coordinators. + #### management port The flag `--management-port` on the coordinator instance is used for the leader coordinator to get the health state from each of diff --git a/pages/clustering/high-availability/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx index 4f4f783c2..e3dec90ed 100644 --- a/pages/clustering/high-availability/ha-commands-reference.mdx +++ b/pages/clustering/high-availability/ha-commands-reference.mdx @@ -10,24 +10,104 @@ import {CommunityLinks} from '/components/social-card/CommunityLinks' This page provides a comprehensive reference for all commands available in Memgraph's high availability cluster management. -## User API +## Cluster registration commands -### Register instance + +**All cluster registration commands (registering coordinators and data instances) should be run on the same coordinator.** +You can pick any coordinator for registering your cluster, which will become the leader coordinator. After cluster has +been set up, the choosing of coordinator does not matter. + -Registering instances should be done on a single coordinator. The chosen coordinator will become the cluster's leader. +### ADD COORDINATOR -Register instance query will result in several actions: -1. The coordinator instance will connect to the data instance on the `management_server` network address. -2. The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. -3. Data instance will be demoted from main to replica. -4. Data instance will start the replication server on `replication_server`. +Adds a coordinator to the cluster. -```plaintext -REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG {"bolt_server": boltServer, "management_server": managementServer, "replication_server": replicationServer}; +```cypher +ADD COORDINATOR coordinatorId WITH CONFIG { + "bolt_server": boltServer, + "coordinator_server": coordinatorServer, + "management_server": managementServer +}; ``` -This operation will result in writing to the Raft log. +**Parameters:** +- `coordinatorId` (int) - unique integer for each coordinator. You can set a different incrementing integer for each coordinator as you + register them. +- `boltServer` (string) - Network address in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`. Port is usually set to 7687 as + that is representative for Bolt protocol. If IPs are ephemeral, it's best to use the DNS name/FQDN. The server IP needs + to be exposed to the external network, if there are any external applications connected to it. +- `coordinatorServer` (string) - Network address in format `"COORDINATOR_HOSTNAME|COORDINATOR_PORT"`. Coordinator hostname and port + are set on the command line flags for each coordinator. Ensure coordinator hostname is a DNS name/FQDN if IP addresses are ephemeral. +- `managementServer` (string) - Network address in format `"COORDINATOR_HOSTNAME|MANAGEMENT_PORT"`. Coordinator hostname and management port + are set on the command line flags for each coordinator. Ensure coordinator hostname is a DNS name/FQDN if IP addresses are ephemeral. + + +**Implications:** +- The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, +the order isn't important. +- `ADD COORDINATOR` query needs to be run for all coordinators in the cluster. +- Bolt server IP needs to be available outside the cluster and not ephemeral. +- Coordinator server and management server IP can be an internal IP/DNS name/FQDN, as the cluster uses it for internal communication. + +**Example:** +```cypher +ADD COORDINATOR 1 WITH CONFIG { + "bolt_server": "my_outside_coordinator_1_IP:7687", + "coordinator_server": "memgraph-coordinator-1.default.svc.cluster.local:12000", + "management_server": "memgraph-coordinator-1.default.svc.cluster.local:10000" +}; +``` + +### REMOVE COORDINATOR + +If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, +`REMOVE COORDINATOR` query can be used. This query can only be executed on the leader coordinator to remove follower coordinators. +Current cluster's leader cannot be removed since this is prohibited by NuRaft. In order to remove the current leader, +you first need to trigger leadership change. + +```cypher +REMOVE COORDINATOR coordinatorId; +``` + +**Parameters:** +- `coordinatorId` (integer) - unique integer ID of the coordinator used during the registration +**Example:** +```cypher +REMOVE COORDINATOR 2; +``` + +### REGISTER INSTANCE + +Registers a data instance to the cluster. + + +```cypher +REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG { + "bolt_server": boltServer, + "management_server": managementServer, + "replication_server": replicationServer +}; +``` + +**Parameters:** +- `instanceName` (symbolic name) - unique name of the data instance +- `AS ASYNC` (optional parameter) - register the instance in `ASYNC` replication mode +- `AS STRICT_SYNC` (optional parameter) - register the instance in `STRICT_SYNC` replication mode +- `boltServer` (string) - Network address in format "IP_ADDRESS|DNS_NAME:PORT_NUMBER". Port is usually set to 7687 as + that is representative for Bolt protocol. If IPs are ephemeral, it's best to use the DNS name/FQDN. The server IP needs + to be exposed to the external network, if there are any external applications connected to it. +- `managementServer` (string) - ??? +- `replicationServer` (string) - ??? + +**Behaviour:** +- The coordinator instance will connect to the data instance on the `management_server` network address. +- The coordinator instance will start pinging the data instance every `--instance-health-check-frequency-sec` seconds to check its status. +- Data instance will be demoted from main to replica. +- Data instance will start the replication server on `replication_server`. +- This operation will result in writing to the Raft log. + +**Implications:** In case the main instance already exists in the cluster, a replica instance will be automatically connected to the main. If a replication mode is not specified, REPLICA will be registered in `SYNC` replication mode. Constructs `( AS ASYNC | AS STRICT_SYNC )` serve to specify a different replication mode other than `SYNC`. @@ -35,132 +115,131 @@ Constructs `( AS ASYNC | AS STRICT_SYNC )` serve to specify a different replicat You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. - -### Add coordinator instance - -The user can choose any coordinator instance to run cluster setup queries. This can be done before or after registering data instances, -the order isn't important. - -```plaintext -ADD COORDINATOR coordinatorId WITH CONFIG {"bolt_server": boltServer, "coordinator_server": coordinatorServer}; +**Example:** +```cypher +REGISTER INSTANCE instance1 WITH CONFIG { + "bolt_server": "my_outside_instance1_IP:7687", + "management_server": "???:10000", + "replication_server": "???:20000" +}; ``` - +### UNREGISTER INSTANCE -`ADD COORDINATOR` query needs to be run for all coordinators in the cluster. +There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. +The hardware can be broken, network communication could be set up incorrectly, etc. The user can remove the instance +from the cluster using the following query: -``` -ADD COORDINATOR 1 WITH CONFIG {"bolt_server": "127.0.0.1:7691", "coordinator_server": "127.0.0.1:10111", "management_server": "127.0.0.1:12111"}; -ADD COORDINATOR 2 WITH CONFIG {"bolt_server": "127.0.0.1:7692", "coordinator_server": "127.0.0.1:10112", "management_server": "127.0.0.1:12112"}; -ADD COORDINATOR 3 WITH CONFIG {"bolt_server": "127.0.0.1:7693", "coordinator_server": "127.0.0.1:10113", "management_server": "127.0.0.1:12113"}; +```cypher +UNREGISTER INSTANCE instanceName; ``` - +**Parameters:** +- `instanceName` (symbolic name) - respective name of the data instance -### Remove coordinator instance +**Implications:** +When unregistering an instance, ensure that the instance being unregistered is +**not** the MAIN instance. Unregistering MAIN can lead to an inconsistent +cluster state. Additionally, the cluster must have an **alive** MAIN instance +during the unregistration process. If no MAIN instance is available, the +operation cannot be guaranteed to succeed. -If during cluster setup or at some later stage of cluster life, the user decides to remove some coordinator instance, `REMOVE COORDINATOR` query can be used. -Only on leader can this query be executed in order to remove followers. Current cluster's leader cannot be removed since this is prohibited -by NuRaft. In order to remove the current leader, you first need to trigger leadership change. +The instance requested to be unregistered will also be unregistered from the current MAIN's replica set. -```plaintext -REMOVE COORDINATOR ; +**Example:** +```cypher +UNREGISTER INSTANCE instance_1; ``` +## Replication role management queries -### Set instance to main +### SET INSTANCE TO MAIN -Once all data instances are registered, one data instance should be promoted to main. This can be achieved by using the following query: +Once all data instances are registered, one data instance should be promoted to main. +This can be achieved by using the following query: -```plaintext -SET INSTANCE instanceName to main; +```cypher +SET INSTANCE instanceName TO MAIN; ``` -This query will register all other instances as replicas to the new main. If one of the instances is unavailable, setting the instance to main will not succeed. -If there is already a main instance in the cluster, this query will fail. +**Parameters:** +- `instanceName` (symbolic name) - name of the data instance that is going to be promoted to main +**Behaviour:** +This query will register all other instances as replicas to the new main. This operation will result in writing to the Raft log. -### Demote instance +**Implications: +If one of the instances is unavailable, setting the instance to MAIN will not succeed. +If there is already a MAIN instance in the cluster, this query will fail. -Demote instance query can be used by an admin to demote the current main to replica. In this case, the leader coordinator won't perform a failover, but as a user, -you should choose promote one of the data instances to main using the `SET INSTANCE `instance` TO main` query. +**Example:** +```cypher +SET INSTANCE instance_0 TO MAIN; +``` + +### DEMOTE INSTANCE -```plaintext +Demote instance query can be used by an admin to demote the current MAIN to REPLICA. + +```cypher DEMOTE INSTANCE instanceName; ``` -This operation will result in writing to the Raft log. +**Behaviour:** +- MAIN is demoted to REPLICA +- This operation will result in writing to the Raft log. - +**Implications:** +- In this case, the leader coordinator won't perform a failover, but as a user, you should choose promote one of +the data instances to main using the `SET INSTANCE `instance` TO main` query. + By combining the functionalities of queries `DEMOTE INSTANCE instanceName` and `SET INSTANCE instanceName TO main` you get the manual failover capability. This can be useful e.g during a maintenance work on the instance where the current main is deployed. - - -### Unregister instance - -There are various reasons which could lead to the decision that an instance needs to be removed from the cluster. The hardware can be broken, -network communication could be set up incorrectly, etc. The user can remove the instance from the cluster using the following query: - -```plaintext -UNREGISTER INSTANCE instanceName; +**Example:** +```cypher +DEMOTE INSTANCE instance1; ``` -When unregistering an instance, ensure that the instance being unregistered is -**not** the main instance. Unregistering main can lead to an inconsistent -cluster state. Additionally, the cluster must have an **alive** main instance -during the unregistration process. If no main instance is available, the -operation cannot be guaranteed to succeed. - -The instance requested to be unregistered will also be unregistered from the current main's replica set. +## Monitoring commands -### Force reset cluster state +### SHOW INSTANCES -In case the cluster gets stuck there is an option to do the force reset of the cluster. You need to execute a command on the leader coordinator. -This command will result in the following actions: - -1. The coordinator instance will demote each alive instance to replica. -2. From the alive instance it will choose a new main instance. -3. Instances that are down will be demoted to replicas once they come back up. +You can check the state of the whole cluster using the `SHOW INSTANCES` query. -```plaintext -FORCE RESET CLUSTER STATE; +```cypher +SHOW INSTANCES; ``` -This operation will result in writing to the Raft log. - -### Show instances - -You can check the state of the whole cluster using the `SHOW INSTANCES` query. The query will display all the Memgraph servers visible in the cluster. With +**Behaviour:** +The query will display all the Memgraph servers visible in the cluster. With each server you can see the following information: 1. Network endpoints they are using for managing cluster state 2. Health state of server 3. Role - main, replica, LEADER, FOLLOWER or unknown if not alive 4. The time passed since the last response time to the leader's health ping -This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state and last response time, -followers will execute actions in this exact order: +**Implications:** +This query can be run on either the leader or followers. Since only the leader knows the exact status of the health state +and last response time, followers will execute actions in this exact order: 1. Try contacting the leader to get the health state of the cluster, since the leader has all the information. If the leader responds, the follower will return the result as if the `SHOW INSTANCES` query was run on the leader. 2. When the leader doesn't respond or currently there is no leader, the follower will return all the Memgraph servers with the health state set to "down". -```plaintext -SHOW INSTANCES; -``` - -### Show instance +### SHOW INSTANCE You can check the state of the current coordinator to which you are connected by running the following query: -```plaintext +```cypher SHOW INSTANCE; ``` +**Behaviour:** This query will return the information about: 1. instance name 2. external bolt server to which you can connect using Memgraph clients @@ -168,16 +247,42 @@ This query will return the information about: 4. management server which is also used for inter-coordinators communication and 5. cluster role: whether the coordinator is currently a leader of the follower. +**Implications:** If the query `ADD COORDINATOR` wasn't run for the current instance, the value of the bolt server will be "". -### Show replication lag +### SHOW REPLICATION LAG -The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. The replication lag is expressed with -the number of committed transactions. Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. The information -about the replication lag can be useful when manually performing a failover to check whether there is a risk of a data loss. +The user can find the current replication lag on each instance by running `SHOW REPLICATION LAG` on the cluster's leader. +The replication lag is expressed with the number of committed transactions. -```plaintext +```cypher SHOW REPLICATION LAG; ``` +**Implications:** +- Such an info is made durable through snapshots and WALs so restarts won't cause the information loss. +- The information about the replication lag can be useful when manually performing a failover to check whether there is a +risk of a data loss. + +## Troubleshooting commands + +### FORCE RESET CLUSTER STATE + +In case the cluster can't get into a healthy state, or any unexpected event occurs, there is an option to do the force +reset of the cluster. + +```cypher +FORCE RESET CLUSTER STATE; +``` + +**Behaviour:** +1. The coordinator instance will demote each alive instance to replica. +2. From the alive instance it will choose a new main instance. +3. Instances that are down will be demoted to replicas once they come back up. + +This operation will result in writing to the Raft log. + +**Implications:** +You need to execute a command on the leader coordinator. + From 9a7e7de9402c31e39060b41adf2378b51f129329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Wed, 12 Nov 2025 15:52:04 +0100 Subject: [PATCH 09/13] Update concerns --- .../high-availability/best-practices.mdx | 40 +++++++++---------- .../ha-commands-reference.mdx | 23 +++++++---- .../setup-ha-cluster-docker-compose.mdx | 5 ++- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/pages/clustering/high-availability/best-practices.mdx b/pages/clustering/high-availability/best-practices.mdx index 9ad276a01..d4909f13f 100644 --- a/pages/clustering/high-availability/best-practices.mdx +++ b/pages/clustering/high-availability/best-practices.mdx @@ -175,7 +175,6 @@ have precedence over command line arguments**, and any set environment variable ## Coordinator settings ### enabled reads on main - There is a configuration option for specifying whether reads from the main are enabled. The configuration value is by default false but can be changed in run-time using the following query: @@ -184,22 +183,28 @@ SET COORDINATOR SETTING 'enabled_reads_on_main' TO 'true'/'false' ; ``` ### sync failover only - -Users can also choose whether failover to the async replica is allowed by using the following query: +Users can also choose whether failover to the ASYNC REPLICA is allowed by using the following query: ``` SET COORDINATOR SETTING 'sync_failover_only' TO 'true'/'false' ; ``` -### max failover replica lag +By default, the value is `true`, which means that only SYNC REPLICAs are candidates in the election. When the value is set to +`false`, the ASYNC REPLICA is also considered, but there is an additional risk of experiencing data loss. + +In extreme cases, failover to an ASYNC REPLICA may be necessary when other SYNC REPLICAs are down and you want to +manually perform a failover. -Users can control the maximum transaction lag allowed during failover through configuration. If a replica is behind the main instance by more than the configured threshold, -that replica becomes ineligible for failover. This prevents data loss beyond the user's acceptable limits. +### max failover replica lag +Users can control the maximum transaction lag allowed during failover through configuration. If a REPLICA is behind the MAIN +instance by more than the configured threshold, that REPLICA becomes ineligible for failover. This prevents data loss +beyond the user's acceptable limits. -To implement this functionality, we employ a caching mechanism on the cluster leader that tracks replicas' lag. The cache gets updated with each StateCheckRpc response from -replicas. During the brief failover window on the cooordinators' side, the new cluster leader may not have the current lag information for all data instances and in that case, -any replica can become main. This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety guarantees -in the large majority of situations. +To implement this functionality, we employ a caching mechanism on the cluster leader coordinator that tracks replicas' lag. The cache gets +updated with each `StateCheckRpc` response from REPLICAs. During the brief failover window on the cooordinators' side, the new +cluster leader may not have the current lag information for all data instances and in that case, any REPLICA can become MAIN. +This trade-off is intentional and it avoids flooding Raft logs with frequently-changing lag data while maintaining failover safety +guarantees in the large majority of situations. The configuration value can be controlled using the query: @@ -208,20 +213,15 @@ The configuration value can be controlled using the query: SET COORDINATOR SETTING 'max_failover_replica_lag' TO '10' ; ``` -By default, the value is `true`, which means that only sync replicas are candidates in the election. When the value is set to `false`, the async replica is also considered, but -there is an additional risk of experiencing data loss. However, failover to an async replica may be necessary when other sync replicas are down and you want to -manually perform a failover. - -### max_replica_read_lag_ ??? - - -Users can control the maximum allowed replica lag to maintain read consistency. When a replica falls behind the current main by more than `max_replica_read_lag_` transactions, the -bolt+routing protocol will exclude that replica from read query routing to ensure data freshness. +### max_replica_read_lag +Users can control the maximum allowed REPLICA lag to maintain read consistency. When a REPLICA falls behind the current MAIN by +more than `max_replica_read_lag` transactions, the bolt+routing protocol will exclude that REPLICA from read query routing to +ensure data freshness. The configuration value can be controlled using the query: ``` -SET COORDINATOR SETTING 'max_replica_read_lag_' TO '10' ; +SET COORDINATOR SETTING 'max_replica_read_lag' TO '10' ; ``` ## Observability diff --git a/pages/clustering/high-availability/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx index e3dec90ed..8129865d9 100644 --- a/pages/clustering/high-availability/ha-commands-reference.mdx +++ b/pages/clustering/high-availability/ha-commands-reference.mdx @@ -33,7 +33,7 @@ ADD COORDINATOR coordinatorId WITH CONFIG { **Parameters:** - `coordinatorId` (int) - unique integer for each coordinator. You can set a different incrementing integer for each coordinator as you register them. -- `boltServer` (string) - Network address in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`. Port is usually set to 7687 as +- `boltServer` (string) - Network address in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`, used for querying the coordinator. Port is usually set to 7687 as that is representative for Bolt protocol. If IPs are ephemeral, it's best to use the DNS name/FQDN. The server IP needs to be exposed to the external network, if there are any external applications connected to it. - `coordinatorServer` (string) - Network address in format `"COORDINATOR_HOSTNAME|COORDINATOR_PORT"`. Coordinator hostname and port @@ -94,11 +94,15 @@ REGISTER INSTANCE instanceName ( AS ASYNC | AS STRICT_SYNC ) ? WITH CONFIG { - `instanceName` (symbolic name) - unique name of the data instance - `AS ASYNC` (optional parameter) - register the instance in `ASYNC` replication mode - `AS STRICT_SYNC` (optional parameter) - register the instance in `STRICT_SYNC` replication mode -- `boltServer` (string) - Network address in format "IP_ADDRESS|DNS_NAME:PORT_NUMBER". Port is usually set to 7687 as - that is representative for Bolt protocol. If IPs are ephemeral, it's best to use the DNS name/FQDN. The server IP needs - to be exposed to the external network, if there are any external applications connected to it. -- `managementServer` (string) - ??? -- `replicationServer` (string) - ??? +- `boltServer` (string) - Server endpoint used for executing queries against the instance. The endpoint needs to be + in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`. Port is usually set to 7687 as that is representative for Bolt protocol. + If IPs are ephemeral, it's best to use the DNS name/FQDN. The server IP needs to be exposed to the external network, + if there are any external applications connected to it. +- `managementServer` (string) - Server endpoint used for communication between coordinator and data instance. The endpoint + needs to be in format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`. The management port needs to be the same, as provided in the command line + arguments for that data instance. +- `replicationServer` (string) - Server endpoint used for replicating data between data instances. The endpoint needs to be in + format `"IP_ADDRESS|DNS_NAME:PORT_NUMBER"`. Usual port that is assigned for replication server is 20000. **Behaviour:** - The coordinator instance will connect to the data instance on the `management_server` network address. @@ -115,12 +119,15 @@ Constructs `( AS ASYNC | AS STRICT_SYNC )` serve to specify a different replicat You can only have `STRICT_SYNC` and `ASYNC` or `SYNC` and `ASYNC` replicas together in the cluster. Combining `STRICT_SYNC` and `SYNC` replicas together doesn't have proper semantic meaning so it is forbidden. +For local development, hostname of the data instance for management server and replication server is `localhost`. For Helm charts, +check the name of the service (e.g. `memgraph-coordinator-1.default.svc.cluster.local`). + **Example:** ```cypher REGISTER INSTANCE instance1 WITH CONFIG { "bolt_server": "my_outside_instance1_IP:7687", - "management_server": "???:10000", - "replication_server": "???:20000" + "management_server": "memgraph-data-1.default.svc.cluster.local:10000", + "replication_server": "memgraph-data-1.default.svc.cluster.local:20000" }; ``` diff --git a/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx index 52f9511ac..a99057d18 100644 --- a/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx +++ b/pages/clustering/high-availability/setup-ha-cluster-docker-compose.mdx @@ -288,6 +288,9 @@ coordinators in the cluster: For localhost development: Since the host can't resolve the IP for coordinators and data instances, Bolt -servers in Docker Compose setup require `bolt_server` set to `localhost:`. ??? +servers in Docker Compose setup require `bolt_server` set to `localhost:`, instead of `127.0.0.1`. + +This behaviour is such, because in some Docker Setups, for different machines, the `localhost` is intercepted, +and mapped to the host network automatically, while `127.0.0.1` stays within the container. \ No newline at end of file From 5087847c2b60d9982a1a1608217b6f9eafa1ae9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Thu, 20 Nov 2025 10:07:19 +0100 Subject: [PATCH 10/13] Add change from memgraph 3.7 --- pages/clustering/concepts/how-high-availability-works.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx index e283db756..cd6684602 100644 --- a/pages/clustering/concepts/how-high-availability-works.mdx +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -299,7 +299,8 @@ the cluster: synchronize its state. - The REPLICA's old durability files will be preserved in a `.old` directory in `data_directory/snapshots` and `data_directory/wal` folders, allowing admins - to manually recover data if needed. + to manually recover data if needed. The `.old` directory is reused for subsequent + recovery operations, meaning **only a single backup is maintained at any time**. Depending on the replication mode used, there are different levels of data loss that can happen upon the failover. With the default `SYNC` replication mode, From 9274b0a95076557b3953698df43d04d62b1a58fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Thu, 20 Nov 2025 10:11:11 +0100 Subject: [PATCH 11/13] Remove croatian language --- .../concepts/how-high-availability-works.mdx | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx index cd6684602..3c242812b 100644 --- a/pages/clustering/concepts/how-high-availability-works.mdx +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -108,26 +108,28 @@ for replication and high availability tasks. Memgraph is ensuring a consistent state of the cluster using RPC messages. Below is a full list of RPC messages and their purpose. Each -- `ShowInstancesRpc` - sent by the follower coordinator to the leader coordinator if the user executed `SHOW INSTANCES` through the follower - coordinator -- `DemoteMainToReplicaRpc` - sent by the leader coordinator to the old MAIN in order to demote it to REPLICA -- `PromoteToMainRpc` - sent by the leader coordinator to a REPLICA in order to promote it to MAIN -- `RegisterReplicaOnMainRpc` - sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN -- `UnregisterReplicaRpc` - sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN -- `EnableWritingOnMainRpc` - sent by the leader coordinator to MAIN to enable writing on that MAIN -- `GetDatabaseHistoriesRpc` - sent by the leader coordinator to all REPLICA instances in order to select new MAIN - during the failover process -- `StateCheckRpc` - sent by the leader coordinator to all data instances for liveness check -- `SwapMainUUIDRpc` - sent by the leader coordinator to REPLICA instances to set which MAIN to listen to -- `FrequentHeartbeatRpc` - sent by the MAIN instance to a REPLICA for liveness check -- `HeartbeatRpc` - sent by the MAIN instance to a REPLICA instance for timestamp/epoch/transaction/commit information -- `SystemRecoveryRpc` - sent by the MAIN instance to a REPLICA instance for system replication queries (auth, multi-tenancy) - and other non-graph information -- `PrepareCommitRpc` - main replici (prva faza u strict syncu ili jedina faza u ostalima), pošalje delta stream -- `FinalizeCommitRpc` - samo za strict sync za 2pc, s maina na replice ako su sve strict sync replice odgovorile pozitivno za commitat -- `SnapshotRpc` - sent by the MAIN to a REPLICA for snapshot recovery to catch-up with the MAIN instance -- `WalFilesRpc` - sent by the MAIN to a REPLICA for WAL recovery to catch-up with the MAIN instance -- `CurrentWalRpc` - sent by the MAIN to a REPLICA for current/latest/unfinished WAL file recovery to catch-up with the MAIN instance +- `ShowInstancesRpc` - Sent by the follower coordinator to the leader coordinator if the user executed `SHOW INSTANCES` through the follower + coordinator. +- `DemoteMainToReplicaRpc` - Sent by the leader coordinator to the old MAIN in order to demote it to REPLICA. +- `PromoteToMainRpc` - Sent by the leader coordinator to a REPLICA in order to promote it to MAIN. +- `RegisterReplicaOnMainRpc` - Sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN. +- `UnregisterReplicaRpc` - Sent by the leader coordinator to MAIN in order to register a REPLICA on MAIN. +- `EnableWritingOnMainRpc` - Sent by the leader coordinator to MAIN to enable writing on that MAIN. +- `GetDatabaseHistoriesRpc` - Sent by the leader coordinator to all REPLICA instances in order to select new MAIN + during the failover process. +- `StateCheckRpc` - Sent by the leader coordinator to all data instances for liveness check. +- `SwapMainUUIDRpc` - Sent by the leader coordinator to REPLICA instances to set which MAIN to listen to. +- `FrequentHeartbeatRpc` - Sent by the MAIN instance to a REPLICA for liveness check. +- `HeartbeatRpc` - Sent by the MAIN instance to a REPLICA instance for timestamp/epoch/transaction/commit information. +- `SystemRecoveryRpc` - Sent by the MAIN instance to a REPLICA instance for system replication queries (auth, multi-tenancy) + and other non-graph information. +- `PrepareCommitRpc` - Sent by the MAIN instance to the REPLICA instances, either as a first phase in `STRICT_SYNC` mode, or as the only phase in other + replication modes. Used to send the delta stream during the execution of a write query. +- `FinalizeCommitRpc` - Sent by the MAIN instance to the REPLICA instances in `STRICT_SYNC` replication mode when all the REPLICAs have + answered that they're ready to commit. +- `SnapshotRpc` - Sent by the MAIN to a REPLICA for snapshot recovery to catch-up with the MAIN instance. +- `WalFilesRpc` - Sent by the MAIN to a REPLICA for WAL recovery to catch-up with the MAIN instance. +- `CurrentWalRpc` - Sent by the MAIN to a REPLICA for current/latest/unfinished WAL file recovery to catch-up with the MAIN instance. #### RPC timeouts From 8f98f3d956e538b74a0d1ce2fdc7aa8fd824c83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Thu, 20 Nov 2025 11:48:03 +0100 Subject: [PATCH 12/13] Add flowchart images --- .../concepts/how-high-availability-works.mdx | 4 ++-- .../main-rejoining-cluster.png | Bin 0 -> 49981 bytes .../replica-rejoining-cluster.png | Bin 0 -> 31476 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 public/pages/clustering/high-availability/main-rejoining-cluster.png create mode 100644 public/pages/clustering/high-availability/replica-rejoining-cluster.png diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx index 3c242812b..131f712aa 100644 --- a/pages/clustering/concepts/how-high-availability-works.mdx +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -227,7 +227,7 @@ Depending on the data instance role, we have 2 scenarios: 1. In case a **REPLICA instance doesn't respond to a health check**, the leader coordinator will try to contact it again on the next scheduled interval. **Replica instance will always rejoin the cluster as a replica.** -??? flowchart diagram +![](/pages/clustering/high-availability/replica-rejoining-cluser.png) 2. In case a **MAIN instance doesn't respond to a health check**, there are two options: - If it is down for less than `--instance-down-timeout-sec` interval, it will rejoin as MAIN because it is still considered alive. @@ -236,7 +236,7 @@ Depending on the data instance role, we have 2 scenarios: - If the failover procedure succeeds, now old main will rejoin as REPLICA. - If failover doesn't succeed, MAIN will rejoin as MAIN once it comes back up. -??? flowchart diagram +![](/pages/clustering/high-availability/main-rejoining-cluster.png) You can check the [best practices](/clustering/high-availability/best-practices) if you want to see more about instance health check configuration. diff --git a/public/pages/clustering/high-availability/main-rejoining-cluster.png b/public/pages/clustering/high-availability/main-rejoining-cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..389e3dae2cc56daa6636f7c5a51e978a3920d789 GIT binary patch literal 49981 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 literal 0 HcmV?d00001 diff --git a/public/pages/clustering/high-availability/replica-rejoining-cluster.png b/public/pages/clustering/high-availability/replica-rejoining-cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..86dd09a1ed9efe6d582bb906310175da461676f8 GIT binary patch literal 31476 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 literal 0 HcmV?d00001 From f5b045ccc65e463b948affb29f9bdc6b5531fba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Mr=C4=91en?= Date: Thu, 20 Nov 2025 11:49:21 +0100 Subject: [PATCH 13/13] Typo --- pages/clustering/concepts/how-high-availability-works.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/clustering/concepts/how-high-availability-works.mdx b/pages/clustering/concepts/how-high-availability-works.mdx index 131f712aa..5860643ce 100644 --- a/pages/clustering/concepts/how-high-availability-works.mdx +++ b/pages/clustering/concepts/how-high-availability-works.mdx @@ -227,7 +227,7 @@ Depending on the data instance role, we have 2 scenarios: 1. In case a **REPLICA instance doesn't respond to a health check**, the leader coordinator will try to contact it again on the next scheduled interval. **Replica instance will always rejoin the cluster as a replica.** -![](/pages/clustering/high-availability/replica-rejoining-cluser.png) +![](/pages/clustering/high-availability/replica-rejoining-cluster.png) 2. In case a **MAIN instance doesn't respond to a health check**, there are two options: - If it is down for less than `--instance-down-timeout-sec` interval, it will rejoin as MAIN because it is still considered alive.