Sunday, March 01, 2015

MongoDB shard configuration

How To Create a Sharded Cluster in MongoDB
Introduction


MongoDB is a NoSQL document database system that scales well horizontally and implements data storage through a key-value system. A popular choice for web applications and websites, MongoDB is easy to implement and access programmatically.

MongoDB achieves scaling through a technique known as "sharding". Sharding is the process of writing data across different servers to distribute the read and write load and data storage requirements.

MongoDB Sharding Topology



Sharding is implemented through three separate components. Each part performs a specific function:

·         Config Server: Each production sharding implementation must contain exactly three configuration servers. This is to ensure redundancy and high availability.
Config servers are used to store the metadata that links requested data with the shard that contains it. It organizes the data so that information can be retrieved reliably and consistently.

·         Query Routers: The query routers are the machines that your application actually connects to. These machines are responsible for communicating to the config servers to figure out where the requested data is stored. It then accesses and returns the data from the appropriate shard(s).
Each query router runs the "mongos" command.

·         Shard Servers: Shards are responsible for the actual data storage operations. In production environments, a single shard is usually composed of a replica set instead of a single machine. This is to ensure that data will still be accessible in the event that a primary shard server goes offline.
Implementing replicating sets is outside of the scope of this tutorial, so we will configure our shards to be single machines instead of replica sets. You can easily modify this if you would like to configure replica sets for your own configuration.

Initial Set Up



If you were paying attention above, you probably noticed that this configuration requires quite a few machines. In this tutorial, we will configure an example sharding cluster that contains:

·         3 Config Servers (Required in production environments)
·         2 Query Routers (Minimum of 1 necessary)
·         4 Shard Servers (Minimum of 2 necessary)

This means that you will need nine VPS instances to follow along exactly. In reality, some of these functions can overlap (for instance, you can run a query router on the same VPS you use as a config server) and you only need one query router and a minimum of 2 shard servers.
We will go above this minimum in order to demonstrate adding multiple components of each type. We will also treat all of these components as discrete machines for clarity and simplicity.

For the purposes of this tutorial, we will refer to the components as being accessible at these subdomain:

·         Config Servers
o    config0.example.com
o    config1.example.com
o    config2.example.com

·         Query Routers
o    query0.example.com
o    query1.example.com

·         Shard Servers
o    shard0.example.com
o    shard1.example.com
o    shard2.example.com
o    shard3.example.com

If you do not set up subdomains, you can still follow along, but your configuration will not be as robust. If you wish to go this route, simply substitute the subdomain specifications with your droplet's IP address.

Initialize the Config Servers



The first components that must be set up are the configuration servers. These must be online and operational before the query routers or shards can be configured.
Log into your first configuration server as root.
The first thing we need to do is create a data directory, which is where the configuration server will store the metadata that associates location and content:
mkdir /mongo-metadata
Now, we simply have to start up the configuration server with the appropriate parameters. The service that provides the configuration server is called mongod. The default port number for this component is 27019.
We can start the configuration server with the following command:
mongod --configsvr --dbpath /mongo-metadata --port 27019
The server will start outputting information and will begin listening for connections from other components.
Repeat this process exactly on the other two configuration servers. The port number should be the same across all three servers.

 

Configure Query Router Instances



At this point, you should have all three of your configuration servers running and listening for connections. They must be operational before continuing.
Log into your first query router as root.
The first thing we need to do is stop the mongodb process on this instance if it is already running. The query routers use data locks that conflict with the main MongoDB process:
service mongodb stop
Next, we need to start the query router service with a specific configuration string. The configuration string must be exactly the same for every query router you configure (including the order of arguments). It is composed of the address of each configuration server and the port number it is operating on, separated by a comma.
They query router service is called mongos. The default port number for this process is 27017 (but the port number in the configuration refers to the configuration server port number, which is 27019 by default).
The end result is that the query router service is started with a string like this:

mongos --configdb config0.example.com:27019,config1.example.com:27019,config2.example.com:27019

Your first query router should begin to connect to the three configuration servers. Repeat these steps on the other query router. Remember that the mongodb service must be stopped prior to typing in the command.
Also, keep in mind that the exact same command must be used to start each query router. Failure to do so will result in an error.

Add Shards to the Cluster



Now that we have our configuration servers and query routers configured, we can begin adding the actual shard servers to our cluster. These shards will each hold a portion of the total data.

Log into one of your shard servers as root.

As we mentioned in the beginning, in this guide we will only be using single machine shards instead of replica sets. This is for the sake of brevity and simplicity of demonstration. In production environments, a replica set is very highly recommended in order to ensure the integrity and availability of the data. To configure replica sets in MongoDB, follow this guide.
To actually add the shards to the cluster, we will need to go through the query routers, which are now configured to act as our interface with the cluster. We can do this by connecting to any of the query routers like this:
mongo --host query0.example.com --port 27017
This will connect to the appropriate query router and open a mongo prompt. We will add all of our shard servers from this prompt.
To add our first shard, type:
sh.addShard( "shard0.example.com:27017" )
You can then add your remaining shard droplets in this same interface. You do not need to log into each shard server individually.
sh.addShard( "shard1.example.com:27017" )
sh.addShard( "shard2.example.com:27017" )
sh.addShard( "shard3.example.com:27017" )
If you are configuring a production cluster, complete with replication sets, you have to instead specify the replication set name and a replication set member to establish each set as a distinct shard. The syntax would look something like this:
sh.addShard( "rep_set_name/rep_set_member:27017" )

How to Enable Sharding for a Database Collection



MongoDB organizes information into databases. Inside each database, data is further compartmentalized through "collections". A collection is akin to a table in traditional relational database models.
In this section, we will be operating using the querying routers again. If you are not still connected to the query router, you can access it again using the same mongo command you used in the last section:
mongo --host config0.example.com --port 27017

Enable Sharding on the Database Level



We will enable sharding first on the database level. To do this, we will create a test database called (appropriately) test_db.
To create this database, we simply need to change to it. It will be marked as our current database and created dynamically when we first enter data into it:
use test_db
We can check that we are currently using the database we just created by typing:
db


test_db
We can see all of the available databases by typing:
show dbs
You may notice that the database that we just created does not show up. This is because it holds no data so it is not quite real yet.
We can enable sharding on this database by issuing this command:
sh.enableSharding("test_db")
Again, if we enter the show dbs command, we will not see our new database. However, if we switch to the config database which is generated automatically, and issue a find() command, our new database will be returned:
use config
db.databases.find()


{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test_db", "partitioned" : true, "primary" : "shard0003" }
Your database will show up with the show dbs command when MongoDB has added some data to the new database.

Enable Sharding on the Collections Level



Now that our database is marked as being available for sharding, we can enable sharding on a specific collection.
At this point, we need to decide on a sharding strategy. Sharding works by organizing data into different categories based on a specific field designated as the shard key in the documents it is storing. It puts all of the documents that have a matching shard key on the same shard.
For instance, if your database is storing employees at a company and your shard key is based on favorite color, MongoDB will put all of the employees with blue in the favorite color field on a single shard. This can lead to disproportional storage if everybody likes a few colors.
A better choice for a shard key would be something that's guaranteed to be more evenly distributed. For instance, in a large company, a birthday (month and day) field would probably be fairly evenly distributed.
In cases where you're unsure about how things will be distributed, or there is no appropriate field, you can create a "hashed" shard key based on an existing field. This is what we will be doing for our data.
We can create a collection called test_collection and hash its "id" field. Make sure we're using our testdb database and then issue the command:
use test_db
db.test_collection.ensureIndex( { _id : "hashed" } )
We can then shard the collection by issuing this command:
sh.shardCollection("test_db.test_collection", { "_id": "hashed" } )
This will shard the collection across all of the available shards.

Insert Test Data into the Collection



We can see our sharding in action by using a loop to create some objects. This loop comes directly from the MongoDB website for generating test data.
We can insert data into the collection using a simple loop like this:
use test_db
for (var i = 1; i <= 500; i++) db.test_collection.insert( { x : i } )
This will create 500 simple documents ( only an ID field and an "x" field containing a number) and distribute them among the different shards. You can see the results by typing:
db.test_collection.find()


{ "_id" : ObjectId("529d082c488a806798cc30d3"), "x" : 6 }
{ "_id" : ObjectId("529d082c488a806798cc30d0"), "x" : 3 }
{ "_id" : ObjectId("529d082c488a806798cc30d2"), "x" : 5 }
{ "_id" : ObjectId("529d082c488a806798cc30ce"), "x" : 1 }
{ "_id" : ObjectId("529d082c488a806798cc30d6"), "x" : 9 }
{ "_id" : ObjectId("529d082c488a806798cc30d1"), "x" : 4 }
{ "_id" : ObjectId("529d082c488a806798cc30d8"), "x" : 11 }
. . .
To get more values, type:
it


{ "_id" : ObjectId("529d082c488a806798cc30cf"), "x" : 2 }
{ "_id" : ObjectId("529d082c488a806798cc30dd"), "x" : 16 }
{ "_id" : ObjectId("529d082c488a806798cc30d4"), "x" : 7 }
{ "_id" : ObjectId("529d082c488a806798cc30da"), "x" : 13 }
{ "_id" : ObjectId("529d082c488a806798cc30d5"), "x" : 8 }
{ "_id" : ObjectId("529d082c488a806798cc30de"), "x" : 17 }
{ "_id" : ObjectId("529d082c488a806798cc30db"), "x" : 14 }
{ "_id" : ObjectId("529d082c488a806798cc30e1"), "x" : 20 }
. . .
To get information about the specific shards, you can type:
sh.status()


--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "version" : 3,
    "minCompatibleVersion" : 3,
    "currentVersion" : 4,
    "clusterId" : ObjectId("529cae0691365bef9308cd75")
}
  shards:
    {  "_id" : "shard0000",  "host" : "162.243.243.156:27017" }
    {  "_id" : "shard0001",  "host" : "162.243.243.155:27017" }
. . .
This will provide information about the chunks that MongoDB distributed between the shards.

Conclusion



By the end of this guide, you should be able to implement your own MongoDB sharding configuration. The specific configuration of your servers and the shard key that you choose for each collection will have a big impact on the performance of your cluster.
Choose the field or fields that have the best distribution properties and most closely represent the logical groupings that will be reflected in your database queries. If MongoDB only has to go to a single shard to retrieve your data, it will return faster.






Friday, February 08, 2013

Circular replication with 4 nodes


Circular replication with 4 nodes

1 Preliminary Note

In this tutorial I will show how to replicate the database manish on four MySQL nodes:

server1.example.com: IP address 192.168.1.1
server2.example.com: IP address 192.168.1.2
server3.example.com: IP address 192.168.1.3
server4.example.com: IP address 192.168.1.4

Each node is a master and a slave at the same time. All four systems are running centos5; however the configuration should apply to almost all distributions with little or no modifications.

Replication will work in a circle,the replication goes from server1 to server2, from server2 to server3, from server3 to server4, and from server4 back to server1:

... --> server1 --> server2 --> server3 --> server4 --> server1 --> ...


2 Installing MySQL 5.0

If MySQL 5.0 isn't already installed on server1 to server4, install it now:

server1/server2/server3/server4:

yum install mysql-server-5.0 mysql-client-5.0

To make sure that the replication can work, we must make MySQL listen on all interfaces.

server1/server2/server3/server4:

vi /etc/mysql/my.cnf

server1/server2/server3/server4:

/etc/init.d/mysql restart

Then check with

server1/server2/server3/server4:

netstat -tap | grep mysql

that MySQL is really listening on all interfaces:

server1:~# netstat -tap | grep mysql
tcp        0      0 *:mysql                 *:*                     LISTEN     5543/mysqld



Afterthis, set a MySQL password for the user root@localhost:

server1/server2/server3/server4:

mysqladmin -u root password password



Next we create MySQL passwords for root@server1.example.com, root@server2.example.com, root@server3.example.com, and root@server4.example.com:

server1:

mysqladmin -h server1.example.com -u root password password

server2:

mysqladmin -h server2.example.com -u root password password

server3:

mysqladmin -h server3.example.com -u root password password

server4:

mysqladmin -h server4.example.com -u root password password

Now we set up a replication user repl_s2 that can be used by server2 to access the MySQL database on server1:

server1:

mysql -u root -p

On the MySQL shell, run the following commands:

GRANT REPLICATION SLAVE ON *.* TO 'repl_s2'@'%' IDENTIFIED BY 'repl2_password';
FLUSH PRIVILEGES;
quit;

Then we set up a replication user repl_s3 that can be used by server3 to access the MySQL database on server2...

server2:

mysql -u root -p

GRANT REPLICATION SLAVE ON *.* TO 'repl_s3'@'%' IDENTIFIED BY 'repl_password';
FLUSH PRIVILEGES;
quit;

... and a replication user repl_s4 that can be used by server4 to access the MySQL database on server3...

server3:

mysql -u root -p

GRANT REPLICATION SLAVE ON *.* TO 'repl_s4'@'%' IDENTIFIED BY 'repl_password';
FLUSH PRIVILEGES;
quit;

finally a replication user repl_s1 that can be used by server1 to access the MySQL database on server4:

server4:

mysql -u root -p

GRANT REPLICATION SLAVE ON *.* TO 'repl_s1'@'%' IDENTIFIED BY 'repl_password';
FLUSH PRIVILEGES;
quit;



3 Some Notes

In the following I will assume that the database exampledb is already existing on server1, and that there are tables with records in it.

Before we start setting up the replication, we create an empty database exampledb on server2, server3, and server4:

server2/server3/server4:

mysql -u root -p

CREATE DATABASE exampledb;
quit;


4 Setting Up Replication


Now we set up master-master replication in /etc/mysql/my.cnf. The crucial configuration options for master-master replication are auto_increment_increment and auto_increment_offset:

auto_increment_increment controls the increment between successive AUTO_INCREMENT values.
auto_increment_offset determines the starting point for AUTO_INCREMENT column values.
Let's assume we have N MySQL nodes (N=4 in this example), then auto_increment_increment has the value N on all nodes, and each node must have a different value for auto_increment_offset (1, 2, ..., N).

We also need to configure log-slave-updates because otherwise replication will work only, for example, from server1 to server2, but not to server3 and server4.


server1:

vi /etc/mysql/my.cnf

[...]
[mysqld]
server-id = 1
replicate-same-server-id = 0
auto-increment-increment = 4
auto-increment-offset = 1

server2:

vi /etc/mysql/my.cnf

[...]
[mysqld]
server-id = 2
replicate-same-server-id = 0
auto-increment-increment = 4
auto-increment-offset = 2


server3:

vi /etc/mysql/my.cnf

[...]
[mysqld]
server-id = 3
replicate-same-server-id = 0
auto-increment-increment = 4
auto-increment-offset = 3

server4:

vi /etc/mysql/my.cnf

[...]
[mysqld]
server-id = 4
replicate-same-server-id = 0
auto-increment-increment = 4
auto-increment-offset = 4


server1/server2/server3/server4:

/usr/bin/mysqladmin --user=root --password=yourrootsqlpassword stop-slave

server1:

mysql -u root -p

On the MySQL shell, run the following commands:

server1:

USE exampledb;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

The last command should show something like this (please write it down, we'll need it later on):

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |       98 | exampledb    |                  |
+------------------+----------+--------------+------------------+


Now don't leave the MySQL shell, because if you leave it, the database lock will be removed, and this is not what we want right now because we must create a database dump now. While the MySQL shell is still open, we open a second command line window where we create the SQL dump snapshot.sql and transfer it to server2, server3, and server4 (using scp):

server1:

cd /tmp
mysqldump -u root -pyourrootsqlpassword --opt exampledb > snapshot.sql
scp snapshot.sql root@192.168.1.2:/tmp

scp snapshot.sql root@192.168.1.3:/tmp

scp snapshot.sql root@192.168.1.4:/tmp

Afterwards, you can close the second command line window. On the first command line window, we can now unlock the database and leave the MySQL shell:

server1:

UNLOCK TABLES;
quit;


4.1 Setting Up Replication On server2
(This chapter is for server2 only!)

On server2, we can now import the SQL dump snapshot.sql like this:


server2:

/usr/bin/mysqladmin --user=root --password=yourrootsqlpassword stop-slave
cd /tmp
mysql -u root -pyourrootsqlpassword exampledb < snapshot.sql

Afterwards, we must find out about the master status of server2 as well and write it down:

mysql -u root -p

USE exampledb;
FLUSH TABLES WITH READ LOCK;

SHOW MASTER STATUS;

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |     1067 | exampledb    |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

mysql>

Then unlock the tables:

UNLOCK TABLES;

and run the following command to make server2 a slave of server1 (it is important that you replace the values in the following command with the values you got from the SHOW MASTER STATUS; command that we ran on server1!):

CHANGE MASTER TO MASTER_HOST='192.168.1.1', MASTER_USER='slaveuser_for_s2', MASTER_PASSWORD='slave_user_for_server2_password', MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=98;

Finally start the slave:

START SLAVE;

Then check the slave status:

SHOW SLAVE STATUS \G

It is important that both Slave_IO_Running and Slave_SQL_Running have the value Yes in the output (otherwise something went wrong, and you should check your setup again and take a look at /var/log/syslog to find out about any errors):

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 192.168.1.1
                Master_User: repl_s2
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000010
        Read_Master_Log_Pos: 98
             Relay_Log_File: slave-relay.000002
              Relay_Log_Pos: 235
      Relay_Master_Log_File: mysql-bin.000010
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB: db
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 98
            Relay_Log_Space: 235
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.01 sec)

mysql>

Afterwards, you can leave the MySQL shell on server2:

quit


4.2 Setting Up Replication On server3

On server3, we can now import the SQL dump snapshot.sql like this:

server3:

/usr/bin/mysqladmin --user=root --password=yourrootsqlpassword stop-slave
cd /tmp
mysql -u root -pyourrootsqlpassword exampledb < snapshot.sql

Afterwards, we must find out about the master status of server3 as well and write it down:

mysql -u root -p

USE exampledb;
FLUSH TABLES WITH READ LOCK;

SHOW MASTER STATUS;

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |     1067 | exampledb    |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

mysql>

Then unlock the tables:

UNLOCK TABLES;

and run the following command to make server3 a slave of server2 (it is important that you replace the values in the following command with the values you got from the SHOW MASTER STATUS; command that we ran on server2!):

CHANGE MASTER TO MASTER_HOST='192.168.1.2', MASTER_USER='slaveuser_for_s3', MASTER_PASSWORD='slave_user_for_server3_password', MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=1067;

Finally start the slave:

START SLAVE;

Then check the slave status:

SHOW SLAVE STATUS \G

It is important that both Slave_IO_Running and Slave_SQL_Running have the value Yes in the output (otherwise something went wrong, and you should check your setup again and take a look at /var/log/syslog to find out about any errors):

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 192.168.1.2
                Master_User: repl_s3
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000010
        Read_Master_Log_Pos: 1067
             Relay_Log_File: slave-relay.000002
              Relay_Log_Pos: 235
      Relay_Master_Log_File: mysql-bin.000010
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB: db
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 1067
            Relay_Log_Space: 235
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.00 sec)

mysql>

Afterwards, you can leave the MySQL shell on server3:

quit

Now the replication from server2 to server3 is set up. Next we must configure replication from server3 to server4.



4.3 Setting Up Replication On server4
(This chapter is for server4 only!)

On server4, we can now import the SQL dump snapshot.sql like this:

server4:

/usr/bin/mysqladmin --user=root --password=yourrootsqlpassword stop-slave
cd /tmp
mysql -u root -pyourrootsqlpassword exampledb < snapshot.sql

Afterwards, we must find out about the master status of server4 as well and write it down:

mysql -u root -p

USE exampledb;
FLUSH TABLES WITH READ LOCK;

SHOW MASTER STATUS;

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |     1067 | exampledb    |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)


UNLOCK TABLES;

and run the following command to make server4 a slave of server3 (it is important that you replace the values in the following command with the values you got from the SHOW MASTER STATUS; command that we ran on server3!):

CHANGE MASTER TO MASTER_HOST='192.168.1.3', MASTER_USER='repl_s4', MASTER_PASSWORD='slave_user_for_server4_password', MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=1067;

Finally start the slave:

START SLAVE;

Then check the slave status:

SHOW SLAVE STATUS \G

It is important that both Slave_IO_Running and Slave_SQL_Running have the value Yes in the output (otherwise something went wrong, and you should check your setup again and take a look at /var/log/syslog to find out about any errors):

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 192.168.1.3
                Master_User: repl_s4
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000010
        Read_Master_Log_Pos: 1067
             Relay_Log_File: slave-relay.000002
              Relay_Log_Pos: 235
      Relay_Master_Log_File: mysql-bin.000010
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB: exampledb
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 1067
            Relay_Log_Space: 235
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.00 sec)

mysql>

Afterwards, you can leave the MySQL shell on server3:

quit

Now the replication from server3 to server4 is set up. Finally we must configure replication from server4 to server1 to close the replication circle.



4.4 Setting Up Replication On server1
(This chapter is for server1 only!)

To do this, we stop the slave on server1 and make it a slave of server4:

server1:

mysql -u root -p

STOP SLAVE;

Make sure that you use the values of the SHOW MASTER STATUS; command that you ran on server4 in the following command:

CHANGE MASTER TO MASTER_HOST='192.168.0.103', MASTER_USER='slaveuser_for_s1', MASTER_PASSWORD='slave_user_for_server1_password', MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=1067;

Then start the slave on server1:

START SLAVE;

Then check the slave status:

SHOW SLAVE STATUS \G

It is important that both Slave_IO_Running and Slave_SQL_Running have the value Yes in the output (otherwise something went wrong, and you should check your setup again and take a look at /var/log/syslog to find out about any errors):

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 192.168.0.103
                Master_User: slaveuser_for_s1
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000010
        Read_Master_Log_Pos: 1067
             Relay_Log_File: slave-relay.000002
              Relay_Log_Pos: 235
      Relay_Master_Log_File: mysql-bin.000010
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB: exampledb
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 1067
            Relay_Log_Space: 235
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.00 sec)

mysql>

Afterwards you can leave the MySQL shell:

quit






Thursday, September 21, 2006

MariaDB Galera cluster setup with 3 node

MariaDB Galera cluster setup.


 #############################################################
 # How To Setup MariaDB Galera Cluster 10.0 On CentOS        #
 #############################################################

 MariaDB is a relational database management system (RDBMS) and  MariaDB Galera Cluster is a synchronous
 multi-master cluster for MariaDB. It is available on Linux only, and only supports the XtraDB/InnoDB storage
 engines. This article explains how to setup MariaDB Galera Cluster 10.0 with 3 nodes running on CentOS 6.5 x86_64
 resulting in a HA (high-availability) database cluster.

CLUSTER DETAILS

We using 3 freshly deployed VMs running a minimal install of CentOS 6.5 x86_64.

Cluster node 1 has hostname db1 and IP address 1.1.1.1
Cluster node 2 has hostname db2 and IP address 1.1.1.2
Cluster node 3 has hostname db3 and IP address 1.1.1.3

Step 1: Add MariaDB Repositories
Create a mariadb repository /etc/yum.repos.d/mariadb.repo using following content in your system.

For CentOS 6 – 64bit:

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.0/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
For CentOS 6 – 32bit:

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.0/centos6-x86
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1


Step 2 – Set SELinux in permissive mode
Before starting the setup put SELinux into permissive mode on all nodes:

sudo setenforce0

Step 3 – Install MariaDB Galera Cluster 10.0 software
If you did a CentOS 6 minimal installation then make sure you install the socat package from the EPEL repository before proceeding with installing the MariaDB Galera Cluster 10.0 software.

You can install socat package directly from EPEL with the following command (for x86_64):
sudo yum install http://dl.fedoraproject.org/pub/epel/6/x86_64/socat-1.7.2.3-1.el6.x86_64.rpm

On CentOS 7 you can install socat package with following command.

sudo yum install socat

Install the MariaDB Galera Cluster 10.0 software by executing the following command on all nodes:

sudo yum install MariaDB-Galera-server MariaDB-client rsync galera
Step 4:  Setup MariaDB security
Start the mysql ( init script in MariaDB 10.0 is still called mysql)

sudo service mysql start
Run the mysql_secure_installation script so we can improve the security. Run the following command on all nodes:

sudo /usr/bin/mysql_secure_installation
I choose password as ‘dbpass’ and accepted all defaults (so answered yes to all questions).

Step 5 – Create MariaDB Galera Cluster users

Now, we have to create some users that must be able to access the database. The ‘sst_user’ is the user which a database node will use for authenticating to another database node in the State Transfer Snapshot (SST) phase. Run the following command on all nodes:

mysql -u root -p
mysql> DELETE FROM mysql.user WHERE user='';
mysql> GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'dbpass';
mysql> GRANT USAGE ON *.* to sst_user@'%' IDENTIFIED BY 'dbpass';
mysql> GRANT ALL PRIVILEGES on *.* to sst_user@'%';
mysql> FLUSH PRIVILEGES;
mysql> quit
You are suggested to change ‘%’ to hostname(s) or IP addresses from which those users can access the database. Because ‘%’ means that the root or sst_user is allowed to access the database from any host, So less security.

Step 6 – Create the MariaDB Galera Cluster config
First stop the mysql services on all nodes:

sudo service mysql stop
Next, We are going to create the MariaDB Galera Cluster configuration by the following command on all nodes (go through the IMPORTANT NOTE after the config and make required changes for db2, and db3):

sudo cat >> /etc/my.cnf.d/server.cnf << EOF
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1
query_cache_size=0
query_cache_type=0
bind-address=0.0.0.0
datadir=/var/lib/mysql
innodb_log_file_size=100M
innodb_file_per_table
innodb_flush_log_at_trx_commit=2
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://1.1.1.1,1.1.1.2,1.1.1.3"
wsrep_cluster_name='galera_cluster'
wsrep_node_address='1.1.1.1'
wsrep_node_name='db1'
wsrep_sst_method=rsync
wsrep_sst_auth=sst_user:dbpass
EOF
IMPORTANT NOTE: when executing this command on db2 and db3 do not forget to adjust the wsrep_node_address and wsrep_node_name variables.

On db2 :

wsrep_node_address=1.1.1.2
wsrep_node_name='db2'
On db3 :

wsrep_node_address='1.1.1.3'
wsrep_node_name='db3'
Step 7– Initialize the first cluster node
Start MariaDB with the special ‘‐‐wsrep-new-cluster’ option , Do it on node db1 only so the primary node of the cluster is initialized:

sudo /etc/init.d/mysql start --wsrep-new-cluster
Check status by run the following command on node db1 only:

mysql-uroot-p-e"show status like 'wsrep%'"
Some important information in the output are the following lines:

wsrep_local_state_comment | Synced <-- cluster is synced
wsrep_incoming_addresses  | 1.1.1.1:3306 <-- node db1 is a provider
wsrep_cluster_size        | 1 <-- cluster consists of 1 node
wsrep_ready               | ON <-- good :)
Step 8– Add the other cluster nodes
Check and confirm nodes db2 and db3 have the correct configuration in /etc/my.cnf.d/server.cnf under the [mariadb-10.0] as described in step 6.

With the correct configuration in place, all that is required to make db2 and db3 a member of the cluster is to start them like you would start any regular service. On db2 issue the following command:

sudo service mysql start
Check what has changed in the cluster status by executing the following command on db1 or db2:

mysql -u root -p -e "show status like 'wsrep%'"
And you will see that node db2 is now known as the cluster size is ‘2’ and the IP address of node db2 is listed:

| wsrep_local_state_comment | Synced                    |
| wsrep_incoming_addre sses | 1.1.1.1:3306,1.1.1.2:3306 |
| wsrep_cluster_size        | 2                         |
| wsrep_connected           | ON                        |
| wsrep_ready               | ON                        |
Repeat the same step for node db3. On node db3 only execute the following command

sudo service mysql start
Check what has changed in the cluster status by executing the following command on for example db1:

mysql -u root -p -e "show status like 'wsrep%'"
And you should see that node db3 is now known as the cluster size is ‘3’ and the IP address of node db3 is listed:

| wsrep_local_state_comment | Synced                                 |
| wsrep_incoming_addresses  | 1.1.1.3:3306,1.1.1.1:3306,1.1.1.2:3306 |
| wsrep_cluster_size        | 3                                      |
| wsrep_connected           | ON                                     |
| wsrep_ready               | ON                                     |
Step 9 – Verify replication
Now the cluster is running. Let’s test whether it is working. On db1 create a database ‘clustertest’ by run the following command:

mysql -u root -p -e 'CREATE DATABASE clustertest;'
mysql -u root -p -e 'CREATE TABLE clustertest.mycluster ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), ipaddress VARCHAR(20), PRIMARY KEY(id));'
mysql -u root -p -e 'INSERT INTO clustertest.mycluster (name, ipaddress) VALUES ("db1", "1.1.1.1");'
Check if the database, table and data exists:

mysql -u root -p -e 'SELECT * FROM clustertest.mycluster;'
Enter password:
+----+------+-----------+
| id | name | ipaddress |
+----+------+-----------+
| 2  | db1  | 1.1.1.1   |
+----+------+-----------+
Now do the check on node db2:

mysql -u root -p -e 'SELECT * FROM clustertest.mycluster;'
Enter password:
+----+------+-----------+
| id | name | ipaddress |
+----+------+-----------+
| 2  | db1  | 1.1.1.1   |
+----+------+-----------+
Now do the same check on node db3:

mysql -u root -p -e 'SELECT * FROM clustertest.mycluster;'
Enter password:
+----+------+-----------+
| id | name | ipaddress |
+----+------+-----------+
| 2  | db1  | 1.1.1.1   |
+----+------+-----------+
From these outputs we can confirm that everything was successfully replicated by node db1 across all other nodes.