Quantcast
Channel: Severalnines - load balancing
Viewing all 98 articles
Browse latest View live

A DevOps Guide to Database Infrastructure Automation for eCommerce - Replay & Slides

$
0
0

Thanks to everyone who attended and participated in last week’s webinar on ‘A DevOps Guide to Database Infrastructure Automation for eCommerce’. If you missed the sessions or would like to watch the webinar again & browse through the slides, they are now available online.

Our guest speaker this time was Riaan Nolan of Foodpanda/Rocket Internet. Topics included a roundup of infrastructure challenges faced by online retailers: multi-datacenter/cloud environments, configuration management, health and performance monitoring, capacity analysis and planning, elastic scaling, and automatic failure handling. Thanks again to Riaan for taking the time to speak to us!

Screen Shot 2015-02-20 at 12.30.12.png

The full agenda included: 

  • eCommerce infrastructure challenges in 2014, including a sample workflow chart outlining: 
  • Puppet, GitHub, Capistrano, Nginx, PHP5-FPM / Ruby, Percona XtraDB, Couchbase, SOLR, GlusterFS
  • Provisioning of test/QA and highly available production environments across multi-datacenter and multi-cloud environments (AWS Cloud Formation) 
  • Building and maintaining configuration management systems such as Puppet and Chef
  • Enabling self-service infrastructure services to internal dev teams
  • Health and performance monitoring 
  • Capacity analysis and planning
  • Elastic scaling 
  • Automating failure handling
  • Disaster recovery

 

Watch the replay

 

Read the slides

 

Screen Shot 2015-02-20 at 12.28.33.png

RELATED BLOGS

 

Blog category:


Resources for Highly Available Database Clusters: ClusterControl Release Webinar, Support for Postgres, New Website and More

$
0
0

Check Out Our Latest Technical Resources for MySQL, MariaDB, Postgres and MongoDB Clusters

Like every month, we have created new content and tools for you; here is a summary of what we’ve published. Please do check it out and let us know if you have any comments or feedback.

New Live Technical Webinar

Introducing the New ClusterControl with Live Demo on 24th of March

Johan Andersson, CTO at Severalnines will walk us through the latest edition of ClusterControl and its new features in the form of a live demo. Johan will go over the latest features in ClusterControl including the recently announced support for Postgres.

Register here

cluster_control_logo.jpg

 

Product Announcements & Resources

psql_feat1.PNG

Management and Monitoring of Existing Postgres Servers

This week we announced support for PostgreSQL and ClusterControl can now be used to monitor database metrics, queries and schedule backups. With this new addition, ClusterControl supports MySQL with its main variations MariaDB, Percona XtraDB (single or clustered), MongoDB and PostgreSQL. Companies can manage all these databases through one unified interface.

Find out more

zbx_fi.PNG

ClusterControl Template for Zabbix

We also announced a ClusterControl Template for Zabbix, so Zabbix users can now get information about the status of their database clusters, backups and alarms. We have previously published integrations with other monitoring systems including Nagios and PagerDuty.

Find out more

 

Technical Webinar - Replay

A DevOps Guide to Database Infrastructure Automation for eCommerce

We were lucky enough to recently have Riaan Nolan of Foodpanda/Rocket Internet as our guest speaker for a session during which he shared his experience and advice on how to automate highly available Commerce infrastructures.

If you’re interested in how to deal with the following topics (and more), then do check out the replay of this webinar:

  • eCommerce infrastructure challenges in 2014, including a sample workflow chart outlining: Puppet, GitHub, Capistrano, Nginx, PHP5-FPM / Ruby, Percona XtraDB, Couchbase, SOLR, GlusterFS
  • Provisioning of test/QA and highly available production environments across multi-datacenter and multi-cloud environments (AWS Cloud Formation)
  • Building and maintaining configuration management systems such as Puppet and Chef

Watch the replay and read the slides here

 

Technical Blogs

As many of you will know, GTID was introduced along with MySQL 5.6, and brought along some major changes in the way MySQL operates. When previously one had to work around limitations related to binary logs, it’s now all in the GTID. GTIDs are not flawless though, find out more in this blog post:   

MySQL Replication and GTID-based failover - A Deep Dive into Errant Transactions

mrgt_arch.png

Severalnines Company News

The past twelve months have been quite an exiciting time for us and we decided to publish a status update on where we are today as a company and on what we’re looking forward to for the future. If you haven’t read it yet, do have a look at our Momentum Press Release, which we published recently.

Read the Momentum Press Release

And, last but not least, we’ve also published a brand new website last month! Most of you will have noticed the change already: we’re sporting a new look and have introduced a website with better ease of navigation and simpler paths to get to the information our users are looking for. Do let us know if you have any feedback on it!

We trust these resources are useful. If you have any questions on them or on related topics, please do contact us!

Your Severalnines Team

 

Blog category:

How to Manage the World’s Top Open Source Databases: ClusterControl 1.2.9 Features Webinar Replay

$
0
0

Thanks to everyone who attended and participated in this week’s webinar on 'New Features - ClusterControl 1.2.9 Release'. If you missed the sessions or would like to watch the webinar again & browse through the slides, they are now available online.

Our speaker this time was Johan Andersson, CTO, Severalnines.

Watch the replay

 

 

Read the slides

 

 

With over 7,000 users to date, ClusterControl is the leading, platform independent automation and management solution for the MySQL, MongoDB and now Postgres databases, its latest main feature. 

psql_dash.png

Highlights in ClusterControl 1.2.9 include:

  • Support for PostgreSQL Servers
  • Advanced HAProxy Configurations and Built-in Stats
  • Hybrid Replication with Galera Clusters
  • Galera Replication Traffic Encryption
  • Encrypted Communication between ClusterControl and MySQL-based systems
  • Query Deadlock Detection in MySQL-based systems
  • Bootstrap Galera Cluster
  • Restore of Backups
  • New UI theme
  • RPC interface to ClusterControl
  • Chef Recipe and Puppet Manifest for ClusterControl
  • Zabbix Plugin for ClusterControl

 

RELATED BLOGS

 

ABOUT CLUSTERCONTROL

Setting up, maintaining and operating a database cluster can be tricky. ClusterControl gives you the power to deploy, manage, monitor and scale entire clusters efficiently and reliably. ClusterControl supports a variety of MySQL-based clusters (Galera, NDB, 5.6 Replication), MariaDB as well as MongoDB/TokuMX-based clusters - and now Postgres.

 

Blog category:

How to Deploy and Configure MaxScale for SQL Load Balancing with Read-Write Split

$
0
0

There are two models of load balancing: transport and application layer. HAProxy is a great TCP load balancer, but it’s lack of SQL awareness effectively limits its ability to address certain scaling issues in distributed database environments. In the open source world, there’s been a few SQL-aware load balancers, namely MySQL Proxy, ProxySQL and MaxScale, but they all seemed to be in beta status and unfit for production use. So we were pretty excited when the MariaDB team released a GA version of MaxScale earlier this year. In this blog, we’ll have a look at MaxScale and see how it compares with HAProxy.

Deployment

Installation is easy, at least on the latest LTS version of Ubuntu (Trusty, 14.04) which we used for our tests.

Add a public key:

$ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8167EE24

Add a MaxScale repository to one of *.list files for apt-get:

deb [arch=amd64] http://downloads.mariadb.com/software/MaxScale/maxscale/DEB trusty main

Run:

$ apt-get update && apt-get install maxscale

and you can enjoy your new software - proxy is installed into the /usr/local/skysql/maxscale directory. 

 

Configuration

Once installed, we need to configure it. Along with installation comes an example configuration file, located in: /usr/local/skysql/maxscale/etc/MaxScale_template.cnf. It gives a nice introduction to the available options, and helps to setup the environment.

MaxScale uses a pluggable architecture with different plugins providing different features. In this post, we will concentrate on the routing part, and for now, leave out other interesting possibilities like query rewriting. MaxScale uses different types of services; monitors, services, listeners and filters. 

For our tests we defined two types of routing services: 

  • ‘router=readwritesplit’, which provides read/write (RW) splitting,
  • ‘router=readconnroute’, which provides round-robin-like (RR) kind of access.

Each service was accompanied by a listener, port 3307 for RW split and 3308 for RR service. With RR service, we relied on MaxScale’s monitoring of Galera nodes to route connections only to the nodes in a ‘Synced’ state.

[maxscale]
threads=4

[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3
user=maxmon
passwd=maxpwd
monitor_interval=10000
disable_master_failback=1

[qla]
type=filter
module=qlafilter
options=/tmp/QueryLog

[fetch]
type=filter
module=regexfilter
match=fetch
replace=select

[RW]
type=service
router=readwritesplit
servers=server1,server2,server3
user=root
passwd=secretpass
max_slave_connections=100%
router_options=slave_selection_criteria=LEAST_CURRENT_OPERATIONS

[RR]
type=service
router=readconnroute
router_options=synced
servers=server1,server2,server3
user=root
passwd=secretpass

[Debug Interface]
type=service
router=debugcli

[CLI]
type=service
router=cli

[RWlistener]
type=listener
service=RW
protocol=MySQLClient
address=10.69.179.54
port=3307

[RRlistener]
type=listener
service=RR
protocol=MySQLClient
address=10.69.179.54
port=3308

[Debug Listener]
type=listener
service=Debug Interface
protocol=telnetd
address=127.0.0.1
port=4442

[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
address=127.0.0.1
port=6603


[server1]
type=server
address=10.138.103.93
port=3306
protocol=MySQLBackend

[server2]
type=server
address=10.139.81.25
port=3306
protocol=MySQLBackend

[server3]
type=server
address=10.81.192.219
port=3306
protocol=MySQLBackend

There are couple of interesting bits in the configuration file. As you can see, we had to define user/password pairs several times. Those users are used to check the health of the MySQL nodes and to get access to the list of users defined in the system. For the sake of simplicity we used plain text passwords but it is possible to use hashed passwords for better security. 

Finally, since we wanted to compare performance of MaxScale vs HAProxy, we used HAProxy installed from within ClusterControl in a default setup  configured similarly to MaxScale’s RR service. 

 

How does MaxScale work with Galera Cluster?

So, let’s talk about how MaxScale sees the Galera Cluster. MaxScale provides an admin CLI which gives you access to some internal statistics. After the first login (user admin, password skysql), you can check available options by running the ‘help’ command. One of the very useful commands is ‘show servers’, which returns a health status of the cluster. Below is the example output of that command.

$ /usr/local/skysql/maxscale/bin/maxadmin -u admin
Password:
MaxScale> show servers
Server 0x219bac0 (server1)
    Server:                10.138.103.93
    Status:                       Slave, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            2
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0
Server 0x20f7da0 (server2)
    Server:                10.139.81.25
    Status:                       Slave, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            1
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0
Server 0x20f7c90 (server3)
    Server:                10.81.192.219
    Status:                       Master, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            0
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0

We are interested in the status of the nodes right now  as we can see, we have three nodes ‘Running’, all of them are ‘Synced’. Two were elected as ‘Slave’ and one as a ‘Master’. Those states are what we can use in the configuration file. For example, in RR service we defined the following variable:

router_options=synced

It means that, at any given time, connections can be routed to any of the nodes, as long as they are in the ‘synced’ state (i.e. not serving as a donor or joining the cluster). On the other hand, the RW service was looking for ‘Slave’ and ‘Master’ states to route traffic accordingly. In case of a master failure, a new node is elected as a new master. Your application needs to reconnect though, MaxScale currently does not provide failover for currently open connections.

What’s worth noting, if you want to setup a RW split, you will need to set the max_slave_connections variable accordingly. By default MaxScale sets it to one and, as a result, only one slave is getting read connections. You can here use a fixed number (2, 5) or a percent of the slave pool (50%, 100%). As we wanted all of our slaves, no matter how many there are out there, to serve the traffic, we set this variable to 100%:

max_slave_connections=100%

Another interesting bit is the ‘master’ failover part  when MaxScale detects that a node, elected as a master, is unreachable, it promotes one of the ‘slaves’ to the ‘master’ role. Then, by default, when old ‘master’ comes back online, it is immediately promoted to its old master role. As a result, writes may switch back and forth between different nodes should the ‘master’ start to flap. You can switch this default behavior by adding ‘disable_master_failback=1’ directive to the definition of the monitor service.

In case of any connectivity issues, it’s worth checking log files (by default located in the /usr/local/skysql/maxscale/log/ directory) and the kind of MySQL users MaxScale had detected. The latter can be done from the CLI, using the ‘show dbusers <service>’ command:

MaxScale> show dbusers RW
Users table data
Hashtable: 0x2a0c900, size 52
    No. of entries:         3
    Average chain length:    0.5
    Longest chain length:    7
User names: sbtest@%, maxmon@%, maxmon@%

If you added some new users on the MySQL side, you can refresh MaxScale’s database by running reload dbusers <service>:

MaxScale> reload dbusers RW

In general, the CLI gives you some nice options to use. We’ll not go over all of them in this post, but we’d still like to mention some features:

  • configuration (at least partially) can be changed on fly and reloaded (reload config command)
  • server state can be set from the CLI, which enables a DBA to move writes to a different node in the cluster (set server … command)
  • services can be disabled/enabled/restarted from the CLI

While in the CLI, help is easily reachable through the following commands:

help
help <command> (for example help show)

Stay tuned for part two of this post where we will cover the performance comparison between MaxScale’s different router services and HAProxy.

Blog category:

SQL Load Balancing Benchmark - Comparing Performance of MaxScale vs HAProxy

$
0
0

In a previous post, we gave you a quick overview of the MaxScale load balancer and walked through installation and configuration. We did some quick benchmarks using sysbench, a system performance benchmark that supports testing CPU, memory, IO, mutex and also MySQL performance. We will be sharing the results in this blog post.

Sysbench setup

For our tests we used the latest version of sysbench, straight from bzr. Installation is simple. First, make sure you have all the prerequisites. For Ubuntu these are: libmysqlclient-dev (or equivalent), bzr, automake, make, libtool and libssl-dev.

Get the code and compile it:

$ cd /root
$ bzr branch lp:sysbench
$ cd /root/sysbench
$ ./autogen.sh
$ ./configure
$ make
$ make install

The next step was to prepare database for a benchmark. We created the ‘sbtest’ schema and granted access to it to the ‘sbtest’ user with a correct password. After that, populate the database using the following command:

$ sysbench \
--test=/root/sysbench/sysbench/tests/db/oltp.lua \
--mysql-host=10.69.179.54 \
--mysql-port=3307 \
--mysql-user=sbtest \
--mysql-password=sbtest \
--oltp-tables-count=128 \
--oltp-table-size=400000 \
prepare

Once complete, it is time for some benchmarking.

 

Performance benchmarks

We were interested mostly in the proxy’s throughput thus we executed a series of read-only sysbench OLTP tests. The exact command looked as below:

$ sysbench \
--test=/root/sysbench/sysbench/tests/db/oltp.lua \
--num-threads=512 \
--max-requests=0 \
--max-time=600 \
--mysql-host=10.69.179.54 \
--mysql-port=3307 \
--mysql-user=sbtest \
--mysql-password=sbtest \
--oltp-tables-count=128 \
--oltp-read-only=on \
--oltp-skip-trx=on  \
--report-interval=1 \
--oltp-table-size=400000 \
run

Now, one of the gotchas we ran into while evaluating MaxScale - when using RW service, is that all reads headed directly to the ‘Master’. After some head scratching, we found that, by default, sysbench uses explicit transactions (see --oltp-skip-trx=on in the sysbench command above). MaxScale implements read/write split in a way that may be slightly misleading before you get used to it - reads are split across "slave" nodes, but there are some exceptions. One of them are transactions that are started explicitly - if your app executes queries using BEGIN; ... ; COMMIT; , then all such queries will be routed to the single ‘Master’ instance. As a result, we had to add --oltp-skip-trx=on flag to the sysbench program to make sure reads will be split onto the slaves.

Let’s take a look at the results. Hardware-wise, we’ve been using r3.4xlarge EC2 instances for a proxy/sysbench node and three r3.2xlarge EC2 instances for Galera nodes. Workload was in-memory, CPU bound. Thanks to scalability improvements in MySQL 5.6, we were able to fully saturate all 8 CPU cores on an instance when running sysbench directly against a node - this confirmed that results won’t be skewed by MySQL’s scalability limitations.

As can be seen, each routing method provided fairly stable performance with occasional drops. What’s important to clarify - HAProxy fully saturated one CPU core so this level of performance, around 75k selects per second, is the maximum we can get from this proxy under the test workload. 

On the other hand, the round-robin MaxScale router hit contention of some kind outside of the proxy itself - neither network nor CPU were saturated on the proxy or the Galera nodes. We were not able to push through this level of performance. While performing a sanity check using direct connections to Galera, bypassing the proxy, we were only able to reach the same level of performance, confirming it is something outside of MaxScale. We did not investigate further, AWS is a bit too black-boxish for that and it wasn’t really necessary. The total theoretical throughput of the system under our workload was ~135 - 140k selects per second (two nodes with 100% CPU utilization, delivered ~90-95k selects per second).

The read-write split router performed around ~57k of selects per second, saturating four cores - MaxScale was configured to use four threads. Having seen that, we repeated the benchmark allowing MaxScale to use 12 threads. Here are results:

We can see that read-write split router (green dots) bypassed HAProxy’s performance (blue dots). What we can’t see on the graph, but it was captured by us during the benchmark, was that MaxScale used almost nine CPU cores to get there:

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 31612 root      20   0 1389876  62860   4392 R 877.2  0.0 339:53.56 maxscale
 34485 root      20   0 8435680  48384   1640 S 317.8  0.0  28:46.06 sysbench

R3.4xlarge has 16 virtual cores so there was still room for growth. It seems like this was a maximum possible throughput under our conditions.

What’s interesting is that the round-robin like setup, using readconnroute router, performed worse while having 12 threads (versus when we had 4 threads) enabled in MaxScale’s configuration. After a short investigation, we could see an internal contention on mspin_lock which decreased the performance. What else we can see? Readconnroute router definitely had issues with maintaining stable performance - drops are noticeable and long-running.

 

Response time results

Let’s check the response time graphs. Below, you can see a global overview followed by a zoom into the 0 - 300ms region.

Rather expected results, in line with the performance we have seen in earlier graphs. It’s worth noticing though that both 12 thread configurations delivered much less stable performance than the rest of the setups tested.

 

Conclusions

Let’s try to draw some conclusions from the data. First, MaxScale allows you to implement read/write split without the need to redesign your application. All you need to do is to setup MaxScale with the correct configuration (readwritesplit router). At least, that’s the theory. In practice, your application cannot use explicit transactions (which is not that big limitation per se, but if you do use them, you will not be able to benefit from RW split in an easy way). There are some other gotchas regarding the use of user-defined variables in queries. Those are pretty valid limitations, which are totally understandable, but it has to be said that one can’t expect that RW split in MaxScale will work in all of the cases. You should take some time to read MaxScale’s documentation to familiarize with any other limitations which may affect your particular workload.

Second, MaxScale RW split, while it was able to bypass HAProxy by a small margin in terms of the performance, required significant CPU resources to get there (9 cores compared to HAProxy’s single core) and its performance was not as stable as HAProxy’s. It’s obviously caused by the additional logic needed for a RW split (a MaxScale configuration similar to HAProxy, round-robin, delivered much higher performance than HAProxy and comparable in the stability) but it makes this setup not necessarily the best option to use in all cases.

Taking it all under consideration, we’d say that, for now at least, if you have the possibility of performing a RW split on the application side, you might want to consider it - setup two listeners in the way we did it in this test. Use readconnroute router for reads and readwritesplit router for writes. In that way you’ll be able to read from all nodes of the cluster while writing only to one of them, to minimize chances of deadlocks in Galera. If your application does not allow you to do that, you can still use readwritesplit router to get a RW split even when it results in additional CPU utilization on the proxy’s node. It’s great to have this option even if it comes with a reduced overall performance.

Having said that, the workload that we tested was designed to stress a proxy - it’s very unlikely that your application will want to execute 75k selects per second. Heavier queries will take longer time and total throughput will be much lower. You can also be less CPU-bound but more I/O-bound - usually databases do not fit entirely in the InnoDB buffer pool. In such cases you may never notice the performance limits of the MaxScale readwritesplit router. As usual, it’s all about performing tests and checking what works best in your environment.

Last but not least, MaxScale is still a pretty new software and we’d expect it to mature with every release, adding new options and removing design and scalability limitations. It’s definitely nice to have more options when it comes to proxies, especially when the proxy is database-centric.

Blog category:

How to Deploy and Manage MaxScale using ClusterControl

$
0
0

We were delighted to announce that ClusterControl now supports MaxScale, the intelligent database gateway from the MariaDB team. In this blog, we will show you how to deploy and manage MaxScale from ClusterControl. We previously blogged about MaxScale, read it if you’d like a quick overview and introduction. We also published a quick benchmark of HAProxy vs MaxScale.

How to install MaxScale from ClusterControl

Assume you have a Galera Cluster currently managed by ClusterControl. As next step you want to install MaxScale as load balancer. From the ClusterControl UI, go to Manage > Load Balancer > Install MaxScale. You’ll be presented with following dialog box. 

Please make sure you have chosen ‘Create MaxScale Instance’. We’ll discuss the “MariaDB Repository URL” further down in this blog. The remaining options are pretty clear: 

  • choose or type in the IP address of the node where MaxScale will be installed. ClusterControl has to be able to ssh in a passwordless fashion to this host. 
  • username and password  - it will be used to access MaxScale’s administration interface.
  • next is another username/password - this time, it is a MariaDB/MySQL user that will be used by MaxScale to access and monitor the MariaDB/MySQL nodes in your infrastructure.

Below that you can set couple of configuration settings for MaxScale:

  • how many threads it is allowed to use 
  • which ports should be used for different services. Currently, MaxScale deployed by ClusterControl comes with a CLI service and Debug service - those are standard services available for MaxScale. We also create two ‘production’ services - ‘RW’, which implements a read-write split and ‘RR’ which implements round-robin access to all of the nodes in the cluster. Each of those services have a port assigned to it - you can change it at the deploy stage.

At the bottom of the dialog box, you’ll see your nodes with checkboxes - you can pick those that will be included in the proxy’s configuration.

Let’s get back to the repository URL. Once you click on the tooltip, you’ll see the following screen:

MariaDB introduced individual links to the repository where MaxScale is stored. To get your link, you should log into the MariaDB Enterprise Portal and generate one for yourself. Once you have it, you can paste it in the MariaDB Repository URL box. This concludes the preparations for deployment, you can now click on the ‘Install MaxScale’ button and wait for the process to complete.

You can monitor the progress in ClusterControl > Logs > Jobs. When it finishes, it prints some examples covering how you can connect to your MaxScale instance. For better security you should delete this job by clicking the ‘Delete’ button above it.

How to add an existing MaxScale instance to ClusterControl?

If you already have MaxScale installed in your setup, you can easily add it to ClusterControl to benefit from health monitoring and access to MaxAdmin - MaxScale’s CLI from the same interface you use to manage the database nodes. 
The only requirement is to have passwordless SSH configured between ClusterControl node and host where MaxScale is running. Once you have SSH set up, you can go to Manage > Load Balancer > Install MaxScale. Once you are there, ensure you have chosen ‘Add Existing MaxScale’. You’ll be then presented with a following screen:

The only data you need to pass here is IP of the MaxScale server and port for the MaxScale CLI. After clicking ‘Install MaxScale’, it will be added to the list of processes monitored by ClusterControl.

How to uninstall MaxScale from ClusterControl?

If, for some reason, you would like to uninstall MaxScale, go to the ‘Nodes’ tab and then click on the ‘-’ icon next to the MaxScale node. You’ll be asked if you want to remove the node. If you click yes, MaxScale will be uninstalled from the node you’ve just chosen.

How to access MaxScale MaxAdmin commands?

MaxAdmin is a command line interface available with MaxScale that allows extensive health checks, user management, status and control of MaxScale operations. ClusterControl gives you direct access to the MaxAdmin commands. You can reach it by going to ‘Nodes’ tab and then clicking on your MaxScale node. Once you do that, you’ll be presented with the following screenshot:

You can see the status of the node, and stop the instance if needed. In the user/password boxes, you need to enter MaxScale’s administrative user credentials - this is what you put in the Admin username/password fields where installing MaxScale. If you added an existing MaxScale installation, please use here any administrative user that you created. By default (if you do not provide any input) ClusterControl will try to use the default username and password created during the MaxScale installation (admin/mariadb).

The drop down box contains a predefined set of commands that you can execute by just picking them from the list and then clicking on the ‘Execute’ button. For a full list of commands, you can execute the ‘help’ command.

Results are presented in a console window:

You can clear it at any time by using ‘Reset Console’ button.

Please keep in mind that some of the commands require additional parameters. For example, the ‘show server’ command requires you to pass a server name as a parameter. You can do so by just editing the dropdown box and typing in the parameter:

As we mentioned before, you are not limited to the predefined commands - you can type anything you like in the command box. For example, we can stop and then start one of the services:

CLI access from ClusterControl talks directly to the MaxAdmin, therefore you can use ClusterControl to execute everything that you are able to run using the MaxAdmin CLI client.

Have fun with MaxScale!

Blog category:

nginx as Database Load Balancer for MySQL or MariaDB Galera Cluster

$
0
0

Nginx is well-known for its ability to act as a reverse-proxy with small memory footprint. It usually sits in the front-end web tier to redirect connections to available backend services, provided these passed some health checks. Using a reverse-proxy is common when you are running a critical application or service that requires high availability. It also distributes the load equally among the backend services.

Recently, nginx 1.9 introduced support for TCP load balancing - similar to what HAProxy is capable of. The one major drawback is that it does not support advanced backend health checks. This is required when running MySQL Galera Cluster, as we’ll explain in the next section. Note that this limitation is removed in the paid-only edition called NGINX Plus. 

In this blog post, we are going to play around with nginx as a reverse-proxy for MySQL Galera Cluster services to achieve higher availability. We had a Galera cluster up and running, deployed using ClusterControl on CentOS 7.1. We are going to install nginx on a fresh new host, as illustrated in the following diagram:

Backend Health Checks

With the existence of a synchronously-replicated cluster like Galera or NDB, it has become quite popular to use a TCP reverse-proxy as load balancer. All MySQL nodes are treated equal as one can read or write from any node. No read-write splitting is required, as you would with MySQL master-slave replication. Nginx is not database-aware, so some additional steps are required to configure the health checks for Galera Cluster backends so that they return something understandable. 

If you are running HAProxy, a healthcheck script on each MySQL server in the load balancing set should be able to return an HTTP response status. For example, if the backend MySQL server is healthy, then the script will return a simple HTTP 200 OK status code. Else, the script will return 503 Service unavailable. HAProxy can then update the routing table to exclude the problematic backend servers from the load balancing set and redirect the incoming connections only to the available servers. This is well explained in this webinar on HAProxy. Unfortunately, the HAProxy health check uses xinetd to daemonize and listen to a custom port (9200) which is not configurable in nginx yet.

The following flowchart illustrates the process to report the health of a Galera node for multi-master setup:

At the time of this writing, NGINX Plus (the paid release of nginx) also supports advanced backend health but it does not support custom backend monitoring port.

Using clustercheck-iptables

To overcome this limitation, we’ve created a healthcheck script called clustercheck-iptables. It is a background script that checks the availability of a Galera node, and adds a redirection port using iptables if the Galera node is healthy (instead of returning HTTP response). This allows other TCP-load balancers with limited health check capabilities to monitor the backend Galera nodes correctly. Other than HAProxy, you can now use your favorite reverse proxy like nginx (>1.9), IPVS, keepalived, piranha, distributor, balance or pen to load balance requests across Galera nodes.

So how does it work? The script performs a health check every second on each Galera node. If the node is healthy (wsrep_cluster_state_comment=Synced and read_only=OFF) or (wsrep_cluster_state_comment=Donor and wsrep_sst_method=xtrabackup/xtrabackup-v2), a port redirection will be setup using iptables (default: 3308 redirects to 3306) using the following command:

$ iptables -t nat -A PREROUTING -s $0.0.0.0/0 -p tcp --dport 3308 -j REDIRECT --to-ports 3306

Else, the above rule will be taken out from the iptables PREROUTING chain. On the load balancer, define the designated redirection port (3308) instead. If the backend node is "unhealthy", port 3308 will be unreachable because the corresponding iptables rule is removed on the database node. The load balancer shall then exclude it from the load balancing set.

Let’s install the script and see how it works in practice.

1. On the database servers, run the following commands to install the script:

$ git clone https://github.com/ashraf-s9s/clustercheck-iptables
$ cp clustercheck-iptables/mysqlchk_iptables /usr/local/sbin

2. By default, the script will use a MySQL user called “mysqlchk_user” with password “mysqlchk_password”. We need to ensure this MySQL user exists with the corresponding password before the script is able to perform health checks. Run the following DDL statements on one of the DB nodes (Galera should replicate the statement to the other nodes):

mysql> GRANT PROCESS ON *.* TO 'mysqlchk_user'@'localhost' IDENTIFIED BY 'mysqlchk_password';
mysql> FLUSH PRIVILEGES;

** If you would like to run as different user/password, specify -u and/or -p argument in the command line. See examples on the Github page.

3. This script requires running iptables. In this example, we ran on CentOS 7 which comes with firewalld by default. We have to install iptables-services beforehand:

$ yum install -y iptables-services
$ systemctl enable iptables
$ systemctl start iptables

Then, setup basic rules for MySQL Galera Cluster so iptables won’t affect the database communication:

$ iptables -I INPUT -m tcp -p tcp --dport 3306 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 3308 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 4444 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 4567:4568 -j ACCEPT
$ service iptables save
$ service iptables restart

4. Once the basic rules are added, verify them with the following commands:

$ iptables -L -n

5. Test mysqlchk_iptables:

$ mysqlchk_iptables -t
Detected variables/status:
wsrep_local_state: 4
wsrep_sst_method: xtrabackup-v2
read_only: OFF

[11-11-15 08:33:49.257478192] [INFO] Galera Cluster Node is synced.

6. Looks good. Now we can daemonize the health check script:

$ mysqlchk_iptables -d
/usr/local/sbin/mysqlchk_iptables started with PID 66566.

7. Our PREROUTING rules will look something like this:

$ iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:3308 redir ports 3306

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

8. Finally, add the health check command into /etc/rc.local so it starts automatically on boot:

echo '/usr/local/sbin/mysqlchk_iptables -d'>> /etc/rc.local

In some distributions, you need to verify that rc.local holds the correct permission to execute scripts on boot. Verify with:

$ chmod +x /etc/rc.local

From the application side, verify that you can connect to MySQL through port 3308. Repeat the above steps (except step #2) for the remaining DB nodes. Now, we have configured our backend health checks correctly. Let’s set up our MySQL load balancer as described in the next section.

Setting Up nginx as MySQL Load Balancer

1. On the load balancer node, install the required packages:

$ yum -y install pcre-devel zlib-devel

2. Install nginx 1.9 from source with TCP proxy module (--with-stream):

$ wget http://nginx.org/download/nginx-1.9.6.tar.gz
$ tar -xzf nginx-1.9.6.tar.gz
$ ./configure --with-stream

3. Add the following lines into nginx configuration file located at /usr/local/nginx/conf/nginx.conf:

stream {
      upstream stream_backend {
        zone tcp_servers 64k;
        server 192.168.55.201:3308;
        server 192.168.55.202:3308;
        server 192.168.55.203:3308;
    }

    server {
        listen 3307;
        proxy_pass stream_backend;
        proxy_connect_timeout 1s;
    }
}

4. Start nginx:

$ /usr/local/nginx/sbin/nginx

5. Verify that nginx is listening to port 3307 that we have defined. MySQL connections should be coming via this port of this node and then redirects to available backends on port 3308. Then the respective DB node will redirect it to port 3306 where MySQL is listening:

$ netstat -tulpn | grep 3307
tcp        0      0 0.0.0.0:3307            0.0.0.0:*               LISTEN      5348/nginx: master

Great. We have now set up our nginx instance as MySQL Galera Cluster load balancer. Let’s test it out!

Testing

Let’s perform some tests to verify that our Galera cluster is correctly load balanced. We performed various exercises to look at nginx and Galera cluster work in action. We performed the following actions consecutively:

  1. Turn g1.local to read-only=ON and read_only=OFF.
  2. Kill mysql service on g1.local and force SST when startup.
  3. Kill the other two database nodes so g1.local will become non-primary.
  4. Bootstrap g1.local from non-primary state.
  5. Rejoin the other 2 nodes back to the cluster.

The screencast below contains several terminal outputs which explained as follows:

  • Terminal 1 (top left): iptables PREROUTING chain output
  • Terminal 2 (top right): MySQL error log for g1.local
  • Terminal 3 (middle left): Application output when connecting to nginx load balancer. It reports date, hostname, wsrep_last_committed and wsrep_local_state_comment
  • Terminal 4 (middle right): Output of /var/log/mysqlchk_iptables
  • Terminal 5 (bottom left): Output of read_only and wsrep_sst_method on g1.local
  • Terminal 6 (bottom right): Action console

The following asciinema recording shows the result:

 

Summary

Galera node health checks by a TCP load balancer was limited to HAProxy due to its ability to use a custom port for backend health checks. With this script, it’s now possible for any TCP load balancers/reverse-proxies to monitor Galera nodes correctly. 

You are welcome to fork, pull request and extend the capabilities of this script.

Blog category:

A DevOps Guide to Database Infrastructure Automation for eCommerce - Replay & Slides

$
0
0

Thanks to everyone who attended and participated in last week’s webinar on ‘A DevOps Guide to Database Infrastructure Automation for eCommerce’. If you missed the sessions or would like to watch the webinar again & browse through the slides, they are now available online.

Our guest speaker this time was Riaan Nolan of Foodpanda/Rocket Internet. Topics included a roundup of infrastructure challenges faced by online retailers: multi-datacenter/cloud environments, configuration management, health and performance monitoring, capacity analysis and planning, elastic scaling, and automatic failure handling. Thanks again to Riaan for taking the time to speak to us!

Screen Shot 2015-02-20 at 12.30.12.png

The full agenda included: 

  • eCommerce infrastructure challenges in 2014, including a sample workflow chart outlining: 
  • Puppet, GitHub, Capistrano, Nginx, PHP5-FPM / Ruby, Percona XtraDB, Couchbase, SOLR, GlusterFS
  • Provisioning of test/QA and highly available production environments across multi-datacenter and multi-cloud environments (AWS Cloud Formation) 
  • Building and maintaining configuration management systems such as Puppet and Chef
  • Enabling self-service infrastructure services to internal dev teams
  • Health and performance monitoring 
  • Capacity analysis and planning
  • Elastic scaling 
  • Automating failure handling
  • Disaster recovery

 

Watch the replay

 

Read the slides

 

Screen Shot 2015-02-20 at 12.28.33.png

RELATED BLOGS

 

Blog category:


Resources for Highly Available Database Clusters: ClusterControl Release Webinar, Support for Postgres, New Website and More

$
0
0

Check Out Our Latest Technical Resources for MySQL, MariaDB, Postgres and MongoDB Clusters

Like every month, we have created new content and tools for you; here is a summary of what we’ve published. Please do check it out and let us know if you have any comments or feedback.

New Live Technical Webinar

Introducing the New ClusterControl with Live Demo on 24th of March

Johan Andersson, CTO at Severalnines will walk us through the latest edition of ClusterControl and its new features in the form of a live demo. Johan will go over the latest features in ClusterControl including the recently announced support for Postgres.

Register here

cluster_control_logo.jpg

 

Product Announcements & Resources

psql_feat1.PNG

Management and Monitoring of Existing Postgres Servers

This week we announced support for PostgreSQL and ClusterControl can now be used to monitor database metrics, queries and schedule backups. With this new addition, ClusterControl supports MySQL with its main variations MariaDB, Percona XtraDB (single or clustered), MongoDB and PostgreSQL. Companies can manage all these databases through one unified interface.

Find out more

zbx_fi.PNG

ClusterControl Template for Zabbix

We also announced a ClusterControl Template for Zabbix, so Zabbix users can now get information about the status of their database clusters, backups and alarms. We have previously published integrations with other monitoring systems including Nagios and PagerDuty.

Find out more

 

Technical Webinar - Replay

A DevOps Guide to Database Infrastructure Automation for eCommerce

We were lucky enough to recently have Riaan Nolan of Foodpanda/Rocket Internet as our guest speaker for a session during which he shared his experience and advice on how to automate highly available Commerce infrastructures.

If you’re interested in how to deal with the following topics (and more), then do check out the replay of this webinar:

  • eCommerce infrastructure challenges in 2014, including a sample workflow chart outlining: Puppet, GitHub, Capistrano, Nginx, PHP5-FPM / Ruby, Percona XtraDB, Couchbase, SOLR, GlusterFS
  • Provisioning of test/QA and highly available production environments across multi-datacenter and multi-cloud environments (AWS Cloud Formation)
  • Building and maintaining configuration management systems such as Puppet and Chef

Watch the replay and read the slides here

 

Technical Blogs

As many of you will know, GTID was introduced along with MySQL 5.6, and brought along some major changes in the way MySQL operates. When previously one had to work around limitations related to binary logs, it’s now all in the GTID. GTIDs are not flawless though, find out more in this blog post:   

MySQL Replication and GTID-based failover - A Deep Dive into Errant Transactions

mrgt_arch.png

Severalnines Company News

The past twelve months have been quite an exiciting time for us and we decided to publish a status update on where we are today as a company and on what we’re looking forward to for the future. If you haven’t read it yet, do have a look at our Momentum Press Release, which we published recently.

Read the Momentum Press Release

And, last but not least, we’ve also published a brand new website last month! Most of you will have noticed the change already: we’re sporting a new look and have introduced a website with better ease of navigation and simpler paths to get to the information our users are looking for. Do let us know if you have any feedback on it!

We trust these resources are useful. If you have any questions on them or on related topics, please do contact us!

Your Severalnines Team

 

Blog category:

How to Manage the World’s Top Open Source Databases: ClusterControl 1.2.9 Features Webinar Replay

$
0
0

Thanks to everyone who attended and participated in this week’s webinar on 'New Features - ClusterControl 1.2.9 Release'. If you missed the sessions or would like to watch the webinar again & browse through the slides, they are now available online.

Our speaker this time was Johan Andersson, CTO, Severalnines.

Watch the replay

 

 

Read the slides

 

 

With over 7,000 users to date, ClusterControl is the leading, platform independent automation and management solution for the MySQL, MongoDB and now Postgres databases, its latest main feature. 

psql_dash.png

Highlights in ClusterControl 1.2.9 include:

  • Support for PostgreSQL Servers
  • Advanced HAProxy Configurations and Built-in Stats
  • Hybrid Replication with Galera Clusters
  • Galera Replication Traffic Encryption
  • Encrypted Communication between ClusterControl and MySQL-based systems
  • Query Deadlock Detection in MySQL-based systems
  • Bootstrap Galera Cluster
  • Restore of Backups
  • New UI theme
  • RPC interface to ClusterControl
  • Chef Recipe and Puppet Manifest for ClusterControl
  • Zabbix Plugin for ClusterControl

 

RELATED BLOGS

 

ABOUT CLUSTERCONTROL

Setting up, maintaining and operating a database cluster can be tricky. ClusterControl gives you the power to deploy, manage, monitor and scale entire clusters efficiently and reliably. ClusterControl supports a variety of MySQL-based clusters (Galera, NDB, 5.6 Replication), MariaDB as well as MongoDB/TokuMX-based clusters - and now Postgres.

 

Blog category:

How to Deploy and Configure MaxScale for SQL Load Balancing with Read-Write Split

$
0
0

There are two models of load balancing: transport and application layer. HAProxy is a great TCP load balancer, but it’s lack of SQL awareness effectively limits its ability to address certain scaling issues in distributed database environments. In the open source world, there’s been a few SQL-aware load balancers, namely MySQL Proxy, ProxySQL and MaxScale, but they all seemed to be in beta status and unfit for production use. So we were pretty excited when the MariaDB team released a GA version of MaxScale earlier this year. In this blog, we’ll have a look at MaxScale and see how it compares with HAProxy.

Deployment

Installation is easy, at least on the latest LTS version of Ubuntu (Trusty, 14.04) which we used for our tests.

Add a public key:

$ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8167EE24

Add a MaxScale repository to one of *.list files for apt-get:

deb [arch=amd64] http://downloads.mariadb.com/software/MaxScale/maxscale/DEB trusty main

Run:

$ apt-get update && apt-get install maxscale

and you can enjoy your new software - proxy is installed into the /usr/local/skysql/maxscale directory. 

 

Configuration

Once installed, we need to configure it. Along with installation comes an example configuration file, located in: /usr/local/skysql/maxscale/etc/MaxScale_template.cnf. It gives a nice introduction to the available options, and helps to setup the environment.

MaxScale uses a pluggable architecture with different plugins providing different features. In this post, we will concentrate on the routing part, and for now, leave out other interesting possibilities like query rewriting. MaxScale uses different types of services; monitors, services, listeners and filters. 

For our tests we defined two types of routing services: 

  • ‘router=readwritesplit’, which provides read/write (RW) splitting,
  • ‘router=readconnroute’, which provides round-robin-like (RR) kind of access.

Each service was accompanied by a listener, port 3307 for RW split and 3308 for RR service. With RR service, we relied on MaxScale’s monitoring of Galera nodes to route connections only to the nodes in a ‘Synced’ state.

[maxscale]
threads=4

[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3
user=maxmon
passwd=maxpwd
monitor_interval=10000
disable_master_failback=1

[qla]
type=filter
module=qlafilter
options=/tmp/QueryLog

[fetch]
type=filter
module=regexfilter
match=fetch
replace=select

[RW]
type=service
router=readwritesplit
servers=server1,server2,server3
user=root
passwd=secretpass
max_slave_connections=100%
router_options=slave_selection_criteria=LEAST_CURRENT_OPERATIONS

[RR]
type=service
router=readconnroute
router_options=synced
servers=server1,server2,server3
user=root
passwd=secretpass

[Debug Interface]
type=service
router=debugcli

[CLI]
type=service
router=cli

[RWlistener]
type=listener
service=RW
protocol=MySQLClient
address=10.69.179.54
port=3307

[RRlistener]
type=listener
service=RR
protocol=MySQLClient
address=10.69.179.54
port=3308

[Debug Listener]
type=listener
service=Debug Interface
protocol=telnetd
address=127.0.0.1
port=4442

[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
address=127.0.0.1
port=6603


[server1]
type=server
address=10.138.103.93
port=3306
protocol=MySQLBackend

[server2]
type=server
address=10.139.81.25
port=3306
protocol=MySQLBackend

[server3]
type=server
address=10.81.192.219
port=3306
protocol=MySQLBackend

There are couple of interesting bits in the configuration file. As you can see, we had to define user/password pairs several times. Those users are used to check the health of the MySQL nodes and to get access to the list of users defined in the system. For the sake of simplicity we used plain text passwords but it is possible to use hashed passwords for better security. 

Finally, since we wanted to compare performance of MaxScale vs HAProxy, we used HAProxy installed from within ClusterControl in a default setup  configured similarly to MaxScale’s RR service. 

 

How does MaxScale work with Galera Cluster?

So, let’s talk about how MaxScale sees the Galera Cluster. MaxScale provides an admin CLI which gives you access to some internal statistics. After the first login (user admin, password skysql), you can check available options by running the ‘help’ command. One of the very useful commands is ‘show servers’, which returns a health status of the cluster. Below is the example output of that command.

$ /usr/local/skysql/maxscale/bin/maxadmin -u admin
Password:
MaxScale> show servers
Server 0x219bac0 (server1)
    Server:                10.138.103.93
    Status:                       Slave, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            2
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0
Server 0x20f7da0 (server2)
    Server:                10.139.81.25
    Status:                       Slave, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            1
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0
Server 0x20f7c90 (server3)
    Server:                10.81.192.219
    Status:                       Master, Synced, Running
    Protocol:            MySQLBackend
    Port:                3306
    Server Version:            5.6.22-72.0-56-log
    Node Id:            0
    Master Id:            -1
    Repl Depth:            0
    Number of connections:        0
    Current no. of conns:        0
    Current no. of operations:    0

We are interested in the status of the nodes right now  as we can see, we have three nodes ‘Running’, all of them are ‘Synced’. Two were elected as ‘Slave’ and one as a ‘Master’. Those states are what we can use in the configuration file. For example, in RR service we defined the following variable:

router_options=synced

It means that, at any given time, connections can be routed to any of the nodes, as long as they are in the ‘synced’ state (i.e. not serving as a donor or joining the cluster). On the other hand, the RW service was looking for ‘Slave’ and ‘Master’ states to route traffic accordingly. In case of a master failure, a new node is elected as a new master. Your application needs to reconnect though, MaxScale currently does not provide failover for currently open connections.

What’s worth noting, if you want to setup a RW split, you will need to set the max_slave_connections variable accordingly. By default MaxScale sets it to one and, as a result, only one slave is getting read connections. You can here use a fixed number (2, 5) or a percent of the slave pool (50%, 100%). As we wanted all of our slaves, no matter how many there are out there, to serve the traffic, we set this variable to 100%:

max_slave_connections=100%

Another interesting bit is the ‘master’ failover part  when MaxScale detects that a node, elected as a master, is unreachable, it promotes one of the ‘slaves’ to the ‘master’ role. Then, by default, when old ‘master’ comes back online, it is immediately promoted to its old master role. As a result, writes may switch back and forth between different nodes should the ‘master’ start to flap. You can switch this default behavior by adding ‘disable_master_failback=1’ directive to the definition of the monitor service.

In case of any connectivity issues, it’s worth checking log files (by default located in the /usr/local/skysql/maxscale/log/ directory) and the kind of MySQL users MaxScale had detected. The latter can be done from the CLI, using the ‘show dbusers <service>’ command:

MaxScale> show dbusers RW
Users table data
Hashtable: 0x2a0c900, size 52
    No. of entries:         3
    Average chain length:    0.5
    Longest chain length:    7
User names: sbtest@%, maxmon@%, maxmon@%

If you added some new users on the MySQL side, you can refresh MaxScale’s database by running reload dbusers <service>:

MaxScale> reload dbusers RW

In general, the CLI gives you some nice options to use. We’ll not go over all of them in this post, but we’d still like to mention some features:

  • configuration (at least partially) can be changed on fly and reloaded (reload config command)
  • server state can be set from the CLI, which enables a DBA to move writes to a different node in the cluster (set server … command)
  • services can be disabled/enabled/restarted from the CLI

While in the CLI, help is easily reachable through the following commands:

help
help <command> (for example help show)

Stay tuned for part two of this post where we will cover the performance comparison between MaxScale’s different router services and HAProxy.

Blog category:

SQL Load Balancing Benchmark - Comparing Performance of MaxScale vs HAProxy

$
0
0

In a previous post, we gave you a quick overview of the MaxScale load balancer and walked through installation and configuration. We did some quick benchmarks using sysbench, a system performance benchmark that supports testing CPU, memory, IO, mutex and also MySQL performance. We will be sharing the results in this blog post.

Sysbench setup

For our tests we used the latest version of sysbench, straight from bzr. Installation is simple. First, make sure you have all the prerequisites. For Ubuntu these are: libmysqlclient-dev (or equivalent), bzr, automake, make, libtool and libssl-dev.

Get the code and compile it:

$ cd /root
$ bzr branch lp:sysbench
$ cd /root/sysbench
$ ./autogen.sh
$ ./configure
$ make
$ make install

The next step was to prepare database for a benchmark. We created the ‘sbtest’ schema and granted access to it to the ‘sbtest’ user with a correct password. After that, populate the database using the following command:

$ sysbench \
--test=/root/sysbench/sysbench/tests/db/oltp.lua \
--mysql-host=10.69.179.54 \
--mysql-port=3307 \
--mysql-user=sbtest \
--mysql-password=sbtest \
--oltp-tables-count=128 \
--oltp-table-size=400000 \
prepare

Once complete, it is time for some benchmarking.

 

Performance benchmarks

We were interested mostly in the proxy’s throughput thus we executed a series of read-only sysbench OLTP tests. The exact command looked as below:

$ sysbench \
--test=/root/sysbench/sysbench/tests/db/oltp.lua \
--num-threads=512 \
--max-requests=0 \
--max-time=600 \
--mysql-host=10.69.179.54 \
--mysql-port=3307 \
--mysql-user=sbtest \
--mysql-password=sbtest \
--oltp-tables-count=128 \
--oltp-read-only=on \
--oltp-skip-trx=on  \
--report-interval=1 \
--oltp-table-size=400000 \
run

Now, one of the gotchas we ran into while evaluating MaxScale - when using RW service, is that all reads headed directly to the ‘Master’. After some head scratching, we found that, by default, sysbench uses explicit transactions (see --oltp-skip-trx=on in the sysbench command above). MaxScale implements read/write split in a way that may be slightly misleading before you get used to it - reads are split across "slave" nodes, but there are some exceptions. One of them are transactions that are started explicitly - if your app executes queries using BEGIN; ... ; COMMIT; , then all such queries will be routed to the single ‘Master’ instance. As a result, we had to add --oltp-skip-trx=on flag to the sysbench program to make sure reads will be split onto the slaves.

Let’s take a look at the results. Hardware-wise, we’ve been using r3.4xlarge EC2 instances for a proxy/sysbench node and three r3.2xlarge EC2 instances for Galera nodes. Workload was in-memory, CPU bound. Thanks to scalability improvements in MySQL 5.6, we were able to fully saturate all 8 CPU cores on an instance when running sysbench directly against a node - this confirmed that results won’t be skewed by MySQL’s scalability limitations.

As can be seen, each routing method provided fairly stable performance with occasional drops. What’s important to clarify - HAProxy fully saturated one CPU core so this level of performance, around 75k selects per second, is the maximum we can get from this proxy under the test workload. 

On the other hand, the round-robin MaxScale router hit contention of some kind outside of the proxy itself - neither network nor CPU were saturated on the proxy or the Galera nodes. We were not able to push through this level of performance. While performing a sanity check using direct connections to Galera, bypassing the proxy, we were only able to reach the same level of performance, confirming it is something outside of MaxScale. We did not investigate further, AWS is a bit too black-boxish for that and it wasn’t really necessary. The total theoretical throughput of the system under our workload was ~135 - 140k selects per second (two nodes with 100% CPU utilization, delivered ~90-95k selects per second).

The read-write split router performed around ~57k of selects per second, saturating four cores - MaxScale was configured to use four threads. Having seen that, we repeated the benchmark allowing MaxScale to use 12 threads. Here are results:

We can see that read-write split router (green dots) bypassed HAProxy’s performance (blue dots). What we can’t see on the graph, but it was captured by us during the benchmark, was that MaxScale used almost nine CPU cores to get there:

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 31612 root      20   0 1389876  62860   4392 R 877.2  0.0 339:53.56 maxscale
 34485 root      20   0 8435680  48384   1640 S 317.8  0.0  28:46.06 sysbench

R3.4xlarge has 16 virtual cores so there was still room for growth. It seems like this was a maximum possible throughput under our conditions.

What’s interesting is that the round-robin like setup, using readconnroute router, performed worse while having 12 threads (versus when we had 4 threads) enabled in MaxScale’s configuration. After a short investigation, we could see an internal contention on mspin_lock which decreased the performance. What else we can see? Readconnroute router definitely had issues with maintaining stable performance - drops are noticeable and long-running.

 

Response time results

Let’s check the response time graphs. Below, you can see a global overview followed by a zoom into the 0 - 300ms region.

Rather expected results, in line with the performance we have seen in earlier graphs. It’s worth noticing though that both 12 thread configurations delivered much less stable performance than the rest of the setups tested.

 

Conclusions

Let’s try to draw some conclusions from the data. First, MaxScale allows you to implement read/write split without the need to redesign your application. All you need to do is to setup MaxScale with the correct configuration (readwritesplit router). At least, that’s the theory. In practice, your application cannot use explicit transactions (which is not that big limitation per se, but if you do use them, you will not be able to benefit from RW split in an easy way). There are some other gotchas regarding the use of user-defined variables in queries. Those are pretty valid limitations, which are totally understandable, but it has to be said that one can’t expect that RW split in MaxScale will work in all of the cases. You should take some time to read MaxScale’s documentation to familiarize with any other limitations which may affect your particular workload.

Second, MaxScale RW split, while it was able to bypass HAProxy by a small margin in terms of the performance, required significant CPU resources to get there (9 cores compared to HAProxy’s single core) and its performance was not as stable as HAProxy’s. It’s obviously caused by the additional logic needed for a RW split (a MaxScale configuration similar to HAProxy, round-robin, delivered much higher performance than HAProxy and comparable in the stability) but it makes this setup not necessarily the best option to use in all cases.

Taking it all under consideration, we’d say that, for now at least, if you have the possibility of performing a RW split on the application side, you might want to consider it - setup two listeners in the way we did it in this test. Use readconnroute router for reads and readwritesplit router for writes. In that way you’ll be able to read from all nodes of the cluster while writing only to one of them, to minimize chances of deadlocks in Galera. If your application does not allow you to do that, you can still use readwritesplit router to get a RW split even when it results in additional CPU utilization on the proxy’s node. It’s great to have this option even if it comes with a reduced overall performance.

Having said that, the workload that we tested was designed to stress a proxy - it’s very unlikely that your application will want to execute 75k selects per second. Heavier queries will take longer time and total throughput will be much lower. You can also be less CPU-bound but more I/O-bound - usually databases do not fit entirely in the InnoDB buffer pool. In such cases you may never notice the performance limits of the MaxScale readwritesplit router. As usual, it’s all about performing tests and checking what works best in your environment.

Last but not least, MaxScale is still a pretty new software and we’d expect it to mature with every release, adding new options and removing design and scalability limitations. It’s definitely nice to have more options when it comes to proxies, especially when the proxy is database-centric.

Blog category:

How to Deploy and Manage MaxScale using ClusterControl

$
0
0

We were delighted to announce that ClusterControl now supports MaxScale, the intelligent database gateway from the MariaDB team. In this blog, we will show you how to deploy and manage MaxScale from ClusterControl. We previously blogged about MaxScale, read it if you’d like a quick overview and introduction. We also published a quick benchmark of HAProxy vs MaxScale.

How to install MaxScale from ClusterControl

Assume you have a Galera Cluster currently managed by ClusterControl. As next step you want to install MaxScale as load balancer. From the ClusterControl UI, go to Manage > Load Balancer > Install MaxScale. You’ll be presented with following dialog box. 

Please make sure you have chosen ‘Create MaxScale Instance’. We’ll discuss the “MariaDB Repository URL” further down in this blog. The remaining options are pretty clear: 

  • choose or type in the IP address of the node where MaxScale will be installed. ClusterControl has to be able to ssh in a passwordless fashion to this host. 
  • username and password  - it will be used to access MaxScale’s administration interface.
  • next is another username/password - this time, it is a MariaDB/MySQL user that will be used by MaxScale to access and monitor the MariaDB/MySQL nodes in your infrastructure.

Below that you can set couple of configuration settings for MaxScale:

  • how many threads it is allowed to use 
  • which ports should be used for different services. Currently, MaxScale deployed by ClusterControl comes with a CLI service and Debug service - those are standard services available for MaxScale. We also create two ‘production’ services - ‘RW’, which implements a read-write split and ‘RR’ which implements round-robin access to all of the nodes in the cluster. Each of those services have a port assigned to it - you can change it at the deploy stage.

At the bottom of the dialog box, you’ll see your nodes with checkboxes - you can pick those that will be included in the proxy’s configuration.

Let’s get back to the repository URL. Once you click on the tooltip, you’ll see the following screen:

MariaDB introduced individual links to the repository where MaxScale is stored. To get your link, you should log into the MariaDB Enterprise Portal and generate one for yourself. Once you have it, you can paste it in the MariaDB Repository URL box. This concludes the preparations for deployment, you can now click on the ‘Install MaxScale’ button and wait for the process to complete.

You can monitor the progress in ClusterControl > Logs > Jobs. When it finishes, it prints some examples covering how you can connect to your MaxScale instance. For better security you should delete this job by clicking the ‘Delete’ button above it.

How to add an existing MaxScale instance to ClusterControl?

If you already have MaxScale installed in your setup, you can easily add it to ClusterControl to benefit from health monitoring and access to MaxAdmin - MaxScale’s CLI from the same interface you use to manage the database nodes. 
The only requirement is to have passwordless SSH configured between ClusterControl node and host where MaxScale is running. Once you have SSH set up, you can go to Manage > Load Balancer > Install MaxScale. Once you are there, ensure you have chosen ‘Add Existing MaxScale’. You’ll be then presented with a following screen:

The only data you need to pass here is IP of the MaxScale server and port for the MaxScale CLI. After clicking ‘Install MaxScale’, it will be added to the list of processes monitored by ClusterControl.

How to uninstall MaxScale from ClusterControl?

If, for some reason, you would like to uninstall MaxScale, go to the ‘Nodes’ tab and then click on the ‘-’ icon next to the MaxScale node. You’ll be asked if you want to remove the node. If you click yes, MaxScale will be uninstalled from the node you’ve just chosen.

How to access MaxScale MaxAdmin commands?

MaxAdmin is a command line interface available with MaxScale that allows extensive health checks, user management, status and control of MaxScale operations. ClusterControl gives you direct access to the MaxAdmin commands. You can reach it by going to ‘Nodes’ tab and then clicking on your MaxScale node. Once you do that, you’ll be presented with the following screenshot:

You can see the status of the node, and stop the instance if needed. In the user/password boxes, you need to enter MaxScale’s administrative user credentials - this is what you put in the Admin username/password fields where installing MaxScale. If you added an existing MaxScale installation, please use here any administrative user that you created. By default (if you do not provide any input) ClusterControl will try to use the default username and password created during the MaxScale installation (admin/mariadb).

The drop down box contains a predefined set of commands that you can execute by just picking them from the list and then clicking on the ‘Execute’ button. For a full list of commands, you can execute the ‘help’ command.

Results are presented in a console window:

You can clear it at any time by using ‘Reset Console’ button.

Please keep in mind that some of the commands require additional parameters. For example, the ‘show server’ command requires you to pass a server name as a parameter. You can do so by just editing the dropdown box and typing in the parameter:

As we mentioned before, you are not limited to the predefined commands - you can type anything you like in the command box. For example, we can stop and then start one of the services:

CLI access from ClusterControl talks directly to the MaxAdmin, therefore you can use ClusterControl to execute everything that you are able to run using the MaxAdmin CLI client.

Have fun with MaxScale!

Blog category:

nginx as Database Load Balancer for MySQL or MariaDB Galera Cluster

$
0
0

Nginx is well-known for its ability to act as a reverse-proxy with small memory footprint. It usually sits in the front-end web tier to redirect connections to available backend services, provided these passed some health checks. Using a reverse-proxy is common when you are running a critical application or service that requires high availability. It also distributes the load equally among the backend services.

Recently, nginx 1.9 introduced support for TCP load balancing - similar to what HAProxy is capable of. The one major drawback is that it does not support advanced backend health checks. This is required when running MySQL Galera Cluster, as we’ll explain in the next section. Note that this limitation is removed in the paid-only edition called NGINX Plus. 

In this blog post, we are going to play around with nginx as a reverse-proxy for MySQL Galera Cluster services to achieve higher availability. We had a Galera cluster up and running, deployed using ClusterControl on CentOS 7.1. We are going to install nginx on a fresh new host, as illustrated in the following diagram:

Backend Health Checks

With the existence of a synchronously-replicated cluster like Galera or NDB, it has become quite popular to use a TCP reverse-proxy as load balancer. All MySQL nodes are treated equal as one can read or write from any node. No read-write splitting is required, as you would with MySQL master-slave replication. Nginx is not database-aware, so some additional steps are required to configure the health checks for Galera Cluster backends so that they return something understandable. 

If you are running HAProxy, a healthcheck script on each MySQL server in the load balancing set should be able to return an HTTP response status. For example, if the backend MySQL server is healthy, then the script will return a simple HTTP 200 OK status code. Else, the script will return 503 Service unavailable. HAProxy can then update the routing table to exclude the problematic backend servers from the load balancing set and redirect the incoming connections only to the available servers. This is well explained in this webinar on HAProxy. Unfortunately, the HAProxy health check uses xinetd to daemonize and listen to a custom port (9200) which is not configurable in nginx yet.

The following flowchart illustrates the process to report the health of a Galera node for multi-master setup:

At the time of this writing, NGINX Plus (the paid release of nginx) also supports advanced backend health but it does not support custom backend monitoring port.

Using clustercheck-iptables

To overcome this limitation, we’ve created a healthcheck script called clustercheck-iptables. It is a background script that checks the availability of a Galera node, and adds a redirection port using iptables if the Galera node is healthy (instead of returning HTTP response). This allows other TCP-load balancers with limited health check capabilities to monitor the backend Galera nodes correctly. Other than HAProxy, you can now use your favorite reverse proxy like nginx (>1.9), IPVS, keepalived, piranha, distributor, balance or pen to load balance requests across Galera nodes.

So how does it work? The script performs a health check every second on each Galera node. If the node is healthy (wsrep_cluster_state_comment=Synced and read_only=OFF) or (wsrep_cluster_state_comment=Donor and wsrep_sst_method=xtrabackup/xtrabackup-v2), a port redirection will be setup using iptables (default: 3308 redirects to 3306) using the following command:

$ iptables -t nat -A PREROUTING -s $0.0.0.0/0 -p tcp --dport 3308 -j REDIRECT --to-ports 3306

Else, the above rule will be taken out from the iptables PREROUTING chain. On the load balancer, define the designated redirection port (3308) instead. If the backend node is "unhealthy", port 3308 will be unreachable because the corresponding iptables rule is removed on the database node. The load balancer shall then exclude it from the load balancing set.

Let’s install the script and see how it works in practice.

1. On the database servers, run the following commands to install the script:

$ git clone https://github.com/ashraf-s9s/clustercheck-iptables
$ cp clustercheck-iptables/mysqlchk_iptables /usr/local/sbin

2. By default, the script will use a MySQL user called “mysqlchk_user” with password “mysqlchk_password”. We need to ensure this MySQL user exists with the corresponding password before the script is able to perform health checks. Run the following DDL statements on one of the DB nodes (Galera should replicate the statement to the other nodes):

mysql> GRANT PROCESS ON *.* TO 'mysqlchk_user'@'localhost' IDENTIFIED BY 'mysqlchk_password';
mysql> FLUSH PRIVILEGES;

** If you would like to run as different user/password, specify -u and/or -p argument in the command line. See examples on the Github page.

3. This script requires running iptables. In this example, we ran on CentOS 7 which comes with firewalld by default. We have to install iptables-services beforehand:

$ yum install -y iptables-services
$ systemctl enable iptables
$ systemctl start iptables

Then, setup basic rules for MySQL Galera Cluster so iptables won’t affect the database communication:

$ iptables -I INPUT -m tcp -p tcp --dport 3306 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 3308 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 4444 -j ACCEPT
$ iptables -I INPUT -m tcp -p tcp --dport 4567:4568 -j ACCEPT
$ service iptables save
$ service iptables restart

4. Once the basic rules are added, verify them with the following commands:

$ iptables -L -n

5. Test mysqlchk_iptables:

$ mysqlchk_iptables -t
Detected variables/status:
wsrep_local_state: 4
wsrep_sst_method: xtrabackup-v2
read_only: OFF

[11-11-15 08:33:49.257478192] [INFO] Galera Cluster Node is synced.

6. Looks good. Now we can daemonize the health check script:

$ mysqlchk_iptables -d
/usr/local/sbin/mysqlchk_iptables started with PID 66566.

7. Our PREROUTING rules will look something like this:

$ iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:3308 redir ports 3306

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

8. Finally, add the health check command into /etc/rc.local so it starts automatically on boot:

echo '/usr/local/sbin/mysqlchk_iptables -d'>> /etc/rc.local

In some distributions, you need to verify that rc.local holds the correct permission to execute scripts on boot. Verify with:

$ chmod +x /etc/rc.local

From the application side, verify that you can connect to MySQL through port 3308. Repeat the above steps (except step #2) for the remaining DB nodes. Now, we have configured our backend health checks correctly. Let’s set up our MySQL load balancer as described in the next section.

Setting Up nginx as MySQL Load Balancer

1. On the load balancer node, install the required packages:

$ yum -y install pcre-devel zlib-devel

2. Install nginx 1.9 from source with TCP proxy module (--with-stream):

$ wget http://nginx.org/download/nginx-1.9.6.tar.gz
$ tar -xzf nginx-1.9.6.tar.gz
$ ./configure --with-stream

3. Add the following lines into nginx configuration file located at /usr/local/nginx/conf/nginx.conf:

stream {
      upstream stream_backend {
        zone tcp_servers 64k;
        server 192.168.55.201:3308;
        server 192.168.55.202:3308;
        server 192.168.55.203:3308;
    }

    server {
        listen 3307;
        proxy_pass stream_backend;
        proxy_connect_timeout 1s;
    }
}

4. Start nginx:

$ /usr/local/nginx/sbin/nginx

5. Verify that nginx is listening to port 3307 that we have defined. MySQL connections should be coming via this port of this node and then redirects to available backends on port 3308. Then the respective DB node will redirect it to port 3306 where MySQL is listening:

$ netstat -tulpn | grep 3307
tcp        0      0 0.0.0.0:3307            0.0.0.0:*               LISTEN      5348/nginx: master

Great. We have now set up our nginx instance as MySQL Galera Cluster load balancer. Let’s test it out!

Testing

Let’s perform some tests to verify that our Galera cluster is correctly load balanced. We performed various exercises to look at nginx and Galera cluster work in action. We performed the following actions consecutively:

  1. Turn g1.local to read-only=ON and read_only=OFF.
  2. Kill mysql service on g1.local and force SST when startup.
  3. Kill the other two database nodes so g1.local will become non-primary.
  4. Bootstrap g1.local from non-primary state.
  5. Rejoin the other 2 nodes back to the cluster.

The screencast below contains several terminal outputs which explained as follows:

  • Terminal 1 (top left): iptables PREROUTING chain output
  • Terminal 2 (top right): MySQL error log for g1.local
  • Terminal 3 (middle left): Application output when connecting to nginx load balancer. It reports date, hostname, wsrep_last_committed and wsrep_local_state_comment
  • Terminal 4 (middle right): Output of /var/log/mysqlchk_iptables
  • Terminal 5 (bottom left): Output of read_only and wsrep_sst_method on g1.local
  • Terminal 6 (bottom right): Action console

The following asciinema recording shows the result:

 

Summary

Galera node health checks by a TCP load balancer was limited to HAProxy due to its ability to use a custom port for backend health checks. With this script, it’s now possible for any TCP load balancers/reverse-proxies to monitor Galera nodes correctly. 

You are welcome to fork, pull request and extend the capabilities of this script.

Blog category:

Become a ClusterControl DBA: Making your DB components HA via Load Balancers

$
0
0

Choosing your HA topology

There are various ways to retain high availability with databases. You can use Virtual IPs (VRRP) to manage host availability, you can use resource managers like Zookeeper and Etcd to (re)configure your applications or use load balancers/proxies to distribute the workload over all available hosts.

The Virtual IPs need either an application to manage them (MHA, Orchestrator), some scripting (KeepaliveD, Pacemaker/Corosync) or an engineer to manually fail over and the decision making in the process can become complex. The Virtual IP failover is a straightforward and simple process by removing the IP address from one host, assigning it to another and use arping to send a gratuitous ARP response. In theory a Virtual IP can be moved in a second but it will take a few seconds before the failover management application is sure the host has failed and acts accordingly. In reality this should be somewhere between 10 and 30 seconds. Another limitation of Virtual IPs is that some cloud providers do not allow you to manage your own Virtual IPs or assign them at all. E.g., Google does not allow you to do that on their compute nodes.

Resource managers like Zookeeper and Etcd can monitor your databases and (re)configure your applications once a host fails or a slave gets promoted to master. In general this is a good idea but implementing your checks with Zookeeper and Etcd is a complex task.

A load balancer or proxy will sit in between the application and the database host and work transparently as if the client would connect to the database host directly. Just like with the Virtual IP and resource managers, the load balancers and proxies also need to monitor the hosts and redirect the traffic if one host is down. ClusterControl supports two proxies: HAProxy and MaxScale and both are supported for MySQL master-slave replication and Galera cluster. HAProxy and MaxScale both have their own use cases, we will describe them in this post as well.

Why do you need a load balancer?

In theory you don’t need a load balancer but in practice you will prefer one. We’ll explain why. 

If you have virtual IPs setup, all you have to do is point your application to the correct (virtual) IP address and everything should be fine connection wise. But suppose you have scaled out the number of read replicas, you might want to provide virtual IPs for each of those read replicas as well because of maintenance or availability reasons. This might become a very large pool of virtual IPs that you have to manage. If one of those read replicas had a failure, you need to re-assign the virtual IP to another host or else your application will connect to either a host that is down or in worst case, a lagging server with stale data. Keeping the replication state to the application managing the virtual IPs is therefore necessary.

Also for Galera there is a similar challenge: you can in theory add as many hosts as you’d like to your application config and pick one at random. The same problem arises when this host is down: you might end up connecting to an unavailable host. Also using all hosts for both reads and writes might also cause rollbacks due to the optimistic locking in Galera. If two connections try to write to the same row at the same time, one of them will receive a roll back. In case your workload has such concurrent updates, it is advised to only use one node in Galera to write to. Therefore you want a manager that keeps track of the internal state of your database cluster.

Both HAProxy and MaxScale will offer you the functionality to monitor the database hosts and keep state of your cluster and its topology. For replication setups, in case a slave replica is down, both HAProxy and MaxScale can redistribute the connections to another host. But if a replication master is down, HAProxy will deny the connection and MaxScale will give back a proper error to the client. For Galera setups, both load balancers can elect a master node from the Galera cluster and only send the write operations to that specific node.

On the surface HAProxy and MaxScale may seem to be similar solutions, but they differ a lot in features and the way they distribute connections and queries. Both HAProxy and MaxScale can distribute connections using round-robin. You can utilize the round-robin also to split reads by designating a specific port for sending reads to the slaves and another port to send writes to the master. Your application will have to decide whether to use the read or write port. Since MaxScale is an intelligent proxy, it is database aware and is also able to analyze your queries. MaxScale is able to do read/write splitting on a single port by detecting whether you are performing a read or write operation and connecting to the designated slaves or master in your cluster. MaxScale includes additional functionality like binlog routing, audit logging and query rewriting but we will have to cover these in a separate article.

That should be enough background information on this topic, so let’s see how you can deploy both load balancers for MySQL replication and Galera topologies.

Deploying HAProxy

Using ClusterControl to deploy HAProxy on a Galera cluster is easy: go to the relevant cluster and select “Add Load Balancer”:

severalnines-blogpost-add-galera-haproxy.png

And you will be able to deploy an HAProxy instance by adding the host address and selecting the server instances you wish to include in the configuration:

severalnines-blogpost-add-galera-haproxy-2.png

By default the HAProxy instance will be configured to send connections to the server instances receiving the least number of connections, but you can change that policy to either round robin or source. 

Under advanced settings you can set timeouts, maximum amount of connections and even secure the proxy by whitelisting an IP range for the connections.

Under the nodes tab of that cluster, the HAProxy node will appear:

severalnines-blogpost-add-galera-haproxy-3.png

Now your Galera cluster is also available via the newly deployed HAProxy node on port 3307. Don’t forget to GRANT your application access from the HAProxy IP, as now the traffic will be incoming from the proxy instead of the application hosts.  Also, remember to point your application connection to the HAProxy node.

Now suppose the one server instance would go down, HAProxy will notice this within a few seconds and stop sending traffic to this instance:

severalnines-blogpost-add-galera-haproxy-node-down.png

The two other nodes are still fine and will keep receiving traffic. This retains the cluster highly available without the client even noticing the difference.

Deploying a secondary HAProxy node

Now that we have moved the responsibility of retaining high availability over the database connections from the client to HAProxy, what if the proxy node dies? The answer is to create another HAProxy instance and use a virtual IP controlled by Keepalived as shown in this diagram:

The benefit compared to using virtual IPs on the database nodes is that the logic for MySQL is at the proxy level and the failover for the proxies is simple.

So let’s deploy a secondary HAProxy node:

severalnines-blogpost-add-galera-second-haproxy-1.png

After we have deployed a secondary HAProxy node, we need to add Keepalived:

severalnines-blogpost-add-keepalived.png

And after Keepalived has been added, your nodes overview will look like this:

severalnines-blogpost-keepalived.png

So now instead of pointing your application connections to the HAProxy node directly you have to point them to the virtual IP instead.

In the example here, we used separate hosts to run HAProxy on, but you could easily add them to existing server instances as well. HAProxy does not bring much overhead, although you should keep in mind that in case of a server failure, you will lose both the database node and the proxy.

Deploying MaxScale

Deploying MaxScale to your cluster is done in a similar way to HAProxy: ‘Add Load Balancer’ in the cluster list.

severalnines-blogpost-add-maxscale.png

ClusterControl will deploy MaxScale with both the round-robin router and the read/write splitter. The CLI port will be used to enable you to administrate MaxScale from ClusterControl.

After MaxScale has been deployed, it will be available under the Nodes tab:

severalnines-blogpost-maxscale-admin2.png

Opening the MaxScale node overview will present you the interface that grants you access to the CLI interface, so there is no reason to log into MaxScale on the node anymore. 

For MaxScale, the grants are slightly different: as you are proxying, you need to allow connections from the proxy - just like with HAProxy. But since MaxScale is also performing local authentication and authorization, you need to grant access to your application hosts as well.

Deploying Garbd

Galera implements a quorum-based algorithm to select a primary component through which it enforces consistency. The primary component needs to have a majority of votes (50% + 1 node), so in a 2 node system, there would be no majority resulting in split brain. Fortunately, it is possible to add a garbd (Galera Arbitrator Daemon), which is a lightweight stateless daemon that can act as the odd node. The added benefit by adding the Galera Arbitrator is that you can now do with only two nodes in your cluster.

If ClusterControl detects that your Galera cluster consists of an even number of nodes, you will be given the warning/advice by ClusterControl to extend the cluster to an odd number of nodes:

severalnines-blogpost-even-nodes-galera.png

Choose wisely the host to deploy garbd on, as it will receive all replicated data. Make sure the network can handle the traffic and is secure enough. You could choose one of the HAProxy or MaxScale hosts to deploy garbd on, like in the example below:

severalnines-blogpost-add-garbd.png

Alternatively you could install garbd on the ClusterControl host.

After installing garbd, you will see it appear next to your two Galera nodes:

severalnines-blogpost-garbd-cluster-list.png

Final thoughts

We showed you how to make your MySQL master-slave and Galera cluster setups more robust and retain high availability using HAProxy and MaxScale. Also garbd is a nice daemon that can save the extra third node in your Galera cluster. 

This finalizes the deployment side of ClusterControl. In our next blog, we will show you how to integrate ClusterControl within your organization by using groups and assigning certain roles to users.

Blog category:


High availability read-write splitting with php-mysqlnd, MySQL Replication and HAProxy

$
0
0

MySQL Replication is used in a variety of use cases - scale out read workloads, provide high availability and geographic redundancy, offload backups and reporting/analytic jobs. However it has a big drawback - the application needs to be able to send writes to the master only. Updating more than one master in a replication setup can result in data inconsistency and cause replication to break.

An SQL-aware load balancer like MaxScale could help here, as it could redirect SQL to the appropriate node. If you are using HAProxy and the application is written in PHP, read-write splitting is still achievable with the PHP MySQL native driver with master slave plugin (aka php-mysqlnd_ms). The driver can perform the read-write splitting, as well as load balancing and failover. There are advantages for having a load balancer as well though. php-mysqlnd_ms also has experimental support for multi-master replication setups like Galera or MMM.

In this blog post, we explore the use of php-mysqlnd_ms with a PHP application (Wordpress) on a standard MySQL Replication backend.

Why add HAProxy between php-mysqlnd and MySQL?

The suggestion here is to use HAProxy between the PHP driver and MySQL, as it provides a single point access to the application, routes queries to the backend MySQL servers and also takes care of the master slave health checks. The reason behind this is to minimize the changes that need to be done on the php-mysqlnd configuration file residing on each application server. Especially important during dynamic replication topology changes, e.g., when a new slave is added or removed from the setup. If you have many application/web servers that connects to a single replication setup or the database servers are hosted in a dynamic environment that is constantly changing (e.g Docker, cloud instances), then this setup might be what you are looking for.

Our architecture looks like this:

The PHP application (Wordpress) is hosted on the web server,  and php-mysqlnd_ms will redirect writes to the HAProxy node on port 3307 while reads are redirected to port 3308. A hot-standby HAProxy instance is coupled with Keepalived to provide a virtual IP address. The web server connects to the virtual IP address on the respective port as a single access point to our MySQL Replication setup. All nodes in this setup are running on Debian 8 (Jessie).

Deploying MySQL Replication

We use ClusterControl to deploy a three node MySQL Replication with two slaves. Install ClusterControl and go to “Create Database Node”. In this dialog, we are going to create a MySQL Replication master node. Specify the required information and click “Deploy”:

Once added, we will use “Add Node” function to add one slave at a time:

Repeat the above step for the second slave. At the end of the deployment, you should see something like the below in ClusterControl’s summary bar. You should see one master node and two slaves:

Deploying HAProxy and Configuring Health Checks

ClusterControl supports deployment of HAProxy and Keepalived. For MySQL Replication, ClusterControl by default uses a script called mysqlchk located at /usr/local/sbin/mysqlchk on the every database node to run a simple ‘select 1’ health check. The script doesn’t produce an accurate health check result and can’t distinguish whether the database node is a healthy master or slave.

We have to come out with a better health check that suits HAProxy. For the purpose of this blog post, we have built a custom health check script. The script detects the MySQL replication role on the database node as per below:

  • if master (SHOW SLAVE HOSTS > 1 AND read_only = OFF)
    • return 'MySQL master is running.'
  • if slave (Slave_IO_Running = Yes AND Slave_SQL_Running = Yes AND (Seconds_Behind_Master = 0 OR Seconds_Behind_Master < SLAVE_LAG_LIMIT))
    • return 'MySQL slave is running. (slave lag: 0)'
  • else
    • return 'MySQL is *down*'

Note that the assigned mysql user must have at least REPLICATION CLIENT and REPLICATION SLAVE in order for the script to report correctly.

  1. Before the deployment begins, run the following command on the ClusterControl node to replace the health check template for MySQL Replication:

    $ wget https://raw.githubusercontent.com/ashraf-s9s/mysqlchk/master/mysqlchk.mysql -O /usr/share/cmon/templates/mysqlchk.mysql
  2. Now we are good to deploy the two HAProxy instances. Ensure the role for all nodes are set to Active and click on ‘Install HAProxy’ to start the installation:

    Repeat the above step for the second HAproxy node.

  3. To make HAProxy work with MySQL Replication, two HAProxy listeners (3307 for writes, 3308 for reads) are required. We also have to use tcp-check to distinguish whether the backend node is a healthy master or slave. To achieve this, we need to perform some modification to the installed HAProxy configuration file located at /etc/haproxy/haproxy.cfg of the load balancer nodes.

    Ensure you have the following configuration lines in haproxy.cfg on both load balancer nodes:

    listen  haproxy_192.168.55.110_3307
            bind *:3307
            mode tcp
            timeout client  10800s
            timeout server  10800s
            balance leastconn
            option tcp-check
            tcp-check expect string MySQL\ master
            option allbackups
            default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server 192.168.55.111 192.168.55.111:3306 check
            server 192.168.55.112 192.168.55.112:3306 check
            server 192.168.55.113 192.168.55.113:3306 check
    
    listen  haproxy_192.168.55.110_3308
            bind *:3308
            mode tcp
            timeout client  10800s
            timeout server  10800s
            balance leastconn
            option tcp-check
            tcp-check expect string is\ running.
            option allbackups
            default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server 192.168.55.111 192.168.55.111:3306 check
            server 192.168.55.112 192.168.55.112:3306 check
            server 192.168.55.113 192.168.55.113:3306 check

    ** The use of ‘option tcp-check’ and ‘tcp-check expect’ is vital here. This is how HAProxy is capable to route the incoming query to the correct backend server. Writes are redirected to the node which report ‘MySQL master is running’ (therefore the expected string is “MySQL\ master”). Reads are redirected to the nodes which contain “is\ running” in the return string, to include master (‘MySQL master is running’) and all slaves (‘MySQL slave is running’) in the read-only load balancing set.

  4. Then, deploy Keepalived with virtual IP address 192.168.55.100 via ClusterControl > Actions > Add Load Balancer > Install Keepalived:

    At this point, all nodes have been deployed correctly - as indicated by the green ticks in the summary bar:

Database and load balancer tiers are now deployed. Let’s move to the application tier.

Deploying Web Server and Configuring php-mysqlnd for Master Slave

The following steps should be performed on the web/application server:

  1. Install Apache web server and PHP 5 packages:

    $ apt-get install apache2 libapache2-mod-php5 php5-common php5-gd php5-json php5-curl php5-mysqlnd php-pear php5-dev
  2. Install mysqlnd_ms module through PECL:

    $ pecl install mysqlnd_ms
  3. Create a configuration file for mysqlnd_ms:

    $ vi /etc/php5/mods-available/mysqlnd_ms.ini

    Add the following line:

    ; configuration for php MySQL module
    ; priority=40
    extension=mysqlnd_ms.so
    mysqlnd_ms.enable=1
    mysqlnd_ms.config_file=/etc/php5/mods-available/mysqlnd_ms.json

    **We are using priority=40 since it requires php-mysqlnd module to be loaded first.

  4. Enable the module:

    $ php5enmod mysqlnd_ms
  5. Create the mysqlnd_ms.json configuration file

    $ vi /etc/php5/mods-available/mysqlnd_ms.json

    Add the following lines:

    {
           "wordpress_ms": {
                   "master": {
                           "master_0": {
                                   "host": "192.168.55.100",
                                   "port": "3307",
                                   "user": "wpress",
                                   "password": "password",
                                   "db": "wpress"
                           }
                   },
                   "slave": {
                           "slave_0": {
                                   "host": "192.168.55.100",
                                   "port": "3308",
                                   "user": "wpress",
                                   "password": "password",
                                   "db": "wpress"
                           }
                   }
           }
    }

    We defined the application name as “wordpress_ms”, this value will be used to replace the ‘host’ value in MySQL function call. The master section provides information about the MySQL master - we forward writes to the virtual IP address on the HAProxy node, on port 3307. HAProxy will automatically discover the correct master to send the writes to. The slave section provides information for MySQL slaves - we forward reads to the virtual IP address on the HAProxy node, on port 3308. HAProxy will then automatically discover which nodes available to send the reads to.

  6. The JSON configuration file must be accessible by the Apache user, in this case we are using the default www-data. Apply correct ownership on the config file:

    $ chown www-data.www-data /etc/php5/mods-available/mysqlnd_ms.json

Now we are ready to deploy Wordpess with MySQL Replication as the database backend.

Installing Wordpress

When installing Wordpress, specify the mysqlnd_ms application name (wordpess_ms) as the Database Host value:

That’s it! You are now running Wordpress with read-write splitting on top of MySQL Replication.

Testing

Writes are done on the master server only. If the master fails, replication will stop. Failover must be done by promoting the most updated slave, before replication can resume. Applications doing updates must then reconnect to the newly promoted master and then continue to operate.

If the master (192.168.55.111) is down, we need to promote one of the slaves (192.168.55.112) to new master. To achieve this, go to ClusterControl > Nodes > choose 192.168.55.112 > Promote Slave:

Once selected, click ‘Execute’. You will be prompted with the following:

Once the selected slave has become the new master, the other slaves will automatically failover to the new master and continue to get updates while the old master is down. When the old master comes up again, it will take the role of a slave and synchronize with the new master (which is handling application updates). This is orchestrated by ClusterControl. The following screenshot shows the old master (192.168.55.111) has became a slave in the replication chain:

Once the old master is up-to-date with the new master, the old master will remain as slave.

When a new master is promoted, HAProxy will automatically send the writes to the newly promoted node, as shown in the HAProxy stats page below:

This setup will require no changes on the application and load balancer tier if the replication topology changes. Easier to manage and less error prone. Happy read-write splitting!

Newly Updated “MySQL Load Balancing with HAProxy” Tutorial

$
0
0

We are glad to announce that one of our most popular tutorials has just been updated and is available here. In this tutorial, we cover how HAProxy works, and how to deploy, configure and manage HAProxy in conjunction with MySQL using ClusterControl.

Applications typically connect to a database cluster or replicated setup by opening connections on one of the database nodes in order to run transactions. If the database node fails, the client would need to reconnect to another database node before it can continue to serve requests. There are database drive that supports connection pooling, load balancing and failover e.g. Connector/J and PHP MySQL native driver for master slave. However, in other clustering setup like Galera Cluster for MySQL or MariaDB, the JDBC and PHP drivers are not aware of internal Galera state information, and introducing a reverse proxy layer will make your architecture expandable in the future.

In short, there are 3 health check methods that can be used with MySQL:

  • mysql-check
  • tcp-check
  • httpchk

Some health check methods require a health check script tailored for it. Configuring health check is the key component to correctly identify the backend MySQL servers so HAProxy can route the incoming connections to the correct server. It reduces the application complexity when dealing with constantly changing cluster or replication state.

We also covered how HAProxy performs failure detection, what configuration options should we tweak for different environments, what is the recommended architecture to avoid single point of failure (SPOF), etc.

New chapters introduced in this tutorial:

  • Read-write splitting with HAProxy
  • How health check should be performed on different MySQL setups
  • Updated deployment instructions with ClusterControl
  • HAProxy redundancy with Keepalived
  • Monitoring HAProxy
  • Troubleshooting and workaround on common issues

Take a look at the tutorial. Happy load balancing!

Planets9s: Sign up for our best practices webinar on how to upgrade to MySQL 5.7

$
0
0

Welcome to this week’s Planets9s, covering all the latest resources and technologies we create around automation and management of open source databases.

Sign up for our best practices webinar on how to upgrade to MySQL 5.7

Join us on Tuesday, March 15th for this new webinar on best practices for upgrading to MySQL 5.7 led by Krzysztof Książek, Senior Support Engineer at Severalnines.

MySQL 5.7 has been around for a while now, and if you haven’t done so yet, it’s probably about time to start thinking about upgrading. There are a few things to keep in mind when planning an upgrade, such as important changes between versions 5.6 and 5.7 as well as detailed testing that needs to precede any upgrade process. Amongst other things, we’ll look at how to best research, prepare and perform such tests before the time comes to finally start the upgrade.

Sign up today

Newly Updated “MySQL Load Balancing with HAProxy” Tutorial

We are glad to announce that one of our most popular tutorials, MySQL Load Balancing with HAProxy, has just been updated and is available online. In this tutorial, we cover how HAProxy works, and how to deploy, configure and manage HAProxy in conjunction with MySQL using ClusterControl.

Read the tutorial

Watch the replay: How to build scalable database infrastructures with MariaDB & HAProxy

Thanks to everyone who participated in last week’s live webinar on how CloudStats.me moved from MySQL to clustered MariaDB for high availability with Severalnines ClusterControl. The webinar included use case discussions on CloudStats.me’s database infrastructure bundled with a live demonstration of ClusterControl to illustrate the key elements that were discussed.

Watch the replay

Do share these resources with your colleagues and follow us in our social media channels.

Have a good end of the week,

Jean-Jérôme Schmidt

Planets9s Editor
Severalnines AB

Planets9s - Watch the replay: How To Set Up SQL Load Balancing with HAProxy

$
0
0

Welcome to this week’s Planets9s, covering all the latest resources and technologies we create around automation and management of open source databases.

Watch the replay: How To Set Up SQL Load Balancing with HAProxy

This webinar covers the concepts around the popular open-source HAProxy load balancer, and shows you how to use it with your SQL-based database clusters. High availability strategies for HAProxy with Keepalived and Virtual IP are also discussed. This is a great webinar to watch as a complement to our popular load balancing tutorial.

Watch the replay

Sign up for our best practices webinar on how to upgrade to MySQL 5.7

Join us next Tuesday for this live webinar on best practices for upgrading to MySQL 5.7!

There are a few things to keep in mind when planning an upgrade like this, such as important changes between versions 5.6 and 5.7 as well as the detailed testing that needs to precede any upgrade process. Amongst other things, we’ll look at how to best research, prepare and perform such tests before the time comes to finally start the upgrade.

Sign up today

Success story: iyzico uses ClusterControl to increase MySQL database uptime

Discover why ClusterControl was chosen by iyzico, a PCI DSS Level-1 certified Payment Service Provider in Turkey, to manage its high availability databases across multiple datacenters. It took only three weeks for iyzico to go live on ClusterControl.

Read the customer success story

Do share these resources with your colleagues and follow us in our social media channels.

Have a good end of the week,

Jean-Jérôme Schmidt
Planets9s Editor
Severalnines AB

Read-Write Splitting for Java Apps using Connector/J, MySQL Replication and HAProxy

$
0
0

In a previous post, we looked into load balancing for PHP apps and how to configure read-write splitting on MySQL Replication setups. The native PHP MySQL driver (php-mysqlnd_ms) would perform read/write splits, and the MySQL connections would be made on one of the two listeners of HAProxy.

In this post, we’ll play around with Java, Connector/J, MySQL Replication and HAProxy. One important thing to note is that, unlike php-mysqlnd_ms, Connector/J is aware of MySQL Replication but it does not automatically perform read-write splitting. We have to instruct the query statement in the code of our Java application to establish a so-called read operation, using a JDBC connection object as read-only. Then, the driver will redirect the query to one of the healthy slaves as defined in the JDBC connection string.

We are going to manually deploy a MariaDB Replication setup and add it into ClusterControl using “Add Existing Server/Cluster”. Then, we will deploy HAProxy with Keepalived, and create a simple Java application to connect to our Replication setup.

Why add HAProxy between Connector/J and MariaDB?

Since we are using MariaDB Server, we are going to use MariaDB Connector/J. Similar to MySQL Connector/J (MariaDB’s Connector/J also supports MySQL and vice versa), it supports various features like read/write master, failover or round-robin load balanced set of slaves. These features are configurable from the application via coding, and we want to eliminate that so the load balancer tier (HAProxy and Keepalived) is totally independent. The load balancer tier will take care of failover, load balancing, connection throttling, Virtual IP address and backend health checks. By doing this, we can minimize the hard-coded changes on the application side and reduce dependency between the layers. If you have multiple application/web servers that connect to a single replication setup, or the database servers are hosted in a dynamic environment that is constantly changing (e.g Docker, cloud instances), then this setup might be what you are looking for.

Our architecture looks like this:

Our simple Java application is hosted on the web server, and the JDBC driver will redirect writes to the HAProxy node on port 3307 while reads are redirected to port 3308. A hot-standby HAProxy instance is coupled with Keepalived to provide a virtual IP address. The web server connects to the virtual IP address on the respective port as a single access point to our MariaDB Replication setup. All database nodes in this setup are running on Debian 8 (Jessie).

Deploying a replicated master-slave MariaDB setup

  1. Let’s deploy our MariaDB setup. We used three hosts for this purpose, one master and two slaves. Install MariaDB server on each of the server:

    $ apt-get install software-properties-common
    $ apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
    $ add-apt-repository 'deb [arch=amd64,i386] http://ossm.utm.my/mariadb/repo/10.1/debian jessie main'
    $ apt-get update
    $ apt-get install -y mariadb-server

    ** Enter the MySQL root password in the password dialog.

  2. Configure each MariaDB server with minimal recommended replication configuration. Firstly, create a new MariaDB configuration file at /etc/mysql/my.cnf:

    $ vi /etc/my.cnf

    And add following lines:

    mariadb1:

    [mysqld]
    bind-address=0.0.0.0
    gtid_domain_id=1
    log_bin=binlog
    log_slave_updates=1
    expire_logs_days=7
    server_id=1001
    binlog_format=ROW
    basedir=/usr
    datadir=/var/lib/mysql
    pid_file=mysql.pid
    socket=/var/run/mysqld/mysqld.sock

    mariadb2:

    [mysqld]
    bind-address=0.0.0.0
    gtid_domain_id=1
    log_bin=binlog
    log_slave_updates=1
    expire_logs_days=7
    server_id=1002
    binlog_format=ROW
    basedir=/usr
    datadir=/var/lib/mysql
    pid_file=mysql.pid
    socket=/var/run/mysqld/mysqld.sock

    mariadb3:

    [mysqld]
    bind-address=0.0.0.0
    gtid_domain_id=1
    log_bin=binlog
    log_slave_updates=1
    expire_logs_days=7
    server_id=1003
    binlog_format=ROW
    basedir=/usr
    datadir=/var/lib/mysql
    pid_file=mysql.pid
    socket=/var/run/mysqld/mysqld.sock
  3. Restart MariaDB to load the changes:

    $ systemctl restart mysql
  4. On mariadb1, create the replication slave user. Use mysql client to access the server:

    $ mysql -uroot -p

    And run the following statements:

    MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO ‘slave’@’%’ IDENTIFIED BY ‘slavepassword’;
    MariaDB [(none)]> FLUSH PRIVILEGES;
  5. Identify the MariaDB GTID value on mariadb1 by using the binlog_gtid_pos function:

    MariaDB [(none)]> show master status;
    +---------------+----------+--------------+------------------+
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +---------------+----------+--------------+------------------+
    | binlog.000003 |      609 |              |                  |
    +---------------+----------+--------------+------------------+
    1 row in set (0.00 sec)
    
    MariaDB [(none)]>  SELECT binlog_gtid_pos('binlog.000003',609);
    +--------------------------------------+
    | binlog_gtid_pos('binlog.000003',609) |
    +--------------------------------------+
    | 1-1001-2                             |
    +--------------------------------------+

    The GTID position is 1-1001-2. We will use this value when setting up the slaves.

  6. On slaves (mariadb2 and mariadb3), run the following statements to start the slaves:

    MariaDB [(none)]> SET GLOBAL gtid_slave_pos = '1-1001-2';
    MariaDB [(none)]> CHANGE MASTER TO master_host='192.168.55.111', master_user='slave', master_password='slavepassword', master_use_gtid=slave_pos;
    MariaDB [(none)]> START SLAVE;
  7. Verify the slave status and ensure the value of Slave_IO_Running and Slave_SQL_Running is ‘Yes’:

    MariaDB [(none)]> SHOW SLAVE STATUS\G

Our Replication setup is now deployed.

Adding the Replication Setup into ClusterControl

  1. Install ClusterControl on ClusterControl server.

  2. Once installed, generate SSH keys and copy it to all nodes (including the ClusterControl server itself):

    $ ssh-keygen -t rsa
    $ ssh-copy-id 192.168.55.110 # ClusterControl + Haproxy #1
    $ ssh-copy-id 192.168.55.111 # mariadb1
    $ ssh-copy-id 192.168.55.112 # mariadb2
    $ ssh-copy-id 192.168.55.113 # mariadb3
    $ ssh-copy-id 192.168.55.101 # Haproxy #2
  3. Login to ClusterControl and go to “Add Existing Server/Cluster”. Specify the required details in the dialog:

    Click on ‘Add Cluster’ and wait for the job to complete.

    Once completed, you should see something like the below in the ClusterControl summary bar. You should see one master node and two slaves:

    Since our database is MariaDB, we are going to change some parameters so ClusterControl can handle Replication for MariaDB. Find the following lines inside /etc/cmon.d/cmon_1.cnf and change the value accordingly:

    type=replication
    vendor=mariadb

    Save the file and restart CMON service so it loads up the new configuration options:

    $ service cmon restart

    Go to ClusterControl > Settings > Cluster Registrations > Synchronize Cluster to load up the interface for Replication. You should now notice the changes, similar to the screenshot below:

Deploying HAProxy and Configuring Health Checks

Similar to the previous blog post, we are going to use the same custom health check script for MariaDB. This health check script produces a more accurate health check on the master and slave servers. The script detects the MySQL replication role on the database node as per below:

  • if master (SHOW SLAVE HOSTS > 1 AND read_only = OFF)
    • return 'MySQL master is running.'
  • if slave (Slave_IO_Running = Yes AND Slave_SQL_Running = Yes AND (Seconds_Behind_Master = 0 OR Seconds_Behind_Master < SLAVE_LAG_LIMIT))
    • return 'MySQL slave is running. (slave lag: 0)'
  • else
    • return 'MySQL is *down*'

Note that the assigned mysql user must have at least PROCESS, REPLICATION CLIENT and REPLICATION SLAVE privileges in order for the script to report correctly.

  1. Before the deployment begins, run the following command on the ClusterControl node to replace the health check template for MySQL Replication:

    $ wget https://raw.githubusercontent.com/ashraf-s9s/mysqlchk/master/mysqlchk.mysql -O /usr/share/cmon/templates/mysqlchk.mysql
  2. Now we are good to deploy the two HAProxy instances. Ensure the role for all nodes are set to Active and click on ‘Install HAProxy’ to start the installation:

    Repeat the above step for the second HAproxy node.

  3. To make HAProxy work with MySQL Replication, two HAProxy listeners (3307 for writes, 3308 for reads) are required. We also have to use tcp-check to distinguish whether the backend node is a healthy master or slave. To achieve this, we need to perform some modification to the installed HAProxy configuration file located at /etc/haproxy/haproxy.cfg of the load balancer nodes.

    Ensure you have the following configuration lines in haproxy.cfg on both load balancer nodes (don’t forget to replace the existing listener directive created by ClusterControl):

    listen  haproxy_192.168.55.110_3307
            bind *:3307
            mode tcp
            timeout client  10800s
            timeout server  10800s
            balance leastconn
            option tcp-check
            tcp-check expect string MySQL\ master
            option allbackups
            default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server mariadb1 192.168.55.111:3306 check
            server mariadb2 192.168.55.112:3306 check
            server mariadb3 192.168.55.113:3306 check
     
    listen  haproxy_192.168.55.110_3308
            bind *:3308
            mode tcp
            timeout client  10800s
            timeout server  10800s
            balance leastconn
            option tcp-check
            tcp-check expect string is\ running.
            option allbackups
            default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server mariadb1 192.168.55.111:3306 check
            server mariadb2 192.168.55.112:3306 check
            server mariadb3 192.168.55.113:3306 check

    ** The use of ‘option tcp-check’ and ‘tcp-check expect’ is vital here. This is how HAProxy is capable of routing the incoming query to the correct backend server. Writes are redirected to the node which report ‘MySQL master is running’ (therefore the expected string is “MySQL\ master”). Reads are redirected to the nodes which contain “is\ running” in the return string, to include master (‘MySQL master is running’) and all slaves (‘MySQL slave is running’) in the read-only load balancing set.

    Restart HAProxy service to load it up:

    $ systemctl restart haproxy

    To verify, go to ClusterControl > Nodes > choose one of the load balancer node, and you should see something like below:

  4. Then, deploy Keepalived with virtual IP address 192.168.55.100 via ClusterControl > Actions > Add Load Balancer > Install Keepalived:

    At this point, all nodes have been deployed correctly - as indicated by the green ticks in the summary bar:

Database and load balancer tiers are now deployed. Let’s move to the application tier.

Deploying Application and MariaDB Connector/J

In this example, we wrote a simple Java application that can read/write to our MariaDB setup. The connection string for replication format is “jdbc:mysql:replication://master,slave1,slave2,slave3/database”, assumes that the first (and only the first) host is the master and the rest are slaves. We also need to install MariaDB Connector/J before the application can connect to the database.

To perform read-write splitting, we have to use the setReadOnly method. If the connection object with Connection.setReadOnly(false) is called, connection will be established on the available master, while Connection.setReadOnly(true) will be established to the available slave(s), throwing an SQLException if it cannot establish a connection to a slave, unless the property readFromMasterWhenNoSlaves is set to be “true”.

  1. Install Java and required packages:

    $ yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
  2. On the master node (mariadb1), create a database, a database user and a table, java.tbl_test:

    $ mysql -uroot -p -h192.168.55.111 -P3306

    And run the following statements:

    MariaDB> CREATE SCHEMA java;
    MariaDB> GRANT ALL PRIVILEGES ON java.* to java@’%’ IDENTIFIED BY ‘password’;
    MariaDB> CREATE TABLE tbl_test (id INT PRIMARY KEY AUTO_INCREMENT, data INT);
  3. Create an application directory and a file called ExampleReadWrite.java:

    $ mkdir -p /root/java-apps
    $ vi /root/java-apps/ExampleReadWrite.java

    And paste the following lines into it:

    import java.sql.*;
    
    public class ExampleReadWrite {
     // JDBC driver name and database URL                                                                    
     static final String JDBC_DRIVER = "org.mariadb.jdbc.Driver";
     static final String DB_URL = "jdbc:mysql:replication://192.168.55.100:3307,192.168.55.100:3308/java";
    
     // Database credentials                                                                                
     static final String USER = "java";
     static final String PASS = "password";
    
     public static void main(String[] args) {
      Connection conn = null;
      Statement stmt = null;
      try {
       // Register JDBC driver                                                                       
       Class.forName("org.mariadb.jdbc.Driver");
    
       // Open a connection                                                                          
       while (true) {
        conn = DriverManager.getConnection(DB_URL, USER, PASS);
        stmt = conn.createStatement();
    
        String insert_sql = "INSERT INTO tbl_test (data) VALUES (1)";
        String get_hostname = "SELECT @@hostname";
        String read_sql = "SELECT @@hostname AS hostname, count(id) AS count FROM tbl_test";
    
        // Turn off readonly so write is forwarded to master - HAProxy port 3307
        conn.setReadOnly(false);
        conn.setAutoCommit(false);
        ResultSet hrs = stmt.executeQuery(get_hostname);
        stmt.executeUpdate(insert_sql);
        conn.commit();
    
        if (hrs.next()) {
         String write_hostname = hrs.getString(1);
         System.out.println("[WRITE] Hostname: " + write_hostname);
        }
    
        // Turn on readonly so read is forwarded to master/slave(s) - HAProxy port 3308
        conn.setReadOnly(true);
        ResultSet rs = stmt.executeQuery(read_sql);
    
        while (rs.next()) {
         String hostname = rs.getString("hostname");
         int row_count = rs.getInt("count");
         System.out.println("[READ ] Hostname: " + hostname + " | Row counts: " + row_count);
         System.out.println("");
        }
        rs.close();
        stmt.close();
        conn.close();
        // Pause for 2 seconds before loop
        Thread.sleep(2000);
       }
    
      } catch (SQLException se) {
       se.printStackTrace();
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       try {
        if (stmt != null)
         stmt.close();
       } catch (SQLException se2) {}
       try {
        if (conn != null)
         conn.close();
       } catch (SQLException se) {
        se.printStackTrace();
       }
      }
      System.out.println("Goodbye!");
     }
    }
  4. Download and install MariaDB Connector/J JAR file from this page (registration required) inside the application directory. Then, set the location of the JAR file into CLASSPATH environment so Java can load it:

    $ cd /root/java-apps
    $ wget https://downloads.mariadb.com/enterprise/zdkv-r01a/connectors/java/connector-java-1.3.6/mariadb-java-client-1.3.6.jar
    $ export CLASSPATH=/root/java-apps/mariadb-java-client-1.3.6.jar:$CLASSPATH
  5. Compile the source:

    $ javac ExampleReadWrite.java
  6. Let’s run the application:

    $ java ExampleReadWrite
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb1.local | Row counts: 124
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb2.local | Row counts: 125
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb3.local | Row counts: 126
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb1.local | Row counts: 127
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb2.local | Row counts: 128
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb3.local | Row counts: 129
    
    [WRITE] Hostname: mariadb1.local
    [READ ] Hostname: mariadb1.local | Row counts: 130

    From the application’s output, we can see that writes will always go to master (mariadb1.local) while reads are distributed evenly to all nodes (slaves + master), based on the leastconn algorithm specified in the HAProxy configuration.

    You can also access the HAProxy admin page available at http://[clustercontrol_server]:9600/ with default username/password is “admin”:

    Note that in this example, no connection pooling is configured for our Java apps.

Connection Pooling + HAProxy

Connection pooling is popular in Java since it can significantly increase the performance of your Java application, while reducing overall resource usage. After a connection is created, it is placed in the pool and it is used again so that a new connection does not have to be established. If all the connections are being used, a new connection is made and is added to the pool. Connection pooling also cuts down on the amount of time a user must wait to establish a connection to the database.

On the other hand, HAProxy is pretty good in forwarding raw TCP packets where connections are created and then closed. Due to this, HAProxy is usually configured with low timeout values. Common practice if using connection pooling with HAProxy is to configure the timeout client, timeout connect and timeout server variables to be the same value as the timeout value configured in the connection pool. Also, the value of HAProxy’s maxconn must be equal to or greater than the maximum number of database connections in the pool.

That’s it. You are now set with a more resilient architecture of your Java apps on top of Replication setups.

Viewing all 98 articles
Browse latest View live