Fuse Fabric uses Apache ZooKeeper, which is highly reliable distributed coordination service, as its registry to store the cluster configuration and node registration.
ZooKeeper is designed with consistency and high availability across data centers in mind while also protecting against network splits by using a quorum of ZooKeeper servers. e.g. you may run 3 or 5 ZooKeeper servers and so long as you have quorum running (2 or 3 servers respectively) you are reliable and are not in a network split.
Conceptually Fabric has 2 registries:
More details on the fabric registry.
Fabric defines a notion of profile that can be applied to containers of the Fabric. A profile consists of a list of configurations that will be provided to ConfigAdmin along with bundles and features to be provisioned. Multiple profiles can be associated to a given container, allowing a given container to serve multiple purposes.
If you want a Fabric where each container running exactly the same set of features with exactly the same configuration then you only need one profile. However in most real world use cases you often want either to provision features differently across nodes or at least have different configurations.
For example you may wish to run different kinds of things on different nodes; you may run some message brokers, some web applications, some ESBs and some transformation engines and proxies. Each of these can be profiles that you can manage as a single logical entity irrespective of how many instances you wish to run. Or you may want to run the same features everywhere but you may wish to provide location specific configurations, you may use different locations of message broker or cache services in different data centres or geographical regions.
Profiles can also have inheritance so that parts of configuration can be shared across multiple profiles; similar to the use of trees in LDAP repositories. The overall list of configurations is computed using an overlay mechanism which allow a profile to override values from its parents, which provides power and flexibility while keeping your configuration nice and DRY. Those profiles are stored in ZooKeeper, hence automatically and immediately propagated to all nodes which can refresh the configurations as needed.
Fabric defines a provisioning agent relying on profiles. The agent runs on each managed container and its role is to provision the container according to the profiles assigned to it. The agent will retrieve the configuration, bundles & features as defined in the profile overlay, calculate what needs to be installed / uninstalled and finally perform all the actions required.
The agent is not just capable of provisioning just applications. It is capable of even provisioning fabric itself and can go as low as the osgi framework.
Each node in the cluster has a logical name and on startup the provisioning agent registers an ephemeral node in ZooKeeper. It then looks in the configuration using its logical name for its profile of what configuration to use and what services to provision. If there is no configuration or the logical name it uses the default profile.
Each node watches the relevant parts of the ZooKeeper tree for changes; so that as soon as any profile is updated the dependent nodes refresh and re-apply any provisioning or configuration changes.
You can then use the Fabric command line shel to interact with the configuration so that you can dynamically control configuration and provisioning.
Through the use of profiles you can then control all or a group of nodes in each operation. For example you can set global configuration properties or properties which only affect a group of nodes (e.g. message brokers only or web servers only or all ESBs within some data centre).
Each container registers itself into the ZooKeeper runtime registry details of its machine, host name and connection details (e.g. JMX URL) so its easy to discover and introspect the Fabric and to delve into any node to introspect or control it in more detail.
In addition Fabric supports a number of additional discovery mechanisms which are framework specific in the Fabric Extensions.
Provisioning and configuration is very powerfull feature of fabric. However, Fabric does not stop there. It provides you the ability to create container from scratch:
Fabric uses the notion of container provider. A container provider allows you to create new containers, without any prior container installation. Currently it provides 3 types of container provides, one for each of the cases mentioned above. The container providers allow you to gradually build and extend your cluster (weave your Fabirc).
A child container is a container that runs an individual process and shares the same host with its parent and siblings. This allows you to have parts of the application trully isolated from each other, but also allows you to make better use of your resources. From any Fabric container you can create a child container for any of your existing containers (not just the current container, you can also create child containers for containers on remote hosts).
Creating a container is as simple as using the fabric:container-create-child command, For example:
fabric:container-create-child root child1
In addition to the core Provisioning, Configuration and Management Fabric described above, Fabric also provides a number of technology specific extensions:
When using ActiveMQ you have to configure your ActiveMQ clients with the locations of the ActiveMQ brokers up front which is not terribly cloud friendly (e.g. working on a number of new EC2 boxes spun up on Amazon).
However the ActiveMQ Fabric let you avoid this by reusing the Fabric discovery mechanism. ActiveMQ brokers register themselves into the Runtime Registry. Then ActiveMQ clients use the Runtime Registry to discover brokers; plus watch for brokers failing and new brokers starting so there is a real time discovery and load balancing mechanism.
Find more information on ActiveMQ Fabric
When using ActiveMQ or JMS endpoints in Camel you are already fabric ready since message brokers provide true location independence (as well as time independence too, the consumer of a message does not even have to be running at the time you send a message).
However if you are using socket or HTTP endpoints this is not the case; each client wishing to invoke your service needs to know all the available network addresses of each implementation (e.g. a list of protocols, host name & ports).
This is where the Camel Fabric comes in; it provides a way to reuse Fabric's discovery mechanism to expose physical socket & HTTP endpoints into the runtime registry using a logical name so that clients can use the existing Camel Load Balancer.
Currently Camel Fabric works using the fabric Camel component.
Here we just prefix any socket or HTTP based endpoint with fabric::myName where the myName is the logical name of the service you wish to use. This prefix is then used to expose your endpoint URI into the Runtime Registry
In the above route we send to the endpoint fabric:myName which at runtime will use the myName entry in the Camel Fabric to discover the currently available physical endpoints in the fabric for this name; then load balance across them.
Like the Camel Fabric above, the CXF Fabric makes it easy to expose physical web services into the Runtime Registry so that clients can just bind to the logical name of the service and at runtime locate and load balance across the running implementations.
Basically, your CXF endpoint will know nothing about the Fabric runtime, and you just need to configure the FabricLoadBalanceFeature with the ZKClientFactoryBean and set the feature into the bus, the FabricLoadBalanceFeature will interact with Fabric runtime automatically.
You can configure the fabricPath of the FabricLoadBalancerFeature for the CXF server and CXF client to use.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxfcore="http://cxf.apache.org/core" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <bean id="zkClient" class="io.fabric8.zookeeper.spring.ZKClientFactoryBean"> <property name="timeoutText" value="30s"/> <property name="connectString" value="localhost:2181"/> </bean> <bean id="fabicLoadBalancerFeature" class="io.fabric8.cxf.FabricLoadBalancerFeature"> <property name="zkClient" ref="zkClient" /> <property name="fabricPath" value="simple" /> </bean> <!-- configure the feature on the bus --> <cxfcore:bus> <cxfcore:features> <ref bean="fabicLoadBalancerFeature" /> </cxfcore:features> </cxfcore:bus> </beans>
// You just need to make sure the bus is configured with the FabricLoadBalanceFeature ServerFactoryBean factory = new ServerFactoryBean(); factory.setServiceBean(new HelloImpl()); factory.setAddress("http://localhost:9000/simple/server"); factory.setBus(bus); factory.create();
Here you can use the CXF normal code to publish the CXF service, but you need to make sure the FabricLoadBalancerFeature is registered into the bus that you service will be published.
ClientProxyFactoryBean clientFactory = new ClientProxyFactoryBean(); clientFactory.setServiceClass(Hello.class); // The address is not the actual address that the client will access clientFactory.setAddress("http://someotherplace"); List<AbstractFeature> features = new ArrayList<AbstractFeature>(); Feature feature = new FabricFailOverFeature(); // you need setting the feature with zkClient and fabricPath to load the server addresses ...... // add the instance of FabricLoadBalancerFeature into features list features.add(feature); // we need to setup the feature on the clientfactory clientFactory.setFeatures(features); Hello hello = clientFactory.create(Hello.class); String response = hello.sayHello(); System.out.println(response);
For the CXF client, you just need to set the FabricLoadBalancerFeature directly into the clientFactory. The FabricLoadBalancerFeature will pick a real service physical address for the Fabric service registry for the client to use.
The OSGi registry by default contains local services. However since Fabric has a Configuration Registry defining profiles along with a Runtime Registry for discovery, its easy to configure Fabric to expose remote OSGi services into the Runtime Registry for different profiles so that you can get invisible remoting of services with dynamic discovery, load balancing and fail over. The OSGi Fabric follows the OSGi Remote Services specification. Any service exported in the OSGi registry with a property named “service.exported.interfaces” (with a value of either “*" or a list of interfaces to export) will be automatically exported in Fabric Registry and imported on other Fabric containers as needed.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <bean id="theBean" class="foo.bar.Example" /> <service ref="theBean" auto-export="interfaces"> <service-properties> <entry key="service.exported.interfaces" value="*"/> </service-properties> </service> </blueprint>
Well, nothing to do there. Just use the service as usual and the OSGi Fabric will import it for you :-)
While OSGi is cool and all; not everything is available as OSGi bundles. You often want to run other things inside your Fabric other than bundles. For example databases, non Java code or even just different packaging of Java code such as a Tomcat distribution for your web applications.
The Process Fabric* extends the fabric of Karaf nodes to support any other kind of process on your machine. Think of it as like a distributed version of monit or init.d.
The primary interface currently for working with Fabric is via the command line shells in Karaf.