此内容没有您所选择的语言版本。
Chapter 44. Fabric Component
Abstract
The Fabric component implements a location discovery mechanism for Apache Camel endpoints. This mechanism can also be used to provide load-balancing over a cluster of endpoints. On the client side (producer endpoints), endpoints are represented by an abstract ID and at run time, the ID is resolved to a specific endpoint URI. Because the URI is stored in a distributed registry (provided by Fuse Fabric), this enables you to create flexible applications whose topology can be specified at deploy time and updated dynamically.
Dependencies
The Fabric 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:
In the context of Fabric, you install a feature by adding it to the relevant profile. For example, if you are using a profile called
my-master-profile
, you would add the fabric-camel
feature by entering the following console command:
karaf@root> fabric:profile-edit --features fabric-camel my-master-profile
URI format
A fabric endpoint has the following URI format:
fabric:ClusterID[:PublishedURI[?Options]]
The format of the URI depends on whether it is used to specify a consumer endpoint or a producer endpoint.
For a Fabric producer endpoint, the URI format is:
fabric:ClusterID:PublishedURI[?Options]
Where the specified URI,
PublishedURI
, is published in the fabric registry and associated with the ClusterId
cluster. The options, Options
, are used when creating the producer endpoint instance, but the options are not published with the PublishedURI
in the fabric registry.
For a Fabric consumer endpoint, the URI format is:
fabric:ClusterID
Where the client looks up the ID,
ClusterId
, in the fabric registry to discover the URI to connect to.
URI options
The Fabric 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.
Use cases for fabric endpoints
Fabric endpoints essentially provide a discovery mechanism for Apache Camel endpoints. For example, they support the following basic use cases:
Location discovery
Figure 44.1, “Location Discovery through Fabric” gives an overview of how Fabric endpoints enable location discovery at run time.
Figure 44.1. Location Discovery through Fabric
The server side of this application is defined by a route that starts with a Fabric endpoint, where the Fabric endpoint publishes the URI,
jetty:http://0.0.0.0:9090
. When this route is started, it automatically registers the Jetty URI in the fabric registry, under the cluster ID, foo
.
The client side of the application is defined by a route that ends with the Fabric endpoint,
fabric:foo
. Now, when the client route starts, it automatically looks up the ID, foo
, in the fabric registry and retrieves the associated Jetty endpoint URI. The client then creates a producer endpoint using the discovered Jetty URI and connects to the corresponding server port.
Load-balancing cluster
Figure 44.2, “Load Balancing through Fabric” gives an overview of how Fabric endpoints enable you to create a load-balancing cluster.
Figure 44.2. Load Balancing through Fabric
In this case, two Jetty servers are created, with the URIs,
jetty:http://0.0.0.0:9090
and jetty:http://0.0.0.0:9191
. Because these published URIs are both prefixed by fabric:foo:
, both of the Jetty URIs are registered under the same cluster ID, foo
, in the fabric registry.
Now, when the client routes starts, it automatically looks up the ID,
foo
, in the fabric registry. Because the foo
ID is associated with multiple endpoint URIs, fabric implements a random load balancing algorithm to choose one of the available URIs. The client then creates a producer endpoint, using the chosen URI.
Auto-reconnect feature
Fabric endpoints support auto-reconnection. So, if a client endpoint (producer endpoint) loses its connection to a server endpoint, it will automatically go back to the fabric registry, ask for another URI, and then connect to the new URI.
Publishing an endpoint URI
To publish an endpoint URI,
PublishedURI
, in the fabric registry, define a fabric endpoint with the publisher syntax, FabricScheme:ClusterID:PublishedURI
. Note that this syntax can only be used in a consumer endpoint (that is, an endpoint that appears in a from
DSL command).
Example 44.1, “Publishing a URI ” shows a route that implements a Jetty HTTP server, where the Jetty URI is published to the fabric registry under the ID,
cluster
. The route is a simply HTTP server that returns the constant message, Response from Zookeeper agent
, in the body of the HTTP response.
Example 44.1. Publishing 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"> <bean id="fabric-camel" class="io.fabric8.camel.FabricComponent"/> <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint"> <route id="fabric-server"> <from uri="fabric-camel:cluster:jetty:http://0.0.0.0:9090/fabric"/> <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>
Note the following points about the preceding sample:
- The Fabric component uses the
CuratorFramework
object to connect to the ZooKeeper server (Fabric registry), where the reference to theCuratorFramework
object is provided automatically. - The
from
DSL command defines the fabric URI,fabric-camel:cluster:jetty:http://0.0.0.0:9090/fabric
. At run time, this causes two things to happen:- The specified
jetty
URI is published to the fabric registry under the cluster ID,cluster
. - The Jetty endpoint is activated and used as the consumer endpoint of the route (just as if it had been specified without the
fabric-camel:cluster:
prefix).
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.
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,
FabricScheme:ClusterID
. This syntax is used in a producer endpoint (for example, an endpoint that appears in a to
DSL command).
Example 44.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,
cluster
, in the fabric registry.
Example 44.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"> <bean id="fabric-camel" class="io.fabric8.camel.FabricComponent"/> <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint"> <route id="fabric-client"> <from uri="timer://foo?fixedRate=true&period=10000"/> <setBody> <simple>Hello from Zookeeper server</simple> </setBody> <to uri="fabric-camel:cluster"/> <log message=">>> ${body} : ${header.karaf.name}"/> </route> </camelContext> <reference interface="org.apache.camel.spi.ComponentResolver" filter="(component=jetty)"/> </blueprint>
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.
Load-balancing example
In principle, implementing load balancing is easy using fabric endpoints. All that you have to do is to publish more than one endpoint URI under the same cluster ID. Now, when a client looks up that cluster ID, it gets a random selection out of the list of available endpoint URIs.
The servers in the load-balancing 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 load-balancing cluster, however, it is better to define a template that enables you to specify the host or port using a configuration variable.
Example 44.3, “Server Template for a Load-Balancing Cluster” illustrates the template approach to defining servers in a load-balancing cluster.
Example 44.3. Server Template for a Load-Balancing 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="myConfig" persistent-id="io.fabric8.examples.camel.loadbalancing.server"/> <bean id="fabric-camel" class="io.fabric8.camel.FabricComponent"/> <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint"> <!-- using Camel properties component and refer to the blueprint property placeholder by its id --> <propertyPlaceholder id="properties" location="blueprint:myConfig" prefixToken="[[" suffixToken="]]"/> <route id="fabric-server"> <from uri="fabric-camel:cluster:jetty:http://0.0.0.0:[[portNumber]]/fabric"/> <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>
First of all, you need to initialize the OSGi blueprint property placeholder. The property placeholder 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
io.fabric8.examples.camel.loadbalancing.server
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 persistent ID using the syntax, [[PropName]]
.
The Fabric 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.
OSGi bundle plug-in configuration
When defining an OSGi bundle that uses Fabric endpoints, the
Import-Package
bundle header must be configured to import the following Java packages:
io.fabric8.zookeeper
For example, assuming that you use Maven to build your application, Example 44.4, “Maven Bundle Plug-In Configuration” shows how you can configure the Maven bundle plug-in to import the required packages.
Example 44.4. 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> io.fabric8.zookeeper, * </Import-Package> </instructions> </configuration> </plugin> </plugins> </build> ... </project>