Monday, August 12, 2013

Open Source Load Balancer for Exchange 2010

On many installations of Exchange 2010, we decided to use DNS Round Robin as our Load Balancer method for the CAS services. This works well until one of the CAS server fails or is taked offline. DNS Round robin doesn't check service status so it keeps returning the failed server IP address even if its offline. So clients will receive a connection error until the Browser cookie expires or DNS TTL expires on the client OS. This is a big head-each because some clients are working OK (the ones that are using the online CAS) and some are not.

Another solution its to use Windows Network Load Balance (WNLB), a windows built-in Feature that works, but not very well, specially in  virtualized environments. It generates a high amount of traffic and... Exchange 2010 with WNLB is not supported by Microsoft :( .

There are out there many commercial solutions like F5, BigIP or Cisco CSS, but they are expensive and cost is high for only one service needed for these products. Digging into Open Source solutions, I found relayd (previously hoststated). Relayd looks very good, but seems that his power is to interact with OpenBSD PF which I like too, but for doing only Load Balancing, I thing its too much (I will try it in the future).

The Load Balancing tool of my choice is haproxy. This tools is very cool, its latest stable version 1.4 was released on 2013/06/17 meaning that its an active project and continues in development (v1.5-dev19). This tool is used by other network products as load balancer or high availavility module. Its supported by Linux, Solaris, FreeBSD and OpenBSD. I will use FreeBSD as Operating System for the  HAProxy. This might not be the best recommended option but we are not an ISP needed hundreds of thousand of connections, only need some thousand. If you need very high speeds like 10Gbps kinks, read the haproxy supported platforms documentation, they recommend using haproxy on Linux kernel 2.6.32 and above for a better performance and high speed bandwidths (above 10Gbps).  


For my scenario, i used VirtualBox 4.2.16 as my virtualization platform. I created the following vm's:

  • lb1.- HAProxy Box. FreeBSD 9.1 x86, 2 NIC's
  • ex1.- Exchange 2010 sp2 Box, Windows 2008R2, CAS, HT and Mailbox Roles.
  • ex2.- Exchange 2010 sp2 Box, Windows 2008R2, CAS, HT and Mailbox Roles.
This is the Layout for the lab:



I divided this blog in three sections:
  1. Install the Loab Balancer OS and HAProxy package
  2. Configure Exchange CAS services 
  3. Configure HAProxy


1.- I created the virtual machine with two NIC's, one for the Load Balancer and other for Administration.First let start with the OS installation. I will use VirtualBox for the lab demostration. Download the FreeBSD 9.1 ISO image from the FreeBSD FTP site. Install FreeBSD using the default options, it will take you 10-15 mins only. 

After OS finishes, first thing its to install the Virtual Box Addtions:


# cd /usr/ports/emulators/virtualbox-ose-additions/

# make install clean BATCH=yes

===>  License GPLv2 accepted by the user
===>  Extracting for virtualbox-ose-additions-4.1.22
=> SHA256 Checksum mismatch for VirtualBox-4.1.22.tar.bz2.
===>  Refetch for 1 more times files: VirtualBox-4.1.22.tar.bz2
===>  License GPLv2 accepted by the user
=> VirtualBox-4.1.22.tar.bz2 doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch http://download.virtualbox.org/virtualbox/4.1.22/VirtualBox-4.1.22.tar.bz2
fetch: http://download.virtualbox.org/virtualbox/4.1.22/VirtualBox-4.1.22.tar.bz2: Moved Temporarily
=> Attempting to fetch http://tmp.chruetertee.ch/VirtualBox-4.1.22.tar.bz2

VirtualBox-4.1.22.tar.bz2                       0% of   69 MB   44 kBps 27m53s

After guest addtions, we install the HAProxy package from the ports:

# cd /usr/ports/net/haproxy
# make install clean
===> Installing rc.d startup script(s)

*************************************************
*  Congratulations!  Haproxy is now installed.  *
*************************************************

Check the following directories for further info:
  documentation:  '/usr/local/share/doc/haproxy'
  examples:       '/usr/local/share/examples/haproxy'

rc.conf variables listing can be found in:

  '/usr/local/etc/rc.d/haproxy'


Modify the file /etc/rc.conf and add the following lines

haproxy_enable=""YES
haproxy_config="/usr/local/etc/haproxy.cfg"

The previos lines will start haproxy at bootup.


2.- For the Exchange server side, we need to set the TCP ports the RPC Client Access service and the Address Book Service. Why?..  Because this two services use MAPI which uses RCP connections. RPC uses TCP random ports, we would need to load balance across all thid 65K ports.. so we fix this to only two ports (59532 and 59533).

To do this for the RPC service, on each CAS open regedit.exe and Navigate to

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MSExchangeRPC\

Create the key named "ParametersSystem" and create a REG_DWORD setting named "TCP/IP Port" with value of 59532 (decimal):



Now for the AB service, navigate to 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MSExchangeAB

Create the key named "Parameters" and create the REG_SZ setting named "RpcTcpPort" with the value of  59533.




Restart the so the changes be reflected.

To verify that the settings have applied, open an elevated command prompt window and type 'netstat -an | findstr "5953*"':



Both ports should be listening now.



3.- Now lets configure our Load Balncer. Create the file haproxy.cfg:

# vi /usr/local/etc/haproxy.cfg


You can copy and paste the following to the file and will explain later:

#### Begin File ####

global
        #uid 99
        #gid 99
        daemon
        stats socket /var/run/haproxy.stat mode 600 level admin
        maxconn 40000
        ulimit-n 81000
        pidfile /var/run/haproxy.pid

defaults
        mode    http
        contimeout      4000
        clitimeout      3600000
        srvtimeout      3600000
        balance roundrobin

listen  Exchange2010 192.168.100.20:80
        bind 192.168.100.20:25
        bind 192.168.100.20:110,192.168.100.20:135
        bind 192.168.100.20:139,192.168.100.20:443
        bind 192.168.100.20:59532,192.168.100.20:59533
        bind 192.168.100.20:6001-6004
        bind 192.168.100.20:993-995
        mode    tcp
        option  persist
        balance roundrobin
        stick-table type ip size 10240k expire 30m
        stick on src
        server CAS1 192.168.100.11 weight 1 check port 80 inter 5000 rise 2 fall 3
        server CAS2 192.168.100.12 weight 1 check port 80 inter 5000 rise 2 fall 3
        option redispatch
        option abortonclose
        maxconn 40000

listen  stats :7000
        stats   enable
        stats   uri /
        option  httpclose

        stats   auth admin01:Pa$$w0rd

####End File ####


The Global section which sets process-wide information and OS-specific. They are generally set once for all and do not need being changed once correct. Some of them have command-line equivalents. See the man file for more options.


Proxy configuration can be located in a set of sections:
 - defaults 
 - frontend 
 - backend  
 - listen   

The Defaults section sets default parameters for all other sections following
its declaration. 


A "frontend" section describes a set of listening sockets accepting client
connections.

A "backend" section describes a set of servers to which the proxy will connect
to forward incoming connections.

A "listen" section defines a complete proxy with its frontend and backend
parts combined in one section. It is generally useful for TCP-only traffic.


For our Load Balancer the "listen" section is where we configure the settings for Exchange. We name the section "Exchange2010" and here is where we bind each service that our balancer will be handling:


135 - RPC 
80/443 - OWA/ActiveSync/OutlookAnywhere
110 : POP
139 : Netbios
60000/60001 - These are the ones we just set on exchange server (For Mail and Address book) 
993-995: SSL POP/IMAP
6001 - 6004 : Exchange Information Store

After binding, the proxy will use Round Robin and peristance of 30 minutes. The affinity will be source IP. The master of the things... Will use port 80 to check the availability of the service. The option 'redispatch' tells to look another sever is check fails.

Last 'listen' section are the stats, in these section HAProxy listens on port 7000 (http) autenticating using the user and password provided. 

This is a big difference with NLB, we can monitor the Balancer status and see connections, response times, etc.




Don't forget to update your DNS records (owa, async, autodiscover,ews,CasArray,OAnywhere) to point to the VIP of the balancer.

Now if you have MS-NLB.. you have just realized that you are wasting resources and efforts maintaining a useless service..  Change to HAPROXY and give me your thoughts.

Hope this helps you.

Thursday, July 11, 2013

Get Exchange Roll up script

One of the tasks that I do as Exchange Admin is to patch and upgrade Exchange to the latest version. I cross with the issue about getting the Exchange Roll up version of my 63 Exchange Servers. There are many scripts out there but none satisfied to me.  So I created this power shell script that displays the Roll up version from Exchange 2007 to 2013. You must run it from Exchange Management Shell and of course need to have permissions to execute the 'Get-ExchangeServer' cmdlet. The results are send to console, but you can modify to export the results to a .csv file.

Here is an output of the results:



Well, hope that this script saves you many hours of work like it did it for me.

######################################

## GetExchanegRollUp.ps1 ##
## Creted By: Carlos Ramirez ##

Clear-Host
$ErrorActionPreference = "SilentlyContinue"
$tmpFilePath="c:\temp\E2k.csv"


#Get-ExchangeServer | where {$_.ServerRole -ne "Edge" -and $_.AdminDisplayVersion -like "Version 14*"} |  select-object  @{Name="svrName";Expression={$_.name}},@{Name="exDataPath";Expression={$_.DataPath}} | export-csv $tmpFilePath -notype -force

Get-ExchangeServer | Sort-Object $_.name | select-object  @{Name="svrName";Expression={$_.name}},@{Name="exDataPath";Expression={$_.DataPath}},@{Name="EXVersion";Expression={$_.AdminDisplayVersion}} | export-csv $tmpFilePath -notype -force


$Filecsv = import-csv $tmpFilePath
$BuildPath = $null
foreach($File in $Filecsv)
  {
   $ServerName = $File.svrName
   $MailboxPath = $File.exDataPath
   #echo $ServerName $MailboxPath
   $arrMailboxPath = $MailboxPath.split("\")
   $strBuildPath = $null
   for($i=0;$i-le $arrMailboxPath.length-2;$i++)
      {
  $strBuildPath=$strBuildPath + $arrMailboxPath[$i] + "\"
 } #End for
   
   $fixBuildPath = $strBuildPath.replace(":","$")
   $BuildPath = "\\" + $ServerName + "\" + $fixBuildPath + "Bin\ExSetup.exe"
   
   $ExBuildFile = get-item $BuildPath
   $ExBuildVersion = $ExBuildFile.VersionInfo.ProductVersion
   
   switch($ExBuildVersion)
      { "14.00.0639.021" {write-host $ServerName "-> Microsoft Exchange Server 2010 RTM" -foregroundcolor "green"}
"14.00.0682.001" {write-host $ServerName "-> Update Rollup 1 for Exchange Server 2010" -foregroundcolor "green"}
"14.00.0689.000" {write-host $ServerName "-> Update Rollup 2 for Exchange Server 2010" -foregroundcolor "green"}
"14.00.0694.000" {write-host $ServerName "-> Update Rollup 3 for Exchange Server 2010" -foregroundcolor "green"}
"14.00.0702.001" {write-host $ServerName "-> Update Rollup 4 for Exchange Server 2010" -foregroundcolor "green"}
"14.00.0726.000" {write-host $ServerName "-> Update Rollup 5 for Exchange Server 2010" -foregroundcolor "green"}
"14.01.0218.015" {write-host $ServerName "-> Microsoft Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0255.002" {write-host $ServerName "-> Update Rollup 1 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0270.001" {write-host $ServerName "-> Update Rollup 2 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0289.003" {write-host $ServerName "-> Update Rollup 3 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0289.007" {write-host $ServerName "-> Update Rollup 3-v3 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0323.001" {write-host $ServerName "-> Update Rollup 4 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0323.006" {write-host $ServerName "-> Update Rollup 4-v2 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0339.001" {write-host $ServerName "-> Update Rollup 5 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0355.002" {write-host $ServerName "-> Update Rollup 6 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0421.000" {write-host $ServerName "-> Update Rollup 7 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0421.002" {write-host $ServerName "-> Update Rollup 7-v2 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0421.003" {write-host $ServerName "-> Update Rollup 7-v3 for Exchange Server 2010 SP1" -foregroundcolor "green"}
"14.01.0438.000" {write-host $ServerName "-> Update Rollup 8 for Exchange Server 2010 SP1" -foregroundcolor "green"}
    "14.02.0247.005" {write-host $ServerName "-> Microsoft Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0283.003" {write-host $ServerName "-> Update Rollup 1 for Exchange Server 2010 SP2"   -foregroundcolor "green"}
"14.02.0298.004" {write-host $ServerName "-> Update Rollup 2 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0309.002" {write-host $ServerName "-> Update Rollup 3 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0318.002" {write-host $ServerName "-> Update Rollup 4 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0318.004" {write-host $ServerName "-> Update Rollup 4-v2 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0328.005" {write-host $ServerName "-> Update Rollup 5 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0328.010" {write-host $ServerName "-> Update Rollup 5-v2 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.02.0342.003" {write-host $ServerName "-> Update Rollup 6 for Exchange Server 2010 SP2"  -foregroundcolor "green"}
"14.03.0123.004" {write-host $ServerName "-> Microsoft Exchange Server 2010 SP3" -foregroundcolor "green"}
"14.03.0146.000" {write-host $ServerName "-> Update Rollup 1 for Exchange Server 2010 SP3" -foregroundcolor "green"}

default {write-host $ServerName "-> Undetermined version"  -foregroundcolor "red"}
 } #End switch

   } #End foreach
   

########################################

C.R.