[Liferay] Clustering Liferay 6.1, Liferay 6.2 with Apache and mod_jk loadbalancer, EHCache, Lucene Index, Cluster session, Jackrabbit

1. Mô tả hệ thống
Trước khi làm theo hướng dẫn cài đặt dưới đây, các bạn cần thực hiện các yêu cầu sau trước tiên:
- Tất cả các node của cluster đều được kết nối tới chung 1 database (chúng ta có thể sử dụng MariaDB để clustering database)
- Cài đặt apache2 và modjk phục vụ cho việc loadbalancing
- Sử dụng hardware loadbalancing hoặc keepalived để HA cho 2 server apache (lúc này client access tới 2 server apache thông qua 1 VIP)

Mô tả:
- Server Apache1 (192.168.2.50) và server Apache 2 (192.168.2.239) đóng vai trò là load balancing cho 2 server Tomcat 1 và Tomcat 2
- 2 server Tomcat sử dụng các công nghệ clustering, lucense index, Jackrabbit
- Cụm cluster DB sử dụng MariaDB và các server Tomcat kết nối tới cụm cluster này bằng 1 địa chỉ IP duy nhất.

2. Setup loadbalancing session cho Tomcat
Setup Apache + modejk trên cả 2 server  Apache:
B1. Cài đặt mod_jk cho apache
apt-get install libapache2-mod-jk
apt-get install apache2-threaded-dev    (dev package for debian)
B2. Tạo file /etc/apache2/workers.properties với nội dung sau
# Define list of workers that will be used
# for mapping requests
worker.list=tomcat1,tomcat2,loadbalancer,status
# Define Tomcat1
worker.tomcat1.port=8009
worker.tomcat1.host=192.168.2.50
worker.tomcat1.type=ajp13                
worker.tomcat1.cachesize=10
worker.tomcat1.lbfactor=1
worker.tomcat1.socket_timeout=60
worker.tomcat1.connection_pool_timeout=60
worker.tomcat1.ping_mode=A
worker.tomcat1.ping_timeout=20000
worker.tomcat1.connect_timeout=20000
# Define Tomcat2
worker.tomcat2.port=8009
worker.tomcat2.host=192.168.2.239
worker.tomcat2.type=ajp13                  
worker.tomcat1.cachesize=10
worker.tomcat2.lbfactor=1
worker.tomcat2.socket_timeout=60
worker.tomcat2.connection_pool_timeout=60
worker.tomcat2.ping_mode=A
worker.tomcat2.ping_timeout=20000
worker.tomcat2.connect_timeout=20000
# Load-balancing behaviour
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2
worker.loadbalancer.sticky_session=1
# Status worker for managing load balancer
worker.status.type=status
B3. Thêm các dòng sau vào file /etc/apache2/mods-enabled/jk.load
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
JkWorkersFile /etc/apache2/workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
B4. Mở file  /etc/apache2/mods-enabled/jk.conf 
Remove line:    
#JkWorkersFile /etc/libapache2-mod-jk/workers.properties
B5. Tạo và enable file virtual host
<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName qgs.vn
        #DocumentRoot /var/www
        JkMount / loadbalancer
        JkMount /* loadbalancer
</VirtualHost>
3. Clustering session cho liferay
B1. Chỉnh sửa file server.xml
Tìm dòng:
<Engine name="Catalina" defaultHost="localhost">
sửa thành: (tomcat2 là tên mod_jk của server đang cấu hình)
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">
          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>
            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor
className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>
          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>
          <ClusterListener
className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>
B2. Chỉnh sửa file webapps/ROOT/WEB-INF/web.xml
Thêm dòng sau vào tag <web-app ..> </web-app>
<distributable/>
B3.  Chỉnh sửa file /etc/hosts
127.0.1.1 hostname 
thành
IP_computer hostname
4. EHCache và Lucene Index cho liferay
B1. Thêm đoạn sau vào sau JAVA_OPTS trong file setenv.sh
-Djava.net.preferIPv4Stack=true
B2. Tạo folder WEB-INF/classes/ehcache và giải nén file WEB-INF/lib/portal-impl.jar vào đó. Lưu ý: folder ehcache là folder chứa 4 file: hibernate-clustered.xml, liferay-multi-vm-clustered.xml
B3. Thêm vào file portal-ext.properties nội dung sau:
### Lucene Search
#lucene.analyzer=org.apache.lucene.analysis.WhitespaceAnalyzer
image.hook.impl=com.liferay.portal.image.FileSystemHook
setup.wizard.enabled=false
############ Cluster Cache #########################
cluster.link.enabled=true
cluster.link.autodetect.address=192.168.2.60:8080
# 192.168.2.60 la IP cua may can joint toi
lucene.replicate.write=true
 <!--
 Uncomment the following in a clustered configuration.
 -->
 <cacheManagerPeerProviderFactory
    class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    properties="peerDiscovery=automatic,multicastGroupAddress=230.0.0.2,multicastGroupPort=4446,timeToLive=1"
    propertySeparator=","
 />
 <cacheManagerPeerListenerFactory
   class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
 />
net.sf.ehcache.configurationResourceName=/ehcache/hibernate-clustered.xml
ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xml
  //MODIFY MULTICAST ADDRESS/PORT TO FIT YOUR ENVIRONMENT
 #
     # See the property "cluster.link.channel.properties.control".
    #
    multicast.group.address["cluster-link-control"]=239.255.0.1
    multicast.group.port["cluster-link-control"]=23301
    #
    # See the properties "cluster.link.channel.properties.transport.0" and
    # "cluster.link.channel.system.properties".
    #
    multicast.group.address["cluster-link-udp"]=239.255.0.2
    multicast.group.port["cluster-link-udp"]=23302
    #
    # See the property "cluster.link.channel.system.properties".
    #
    multicast.group.address["cluster-link-mping"]=239.255.0.3
    multicast.group.port["cluster-link-mping"]=23303
    #
    # See the properties "net.sf.ehcache.configurationResourceName" and
    # "net.sf.ehcache.configurationResourceName.peerProviderProperties".
    #
    multicast.group.address["hibernate"]=239.255.0.4
    multicast.group.port["hibernate"]=23304
    #
    # See the properties "ehcache.multi.vm.config.location" and
    # "ehcache.multi.vm.config.location.peerProviderProperties".
    #
    multicast.group.address["multi-vm"]=239.255.0.5
    multicast.group.port["multi-vm"]=23305
#################### End Cluster Cache ################################ 
5. Setup Jackrabbit
B1. Shutdown liferay
B2. Thêm dòng sau vào file portal-ext.properties
##### JACKRABBIT #####
dl.store.impl=com.liferay.portlet.documentlibrary.store.JCRStore
jcr.initialize.on.startup=true
jcr.wrap.session=true
jcr.workspace.name=liferay
jcr.node.documentlibrary=documentlibrary
jcr.jackrabbit.repository.root=${liferay.home}/data/jackrabbit
jcr.jackrabbit.config.file.path=${jcr.jackrabbit.repository.root}/repository.xml
jcr.jackrabbit.repository.home=${jcr.jackrabbit.repository.root}/home
jcr.jackrabbit.credentials.username=none
jcr.jackrabbit.credentials.password=none
B3. Thay thế nội dung file liferay/data/jackrabbit/repository.xml bằng nội dung dưới
<?xml version="1.0"?>
<Repository>
<FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
<param name="driver" value="com.mysql.jdbc.Driver"/>
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql"/>
<param name="schemaObjectPrefix" value="J_R_FS_"/>
</FileSystem>
<Security appName="Jackrabbit">
<AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager" />
<LoginModule class="org.apache.jackrabbit.core.security.SimpleLoginModule">
<param name="anonymousId" value="anonymous" />
</LoginModule>
</Security>
<Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="liferay" />
<Workspace name="${wsp.name}">
<PersistenceManager class="org.apache.jackrabbit.core.state.db.SimpleDbPersistenceManager">
<param name="driver" value="com.mysql.jdbc.Driver" />
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql" />
<param name="schemaObjectPrefix" value="J_PM_${wsp.name}_" />
<param name="externalBLOBs" value="false" />
</PersistenceManager>
<FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
<param name="driver" value="com.mysql.jdbc.Driver"/>
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql"/>
<param name="schemaObjectPrefix" value="J_FS_${wsp.name}_"/>
</FileSystem>
</Workspace>
<Versioning rootPath="${rep.home}/version">
<FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
<param name="driver" value="com.mysql.jdbc.Driver"/>
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql"/>
<param name="schemaObjectPrefix" value="J_V_FS_"/>
</FileSystem>
<PersistenceManager class="org.apache.jackrabbit.core.state.db.SimpleDbPersistenceManager">
<param name="driver" value="com.mysql.jdbc.Driver" />
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql" />
<param name="schemaObjectPrefix" value="J_V_PM_" />
<param name="externalBLOBs" value="false" />
</PersistenceManager>
</Versioning>
<Cluster id="node_2" syncDelay="5">
<Journal class="org.apache.jackrabbit.core.journal.DatabaseJournal">
<param name="revision" value="${rep.home}/revision" />
<param name="driver" value="com.mysql.jdbc.Driver" />
<param name="url" value="jdbc:mysql://10.96.180.10/jcr" />
<param name="user" value="jcr" />
<param name="password" value="jcr@123" />
<param name="schema" value="mysql" />
<param name="schemaObjectPrefix" value="J_C_" />
</Journal>
</Cluster>
</Repository>
B4. Tạo database jcr
create database jcr;
B5. Start liferay

Notes: 
- EHCache và Lucene là kỹ thuật giúp reindex một cách tự động liferay để ăn với database.
- Jackrabbit là phương thức lưu trữ document của liferay, mặc định liferay sử dụng phương thức document_library, các file được lưu trữ tại folder liferay/data/document_library do đó sẽ không đồng bộ được document up lên giữa các server. Jackrabbit quản lý nôi dung document dựa trên 1 database dùng chung giữa các server với nhau, nội dung sẽ được lưu trực tiếp lên datase dùng chung này.
- Ở bước 3, chỉnh sửa cho chính xác địa chỉ IP, username, password, db name.
- Để tránh bị lỗi không nhận được cấu trúc lưu trữ file jackrabbit, chúng ta nên thực hiện các thao tác trên1 server và copy source ra 1 server khác sau đó sửa lại các thông số cho chính xác.

Đọc thêm: Hướng dẫn cài đặt, cấu hình Liferay trên Ubuntu, kết nối Liferay với Active Directory và cài đặt CAS cho Liferay