<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Koushik's Blog on Open Source on Azure</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/opensourcemsft/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/feed.xml</link>
    <description />
    <lastBuildDate>Sun, 11 Dec 2016 03:29:35 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Step by step: Set up a Docker host on Azure using CLI on a Mac</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/step-by-step-set-up-a-docker-host-on-azure-using-cli-on-a-mac</link>
      <pubDate>Sun, 11 Dec 2016 03:29:35 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">http://blogs.msdn.microsoft.com/opensourcemsft/?p=195</guid>
      <description><![CDATA[After I published my architectural discussion on how to scale a simple dockerized Apache-PHP...]]></description>
      <content:encoded><![CDATA[<i>After I published my architectural discussion on how to scale a simple dockerized Apache-PHP application for production use at large scale <a href="https://github.com/kbxkb/file-upload-link-share-simple">on github</a>, I got several requests to publish the steps to get a Docker host up and running - mostly because that is a pre-requisite to replicate my small project.</i>

Hence, I am going to quickly document the steps you can follow from your Mac to get a Docker host running on Microsoft Azure.

In order to do follow these steps, you will need an Azure subscription, which I assume you will have.
<ol>
 	<li>Install Node and npm on on your Mac, as that is one of the easier ways to get the Azure CLI (Command Line Interface) installed.

Follow the steps here to do so: <a href="http://blog.teamtreehouse.com/install-node-js-npm-mac">http://blog.teamtreehouse.com/install-node-js-npm-mac</a>

One thing that the above blog does not go into the details of is how to install the correct Xcode on your Mac. If you go to the Apple Store, you will only get the latest version of Xcode. But your Mac may be running an older version of OSX, which cannot install the latest version of Xcode. If that happens, you will have to find which Xcode version is good for your OSX (usually Xcode 6.2 works well on OSX 10.X, please verify the support matrix by running some searches). Once you know which Xcode version to install, download it from Apple <a href="https://developer.apple.com/download/">developer download center</a> and install it.</li>
 	<li>Install the Azure CLI

<span style="font-family: 'courier new','courier',monospace">npm install -g azure-cli</span></li>
 	<li>Check if the CLI is working by running some basic commands

<span style="font-family: 'courier new','courier',monospace">azure help
azure --version</span></li>
 	<li>Login to your Azure account (the following command is for interactive login using a browser window, there are other ways too)

<span style="font-family: 'courier new','courier',monospace">azure login</span></li>
 	<li>If you have multiple subscriptions, run this command to see all of them so that you can verify whether the CLI is using the correct one. The "Current" column of the output will be "true" for the subscription being currently used.

<span style="font-family: 'courier new','courier',monospace">azure account list</span></li>
 	<li>If you have multiple subscriptions, and if the above command shows that the CLI session is using the incorrect one, use the following command to set the correct one as default:

<span style="font-family: 'courier new','courier',monospace">azure account set &lt;&lt;<i><span style="font-family: 'times','times new roman',serif">name of the subscription you want to set as default from the "Name" column displayed in the output of the "azure account list" command</span></i>&gt;&gt;</span></li>
 	<li>Go to Azure ARM mode (if you do not know the differences between the two modes or deployment models supported by Azure - the older "classic" model and the newer "ARM" model, where ARM stands for "Azure Resource Manager", see <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-deployment-model">this</a>):

<span style="font-family: 'courier new','courier',monospace">azure config mode arm</span></li>
 	<li>An easy way to create a Docker host on Azure is to just execute a pre-existing JSON template that Microsoft template developers have contributed to github. You can find a lot of templates in <a href="https://github.com/Azure/azure-quickstart-templates">this quickstart template repository</a>.

I picked one that says <a href="https://github.com/Azure/azure-quickstart-templates/tree/master/docker-simple-on-ubuntu">docker-simple-on-ubuntu</a>. The beauty of these templates is that you just run a CLI command with the template file's location on github and your infrastructure, whatever the template is written to deploy, will get created and deployed within a few minutes!

<span style="font-family: 'courier new','courier',monospace">azure group create --name file-upload-container-demo --location "West US" --template-uri https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/docker-simple-on-ubuntu/azuredeploy.json</span>

In the above command, I passed, as value for the --name parameter, "file-upload-container-demo". That creates an <a href="https://docs.microsoft.com/en-us/azure/virtual-machines/virtual-machines-windows-infrastructure-resource-groups-guidelines#resource-groups">Azure Resource Group</a> by that name. The benefit of creating your entire infrastructure within a new <i>Resource Group </i>is that you can, later, simply delete the Resource Group, and all the VM-s, VNET-s, Load Balancers, IP Addresses, Network Security Groups, NIC-s, etc. you had deployed withing that Resource Group will all be removed in one go - so cleaning up is easy. You may be thinking... why am I going to deploy all these things to run a simple Docker host?

The answer to that is, you need some of these basic infrastructure components to have a usable Virtual Machine. For example, you can spin up a VM, but unless you have a public IP address, you cannot access it easily. Unless you have a NSG (Network Security Group), you cannot selectively open ports (like 22 for SSH or 80 for web). When you create a VM from the Azure portal, these peripheral infrastructure components <i>are automatically created for you</i>. But when you are creating something from a command line or code, you will need to create all of these. Luckily, that is where the template helps. The template here has instruction to create all of these, and just one CLI command to execute the ARM Template is enough to stand up the whole gamut of components needed to start using your Docker host quickly!

One possible down-side of using this pre-written template is that you may not want your Docker Host to be of size standard F1. But that is what you will get, as the template specifies that. You may want your storage disks to be either HDD or SSD, but you will get whatever the template specifies. In short, if you need to customize your deployment like what you want, you will have to write your own template. Some template authors go the extra mile to make these choices configurable. In that case, you will have to pass these as parameters for the template.</li>
 	<li>The above command is interactive, and it will ask you a few things. Once it succeeds, your Docker host is ready. It will interactively ask you some questions like the DNS name for your VM, use a unique name for the region you are using in the command.

In my case, I specified the DNS Name "uploadnshare0123" and user name "user_name", so trying to access the VM through the DNS name associated with it via SSH from my Mac is done by a simple ssh command

<span style="font-family: 'courier new','courier',monospace">ssh user_name@uploadnshare0123.westus.cloudapp.azure.com</span></li>
 	<li>Once you are in, start running docker commands

<span style="font-family: 'courier new','courier',monospace">sudo docker ps</span></li>
 	<li>If you are wondering how exactly Docker is running on the machine without you installing it, it is all magic done inside the JSON ARM template. Read it <a href="https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/docker-simple-on-ubuntu/azuredeploy.json">here</a> to understand it in greater details. Good luck!</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>Scaling a LAMP app using Docker Containers - simple code and architectural discussion</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/scaling-docker-containers-code-architectural-discussion</link>
      <pubDate>Sat, 10 Dec 2016 15:40:09 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">http://blogs.msdn.microsoft.com/opensourcemsft/?p=175</guid>
      <description><![CDATA[As the journey to the cloud and containerization continues, and the quest to scale and leverage...]]></description>
      <content:encoded><![CDATA[<div class="prose">

As the journey to the cloud and containerization continues, and the quest to scale and leverage these technologies in production gains momentum, I wanted to share my perspectives on how to scale a simple LAMP-stack web app using containers.

The simple PHP code in this app lets you upload a file and share its link with someone else.

More than the code-base itself (which has some minor points of interest), I want to draw your attention to the following architectural discussion (all in README):

<a href="https://github.com/kbxkb/file-upload-link-share-simple">https://github.com/kbxkb/file-upload-link-share-simple</a>

Enjoy, and please provide feedback and suggestions!

Thanks!

</div>]]></content:encoded>
    </item>
    <item>
      <title>Ansible on Red Hat on Microsoft Azure: Deploy Apache Web App with Mysql back-end</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/ansible-redhat-microsoft-azure</link>
      <pubDate>Fri, 27 May 2016 18:25:24 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">http://blogs.msdn.microsoft.com/opensourcemsft/?p=155</guid>
      <description><![CDATA[Introduction
After the Microsoft - Red Hat alliance, engineering teams from both sides are working...]]></description>
      <content:encoded><![CDATA[<h1>Introduction</h1>
<h4>After the Microsoft - Red Hat alliance, engineering teams from both sides are working on the integration aspects. There is a lot to integrate - OpenShift, CloudForms, Ansible, etc. Speaking of Ansible, I recently had to set it up on an Azure Red Hat VM for a demo. Like any developer-at-heart would, I was determined to make Ansible work from source (as opposed to a downloaded binary package). To my surprise, the packages needed for the Ansible master to run on an Azure Red Hat VM were mostly missing! I went through the usual package-hunting process and finally got it going. Thought I would put a blog out to help others in my shoes.</h4>
&nbsp;
<h1>My take on Ansible</h1>
Ansible feels very simple for the power it gives you. I have used Chef and Puppet - in fact Azure Linux VM-s can be provisioned with Chef and Puppet Extensions enabled. However, what I find a little messy about Chef and Puppet is their dependency on Ruby. Ruby, in any shape and form, is painful to install and keep up to date. Ansible, on the other hand, has nothing to do with Ruby. I was blown away at the power of Ansible's inventory files. Such simplicity! The concept of supporting groups, variables, roles, wild cards, even regular expressions is great. It is simple and intuitive. Ansible is also completely agent-less - you do not install anything on the managed nodes. That makes it extremely lightweight. It relies on inbuilt SSH security - which is well-understood and reliable. I like Ansible a lot!

Of course, I should also point out the potential cons. Ansible is for geeks, because it needs scripting, writing playbooks - so for DevOps personnel who would normally shy away from a little bit of coding, it may demand some learning curve. One good question I faced from an Azure customer was: As Ansible does not install an agent on the managed nodes, does that mean Ansible cannot detect drift of state on the nodes automatically and fix it like Chef does?

That is a good question because it betrays a not-so-uncommon lack of understanding of how Chef works. Chef gives you the illusion of instantly detecting the slightest drift in state because the agent is running every so many seconds or minutes (whatever you have configured it to be) on the managed node. With Ansible, there is nothing stopping you from running your playbooks every few seconds or minutes either (say, by using a cronjob on the master). It will have the same effect. However, with Ansible, you need to be careful that you do not do anything stupid in the playbooks if you use it that way - for example, if you have an online web server serving traffic, and the playbook runs every few seconds - you need to be careful to not step on the live operation. It is definitely doable, but needs conscious deliberation. For example, if you specify the existence of the package "apache" as the desired state, Ansible might keep on resetting your log files and you may lose log files for later processing :)

&nbsp;
<h1>Get set, ready, go</h1>
Let us set up a web server and a database server on Azure Red Hat using Ansible. We will need to spin up three Azure Red Hat VM-s: one will be controller (aka master), and the other two will be the managed nodes - one of them the web server running apache, and the other a database server running mysql (mariadb).

I will share how I did this.

&nbsp;
<h3>Step 1. Spin your Linux Infrastructure up</h3>
I spun up three RHEL 7.2 instances ("ansiblecontroller", "apacheweb" and "mysqldb"). I was careful to use SSH Keys for them - not just passwords. Ansible is a lot easier if you use SSH Keys. I used the same user id and SSH Key Pair for all three nodes - you should do that while trying Ansible for the first time, it will help keep the focus on functionality rather than configuration. Best way to spin the VM-s up is using the Azure portal, as it automatically adds 1 Public IP Address (for ease of access) and 1 Network Security Group aka NSG (for selectively opening ports) to each VM - we will need these constructs to demo the results of our web deployment by accessing the web server from a browser.

I went ahead and added an inbound security rule to the NSG associated with "apacheweb" that let me access port 80 from the browser.

Finally, after the VM-s are spun up, and you are testing them out one by one SSH-ing into them, quickly do this: copy your private key into the controller VM. Place it in ~/.ssh directory. Name it <strong>id_rsa</strong>. I know, we can make it work even if we call something else. I just wanted to stick to norms because I was playing with Ansible for the first time on Azure, and I did not want to run against edge cases!

&nbsp;
<h3>Step 2. Install and run Ansible on the controller</h3>
When I ran the following commands in that order, it worked (this is the result of some research, trial and error, so I am sure that this is not the shortest nor the most optimized sequence of commands, but they work):
<ol>
	<li>
<pre>sudo yum install git</pre>
</li>
	<li>
<pre>git clone git://github.com/ansible/ansible.git --recursive</pre>
</li>
	<li>
<pre>cd ./ansible</pre>
</li>
	<li>
<pre>source ./hacking/env-setup</pre>
</li>
	<li>
<pre>sudo easy_install pip</pre>
</li>
	<li>
<pre>sudo yum install python-devel</pre>
</li>
	<li>
<pre>sudo yum groupinstall "Development Tools"</pre>
</li>
	<li>
<pre>sudo yum install libffi-devel</pre>
</li>
	<li>
<pre>sudo yum install openssl-devel</pre>
</li>
	<li>
<pre>.sudo pip install paramiko PyYAML Jinja2 httplib2 six</pre>
</li>
	<li>
<pre>sudo pip install pycrypto</pre>
</li>
</ol>
&nbsp;

After the above commands complete successfully, ansible will run: <strong>ansible all -m ping</strong>

It will of course not find any managed host to ping, as we have not added or configured any.

Even if ansible runs fine after the above commands, it does need the command #4 above ("source ./hacking/env-setup") to be run every time you log in. Therefore, go ahead and append the following lines to ~/.bashrc file:
<pre> pushd ansible
 source ./hacking/env-setup
 popd

</pre>
<h3>Step 3. Create your own custom inventory file and see it work</h3>
Now, we need to tell Ansible about the managed nodes. We do that via the inventory file called "hosts". We can put the hosts file in several places, there exists an order in which Ansible looks for it. I chose to place it in /etc/ansible directory (just my preference - in fact, /etc/ansible happens to be the last place Ansible looks for it, so for example, if you put another hosts file in the same directory as the playbook, that will take precedence over /etc/ansible/hosts).

So I created the directory /etc/ansible: <strong>sudo mkdir -p /etc/ansible</strong>

I then created a file called "hosts" in there, with the following contents (change the private IP addresses of the webserver and dbserver to whatever they are in your case, look them up from the Azure portal):
<pre>[webservers]
 apacheweb ansible_host=10.6.0.5</pre>
<pre>[dbservers]
 mysqldb ansible_host=10.6.0.6</pre>
&nbsp;

I will not go into the details of all possible ways to create entries in an inventory file, but it is very powerful and simple. In this example, we have used the keyword "ansible_host" and the concept of groups by having two groups: [webservers] and [dbservers].

After this, I configured SSH for ease:

ssh-agent bash; ssh-add ~/.ssh/id_rsa

And now, a ping should show both the managed nodes: <strong>ansible all -m ping</strong>

(The first two times you try to ping, RHEL will ask you whether to trust the connection (once per managed node), so the output of [<strong>ansible all -m ping</strong>] will not be as expected. Go ahead and say yes to the prompts, and it should work fine after that)

&nbsp;
<h3>Step 4. Deploy Web Server and Database Server and see it all work</h3>
At this stage, you have succeeded in running Ansible on the controller. The other two VM-s are running, but they are doing nothing yet. The controller can see them. Hence, you can run  a playbook that deploys some software on them. I wanted to demo this part quickly, so I started looking for the right playbook on the internet. I came across this excellent collection:

https://github.com/ansible/ansible-examples

Clone it and cd into lamp_simple_rhel7. We will use this playbook.

For me, using this "simple" playbook was not so simple, as it turned out. I had to make certain changes to the downloaded (cloned) files for them to work on Azure. Here is a list of changes I did:
<ol>
	<li>First of all, the playbook "lamp_simple_rhel7" came with its own hosts file in the lamp_simple_rhel7 directory. I renamed it to something else, as I was trying to use /etc/ansible/hosts</li>
	<li>I commented out the 3 lines, each saying "remote_user=root" from site.yml, the playbook that I was trying to run. I used a leading '#' to comment them out</li>
	<li>For each *.yml file in lamp_simple_rhel7 directory and all subdirectories (<strong>except site.yml</strong>), I added "sudo: yes" to every task and include.
To do this, first cd into lamp_simple_rhel7 directory and run a find command: find . -name "*.yml"
I found 7 files except site.yml. Ignore site.yml. In each of these 7 files, I added a line "sudo: yes" after proper indentation to each task/ include. As an example, I will show the final form of /roles/web/tasks/copy_code.yml file:</li>
</ol>
<pre style="padding-left: 60px">- name: Copy the code from repository
  git: repo={{ repository }} dest=/var/www/html/
  sudo: yes</pre>
<pre style="padding-left: 60px">- name: Creates the index.php file
  template: src=index.php.j2 dest=/var/www/html/index.php
  sudo: yes</pre>
&nbsp;

Doing the above changes to the downloaded code was <em>not enough</em> though. I soon realized that I had to make certain changes to the managed nodes as well. Looks like the yum repo rh-cloud tries to reach out Red Hat servers over SSL, and this gets blocked, may be because firewalls on these Red Hat servers might be blocking SSL traffic from Azure. Because of this, I got this error when I tried to run the playbook:
<pre>Failure talking to yum: Could not contact any CDS load balancers</pre>
&nbsp;

To fix this, we have to turn off communication over SSL for this repo. This is not recommended for production servers, but I am sure this is one of the things Microsoft and RedHat engineers are jointly trying to resolve so that they can make Ansible more Azure-friendly.

I SSH-ed into each of the managed nodes (apacheweb and mysqldb) and did the following to each, one by one:
I edited <strong>/etc/yum.repos.d/rh-cloud.repo</strong>, changed all instances of "sslverify=1" to "sslverify=0", and saved (If you use vi, a simple search and replace command is all this takes)

&nbsp;

After I did all the above course-corrects, I was finally ready to run the playbook without errors:

<strong>ansible-playbook site.yml</strong>

It should succeed!

&nbsp;
<h3>Step 5. Verify installation</h3>
Go to a browser and type in http://&lt;&gt;/index.php, where replace the &lt;&gt; with the public IP address of the web managed node. See the output, which should contain the list of databases in the MariaDB instance! Thus, we have deployed a two-tier application on Azure using Ansible!

&nbsp;
<h1>Conclusion</h1>
I hope you found this useful. As the Microsoft - Red Hat integration proceeds further, this blog may get out-of-date, as many of the workarounds may not be needed any more! However, knowing what it took at the early stages sometimes can help! Please leave a comment or feedback to let me know if you tried, and what you found! Thanks!]]></content:encoded>
    </item>
    <item>
      <title>Thoughts on Azure Stack and Multi-Cloud Strategy</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/thoughts-on-azure-stack-and-multi-cloud-strategy</link>
      <pubDate>Mon, 15 Feb 2016 14:17:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2016/02/15/thoughts-on-azure-stack-and-multi-cloud-strategy/</guid>
      <description><![CDATA[&nbsp;
What is Azure Stack? Is it truly Azure-In-A-Box? Why should one use it?
You know that it...]]></description>
      <content:encoded><![CDATA[&nbsp;
<h1>What is Azure Stack? Is it truly Azure-In-A-Box? Why should one use it?</h1>
You know that it makes financial sense to move to the cloud. Cloud, if used correctly, saves you money. However, you do not feel ready to take the plunge yet. There may be several reasons, including the perception of security, compliance to regulations, lack of consensus or the overwhelming need to ship features first to stay relevant.

However, the latest feature addition or the new component requires massive warm storage. Your developers will store them somewhere, write code to retrieve and save the objects. Do not let the moment get bigger than the future. Build your application around Azure Stack. In two years, when you are finally moving to Azure instead of writing another big check for hardware refresh, you will have one less part of your whole stack to migrate. You will be partially cloud-ready!

Azure Stack is your own private cloud sitting right inside your data-center. Your data is sitting on a bunch of exclusive dedicated servers that you procured. However, your application interacts with it via the same REST API-s, SDK-s, authentication mechanism and logistics as if it were interacting with Azure! Your infrastructure will be deployed using the same scripts and templates! This consistency makes moving to Azure a breeze down the line if you ever have to.

Right now, the Azure Stack preview is only available as a single server install. It is not anywhere close to the parity with the real Azure as it will be by the end of 2016. You will have PaaS components running on Azure Stack. You will be able to access the whole bunch of standard gallery images - not just Windows Server 2016 and Ubuntu. You will be able to create a cluster of Azure Stack servers in order to scale out your VM infrastructure.

Azure Stack is Microsoft's way of putting cloud within everyone's reach - treating the cloud as a model, not as a place.

I am confident in the continuous innovation cycle that the Azure Stack team has signed up for. In their <a href="https://azure.microsoft.com/en-us/blog/announcing-early-preview-of-azure-paas-services-and-devops-tools-for-azure-stack/">first installment</a>, they delivered:
<ol>
 	<li>Web Apps</li>
 	<li>MySQL and SQL resource providers to act as back-ends for the Web Apps</li>
 	<li>Updated X-Plat CLI and Powershell support for Native SDK</li>
 	<li>Productivity Boosters like Native Visual Studio support (enabling things like CI/CD right from inside Visual Studio)</li>
</ol>
I would love to come back and discuss about the differences and similarities between Azure Stack and OpenStack in details! OpenStack is very promising, but doing OpenStack at enterprise scale is not easy. It is signing up for too much - highly skilled IT Operations folks and need to refresh hardware every six to nine months are cost centers you should be aware of with OpenStack. However, it can make sense for medium sized operations spread across a single or couple of regions. OpenStack is a great tool for managing your own datacenter like a cloud, as long as you would not need to handle that deadly burst of traffic where you wished there was a public cloud to fall back on. It can still be part of your IT strategy - as it has some remarkable positives!
<h1>What About "Multi-Cloud" Strategy?</h1>
I also want to address something I have heard from several customers in their initial stages of cloud consideration - the fact that they do not want to "get locked in", the perceived strategy of spreading the eggs out in different baskets, the so-called "multi-cloud strategy". I want to address this concern here because the inevitable question that would rise in one's mind when deciding whether to go for Azure Stack is: will this lock me into Azure? Can I ever go back to AWS or Rackspace if need be?

I have almost two decades of development, design and architecture experience in several domains. I have created massive globally distributed systems - right from the envisioning to implementation and support. What I can guarantee you is that truly re-usable code and software is rare, and it takes a lot of farsightedness and painstaking design to make it happen. It is possible, but not many get it right.

Imagine for a moment that you indeed want to implement a cloud-agnostic strategy. All your code must then be designed bottom-up as extremely modular and each module boasting a generic interface where you can plug in cloud-specific libraries. Conceptually, you are building an electronic equipment that can be plugged into any wall socket around the world, so the inner mechanism should be completely abstracted from the power supply - you just delegate power access to one small detachable subroutine that deals with the myriad voltage and pin shape/size variations.

Does that sound easy to grasp? If so, it is actually oversimplification and not a true analogy for cloud-agnostic software.

Even if you painstakingly build abstracted multi-layered software for your functionality, monitoring, metrics, scalability, fault tolerance, HA, deployment, installation and DR - all of which can now run on both Azure and AWS (and can be a support and maintenance nightmare), you are now stuck with IaaS - missing out on the true revolution in public cloud - PaaS! If you have selected a CPM (Cloud Platform Manager) like Red Hat CloudForms, most CPM-s are only focused on keeping up with the IaaS features - compatibility with managed offerings are still quite a distance away! You may need to re-architect to use PaaS solutions to stay relevant in the market, as your competitors start to slash costs by moving to PaaS. They are churning out more features on a faster Agile sprinting cycle than your team can, because your team is bottle-necked by IT patching OS-s.

It may almost sound unfair that the major public cloud players are developing their own PaaS solutions with no commonality or uniformity in application consumption patterns. The truth, however, is that it does not matter. Because the level of effort needed to consume and build on top of PaaS services is orders-of-magnitude less than continuing to control your own IaaS environment. You may think that building cloud-agnostic software is a good strategy, but the LOE and TCO to do so are several times higher than writing the same thing for PaaS on Vendor 1, and then throw it away (or keep it) and re-write it for PaaS on Vendor 2!

Thus, a true bytes-duplicated multi-cloud strategy is very tough to achieve. It sounds great, it sounds like traditional wisdom to not put all your eggs in one basket. However, the cloud has not yet evolved to support such a strategy easily - or at least without significant pain!

And with either Microsoft or Amazon Web Services, one thing is certain. Capabilities will only grow, prices are not going up drastically. These two giants are locked in an epic battle, and customers will benefit from that!

It may make sense to have different parts of your operation on different clouds, but that is a discussion for another day!]]></content:encoded>
    </item>
    <item>
      <title>Open Source on Azure - What we achieved together</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/open-source-on-azure-what-we-achieved-together</link>
      <pubDate>Tue, 02 Feb 2016 07:17:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2016/02/02/open-source-on-azure-what-we-achieved-together/</guid>
      <description><![CDATA[As we transitioned to 2016, we can look back at the closing months of 2015 with pride and happiness...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium; font-family: helvetica;">As we transitioned to 2016, we can look back at the closing months of 2015 with pride and happiness at having accomplished so much in so little time. A quick recap of the most major recent milestones won't hurt!</span></p>
<p>&nbsp;</p>
<p><span style="font-size: large; color: #993300;"><strong><span style="font-family: helvetica;">Partnership with Red Hat</span></strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">We are trying to work hard to make the RHEL Pay-As-You-Go images </span><span style="font-size: medium; font-family: helvetica;">available on Azure as standard supported Gallery images, as of the writing of this blog post. The developer and partner community should not need to wait much longer for this to happen! However, if someone wants to bring their own custom RHEL image, upload it as a VHD to Azure Blob Storage and provision Virtual Machines from the same, they can do so even today. That's called the "BYOL" model - Bring your own license.</span></p>
<p><span style="font-family: helvetica; font-size: medium;">The terms of the much-anticipated partners</span><span style="font-size: medium; font-family: helvetica;">hip included, other than the RHEL OS, the following Red Hat solutions to be made available on the Azure Platform: JBoss Middleware Suite, GlusterFS, Openshift platform as well as CloudForms. It included support for Hybrid environments - partially on the cloud and partially on-premises or 3rd party hosted sites. It also assured us that RHEL will be the primary OS for .NET Core on Linux.</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium; font-family: helvetica;"><span style="color: #993300;"><strong><span style="font-size: large;">Containerization and Docker - Windows integration and Azure Container Service</span></strong></span><br /></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">Microsoft's efforts to integrate Docker Engine and Windows OS has made great progress! Though it is Work in Progress, you can now, as of the writing of this blog post, go to the Azure Portal (and remember that the "new" portal is now the "current" portal), spin up a VM from the image "Windows Server 2016 Core with Containers Tech Preview 4", and start creating Windows Containers on it! The step by step preview guide for creating Windows Containers and playing around with them can be found here:&nbsp;https://msdn.microsoft.com/en-us/virtualization/windowscontainers/containers_welcome.</span></p>
<p><span style="font-family: helvetica; font-size: medium;">This incredible speed is also evident in the work done on the Azure Container Service front. After we announced it at AzureCon in September 2015, we opened Preview by self-nomination in December. The Azure Container Service is a Compute Resource Provider - it creates a cluster of VM-s acting as container hosts together with master VM-s that orchestrate deployment and execution of containers, providing HA, Fault Tolerance and Utilization Density.</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium; font-family: helvetica;"><span style="font-size: large; color: #993300;"><strong>Availability of Debian as an Azure-endorsed OS</strong></span><br /></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">Debian (7 and 8) are now fully endorsed on Azure, thanks to our partnership with Credactiv! This piece of news was welcomed by the cloud community:&nbsp;http://www.zdnet.com/article/debian-gnulinux-now-supported-on-microsofts-azure/.</span></p>
<p><span style="font-family: helvetica; font-size: medium;">Though Debian is widely considered a 'developer-friendly' Operating System (as opposed to Ubuntu's perceived ease of use), recent changes in Debian are clearly attempting to erase that gap. In my opinion, the structure that Canonical has provided to Ubuntu's feature releases, software and hardware compatibility, usability etc. have resulted in a more streamlined user experience than the completely open source community developing Debian. However, Debian remains the Rock of Gibraltar when it comes to stability, and is also known to have outperformed Ubuntu, though not by much, in performance tests. They cater to slightly different audiences. Availability of both on the Azure Platform, therefore, is critical to opening up Azure to the widest possible spectrum of Linux users!</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium; font-family: helvetica;"><span style="font-size: large; color: #993300;"><strong>General Availability of HDInsight: Run Hadoop clusters <span style="font-family: helvetica;">on Linux on Azure</span></strong></span><br /></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">The ability to create Hadoop, Hbase, STORM and SPARK clusters on a LINUX based collection of VM-s (in addition to the Windows option) &ndash; which is fully managed, monitored and supported by us with 99.9% SLA &ndash; was greeted with enthusiasm by entire OSS and Big Data Community in September of last year! It is amazing that Microsoft runs a major PAAS service entirely on Linux!</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium; font-family: helvetica;"><span style="font-size: large; color: #993300;"><strong>Node.js support for Azure Mobile Apps Backend</strong></span><br /></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">We released Node SDK for Mobile Apps under Azure App Service early September 2015. Complete with push notifications, mobile auth, offline sync and other rich features, this addition to Azure App Service was an instant hit with OSS Mobile Developers, which is a significant chunk of the IT community. We followed up with a beta update recently a few days back, adding even more features!</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium; font-family: helvetica;"><span style="font-size: large; color: #993300;"><strong>Not directly related to Azure, but our recent open-sourcing of CNTK definitely deserves mention here</strong></span><br /></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: medium;">Microsoft&rsquo;s brain is now available for anyone to use in their apps! We have open-sourced the artificial intelligence framework we use to power speech recognition in our Cortana Digital Assistant and Skype Translate applications. The framework, called, CNTK (Computational Network Toolkit), is based on a branch of Artificial intelligence called Deep Learning, which seeks to help machines do things like recognize photos and videos or understanding human speech by mimicking the structure and functions of the human brain.<br /><br />CNTK's advantage over Google TensorFlow (quoted from http://www.wired.com/2016/01/microsoft-tries-to-one-up-google-in-the-open-source-ai-race/): CNTK has a big advantage over TensorFlow for people outside of academia: it can take advantage of the power of many servers at the same time. That&rsquo;s important because it&rsquo;s rare that a single computer is powerful enough to handle a real-world artificial intelligence application, such as speech recognition on an app used by millions of people. Internally, Google likely uses TensorFlow on thousands of servers at a time. But the version Google released to the public, Huang says, can&rsquo;t be used in this way. In fact, few deep learning frameworks other than CNTK support running across multiple servers right out of the box, though it&rsquo;s possible to do with other open source software such as Torch, which is used by Facebook and Google.<br /><br />The code can be found on github: https://github.com/Microsoft/CNTK<br /></span></p>
<p>&nbsp;</p>
<p>As we continue to drive the momentum of innovation, openness and empowerment even harder, you can expect bigger and better things from Microsoft in the future! I would like to thank you for the support!</p>
<p><span style="font-family: helvetica; font-size: medium;"><br /></span></p>]]></content:encoded>
    </item>
    <item>
      <title>Set up and use Docker Swarm on Azure</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/set-up-and-use-docker-swarm-on-azure</link>
      <pubDate>Sun, 06 Dec 2015 20:55:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2015/12/06/set-up-and-use-docker-swarm-on-azure/</guid>
      <description><![CDATA[As Docker dominates as the hot containerization topic, the focus is starting to shift from just...]]></description>
      <content:encoded><![CDATA[<p>As Docker dominates as the hot containerization topic, the focus is starting to shift from just containers to <strong><em>container orchestration</em></strong>. <strong>SWARM</strong> is the first step towards this.</p>
<p>There are several ways to set up a SWARM cluster of Docker hosts on Azure. The documentation out there is out-of-date or incomplete or simply does not work. I wanted to share one way that seemed easy to me.</p>
<p>&nbsp;</p>
<p>Here is a diagrammatic representation of the SWARM cluster we will create on Azure [ <em>1 Swarm Manager (Ubuntu), 2 Swarm Nodes (Ubuntu) in a VNET,</em> <em>being controlled from a Docker Client of any sort (I use my Windows laptop</em>) ]:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8802.Swarm_Cluster.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8802.Swarm_5F00_Cluster.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8802.Swarm_Cluster.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8802.Swarm_5F00_Cluster.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>(In addition, I used another Linux VM to issue Azure CLI commands to actually create the set-up. Instead, you could use the same machine for the Docker client and CLI client)</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>Steps involved:</strong></p>
<p>1. Create the SWARM Master using Azure CLI, then configure it:</p>
<p style="padding-left: 30px;">a. Pre-requisite: Install Azure CLI. Steps for an Azure Ubuntu VM are given below:</p>
<p style="padding-left: 60px;">i. <strong>sudo apt-get update</strong></p>
<p style="padding-left: 60px;">ii. <strong>sudo apt-get install nodejs-legacy</strong></p>
<p style="padding-left: 60px;">iii. <strong>sudo apt-get install npm</strong></p>
<p style="padding-left: 60px;">iv. <strong>sudo npm install -g azure-cli</strong></p>
<p style="padding-left: 60px;">v. (Log yourself in) <strong>azure login</strong></p>
<p style="padding-left: 30px;">b. Change mode to ARM:</p>
<p style="padding-left: 60px;">i. <strong>azure config mode arm</strong></p>
<p style="padding-left: 30px;">c. Create a separate resource group which will contain all the resources for this set-up</p>
<p style="padding-left: 60px;">i. <strong>azure group create -n "cliSouthCentralSwarmRG" -l "South Central US"</strong></p>
<p style="padding-left: 30px;">d. Create the SWARM master VM with its own NIC, Public IP Address and a new storage account, also creating the VNET and subnet in the process</p>
<p style="padding-left: 60px;">i. <strong>azure</strong> <strong> </strong> <strong>vm docker create --resource-group cliSouthCentralSwarmRG --name cli-swarm-master --location southcentralus</strong> <strong> </strong> <strong>--os-type</strong> <strong> </strong> <strong>linux</strong> <strong> </strong> <strong>--nic-name clitestnic --public-ip-name clitestpip --vnet-name cliswarmvnet --vnet-subnet-name</strong> <strong> </strong> <strong>cliswarmsubnet --storage-account-name clidockerswarmstorage --image-urn canonical:</strong> <strong>UbuntuServer</strong> <strong>:14.04.3-</strong> <strong>LTS:latest</strong> <strong> </strong> <strong>--admin-username Azure123 --admin-password 'Azure!23'</strong> <strong></strong></p>
<p style="padding-left: 60px;">ii. (When prompted for VNET address prefix, use something that works for you like 10.10.0/16, for subnet address prefix, you can use 10.10.1.0/24 in that case. When prompted for Public IP domain name, use something unique, e.g., &ldquo;clidockerswarm&rdquo; &ndash; I have already taken that one for South Central US though)</p>
<p style="padding-left: 60px;">iii. Check the portal for the FQDN of the Public IP you just created, use that and port 22 to SSH into the box (you can use Putty)</p>
<p style="padding-left: 30px;">e. Disable TLS on the Swarm Master &ndash; for demo purposes, we will disable TLS, as using TLS for Swarm cluster is slightly more work than enabling it for just one server, and we can dedicate some time later on if we are working on a real production or dev/QA workload, adding TLS back</p>
<p style="padding-left: 60px;">i. Once logged into the Swarm Master host on SSH, enter a sudo shell (&ldquo;<strong>sudo su</strong>&rdquo;) as the following operations will need root access</p>
<p style="padding-left: 60px;">ii. Edit /etc/default/docker (use vi or some other editor) and remove the parameters tlsverify, tlscacert, tlscert and tlskey. The shortened line should look like this: <strong>DOCKER_OPTS="-H=unix:// -H=0.0.0.0:2376"</strong></p>
<p style="padding-left: 60px;">iii. <strong>service docker restart</strong></p>
<p style="padding-left: 60px;">iv. (To verify that your changes have taken effect) <strong>ps aux | grep docker</strong></p>
<p style="padding-left: 30px;">f. Connect to the SWARM master host from your docker client. If you are not sure how to set up a docker client on your windows laptop, follow the first 2 sub-steps in &ldquo;Step 2: Set up your Docker client on your Windows desktop/ laptop and connect to the server&rdquo; of my blog <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/09/26/set-up-docker-on-ubuntu-on-azure-connect-to-nginx-web-server-from-windows.aspx">here</a> . There is no need to follow the sub-steps beyond the first two as we will not be using TLS. On your WINDOWS laptop command prompt/ Cygwin terminal running on WINDOWS laptop:</p>
<p style="padding-left: 60px;">i. Make sure that you have no user or user/environment variables DOCKER_HOST or DOCKER_TLS_VERIFY or DOCKER_CERT_PATH. If you have set them previously to connect to another docker server, you can do the following: (a) if you are running Cygwin, temporarily disable these for the current session by running: unset DOCKER_HOST; unset DOCKER_TLS_VERIFY; unset DOCKER_CERT_PATH (b) If you are running on command prompt, these will turn the variables off permanently: setx DOCKER_HOST &ldquo;&rdquo;; setx DOCKER_TLS_VERIFY &ldquo;&rdquo;; setx DOCKER_CERT_PATH &ldquo;&rdquo;</p>
<p style="padding-left: 60px;">ii. <strong>docker -H tcp://{domain name of your docker VM swarm master's Public IP Address}:2376 {some docker command}</strong> <br /> Example: <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2376 ps -a</strong></p>
<p>2. Create the two SWARM nodes using Azure CLI and configure them:</p>
<p style="padding-left: 30px;">a. Azure CLI command to create the 2 VM-s &ndash; basically the same command as for creating the swarm master, but with new values for (a) --name (b) --nic-name (c) --public-ip-name, but with existing values of vnet-name, vnet-subnet-name and storage-account-name. Which means that we are, with each command, creating a new VM with a new NIC and a new Public IP Address but we are adding it to the same vnet/subnet and using the same storage account. When prompted, use some unique name for Public IP domain name for each node (like &ldquo;clidockerswarmnodeone&rdquo;, &ldquo;clidockerswarmnodetwo&rdquo;):</p>
<p style="padding-left: 60px;">i. <strong> azure vm docker create --resource-group cliSouthCentralSwarmRG --name cli-node-1 --location southcentralus --os-type linux --nic-name clitestnicnodeone --public-ip-name clitestpipnodeone --vnet-name cliswarmvnet --vnet-subnet-name cliswarmsubnet --storage-account-name clidockerswarmstorage --image-urn canonical:UbuntuServer:14.04.3-LTS:latest --admin-username Azure123 --admin-password 'Azure!23' </strong></p>
<p style="padding-left: 60px;">ii. <strong> azure vm docker create --resource-group cliSouthCentralSwarmRG --name cli-node-2 --location southcentralus --os-type linux --nic-name clitestnicnodetwo --public-ip-name clitestpipnodetwo --vnet-name cliswarmvnet --vnet-subnet-name cliswarmsubnet --storage-account-name clidockerswarmstorage --image-urn canonical:UbuntuServer:14.04.3-LTS:latest --admin-username Azure123 --admin-password 'Azure!23' </strong></p>
<p style="padding-left: 30px;">b. Like you did with the SWARM Master host, disable TLS on each and connect to each node from your docker client repeating the steps 1(e) and 1(f) for each of the nodes, with ONE IMPORTANT DIFFERENCE. When you edit /etc/default/docker on the nodes, ALSO CHANGE THE PORT NUMBER TO 2375 (instead of 2376). The DOCKER_OPTS line should look like this for the nodes: <strong>DOCKER_OPTS="-H=unix:// -H=0.0.0.0:2375"</strong>.</p>
<p>3. Create the swarm cluster and join the nodes to the cluster (all commands from now on should be executed on the docker client, using the -H parameter to point it to the correct docker server, be it the swarm master or one of the swarm nodes). NOTE: We are installing swarm using docker, which means swarm will run as a container:</p>
<p style="padding-left: 30px;">a. Pointing client towards swarm master (commands show the FQDN as created in the above examples, replace with your own FQDN):</p>
<p style="padding-left: 60px;">i. <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2376 pull swarm</strong></p>
<p style="padding-left: 60px;">ii. <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2376 run --rm swarm create</strong></p>
<p style="padding-left: 60px;">iii. Save the cluster id reported back by the last command, we will need it later on</p>
<p style="padding-left: 30px;">b. Pointing client towards swarm node one (commands show the FQDN as created in the above examples, replace with your own FQDN):</p>
<p style="padding-left: 60px;">i. <strong>docker -H tcp://clidockerswarmnodeone.southcentralus.cloudapp.azure.com:2375 pull swarm</strong></p>
<p style="padding-left: 60px;">ii. In the following command, use the public ip address of node one for the value of addr parameter (get it from the portal) and use the cluster id saved in 3(a)(iii) above after token://</p>
<p style="padding-left: 60px;">iii. <strong> docker -H tcp://clidockerswarmnodeone.southcentralus.cloudapp.azure.com:2375 run -d swarm join --addr=40.84.184.174:2375 token://cb12d74b9b5c45deb054f92cf6578efe </strong></p>
<p style="padding-left: 60px;">iv. (to verify) <strong>docker -H tcp://clidockerswarmnodeone.southcentralus.cloudapp.azure.com:2375 ps -a</strong></p>
<p style="padding-left: 30px;">c. Pointing client towards swarm node two (commands show the FQDN as created in the above examples, replace with your own FQDN):</p>
<p style="padding-left: 60px;">i. <strong>docker -H tcp://clidockerswarmnodetwo.southcentralus.cloudapp.azure.com:2375 pull swarm</strong></p>
<p style="padding-left: 60px;">ii. In the following command, use the public ip address of node two for the value of addr parameter (get it from the portal) and use the cluster id saved in 3(a)(iii) above after token://</p>
<p style="padding-left: 60px;">iii. <strong> docker -H tcp://clidockerswarmnodetwo`.southcentralus.cloudapp.azure.com:2375 run -d swarm join --addr=40.84.190.103:2375 token://cb12d74b9b5c45deb054f92cf6578efe </strong></p>
<p style="padding-left: 60px;">iv. (to verify) <strong>docker -H tcp://clidockerswarmnodetwo.southcentralus.cloudapp.azure.com:2375 ps -a</strong></p>
<p style="padding-left: 30px;">d. Pointing client towards swarm master (commands show the FQDN as created in the above examples, replace with your own FQDN):</p>
<p style="padding-left: 60px;">i. In the following command, use the cluster id saved in 3(a)(iii) above after token:// and be careful with the port numbers, note that we are connecting the docker client to port 2376 where the docker daemon is running, but we are asking to start the swarm manager daemon to start up and listen on port 2375, and pass docker commands to port 2375 on the nodes:</p>
<p style="padding-left: 60px;">ii. <strong> docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2376 run -d -p 2375:2375 swarm manage token://cb12d74b9b5c45deb054f92cf6578efe </strong></p>
<p style="padding-left: 60px;">iii. Once the manager is up and running, our cluster is ready, and we should be able to list the nodes. There are 2 ways to list the nodes</p>
<p style="padding-left: 60px;">iv. (First way to list the nodes): <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2375 info</strong></p>
<p style="padding-left: 60px;">v. (Second way to list the nodes): <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2376 run --rm swarm list token://cb12d74b9b5c45deb054f92cf6578efe</strong></p>
<p style="padding-left: 30px;">e. It may happen that when you try to list the nodes, you do not see two of them, you only see one. That would be a bug whereby you joined one of the nodes too soon. Just join it back again (run 3b or 3c again depending on which node needs re-joining) and verify using the listing methods</p>
<p>4. Put SWARM to work &ndash; well what use of setting a SWARM cluster up unless you also use it for something. I will cover the basics of how you could use the cluster:</p>
<p style="padding-left: 30px;">a. From this point on, issue ALL docker commands (from your docker client) against the SWARM master port 2375 (where the SWARM manager daemon is running):</p>
<p style="padding-left: 60px;">i. First, verify that no containers are running on any node: <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2375 ps</strong></p>
<p style="padding-left: 60px;">ii. Then, run mysql on your cluster and see SWARM master pick one of the nodes automatically: <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2375 run -d -P --name db mysql</strong></p>
<p style="padding-left: 60px;">iii. Then, check which node it chose with the ps command again, it should show which node it chose in the &lsquo;names&rsquo; column. Also, note the container id</p>
<p style="padding-left: 60px;">iv. Then, stop the container: <strong>docker -H tcp://clidockerswarm.southcentralus.cloudapp.azure.com:2375 stop &lt;container id of mysql container&gt;</strong></p>
<p style="padding-left: 30px;">b. That was an example of SWARM selecting the node for you. However, SWARM provides several ways by which you can specify your preference of nodes. See the <a href="https://docs.docker.com/swarm/scheduler/filter/">filters topic</a> here</p>
<p style="padding-left: 30px;">c. Once you combine the filters with <a href="https://docs.docker.com/swarm/scheduler/strategy/">strategies</a>, you can start putting together the rules of how to design an end-to-end solution/application (e.g., an n-tier backend) with containers. I will write back, in another session, on the application design and architecture aspects of using docker, swarm, etc.</p>
<p>&nbsp;</p>
<p>Thanks</p>]]></content:encoded>
    </item>
    <item>
      <title>An often overlooked trick to get better disk performance from your Azure Linux VM</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/an-often-overlooked-trick-to-get-better-disk-performance-from-your-azure-linux-vm</link>
      <pubDate>Thu, 19 Nov 2015 14:42:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2015/11/19/an-often-overlooked-trick-to-get-better-disk-performance-from-your-azure-linux-vm/</guid>
      <description><![CDATA[This may sound obvious to many - my apologies to that section of my audience. However, as I engage...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">This may sound obvious to many - my apologies to that section of my audience. However, as I engage with more and more customers complaining about not getting good read/ write IO&nbsp;performance on Azure Linux VM-s, especially when using databases like Mongo/ MySQL or Cassandra/ CouchDB or HBase, I see a trend.</span></p>
<p><span style="font-size: medium;">Typically, the engineering group runs the initial tests on performance. They spin up an Azure Linux VM, install the database software on it, point a load testing client at it and run tests. As this is meant to be a quick go/no-go assessment, they do not bother to add additional data disks and&nbsp;<em><strong>move the data location from the OS disk to the data disk</strong></em>.</span></p>
<p><span style="font-size: medium;">The results, therefore, are misleading. When you install any of these databases using the standard package managers (apt-get or rpm), the data location is still on the OS disk (/usr/local or /etc or something like that).</span></p>
<p><span style="font-size: medium;">On an Azure VM, the OS Disk is not optimized for IO performance. Instead, it is optimized for faster boot times. That is why before running any initial performance tests, we should add at least one data disk and move the data location to the new additional disk. After all, that is the way production is going to look like - so the initial tests will mimic production in that sense.</span></p>
<p><span style="font-size: medium;">That alone will improve the IO performance by several times. If we&nbsp;want to get even more performance gain, we should add multiple data disks and stripe them in a RAID 0 array. See&nbsp;<a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/24/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-versus-raid-0-array-xfs.aspx" rel="nofollow" target="_blank">this</a>&nbsp;blog post.</span></p>
<p><span style="font-size: medium;">Build better things on Azure!</span></p>]]></content:encoded>
    </item>
    <item>
      <title>MySQL Cluster IaaS best practices for Azure - High Availability, Fault Tolerance, Scalability</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/mysql-cluster-iaas-best-practices-for-azure-high-availability-fault-tolerance-scalability</link>
      <pubDate>Wed, 04 Nov 2015 14:25:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2015/11/04/mysql-cluster-iaas-best-practices-for-azure-high-availability-fault-tolerance-scalability/</guid>
      <description><![CDATA[Introduction
MySQL Cluster, if used correctly,&nbsp;has proven to be&nbsp;one of the most fault...]]></description>
      <content:encoded><![CDATA[<h1><span style="font-size: large;"><span style="font-family: helvetica;">Introduction</span></span></h1>
<p><span style="font-size: small;"><span style="font-family: helvetica;">MySQL Cluster, if used correctly,&nbsp;has proven to be&nbsp;one of the most fault tolerant, scalable and real-time distributed Active/Active-capable enterprise data storage solutions.&nbsp;Web providers with tons of daily visits like Paypal and Zillow, as well as leading telecommunications and network equipment providers, including Alcatel-Lucent, AT&amp;T, BT, and Ericsson have successfully deployed MySQL Clusters. You can&nbsp;</span><span style="font-family: helvetica;">listen to Paypal Chief Architect talk about using MySQL cluster for Paypal fraud detection in <a href="http://medianetwork.oracle.com/video/player/1873920417001">this video </a> starting at the 24 minutes 20 seconds. Check out the Zillow case study <a href="https://www.mysql.com/why-mysql/case-studies/mysql-cs-zillow.html">here</a>. They use the MySQL Cluster Carrier Grade Edition ("CGE") which includes support and useful enterprise tools - but the MySQL Cluster Community edition is free to try out and play around with.<br /><br /></span></span></p>
<h1><span style="font-size: large;"><span style="font-family: helvetica;">Why another best practice guide?</span></span></h1>
<p><span style="font-size: small;"><span style="font-family: helvetica;">So why another best practices guideline for MySQL Cluster? Because when it comes to <span style="color: #339966;"><strong>deploying and getting the best out of MySQL on Azure as an IaaS solution</strong></span>, we have to keep certain things in mind that is not necessarily covered very well out there today. Oracle has a whitepaper that is intended to be on the topic of MySQL for cloud - it is called <a href="https://www.mysql.com/why-mysql/white-papers/a-guide-to-mysql-for-saas/">"A Guide to MySQL for SaaS"</a>. However, I found that it is more of a marketing material than being a technical guide. Also, it covers all MySQL offerings broadly, and none very deeply, including MySQL Cluster.<br /><br /></span></span></p>
<h1><span style="font-size: large;"><span style="font-family: helvetica;">Distinguishing MySQL Cluster from MySQL</span></span></h1>
<p><span style="font-size: small;"><span style="font-family: helvetica;">Which brings me to the distinction - an important one for this blog post - <a href="http://dev.mysql.com/doc/index-cluster.html">MySQL Cluster</a> is not the same as <a href="https://www.mysql.com/products/classic/">MySQL Database</a> (which, in short, is just "MySQL"). They do not follow the same release cycle and version number patterns. As of this blog post, the GA version of MySQL Cluster is 7.4, but the GA version of (simply) MySQL is 5.7. MySQL Cluster does not use the same engine as MySQL - it uses a different engine called "NDB Cluster". MySQL Cluster does not store the data co-located with the mysqld daemon, it uses separate data nodes. It is a very different beast in that sense. Of course, it is still the same in one sense, but the difference is important to note for this blog post, because we are going to explore <strong>MySQL Cluster on Azure</strong>. On the contrary, <a href="https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-optimize-mysql-perf/">this article</a> and <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/24/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-versus-raid-0-array-xfs.aspx">this blog post of mine</a> deals with certain best practices of using MySQL on Azure.<br /><br /></span></span></p>
<h1><span style="font-size: large;"><span style="font-family: helvetica;">PaaS versus IaaS MySQL Cluster for Azure</span></span></h1>
<p><span style="font-family: helvetica; font-size: small;"><a style="font-family: helvetica; font-size: small;" href="https://www.cleardb.com/store/azure">ClearDB</a><span> now provides PAAS MySQL Clusters on Azure as well. In fact, their offering seems very robust and technically a lot more attractive than managing your own instances of MySQL Clusters because of the </span><a style="font-family: helvetica; font-size: small;" href="https://azure.microsoft.com/en-us/blog/announcing-new-mysql-premium-tiers-from-cleardb/">recently announced</a><span> option of Premium Dedicated Clusters. I say that because personally, PaaS is always more attractive than IaaS, because you do not have to worry about maintaining/ monitoring/ baby-sitting/ upgrading your infrastructure, you do not have to worry about the up-time SLA or handle scaling your VM-s yourself. However, I am not sure of how ClearDB stacks up against Azure IaaS cost-wise. Though I have not done an accurate cost comparison analysis between these choices, it is clear to me that MySQL Cluster demands Azure VM-s of bigger sizes because of its memory needs. See Point 3 in the next section "What about Performance?". Therefore, none of the options promise to be cheap, but I am sure both of them are cheaper than having on-premises servers which tend to be severely under-utilized and almost always end up having a higher TCO because of man-hours spent in maintaining these servers, money spent behind refreshing hardware, etc.</span><br /><br /><span>This blog post is about IaaS - where you set up the MySQL Cluster yourself on Azure. I wrote another </span><a style="font-family: helvetica; font-size: small;" href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/26/set-up-a-mysql-iaas-ndb-cluster-with-four-nodes-on-azure-linux.aspx">blog post</a><span> about the actual process of creating a MySQL Cluster on Azure. I will not cover the same here again. This one will be about architectural best practices regarding high availability, fault tolerance and geo-replication.<br /></span><br /></span></p>
<h1><span style="font-family: helvetica; font-size: large;">What about Performance?</span><span style="font-size: 2em;">&nbsp;</span></h1>
<p><span style="font-family: helvetica; font-size: small;"><span>Today, we will cover High Availability, Fault Tolerance, Scalability and some thoughts on Geo Replication related to MySQL Cluster on Azure. We will leave the performance for another day. Why? A few thoughts:</span><br /></span></p>
<ol>
<li><span style="font-family: helvetica; font-size: small;">There are a lot of articles on the internet that focuses on performance optimization, fine tuning and cluster configuration for optimum MySQL cluster performance. Most of these techniques are specific to MySQL Cluster and will work regardless of where it is running &ndash; on-premises or cloud, AWS or Azure. However, in my opinion, HA and Fault Tolerance aspects are different on the cloud, and need special considerations.<br />&nbsp;</span></li>
<li><span style="font-family: helvetica; font-size: small;">You will hear a lot of great things about MySQL Cluster performance. Sometimes it gets difficult to sieve through results published by people trying to sell something versus people stating facts in a blunt way. Not every product is suitable for every use case. You get a feature at the cost of another, trade-offs are made - but these trade-offs are sometimes not discussed openly. What is the trade-off involved with MySQL Cluster? This is a quote from an official MySQL Cluster white paper: "<em>MySQL Cluster is a distributed, shared-nothing data store that provides very high, scalable performance for applications that largely use primary key access and have high concurrency, but it incurs a cost in network access when accessing data between a MySQL Server and tables distributed across Data Nodes</em>". Well of course it does! If you are writing your data spread across multiple data nodes which can be spread out in different regions, you will incur a latency cost. It will slow things down. Software is not magic. So why do we do it? Well, if the benefits outweigh the costs, then sure why not? But the important point to note here is this: Every piece of software tool out there wants to be "enterprise grade" - meaning they want to be fault-tolerant, BCP-enabled, DR-enabled, able to scale up and down as well as in and out. But for an ACID compliant database, this does not come free - they come at the cost of latency and performance. Therefore, as MySQL evolved into MySQL Cluster, some performance had to be sacrificed. But good engineers do not just accept that - they provide knobs and levers to adjust this and adjust that, so that users can find the sweet spot between performance and features. The same is true for MySQL cluster. When JOIN performance started suffering because of data being distributed across several nodes, the MySQL Cluster team came up with <a href="http://www.clusterdb.com/mysql-cluster/70x-faster-joins-with-aql-in-mysql-cluster-7-2">AQL</a>&nbsp;in version 7.2. Various configurations are provided to fine tune performance, sometimes at the cost of durability, sometimes at the cost of RTO/RPO. However, most of that is extremely well documented. The focus of this blog post happens to be HA and Fault Tolerance because these are the reasons <em>why we have so many performance levers in the first place</em>!<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;">In the cloud, performance of MySQL Cluster will depend on, among several other factors, the size, CPU and memory of the Virtual Machines you are running the data nodes on. MySQL uses a lot of memory as it keeps a large part of the database in memory for performance. Everything has knobs and levers of course, but the recommended RAM size on MySQL Cluster data nodes for a 50 GB database is 64 GB (see page 20 of <a href="https://www.mysql.com/why-mysql/white-papers/mysql-reference-architectures-for-scalable-web-infrastructure/">this whitepaper</a>). In terms of Azure VM-s, a <a href="https://azure.microsoft.com/en-us/blog/new-d-series-virtual-machine-sizes/"><strong>D14</strong></a> or <a href="https://azure.microsoft.com/en-us/blog/largest-vm-in-the-cloud/"><strong>G3</strong></a> will be the right choice. It is this realization that makes me say that ClearDB is worth a shot - because when you spin up large VM-s, you want density and utilization. None of the two options (MySQL Cluster PAAS versus IAAS) will be very cheap, but in most cases either will be cheaper than having on-premises physical servers or 3rd party hosting.</span></li>
</ol>
<p><span style="font-family: helvetica; font-size: small;">&nbsp;</span></p>
<h1><span style="font-family: helvetica; font-size: small;"><span style="font-size: large;">Evolution of HA in the MySQL product line</span><br /></span></h1>
<p><span style="font-family: helvetica; font-size: small;"><br />Before we jump into the meat of this discussion, there is one other thing that should be kept in mind, and that is: MySQL Cluster represents the peak of MySQL's HA journey - 99.999% up-time guarantee if the architecture is done correctly. There are several other offerings that are less complex and provide less HA. Before studying MySQL Cluster, you should study these other offerings because they will be less complex to set up and definitely cheaper. If one them happens to suit your needs, there is no need to over-provision yourself in that case.<br /><br />The best way to understand all these other offerings leading up to MySQL Cluster, in my opinion, is to follow the evolution path. Imagine the single server MySQL Database. It is a good ACID database, but enterprises do not just need a database to be ACID compliant - they are in constant fear of vandalism, earthquakes and dinosaur level extinction events. They want to <em><strong>replicate</strong></em>. They want Disaster Recovery with low RTO and RPO. So backing up the database once a day is no longer sufficient, it needs to be continuous.<br /><br /><strong>Stage 1 - single server MySql with replication</strong><br /><br />Hence the single server MySQL Server evolved to provide simple replication mechanisms - an inbuilt feature that does not need any plugins/ add-ons. It is a simple master-slave topology. Replication can be synchronous - where the write on the master will be committed only when the write gets committed on the slave, thereby ensuring 100% consistency of the replica but at the cost of write performance - or it can be asynchronous, where the master propagates the changes out to the slave after the fact, thereby improving write latency but increasing the chance of data loss in case of disaster. The master-slave topology also provides the additional benefit of directing readers to the slave if they can work with slightly stale data, thereby reducing the load on the master, which can then funnel these resources to write operations, thereby isolating the two operations from each other.<br /><br />While that sounds wonderful, there came a day when that was inadequate. As financial transactions moved to the web, even more rigor was required from the replication process. Compliance to stringent standards required multiple replicas. Keeping all of them in sync was a challenge. On top of that, who would oversee the replication itself? What if replication was failing silently for days? It would leave a bad taste in the mouth if we found that out only after the replica was actually needed. And the million dollar question of availability then started glaring people in the face: <em><strong>how quickly can we fail over</strong></em>? What use is a replica if we cannot quickly fail over to it? As every second of availability became critical to businesses, the need for sub-second fail-over arose, and with that came the need for near-real-time replication without sacrificing performance (what use is a quick fail-over if the replica is stale?)<br /><br /><strong>Stage 2 - clustered and virtualized systems</strong><br /><br />At this stage, the simple master-slave replication evolved to LAN/WAN based wider "failover clustering" approaches. Balance was achieved between completely asynchronous replication (which improves write performance but increases possibility of stale reads from the slave) and completely synchronous replication (which degrades write performance but improves the chances of consistent replica on the slave). This balance was called "semi-synchronous replication" where the master commits a write when the change just reaches the slave - thereby re-defining the meaning of error and success. Multiple copies of the replica are handled in a "failover cluster", with a "cluster resource manager" constantly monitoring each copy using a heart beat mechanism, ensuring the health of the copies themselves, so that failover, when and if needed, is quick and seamless. All such mechanisms constantly monitor hardware, OS, network and database processes so that it can automatically fail over to standby servers in the event of a failure being detected, redirecting applications to new master as part of the process. Automatic failover was one of the biggest wins in this step of the evolution - lower downtime, less losses. Such solutions provided a new breed of HA-aware MySQL products: <strong>Oracle Clusterware</strong> (on Linux/ Solaris), <strong>Oracle VM Template</strong> (on Linux), <strong>Solaris Cluster</strong> (on Solaris), <strong>Windows Cluster</strong> (on Windows) and <strong>DRBD</strong> (on Linux). You can explore some aspects of these solutions in this <a href="https://www.mysql.com/why-mysql/white-papers/mysql-guide-to-high-availability-solutions/">white paper</a>, which calls such systems "Clustered and Virtualized systems"<br /><br />While that sounds even more wonderful, limitations still exist in the above systems. Availability guarantees are still lower than what mission critical and massive for-profit organizations needed. As business started operating globally, their user bases started interacting with the database from multiple regions. The concept of master-slave suddenly felt inadequate because the traditional master-slave arrangement only allows writes against the master. All of a sudden, the need for master-master arose, because we now needed the ability to write from different parts of the world. Multi-master topology brought its own challenges, like data consistency issues due to update conflicts.<br /><br /><strong>Stage 3 - MySQL Cluster</strong><br /><br />MySQL Cluster, therefore, represents the peak of this evolution as of today. It attempts to resolve the above challenges, and provides 99.999% availability guarantee if the architecture is right - <em>that comes to less than 5.5 minutes of downtime each year, including planned maintenance</em>. I will not go into the details of how MySQL Cluster actually works. <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/26/set-up-a-mysql-iaas-ndb-cluster-with-four-nodes-on-azure-linux.aspx">My earlier blog</a> describes the topology of a MySQL Cluster. Consider reading <a href="https://www.mysql.com/why-mysql/white-papers/mysql-cluster-evaluation-guide/">this whitepaper</a> to find out how MySQL Cluster attempts to solve these problems. MySQL Cluster is shared-nothing and geo-replicated. It has three layers - management nodes, application nodes (aka SQL Nodes), and data nodes. The most interesting part is the data nodes. We will soon see how data is spread across the data nodes for fault tolerance.<br /><br />This picture shows the evolution I just described:<br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/0844.MySQL%20HA%20Options.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/0844.MySQL-HA-Options.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/0844.MySQL%20HA%20Options.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/0844.MySQL-HA-Options.png" alt="" border="0" /></a><br /><br />&nbsp;</span></p>
<p>&nbsp;</p>
<h1><span><span style="font-family: helvetica; font-size: large;">What does High Availability and Fault Tolerance mean w.r.t MySQL Cluster?</span><br /></span></h1>
<p><span style="font-size: small; font-family: helvetica;">From a MySQL Cluster perspective, it means that </span><em style="font-size: small; font-family: helvetica;">no single failure can result in the loss of service</em><span style="font-size: small; font-family: helvetica;">. That guarantee, however, is dependent upon the architecture of the cluster. Not all architecture can provide that guarantee. That is one of the things that we are going to explore &ndash; how to architect the MySQL cluster on Azure so that its intrinsic guarantee of HA/ BCP is realized.</span></p>
<p><span style="font-family: helvetica;"><span style="font-size: small;"><br />An important point to note is MySQL Cluster&rsquo;s <a href="https://en.wikipedia.org/wiki/CAP_theorem">CAP Theorem</a> stance. In case of catastrophic network partition, does MySQL choose <em><strong>availability</strong></em> or <em><strong>consistency</strong></em>? The answer is <em><strong>consistency</strong></em>&nbsp;(as is truly becoming of an ACID compliant database) It shuts the cluster down to prevent inconsistency in data. Therefore, it is even more important to architect the cluster properly &ndash; because a MySQL cluster with improper architecture will shut itself down in case of node or network failure, thereby failing to provide HA. Hence, the 99.999% guarantee will not be reached. That is why architecture plays a big role in determining your HA mileage out of MySQL Cluster, 99.999% being the best case scenario.</span></span></p>
<h1><span style="font-family: helvetica; font-size: small;"><br /><span style="font-size: large;">The Data Node Algorithm</span><br /></span></h1>
<p><span style="font-size: small;"><span style="font-family: helvetica;">MySQL Cluster, as I described earlier, has at least three layers, not counting the clients that connect to it. In the diagram below, borrowed from http://www.handybackup.net/, the "storage nodes" is the most important layer - we will call them "</span><strong style="font-family: helvetica; font-size: small;">data nodes</strong><span style="font-family: helvetica;">". The "query processing nodes" are the ones where MySQL daemon (mysqld) runs - which means clients connect to this node to run queries against - we will call them "</span><strong style="font-family: helvetica; font-size: small;">SQL Nodes</strong><span style="font-family: helvetica;">". The </span><strong style="font-family: helvetica; font-size: small;">management nodes</strong><span style="font-family: helvetica;"> run the cluster orchestrating processes - they distribute workloads and arbitrate in case of node failures in case leader election is needed:</span><br /><br /><a style="font-family: helvetica; font-size: small;" href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8765.mysql-clustering.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8765.mysql_2D00_clustering.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8765.mysql-clustering.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/368x249/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8765.mysql_2D00_clustering.png" alt="" border="0" /></a><br /><br /><br /><span style="font-family: helvetica;">Two very important points to note about MySQL Cluster is that data is written to the data nodes (a) auto-sharded (partitioned) and (b) replicated in a synchronous manner.</span><br /><br /><span style="font-family: helvetica;">In the config.ini file in the management node (typically&nbsp;/var/lib/mysql-cluster/config.ini), there is a key "NoOfReplicas". In the same file, the data nodes are defined - so the cluster knows the number of data nodes. From these two pieces of information (#replicas, #data nodes), MySQL Cluster calculates the number of </span><strong style="font-family: helvetica; font-size: small;">node groups</strong><span style="font-family: helvetica;">.</span><br /><br /><span style="font-family: helvetica;">#Node Groups = #Data Nodes / #Replicas</span><br /><br /><span style="font-family: helvetica;">It then arranges the data nodes into as many node groups. </span><strong style="font-family: helvetica; font-size: small;">A node group is defined as the group of data nodes which contain the same partition of data, replicated {#Replicas} times</strong><span style="font-family: helvetica;">. Inside a given node group, MySQL cluster establishes a primary node for a given partition, and one or more secondary nodes for the same partition - and it does this in such a way that each partition has a distinct primary and distinct secondary(ies).</span><br /><br /><span style="font-family: helvetica;">Confusing? Let us try this diagram (click on it to make it bigger):</span><br /><br /><a style="font-family: helvetica; font-size: small;" href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/1715.mySQLCLusterAlgorithm.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/1715.mySQLCLusterAlgorithm.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/1715.mySQLCLusterAlgorithm.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/1715.mySQLCLusterAlgorithm.jpg" alt="" border="0" /></a><br /><br /><br /><span style="font-family: helvetica;">In this example,&nbsp;</span><span style="font-family: helvetica;">#Data Nodes = 12,&nbsp;#Replicas = 3 (the two inputs).<br /><br />Therefore, here are the computed counts:<br /></span><span style="font-family: helvetica;"># Node Groups = 12/3 = 4 (marked as Node Group 1, Node Group 2, Node Group 3 and Node Group 4 in the diagram, with a-l being the names of the actual data nodes)</span><br /><span style="font-family: helvetica;"># Partitions per table = #Data Nodes = 12</span><br /><span style="font-family: helvetica;"># Partitions per node group = #Replicas = 3</span><br /><br /><span style="font-family: helvetica;">What that means is that a given table will be partitioned into 12 parts (based on the hash of the primary key, unless a different algorithm is provided). In the above example, the table shown is, therefore, split into 12 partitions (12 sets of rows): Partition 1, Partition 2, ... Partition 12.</span><br /><br /><span style="font-family: helvetica;">Out of these 12 partitions, 3 are selected for Node Group 1, 3 selected for Node Group 2 and so on. In the above example, say Partitions 1, 2 and 3 are selected for Node Group 1. These 3 partitions are stored in the Node Group 1 - but remember that Node Group 1 has 3 data nodes. Therefore, MySQL Cluster chooses one primary and two secondaries for each of Partitions 1, 2, and 3 in such a way that no single node in that group is the primary of more than one. See the table embedded in the diagram. One way to read the table is: Data Node a is the primary for Partition 1, hence all reads/writes for rows in this partition will first come to data node a, and then will be synchronously replicated to data nodes b and c.</span><br /><br /><span style="font-family: helvetica;">This is a simplified algorithm - but one that is sufficient to explain HA in MySQL Cluster.</span><br /><br /><br /><strong style="font-family: helvetica; font-size: small;">Fault Scenarios - the goal of MySQL Cluster Architecture</strong><br /><br /><span style="font-family: helvetica;">So what happens when a network partition happens and the data nodes can no longer talk to each other? Or one or more data nodes fail, thereby severing communication with other data nodes?</span><br /><br /><span style="font-family: helvetica;">The data nodes are split into separate communities - each community containing nodes than can talk to each other. Each community follows this flow chart (again, clicking should give you a bigger diagram to look at):</span><br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/3201.Fault_Decision.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/3201.Fault_5F00_Decision.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/3201.Fault_Decision.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/3201.Fault_5F00_Decision.jpg" alt="" border="0" /></a><br /><br /><br /><span style="font-family: helvetica;">The goal of MySQL Cluster architecture is to reach one of those two green circles for all possible single point failures. If you reach one of the red ones, you lose service, and the promise of 99.999% availability is vaporware.</span><br /><br /><span style="font-family: helvetica;">At this point, I urge you to, if you have not yet done so, go through </span><a style="font-family: helvetica; font-size: small;" href="http://mysqlhighavailability.com/mysql-cluster-fault-tolerance-impact-of-deployment-decisions/">this excellent blog</a><span style="font-family: helvetica;"> to understand how the architecture would impact availability if you were to do this on physical servers.<br /></span><br /></span></p>
<h1><span style="font-size: small;"><br /><span style="font-family: helvetica; font-size: large;">Azure specific thoughts</span></span></h1>
<p>&nbsp;</p>
<ol>
<li>
<p><span style="font-family: helvetica; font-size: small;">This is the recommended architecture on Azure (assuming that this cluster is contained in one single data center):<br /><br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8666.AzureAlgorithm.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8666.AzureAlgorithm.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8666.AzureAlgorithm.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8666.AzureAlgorithm.jpg" alt="" border="0" /></a><br /><br /><br />Here is why: Because each node group is in its own Availability Set, at least one of them will always be up and running (unless the whole Azure data center goes down, we will talk about that later). Therefore, any residual community of data nodes after one or more failures will always be a <strong>viable community of data nodes</strong>&nbsp;(see definition of viable community in the flow chart above, "viable community" means a group of data nodes where there is at least one node from each Node Group). Therefore, as we traverse the flow chart, we come down to the second diamond. At this point, it either continues operating, or even if it needs arbitration, it will always be able to connect to the management node, as we have two of them sitting in an availability set - so one of them will always be available. Therefore, loss of service is prevented under all conditions except loss of entire cluster (i.e., entire Azure data center)<br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">In order to protect your data from catastrophic disasters which can take an entire Azure data center down, you can choose to employ MySQL Cluster's geo-replication feature in Azure. Geo-replication provides geographic redundancy - while the internal (synchronous) replication provides High Availability between data nodes co-located within the cluster, the asynchronous inter-region replication to a remote site guards against site failures<br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">A very interesting option for MySQL Cluster with Azure is the "Multi-site clustering", where two data nodes belonging to the same cluster can reside in two regions. This is normally not going to fly, as replication between data nodes is synchronous. Synchronous inter-data-center writes are normally prohibitive in terms of latency. However, Azure provides <a href="https://azure.microsoft.com/en-us/services/expressroute/">the ExpressRoute</a> - which can provide up to 10 GBPS of throughput between Azure data centers (or even your premises and Azure cloud). A typical use case would be when we need writes happening at both ends - Active/Active configuration with no need for conflict resolution, as MySQL handles conflicts as an inbuilt feature (using time stamps and other techniques). When the user base is geographically distributed and writes must be supported from both ends, this is a viable architecture. Azure ExpressRoute can make this possible, though I do not know of anyone who has actually used MySQL Cluster this way. But MySQL Cluster provides the feature and you can give it a try on Azure!<br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/1452.MultisiteClustering.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/1452.MultisiteClustering.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/1452.MultisiteClustering.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/1452.MultisiteClustering.png" alt="" border="0" /><br /><br /><br /></a>This option is also a viable one if the two sites are in the same geographical regions (like Azure East and East 2) - and for some reason we want to set replication up, say, for example, between corporate locations.</span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">&nbsp;The other option for writes happening at both ends is Active/Active Multi-Master geo-replication on two Azure data centers. This would typically increase your compute costs compared to the previous option ("Multi Site Clustering"), but the previous option will need Express Route, while this option may be feasible using IPSEC tunnels. Again, MySQL Cluster supports full multi-master Active/Active geo-replication where both clusters are active - and there is no need for application level conflict resolution. Replication can happen asynchronously or semi-synchronously in this case. An important aspect to remember about Azure is that traffic between Azure data centers traverses Microsoft owned network backbones. This is key to high geo-replication performance - one of the several ways that Azure makes it easier to use MySQL Cluster.<br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/4382.GeoReplication.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/4382.GeoReplication.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/4382.GeoReplication.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/4382.GeoReplication.png" alt="" border="0" /></a><br /><br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">&nbsp;Another use case where geo-replication make sense on Azure is reporting. Several reporting tools can act on a MySQL data store and run complex queries - <a href="http://biinsight.com/mysql-and-power-bi-how-does-it-work/">including Power BI</a>. However, the recommended MySQL Engine optimized for such a use case is InnoDB, not NDB Cluster. We can use Active/Passive asynchronous geo-replication to offload the data to an InnoDB engine store where we can point our report and dashboard generation applications to<br /><br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">&nbsp;For applications that read/write/update a bunch of records per transaction, it is recommended that we build in "distribution awareness" in the application - where partitioning happens based on a sub-key common to all the rows being affected by the transaction (e.g., transaction or session id) - so that all records go to the same data node. This is especially required if we are using Multi Site Clustering<br /><br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">&nbsp;Azure can provide the perfect platform for real time applications that need fast propagation of updates across nodes or clusters or regions.&nbsp;Basically, applications that need low latency real time updates (e.g., reflecting status updates on financial transactions) either across the nodes of a cluster or across multiple clusters, can use a feature in MySQL where most or all data can be stored just in memory (RAM). This provides millisecond level cross node/cross cluster updates, but the cost incurred is durability/RTO/RPO. On a typical on-premises installation, power outages taking down the whole cluster will result in loss of the data that was still held in RAM. MySQL provides a way to mitigate this problem &ndash; continuous/ frequent disk-check-pointing and redo-logging, but that can reduce performance as it uses CPU and disk. However, a commercial cloud like Azure can take these trade-offs away. A MySQL cluster can be easily deployed with individual nodes distributed across availability sets, thus protecting the cluster from power/ rack failures. Therefore, real time applications can use the in-memory feature without the fear of losing data &ndash; and also without the need for continuous disk check-pointing and redo-logging which compromise performance<br /><br /></span></p>
</li>
<li>
<p><span style="font-family: helvetica; font-size: small;">MySQL Cluster's operational agility features (online scaling by adding more slaves or nodes) are very nicely complemented by Azure auto-scaling features</span></p>
</li>
</ol>
<h1><span><span>Conclusion</span></span></h1>
<p><span style="font-size: small; font-family: helvetica;">In my opinion, ClearDB is a good example of what can be done with MySQL on Azure. They are running a successful commercial PAAS MySQL Cluster service on Azure, which is simply fantastic. As we work with more and more partners to deploy complex clusters on Azure, I will come back and update this blog. Thanks!&nbsp;</span></p>
<p><span style="font-family: helvetica; font-size: x-small;"><br /><br /></span></p>]]></content:encoded>
    </item>
    <item>
      <title>Set up a MySQL IaaS NDB cluster with 4 nodes on Azure Linux</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/set-up-a-mysql-iaas-ndb-cluster-with-4-nodes-on-azure-linux</link>
      <pubDate>Mon, 26 Oct 2015 10:34:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2015/10/26/set-up-a-mysql-iaas-ndb-cluster-with-4-nodes-on-azure-linux/</guid>
      <description><![CDATA[&nbsp;
Introduction
&nbsp;
In an earlier blog post, I wrote about setting up a MySQL single...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<p><strong><span style="color: #800080; font-family: helvetica; font-size: x-large;">Introduction</span></strong></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">In an <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/24/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-versus-raid-0-array-xfs.aspx">earlier blog post</a>, I wrote about setting up a MySQL single server instance on Azure Linux (Ubuntu) Virtual Machine. We also did some performance bench-marking around READ-s with lots of joins.<br /></span></p>
<p><span style="font-family: helvetica; font-size: small;">However, most enterprises would be interested in exploring a full-fledged MySQL cluster as opposed to just a single server. MySQL cluster uses the NDB engine to manage the different nodes, and data is saved in the data nodes in such a way that it is extremely fault-resilient, scalable and high performing.<br /></span></p>
<p><span style="font-family: helvetica; font-size: small;">In this blog post, I will explore how to set up a 4 node MySQL IAAS cluster on Azure.<br /><br /><span style="background-color: #ffff00;"><strong>Note:</strong></span> <a href="https://www.cleardb.com/store/azure">ClearDB</a> now provides PAAS MySQL Clusters on Azure as well. In fact, their offering seems very robust and technically a lot more attractive than setting your own IAAS instance because of the <a href="https://azure.microsoft.com/en-us/blog/announcing-new-mysql-premium-tiers-from-cleardb/">recently announced</a> option of Premium&nbsp;Dedicated Clusters. I said "technically" because I have not had the chance to compare the cost model of going with them versus hosting your own IAAS cluster on Azure. In this blog post, we will focus on the IAAS option.</span></p>
<p>&nbsp;</p>
<p><span style="color: #800080; font-family: helvetica; font-size: x-large;"><strong>Architecture</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">These steps are listed on mysql website in a generic fashion -&nbsp;http://dev.mysql.com/doc/mysql-cluster-excerpt/5.1/en/mysql-cluster-installation.html</span></p>
<p><span style="font-family: helvetica; font-size: small;">However, these steps need some modifications on Azure Virtual Machines running Ubuntu LTS 14.04. We will try to capture the differences here.</span></p>
<p><span style="font-family: helvetica; font-size: small;">Here is the conceptual architecture diagram of what we are trying to achieve. We will, as is obvious from this diagram, we will spin up 4 Virtual Machines - 2 for the data nodes, 1 for SQL Node, and 1 for the NDB Management node. You can set up a 5th node as a client if you want to run performance tests, and we will also briefly cover that. However, to hold against a large performance test run on the cluster, the cluster nodes need to be beefy, as MySQL has a tendency to consume large amounts of memory unless tuned well - especially queries with JOINS needs AQL. Discussing such optimizations in not within the scope of this blog post.</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/3835.multi-comp-1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/3835.multi_2D00_comp_2D00_1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/3835.multi-comp-1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/3835.multi_2D00_comp_2D00_1.png" alt="" border="0" /></a><br /><br /><br /><br /></span></p>
<div>
<p>&nbsp;</p>
</div>
<div>
<p><span style="color: #800080;"><strong><span style="font-family: helvetica; font-size: x-large;">Set up the cluster on Azure</span></strong></span></p>
<p>&nbsp;</p>
<ol>
<li><span style="font-family: helvetica; font-size: small;">Set up the 1st data node ("mysqlclusterdatanodeA")&nbsp;from Azure portal with its own resource group, vNet, storage account and availability Set. Recommended minimum size SKU is D1 Standard<br />&nbsp;</span></li>
<li><span style="font-family: helvetica; font-size: small;">Set up the 2nd data node ("<span>mysqlclusterdatanodeB") - join it to the same resource group, vNET, storage account and availability Set as the data node A.&nbsp;<span>Recommended minimum size SKU is D1 Standard<br />&nbsp;</span></span></span></li>
<li><span style="font-family: helvetica; font-size: small;"><span>Set up the SQ<span style="font-size: small;">L Node ("mysqlclustersqlnode") -&nbsp;join it to the same resource group, vNET and storage account as the data nodes. No need for Availability Set. Recommended minimum size SKU is A1<br />&nbsp;</span></span></span></li>
<li><span style="font-family: helvetica; font-size: small;">Set up the Management Node ("mysqlclustermgmtnode") -&nbsp;join it to the same resource group, vNET and storage account as the data nodes. No need for Availability Set. Recommended minimum size SKU is A0<br />&nbsp;</span></li>
<li><span style="font-family: helvetica; font-size: small;">From the MySQL cluster download area (http://dev.mysql.com/downloads/cluster/) - download the file&nbsp;mysql-cluster-gpl-7.4.8-linux-glibc2.5-x86_64.tar.gz. Copy it to each of the 4 VM-s created above<br />&nbsp;</span></li>
<li><span style="font-family: helvetica; font-size: small;">[At this stage, we have moved on to the section 4.1.1 here:&nbsp;http://dev.mysql.com/doc/mysql-cluster-excerpt/5.1/en/mysql-cluster-install-linux-binary.html. However, instead of saving the downloaded and copied tar.gz file in /var/tmp, we can proceed with it being present in the home directory of the primary used being used to log into the Azure VM-s]<br />&nbsp;</span></li>
<li><span style="font-family: helvetica; font-size: small;">Follow all the steps in section 4.1.1. You will need to deviate in the following steps:<br />&nbsp;</span></li>
<ol>
<li><span style="font-family: helvetica; font-size: small;">Step 3 - "cd mysql" should read "/usr/local/mysql"<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;">Step 3 - The step "scripts/mysql_install_db --user=mysql" will fail as it cannot find libaio.so, it turns out that the 64 bit version of the library is not installed on the Azure VM by default, "sudo apt-get install libaio1" fixes it<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;">Step 5 - Instead of /etc/rc.d/init.d use /etc/init.d<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;">Step 5 - instead of the chkconfig command use: sudo update-rc.d mysql.server defaults<br /><br /></span></li>
</ol>
<li><span style="font-family: helvetica; font-size: x-small;"><span style="font-size: small;">Do not restart the SQL node now, just move on to the data node A<br /></span><br /></span></li>
<li><span style="font-family: helvetica; font-size: x-small;"><span style="font-size: small;">Follow steps for data node A, data node B from the same section. DO NOT RESTART ANY OF THESE, move on to the next node<br /><br /></span></span></li>
<li><span style="font-family: helvetica; font-size: x-small;"><span style="font-size: small;">Follow steps for management node from the same section. Do not restart. Move on<br /><br /></span></span></li>
<li><span style="font-family: helvetica; font-size: small;">[At this stage, we have moved on to the section 4.3 here:&nbsp;http://dev.mysql.com/doc/mysql-cluster-excerpt/5.1/en/mysql-cluster-install-configuration.html]<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;">Log into the SQL Node and do the following:<br /><br /></span></li>
<ol>
<li><span style="font-family: helvetica; font-size: small;">sudo vi /etc/my.cnf (or use your favorite editor)<br /><br /></span></li>
<li><span style="font-family: helvetica; font-size: small;"><span style="font-family: helvetica;">Paste this:<br /></span></span>
<pre><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;">[mysqld]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;"># Options for mysqld process:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;">ndbcluster # run NDB storage engine</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;">[mysql_cluster]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;"># Options for MySQL Cluster processes:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-size: small; font-family: 'courier new', courier;">ndb-connectstring=10.2.0.7 # location of management server</span></strong></span><br /><br /></pre>
</li>
<li>
<pre><span style="font-size: small; font-family: helvetica;">[Remember to use the correct Private IP address for the management server in the last line.<br />Get that from Azure Portal. Make sure that you DO NOT use the VM's Public IP Address here.<br />Use the private one]</span></pre>
</li>
<li>
<pre><span style="font-size: small; font-family: helvetica;">sudo reboot (so that the mysql process can start as we put it in /etc/init.d)<br />This is also a test whether we did that right!<br /></span></pre>
</li>
</ol>
<li><span style="font-size: small; font-family: helvetica;"><span style="white-space: pre;">While that is rebooting, repeat the same steps (12 a, b) on the two data nodes (but no need to reboot<br />them, as data nodes are not expected to run any daemon that needs restarting or starting)<br /><br /></span></span></li>
<li><span style="font-size: small; font-family: helvetica;"><span style="white-space: pre;">Log into the management Node and do the following:<br /></span></span></li>
<ol>
<li><span style="font-size: small; font-family: helvetica;"><span style="white-space: pre;">sudo mkdir /var/lib/mysql-cluster<br /></span></span></li>
<li><span style="font-size: small; font-family: helvetica;"><span style="white-space: pre;">cd /var/lib/mysql-cluster<br /></span></span></li>
<li><span style="font-size: small;"><span style="white-space: pre;"><span style="font-family: helvetica;">sudo vi config.ini</span><br /></span></span></li>
<li><span style="font-size: small;"><span style="font-size: small;"><span style="white-space: pre;">Paste this:<br /></span></span></span>
<pre><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[ndbd default]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># Options affecting ndbd processes on all data nodes:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">NoOfReplicas=2 # Number of replicas</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">DataMemory=1024M # How much memory to allocate for data storage</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">IndexMemory=160M # How much memory to allocate for index storage</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # For DataMemory and IndexMemory, we have used the</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # default values. Since the "world" database takes up</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # only about 500KB, this should be more than enough for</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # this example Cluster setup.</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[tcp default]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># TCP/IP options:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">portnumber=2202 # This the default; however, you can use any</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # port that is free for all the hosts in the cluster</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # Note: It is recommended that you do not specify the port</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # number at all and simply allow the default value to be used</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # instead</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[ndb_mgmd]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># Management process options:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">hostname=10.2.0.7 # Hostname or IP address of MGM node</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">datadir=/var/lib/mysql-cluster # Directory for MGM node log files</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[ndbd]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># Options for data node "A":</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # (one [ndbd] section per data node)</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">hostname=10.2.0.4 # Hostname or IP address</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">datadir=/usr/local/mysql/data # Directory for this data node's data files</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[ndbd]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># Options for data node "B":</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">hostname=10.2.0.5 # Hostname or IP address</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">datadir=/usr/local/mysql/data # Directory for this data node's data files</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">[mysqld]</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"># SQL node options:</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;">hostname=10.2.0.6 # Hostname or IP address</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # (additional mysqld connections can be</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # specified for this node for various</span></strong></span><br /><span style="color: #ff0000;"><strong><span style="font-family: 'courier new', courier;"> # purposes such as running ndb_restore)</span></strong></span><br /><br /><br /></pre>
</li>
<li>
<pre><span style="background-color: #ffff00;"><strong>NOTE:</strong></span><br /><span style="font-family: helvetica; font-size: small;">(i) NoOfReplicas = how many data nodes we have<br /><br />(ii) DataMemory, IndexMemory - Key point to note here apart from the explanations available<br />in the documentation is that these memory limits will be imposed on the DATA NODES.<br />Not on the management node. In our case, the management node is small (A0) and has<br />only 0.75 GB of memory. Obviously it cannot handle 1024M as DataMemory - it does<br />not even have that much. The reason we have used 1024M here is that: if you try to install<br />the standard publicly available employees database, which is around 160 MB in size,<br />you will still be good<br /><br />(iii) For IndexMemory, the thumb rule is to allocate between 1/6 and 1/8 of the DataMemory,<br />but if there are too many UNIQUE in the table definitions, it will need more to store all the<br />unique hash indexes<br /><br />(iv) portnumber - internal communication port for all the hosts in the cluster,<br />we will have to open this port up from the portal<br /><br />(v) hostname - in the 4 sections "ndb_mgmd", "ndbd", "ndbd" and "mysqld" - make sure<br />that you use the CORRECT PRIVATE IP ADDRESS of the management node,<br />data node A, data node B and SQL node respectively<br /><br />(v) Remember that the way we have set up the data nodes, <em>there is no directory</em><br />called "/usr/local/mysql/data" on them, but the "datadir" entry for these 2 servers are<br />pointing to this value. Which means we have to log into our data hosts, create this<br />directory and set its permissions correctly&nbsp;</span></pre>
</li>
</ol>
<li><span style="font-family: helvetica; font-size: small;">&nbsp;So we have a few follow-up tasks from the above config.ini. Let us execute these one by one:</span></li>
<ol>
<li>
<pre><span style="font-family: helvetica; font-size: small;">Go to the portal and browse to the NSG for each of the 4 nodes one by one<br />(each host will have one Network Security Group created for itself. Select that NSG,<br />add 1 inbound security rule - Source ANY, Destination Port 2202 (overwrite 80 with 2202),<br />Protocol ANY and 1 outbound security rule - Source Any, Destination Any (overwrite 80<br />with *), Protocol Any. Repeat for each of the 4 NSG-s<br /></span></pre>
</li>
<li>
<pre><span style="font-family: helvetica; font-size: small;">Log onto the data nodes are run these commands on each:<br /></span></pre>
<pre><span style="font-size: small;">sudo mkdir /usr/local/mysql</span><br /><span style="font-size: small;">sudo mkdir /usr/local/mysql/data</span><br /><span style="font-size: small;">sudo chmod a+w /usr/local/mysql</span><br /><span style="font-size: small;">sudo chmod a+w /usr/local/mysql/data/</span></pre>
</li>
</ol>
<li><span style="font-size: small;">Now is a good time to log into your SQL Node and make sure that it rebooted. Once in, run<br />"sudo netstat -tap | grep mysql" and make sure that mysqld is running<br />&nbsp;</span></li>
<li><span style="font-size: small;"><span>[At this stage, we have moved on to the section 4.4 here:&nbsp;http://dev.mysql.com/doc/mysql-cluster-excerpt/5.1/en/mysql-cluster-install-first-start.html]<br /></span><br /></span></li>
<li><span style="font-size: small;"><span>Initial Startup of cluster:<br /></span></span></li>
<ol>
<li><span style="font-size: small;"><span>On management node: Step 1 under section 4.4 will fail unless you run this first: "sudo mkdir /usr/local/mysql" and then run ndb_mgmd with sudo: "ndb_mgmd -f /var/lib/mysql-cluster/config.ini". Verify with "ps aux | grep ndb"<br /><br /></span></span></li>
<li><span style="font-size: small;"><span>On Data nodes: sudo ndbd. Verify wit<span style="font-size: small;">h "ps aux | grep ndbd"<br /></span><br /></span></span></li>
<li><span style="font-size: small;">On SQL Node: mysqld should be running already as we set it to run at startup and we rebooted the node. If you have not done that, do it now<br /><br /></span></li>
<li><span style="font-size: small;">On management node: (VERIFY THAT CLUSTER IS RUNNING): "ndb_mgm" (no need to use sudo) - use verb SHOW and then EXIT<br /><br /></span></li>
</ol>
<li><span style="font-size: x-small;"><span style="font-size: small;">[At this stage, we have moved on to the section 4.5 here:&nbsp;http://dev.mysql.com/doc/mysql-cluster-excerpt/5.1/en/mysql-cluster-install-example-data.html]<br /></span><br /></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;">By now, you can safely exit from any terminal(s) on the data and management nodes. All interaction with the cluster can happen through the SQL node, as if you are talking to a MySQL server located on the SQL Node. Remember, however, that the underlying engine must be specified as "NDBCLUSTER" instead of InnoDB or MyISAM for every table residing on every database in the cluster for it to be replicated across the cluster. Therefore, when creating any table on the cluster, we must specify ENGINE=NDBCLUSTER option. This goes for any mode of creation - even if we are importing databases from dumps. If we have not done so, we must ALTER TABLE each table and set ENGINE=NDBCLUSTER later on<br /><br /></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;">On SQL Node:<br />&nbsp;</span></span></li>
<ol>
<li><span style="font-size: x-small;"><span style="font-size: small;">cd /usr/local/mysql<br /><br /></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;">sudo bin/mysql_secure_installation (As root password is not set yet, just press ENTER when prompted for current root password. Then, set the root password properly)<br /><br /><span style="background-color: #888888;"><strong><span style="background-color: #ffff00;">NOTE:</span></strong></span>&nbsp;It is worth taking into account that Cluster nodes do not make use of the MySQL privilege system when accessing one another. Setting or changing MySQL user accounts (including the root account) affects only applications that access the SQL node, not interaction between nodes<br /><br /></span></span></li>
<li><span style="font-size: small; font-family: helvetica;">&nbsp;log into mysql client prompt using root user (assuming you are still inside /usr/local/mysql):&nbsp;bin/mysql -uroot -p&lt;root password set above&gt;<br /><br /></span></li>
</ol>
<li><span style="font-size: small; font-family: helvetica;">Add <strong>/usr/local/mysql/bin</strong> to PATH so that you can just log into the SQL Node VM and start typing "mysql..." without bothering to change directories.<br /><br />For an Azure Linux (Ubuntu) VM, this can be achieved most easily by executing this:&nbsp;<br /></span>
<pre><span style="font-family: helvetica; font-size: small;">cd ~; ln -s /usr/local/mysql/bin/ ./bin<br /><br />What this will do is create a symbolic link called "bin" in your home directory that links to<br /><strong>/usr/local/mysql/bin/</strong>. Azure Ubuntu VM-s already come with a ~/.profile file that adds<br />your home directory's bin subdirectory to PATH while logging in. Log out and log back in<br />and you should have access to mysql at your command prompt from anywhere.<br /><br /></span></pre>
</li>
<li>
<pre><span style="font-size: small; font-family: helvetica;">The cluster is ready. Treat it like a single server where the network address<br />of the SQL node is the equivalent of the "server" in the single-server world.<br />You can now point another VM (a client box) to this SQL node and connect,<br />and the steps would be the same as if you were connecting to a single server,<br />which are covered in my previous <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/24/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-versus-raid-0-array-xfs.aspx">blog post<br />&nbsp;</a></span></pre>
</li>
</ol></div>
<div>&nbsp;
<p><strong style="color: #800080; font-family: helvetica; font-size: x-large;">Conclusion</strong></p>
</div>
<div>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">This blog post only handles the setting up of the cluster. I am actually going ahead and running some basic performance tests on this cluster - I will update best practice guidelines for Azure shortly.</span></p>
<p>&nbsp;<span style="font-family: helvetica; font-size: small;">Thanks!</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>]]></content:encoded>
    </item>
    <item>
      <title>MySQL performance benchmark on Azure Linux: OS disk (ext4) vs RAID 0 array (xfs)</title>
      <link>https://docs.microsoft.com/archive/blogs/opensourcemsft/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-vs-raid-0-array-xfs</link>
      <pubDate>Sat, 24 Oct 2015 08:59:00 GMT</pubDate>
      <dc:creator><![CDATA[Koushik Biswas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/opensourcemsft/2015/10/24/mysql-performance-benchmark-on-azure-linux-os-disk-ext4-vs-raid-0-array-xfs/</guid>
      <description><![CDATA[&nbsp;
Introduction
&nbsp;
In an earlier blog post, I wrote about how we can configure an Azure...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<p><strong><span style="font-family: helvetica; font-size: x-large; color: #800080;">Introduction</span></strong></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">In an <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/16/set-up-azure-ubuntu-vm-with-xfs-on-raid-zero.aspx">earlier blog post</a>, I wrote about how we can configure an Azure Linux (Ubuntu) VM with a RAID 0 array of data disks and mount XFS on the array. The goal of doing this was gaining disk I/O, hence performance.</span></p>
<p><span style="font-family: helvetica; font-size: small;">In order to substantiate this claim, I am following up with some performance tests run with the popular Open Source RDBMS database - MySQL. This blog shows how to set up the test using Azure Linux (Ubuntu) VM-s from scratch, and also discusses the results.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Install Mysql</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Before we dive into the details of the performance test and its results, let us quickly review what we need to do to install and run MySQL database on an Azure Linux (Ubuntu) VM. Here are the steps:</span></p>
<ol>
<li><span style="font-family: helvetica; font-size: small;">Provision an Azure Linux (Ubuntu 14.04 LTS) VM through <a href="https://portal.azure.com">the portal</a>, <a href="https://azure.microsoft.com/en-us/documentation/articles/xplat-cli/">Azure CLI</a>, Powershell or <a href="https://msdn.microsoft.com/library/azure/ee460799.aspx">REST API-s</a> - or one of the several other ways now available to do so (like <a href="https://github.com/Azure/azure-sdk-for-go">this open source go sdk</a>).</span><br /><br /><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE A:</strong></span> Please remember that we are going to benchmark SQL Server performance on this machine - hence the VM instance type should be carefully chosen. We recommend at least D-series for this purpose. If you plan to add data disks to this VM later on in order to create a RAID array, please pay close attention to the maximum number of data disks allowed as it varies per VM instance type. In order to complete this tutorial as-is, you should choose A2 or higher if you are going with A series, D2 or higher if you are going with D series. That is because we stripe together 4 data disks, and A1/D1 does not allow four data disks.</span><br /><br /><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE B:</strong></span> Please use the "Resource Manager" deployment method (as opposed to the "Classic" method). "Resource Manager" is the newer method and provides expanded manageability of your VM. Also, please create a new Resource Group (name it something meaningful like "mysqltest") and also create a new Virtual Network for this VM (also name it something meaningful). This is important because we will later create a load testing client machine and add it to the same Resource Group and Virtual Network. Adding the client machine to the same network as the server machine results in the load traffic not needing to cross any switches, thus avoiding variance.</span><br />&nbsp;</li>
<li><span style="font-family: helvetica; font-size: small;"><a href="https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-how-to-log-on/">Log into the VM using Putty</a>&nbsp;(or any other SSH client)</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo apt-get update</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo apt-get upgrade</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo apt-get install mysql-server</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo mysql_secure_installation (set root password, make other changes to make your installation as necessary - you can leave anonymous access on for convenience during testing)</span></li>
<li><span style="font-family: helvetica; font-size: small;">mysql -u root -p (test whether you can use the root password that you set in the above step)</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo netstat -tap | grep mysql (test if you can detect the mysqld daemon running)</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo service mysql restart (test if mysql has registered as a service)</span></li>
<li><span style="font-family: helvetica; font-size: small;">mysqlslap -uroot -p{Root password} (test whether the load testing client tool has been installed properly)</span></li>
<li><span style="font-family: helvetica; font-size: small;">vi&nbsp;/etc/mysql/my.cnf (or use any other editor - review this configuration file carefully, we are going to make changes to this file down the line to change the way mysql behaves)</span></li>
</ol>
<p><span style="font-family: helvetica; font-size: small;">[ These steps are consolidated as a shell script here (check out "install-mysql-on-azure-ubuntu-vm-needs-sudo.sh"): <a href="https://github.com/kbxkb/mysql-on-azure">https://github.com/kbxkb/mysql-on-azure</a>&nbsp;]</span></p>
<div>
<p>&nbsp;</p>
</div>
<div>
<p><span style="color: #800080;"><strong><span style="font-family: helvetica; font-size: x-large;">Install a large database to run the test against</span></strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Now that we have installed MySQL Server and got it running on our Azure Linux (Ubuntu) VM, we should download and install a decently large database with lot of records in it so that we can run a good performance test on it. This can be done with any database of your choice, but here is how I downloaded and installed the <a href="http://dev.mysql.com/doc/employee/en/employees-introduction.html">employees db</a> from mysql official site - it has 4 million records in all, and is around 160 MB in size:</span></p>
</div>
<ol>
<li><span style="font-family: helvetica; font-size: small;">mkdir employees_sample_db;&nbsp;cd employees_sample_db/</span></li>
<li><span style="font-family: helvetica; font-size: small;">wget "https://launchpad.net/test-db/employees-db-1/1.0.6/+download/employees_db-full-1.0.6.tar.bz2" (NOTE: Please make sure that you are using the latest and correct URL, launchpad may have a more current version)</span></li>
<li><span style="font-family: helvetica; font-size: small;">tar -xjf employees_db-full-1.0.6.tar.bz2</span></li>
<li><span style="font-family: helvetica; font-size: small;">cd employees_db/</span></li>
<li><span style="font-family: helvetica; font-size: small;">mysql -uroot -p{Root password} -t &lt; employees.sql</span></li>
<li><span style="font-family: helvetica; font-size: small;">Follow the steps <a href="http://dev.mysql.com/doc/employee/en/employees-installation.html">here</a> to install, validate and get the database up and running (note that the last few steps above are also included in this guide, so adjust your starting point accordingly)</span></li>
<li><span style="font-family: helvetica; font-size: small;">Log into the mysql&gt; prompt (mysql -uroot -p{root password}) and run <strong>show databases;</strong> to verify that the <strong>employees</strong> database is now installed on your server</span></li>
</ol>
<p><span style="font-family: helvetica; font-size: small;"><span style="font-family: helvetica; font-size: small;">[ These steps are consolidated as a shell script here (check out "install-employees-db-pass-mysql-root-pwd-as-parameter.sh"): <a href="https://github.com/kbxkb/mysql-on-azure">https://github.com/kbxkb/mysql-on-azure</a>&nbsp;]</span></span></p>
<div>&nbsp;<br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Set up user to run the test with</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Now that we have installed the employees database - let us create a special user for running our performance tests. We will create a powerful user with all permissions on all objects. You can tailor this step as per your need (or entirely skip it), but this is what I did (I granted permission on both localhost as well as '%' because we will eventually run the performance test from a different client VM) - run these commands at the mysql prompt as root ("mysql -uroot -p{Root password}") - substitute the "perftest" and "Azure123" with your own user name and password if you wish:</span></p>
</div>
<div>
<pre class="scroll"><code class="cplusplus">CREATE USER 'perftest'@'localhost' IDENTIFIED BY 'Azure123';<br />GRANT ALL PRIVILEGES ON *.* TO 'perftest'@'localhost' WITH GRANT OPTION;<br />CREATE USER 'perftest'@'%' IDENTIFIED BY 'Azure123';<br />GRANT ALL PRIVILEGES ON *.* TO 'perftest'@'%' WITH GRANT OPTION;<br />FLUSH PRIVILEGES;<br />SELECT * from information_schema.user_privileges where grantee like "'perftest'%";</code></pre>
</div>
<div><br />&nbsp;<br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Set up a client Virtual Machine on Azure</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Now that we have set up the perftest user, we should set up second VM - it will be out load test client machine (because it is never a good idea to run a performance benchmark on a server from the same machine as the server itself). Before we do that, let us reconfigure our MySQL server to accept connections from external hosts:</span></p>
</div>
<div><ol>
<li><span style="font-family: helvetica; font-size: small;">Edit /etc/mysql/my.cnf and comment out the line "bind-address = 127.0.0.1"</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo service mysql restart (for the my.cnf changes to take effect)</span></li>
</ol></div>
<div><span style="font-family: helvetica; font-size: small;">It is time to spin up the client machine:</span></div>
<div><ol>
<li><span style="font-family: helvetica; font-size: small;">Set up&nbsp;an Azure Linux (Ubuntu 14.04 LTS) VM through&nbsp;<a href="https://portal.azure.com">the portal</a>,&nbsp;<a href="https://azure.microsoft.com/en-us/documentation/articles/xplat-cli/">Azure CLI</a>, Powershell or&nbsp;<a href="https://msdn.microsoft.com/library/azure/ee460799.aspx">REST API-s</a>&nbsp;- or one of the several other ways now available to do so (like&nbsp;<a href="https://github.com/Azure/azure-sdk-for-go">this open source go sdk</a>).</span><br /><br /><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE A:</strong></span> The machine type does not need to be as powerful as the server's, but it is really up to you - executing a lot of parallel threads on the client is easier to scale if you have multiple cores.</span><br /><br /><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE B:</strong></span> Please set this machine up in the same Virtual Network as the server's. It is recommended that you also use the same Resource Group so that you can manage/ remove all the resources belonging to the same resource group together. See the notes for the server VM creation step for more information</span><br /><br /></li>
<li><span style="font-family: helvetica; font-size: small;">Log into the VM using Putty (or any other SSH client)</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo apt-get install mysql-client</span></li>
<li><span style="font-family: helvetica; font-size: small;">Use the portal to retrieve the Private IP Address of your server VM (the one that you created earlier). In the following step, use that IP address with the -h parameter, and whatever user name and password you created for the performance test user above. Remember, use the private IP address (not the public IP address) so that the load test traffic stays internal to the VNET</span></li>
<li><span style="font-family: helvetica; font-size: small;">mysql -h 10.1.0.4 -uperftest -pAzure123</span></li>
<li><span style="font-family: helvetica; font-size: small;">The client machine should now connect to the server successfully above</span></li>
</ol></div>
<div><br />&nbsp;<br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Turn off query caching</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Before we kick off a good READ test that will bring out the performance difference between the Azure VM's OS disk and a striped array of data disks, we should turn off query caching. That way, all our queries will hit the disk instead of some of them being served from memory. The comparison benchmark will have less variance. That is easy to do. Edit /etc/mysql/my.cnf and set&nbsp;query_cache_size to 0. Restart the mysql server after making the change (sudo service mysql restart).</span></p>
</div>
<div><br /><br />&nbsp;<br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Know your database design to model good queries</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">At this stage, it is a good idea to inspect the <a href="http://dev.mysql.com/doc/employee/en/sakila-structure.html">layout of the employees database</a> that we imported. This will help us construct good queries for using in the load test. As such, mysqlslap does not need you to provide queries to run a good test. It creates its own queries and it uses them on test tables that it creates before that. We will actually use both these features - we will have it run its own queries as well provide our own.</span></p>
</div>
<div><span style="font-family: helvetica; font-size: small;">While testing mysql using the employees database, we should look to make it work hard. For example:</span></div>
<div>
<pre class="scroll"><code class="cplusplus">select salaries.emp_no, salaries.to_date, dept_emp.dept_no FROM salaries INNER JOIN dept_emp ON salaries.emp_no = dept_emp.emp_no WHERE salaries.to_date BETWEEN '1990-01-01' AND "1991-12-31" ORDER BY salaries.emp_no, salaries.to_date;</code></pre>
</div>
<div><span style="font-family: helvetica; font-size: small;">The above query looks up the salaries table using a non-indexed field (to_date). That causes mysql to read a lot more data from the disk - exactly what we want. It also performs a JOIN, which makes it work even harder. This query returns around 233K records, give it a spin from the mysql prompt!</span></div>
<div><br /><span style="font-family: helvetica; font-size: small;">However, the results being published in this blog post did not use the above query. I used the following query (courtesy <a href="https://www.digitalocean.com/community/tutorials/how-to-measure-mysql-query-performance-with-mysqlslap">this blog post</a>) because it is rich with joins, and returns almost half a million records:</span></div>
<div>
<pre class="scroll"><code class="cplusplus">SELECT e.first_name, e.last_name, d.dept_name, t.title, t.from_date, t.to_date FROM employees e INNER JOIN dept_emp de ON e.emp_no=de.emp_no INNER JOIN departments d ON de.dept_no=d.dept_no INNER JOIN titles t ON e.emp_no=t.emp_no ORDER BY e.first_name, e.last_name, d.dept_name, t.from_date;</code></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Mysqlslap</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">(We should now inspect the load test tool that we will use:&nbsp;<a href="https://dev.mysql.com/doc/refman/5.1/en/mysqlslap.html">mysqlslap</a>. It is a good idea to read up on the tool's features, parameters etc. so that you can make the best use of it.)</span></p>
<p><span style="font-family: helvetica; font-size: small;"><strong><span style="background-color: #ffff00;">NOTE A:</span></strong> mysqlslap has several parameters and supports running load tests in many different ways. You should use it in several other ways as well to get a well-rounded picture. The "--debug-info" parameter results in the output containing interesting system information during the test like memory, CPU, etc. I found the "involuntary context switches" statistics to be one of the few interesting things that mysqlslap reports.</span></p>
<p><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE B:</strong></span> Use the correct value for --host (it should be the Private IP Address of your MySQL server VM that you can easily look up from the Azure portal). Use the correct user id and password as created above or otherwise.</span></p>
<p><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE C:</strong></span> Interpreting mysqlslap's output, quite interestingly, has been an non-intuitive journey for myself. For a given value of --concurrency parameter and a given value of --iterations parameter, its output may look like this:</span></p>
<pre class="scroll"><code class="cplusplus">Average number of seconds to run all queries: 167.015 seconds<br />Minimum number of seconds to run all queries: 166.215 seconds<br />Maximum number of seconds to run all queries: 167.995 seconds</code></pre>
<p><span style="font-family: helvetica; font-size: small;">Naturally, if my concurrency was say 20, and iterations was say 5, I would want to know what exactly took 167 seconds? The phrase "all queries" initially threw me off - I was thinking "wait, do I again need to divide it by the number of queries to get the real mean I need?"</span></p>
<p><span style="font-family: helvetica; font-size: small;">Turns out that I do not need to. If concurrency was 20, mysqlslap created 20 client threads, each running my given query once (provided I have not used the <strong>--number-of-queries</strong> parameter). That was one single test. It then repeated that single test 5 times if I have said <strong>--iterations=5</strong>. So it ran my query 20 * 5 = 100 times. 167.015 seconds is the average across all these 100 runs. It says "<em>all queries</em>" because my query could have easily been a set of queries instead of just one (it also accepts a .sql file with several queries in it). That is why it resorts to a generic phrase "all queries". I suspected this all along, but had to take an incredibly long journey to actually confirm this.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Here is the mysqlslap command that fires off the above query. Please note that the value of <strong>--concurrency</strong> parameter, as quoted below, is 'XX' because that is what I varied during different test runs.</span></p>
<p>&nbsp;</p>
<pre class="scroll"><code class="cplusplus">mysqlslap -uperftest -pAzure123 --host=10.1.0.4 --create-schema=employees --query="SELECT e.first_name, e.last_name, d.dept_name, t.title, t.from_date, t.to_date FROM employees e INNER JOIN dept_emp de ON e.emp_no=de.emp_no INNER JOIN departments d ON de.dept_no=d.dept_no INNER JOIN titles t ON e.emp_no=t.emp_no ORDER BY e.first_name, e.last_name, d.dept_name, t.from_date;" --concurrency=XX --iterations=10 --verbose --debug-info</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="color: #800080;"><strong><span style="font-family: helvetica; font-size: x-large;">Results on OS disk</span></strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Here are the results with the employees database still residing on the OS disk:</span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8130.perf1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8130.perf1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/8130.perf1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/8130.perf1.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Switch to RAID 0 array as data directory</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Now that we have executed our READ test against the ext4 OS Disk, we can now, in order to compare, run it against an alternate partition - the RAID 0 array of 4 standard storage data disks mounted with XFS. In order to do so, you need to follow my <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/16/set-up-azure-ubuntu-vm-with-xfs-on-raid-zero.aspx">earlier blog</a>&nbsp;and add 4 data disks to the mysql server VM, stripe them in a RAID 0 array and mount it as an XFS partition - if you have not already done so.</span></p>
<p><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong>NOTE:</strong></span> You can add data disks and follow all the steps to stripe, partition and mount them without disturbing the software installed on the OS disk</span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Once you have followed those steps, you should have a mount point "/RAID0" on your server VM:</span></p>
<pre class="scroll"><code class="cplusplus">$ df -T<br /> Filesystem Type 1K-blocks Used Available Use% Mounted on<br /> /dev/sda1 ext4 30202916 4062200 24874684 15% /<br /> none tmpfs 4 0 4 0% /sys/fs/cgroup<br /> udev devtmpfs 1756712 12 1756700 1% /dev<br /> tmpfs tmpfs 352320 452 351868 1% /run<br /> none tmpfs 5120 0 5120 0% /run/lock<br /> none tmpfs 1761584 0 1761584 0% /run/shm<br /> none tmpfs 102400 0 102400 0% /run/user<br /> none tmpfs 64 0 64 0% /etc/network/interfaces.dynamic.d<br /> /dev/sdb1 ext4 139203560 60928 132048464 1% /mnt<br /> <strong>/dev/md127 xfs 1048047616 741848 1047305768 1% /RAID0</strong><br />$</code></pre>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Now, we have to copy the entire MySQL database part to /RAID0 partition from / (i.e., to /dev/md127 from /dev/sda) and also point mySQL at the new location.</span></p>
<p><span style="font-family: helvetica; font-size: small;">Follow these steps to do so:</span></p>
<ol>
<li><span style="font-family: helvetica; font-size: small;">sudo service mysql stop</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo netstat -tap | grep mysql #check if stop worked</span></li>
<li><span style="font-family: helvetica; font-size: small;">rm -rf /RAID0/mysql #because rsync will create the mysql folder</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo rsync -avzh /var/lib/mysql /RAID0 #rsync parameters will make sure that all directory permissions and ownerships will be preserved</span></li>
<li><span style="font-family: helvetica; font-size: small;">edit /etc/mysql/my.cnf and change (line following '-' is replaced by the line following '+' without the -/+ sign themselves being part of the lines):</span><br /><br /><span style="font-family: helvetica; font-size: small;">-datadir &nbsp; &nbsp; = /var/lib/mysql</span><br /><span style="font-family: helvetica; font-size: small;">+datadir &nbsp; &nbsp; = /RAID0/mysql</span><br /><br /></li>
<li><span style="font-family: helvetica; font-size: small;">sudo mv /var/lib/mysql /var/lib/mysql-old</span></li>
<li><span style="font-family: helvetica; font-size: small;">edit /etc/apparmor.d/usr.sbin.mysqld and change&nbsp;(line following '-' is replaced by the line following '+' without the -/+ sign themselves being part of the lines):</span><br /><br /><span style="font-family: helvetica; font-size: small;">- &nbsp;/var/lib/mysql/ r,</span><br /><span style="font-family: helvetica; font-size: small;">- &nbsp;/var/lib/mysql/** rwk,</span><br /><span style="font-family: helvetica; font-size: small;">+ &nbsp;/RAID0/mysql/ r,</span><br /><span style="font-family: helvetica; font-size: small;">+ &nbsp;/RAID0/mysql/** rwk,</span><br /><br /></li>
<li><span style="font-family: helvetica; font-size: small;">sudo /etc/init.d/apparmor reload</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo service mysql start</span></li>
<li><span style="font-family: helvetica; font-size: small;">sudo netstat -tap | grep mysql #check if start worked</span></li>
</ol>
<p><span style="font-family: helvetica; font-size: small;"><span style="font-family: helvetica; font-size: small;"><span style="font-family: helvetica; font-size: small;">[ These steps are consolidated as a shell script here (check out "switch-mysql-data-from-var-lib-to-new-dir-needs-sudo-needs-newdir-as-param.sh"): <a href="https://github.com/kbxkb/mysql-on-azure">https://github.com/kbxkb/mysql-on-azure</a>&nbsp;]</span></span></span></p>
<div><br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>Results on RAID 0 array</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Once the switch is complete, invoking mysql server on your server VM, results in it actually reading/ writing data from/to the /RAID0 disk array - and not the OS data disk.</span></p>
</div>
<div><span style="font-family: helvetica; font-size: small;">Therefore, you can now repeat the same test as above - running mysqlslap from the client machine with the same command line and same query, which does not need to know anything about this change we made on the server side.</span></div>
<div>&nbsp;</div>
<div><span style="font-family: helvetica; font-size: small;">Here are the results:</span><br />&nbsp;<br />&nbsp;</div>
<div><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/2806.perf2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/2806.perf2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/2806.perf2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/2806.perf2.png" alt="" border="0" /><br />&nbsp;<br />&nbsp;</a></div>
<div>&nbsp;</div>
<div><span style="font-family: helvetica; font-size: small;">And here is a side by side comparison, the Y axis being latency and X axis being concurrency. You can see that as concurrency increases, the RAID 0 array of 4 standard disks performs twice as well as the OS disk (suffers from half as much latency)</span></div>
<div><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/2437.perf3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/2437.perf3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/72/29/2437.perf3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-72-29/2437.perf3.png" alt="" border="0" /></a></div>
<div><br />
<p><span style="font-family: helvetica; font-size: x-large; color: #800080;"><strong>WRITE tests</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">We can run similar tests for WRITE operations as well. Let us use mysqlslap's built-in capability of generating its own tables and queries. We can use the following command on the client machine to simulate a write load:</span></p>
</div>
<div><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong><br />NOTE A:</strong></span> These two parameters are key here:<strong> --auto-generate-sql</strong>&nbsp;and <strong>--auto-generate-sql-load-type=write</strong>. You can change the concurrency parameter's value just we did with the READ query</span></div>
<div><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong><br />NOTE B:</strong></span> Use the correct value for --host (it should be the Private IP Address of your MySQL server VM that you can easily look up from the Azure portal). Use the correct user id and password as created above or otherwise.</span></div>
<div>
<pre class="scroll"><span style="font-family: helvetica; font-size: small;"><code class="cplusplus">mysqlslap -uperftest -pAzure123 --host=10.1.0.4 --auto-generate-sql --auto-generate-sql-load-type=write --concurrency=100 --iterations=10 --verbose</code></span></pre>
&nbsp;</div>
<div><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong><br />NOTE C:</strong></span> Even if you do not use "<em>--auto-generate-sql-load-type=write</em>", mysqlslap, by default, executes a <em><strong>mixed</strong></em> test - which means it does some reads and some writes</span></div>
<div><span style="font-family: helvetica; font-size: small;"><span style="background-color: #ffff00;"><strong><br />NOTE D:</strong></span> Now that we switched the mysql server's data location to the /RAID0 partition during the READ test, how do I switch it back to the OS disk (/var/lib/mysql) to run the WRITE test against the OS disk? That is quite easy to do - just execute steps 1 &amp; 2, then reverse execute steps 5, 6 &amp; 7, followed by steps 8 &amp; 9 in the above step-by-step guideline that explains how to move the data directory to /RAID0. You can switch back and forth as many times as you want - just remember one thing: there are 2 copies of the database in the two disks, and though they are identical to begin with, they will diverge if you start writing to them. If you have written to them and want to synchronize them, just use the rsync command (step 4) accordingly.</span></div>
<div><span style="font-family: helvetica; font-size: small;">[Actual write tests left as exercise]</span><br />&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>
<p><span style="color: #800080; font-family: helvetica; font-size: x-large;"><strong>Other Considerations</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">MySQL performance tuning is a vast but well documented topic. All such tips and techniques intrinsic to MySQL itself also applies to MySQL running on Azure. Hence, I am not going into much details here, the goal of this blog was to marry MySQL and Azure and let them evolve. The performance tests executed on this blog purposefully made MySQL run slow - because I wanted to tax the server and extract information out of the disk. The queries executed had a lot of JOIN-s in them - and now MySQL has AQL - which can improve performance on JOIN-s by several times. None of these techniques were used here. These numbers, therefore, should not be interpreted as typical MySQL numbers on Azure.</span></p>
<br />
<p><span style="color: #800080; font-family: helvetica; font-size: x-large;"><strong>Conclusion</strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">MySQL demonstrated that it reads from a RAID 0 array of standard data disks twice as fast than it reads the OS disk. The OS disk on Azure Linux VM-s are optimized for fast boot times. They are not the best options for scaling read/write performance and disk throughout. This is part two of my earlier blog post where I discussed how to set up a RAID 0 array on an Azure Linux VM here:&nbsp;http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/16/set-up-azure-ubuntu-vm-with-xfs-on-raid-zero.aspx</span></p>
<p>&nbsp;</p>
<p><span style="font-family: helvetica; font-size: small;">Note: I have followed up this blog post with <a href="http://blogs.msdn.com/b/opensourcemsft/archive/2015/10/26/set-up-a-mysql-iaas-ndb-cluster-with-four-nodes-on-azure-linux.aspx">another</a> that shows you how to set up a MySQL Cluster on Azure, should help with a new perspective.</span></p>
<p><span style="font-family: helvetica; font-size: small;">Thanks!</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>]]></content:encoded>
    </item>
  </channel>
</rss>