Chapter 66. Master Component


Abstract

The Master component provides a failover mechanism for Apache Camel endpoints, based on Fuse Fabric. Using the Master component, you can make almost any type of Apache Camel endpoint participate in a failover cluster, simply by prefixing the consumer endpoints with master:ClusterID:.

Dependencies

The Master component can only be used in the context of a fabric-enabled Red Hat JBoss Fuse container. You must ensure that the fabric-camel feature is installed. If necessary, you can install it using the following console command:
karaf@root> features:install fabric-camel
Alternatively, if you decide to use a custom feature to deploy your application, you can ensure that the fabric-camel feature is installed by including it in your feature definition. For example:
<?xml version="1.0" encoding="UTF-8"?>
<features>
    <feature name="fabric-component-example">
        <feature>fabric-camel</feature>
        <bundle>URIforMyBundle</bundle>
        <!-- Specify any other required bundles or features -->
        ...
    </feature>
</features>
For more details about features, see Deploying Features.

URI format

A Master endpoint can only be used as a consumer endpoint. It has the following URI format:
master:ClusterID:PublishedURI[?Options]
Where the URI, PublishedURI, is published in the fabric registry and associated with the ClusterId cluster.

URI options

The Master component itself does not support any URI options. It is possible, however, to specify options for the published URI. These options are stored in the fabric registry as part of the URI and are used as follows:
  • Server-only options—options that are applicable only to the server are applied to the server endpoint (consumer endpoint) at run time.
  • Client-only options—options that are applicable only to the client are applied to the client endpoint (producer endpoint) at run time.
  • Common options—options common to the client and the server are applied to both.

Master-slave failover cluster

Figure 66.1, “Failover Cluster with Master Endpoints” gives an overview of how Master endpoints enable you to create a failover cluster.

Figure 66.1. Failover Cluster with Master Endpoints

Failover Cluster with Master Endpoints
The sample failover cluster consists of two servers, with the URIs, master:FD:jetty:http://0.0.0.0:9090 and master:FD:jetty:http://0.0.0.0:9191. When the servers are created, they compete to grab a lock on the FD entry in the fabric registry. Whichever server manages to get the lock (in this example, the server listening on port 9090) becomes the master, registering its URI under the cluster ID, FD, and activating its route. The other servers remain slaves: they are not able to register their URIs under the FD cluster ID, their routes do not get activated, and they continue to try the lock on the FD registry entry, in case the master server should fail.
The client must be defined using a Fabric endpoint (see Fabric). In this example, when the client route starts, it looks up the ID, FD, to find the master's endpoint URI, and then connects to the master server.
At some point, the master server could fail. When this happens, the following sequence of events occurs:
  1. Now that the master has died, the lock is free again. One of the slaves will succeed in grabbing the lock and become the new master.
  2. The new master registers its URI under the FD cluster ID, replacing the URI of the old master.
  3. The auto-reconnect capability of the Fabric endpoint in the client is activated. The client detects that the master has died, goes back to the fabric registry to obtain the URI of the new master, and then connects to the new master.

Creating a failover cluster

To create a failover cluster, all that you have to do is to publish more than one endpoint URI under the same cluster ID, using Master endpoints. Now, when a client looks up that cluster ID, it gets the URI of the currently active server in the cluster (the master). If the original server should fail, the client will automatically go back to the fabric registry to get the URI of the new master and then connect to the new master.
The servers in the failover cluster have almost the same configuration. Essentially, the only difference between them is that they publish an endpoint URI with a different hostname and/or IP port. Instead of creating a separate OSGi bundle for every single server in the failover cluster, however, it is better to define a template that enables you to specify the host or port using a configuration variable.
Example 66.1, “Server Template for a Failover Cluster” illustrates the template approach to defining servers in a failover cluster, highlighting the relevant parts of the code.

Example 66.1. Server Template for a Failover Cluster

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
           xsi:schemaLocation="
           http://www.osgi.org/xmlns/blueprint/v1.0.0
           http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

    <!-- osgi blueprint property placeholder -->
    <cm:property-placeholder id="placeholder" persistent-id="masterCamel">
        <cm:default-properties>
            <cm:property name="portNumber" value="8181"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <reference id="org.fusesource.fabric.zookeeper.IZKClient"
               interface="org.fusesource.fabric.zookeeper.IZKClient" />

    <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
        <route id="failover-server">
            <from uri="master:FailoverDemo:jetty:http://0.0.0.0:{{portNumber}}/master"/>
            <log message="Request received : ${body}"/>
            <setHeader headerName="karaf.name">
                <simple>${sys.karaf.name}</simple>
            </setHeader>
            <transform>
                <simple>Response from Zookeeper agent</simple>
            </transform>
        </route>
    </camelContext>

</blueprint>
A reference to the org.fusesource.fabric.zookeeper.IZKClient OSGi service is created using the reference element. This reference is needed, because the Master component implicitly looks for an IZKClient object in the bean registry and uses this object to connect to the underlying fabric.
The route starts with a from command that specifies a Master endpoint URI. The Master endpoint registers the given Jetty URI under the FailoverDemo cluster ID, which effectively means that the server joins the FailoverDemo failover cluster.
This example also illustrates how to use the OSGi blueprint property placehoder. The property placehoder mechanism enables you to read property settings from the OSGi Config Admin service and substitute the properties in the blueprint configuration file. In this example, the property placeholder accesses properties from the masterCamel persistent ID. A persistent ID in the OSGi Config Admin service identifies a collection of related property settings. After initializing the property placeholder, you can access any property values from the masterCamel persistent ID using the syntax, {{PropName}}.
The Master endpont URI exploits the property placeholder mechanism to substitute the value of the Jetty port, {{portNumber}}, at run time. At deploy time, you can specify the value of the portName property. For example, if using a custom feature, you could specify the property in the feature definition (see Add OSGi configurations to the feature). Alternatively, you can specify configuration properties when defining deployment profiles in the Fuse Management Console.

Looking up an endpoint URI

To look up a URI in the fabric registry, simply specify the fabric endpoint URI with an ID, in the format, fabric:ClusterID. This syntax is used in a producer endpoint (for example, an endpoint that appears in a to DSL command).
Example 66.2, “Looking up a URI” shows a route that implements a HTTP client, where the HTTP endpoint is discovered dynamically at run time, by looking up the specified ID, FailoverDemo, in the fabric registry.

Example 66.2. Looking up a URI

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
           http://www.osgi.org/xmlns/blueprint/v1.0.0
           http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

  <reference id="org.fusesource.fabric.zookeeper.IZKClient"
             interface="org.fusesource.fabric.zookeeper.IZKClient"/>

  <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint">

    <route id="failover-client">
      <from uri="timer://foo?fixedRate=true&amp;period=10000"/>
      <setBody>
          <simple>Hello from Zookeeper server</simple>
      </setBody>
      <to uri="fabric:FailoverDemo"/>
      <log message=">>> ${body} : ${header.karaf.name}"/>
    </route>

  </camelContext>

</blueprint>
The client route also needs a reference to the org.fusesource.fabric.zookeeper.IZKClient OSGi service, which the Fabric component uses to connect to the underlying fabric.
Because the route is implemented in blueprint XML, you would normally add the file containing this code to the src/main/resources/OSGI-INF/blueprint directory of a Maven project.

OSGi bundle plug-in configuration

When defining an OSGi bundle that uses Master endpoints, the Import-Package bundle header must be configured to import the following Java packages:
org.fusesource.fabric.zookeeper.spring
org.fusesource.fabric.zookeeper
For example, assuming that you use Maven to build your application, Example 66.3, “Maven Bundle Plug-In Configuration” shows how you can configure the Maven bundle plug-in to import the required packages.

Example 66.3. Maven Bundle Plug-In Configuration

<project ... >
  ...
  <build>
    <defaultGoal>install</defaultGoal>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
            <Import-Package>
              org.fusesource.fabric.zookeeper.spring,
              org.fusesource.fabric.zookeeper,
              *
            </Import-Package>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

© 2024 Red Hat, Inc.