Since Exchange 2007 client connections are handled by the Client Access Server role. With Exchange 2010, Microsoft has introduced the concept of the Client Access Server Array (CAS Array). A CAS Array is required, when internal and external client connections should be load balanced over multiple client access servers. Many client access protocols in Exchange 2010 require session affinity. This means, that the connection between the client and a particular client access server must persist. This requires application-level load balancing for Exchange 2010 and Microsoft recommends this explicitly. Microsoft dropped the concept of the CAS Array in Exchange 2013 and implemented much more logic into the Exchange 2013 Client Access Server role. There is no more need for session affinity in any client access protocol used in Microsoft Exchange 2013. Connections to a Exchange 2013 client access servers can be directed to an available server. A simple DNS round-robin works, but if a server fails, DNS would not handle this.You can use Windows Network Load Balancing (WNLB), but it has several limitations and downsides. I blogged about one of them in my blog post Flooded network due HP Networking Switches & Windows NLB. The other point is, that you can’t use it when you build a two server CAS/ DAG Exchange 2013 environment: You can’t use WNLB on servers that have the Microsoft Failover Cluster role installed. At this point HAProxy comes into play.
HAProxy is a small and reliable TCP/ HTTP Load Balancer. HAproxy is Open Source and supports in its current release everything you need, e.g. support for SSL, IPv6, keep-alive etc. Sometimes there is no need for cost intensive or complex Load Balancers, e.g. for lab setups. HAProxy is small and easy to set up. All you need is your favorite Linux distribution in its current release. I like CentOS and I decied to use CentOS 7 to setup a small HAProxy deployment in my lab.
I have installed a minimal installation of CentOS 7 in a VM (2 GB memory, 1x vCPU, 1x VMXNET3 adapter). You can easily install HAProxy using YUM.
[[email protected] ~]# yum install haproxy Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: ftp.hosteurope.de * extras: centos.intergenia.de * updates: centos.intergenia.de Resolving Dependencies --> Running transaction check ---> Package haproxy.x86_64 0:1.5.2-3.el7_0 will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================== Package Arch Version Repository Size ============================================================================== Installing: haproxy x86_64 1.5.2-3.el7_0 updates 812 k Transaction Summary ============================================================================== Install 1 Package Total download size: 812 k Installed size: 2.5 M Is this ok [y/d/N]: y Downloading packages: haproxy-1.5.2-3.el7_0.x86_64.rpm | 812 kB 00:00:03 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : haproxy-1.5.2-3.el7_0.x86_64 1/1 Verifying : haproxy-1.5.2-3.el7_0.x86_64 1/1 Installed: haproxy.x86_64 0:1.5.2-3.el7_0 Complete!
That’s it. There’s nothing more to do. Now let’s configure HAproxy.
Before you edit the configuration file, take a backup of the /etc/haproxy/haproxy.conf. My haproxy.conf looks like this.
defaults log global option tcplog option dontlognull option redispatch retries 3 timeout http-request 10s timeout http-keep-alive 10s timeout check 10s timeout server 10s timeout connect 10s timeout client 10s listen stats 192.168.200.103:4711 mode http stats enable stats hide-version stats uri / listen e2k13 192.168.200.103:443 mode tcp option ssl-hello-chk option http-keep-alive balance roundrobin stick-table type ip size 20k expire 15m stick on src timeout server 1m timeout connect 1m timeout client 5m server exchange1 192.168.200.100:443 check server exchange2 192.168.200.102:443 check
Nothing fancy. 192.168.200.103 is the IP of my CentOS 7 VM. 192.168.200.100 and 192.168.200.102 are two Exchange 2013 servers (CAS & Mailbox). To get some stats, I added the listen stats section to my config. Please note, that this config passes HTTPS traffic to the backend servers! SSL traffic is not terminated at the HAProxy itself. Therefore you need valid certificates on all of your client access servers. When you finished your config, you can start the HAProxy and check the success with netstat.
[[email protected] ~]# systemctl start haproxy.service [[email protected] ~]# netstat -tulpen Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 0 15431 1309/master tcp 0 0 192.168.200.103:443 0.0.0.0:* LISTEN 0 29484 1979/haproxy tcp 0 0 192.168.200.103:4711 0.0.0.0:* LISTEN 0 29482 1979/haproxy tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 14752 812/sshd tcp6 0 0 ::1:25 :::* LISTEN 0 15432 1309/master tcp6 0 0 :::22 :::* LISTEN 0 14754 812/sshd udp 0 0 0.0.0.0:5353 0.0.0.0:* 70 13708 541/avahi-daemon: r udp 0 0 0.0.0.0:42748 0.0.0.0:* 70 13709 541/avahi-daemon: r
You need to create DNS A-Records that points to the IP address of the HAProxy. Then add this A-Records as internal and external hostnames for the Exchange 2013 virtual directories. Here’s an example for Outlook Anywhere:
[PS] C:\windows\system32>Get-OutlookAnywhere | select servername, *hostname ServerName ExternalHostname InternalHostname ---------- ---------------- ---------------- EXCHANGE1 cas.terlisten-consulting.de mail.vcloudlab.local EXCHANGE2 cas.terlisten-consulting.de mail.vcloudlab.local
A change to the Outlook Anywhere config can take up to 15 minutes, until clients discover the change. As you can see, the client in my lab uses the internal hostname.
Both Exchange servers receive requests. This is screenshot is taken from the HAProxy stats website (click to enlarge).
I really like HAProxy. It’s perfect for lab environments or small deployments, not only to load balance HTTP/ HTTPS requests for Microsoft Exchange 2013.