In this tutorial, we will study the basics of replication in Manticore Search.
Shortly about replication
Manticore search daemon can replicate a write transaction in a Real-Time or Percolate index to other nodes in the cluster.
You can try it alive here or read below.
To use replication with the daemon you need to make sure:
- your build supports replication (on by default in Manticore official builds - https://manticoresearch.com/downloads/)
- set data_dir option in the searchd section of the config. This is where incoming indexes are stored
- set listen option with a range of at least two ports per cluster for the replication protocol
- set listen option for the SphinxAPI protocol
- set listen option for the SphinxQL protocol (to execute cluster manipulation statements)
- optionally set server_id option. The values must be unique across the cluster. When it’s not set the server_ids will be auto-generated
You can take a look at the example of Manticore config used for this demo:
cat /etc/sphinxsearch/sphinx1.conf
index pq {
type = percolate
path = /var/lib/manticore/data/pq1
}
index testrt
{
type = rt
path = /var/lib/manticore/data/testrt1
rt_field = title
rt_field = content
rt_attr_uint = gid
}
searchd {
listen = 127.0.0.1:9312
listen = 127.0.0.1:9306:mysql41
listen = 127.0.0.1:9350-9359:replication
data_dir = /var/run/manticore/replication/1
log = /var/run/manticore/log/searchd1.log
pid_file = /var/run/manticore/searchd1.pid
binlog_path = /var/run/manticore/data/pq1
server_id = 1
}
We have two instances of Manticore search daemon running on different ports (9306 and 9307) here to represent two nodes in our future cluster. The other one’s config is:
cat /etc/sphinxsearch/sphinx2.conf
searchd {
listen = 127.0.0.1:9313
listen = 127.0.0.1:9307:mysql41
listen = 127.0.0.1:9360-9369:replication
data_dir = /var/run/manticore/replication/2
log = /var/run/manticore/log/searchd2.log
pid_file = /var/run/manticore/searchd2.pid
binlog_path = /var/run/manticore/data/pq2
server_id = 2
}
Let’s connect to the first one:
mysql -P 9306 -h0
root@replication-5b59c59f5c-mkqfc:/# mysql -P 9306 -h0
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 3.1.0 445e806e@190716 release
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
and create a new cluster in it.
Creating new cluster
CREATE CLUSTER posts;
MySQL [(none)]> CREATE CLUSTER posts;
Query OK, 0 rows affected (0.90 sec)
To make sure the cluster’s been created successfully, use SHOW STATUS command:
SHOW STATUS LIKE 'cluster%';
MySQL [(none)]> SHOW STATUS LIKE 'cluster%';
+------------------------------------------+----------------------------------------------+
| Counter | Value |
+------------------------------------------+----------------------------------------------+
| cluster_name | posts |
| cluster_posts_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_conf_id | 1 |
| cluster_posts_status | primary |
| cluster_posts_size | 1 |
| cluster_posts_local_index | 0 |
| cluster_posts_node_state | synced |
| cluster_posts_nodes_set | |
| cluster_posts_nodes_view | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_indexes_count | 0 |
| cluster_posts_indexes | |
| cluster_posts_local_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_protocol_version | 9 |
| cluster_posts_last_applied | 0 |
| cluster_posts_last_committed | 0 |
| cluster_posts_replicated | 0 |
| cluster_posts_replicated_bytes | 0 |
| cluster_posts_repl_keys | 0 |
| cluster_posts_repl_keys_bytes | 0 |
| cluster_posts_repl_data_bytes | 0 |
| cluster_posts_repl_other_bytes | 0 |
| cluster_posts_received | 2 |
| cluster_posts_received_bytes | 175 |
| cluster_posts_local_commits | 0 |
| cluster_posts_local_cert_failures | 0 |
| cluster_posts_local_replays | 0 |
| cluster_posts_local_send_queue | 0 |
| cluster_posts_local_send_queue_max | 2 |
| cluster_posts_local_send_queue_min | 0 |
| cluster_posts_local_send_queue_avg | 0.500000 |
| cluster_posts_local_recv_queue | 0 |
| cluster_posts_local_recv_queue_max | 2 |
| cluster_posts_local_recv_queue_min | 0 |
| cluster_posts_local_recv_queue_avg | 0.500000 |
| cluster_posts_local_cached_downto | 0 |
| cluster_posts_flow_control_paused_ns | 0 |
| cluster_posts_flow_control_paused | 0.000000 |
| cluster_posts_flow_control_sent | 0 |
| cluster_posts_flow_control_recv | 0 |
| cluster_posts_flow_control_interval | [ 100, 100 ] |
| cluster_posts_flow_control_interval_low | 100 |
| cluster_posts_flow_control_interval_high | 100 |
| cluster_posts_flow_control_status | OFF |
| cluster_posts_cert_deps_distance | 0.000000 |
| cluster_posts_apply_oooe | 0.000000 |
| cluster_posts_apply_oool | 0.000000 |
| cluster_posts_apply_window | 0.000000 |
| cluster_posts_commit_oooe | 0.000000 |
| cluster_posts_commit_oool | 0.000000 |
| cluster_posts_commit_window | 0.000000 |
| cluster_posts_local_state | 4 |
| cluster_posts_local_state_comment | Synced |
| cluster_posts_cert_index_size | 0 |
| cluster_posts_cert_bucket_count | 2 |
| cluster_posts_gcache_pool_size | 1320 |
| cluster_posts_causal_reads | 0 |
| cluster_posts_cert_interval | 0.000000 |
| cluster_posts_open_transactions | 0 |
| cluster_posts_open_connections | 0 |
| cluster_posts_ist_receive_status | |
| cluster_posts_ist_receive_seqno_start | 0 |
| cluster_posts_ist_receive_seqno_current | 0 |
| cluster_posts_ist_receive_seqno_end | 0 |
| cluster_posts_incoming_addresses | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_cluster_weight | 1 |
| cluster_posts_desync_count | 0 |
| cluster_posts_evs_delayed | |
| cluster_posts_evs_evict_list | |
| cluster_posts_evs_repl_latency | 1.075e-06/7.957e-06/2.2911e-05/8.12112e-06/5 |
| cluster_posts_evs_state | OPERATIONAL |
| cluster_posts_gcomm_uuid | 95b52441-c296-11e9-abae-52c260760909 |
+------------------------------------------+----------------------------------------------+
71 rows in set (0.00 sec)
You can see the information of our new cluster appeared in the status fields.
Let’s insert some data into our testrt index.
INSERT INTO testrt VALUES(1,'List of HP business laptops','Elitebook Probook',10);
MySQL [(none)]> INSERT INTO testrt VALUES(1,'List of HP business laptops
','Elitebook Probook',10);
Query OK, 1 row affected (0.10 sec)
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
Note that all write statements such as INSERT, REPLACE, DELETE, TRUNCATE that are supposed to change the index in the cluster must use cluster_name:index_nameformat instead of a plain index_name to ensure the changes are propagated to all the replicas in the cluster. An error will be triggered otherwise (see below). But until an index is in a cluster you can insert into it without any prefix:
INSERT INTO testrt VALUES(2,'List of Dell business laptops','Latitude Precision Vostro',10);
MySQL [(none)]> INSERT INTO testrt VALUES(2,'List of Dell business laptops','Latitude Precision Vostro',10);
Query OK, 1 row affected (0.00 sec)
When you try to insert a document into an index within a cluster you need to prepend the cluster name to the index name:
INSERT INTO posts:testrt VALUES(3,'List of Dell business laptops','Latitude Precision Vostro',10);
MySQL [(none)]> INSERT INTO posts:testrt VALUES(3,'List of Dell business laptops','Latitude Precision Vostro',10);
ERROR 1064 (42000): index 'testrt' is not in any cluster, use just 'testrt'
As the index is not in the cluster yet we see the error. To be able to replicate the new document, we should first add the index to the cluster. It can be done with the following statement:
ALTER CLUSTER posts ADD testrt;
MySQL [(none)]> ALTER CLUSTER posts ADD testrt;
Query OK, 0 rows affected (0.10 sec)
Our testrt index is now in the cluster, which can be checked by looking at cluster_posts_indexes status field (posts being the name of our cluster).
SHOW STATUS LIKE 'cluster_posts_indexes';
MySQL [(none)]> SHOW STATUS LIKE 'cluster_posts_indexes';
+-----------------------+--------+
| Counter | Value |
+-----------------------+--------+
| cluster_posts_indexes | testrt |
+-----------------------+--------+
1 row in set (0.00 sec)
Let’s insert more data into our testrt index:
INSERT INTO testrt VALUES(3,'List of Dell business laptops','Latitude Precision Vostro',10);
MySQL [(none)]> INSERT INTO testrt VALUES(3,'List of Dell business lapto ps','Latitude Precision Vostro',10);
ERROR 1064 (42000): index 'testrt' is a part of cluster 'posts', use 'posts:testrt'
Now we see the error, because the correct query is:
INSERT INTO posts:testrt VALUES(3,'List of Dell business laptops','Latitude Precision Vostro',10);
MySQL [(none)]> INSERT INTO posts:testrt VALUES(3,'List of Dell business laptops','Latitude Precision Vostro',10);
ERROR 1064 (42000): index 'testrt' is not in any cluster, use just 'testrt'
And it works as expected.
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
Joining a node to a cluster
Let’s go another other node we have.
exit;
MySQL [(none)]> exit;
Bye
mysql -P 9307 -h0
root@replication-5b59c59f5c-mkqfc:/# mysql -P 9307 -h0
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 3.1.0 445e806e@190716 release
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
We know this node is not in our cluster yet so it doesn’t contain any data in the testrt index we’ve added before at the other node. There’s no even index testrt
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
Let’s join to the cluster. To do that, use a JOIN CLUSTER statement. You’ll need to specify cluster name (as there may be multiple clusters) and the node you want to connect to:
JOIN CLUSTER posts at '127.0.0.1:9312';
MySQL [(none)]> JOIN CLUSTER posts at '127.0.0.1:9312';
Query OK, 0 rows affected (1.90 sec)
Now let’s try again:
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
We see that all the index data has been successfully replicated. Let’s insert one more value to the index.
INSERT INTO posts:testrt VALUES(4,'List of Dell gaming laptops','Inspirion Alienware',20);
MySQL [(none)]> INSERT INTO posts:testrt VALUES(4,'List of Dell gaming l aptops','Inspirion Alienware',20);
Query OK, 1 row affected (0.20 sec)
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
And now switch back to our first node:
exit;
MySQL [(none)]> exit;
Bye
mysql -P 9306 -h0
root@replication-5b59c59f5c-mkqfc:/# mysql -P 9306 -h0
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 3.1.0 445e806e@190716 release
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
As we see, the changes were replicated successfully.
Removing cluster indexes and clusters
Now we’ll remove our index from the cluster:
ALTER CLUSTER posts DROP testrt;
MySQL [(none)]> ALTER CLUSTER posts DROP testrt;
Query OK, 0 rows affected (0.00 sec)
SHOW STATUS LIKE 'cluster_posts_indexes';
MySQL [(none)]> SHOW STATUS LIKE 'cluster_posts_indexes';
+-----------------------+--------+
| Counter | Value |
+-----------------------+--------+
| cluster_posts_indexes | testrt |
+-----------------------+--------+
1 row in set (0.00 sec)
It worked!
SELECT * from testrt;
MySQL [(none)]> SELECT * from testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 20 |
+------+------+
4 rows in set (0.00 sec)
testrt index has become just a local non-replicated index. Let’s ensure that:
INSERT INTO testrt VALUES(5,'Lenovo laptops list','Yoga IdeaPad',30);
MySQL [(none)]> INSERT INTO testrt VALUES(5,'Lenovo laptops list','Yoga IdeaPad',30);
Query OK, 1 row affected (0.00 sec)
No warning about missing ‘posts:’, so ’testrt’ is not in the cluster any more.
SELECT * from testrt;
MySQL [(none)]> SELECT * from testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 20 |
+------+------+
4 rows in set (0.00 sec)
Let’s switch to our second node:
exit;
MySQL [(none)]> exit;
Bye
mysql -P 9307 -h0
root@replication-5b59c59f5c-mkqfc:/# mysql -P 9307 -h0
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 3.1.0 445e806e@190716 release
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
SELECT * from testrt;
MySQL [(none)]> SELECT * from testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 20 |
+------+------+
4 rows in set (0.00 sec)
As expected, the changes that we made at the first node were not replicated to the second node.
To remove the cluster completely use DELETE CLUSTER statement:
DELETE CLUSTER posts;
MySQL [(none)]> DELETE CLUSTER posts;
Query OK, 0 rows affected (6.20 sec)
SHOW STATUS LIKE 'cluster%';
MySQL [(none)]> SHOW STATUS LIKE 'cluster%';
+------------------------------------------+----------------------------------------------+
| Counter | Value |
+------------------------------------------+----------------------------------------------+
| cluster_name | posts |
| cluster_posts_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_conf_id | 1 |
| cluster_posts_status | primary |
| cluster_posts_size | 1 |
| cluster_posts_local_index | 0 |
| cluster_posts_node_state | synced |
| cluster_posts_nodes_set | |
| cluster_posts_nodes_view | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_indexes_count | 0 |
| cluster_posts_indexes | |
| cluster_posts_local_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_protocol_version | 9 |
| cluster_posts_last_applied | 0 |
| cluster_posts_last_committed | 0 |
| cluster_posts_replicated | 0 |
| cluster_posts_replicated_bytes | 0 |
| cluster_posts_repl_keys | 0 |
| cluster_posts_repl_keys_bytes | 0 |
| cluster_posts_repl_data_bytes | 0 |
| cluster_posts_repl_other_bytes | 0 |
| cluster_posts_received | 2 |
| cluster_posts_received_bytes | 175 |
| cluster_posts_local_commits | 0 |
| cluster_posts_local_cert_failures | 0 |
| cluster_posts_local_replays | 0 |
| cluster_posts_local_send_queue | 0 |
| cluster_posts_local_send_queue_max | 2 |
| cluster_posts_local_send_queue_min | 0 |
| cluster_posts_local_send_queue_avg | 0.500000 |
| cluster_posts_local_recv_queue | 0 |
| cluster_posts_local_recv_queue_max | 2 |
| cluster_posts_local_recv_queue_min | 0 |
| cluster_posts_local_recv_queue_avg | 0.500000 |
| cluster_posts_local_cached_downto | 0 |
| cluster_posts_flow_control_paused_ns | 0 |
| cluster_posts_flow_control_paused | 0.000000 |
| cluster_posts_flow_control_sent | 0 |
| cluster_posts_flow_control_recv | 0 |
| cluster_posts_flow_control_interval | [ 100, 100 ] |
| cluster_posts_flow_control_interval_low | 100 |
| cluster_posts_flow_control_interval_high | 100 |
| cluster_posts_flow_control_status | OFF |
| cluster_posts_cert_deps_distance | 0.000000 |
| cluster_posts_apply_oooe | 0.000000 |
| cluster_posts_apply_oool | 0.000000 |
| cluster_posts_apply_window | 0.000000 |
| cluster_posts_commit_oooe | 0.000000 |
| cluster_posts_commit_oool | 0.000000 |
| cluster_posts_commit_window | 0.000000 |
| cluster_posts_local_state | 4 |
| cluster_posts_local_state_comment | Synced |
| cluster_posts_cert_index_size | 0 |
| cluster_posts_cert_bucket_count | 2 |
| cluster_posts_gcache_pool_size | 1320 |
| cluster_posts_causal_reads | 0 |
| cluster_posts_cert_interval | 0.000000 |
| cluster_posts_open_transactions | 0 |
| cluster_posts_open_connections | 0 |
| cluster_posts_ist_receive_status | |
| cluster_posts_ist_receive_seqno_start | 0 |
| cluster_posts_ist_receive_seqno_current | 0 |
| cluster_posts_ist_receive_seqno_end | 0 |
| cluster_posts_incoming_addresses | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_cluster_weight | 1 |
| cluster_posts_desync_count | 0 |
| cluster_posts_evs_delayed | |
| cluster_posts_evs_evict_list | |
| cluster_posts_evs_repl_latency | 1.075e-06/7.957e-06/2.2911e-05/8.12112e-06/5 |
| cluster_posts_evs_state | OPERATIONAL |
| cluster_posts_gcomm_uuid | 95b52441-c296-11e9-abae-52c260760909 |
+------------------------------------------+----------------------------------------------+
71 rows in set (0.00 sec)
The cluster gets removed from all the nodes, but its indexes are left intact and become plain local non-replicated indexes.
SELECT * FROM testrt;
MySQL [(none)]> SELECT * FROM testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
+------+------+
1 row in set (0.10 sec)
To make sure it’s really removed from everywhere we can check the status of the other node:
exit;
MySQL [(none)]> exit;
Bye
mysql -P 9306 -h0
root@replication-5b59c59f5c-mkqfc:/# mysql -P 9306 -h0
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 3.1.0 445e806e@190716 release
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
SHOW STATUS LIKE 'cluster%';
MySQL [(none)]> SHOW STATUS LIKE 'cluster%';
+------------------------------------------+----------------------------------------------+
| Counter | Value |
+------------------------------------------+----------------------------------------------+
| cluster_name | posts |
| cluster_posts_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_conf_id | 1 |
| cluster_posts_status | primary |
| cluster_posts_size | 1 |
| cluster_posts_local_index | 0 |
| cluster_posts_node_state | synced |
| cluster_posts_nodes_set | |
| cluster_posts_nodes_view | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_indexes_count | 0 |
| cluster_posts_indexes | |
| cluster_posts_local_state_uuid | 95c2ffc3-c296-11e9-b475-9fad1c2e6dab |
| cluster_posts_protocol_version | 9 |
| cluster_posts_last_applied | 0 |
| cluster_posts_last_committed | 0 |
| cluster_posts_replicated | 0 |
| cluster_posts_replicated_bytes | 0 |
| cluster_posts_repl_keys | 0 |
| cluster_posts_repl_keys_bytes | 0 |
| cluster_posts_repl_data_bytes | 0 |
| cluster_posts_repl_other_bytes | 0 |
| cluster_posts_received | 2 |
| cluster_posts_received_bytes | 175 |
| cluster_posts_local_commits | 0 |
| cluster_posts_local_cert_failures | 0 |
| cluster_posts_local_replays | 0 |
| cluster_posts_local_send_queue | 0 |
| cluster_posts_local_send_queue_max | 2 |
| cluster_posts_local_send_queue_min | 0 |
| cluster_posts_local_send_queue_avg | 0.500000 |
| cluster_posts_local_recv_queue | 0 |
| cluster_posts_local_recv_queue_max | 2 |
| cluster_posts_local_recv_queue_min | 0 |
| cluster_posts_local_recv_queue_avg | 0.500000 |
| cluster_posts_local_cached_downto | 0 |
| cluster_posts_flow_control_paused_ns | 0 |
| cluster_posts_flow_control_paused | 0.000000 |
| cluster_posts_flow_control_sent | 0 |
| cluster_posts_flow_control_recv | 0 |
| cluster_posts_flow_control_interval | [ 100, 100 ] |
| cluster_posts_flow_control_interval_low | 100 |
| cluster_posts_flow_control_interval_high | 100 |
| cluster_posts_flow_control_status | OFF |
| cluster_posts_cert_deps_distance | 0.000000 |
| cluster_posts_apply_oooe | 0.000000 |
| cluster_posts_apply_oool | 0.000000 |
| cluster_posts_apply_window | 0.000000 |
| cluster_posts_commit_oooe | 0.000000 |
| cluster_posts_commit_oool | 0.000000 |
| cluster_posts_commit_window | 0.000000 |
| cluster_posts_local_state | 4 |
| cluster_posts_local_state_comment | Synced |
| cluster_posts_cert_index_size | 0 |
| cluster_posts_cert_bucket_count | 2 |
| cluster_posts_gcache_pool_size | 1320 |
| cluster_posts_causal_reads | 0 |
| cluster_posts_cert_interval | 0.000000 |
| cluster_posts_open_transactions | 0 |
| cluster_posts_open_connections | 0 |
| cluster_posts_ist_receive_status | |
| cluster_posts_ist_receive_seqno_start | 0 |
| cluster_posts_ist_receive_seqno_current | 0 |
| cluster_posts_ist_receive_seqno_end | 0 |
| cluster_posts_incoming_addresses | 127.0.0.1:9312,127.0.0.1:9350:replication |
| cluster_posts_cluster_weight | 1 |
| cluster_posts_desync_count | 0 |
| cluster_posts_evs_delayed | |
| cluster_posts_evs_evict_list | |
| cluster_posts_evs_repl_latency | 1.075e-06/7.957e-06/2.2911e-05/8.12112e-06/5 |
| cluster_posts_evs_state | OPERATIONAL |
| cluster_posts_gcomm_uuid | 95b52441-c296-11e9-abae-52c260760909 |
+------------------------------------------+----------------------------------------------+
71 rows in set (0.00 sec)
And we see that the cluster posts doesn’t exist here either.
Thank you for reading!
This article has given you a basic understanding of how replication in Manticore Search and which basic commands can be used to set up a simple cluster.