Table of Contents
This chapter focuses on a variety of topics, including deployment options, jobs, clustering, encryptions, synchronization control, and configuration of SymmetricDS.
SymmetricDS allows tables to be synchronized bi-directionally. Note that an outgoing
synchronization does not process changes during an incoming synchronization on the same node unless the trigger
was created with the sync_on_incoming_batch
flag set. If the sync_on_incoming_batch
flag
is set, then update loops are prevented by a feature that is available in most database dialects.
More specifically, during an incoming synchronization the source node_id
is put into a database session variable that is
available to the database trigger. Data events are not generated if the target node_id
on an outgoing synchronization is equal to the source node_id
.
By default, only the columns that changed will be updated in the target system.
Conflict resolution strategies can be configured for specific links and/or sets of tables.
There may be scenarios where data needs to flow through multiple tiers of nodes that are organized in a tree-like network with each tier requiring a different subset of data. For example, you may have a system where the lowest tier may be a computer or device located in a store. Those devices may connect to a server located physically at that store. Then the store server may communicate with a corporate server for example. In this case, the three tiers would be device, store, and corporate. Each tier is typically represented by a node group. Each node in the tier would belong to the node group representing that tier.
A node can only pull and push data to other nodes that are represented in the node's NODE
table and in cases where that node's sync_enabled
column is set to 1.
Because of this, a tree-like
hierarchy of nodes can be created by having only a subset of nodes belonging to the same node group represented at the different branches of the tree.
If auto registration is turned off, then this setup must occur manually by opening registration
for the desired nodes at the desired parent node and by configuring each node's registration.url
to be the parent node's URL.
The parent node is always tracked by the setting of the parent's node_id
in the created_at_node_id
column of the new node.
When a node registers and downloads its configuration it is always provided the configuration for nodes
that might register with the node itself based on the Node Group Links defined in the parent node.
When deploying a multi-tiered system it may be advantageous to have only one registration server, even though the parent node of a registering node
could be any of a number of nodes in the system. In SymmetricDS the parent node is always the node that a child registers with. The
REGISTRATION_REDIRECT table allows a single node, usually the root server in the network, to
redirect registering nodes to their true parents. It does so based on a mapping found in the table of the external id (registrant_external_id
) to the parent's node
id (registration_node_id
).
For example, if it is desired to have a series of regional servers that workstations at retail stores get assigned to based on their external_id
, the store number, then
you might insert into REGISTRATION_REDIRECT the store number as the registrant_external_id
and the node_id
of
the assigned region as the registration_node_id
. When a workstation at the store registers, the root server sends an HTTP redirect to the sync_url
of the node
that matches the registration_node_id
.
Please see Section 4.2.2, “Initial Loads” for important details around initial loads and registration when using registration redirect.
An instance of SymmetricDS can be deployed in several ways:
Web application archive (WAR) deployed to an application server
This option means packaging a WAR file and deploying to your favorite web server, like Apache Tomcat. It's a little more work, but you can configure the web server to do whatever you need. SymmetricDS can also be embedded in an existing web application, if desired.
Standalone service that embeds Jetty web server
This option means running the sym command line, which launches the built-in Jetty web server. This is a simple option because it is already provided, but you lose the flexibility to configure the web server any further.
Embedded as a Java library in an application
This option means you must write a wrapper Java program that runs SymmetricDS. You would probably use Jetty web server, which is also embeddable. You could bring up an embedded database like Derby or H2. You could configure the web server, database, or SymmetricDS to do whatever you needed, but it's also the most work of the three options discussed thus far.
The deployment model you choose depends on how much flexibility you need versus how easy you want it to be. Both Jetty and Tomcat are excellent, scalable web servers that compete with each other and have great performance. Most people choose either the Standalone or Web Archive with Tomcat 5.5 or 6. Deploying to Tomcat is a good middle-of-the-road decision that requires a little more work for more flexibility.
Next, we will go into a little more detail on the first three deployment options listed above.
As a web application archive, a WAR is deployed to an application server,
such as Tomcat, Jetty, or JBoss. The structure of the archive will have a web.xml
file in the WEB-INF
folder, an appropriately configured symmetric.properties
file in the WEB-INF/classes
folder,
and the required JAR files in the WEB-INF/lib
folder.
A war file can be generated using the standalone installation's symadmin
utility and the
create-war
subcommand. The command requires the name of the war file to generate. It
essentially packages up the web directory, the conf directory and includes an optional
properties file. Note that if a properties file is included, it will be copied to
WEB-INF/classes/symmetric.properties. This is the same location conf/symmetric.properties
would have been copied to. The generated war distribution uses the same web.xml as the standalone
deployment.
../bin/symadmin -p my-symmetric-ds.properties create-war /some/path/to/symmetric-ds.war
A Java application with the SymmetricDS Java Archive (JAR) library on its
classpath can use the SymmetricWebServer
to start the server.
import org.jumpmind.symmetric.SymmetricWebServer; public class StartSymmetricEngine { public static void main(String[] args) throws Exception { SymmetricWebServer node = new SymmetricWebServer( "classpath://my-application.properties", "conf/web_dir"); // this will create the database, sync triggers, start jobs running node.start(8080); // this will stop the node node.stop(); } }
This example starts the SymmetricDS server on port 8080.
The configuration properties file, my-application.properties
,
is packaged in the application to provide properties that override the SymmetricDS
default values. The second parameter to the constructor points to the web directory.
The default location is ../web
. In this example the web directory is located
at conf/web_dir
. The web.xml is expected to be found at conf/web_dir/WEB-INF/web.xml
.
The sym
command line utility starts a standalone web server with
SymmetricDS pre-deployed. The standalone server uses an embedded instance of the
Jetty application server to handle web requests. The web server can be configured
using command line options or the web server can be configured by changing properties in the
conf/symmetric-server.properties
file.
The following example starts the SymmetricDS server on port 8080 with the startup
properties found in the root.properties
file.
/symmetric/bin/sym --properties root.properties --port 8080 --server
Even though the port and properties settings can be passed in on the command line, the preferred
configuration approach is to put each hosted node's properties file in the engines
directory
and to modify port settings and enable secure mode using the conf/symmetric-server.properties
.
It is also suggested that SymmetricDS be configured to run as a service according to the instructions for your platform as documented in the following section.
SymmetricDS can be configured to start automatically when the system boots, running as a Windows service or Linux/Unix daemon.
A wrapper process starts SymmetricDS and monitors it, so it can be restarted if it runs out of memory or exits unexpectedly.
The wrapper writes standard output and standard error to the logs/wrapper.log
file.
To install the service, run the following command as Administrator:
bin\sym_service.bat install
Most configuration changes do not require the service to be re-installed. To un-install the service, run the following command as Administrator:
bin\sym_service.bat uninstall
To start and stop the service manually, run the following commands as Administrator:
bin\sym_service.bat start bin\sym_service.bat stop
An init script is written to the system /etc/init.d
directory.
Symbolic links are created for starting on run levels 2, 3, and 5 and stopping on run levels 0, 1, and 6.
To install the script, running the following command as root:
bin/sym_service install
Most configuration changes do not require the service to be re-installed. To un-install the service, run the following command as root:
bin/sym_service uninstall
To start and stop the service manually, run the following commands:
bin/sym_service start bin/sym_service stop
A single SymmetricDS node may be clustered across a series of instances, creating a web farm. A node might be clustered to provide load balancing and failover, for example.
When clustered, a hardware load balancer is typically used
to round robin client requests to the cluster. The load balancer should be configured for stateless connections.
Also, the sync.url
(discussed in Section 2.1, “Engine Files”)
SymmetricDS property should be set to the URL of the load balancer.
If the cluster will be running any of the SymmetricDS jobs, then the cluster.lock.enabled
property should be set to true
.
By setting this property to true, SymmetricDS will use a row in the LOCK table as a semaphore to make sure that only one instance at a time
runs a job. When a lock is acquired, a row is updated in the lock table with the time of the lock and the server id of the locking job. The lock time is set back to null
when the job is finished running. Another instance of SymmetricDS cannot aquire a lock until the locking instance (according to the server id) releases the lock. If an
instance is terminated while the lock is still held, an instance with the same server id is allowed to reaquire the lock. If the locking instance remains down, the lock can be
broken after a period of time, specified by the cluster.lock.timeout.ms
property, has expired. Note that if the job is still running and the lock
expires, two jobs could be running at the same time which could cause database deadlocks.
By default, the locking server id is the hostname of the server. If two clustered instances are running on the same server, then the cluster.server.id
property
may be set to indicate the name that the instance should use for its server id.
When deploying SymmetricDS to an application server like Tomcat or JBoss, no special session clustering needs to be configured for the application server.
The db.user
and db.password
properties will accept encrypted text, which protects
against casual observation. The text is prefixed with enc:
to indicate
that it is encrypted. To encrypt text, use the following command:
symadmin -e {engine name} encrypt-text text-to-encrypt
or
symadmin -p {properties file} encrypt-text text-to-encrypt
The text is encrypted using a secret key named "sym.secret" that is retrieved from a keystore file.
By default, the keystore is located in security/keystore
.
The location and filename of the keystore can be overridden by setting the "sym.keystore.file" system property.
If the secret key is not found, the system will generate and install a secret key for use with Triple DES cipher.
Generate a new secret key for encryption using the keytool
command that comes with the JRE. If there is an existing key in the keystore, first remove it:
keytool -keystore keystore -storepass changeit -storetype jceks \ -alias sym.secret -delete
Then generate a secret key, specifying a cipher algorithm and key size. Commonly used algorithms that are supported include aes, blowfish, desede, and rc4.
keytool -keystore keystore -storepass changeit -storetype jceks \ -alias sym.secret -genseckey -keyalg aes -keysize 128
If using an alternative provider, place the provider JAR file in the SymmetricDS lib
folder.
The provider class name should be installed in the JRE security properties or specified on the command line.
To install in the JRE, edit the JRE lib/security/java.security
file
and set a security.provider.i
property for the provider class name.
Or, the provider can be specified on the command line instead.
Both keytool
and sym
accept command line arguments for the provider class name.
For example, using the Bouncy Castle provider, the command line options would look like:
keytool -keystore keystore -storepass changeit -storetype jceks \ -alias sym.secret -genseckey -keyalg idea -keysize 56 \ -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerPath ..\lib\bcprov-ext.jar
symadmin -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -e secret
To customize the encryption, write a Java class that implements the ISecurityService or extends the default SecurityService, and place
the class on the classpath in either lib
or
web/WEB-INF/lib
folders.
Then, in the symmetric.properties
specify your class name for the security service.
security.service.class.name=org.jumpmind.security.SecurityService
Remember to specify your properties file when encrypting passwords, so it will use your custom ISecurityService.
symadmin -p symmetric.properties -e secret
By specifying the "https" protocol for a URL, SymmetricDS will communicate over Secure Sockets Layer (SSL) for an encrypted transport. The following properties need to be set with "https" in the URL:
This is the URL of the current node, so if you want to force other nodes to communicate over SSL with this node, you specify "https" in the URL.
This is the URL where the node will connect for registration when it first starts up. To protect the registration with SSL, you specify "https" in the URL.
For incoming HTTPS connections, SymmetricDS depends on the webserver where it is deployed, so the webserver must be configured for HTTPS. As a standalone deployment, the "sym" launcher command provides options for enabling HTTPS support.
The "sym" launch command uses Jetty as an embedded web server. Using command line options, the web server can be told to listen for HTTP, HTTPS, or both.
sym --port 8080 --server
sym --secure-port 8443 --secure-server
sym --port 8080 --secure-port 8443 --mixed-server
If you deploy SymmetricDS to Apache Tomcat, it can be secured by editing the
TOMCAT_HOME/conf/server.xml
configuration file. There is already a line that can be uncommented
and changed to the following:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/symmetric-ds-1.x.x/security/keystore" />
When SymmetricDS connects to a URL with HTTPS, Java checks the validity of the
certificate using the built-in trusted keystore located at
JRE_HOME/lib/security/cacerts
.
The "sym" launcher command overrides the trusted keystore to use its own
trusted keystore instead, which is located at
security/cacerts
.
This keystore contains the certificate aliased as "sym" for use in testing
and easing deployments.
The trusted keystore can be overridden
by specifying the javax.net.ssl.trustStore
system property.
When SymmetricDS is run as a secure server with the "sym" launcher,
it accepts incoming requests using the key installed in the keystore
located at
security/keystore
.
The default key is provided for convenience of testing, but should be
re-generated for security.
To generate new keys and install a server certificate, use the following steps:
Open a command prompt and navigate to the
security
subdirectory of your SymmetricDS installation on the server to which
communication will be secured (typically the "root" or "central office" server).
Delete the old key pair and certificate.
keytool -keystore keystore -delete -alias sym
keytool -keystore cacerts -delete -alias sym
Enter keystore password: changeit
Generate a new key pair. Note that the first name/last name (the "CN") must match the fully qualified hostname the client will be using to communcate to the server.
keytool -keystore keystore -alias sym -genkey -keyalg RSA -validity 10950
Enter keystore password: changeit What is your first and last name? [Unknown]: localhost What is the name of your organizational unit? [Unknown]: SymmetricDS What is the name of your organization? [Unknown]: JumpMind What is the name of your City or Locality? [Unknown]: What is the name of your State or Province? [Unknown]: What is the two-letter country code for this unit? [Unknown]: Is CN=localhost, OU=SymmetricDS, O=JumpMind, L=Unknown, ST=Unknown, C=Unknown correct? [no]: yes Enter key password for <sym> (RETURN if same as keystore password):
Export the certificate from the private keystore.
keytool -keystore keystore -export -alias sym -rfc -file sym.cer
Install the certificate in the trusted keystore.
keytool -keystore cacerts -import -alias sym -file sym.cer
Copy the cacerts file that is generated by this process to
the security
directory of each client's SymmetricDS installation.
SymmetricDS supports basic authentication for client and server nodes.
To configure a client node to use basic authentication when communicating with a server node, specify the following startup parameters:
username for client node basic authentication. [ Default: ]
password for client node basic authentication. [ Default: ]
The SymmetricDS Standalone Web Server also supports Basic Authentication. It can be enabled by passing the following arguments to the startup program
username for basic authentication [ Default: ]
password for basic authentication [ Default: ]
If the server node is deployed to Tomcat or another application server as a WAR or EAR file, then basic authentication is setup with the standard configuration in the WEB.xml file.
SymmetricDS supports the concept of pluggable data loaders. A data loader defines how data is loaded into a target
datasource. The default data loader for SymmetricDS loads data to the relational database that is represented by the SymmetricDS node.
Data loaders do not always have to load into the target relational database. They can write to
a file, a web service, or any other type of non-relational data source. Data loaders can also use other techniques to increase performance
of data loads into the target relation database. Data loaders are pluggable at the
CHANNEL level. They are configured by setting the data_loader_type
on
the channel table.
To use the preconfigured bulk data loaders,
you set the data_loader_type
on a channel to one of the following:
Tables that should be data loaded should be configured to use this channel. Many times, a reload channel will be set to bulk load to increase the performance of an initial load.
The MongoDB data loader maps relational database rows to MongoDB documents in collections. To use the preconfigured MongoDB data loader,
you set the data_loader_type
to MongoDB on a channel.
Tables that should be synchronized to MongoDB should be configured to use this channel.
In order to point it to a MongoDB instance
set the following properties in the engines properties file.
mongodb.username=xxxx mongodb.password=xxxx mongodb.host=xxxx mongodb.port=xxxx mongodb.default.databasename=default
By default, the catalog or schema passed by SymmetricDS will be used for the MongoDB database name. The table passed by SymmetricDS will be used as the MongoDB collection name. If the catalog or schema are not set, the default database name property is used as the database name.
The _id of the MongoDB document will be the primary key of the database record. If the table has a composite primary key, then the _id will be an embedded document that has name value pairs of the composite key. The body of the document will be name value pairs of the table column name and table row value.
SymmetricDS uses the MongoDB Java Driver to upsert documents.
SymmetricDS transforms can be used to transform the data. If a complex mapping is required that is not supported by transforms, then
the IDBObjectMapper
can be implemented and a new MongoDataLoaderFactory
can be wired up
as an extension point.
Monitoring and administrative operations can be performed using Java Management Extensions (JMX). SymmetricDS uses MX4J to expose JMX attributes and operations that can be accessed from the built-in web console, Java's jconsole, or an application server. By default, the web management console can be opened from the following address:
http://localhost:31416/
In order to use jconsole, you must enable JMX remote management in the JVM. You can edit the startup scripts to set the following system parameters.
-Dcom.sun.management.jmxremote.port=31417 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
More details about enabling JMX for JConsole can be found here.
Using the Java jconsole command, SymmetricDS is listed as a local process named SymmetricLauncher.
In jconsole, SymmetricDS appears under the MBeans tab under the name defined by the engine.name
property. The default value is SymmetricDS.
The management interfaces under SymmetricDS are organized as follows:
Node - administrative operations
Parameters - access to properties set through the parameter service
With the proper configuration SymmetricDS can publish XML messages of captured data changes to JMS during routing or transactionally while data loading synchronized data into a target database. The following explains how to publish to JMS during synchronization to the target database.
The XmlPublisherDatabaseWriterFilter is a IDatabaseWriterFilter that may be configured to publish specific tables as an XML message to a JMS provider. See Section 6.1, “Extension Points” for information on how to configure an extension point. If the publish to JMS fails, the batch will be marked in error, the loaded data for the batch will be rolled back and the batch will be retried during the next synchronization run.
The following is an example extension point configuration that will publish four tables in XML with a root tag of 'sale'. Each XML message will be grouped by the batch and the column names identified by the groupByColumnNames property which have the same values.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="configuration-publishingFilter" class="org.jumpmind.symmetric.integrate.XmlPublisherDatabaseWriterFilter"> <property name="xmlTagNameToUseForGroup" value="sale"/> <property name="tableNamesToPublishAsGroup"> <list> <value>SALE_TX</value> <value>SALE_LINE_ITEM</value> <value>SALE_TAX</value> <value>SALE_TOTAL</value> </list> </property> <property name="groupByColumnNames"> <list> <value>STORE_ID</value> <value>BUSINESS_DAY</value> <value>WORKSTATION_ID</value> <value>TRANSACTION_ID</value> </list> </property> <property name="publisher"> <bean class="org.jumpmind.symmetric.integrate.SimpleJmsPublisher"> <property name="jmsTemplate" ref="definedSpringJmsTemplate"/> </bean> </property> </bean> </beans>
The publisher property on the XmlPublisherDatabaseWriterFilter takes an interface of type IPublisher. The implementation demonstrated here is an implementation that publishes to JMS using Spring's JMS template. Other implementations of IPublisher could easily publish the XML to other targets like an HTTP server, the file system or secure copy it to another server.
The above configuration will publish XML similar to the following:
<?xml version="1.0" encoding="UTF-8"?> <sale xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="0012010-01-220031234" nodeid="00001" time="1264187704155"> <row entity="SALE_TX" dml="I"> <data key="STORE_ID">001</data> <data key="BUSINESS_DAY">2010-01-22</data> <data key="WORKSTATION_ID">003</data> <data key="TRANSACTION_ID">1234</data> <data key="CASHIER_ID">010110</data> </row> <row entity="SALE_LINE_ITEM" dml="I"> <data key="STORE_ID">001</data> <data key="BUSINESS_DAY">2010-01-22</data> <data key="WORKSTATION_ID">003</data> <data key="TRANSACTION_ID">1234</data> <data key="SKU">9999999</data> <data key="PRICE">10.00</data> <data key="DESC" xsi:nil="true"/> </row> <row entity="SALE_LINE_ITEM" dml="I"> <data key="STORE_ID">001</data> <data key="BUSINESS_DAY">2010-01-22</data> <data key="WORKSTATION_ID">003</data> <data key="TRANSACTION_ID">1234</data> <data key="SKU">9999999</data> <data key="PRICE">10.00</data> <data key="DESC" xsi:nil="true"/> </row> <row entity="SALE_TAX" dml="I"> <data key="STORE_ID">001</data> <data key="BUSINESS_DAY">2010-01-22</data> <data key="WORKSTATION_ID">003</data> <data key="TRANSACTION_ID">1234</data> <data key="AMOUNT">1.33</data> </row> <row entity="SALE_TOTAL" dml="I"> <data key="STORE_ID">001</data> <data key="BUSINESS_DAY">2010-01-22</data> <data key="WORKSTATION_ID">003</data> <data key="TRANSACTION_ID">1234</data> <data key="AMOUNT">21.33</data> </row> </sale>
To publish JMS messages during routing
the same pattern is valid, with the exception that the extension point would be the XmlPublisherDataRouter and the router
would be configured by setting the router_type
of a ROUTER to the Spring bean
name of the registered extension point. Of course, the router would need to be linked through TRIGGER_ROUTERs
to each TRIGGER table that needs published.