Load balancing across backend servers

Apigee enhances the availability of your API by providing built-in support for load balancing and failover across multiple backend server instances.

TargetServers decouple concrete endpoint URLs from TargetEndpoint configurations. Instead of defining a concrete URL in the configuration, you can configure one or more named TargetServers. Then, each TargetServer is referenced by name in a TargetEndpoint HTTPConnection.

Videos

Watch the following videos to learn more about API routing and load balancing using target servers

Video Description
Load balancing using target servers Load balancing APIs across target servers.
API routing based on environment using target servers Route an API to a different target server based on the environment.

About the TargetServer configuration

A TargetServer configuration consists of a name, a host and a port, with an additional element to indicate whether the TargetServer is enabled or disabled.

The following code provides an example of a TargetServer configuration:

<TargetServer  name="target1">
  <Host>1.mybackendservice.com</Host>
  <Port>80</Port>
  <IsEnabled>true</IsEnabled>
</TargetServer >

The following table describes the elements used to configure a TargetServer:

Name Description Default Required?
name Name of the TargetServer configuration, which must be unique within the environment and contain only alphanumeric characters. N/A Yes
Host Host URL of the backend service (without the protocol). N/A Yes
Port Port on which the backend service is listening. N/A Yes
IsEnabled Flag that specifies whether the TargetServer configuration is enabled or disabled. Using this flag you can take TargetServers out of rotation without modifying the API proxy configuration. A common usage would be to write an app or script that enables or disables TargetServers automatically based on expected capacity requirements, maintenance schedules, and so on. true Yes

See the schema for TargetServer and other entities on GitHub.

Creating TargetServers

Create TargetServers using the Apigee UI or API as described in the following sections.

Apigee UI

To create TargetServers using the Apigee UI:

  1. Sign in to the Apigee UI.
  2. Select Admin > Environments > TargetServers.
  3. From the Environment drop-down list, select the environment to which you want to define a new TargetServer.

    The Apigee UI displays a list of current TargetServers in the selected environment:

  4. Click +Target server to add a new TargetServer to the selected environment.

    The Add target server dialog box displays:

  5. Click Enabled to enable the new TargetServer. definition immediately after you create it.
  6. Enter a name, host, and port in the fields provided. Optionally select the SSL checkbox. For more information about these fields, see TargetServers (4MV4D video).
  7. Click Add.

    Apigee creates the new TargetServer definition.

  8. After you create a new TargetServer, you can edit your API proxy and change the <HTTPTargetConnection> element to reference the new definition.

Apigee API

The following sections provide examples of using the Apigee API to create and list TargetServers.

For more information, see the TargetServers API.

Creating a TargetServer in an environment using the API

To create a TargetServer named target1 that connects to 1.mybackendservice.com on port 80, use the following API call:

curl "https://apigee.googleapis.com/v1/organization/$ORG/environments/$ENV/targetservers" \
  -X POST \
  -H "Content-Type:text/xml" \
  -d '
  <TargetServer name="target1">
   <Host>1.mybackendservice.com</Host>
   <Port>80</Port>
   <IsEnabled>true</IsEnabled>
 </TargetServer>' \
  -H "Authorization: Bearer $TOKEN"
 

Where $TOKEN is set to your OAuth 2.0 access token, as described in Obtaining an OAuth 2.0 access token. For information about the curl options used in this example, see Using curl. For a description of the environment variables used, see Setting environment variables for Apigee API requests.

The following provides an example of the response:

{
  "host" : "1.mybackendservice.com",
  "isEnabled" : true,
  "name" : "target1",
  "port" : 80
}

Create a second TargetServer using the following API call. By defining two TargetServers, you provide two URLs that a TargetEndpoint can use for load balancing:

curl https://apigee.googleapis.com/v1/organization/$ORG/environments/$ENV/targetservers \
  -X POST \
  -H "Content-type:text/xml" \
  -d '<TargetServer  name="target2">
    <Host>2.mybackendservice.com</Host>
    <Port>80</Port>
    <IsEnabled>true</IsEnabled>
  </TargetServer >' \
  -H "Authorization: Bearer $TOKEN"

The following provides an example of the response:

{
  "host" : "2.mybackendservice.com",
  "isEnabled" : true,
  "name" : "target2",
  "port" : 80
}

Listing the TargetServers in an environment using the API

To list the TargetServers in an environment, use the following API call:

curl https://apigee.googleapis.com/v1/organization/$ORG/environments/$ENV/targetservers \
  -H "Authorization: Bearer $TOKEN"

The following provides an example of the response:

[ "target2", "target1" ]

There are now two TargetServers available for use by API proxies deployed in the test environment. To load balance traffic across these TargetServers, you configure the HTTP connection in an API proxy's target endpoint to use the TargetServers.

Configuring a TargetEndpoint to load balance across named TargetServers

Now that you have two TargetServers available, you can modify the TargetEndpoint HTTP connection setting to reference those two TargetServers by name:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
    <LoadBalancer>
      <Server name="target1" />
      <Server name="target2" />
    </LoadBalancer>
    <Path>/test</Path>
  </HTTPTargetConnection>
</TargetEndpoint>

The configuration above is the most basic load balancing configuration. The load balancer supports three load balancing algorithms, Round Robin, Weighted, and Least Connection. Round Robin is the default algorithm. Since no algorithm is specified in the configuration above, outbound requests from the API proxy to the backend servers will alternate, one for one, between target1 and target2.

The <Path> element forms the basepath of the TargetEndpoint URI for all TargetServers. It is only used when <LoadBalancer> is used. Otherwise, it is ignored. In the above example, a request reaching to "target1" will be http://target1/test and so for other TargetServers.

For more information, see TargetEndpoint.

Configuring load balancer options

You can tune availability by configuring the options for load balancing and failover at the load balancer and TargetServer level as described in the following sections.

Algorithm

Sets the algorithm used by <LoadBalancer>. The available algorithms are RoundRobin, Weighted, and LeastConnections, each of which is documented below.

Round robin

The default algorithm, round robin, forwards a request to each TargetServer in the order in which the servers are listed in the target endpoint HTTP connection. For example:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
      <LoadBalancer>
        <Algorithm>RoundRobin</Algorithm>
        <Server name="target1" />
        <Server name="target2" />
      </LoadBalancer>
      <Path>/test</Path>
  </HTTPTargetConnection>
</TargetEndpoint>

Weighted

The weighted load balancing algorithm enables you to configure proportional traffic loads for your TargetServers. The weighted LoadBalancer distributes request to your TargetServers in direct proportion to each TargetServer's weight. Therefore, the weighted algorithm requires you to set a weight attribute for each TargetServer. For example:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
    <LoadBalancer>
      <Algorithm>Weighted</Algorithm>
      <Server name="target1">
        <Weight>1</Weight>
      </Server>
      <Server name="target2">
        <Weight>2</Weight>
      </Server>
    </LoadBalancer>
    <Path>/test</Path>
  </HTTPTargetConnection>
</TargetEndpoint>

In this example, two requests will be routed to target2 for every one request routed to target1.

Least Connection

LoadBalancers configured to use the least connection algorithm route outbound requests to the TargetServer with fewest open HTTP connections. For example:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
      <LoadBalancer>
        <Algorithm>LeastConnections</Algorithm>
        <Server name="target1" />
        <Server name="target2" />
      </LoadBalancer>
  </HTTPTargetConnection>
  <Path>/test</Path>
</TargetEndpoint>

Maximum failures

The maximum number of failed requests from the API proxy to the TargetServer that results in the request being redirected to another TargetServer.

A response failure means Apigee doesn't receive any response from a TargetServer. When this happens, the failure counter increments by one.

However, when Apigee does receive a response from a target, even if the response is an HTTP error (such as 500), that counts as a response from the TargetServer, and the failure counter is reset. To help ensure that bad HTTP responses (such as 500) also increment the failure counter to take an unhealthy server out of load balancing rotation as soon as possible, you can add the <ServerUnhealthyResponse> element with <ResponseCode> child elements to your load balancer configuration. Apigee will also count responses with those codes as failures.

In the following example, target1 will be removed from rotation after five failed requests, including some 5XX responses from the TargetServer.

<TargetEndpoint name="default">
  <HTTPTargetConnection>
      <LoadBalancer>
        <Algorithm>RoundRobin</Algorithm>
        <Server name="target1" />
        <Server name="target2" />
        <MaxFailures>5</MaxFailures>
        <ServerUnhealthyResponse>
            <ResponseCode>500</ResponseCode>
            <ResponseCode>502</ResponseCode>
            <ResponseCode>503</ResponseCode>
        </ServerUnhealthyResponse>
      </LoadBalancer>
      <Path>/test</Path>
  </HTTPTargetConnection>
</TargetEndpoint>

The MaxFailures default is 0. This means that Apigee always tries to connect to the target for each request and never removes the TargetServer from the rotation.

Retry

If retry is enabled, a request will be retried whenever a response failure (I/O error or HTTP timeout) occurs or the response received matches a value set by <ServerUnhealthyResponse>. See Maximum failures above for more on setting <ServerUnhealthyResponse>.

By default <RetryEnabled> is set to true. Set to false to disable retry. For example:

<RetryEnabled>false</RetryEnabled>

IsFallback

One (and only one) TargetServer can be set as the 'fallback' server. The fallback TargetServer is not included in load balancing routines until all other TargetServers are identified as unavailable by the load balancer. When the load balancer determines that all TargetServers are unavailable, all traffic is routed to the fallback server. For example:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
      <LoadBalancer>
        <Algorithm>RoundRobin</Algorithm>
        <Server name="target1" />
        <Server name="target2" />
        <Server name="target3">
          <IsFallback>true</IsFallback>
        </Server>
      </LoadBalancer>
      <Path>/test</Path>
  </HTTPTargetConnection>
</TargetEndpoint>

The configuration above results in round robin load balancing between targets 1 and 2 until both targets 1 and 2 are unavailable. When targets 1 and 2 are unavailable, all traffic is routed to target 3.

Path

Path defines a URI fragment that will be appended to all requests issued by the TargetServer to the backend server.

This element accepts a literal string path or a message template. A message template lets you perform variable string substitution at runtime. For example, in the following target endpoint definition, the value of {mypath} is used for the path:

<HTTPTargetConnection>
    <SSLInfo>
      <Enabled>true</Enabled>
    </SSLInfo>
    <LoadBalancer>
      <Server name="testserver"/>
    </LoadBalancer>
    <Path>{mypath}</Path>
</HTTPTargetConnection>

Configuring a TargetServer for TLS/SSL

If you are using a TargetServer to define the backend service, and the backend service requires the connection to use the HTTPS protocol, then you must enable TLS/SSL in the TargetServer definition. This is necessary because the <Host> tag does not let you specify the connection protocol. Shown below is the TargetServer definition for one-way TLS/SSL where Apigee makes HTTPS requests to the backend service:

<TargetServer name="target1">
  <Host>mocktarget.apigee.net</Host>
  <Port>443</Port>
  <IsEnabled>true</IsEnabled>
  <SSLInfo>
      <Enabled>true</Enabled>
  </SSLInfo> 
</TargetServer>

If the backend service requires two-way, or mutual, TLS/SSL, then you configure the TargetServer by using the same TLS/SSL configuration settings as TargetEndpoints:

<TargetServer  name="TargetServer 1">
    <IsEnabled>true</IsEnabled>
    <Host>www.example.com</Host>
    <Port>443</Port>
    <SSLInfo>
        <Ciphers/>
        <ClientAuthEnabled>true</ClientAuthEnabled>
        <Enabled>true</Enabled>
        <IgnoreValidationErrors>false</IgnoreValidationErrors>
        <KeyAlias>keystore-alias</KeyAlias>
        <KeyStore>keystore-name</KeyStore>
        <Protocols/>
        <TrustStore>truststore-name</TrustStore>
    </SSLInfo>
</TargetServer >

Health monitoring

Health monitoring enables you to enhance load balancing configurations by actively polling the backend service URLs defined in the TargetServer configurations. With health monitoring enabled, a failed TargetServer is automatically put back into rotation when the HealthMonitor determines that the TargetServer is active.

Health monitoring works with <MaxFailures>. Without health monitoring enabled, <MaxFailures> specifies the number of failed requests from the API proxy to the TargetServer that results in the request being redirected to another TargetServer. The failing TargetServer is then taken out of rotation until you redeploy the proxy.

With health monitoring enabled, a failed TargetServer is automatically put back into rotation and no proxy re-deployments are required.

The HealthMonitor acts as a simple client that invokes a backend service over TCP or HTTP:

  • A TCP client simply ensures that a socket can be opened.
  • You configure the HTTP client to submit a valid HTTP request to the backend service. You can define HTTP GET, PUT, POST, or DELETE operations. The response of the HTTP monitor call must match the configured settings in the <SuccessResponse> block.

Successes and failures

When you enable health monitoring, Apigee begins sending health checks to your target server. A health check is a request sent to the TargetServer that determines whether the TargetServer is healthy or not.

A health check can have one of two possible results:

  • Success: The TargetServer is considered healthy when a successful health check occurs. This is typically the result of one or more of the following:
    • TargetServer accepts a new connection to the specified port, responds to a request on that port, and then closes the port within the specified timeframe. The response from the TargetServer contains Connection: close
    • TargetServer responds to a health check request with a 200 (OK) or other HTTP status code that you determine is acceptable.
    • TargetServer responds to a health check request with a message body that matches the expected message body.

    When Apigee determines that a server is healthy, Apigee continues or resumes sending requests to it.

  • Failure: The TargetServer can fail a health check in different ways, depending on the type of check. A failure can be logged when the TargetServer:
    • Refuses a connection from Apigee to the health check port.
    • Does not respond to a health check request within a specified period of time.
    • Returns an unexpected HTTP status code.
    • Responds with a message body that does not match the expected message body.

    When a TargetServer fails a health check, Apigee increments that server's failure count. If the number of failures for that server meets or exceeds a predefined threshold (<MaxFailures>), Apigee stops sending requests to that server.

Enabling a HealthMonitor

To create a HealthMonitor, you add the <HealthMonitor> element to the TargetEndpoint's HTTPConnection configuration for a proxy. You cannot do this in the UI. Instead, you create a proxy configuration and upload it as a ZIP file to Apigee. A proxy configuration is a structured description of all aspects of an API proxy. Proxy configurations consist of XML files in a pre-defined directory structure. For more information, see API Proxy Configuration Reference.

A simple HealthMonitor defines an IntervalInSec combined with either a TCPMonitor or an HTTPMonitor. The <MaxFailures> element specifies maximum number of failed requests from the API proxy to the TargetServer that results in the request being redirected to another TargetServer. By default <MaxFailures> is 0, which means Apigee performs no corrective action. When configuring a health monitor, ensure that you set <MaxFailures> in the <HTTPTargetConnection> tag of the <TargetEndpoint> tag to a non-zero value.

TCPMonitor

The configuration below defines a HealthMonitor that polls each TargetServer by opening a connection on port 80 every five seconds. (Port is optional. If not specified, the TCPMonitor port is the TargetServer port.)

  • If the connection fails or takes more than 10 seconds to connect, then the failure count increments by 1 for that TargetServer.
  • If the connection succeeds, then the failure count for the TargetServer is reset to 0.

You can add a HealthMonitor as a child element of the TargetEndpoint's HTTPTargetConnetion element, as shown below:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
      <LoadBalancer>
        <Algorithm>RoundRobin</Algorithm>
        <Server name="target1" />
        <Server name="target2" />
        <MaxFailures>5</MaxFailures>
      </LoadBalancer>
      <Path>/test</Path>
      <HealthMonitor>
        <IsEnabled>true</IsEnabled>
        <IntervalInSec>5</IntervalInSec>
        <TCPMonitor>
            <ConnectTimeoutInSec>10</ConnectTimeoutInSec>
            <Port>80</Port>
        </TCPMonitor>
      </HealthMonitor>
  </HTTPTargetConnection>
. . .

HealthMonitor with TCPMonitor configuration elements

The following table describes the TCPMonitor configuration elements:

Name Description Default Required?
IsEnabled A boolean that enables or disables the HealthMonitor. false No
IntervalInSec The time interval, in seconds, between each polling TCP request. 0 Yes
ConnectTimeoutInSec Time in which connection to the TCP port must be established to be considered a success. Failure to connect in the specified interval counts as a failure, incrementing the load balancer's failure count for the TargetServer. 0 Yes
Port Optional. The port on which the TCP connection will be established. If not specified, the TCPMonitor port is the TargetServer port. 0 No

HTTPMonitor

A sample HealthMonitor that uses an HTTPMonitor will submit a GET request to the backend service once every five seconds. The sample below adds an HTTP Basic Authorization header to the request message. The Response configuration defines settings that will be compared against actual response from the backend service. In the example below, the expected response is an HTTP response code 200 and a custom HTTP header ImOK whose value is YourOK. If the response does not match, then the request will treated as a failure by the load balancer configuration.

The HTTPMonitor supports backend services configured to use HTTP and one-way HTTPS protocols. However, it does not support two-way HTTPS, also called two-way TLS/SSL.

Note that all of the Request and Response settings in an HTTP monitor will be specific to the backend service that must be invoked.

<HealthMonitor>
  <IsEnabled>true</IsEnabled>
  <IntervalInSec>5</IntervalInSec>
  <HTTPMonitor>
    <Request>
      <ConnectTimeoutInSec>10</ConnectTimeoutInSec>
      <SocketReadTimeoutInSec>30</SocketReadTimeoutInSec>
      <Port>80</Port>
      <Verb>GET</Verb>
      <Path>/healthcheck</Path>
      <Header name="Authorization">Basic 12e98yfw87etf</Header>
    </Request>
    <SuccessResponse>
      <ResponseCode>200</ResponseCode>
      <Header name=”ImOK”>YourOK</Header>
    </SuccessResponse>
  </HTTPMonitor>
</HealthMonitor>

HealthMonitor with HTTPMonitor configuration elements

The following table describes the HTTPMonitor configuration elements:

Name Description Default Required?
IsEnabled A boolean that enables or disables the HealthMonitor. false No
IntervalInSec The time interval, in seconds, between each polling request. 0 Yes
Request

Configuration options for the outbound request message sent by the HealthMonitor to the TargetServers in the rotation.

The Path does not support variables.

N/A Yes
ConnectTimeoutInSec Time, in seconds, in which the TCP connection handshake to the HTTP service must complete to be considered a success. Failure to connect in the specified interval counts as a failure, incrementing the LoadBalancer's failure count for the TargetServer. 0 No
SocketReadTimeoutInSec Time, in seconds, in which data must be read from the HTTP service to be considered a success. Failure to read in the specified interval counts as a failure, incrementing the LoadBalancer's failure count for the TargetServer. 0 No
Port The port on which the HTTP connection to the backend service will be established. N/A No
Verb The HTTP verb used for each polling HTTP request to the backend service . N/A No
Path The path appended to the URL defined in the TargetServer. Use the path element to configure a 'polling endpoint' on your HTTP service. N/A No
Payload The HTTP body generated for each polling HTTP request. Note that this element is not required for GET requests. N/A No
SuccessResponse Matching options for the inbound HTTP response message generated by the polled backend service. Responses that do not match increment the failure count by 1. N/A No
ResponseCode The HTTP response code expected to be received from the polled TargetServer. A code different than the code specified results in a failure, and the count being incremented for the polled backend service. You can define multiple ResponseCode elements. N/A No
Headers A list of one or more HTTP headers and values expected to be received from the polled backend service. Any HTTP headers or values on the response that are different from those specified result in a failure, and the count for the polled TargetServer is incremented by 1. You can define multiple Header elements. N/A No