Configuring a Liferay cluster

From:http://blogs.aca-it.be/blogs/-/blogs/configuring-a-liferay-cluster


Introduction

Configuring a Liferay cluster is part experience and part black magic. There is some information that you can find online, there's some information you can only find out while working on it and then there are some things like how to configure ehcache to use unicast that you can only discover through blood, sweat and tears. This post will first describe how to set up a Liferay 6.1 cluster with Ehcache in multicast and in unicast mode.

To get clustering to work in Liferay you need to make sure that all of the subsystems below are configured correctly:

  • Database

  • Indexing

  • Media gallery

  • Quartz

  • Cluster Link

  • Ehcache

 

Database

The first subsystem that needs to be configured for clustering, the database, is also one of the easiest to configure correctly. You just need to point each node in the cluster to the same database, either by using the same JNDI datasource

jdbc.default.jndi.name=jdbc /liferay

or by using the same JDBC configuration directly in your portal-ext.properties on each node

jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql: //dbserver :3306 /liferay_test ?useUnicode= true &characterEncoding=UTF-8&useFastDateParsing= false &autoReconnectForPools= true
jdbc.default.username=dbuser
jdbc.default.password=Y@r3FiL

 

Indexing

For Liferay 6.1 the only reliable way to cluster the indexing is to use SOLR. For this you'll need to do 2 things: set up a separate SOLR server (or use an existing one) and deploy a correctly configured solr-web.war from the Marketplace to all cluster nodes.

Depending on which Liferay flavor you're using, CE or EE, this will be an easy process or a little bit more difficult. If you're running Liferay EE, the process is pretty straightforward as for that version there are solr-web versions available for SOLR 3 and 4. For Liferay CE it's a bit more complicated as there's only a relatively old WAR available for SOLR 1.4, which you'll need to upgrade yourself if you want to use newer SOLR versions with Liferay CE.

For this blog we're assuming that a dedicated Liferay SOLR instance will be used (but an additional core in an existing SOLR will also work). To set up a SOLR, you can just follow the instructions on their site: https://wiki.apache.org/solr/SolrInstall. Once you have a default SOLR up and running, you'll need to add some configuration to it so Liferay can use it for indexing. This configuration is done by replacing the existing schema.xml with the Liferay SOLR schema.xml that you can find in the WEB-INF/conf directory of the solr-web.war you downloaded.

If you're running on Liferay 6.1 CE and want to use a newer SOLR version than 1.4, you'll also need to change the schema.xml and possibly also the solr-spring.xml a bit to get it working. The version of the schema.xml that worked for us is:

<? xml version = "1.0" ?>
< schema name = "liferay" version = "1.1" >
     < types >
         < fieldType name = "string" class = "solr.StrField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "boolean" class = "solr.BoolField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "integer" class = "solr.IntField" omitNorms = "true" />
         < fieldType name = "long" class = "solr.LongField" omitNorms = "true" />
         < fieldType name = "float" class = "solr.FloatField" omitNorms = "true" />
         < fieldType name = "double" class = "solr.DoubleField" omitNorms = "true" />
         < fieldType name = "sint" class = "solr.SortableIntField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "slong" class = "solr.SortableLongField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "sfloat" class = "solr.SortableFloatField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "sdouble" class = "solr.SortableDoubleField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "date" class = "solr.DateField" sortMissingLast = "true" omitNorms = "true" />
         < fieldType name = "text_ws" class = "solr.TextField" positionIncrementGap = "100" >
             < analyzer >
                 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
             </ analyzer >
         </ fieldType >
         < fieldType name = "text" class = "solr.TextField" positionIncrementGap = "100" >
             < analyzer type = "index" >
                 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
                 < filter class = "solr.StopFilterFactory" ignoreCase = "true" words = "stopwords.txt" />
                 < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1" generateNumberParts = "1" catenateWords = "1" catenateNumbers = "1" catenateAll = "0" />
                 < filter class = "solr.LowerCaseFilterFactory" />
                 < filter class = "solr.RemoveDuplicatesTokenFilterFactory" />
             </ analyzer >
             < analyzer type = "query" >
                 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
                 < filter class = "solr.SynonymFilterFactory" synonyms = "synonyms.txt" ignoreCase = "true" expand = "true" />
                 < filter class = "solr.StopFilterFactory" ignoreCase = "true" words = "stopwords.txt" />
                 < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1" generateNumberParts = "1" catenateWords = "0" catenateNumbers = "0" catenateAll = "0" />
                 < filter class = "solr.LowerCaseFilterFactory" />
                 < filter class = "solr.RemoveDuplicatesTokenFilterFactory" />
             </ analyzer >
         </ fieldType >
         < fieldType name = "textTight" class = "solr.TextField" positionIncrementGap = "100" >
             < analyzer >
                 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
                 < filter class = "solr.SynonymFilterFactory" synonyms = "synonyms.txt" ignoreCase = "true" expand = "false" />
                 < filter class = "solr.StopFilterFactory" ignoreCase = "true" words = "stopwords.txt" />
                 < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "0" generateNumberParts = "0" catenateWords = "1" catenateNumbers = "1" catenateAll = "0" />
                 < filter class = "solr.LowerCaseFilterFactory" />
                 < filter class = "solr.RemoveDuplicatesTokenFilterFactory" />
             </ analyzer >
         </ fieldType >
         < fieldType name = "alphaOnlySort" class = "solr.TextField" sortMissingLast = "true" omitNorms = "true" >
             < analyzer >
                 < tokenizer class = "solr.KeywordTokenizerFactory" />
                 < filter class = "solr.LowerCaseFilterFactory" />
                 < filter class = "solr.TrimFilterFactory" />
                 < filter class = "solr.PatternReplaceFilterFactory" pattern = "([^a-z])" replacement = "" replace = "all" />
             </ analyzer >
         </ fieldType >
         < fieldtype name = "ignored" stored = "false" indexed = "false" class = "solr.StrField" />
     </ types >
     < fields >
         <!--
             Had to add additional fields, 'dash' fields and 'copyfields' to make
             tables and sorting work correctly in certain Control Panel pages:
                 first-name, last-name, screen-name, job-title and type
             otherwise you'll see the following errors in the SOLR log:
                 Feb 15, 2013 11:20:23 AM org.apache.solr.common.SolrException log
                 SEVERE: org.apache.solr.common.SolrException: can not sort on multivalued field: job-title
                     at org.apache.solr.schema.SchemaField.checkSortability(SchemaField.java:160)
          -->
         < field name = "comments" type = "text" indexed = "true" stored = "true" />
         < field name = "content" type = "text" indexed = "true" stored = "true" />
         < field name = "description" type = "text" indexed = "true" stored = "true" />
         < field name = "entryClassPK" type = "text" indexed = "true" stored = "true" />
         < field name = "firstName" type = "text" indexed = "true" stored = "true" />
         < field name = "first-name" type = "text" indexed = "true" stored = "true" />
         < field name = "firstName_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "job-title" type = "text" indexed = "true" stored = "true" />
         < field name = "jobTitle_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "lastName" type = "text" indexed = "true" stored = "true" />
         < field name = "last-name" type = "text" indexed = "true" stored = "true" />
         < field name = "lastName_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "leftOrganizationId" type = "slong" indexed = "true" stored = "true" />
         < field name = "name" type = "text" indexed = "true" stored = "true" />
         < field name = "name_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "properties" type = "string" indexed = "true" stored = "true" />
         < field name = "rightOrganizationId" type = "slong" indexed = "true" stored = "true" />
         < field name = "screen-name" type = "text" indexed = "true" stored = "true" />
         < field name = "screenName_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "title" type = "text" indexed = "true" stored = "true" />
         < field name = "type" type = "text" indexed = "true" stored = "true" />
         < field name = "type_sortable" type = "string" indexed = "true" stored = "true" />
         < field name = "uid" type = "string" indexed = "true" stored = "true" />
         < field name = "url" type = "string" indexed = "true" stored = "true" />
         < field name = "userName" type = "string" indexed = "true" stored = "true" />
         < field name = "version" type = "string" indexed = "true" stored = "true" />
         <!--
          -->
         < field name = "modified" type = "text" indexed = "true" stored = "true" />
         <!--
             Added 'omitNorms' attribute on '*' to fix the following error:
        
             Liferay side:
            
                 12:07:05,844 ERROR [SolrIndexWriterImpl:55] org.apache.solr.common.SolrException: Bad Request
            
             SOLR side:
            
                 Jul 30, 2012 12:07:05 PM org.apache.solr.common.SolrException log
                 SEVERE: org.apache.solr.common.SolrException:
                 ERROR: [doc=PluginPackageIndexer_PORTLET_liferay/solr-web/6.1.0/war] cannot set an index-time boost, norms are omitted for field entryClassName: com.liferay.p
         -->
         < dynamicField name = "*CategoryNames" type = "string" indexed = "true" multiValued = "true" stored = "true" />
         < dynamicField name = "*CategoryIds" type = "string" indexed = "true" multiValued = "true" stored = "true" />
         < dynamicField name = "expando/*" type = "text" indexed = "true" multiValued = "true" stored = "true" />
         < dynamicField name = "web_content/*" type = "text" indexed = "true" stored = "true" />
         <!--
         This must be the last entry since the fields element is an ordered set.
         -->
         < dynamicField name = "*" type = "string" indexed = "true" multiValued = "true" stored = "true" omitNorms = "false" />
     </ fields >
     < copyField source = "firstName" dest = "firstName_sortable" />
     < copyField source = "first-name" dest = "firstName_sortable" />
     < copyField source = "job-title" dest = "jobTitle_sortable" />
     < copyField source = "lastName" dest = "lastName_sortable" />
     < copyField source = "last-name" dest = "lastName_sortable" />
     < copyField source = "name" dest = "name_sortable" />
     < copyField source = "screen-name" dest = "screenName_sortable" />
     < copyField source = "type" dest = "type_sortable" />
     < uniqueKey >uid</ uniqueKey >
     < defaultSearchField >content</ defaultSearchField >
     < solrQueryParser defaultOperator = "OR" />
</ schema >

and for solr-spring.xml

<? xml version = "1.0" ?>
< beans
         default-destroy-method = "destroy"
         default-init-method = "afterPropertiesSet"
         xmlns = "

Once you have SOLR up and running with the new schema, you just need to tweak the solr-web.war a little bit before deploying it on all nodes as it assumes SOLR is running on localhost:8080 which probably isn't the case. You can change this is in the solr-spring.xml file that you can find in the WEB-INF/classes/META-INF directory of the WAR file. Just change the constructor-arg value of the bean with id com.liferay.portal.search.solr.server.BasicAuthSolrServer so it points to the correct server and port.

 

Media gallery

Now that the document library and image gallery have been combined to form the media gallery in newer Liferay versions, the configuration to cluster it has also simplified. To cluster the media gallery you have 2 options: database or file system. There was also an option to useJackrabbit for this purpose, but this has been deprecated in Liferay 6.1.

Using the database is the simplest option as you only need to add one property to your portal-ext.properties file

This will automatically use the database that is already configured for Liferay to store al media items. As long a your database supports BLOBs of sufficient size to cover your media needs, this is an easy solution. But if your database has issues with large files, like videos for example, you can best use the second option: a common filesystem.

For this, you only need to configure a different store, usuallyeither com.liferay.portlet.documentlibrary.store.FileSystemStore 

or 
com.liferay.portlet.documentlibrary.store.AdvancedFileSystemStore (internally distributes lots of files over more directories to work around limitations of number of files per directory). To use a file system store correctly, you'll also need to configure the property dl.store.file.system.root.dir in your portal-ext.properties to point to a directory on the local filesystem of each node that points to a common file store, SAN, NAS, etc... . The problem with this is that the Liferay documentation doesn't exactly define what kind of file systems are supported or what kind of functionalities (locking, etc... ) they need to support. So it can be a bit of hit and miss finding one that works correctly.

Another option is to use the com.liferay.portlet.documentlibrary.store.CMISStore if you have an Alfresco instance to spare or the com.liferay.portlet.documentlibrary.store.S3Store if you have Amazon S3 buckets available. The only problem with these can be speed as they're usually slower than using a file system.

 

Quartz

The Quartz job scheduler that's available in Liferay also needs to be clustered to prevent problems. This can be done by adding the following line to your portal-ext.properties file:

Cluster Link

In a Liferay cluster all nodes need to be able to talk to each other to keep each other up to date. To enable this, you just need to activate the JGroups based Cluster Link system that's available in Liferay by adding the following two properties to your portal-ext.properties file:

The second property is needed because otherwise the Cluster Link initialization during startup will possibly fail because by default it will try to contact google.com:80 and access to the internet isn't always possible in some environments. For that reason you'll need to have a host/port combination that is reachable by the cluster link and that it can be used to set up itself. The easiest option for this is to use thedatabase server and port that we already know (and can access) and use that to replace dbserver and dbport in the example above.

In order to make the JGroups Cluster Link you'll also need to set the following system properties for your JVM (for example via the JAVA_OPTS of Tomcat):

Ehcache: multicast

In a Liferay cluster the different Ehcache based caches on a node also need to be aware of other nodes so that correct and up to date information is shown on nodes after something is changed on one node. When your server environment supports multicast (some virtualization software has issues with this) and your system administrators allow you to use it, it is pretty easy to configure Ehcache to work in a cluster. Just add the following lines to your portal-ext.properties on each node:

When using multicast isn't possible you'll need to use the information in the next section of this blog.

Ehcache: unicast

In some server environments it might not be possible or allowed to use multicast. Unfortunately this is the default way of communication in a Liferay cluster and the only thoroughly documented way. So when we were faced with the task of setting up a cluster, while only using unicast, we had to do some Sherlock Holmes level investigations. After many hours of Googling, reading forums, trial and error, ... we were able to get it to work.

First off you need to create an JGroups configuration XML that will be the basis of the unicast setup. This XML is what will actually set up JGroups to use TCP instead of UDP. Once you have this file, you just need to provide it as configuration for a couple of properties and things will magically start working. Just create an XML file with the content below and name it unicast.xml (the name is not important as long as you remember to use the same value in the portal-ext.properties) and place it in the WEB-INF/classes directory of Liferay:

-->

Once you have this file in place you just need to add some additional configuration to your portal-ext.properties to configure the Liferay cluster link and Ehcache to use it:


### 回答1: 很抱歉,您遇到了这个问题。这个错误提示通常是在安装或配置软件时出现的。这可能是由于许多不同的原因造成的,例如配置文件的错误设置、缺少依赖项、权限问题等。 要解决此问题,您可以尝试以下几种方法: 1. 检查您的配置文件是否正确设置,并确保您已经安装了所需的依赖项。 2. 确保您有足够的权限来访问所需的文件和目录。您可以尝试使用sudo命令来运行程序,以便获得管理员权限。 3. 查看程序的日志文件以了解更多信息。日志文件通常包含有关错误原因的详细信息,帮助您更好地诊断问题。 4. 如果您仍然无法解决问题,请尝试在相关的技术论坛或社区中寻求帮助。您可能会得到更多的建议和指导。 希望这些方法能够帮助您解决问题。如果您需要进一步的帮助,请告诉我更多细节,我会尽力回答您的问题。 ### 回答2: "A problem occurred configuring" 是一个英语短语,指的是在配置过程中出现了问题。它通常用于描述在软件安装、网络设置或设备连接等过程中遇到的困难或错误。 这个问题的具体原因可能有很多种。可能是由于错误的输入、配置文件的损坏、网络连接的故障、设备驱动程序的不兼容性或其他未知的技术问题。 解决这个问题的方法取决于具体的情况。首先,我们应该检查输入是否准确且符合要求,确保所有的配置选项都正确填写。如果是配置文件损坏,在备份的前提下,我们可以尝试使用备份文件进行修复。如果是网络连接问题,我们可以检查线缆连接、路由器设置或尝试重新启动网络设备。如果是设备驱动程序不兼容性,我们可以尝试更新或更换驱动程序。 此外,查找错误信息和日志文件也是解决问题的关键。这些信息通常会提供有关具体问题的详细信息,从而指导我们采取正确的行动。我们可以在互联网上搜索类似的问题和解决方案,或者寻求专业人士的帮助。 总之,在遇到配置问题时,我们应该耐心且仔细地诊断问题,并采取适当的解决方案。通过正确的操作和合理的解决方案,我们通常能够成功解决配置问题并继续进行正常的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值