Quantcast
Channel: Archives des Alfresco - dbi Blog
Viewing all 50 articles
Browse latest View live

Alfresco Clustering – Apache HTTPD as Load Balancer

$
0
0

In previous blogs, I talked about some basis and presented some possible architectures for Alfresco, I talked about the Clustering setup for the Alfresco Repository, the Alfresco Share and for ActiveMQ. In this one, I will talk about the Front-end layer, but in a very particular setup because it will also act as a Load Balancer. For an Alfresco solution, you can choose the front-end that you prefer and it can just act as a front-end to protect your Alfresco back-end components, to add SSL or whatever. There is no real preferences but you will obviously need to know how to configure it. I posted a blog some years ago for Apache HTTPD as a simple front-end (here) or you can check the Alfresco documentation which now include a section for that as well but there is no official documentation for a Load Balancer setup.

In an Alfresco architecture that includes HA/Clustering you will, at some point, need a Load Balancer. From time to time, you will come across companies that do not already have a Load Balancer available and you might therefore have to provide something to fill this gap. Since you will most probably (should?) already have a front-end to protect Alfresco, why not using it as well as a Load Balancer? In this blog, I choose Apache HTTPD because that’s the front-end I’m usually using and I know it’s working fine as a LB as well.

The architectures that I described in the first blog of this series, there always were a front-end installed on each node with Alfresco Share and there were a LB above that. Here, these two boxes are actually together. There are multiple ways to set that up but I didn’t want to talk about that in my first blog because it’s not really related to Alfresco, it’s above that so it would just have multiplied the possible architectures that I wanted to present and my blog would just have been way too long. There were also no communications between the different front-end nodes because technically speaking, we aren’t going to setup Apache HTTPD as a Cluster, we only need to provide a High Availability solution.

Alright so let’s say that you don’t have a Load Balancer available and you want to use Apache HTTPD as a front-end+LB for a two-node Cluster. There are several solutions so here are two possible ways to do that from an inbound communication point of view that will still provide redundancy:

  • Setup a Round Robin DNS that points to both Apache HTTPD node1 and node2. The DNS will redirect connections to either of the two Apache HTTPD (Active/Active)
  • Setup a Failover DNS with a pretty low TimeToLive (TTL) which will point to a single Apache HTTPD node and redirect all traffic there. If this one isn’t available, it will failover to the second one (Active/Passive)

 

In both cases above, the Apache HTTPD configuration can be exactly the same, it will work. From an outbound communication point of view, Apache HTTPD will talk directly with all the Share nodes behind it. To avoid disconnection and loss of sessions in case an Apache HTTPD is going down, the solution will need to support session stickiness across all Apache HTTPD. With that, all communications coming a single browser will always be redirected to the same backend server which ensures that the sessions are still intact, even if you are losing an Apache HTTPD. I mentioned previously that there won’t be any communications between the different front-ends so this session stickiness must be based on something present inside the session (header or cookie) or inside the URL.

With Apache HTTPD, you can use the Proxy modules to provide both a front-end configuration as well as a Load Balancer but, in this blog, I will use the JK module. The JK module is provided by Apache for communications between Apache HTTPD and Apache Tomcat. It has been designed and optimized for this purpose and it also provides/supports a Load Balancer configuration.

 

I. Apache HTTPD setup for a single back-end node

For this example, I will use the package provided by Ubuntu for a simple installation. You can obviously build it from source to customize it, add your best practices, aso… This has nothing to do with the Clustering setup, it’s a simple front-end configuration for any installation. So let’s install a basic Apache HTTPD:

[alfresco@httpd_n1 ~]$ sudo apt-get install apache2 libapache2-mod-jk
[alfresco@httpd_n1 ~]$ sudo systemctl enable apache2.service
[alfresco@httpd_n1 ~]$ sudo systemctl daemon-reload
[alfresco@httpd_n1 ~]$ sudo a2enmod rewrite
[alfresco@httpd_n1 ~]$ sudo a2enmod ssl

 

Then to configure it for a single back-end Alfresco node (I’m just showing a minimal configuration again, there is much more to do add security & restrictions around Alfresco and mod_jk):

[alfresco@httpd_n1 ~]$ cat /etc/apache2/sites-available/alfresco-ssl.conf
...
<VirtualHost *:80>
    RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName            dns.domain
    ServerAlias           dns.domain dns
    ServerAdmin           email@domain
    SSLEngine             on
    SSLProtocol           -all +TLSv1.2
    SSLCipherSuite        EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:AES2
    SSLHonorCipherOrder   on
    SSLVerifyClient       none
    SSLCertificateFile    /etc/pki/tls/certs/dns.domain.crt
    SSLCertificateKeyFile /etc/pki/tls/private/dns.domain.key

    RewriteRule ^/$ https://%{HTTP_HOST}/share [R,L]

    JkMount /* alfworker
</VirtualHost>
...
[alfresco@httpd_n1 ~]$
[alfresco@httpd_n1 ~]$ cat /etc/libapache2-mod-jk/workers.properties
worker.list=alfworker
worker.alfworker.type=ajp13
worker.alfworker.port=8009
worker.alfworker.host=share_n1.domain
worker.alfworker.lbfactor=1
[alfresco@httpd_n1 ~]$
[alfresco@httpd_n1 ~]$ sudo a2ensite alfresco-ssl
[alfresco@httpd_n1 ~]$ sudo a2dissite 000-default
[alfresco@httpd_n1 ~]$ sudo rm /etc/apache2/sites-enabled/000-default.conf
[alfresco@httpd_n1 ~]$
[alfresco@httpd_n1 ~]$ sudo service apache2 restart

 

That should do it for a single back-end Alfresco node. Again, this was just an example, I wouldn’t recommend using the configuration as is (inside the alfresco-ssl.conf file), there is much more to do for security reasons.

 

II. Adaptation for a Load Balancer configuration

If you want to configure your Apache HTTPD as a Load Balancer, then on top of the standard setup shown above, you just have to modify two things:

  • Modify the JK module configuration to use a Load Balancer
  • Modify the Apache Tomcat configuration to add an identifier for Apache HTTPD to be able to redirect the communication to the correct back-end node (session stickiness). This ID put in the Apache Tomcat configuration will extend the Session’s ID like that: <session_id>.<tomcat_id>

 

So on all the nodes hosting the Apache HTTPD, you should put the exact same configuration:

[alfresco@httpd_n1 ~]$ cat /etc/libapache2-mod-jk/workers.properties
worker.list=alfworker

worker.alfworker.type=lb
worker.alfworker.balance_workers=node1,node2
worker.alfworker.sticky_session=true
worker.alfworker.method=B

worker.node1.type=ajp13
worker.node1.port=8009
worker.node1.host=share_n1.domain
worker.node1.lbfactor=1

worker.node2.type=ajp13
worker.node2.port=8009
worker.node2.host=share_n2.domain
worker.node2.lbfactor=1
[alfresco@httpd_n1 ~]$
[alfresco@httpd_n1 ~]$ sudo service apache2 reload

 

With the above configuration, we keep the same JK Worker (alfworker) but instead of using a ajp13 type, we use a lb type (line 4) which is an encapsulation. The alfworker will use 2 sub-workers named node1 and node2 (line 5), that’s just a generic name. The alfworker will also enable stickiness and use the method B (Busyness), which means that for new sessions, Apache HTTPD to choose to use the worker with the less requests being served, divided by the lbfactor value.

Each sub-worker (node1 and node2) define their type which is ajp13 this time, the port and host it should target (where the Share nodes are located) and the lbfactor. As mentioned above, increasing the lbfactor means that more requests are going to be sent to this worker:

  • For the node2 to serve 100% more requests than the node1 (x2), then set worker.node1.lbfactor=1 and worker.node2.lbfactor=2
  • For the node2 to serve 50% more requests than the node1 (x1.5), then set worker.node1.lbfactor=2 and worker.node2.lbfactor=3

 

The second thing to do is to modify the Apache Tomcat configuration to add a specific ID. On the Share node1:

[alfresco@share_n1 ~]$ grep "<Engine" $CATALINA_HOME/conf/server.xml
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="share_n1">
[alfresco@share_n1 ~]$

 

On the Share node2:

[alfresco@share_n2 ~]$ grep "<Engine" $CATALINA_HOME/conf/server.xml
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="share_n2">
[alfresco@share_n2 ~]$

 

The value to be put in the jvmRoute parameter is just a string so it can be anything but it must be unique across all Share nodes so that the Apache HTTPD JK module can find the correct back-end node that it should transfer the requests to.

It’s that simple to configure Apache HTTPD as a Load Balancer in front of Alfresco… To check which back-end server you are currently using, you can use the browser’s utilities and in particular the network recording which will display, in the headers/cookies section, the Session ID which will therefore display the value that you put in the jvmRoute.

 

 

Other posts of this series on Alfresco HA/Clustering:

Cet article Alfresco Clustering – Apache HTTPD as Load Balancer est apparu en premier sur Blog dbi services.


Alfresco Clustering – Solr6

$
0
0

In previous blogs, I talked about some basis and presented some possible architectures for Alfresco, I talked about the Clustering setup for the Alfresco Repository, the Alfresco Share and for ActiveMQ. I also setup an Apache HTTPD as a Load Balancer. In this one, I will talk about the last layer that I wanted to present, which is Solr and more particularly Solr6 (Alfresco Search Services) Sharding. I planned on writing a blog related to Solr Sharding Concepts & Methods to explain what it brings concretely but unfortunately, it’s not ready yet. I will try to post it in the next few weeks, if I find the time.

 

I. Solr configuration modes

So, Solr supports/provides three configuration modes:

  • Master-Slave
  • SolrCloud
  • Standalone


Master-Slave
: It’s a first specific configuration mode which is pretty old. In this one, the Master node is the only to index the content and all the Slave nodes will replicate the Master’s index. This is a first step to provide a Clustering solution with Solr, and Alfresco supports it, but this solution has some important drawbacks. For example, and contrary to an ActiveMQ Master-Slave solution, Solr cannot change the Master. Therefore, if you lose your Master, there is no indexing happening anymore and you need to manually change the configuration file on each of the remaining nodes to specify a new Master and target all the remaining Slaves nodes to use the new Master. This isn’t what I will be talking about in this blog.

SolrCloud: It’s another specific configuration mode which is a little bit more recent, introduced in Solr4 I believe. SolrCloud is a true Clustering solution using a ZooKeeper Server. It adds an additional layer on top of a Standalone Solr which is slowing it down a little bit, especially on infrastructures with a huge demand on indexing. But at some points, when you start having dozens of Solr nodes, you need a central place to organize and configure them and that’s what SolrCloud is very good at. This solution provides Fault Tolerance as well as High Availability. I’m not sure if SolrCloud could be used by Alfresco because sure SolrCloud also has Shards and its behaviour is pretty similar to a Standalone Solr but it’s not entirely working in the same way. Maybe it’s possible, however I have never seen it so far. Might be the subject of some testing later… In any cases, using a SolrCloud for Alfresco might not be that useful because it’s really easier to setup a Master-Master Solr mixed with Solr Sharding for pretty much the same benefits. So, I won’t talk about SolrCloud here either.

You guessed it, in this blog, I will only talk about Standalone Solr nodes and only using Shards. Alfresco supports Solr Shards only since the version 5.1. Before that, it wasn’t possible to use this feature, even if Solr4 provided it already. When using the two default cores (the famous “alfresco” & “archive” cores), with all Alfresco versions (all supporting Solr… So since Alfresco 4), it is possible to have a High Available Solr installation by setting up two Solr Standalone nodes and putting a Load Balancer in front of it but in this case, there is no communication between the Solr nodes so, it’s only a HA solution, nothing more.

 

In the architectures that I presented in the first blog of this series, if you remember the schema N°5 (you probably don’t but no worry, I didn’t either), I put a link between the two Solr nodes and I mentioned the following related to this architecture:
“N°5: […]. Between the two Solr nodes, I put a Clustering link, that’s in case you are using Solr Sharding. If you are using the default cores (alfresco and archive), then there is no communication between distinct Solr nodes. If you are using Solr Sharding and if you want a HA architecture, then you will have the same Shards on both Solr nodes and in this case, there will be communications between the Solr nodes, it’s not really a Clustering so to speak, that’s how Solr Sharding is working but I still used the same representation.”

 

II. Solr Shards creation

As mentioned earlier in this blog, there are real Cluster solutions with Solr but in the case of Alfresco, because of the features that Alfresco adds like the Shard Registration, there is no real need to set up complex things like that. Having just a simple Master-Master installation of Solr6 with Sharding is already a very good and strong solution to provide Fault Tolerance, High Availability, Automatic Failover, Performance improvements, aso… So how can that be setup?

First, you will need to install at least two Solr Standalone nodes. You can use exactly the same setup for all nodes and it’s also exactly the same setup to use the default cores or Solr Sharding so just do what you are always doing. For the Tracking, you will need to use the Load Balancer URL so it can target all Repository nodes, if there are several.

If you created the default cores, you can remove them easily:

[alfresco@solr_n1 ~]$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 150
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">524</int></lst>
</response>
* Connection #0 to host localhost left intact
[alfresco@solr_n1 ~]$
[alfresco@solr_n1 ~]$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 150
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">485</int></lst>
</response>
* Connection #0 to host localhost left intact
[alfresco@solr_n1 ~]$

 

A status of “0” means that it’s successful.

Once that’s done, you can then simply create the Shards. In this example, I will:

  • use the DB_ID_RANGE method
  • use two Solr nodes
  • for workspace://SpacesStore: create 2 Shards out of a maximum of 10 with a range of 20M
  • for archive://SpacesStore: create 1 Shard out of a maximum of 5 with a range of 50M

Since I will use only two Solr nodes and since I want a High Availability on each of the Shards, I will need to have them all on both nodes. With a simple loop, it’s pretty easy to create all the Shards:

[alfresco@solr_n1 ~]$ solr_host=localhost
[alfresco@solr_n1 ~]$ solr_node_id=1
[alfresco@solr_n1 ~]$ begin_range=0
[alfresco@solr_n1 ~]$ range=19999999
[alfresco@solr_n1 ~]$ total_shards=10
[alfresco@solr_n1 ~]$
[alfresco@solr_n1 ~]$ for shard_id in `seq 0 1`; do
>   end_range=$((${begin_range} + ${range}))
>   curl -v "http://${solr_host}:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=${total_shards}&numNodes=${total_shards}&nodeInstance=${solr_node_id}&template=rerank&coreName=alfresco&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
>   echo ""
>   echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
>   echo ""
>   sleep 2
>   begin_range=$((${end_range} + 1))
> done

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=10&numNodes=10&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-19999999&property.shard.instance=0 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 182
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">254</int></lst><str name="core">alfresco-0</str>
</response>
* Connection #0 to host localhost left intact

  -->  Range N°0 created with: 0-19999999


*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=10&numNodes=10&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=20000000-39999999&property.shard.instance=1 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 182
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">228</int></lst><str name="core">alfresco-1</str>
</response>
* Connection #0 to host localhost left intact

  -->  Range N°1 created with: 20000000-39999999

[alfresco@solr_n1 ~]$
[alfresco@solr_n1 ~]$ begin_range=0
[alfresco@solr_n1 ~]$ range=49999999
[alfresco@solr_n1 ~]$ total_shards=4
[alfresco@solr_n1 ~]$ for shard_id in `seq 0 0`; do
>   end_range=$((${begin_range} + ${range}))
>   curl -v "http://${solr_host}:8983/solr/admin/cores?action=newCore&storeRef=archive://SpacesStore&numShards=${total_shards}&numNodes=${total_shards}&nodeInstance=${solr_node_id}&template=rerank&coreName=archive&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
>   echo ""
>   echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
>   echo ""
>   sleep 2
>   begin_range=$((${end_range} + 1))
> done

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=archive://SpacesStore&numShards=4&numNodes=4&nodeInstance=1&template=rerank&coreName=archive&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-49999999&property.shard.instance=0 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 181
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">231</int></lst><str name="core">archive-0</str>
</response>
* Connection #0 to host localhost left intact

-->  Range N°0 created with: 0-49999999

[alfresco@solr_n1 ~]$

 

On the Solr node2, to create the same Shards (another Instance of each Shard) and therefore provide the expected setup, just re-execute the same commands but replacing solr_node_id=1 with solr_node_id=2. That’s all there is to do on Solr side, just creating the Shards is sufficient. On the Alfresco side, configure the Shards registration to use the Dynamic mode:

[alfresco@alf_n1 ~]$ cat $CATALINA_HOME/shared/classes/alfresco-global.properties
...
# Solr Sharding
solr.useDynamicShardRegistration=true
search.solrShardRegistry.purgeOnInit=true
search.solrShardRegistry.shardInstanceTimeoutInSeconds=60
search.solrShardRegistry.maxAllowedReplicaTxCountDifference=500
...
[alfresco@alf_n1 ~]$

 

After a quick restart, all the Shard’s Instances will register themselves to Alfresco and you should see that each Shard has its two Shard’s Instances. Thanks to the constant Tracking, Alfresco knows which Shard’s Instances are healthy (up-to-date) and which ones aren’t (either lagging behind or completely silent). When performing searches, Alfresco will make a request to any of the healthy Shard’s Instances. Solr will be aware of the healthy Shard’s Instances as well and it will start the distribution of the search request to all the Shards for the parallel query. This is the communication between the Solr nodes that I mentioned earlier: it’s not really Clustering but rather query distribution between all the healthy Shard’s Instances.

 

 

Other posts of this series on Alfresco HA/Clustering:

Cet article Alfresco Clustering – Solr6 est apparu en premier sur Blog dbi services.

Alfresco – Share Clustering fail with ‘Ignored XML validation warning’

$
0
0

In a recent project on Alfresco, I had to setup a Clustering environment. It all went smoothly but I did face one single issue with the setup of the Clustering on the Alfresco Share layer. That’s something I never faced before and you will understand why below.

Initially, to setup the Alfresco Share Clustering, I used the sample file packaged in the distribution zip (E.g.: alfresco-content-services-distribution-6.1.0.5.zip):

<?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:hz="http://www.hazelcast.com/schema/spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.hazelcast.com/schema/spring
                https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd">

   <!--
        Hazelcast distributed messaging configuration - Share web-tier cluster config
        - see http://www.hazelcast.com/docs.jsp
        - and specifically http://docs.hazelcast.org/docs/2.4/manual/html-single/#SpringIntegration
   -->
   <!-- Configure cluster to use either Multicast or direct TCP-IP messaging - multicast is default -->
   <!-- Optionally specify network interfaces - server machines likely to have more than one interface -->
   <!-- The messaging topic - the "name" is also used by the persister config below -->
   <!--
   <hz:topic id="topic" instance-ref="webframework.cluster.slingshot" name="slingshot-topic"/>
   <hz:hazelcast id="webframework.cluster.slingshot">
      <hz:config>
         <hz:group name="slingshot" password="alfresco"/>
         <hz:network port="5801" port-auto-increment="true">
            <hz:join>
               <hz:multicast enabled="true"
                     multicast-group="224.2.2.5"
                     multicast-port="54327"/>
               <hz:tcp-ip enabled="false">
                  <hz:members></hz:members>
               </hz:tcp-ip>
            </hz:join>
            <hz:interfaces enabled="false">
               <hz:interface>192.168.1.*</hz:interface>
            </hz:interfaces>
         </hz:network>
      </hz:config>
   </hz:hazelcast>

   <bean id="webframework.cluster.clusterservice" class="org.alfresco.web.site.ClusterTopicService" init-method="init">
      <property name="hazelcastInstance" ref="webframework.cluster.slingshot" />
      <property name="hazelcastTopicName"><value>slingshot-topic</value></property>
   </bean>
   -->

</beans>

 

I obviously uncommented the whole section and configured it properly for the Share Clustering. The above content is only the default/sample content, nothing more.

Once configured, I restarted Alfresco but it failed with the following messages:

24-Aug-2019 14:35:12.974 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
24-Aug-2019 14:35:12.974 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.34
24-Aug-2019 14:35:12.988 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying configuration descriptor [/opt/tomcat/conf/Catalina/localhost/share.xml]
Aug 24, 2019 2:35:15 PM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Aug 24, 2019 2:35:15 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Aug 24, 2019 2:35:15 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
2019-08-23 14:35:16,052  WARN  [factory.xml.XmlBeanDefinitionReader] [localhost-startStop-1] Ignored XML validation warning
 org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; schema_reference.4: Failed to read schema document 'https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.warning(ErrorHandlerWrapper.java:100)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:392)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4218)
  ... 69 more
Caused by: java.net.ConnectException: Connection refused (Connection refused)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
	... 89 more
...
2019-08-23 14:35:16,067  ERROR [web.context.ContextLoader] [localhost-startStop-1] Context initialization failed
 org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [surf-config.xml]
Offending resource: class path resource [web-application-config.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
  ... 33 more
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
	... 42 more
Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:397)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303)
	... 44 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
	... 64 more
...
24-Aug-2019 14:35:16.196 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
24-Aug-2019 14:35:16.198 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal Context [/share] startup failed due to previous errors
Aug 24, 2019 2:35:16 PM org.apache.catalina.core.ApplicationContext log
...

 

As you can see above, the message is pretty clear: there is a problem within the file “/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml” which is causing Share to fail to start properly. The first warning message points you directly to the issue: “Failed to read schema document ‘https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd’

After checking the content of the sample file and comparing it with a working one, I found out what was wrong. To solve this specific issue, you can simply replace “https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd” with “http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd“. Please note the two differences in the URL:

  • Switch from “https” to “http
  • Switch from “hazelcast.com” to “www.hazelcast.com

 

The issue was actually caused by the fact that this installation was completely offline, with no access to internet. Because of that, Spring wasn’t able to check for the XSD file to validate the definition in the context file. The solution is therefore to switch the URL to http with www.hazelcast.com so that the Spring internal resolution can understand and use the local file to do the validation and not look for it online.

As mentioned previously, I never faced this issue before for two main reasons:

  • I usually don’t use the sample files provided by Alfresco, I always prefer to build my own
  • I mainly install Alfresco on servers which have internet access (outgoing communications allowed)

 

Once the URL is corrected, Alfresco Share is able to start and the Clustering is configured properly:

24-Aug-2019 14:37:22.558 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
24-Aug-2019 14:37:22.558 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.34
24-Aug-2019 14:37:22.573 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying configuration descriptor [/opt/tomcat/conf/Catalina/localhost/share.xml]
Aug 24, 2019 2:37:24 PM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Aug 24, 2019 2:37:25 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Aug 24, 2019 2:37:25 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Resolving domain name 'share_n1.domain' to address(es): [10.10.10.10]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Resolving domain name 'share_n2.domain' to address(es): [127.0.0.1, 10.10.10.11]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Interfaces is disabled, trying to pick one address from TCP-IP config addresses: [share_n1.domain/10.10.10.10, share_n2.domain/10.10.10.11, share_n2.domain/127.0.0.1]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Prefer IPv4 stack is true.
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Picked Address[share_n2.domain]:5801, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=5801], bind any local is true
Aug 24, 2019 2:37:28 PM com.hazelcast.system
INFO: [share_n2.domain]:5801 [slingshot] Hazelcast Community Edition 2.4 (20121017) starting at Address[share_n2.domain]:5801
Aug 24, 2019 2:37:28 PM com.hazelcast.system
INFO: [share_n2.domain]:5801 [slingshot] Copyright (C) 2008-2012 Hazelcast.com
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [share_n2.domain]:5801 [slingshot] Address[share_n2.domain]:5801 is STARTING
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.TcpIpJoiner
INFO: [share_n2.domain]:5801 [slingshot] Connecting to possible member: Address[share_n1.domain]:5801
Aug 24, 2019 2:37:28 PM com.hazelcast.nio.ConnectionManager
INFO: [share_n2.domain]:5801 [slingshot] 54991 accepted socket connection from share_n1.domain/10.10.10.10:5801
Aug 24, 2019 2:37:29 PM com.hazelcast.impl.Node
INFO: [share_n2.domain]:5801 [slingshot] ** setting master address to Address[share_n1.domain]:5801
Aug 24, 2019 2:37:35 PM com.hazelcast.cluster.ClusterManager
INFO: [share_n2.domain]:5801 [slingshot]

Members [2] {
	Member [share_n1.domain]:5801
	Member [share_n2.domain]:5801 this
}

Aug 24, 2019 2:37:37 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [share_n2.domain]:5801 [slingshot] Address[share_n2.domain]:5801 is STARTED
2019-08-23 14:37:37,664  INFO  [web.site.ClusterTopicService] [localhost-startStop-1] Init complete for Hazelcast cluster - listening on topic: share_hz_test
...

 

Cet article Alfresco – Share Clustering fail with ‘Ignored XML validation warning’ est apparu en premier sur Blog dbi services.

Solr Sharding – Concepts & Methods

$
0
0

A few weeks ago, I published a series of blog on the Alfresco Clustering, including Solr Sharding. At that time, I planned to first explain what is really the Solr Sharding, what are the different concepts and methods around it. Unfortunately, I didn’t get the time to write this blog so I had to post the one related to Solr even before explaining the basics. Today, I’m here to rights my wrong! Obviously, this blog has a focus on Alfresco related Solr Sharding since that’s what I do.

I. Solr Sharding – Concepts

The Sharding in general is the partitioning of a set of data in a specific way. There are several possibilities to do that, depending on the technology you are working on. In the scope of Solr, the Sharding is therefore the split of the Solr index into several smaller indices. You might be interested in the Solr Sharding because it improves the following points:

  • Fault Tolerance: with a single index, if you lose it, then… you lost it. If the index is split into several indices, then even if you are losing one part, you will still have all others that will continue working
  • High Availability: it provides more granularity than the single index. You might want for example to have a few small indices without HA and then have some others with HA because you configured them to contain some really important nodes of your repository
  • Automatic Failover: Alfresco knows automatically (with Dynamic Registration) which Shards are up-to-date and which ones are lagging behind so it will choose automatically the best Shards to handle the search queries so that you get the best results possible. In combination with the Fault Tolerance above, this gives the best possible HA solution with the less possible resources
  • Performance improvements: better performance in indexing since you will have several Shards indexing the same repository so you can have less work done by each Shards for example (depends on Sharding Method). Better performance in searches since the search query will be processes by all Shards in parallel on smaller parts of the index instead of being one single query on the full index

Based on benchmarks, Alfresco considers that a Solr Shard can contain up to 50 to 80 000 000 nodes. This is obviously not a hard limit, you can have a single Shard with 200 000 000 nodes but it is more of a best practice if you want to keep a fast and reliable index. With older versions of Alfresco (before the version 5.1), you couldn’t create Shards because Alfresco didn’t support it. So, at that time, there were no other solutions than having a single big index.

There is one additional thing that must be understood here: the 50 000 000 nodes soft limit is 50M nodes in the index, not in the repository. Let’s assume that you are using a DB_ID_RANGE method (see below for the explanation) with an assumed split of 65% live nodes, 20% archived nodes, 15% others (not indexed: renditions, other stores, …). So, if we are talking about the “workspace://SpacesStore” nodes (live ones), then if we want to fill a Shard with 50M nodes, we will have to use a DB_ID_RANGE of 100*50M/65 = 77M. Basically, the Shard should be more or less “full” once there are 77M IDs in the Database. For the “archive://SpacesStore” nodes (archived ones), it would be 100*50M/20 = 250M.

Alright so what are the main concepts in the Solr Sharding? There are several terms that need to be understood:

  • Node: It’s a Solr Server (a Solr installed using the Alfresco Search Services). Below, I will use “Solr Server” instead because I already use “nodes” (lowercase) for the Alfresco Documents so using “Node” (uppercase) for the Solr Server, it might be a little bit confusing…
  • Cluster: It’s a set of Solr Servers all working together to index the same repository
  • Shard: A part of the index. In other words, it’s a representation (virtual concept) of the index composed of a certain set of nodes (Alfresco Documents)
  • Shard Instance: It’s one Instance of a specific Shard. A Shard is like a virtual concept while the Instance is the implementation of that virtual concept for that piece of the index. Several Shard Instances of the same Shard will therefore contain the same set of Alfresco nodes
  • Shard Group: It’s a collection of Shards (several indices) that forms a complete index. Shards are part of the same index (same Shard Group) if they:
    • Track the same store (E.g.: workspace://SpacesStore)
    • Use the same template (E.g.: rerank)
    • Have the same number of Shards max (“numShards“)
    • Use the same configuration (Sharding methods, Solr settings, …)

Shard is often (wrongly) used in place of Shard Instance which might lead to some confusion… When you are reading “Shard”, sometimes it means the Shard itself (the virtual concept), sometimes it’s all its Shard Instances. This is these concepts can look like:
Solr Sharding - Concepts

II. Solr Sharding – Methods

Alfresco supports several methods for the Solr Sharding and they all have different attributes and different ways of working:

  • MOD_ACL_ID (ACL v1): Alfresco nodes and ACLs are grouped by their ACL ID and stored together in the same Shard. Different ACL IDs will be assigned randomly to different Shards (depending on the number of Shards you defined). Each Alfresco node using a specific ACL ID will be stored in the Shard already containing this ACL ID. This simplifies the search requests from Solr since ACLs and nodes are together, so permission checking is simple. If you have a lot of documents using the same ACL, then the distribution will not be even between Shards. Parameters:
    • shard.method=MOD_ACL_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • ACL_ID (ACL v2): This is the same as the MOD_ACL_ID, the only difference is that it changes the method to assign to ACL to the Shards so it is more evenly distributed but if you still have a lot of documents using the same ACL then you still have the same issue. Parameters:
    • shard.method=ACL_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • DB_ID: This is the default Sharding Method in Solr 6 which will evenly distribute the nodes in the different Shards based on their DB ID (“alf_node.id“). The ACLs are replicated on each of the Shards so that Solr is able to perform the permission checking. If you have a lot of ACLs, then this will obviously make the Shards a little bit bigger, but this is usually insignificant. Parameters:
    • shard.method=DB_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • DB_ID_RANGE: Pretty much the same thing as the DB_ID but instead of looking into each DB ID one by one, it will just dispatch the DB IDs from the same range into the same Shard. The ranges are predefined at the Shard Instance creation and you cannot change them later, but this is also the only Sharding Method that allows you to add new Shards dynamically (auto-scaling) without the need to perform a full reindex. The lower value of the range is included and the upper value is excluded (for Math lovers: [begin-end[ ;)). Since DB IDs are incremental (increase over time), performing a search query with a date filter might end-up as simple as checking inside a single Shard. Parameters:
    • shard.method=DB_ID_RANGE
    • shard.range=<begin-end>
    • shard.instance=<shard.instance>
  • DATE: Months will be assigned to a specific Shard sequentially and then nodes are indexed into the Shard that was assigned the current month. Therefore, if you have 2 Shards, each one will contain 6 months (Shard 1 = Months 1,3,5,7,9,11 // Shard 2 = Months 2,4,6,8,10,12). It is possible to assign consecutive months to the same Shard using the “shard.date.grouping” parameter which defines how many months should be grouped together (a semester for example). If there is no date on a node, the fallback method is to use DB_ID instead. Parameters:
    • shard.method=DATE
    • shard.key=exif:dateTimeOriginal
    • shard.date.grouping=<1-12>
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • PROPERTY: A property is specified as the base for the Shard assignment. The first time that a node is indexed with a new value for this property, the node will be assigned randomly to a Shard. Each node coming in with the same value for this property will be assigned to the same Shard. Valid properties are either d:text (single line text), d:date (date only) or d:datetime (date+time). It is possible to use only a part of the property’s value using “shard.regex” (To keep only the first 4 digit of a date for example: shard.regex=^\d{4}). If this property doesn’t exist on a node or if the regex doesn’t match (if any is specified), the fallback method is to use DB_ID instead. Parameters:
    • shard.method=PROPERTY
    • shard.key=cm:creator
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • EXPLICIT_ID: Pretty much similar to the PROPERTY but instead of using the value of a “random” property, this method requires a specific property (d:text) to define explicitly on which Shard the node should be indexed. Therefore, this will require an update of the Data Model to have one property dedicated to the assignment of a node to a Shard. In case you are using several types of documents, then you will potentially want to do that for all. If this property doesn’t exist on a node or if an invalid Shard number is given, the fallback method is to use DB_ID instead. Parameters:
    • shard.method=EXPLICIT_ID
    • shard.key=<property> (E.g.: cm:targetShardInstance)
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>

As you can see above, each Sharding Method has its own set of properties. You can define these properties in:

  • The template’s solrcore.properties file in which case it will apply to all Shard Instance creations
    • E.g.: $SOLR_HOME/solrhome/templates/rerank/conf/solrcore.properties
  • The URL/Command used to create the Shard Instance in which case it will only apply to the current Shard Instance creation
    • E.g.: curl -v “http://host:port/solr/admin/cores?action=newCore&…&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0

Summary of the benefits of each method:
Solr Sharding - Benefits

First supported versions for the Solr Sharding in Alfresco:
Solr Sharding - Availability

Hopefully, this is a good first look into the Solr Sharding. In a future blog, I will talk about the creation process and show some example of what is possible. If you want to read more on the subject, don’t hesitate to take a look at the Alfresco documentation, it doesn’t explain everything, but it is still a very good starting point.

Cet article Solr Sharding – Concepts & Methods est apparu en premier sur Blog dbi services.

CMIS – What importance does it have in ECM World?

$
0
0

As you know, there is a lot of vendors for Enterprise Content Management systems (ECM) and they all have different interfaces. Content Management Interoperability Services (CMIS) is a standard for improving interoperability between Enterprise Content Management systems. The vendor-neutral OASIS Web services interface specification published two versions of CMIS v1.0 and v1.1, then the Technical Committee was closed on 09 May 2017 and is no longer active but the standard is still used by almost all CMS products.

What this means?
In fact, you can write applications targeting Alfresco, Documentum, SharePoint and other ECM systems using CMIS without writing one line of a vendor-specific code, so one source code to interoperate with them all… Compare it with JDBC to connect to any database that provides a JDBC driver 😉
This kind of standardization must survive and be constantly up to date, because it enable applications to target different ECM repositories uniformly with a common interface and I think that is really cool.

CMIS Basics

CMIS Repository

At the root of the CMIS model and services is a repository, which is an instance of the content management system and its store of metadata, content, and indexes.

The repository is the end point to which all requests are directed. In the RESTful model, it is the root path of the resources being addressed in CMIS, then it is capable of describing itself and its capabilities.

CMIS Query

A CMIS Query is based upon SQL-92. The query is read-only and presents no data manipulation capabilities!

The syntax consists of the following clauses:

  • SELECT with a target list.
  • FROM with the object types being queried.
  • JOIN to perform a join between object types.
  • WHERE with the predicate.
  • IN and ANY to query multi-value properties.
  • CONTAINS to specify a full-text qualification.
  • IN_FOLDER and IN_TREE to search within a folder hierarchy.
  • ORDERBY to sort the results.

The CMIS query maps the object type into a relational structure where object type approximates a table, the object approximates a row, and the property approximates a column that can be multi-valued.

CMIS Services

CMIS provides services that you can access using SOAP or AtomPub, and include the following:

  • Repository services let you discover available repositories, get the capabilities of these repositories, and provide basic Data Dictionary information of what types are available in the repository.
  • Navigation services let you navigate the repository by accessing the folder tree and traversing the folder/child hierarchy.
  • Object services provide the basics (Create, Read, Update, Delete) and Control services on any object, including document, folder, policy, and relationship objects. For document objects, this includes setting and getting of properties, policies, and content streams.
  • Object services retrieve objects by path or object ID. Applications may also discover what actions users are allowed to perform.
  • Multi-filing services let you establish the hierarchy by adding or removing an object to or from a folder.
  • Discovery services provide Query and Change services, and a means of paging the results of the query.
  • Change services let you discover what content has changed since the last time checked, as specified by a special token. You can use Change services for external search indexing and replication services.
  • Versioning services control concurrent operation of the Object services by providing Check In and Check Out services. Version services also provide version histories for objects that are versioned.
  • Relationship services let you create, manage, and access relationships or associations between objects as well as allow an application to traverse those associations.
  • Policy services apply policies on document objects. Policies are free-form objects and can be used by implementations for security, record, or control policies.
  • ACL services let you create, manage, and access Access Control Lists to control who can perform certain operations on an object.

CMIS Bindings

Web Services (SOAP)
This binding is based on the SOAP protocol All services and operations defined in the CMIS domain model specification are present in the Web Services binding. For example, in Alfresco you can get a summary of the CMIS services from the following URL:

http://<hostname>:<port>/alfresco/cmis

AtomPUB (REST)
This RESTful binding is based on the Atom Publishing Protocol. Clients communicate with the repository by requesting the service document, which is obtained through a well-known URI. For example, in Alfresco the service document is at:

http://<hostname>:<port>/alfresco/api/-default-/public/cmis/versions/1.1/atom

Personnaly, I used AtomPUB which works very well, and I think is being the most performant and the most popular. But if you’ve ever looked at the XML that comes back from a CMIS AtomPub call you know how verbose it can be!

CMIS v1.0 vs v1.1

CMIS 1.1 has some exciting new features comparing to v1.0. I will not list all v1.1 news, but you can find below the two important news (for me):

Browser Binding

The Browser Binding is based on JSON, so the payloads that go between client and server are smaller, making it the fastest of the three bindings.
The original purpose of the Browser Binding was to make it easy for those building “single page” web apps, but I think apps of all types will move to the Browser Binding because it is easier to work with.

Type Mutability

This allows CMIS developers to create and update the repository’s content model with code. Sometimes you will need content types to store objects with metadata specific to your solution.
Before CMIS 1.1, you have to ship repository-specific content models and configuration instructions with your app.
With CMIS 1.1, developers can simply write install and config logic as part of the solution that will interrogate the repository to determine if any changes need to be made to the content model to support the solution.

So, for the moment we have CMIS 1.0 and 1.1, which is cool but as you know things are moving fast and the CMIS need to follow… Do you think that we will see a CMIS 2.0 soon?

Cet article CMIS – What importance does it have in ECM World? est apparu en premier sur Blog dbi services.

Solr Sharding – Shard creation

$
0
0

I wrote this blog in conjunction with the one about the Solr Sharding – Concepts & Methods a year ago and it was 95% completed but then I had other stuff to do and just forgot I didn’t publish it. It might be a little bit late but well, better late than never… It will complete the overview I wanted to share around the Alfresco Clustering and in particular around the Solr Sharding. In this blog, I will talk about the creation of Shards. This includes the distribution of the different Instances, explaining the global parameters that can be used and showing some examples of what can be done with the concrete commands to achieve that.

I. Shard distribution

One of the strong points of using the Solr Sharding is that you can do pretty much what you want with the distribution of the Shards. It means that you can choose the best distribution of Shards based on your requirements, based on the resources available (Number of Solr Servers, RAM, I/O, …) and then Alfresco can just work with that seamlessly. Let’s consider some situations:

  • 1 Solr Server – 2 Shards – No HA (1 Shard Instance per Shard)
  • 2 Solr Server – 2 Shards – No HA (1 Shard Instance per Shard)
  • 2 Solr Server – 2 Shards – HA (2+ Shard Instances per Shard)
  • 6 Solr Server – 3 Shards – HA (2+ Shard Instances per Shard)

For the above examples, there are several possible representation of the Shards repartitions across the different Solr Servers. If we consider all Shards in the same way (same number of Shard Instance for each), then you can represent the above examples as follow:

Sharding distribution 1

If the Shard N°1 is the most important one and you want this one to be available on all Solr Servers with a maximum of 2 Shards per Solr Server, then this is another possible solution:

Sharding distribution 2

There are several ways to distribute the Shards and the good thing is that it is not really linked with the Sharding Method used. What I mean is that you can define the distribution that you want and it will be possible whatever the Sharding Method is. However, in some cases, the Method used might have an impact on whether or not the chosen distribution make sense. If I take the above example again where the Shard N°1 would be considered he most important one, then it means that you should know exactly what is inside this Shard N°1 but if DB_ID is used, then the content of this Shard will be random… Therefore, even if there is no hard link, some choice might not make a lot of sense if both aspects aren’t considered ;).

Alfresco (ACS only, not community) provides a graphical representation of the Solr Shards on the Alfresco Administration Console (https://alfresco-dns.domain/alfresco/s/enterprise/admin/admin-flocs). This is very useful to quickly see what is setup, how it is organized and what is the status of each and every Shards: whether they are up-to-date, lagging behind or not running at all. Here is an example of 1 Shard Group composed of 5 Shards with 2 Instances each:

Shard Groups

Shard Instances

In addition to that, I always find it very useful to look at the Solr reports (https://solr-dns.domain/solr/admin/cores?action=REPORT and https://solr-dns.domain/solr/admin/cores?action=SUMMARY) since it gives an overview of exactly how many acls and nodes are indexed. These are well known reports for Alfresco but in case you never saw these, I would advise you to take a look.

II. Shard creation parameters

As mentioned in the previous blog related to the Sharding Methods, when creating a Shard Instance, you will need to define some parameters. Here, I will only define them in the URL/Command because it is easier to have everything there. In addition to these parameters specific to each Method, there are some that are global. Before diving into the commands, let’s take a look at a few parameters and what they represent:

  • storeRef: Which Alfresco Store should this Shard index
  • numShards: Maximum number of different Shards that can be created
    • For DB_ID_RANGE, even if you need only 2 Shards at the moment, put more here (like 10/20) to be able to create new Shards in the future as the index grows. Once this limit is defined, you cannot exceed it so keep some margin
    • For all other Methods, set that to the number of Shards needed
  • numNodes: Maximum number of Solr Servers that can be used
    • For DB_ID_RANGE, even if you have only 2 Solr Servers at the moment, put more here (like 10/20) to be able to install new Solr Servers and create Shard Instances in the future. Once this limit is defined, you cannot exceed it so keep some margin
    • For all other Methods, even if you have only 2 Solr Servers at the moment, put more here (like 10/20). Maybe in the future you will want to have the same Shards (fix number) on more Solr Servers. Once this limit is defined, you cannot exceed it so keep some margin
  • nodeInstance: The “ID/Number” of the Solr Server on which the command is going to be executed, from 1 to numNodes, included
  • template: Which template should be used as base to create the new Core. The templates can be found under <SOLR_HOME>/solrhome/templates/
  • coreName: The base name of the Solr Core that this Shard should be part of. If you do not specify one, it will be generated from the Alfresco storeRef (E.g.: “workspace-SpacesStore”). Usual names can be “alfresco” or “archive” for example (Name of the default non-sharded cores)
  • shardIds: An ID that controls the generated Core Name, Base URL and Solr Data storage. This is to differentiate instances of Shards on a single Solr Server. You might think that this is the “ID/Number” of the Shard but not necessarily: with the DB_ID_RANGE for example, you can have the same shardIds used on two different Solr Servers for different Shards because the important thing is the range, it’s not the shardIds parameter in this case. So be careful here, this might be confusing. A best practice is however to have this shardIds set to the real “ID/Number” of the Shard so that it avoids confusion in all cases
  • replicationFactor: Technically speaking, the replication of a Shard Instance is another Shard Instance indexing the same set of nodes (so from the same Shard). You can normally mention the “replicationFactor” parameter in Solr but with the way it was implemented for Alfresco, you don’t need to care about that actually. You will see in the example below that to have several Shard Instances for the same Shard, you only need to execute the same commands on different servers
  • property.XXX: All the properties that can be set in the template’s solrcore.properties as well as the Sharding Method specific ones like:
    • property.data.dir.root: The place where the index will be put
    • property.shard.method: The Sharding Method to be used to create this Shard Instance
    • property.shard.instance: This is supposed to be the real “ID/Number” of the Shard for which a Shard Instance should be created (from 0 to numShards-1)

In summary, with the above parameters:

  • The name of the Core will be: ${coreName}-${shardIds}
  • The Solr Data will be put under: ${data.dir.root}/${coreName}-${shardIds}
  • The Solr Home will be put under: ${solr.solr.home}/${template}–${coreName}–shards–${numShards}-x-${replicationFactor}–node–${nodeInstance}-of-${numNodes}/${coreName}-${shardIds}
  • The Base URL will be: ${solr.baseurl}/${coreName}-${shardIds}
  • The Shard that will be created (unless otherwise): ${property.shard.instance}

One final note about the parameters: you need to be extra careful with these. I will say it again but in case of DB_ID_RANGE for example, Solr will not care about the shardIds or the property.shard.instance, it will only care about what it needs to index and that is based on the range… If you are using the Dynamic Registration, Alfresco will (and this is where the confusion can start) show you (in the Admin Console > Search Services Sharding) wrong information because it will base itself on the “property.shard.instance” to know to which Shard this instance belongs to (or at least supposed to…). This is just a graphical representation of the Shard Instances (so normally no impact on searches) but still, if you want an efficient and correct graphical view, keep things consistent!

III. Examples

a. DB_ID_RANGE

I will use the “High Availability – 6 Solr Server – 3 Shards (2nd solution)” as working example to show which commands can be used to create these: 3 different Shards, 4 Shard Instances for each on the 6 Solr Servers. I will use the DB_ID_RANGE Method so it is easy to see the differences between each command and identify for which Shard an Instance will be created. I will use a range of 50 000 000, assume that we can go up to 20 Shards (so 1 000 000 000 at maximum) on up to 12 Solr Servers.

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2

b. DATE

In this section, I will use the same setup but with a DATE Sharding Method. I will keep the same details as well (3 Shards) and therefore, each Shard Instance will contain 4 of the 12 months. There are several ways to obtain this:

  • No grouping option (default 1): Shard N°1 will contain the months 1,4,7,10 // Shard N°2 will contain the months 2,5,8,11 // Shard N°3 will contain the months 3,6,9,12
  • Grouping of 2: Shard N°1 will contain the months 1,2,7,8 // Shard N°2 will contain the months 3,4,9,10 // Shard N°3 will contain the months 5,6,11,12
  • Grouping of 3: Shard N°1 will contain the months 1,2,3,10 // Shard N°2 will contain the months 4,5,6,11 // Shard N°3 will contain the months 7,8,9,12
  • Grouping of 4: Shard N°1 will contain the months 1,2,3,4 // Shard N°2 will contain the months 5,6,7,8 // Shard N°3 will contain the months 9,10,11,12

Here, I will be group the months by 4. Since this is not the DB_ID_RANGE Method, all the Shard Instances for a Solr Server can be created by single command. However, when doing so, you cannot specify the “property.shard.instance” because it would contain several values (0,1,2 for example) and it is as far as I know, not supported. Therefore, the Shards will be created based on the “shardIds” parameter which has no problem with comma separated list:

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″

c. ACL_ID (ACL v2)

In this section, I will use the same setup but with an ACL_ID Sharding Method. I will keep the same details as well (3 Shards). Each of the three Shards will get assigned some of the ACLs of the Alfresco Repository and it will index all the Alfresco nodes that have these specific ACLs. Therefore, it will be a random assignment that might or might not be evenly distributed (the more ACLs you have, the more evenly it is supposed to be in theory):

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=ACL_ID&property.shard.count=3″

IV. Conclusion & final remarks:

At first, it might be a little confusing to work with Solr Sharding because there are a lot of terms that might overlap each-other a little bit but once you get it, it is such a pleasure to so easily create this kind of indexing architecture. Some final remarks:

  • As mentioned previously, you can create all the Instances on a Solr Server using a single command, except if you are using the DB_ID_RANGE because that contains the one variable parameter that needs to change between two different Shards. If the Instances are part of the same Shard (with the same range), then you can create them all in a single command.
  • If you want to have different Shards on the same Solr Server, then you need to change “property.shard.instance” (because it is a different Shard) and “shardIds” (because the Core & Base URL needs to be unique per Solr Server). The Shard Instance will belong to the Shard specified in “property.shard.instance” by default. If not present, it will use “shardIds” (as always, unless there is a range specified for the DB_ID_RANGE Method because this takes precedence over anything else).
  • If you want to have several Instances of the same Shard on the same Solr Server, then you need to change “shardIds” and keep “property.shard.instance” the same. If you can avoid that, then you should, for simplicity and consistency, but if you have a requirement to have two Instances of the same Shard on the same Solr Server, it is still possible.

If you are interested in playing with the Solr Sharding but you don’t have an existing infrastructure in place, you might want to take a look at this GitHub project from Angel Borroy which should help you to go further. Have fun!

Cet article Solr Sharding – Shard creation est apparu en premier sur Blog dbi services.

Alfresco – ActiveMQ not starting, blocking Alfresco

$
0
0

As already mentioned in a previous blog, ActiveMQ has been used in the scope of Alfresco since quite some time. Initially, as an optional component but then, it became mandatory. Just like for the Database, if ActiveMQ isn’t installed or not reachable, Alfresco will never completely start. Of course, for the Database, you will see that quickly since there will be errors on the Alfresco startup logs but that’s not really the case for ActiveMQ because it is only a subsystem and Alfresco will just quietly wait for this “Messaging” subsystem to be available before continuing the startup process. In this blog, I will show a case I faced recently where ActiveMQ wouldn’t start for a non-obvious reason and therefore Alfresco was stuck in the startup process as well.

 

You can always try to disable the automatic startup of the “Messaging” subsystem (using “messaging.subsystem.autoStart=false“) and you might want to disable the Event one as well. However, it should only stop the automatic startup of the subsystem, that doesn’t mean that it won’t be started later, on-demand. Another alternative could be to use the in-memory broker queue (using something like “messaging.broker.url=vm://localhost?broker.persistent=false” and making sure you have the activemq broker jar loaded). These options are out of scope of this blog since I needed a real ActiveMQ installation, working.

 

So, in case the startup of Alfresco is blocked on the “Messaging” subsystem, the logs will contain something like:

alfresco@alf01:~$ cat /opt/tomcat/logs/catalina.out
...
2021-07-09 12:15:00,670  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Subscriptions' subsystem, ID: [Subscriptions, default]
2021-07-09 12:15:00,692  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Subscriptions' subsystem, ID: [Subscriptions, default] complete
2021-07-09 12:15:00,713  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Synchronization' subsystem, ID: [Synchronization, default]
2021-07-09 12:15:00,903  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Synchronization' subsystem, ID: [Synchronization, default] complete
2021-07-09 12:15:00,979  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco JVM - v11.0.10+9-Ubuntu-0ubuntu1.18.04; maximum heap size 4096.000MB
2021-07-09 12:15:01,019  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] ================================================================
2021-07-09 12:15:01,020  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco license: Mode ENTERPRISE, cluster:enabled granted to Trial User limited to 2 days expiring Sun Jul 11 00:00:00 CEST 2021 (2 days remaining).
2021-07-09 12:15:01,032  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Note: this is a limited trial of the Enterprise version of Alfresco Content Services that goes into read-only mode after 2 days. Request an extended 30-day trial at: https://www.alfresco.com/platform/content-services-ecm/trial/docker
2021-07-09 12:15:01,033  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] ================================================================
2021-07-09 12:15:01,034  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Server Mode :PRODUCTION
2021-07-09 12:15:01,035  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco Content Services started (Enterprise). Current version: 6.1.1 (3 r1dba1394-b23) schema 12,005. Originally installed version: 6.1.1 (3 r1dba1394-b23) schema 12,005.
2021-07-09 12:15:01,102  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default]
2021-07-09 12:15:01,892  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default] complete
2021-07-09 12:15:02,612  INFO  [repo.authorization.AuthorizationService] [localhost-startStop-1] Preauthorized user: admin
2021-07-09 12:15:02,620  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Replication' subsystem, ID: [Replication, default]
2021-07-09 12:15:02,640  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Replication' subsystem, ID: [Replication, default] complete
2021-07-09 12:15:05,278  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Messaging' subsystem, ID: [Messaging, default]
2021-07-09 12:15:44,013  WARN  [repo.usage.RepoUsageMonitor] [DefaultScheduler_Worker-3] The Alfresco Content Services license will expire in 2 days.
09-Jul-2021 12:16:17.538 INFO [hz._hzInstance_1_slingshot.cached.thread-3] com.hazelcast.nio.SocketAcceptor.null [alf01.dbi-services.com]:5801 [slingshot] 5801 is accepting socket connection from /10.10.10.12:56601
09-Jul-2021 12:16:17.551 INFO [hz._hzInstance_1_slingshot.cached.thread-3] com.hazelcast.nio.ConnectionManager.null [alf01.dbi-services.com]:5801 [slingshot] 5801 accepted socket connection from /10.10.10.12:56601
09-Jul-2021 12:16:24.522 INFO [hz._hzInstance_1_slingshot.ServiceThread] com.hazelcast.cluster.ClusterManager.null [alf01.dbi-services.com]:5801 [slingshot]

Members [2] {
 Member [alf01.dbi-services.com]:5801 this
 Member [alf02.dbi-services.com]:5801
}

2021-07-09 12:17:29,624  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Member joined: 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
2021-07-09 12:17:29,629  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Current cluster members:
 10.10.10.11:5701 (hostname: alf01.dbi-services.com)
 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
alfresco@alf01:~$

 

As shown above, the last message during startup is “Starting ‘Messaging’ subsystem, ID: [Messaging, default]“. After that, nothing happens anymore (remaining messages are related to license status and cluster management). As mentioned previously, this is because ActiveMQ is either not running at all, currently starting or just unreachable. Looking at the ActiveMQ logs showed the below:

alfresco@alf01:~$ date
Fri Jul  9 12:18:01 CEST 2021
alfresco@alf01:~$
alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 12:14:33,968 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 12:14:33 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 12:14:35,745 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/data/activemq/kahadb] | org.apache.activemq.broker.BrokerService | main
alfresco@alf01:~$

 

ActiveMQ is apparently in the starting process but it is also stuck on the Persistence Adapter. Looking at the configuration and the current files present:

alfresco@alf01:~$ grep -A2 "<persistenceAdapter" /opt/activemq/conf/activemq.xml
        <persistenceAdapter>
            <kahaDB directory="/data/activemq/kahadb"/>
        </persistenceAdapter>
alfresco@alf01:~$
alfresco@alf01:~$ ll /data/activemq/kahadb/
total 180
drwxr-x--- 1 alfresco alfresco       52 Jul  9 12:14 ./
drwxr-x--- 1 alfresco alfresco       12 Jul  9 12:14 ../
-rw-r----- 1 alfresco alfresco        8 Jul  9 12:14 lock
alfresco@alf01:~$

 

So, the lock file seems present but there is no DB yet. This usually happens when the lock wasn’t set yet. This environment is an Alfresco Cluster, with therefore multiple nodes and multiple ActiveMQ as well. The simplest setup in this case is to use a shared storage for the kahaDB (using NAS in this case). To debug the issue, I tried to start the ActiveMQ but with a local path, which isn’t on a NAS. It started properly:

alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 12:22:11,112 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 12:22:11 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 12:22:14,604 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/opt/activemq/data/kahadb] | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:14,839 | INFO  | PListStore:[/opt/activemq/data/alfdms.b1/tmp_storage] started | org.apache.activemq.store.kahadb.plist.PListStoreImpl | main
2021-07-09 12:22:15,088 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-37899-1625826134875-0:1) is starting | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:15,176 | INFO  | Listening for connections at: tcp://alf01:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,181 | INFO  | Connector openwire started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,207 | INFO  | Listening for connections at: amqp://alf01:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,215 | INFO  | Connector amqp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,235 | INFO  | Listening for connections at: stomp://alf01:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,244 | INFO  | Connector stomp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,263 | INFO  | Listening for connections at: mqtt://alf01:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,268 | INFO  | Connector mqtt started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,855 | WARN  | ServletContext@o.e.j.s.ServletContextHandler@4f449e8f{/,null,STARTING} has uncovered http methods for path: / | org.eclipse.jetty.security.SecurityHandler | main
2021-07-09 12:22:16,039 | INFO  | Listening for connections at ws://alf01:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.ws.WSTransportServer | main
2021-07-09 12:22:16,041 | INFO  | Connector ws started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:16,043 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-37899-1625826134875-0:1) started | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:16,045 | INFO  | For help or more information please see: http://activemq.apache.org | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:16,052 | WARN  | Store limit is 10240 mb (current store usage is 0 mb). The data directory: /opt/activemq/data/kahadb only has 8960 mb of usable space. - resetting to maximum available disk space: 8960 mb | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:17,585 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /admin | main
2021-07-09 12:22:18,425 | INFO  | ActiveMQ WebConsole available at http://0.0.0.0:8161/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 12:22:18,426 | INFO  | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 12:22:18,526 | INFO  | Initializing Spring FrameworkServlet 'dispatcher' | /admin | main
2021-07-09 12:22:18,802 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /api | main
2021-07-09 12:22:18,992 | INFO  | jolokia-agent: Using policy access restrictor classpath:/jolokia-access.xml | /api | main
alfresco@alf01:~$

 

As soon as ActiveMQ was running, Alfresco could continue the startup process as well:

2021-07-09 12:17:29,624  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Member joined: 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
2021-07-09 12:17:29,629  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Current cluster members:
 10.10.10.11:5701 (hostname: alf01.dbi-services.com)
 10.10.10.12:5701 (hostname: alf02.dbi-services.com)

2021-07-09 12:22:25,435  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Messaging' subsystem, ID: [Messaging, default] complete
2021-07-09 12:22:36,007  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 500 Web Scripts (+0 failed), 656 URLs
2021-07-09 12:22:36,020  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 1 Package Description Documents (+0 failed)
2021-07-09 12:22:36,021  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)
2021-07-09 12:22:36,106  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Web Scripts (+0 failed), 0 URLs
...

 

So, this issue is linked to the NAS. Since I already faced this kind of issue in the past years, I tried looking at the ports used by the NAS for the nlockmgr (Lock Manager):

alfresco@alf01:~$ rpcinfo -p 10.10.1.101 | grep nlockmgr
    100021    1   udp  52352  nlockmgr
    100021    3   udp  52352  nlockmgr
    100021    4   udp  52352  nlockmgr
    100021    1   tcp  46364  nlockmgr
    100021    3   tcp  46364  nlockmgr
    100021    4   tcp  46364  nlockmgr
alfresco@alf01:~$

 

I asked a colleague to look at the traces on the network layer, to see if something was being blocked/dropped and he could confirm me that the issue was simply that the port tcp/46364 was closed on the FireWall between the Alfresco/ActiveMQ VM and the NAS. Opening the port allowed ActiveMQ to request a lock of the file and therefore to start properly while using the NAS (port opened ~6min after the startup):

alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 13:51:07,231 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 13:51:07 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 13:51:10,349 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/data/activemq/kahadb] | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:44,643 | INFO  | PListStore:[/opt/activemq/data/alfdms.b1/tmp_storage] started | org.apache.activemq.store.kahadb.plist.PListStoreImpl | main
2021-07-09 13:57:44,794 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-40847-1625831864661-0:1) is starting | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:44,819 | INFO  | Listening for connections at: tcp://alf01:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,821 | INFO  | Connector openwire started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,830 | INFO  | Listening for connections at: amqp://alf01:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,834 | INFO  | Connector amqp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,843 | INFO  | Listening for connections at: stomp://alf01:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,846 | INFO  | Connector stomp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,857 | INFO  | Listening for connections at: mqtt://alf01:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,859 | INFO  | Connector mqtt started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:45,171 | WARN  | ServletContext@o.e.j.s.ServletContextHandler@4f449e8f{/,null,STARTING} has uncovered http methods for path: / | org.eclipse.jetty.security.SecurityHandler | main
2021-07-09 13:57:45,273 | INFO  | Listening for connections at ws://alf01:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.ws.WSTransportServer | main
2021-07-09 13:57:45,274 | INFO  | Connector ws started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:45,283 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-40847-1625831864661-0:1) started | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:45,285 | INFO  | For help or more information please see: http://activemq.apache.org | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:47,106 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /admin | main
2021-07-09 13:57:48,247 | INFO  | ActiveMQ WebConsole available at http://0.0.0.0:8161/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 13:57:48,247 | INFO  | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 13:57:48,297 | INFO  | Initializing Spring FrameworkServlet 'dispatcher' | /admin | main
2021-07-09 13:57:48,484 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /api | main
2021-07-09 13:57:48,640 | INFO  | jolokia-agent: Using policy access restrictor classpath:/jolokia-access.xml | /api | main
alfresco@alf01:~$
alfresco@alf01:~$ ll /data/activemq/kahadb/
total 180
drwxr-x--- 1 alfresco alfresco       52 Jul  9 13:57 ./
drwxr-x--- 1 alfresco alfresco       12 Jul  9 13:57 ../
-rw-r----- 1 alfresco alfresco  3554432 Jul  9 14:03 db-1.log
-rw-r----- 1 alfresco alfresco    53248 Jul  9 14:03 db.data
-rw-r----- 1 alfresco alfresco    53344 Jul  9 14:03 db.redo
-rw-r----- 1 alfresco alfresco        8 Jul  9 13:57 lock
alfresco@alf01:~$

 

There are other reasons why ActiveMQ might not start properly but usually, what’s happening will be written inside the logs. This one is one of the few cases I faced where it’s not that obvious…

 

Cet article Alfresco – ActiveMQ not starting, blocking Alfresco est apparu en premier sur Blog dbi services.

Alfresco – Custom Share action not working after disabling WebDAV servlet

$
0
0

On an Alfresco upgrade project I was working on recently, I faced an interesting issue where post upgrade, one of my custom Share action wasn’t working anymore. This action was used to create folder links for use on an external interface. When applied on a document, it would create a link to the parent folder for example and when applied on a folder, it would link to itself. Generated link could then be used from outside of Alfresco.

I created this custom action when I started working with Alfresco almost 10 years ago and I didn’t touch the source code since then, it always worked. Therefore, I was a little bit surprised when the action didn’t work anymore (the link would always redirect to the root of the Repository [/Company Home]) after the latest upgrade. The action is a simple JavaScript piece of code deployed as an AMP on the Share war file:

$ cat $ALF_HOME/tomcat/webapps/share/components/documentlibrary/folderlink.js
(function() {
  YAHOO.Bubbling.fire("registerAction", {
    actionName: "onActionFolderLink",
    fn: function dbiservices_onActionFolderLink(record) {
      var viewID = record.actionGroupId;
      var path = record.webdavUrl.replace('/webdav', '');
      ...

 

On this code, the “viewID” is used to know on which page and on which element is this action triggered. Possible values can be “folder-browse” (applied on a folder when you browse the repository), “document-browse” (applied on a document when you browse the repository) or “document-details” (applied on a document when viewing the details/preview of this document) for example. The second JavaScript variable “path” is supposed to be the path of the Alfresco Node. I used this “webdavUrl” when I created this method because I found that to be a simple way to retrieve the path, since you can use “record.displayName” to retrieve the name of the Node but you cannot use “record.displayPath” to retrieve its path (look at the end of this post for alternatives).

When trying to debug the issue, I used the JavaScript Console on the Share UI but my piece of code was working and giving me the correct outcome (using “document” instead of “record“). While looking further into the code, the issue was really that “record.webdavUrl” didn’t return anything when executed as part of the custom action while it was working properly on the JavaScript Console.

I couldn’t find anything on Alfresco side that would explain a different behavior between the two versions of Alfresco so I looked into the configuration instead (alfresco-global.properties) and saw that on the new server, the WebDAV was disabled. This was most probably done as part of a best practice, to disable whatever isn’t used. So, I tried to re-enable the WebDAV:

$ grep webdav $ALF_HOME/tomcat/shared/classes/alfresco-global.properties
webdav.enabled=true
system.webdav.servlet.enabled=true
system.webdav.activities.enabled=true
system.webdav.rootPath=${protocols.rootPath}

 

After a restart of Alfresco, the action suddenly worked without any problem. To do some more testing, I tried to enable only the “webdav.enabled=true” parameter but it stopped working again. So my next test was to enable only the servlet instead (“system.webdav.servlet.enabled=true“) and that was indeed sufficient.

Therefore, if you are using “webdavUrl” in any of your JavaScript code, make sure that you enable at least the servlet as follow:

$ grep webdav $ALF_HOME/tomcat/shared/classes/alfresco-global.properties
webdav.enabled=false
system.webdav.servlet.enabled=true
system.webdav.activities.enabled=false
system.webdav.rootPath=${protocols.rootPath}

 

There are other ways to retrieve the path of the working node on JavaScript inside a custom action so instead of enabling the WebDAV servlet, it is also possible (and probably better) to use another alternative. Here are the 4 different ways I know of, with an example value returned when executed on a Document:

  • record.webdavUrl -> ‘/webdav/dbi%20services/A%20Folder/My%20Document.docx’
  • record.location.path -> ‘/dbi services/A Folder’
  • record.location.repoPath -> ‘/dbi services/A Folder’
  • this.currentPath -> ‘/dbi services/A Folder’

 

As you can see, the values are rather similar, except for the node name (which can be retrieve with “record.displayName“) which is only present for the “webdavUrl” one. All the three other alternatives display the path up to the parent only. Therefore, if applied to a folder or document, you might also need the node name to be concatenated. In conclusion, if you do specifically need the “webdavUrl“, make sure that the “system.webdav.servlet.enabled” is set to true otherwise it won’t work.

 

Cet article Alfresco – Custom Share action not working after disabling WebDAV servlet est apparu en premier sur Blog dbi services.


Alfresco – Share Clustering fail with ‘Ignored XML validation warning’, again

$
0
0

In a previous blog, I mentioned an issue that I faced when upgrading an Alfresco Content Services 5.2 to 6.1 on a VM with no internet access. The solution was simply to change one of the schema “URL” so that it can fallback to local references, meaning that it will try to check and find the schema definition inside the jar files present in the classpath. When upgrading this exact same VM from 6.1 to 7.1, I had, again, the same error:

29-Nov-2021 08:19:07.891 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
29-Nov-2021 08:19:07.892 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.55]
29-Nov-2021 08:19:07.922 INFO [main] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying deployment descriptor [alfresco/alfresco-7.1.0.1/tomcat/conf/Catalina/localhost/share.xml]
2021-11-29 08:19:19,024  WARN  [factory.xml.XmlBeanDefinitionReader] [main] Ignored XML validation warning
 org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 92; schema_reference.4: Failed to read schema document 'http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
        at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
        at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.warning(ErrorHandlerWrapper.java:100)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:392)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
        at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4257)
        ...
Caused by: java.net.ConnectException: Connection refused (Connection refused)
...
2021-11-29 08:19:19,061  ERROR [web.context.ContextLoader] [main] Context initialization failed
 org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [surf-config.xml]
Offending resource: class path resource [web-application-config.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 19 in XML document from file [alfresco/alfresco-7.1.0.1/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:104)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:266)
        ...
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
...
29-Nov-2021 08:19:19.074 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
29-Nov-2021 08:19:19.077 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal Context [/share] startup failed due to previous errors

 

The first thing I checked was obviously if there were any differences between the previous and the new versions of the custom-slingshot-application-context.xml files. There was none, so it is not exactly the same issue, but it has the same consequences:

alfresco@alfvm01:alfresco$ ll
total 16
drwxr-x---  4 alfresco alfresco 4096 Nov 26 09:15 ./
drwxr-xr-x 10 alfresco alfresco 4096 Nov 26 10:09 ../
drwxr-x---  8 alfresco alfresco 4096 Nov 29 08:11 alfresco-6.1.1.3/
drwxr-x---  8 alfresco alfresco 4096 Nov 29 14:44 alfresco-7.1.0.1/
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ diff alfresco-*/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
alfresco@alfvm01:alfresco$

 

Since the file should normally be fine and able to fetch classpath definitions, then the issue would most probably be that either there are no jar files present anymore or the specific version that Share is looking for (as written in the log file: hazelcast-spring-2.4.xsd) doesn’t exist/isn’t found. So that’s what I looked into then:

alfresco@alfvm01:alfresco$ find alfresco-*/tomcat/webapps/share/ -name "*hazelcast*jar*"
alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-2.4.jar
alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-2.4.jar
alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-3.12.6.jar
alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-3.12.6.jar
alfresco@alfvm01:alfresco$

 

As you can see, the version of Hazelcast has been upgraded from 2.4 to 3.12. So, it’s probably a version mismatch since the jar files are present properly. Therefore, looking for the 2.4 XSD definition file inside the jar file is the next step:

alfresco@alfvm01:alfresco$ jar -tvf alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-2.4.jar | grep 'hazelcast-spring.*xsd'
 44024 Wed Oct 17 17:51:56 CEST 2012 hazelcast-spring-2.4.xsd
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ jar -tvf alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-3.12.6.jar | grep 'hazelcast-spring.*xsd'
178900 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.8.xsd
106805 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.4.xsd
 56119 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.2.xsd
190415 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.9.xsd
 52802 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.1.xsd
294159 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.12.xsd
148564 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.6.xsd
 50037 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.0.xsd
262083 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.11.xsd
 62043 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.3.xsd
157063 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.7.xsd
129308 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.5.xsd
236019 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.10.xsd
alfresco@alfvm01:alfresco$

 

As seen, the 2.4 XSD definition isn’t available in the new jar file, which would therefore be the culprit. The solution should then be to use the correct XSD definition version (switch from 2.4 to 3.12) in the custom-slingshot-application-context.xml file:

alfresco@alfvm01:alfresco$ sed -i 's,2\.4,3.12,' alfresco-7.1.0.1/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ diff alfresco-*/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
8c8
<                 http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd">
---
>                 http://www.hazelcast.com/schema/spring/hazelcast-spring-3.12.xsd">
13c13
<         - and specifically http://docs.hazelcast.org/docs/2.4/manual/html-single/#SpringIntegration
---
>         - and specifically http://docs.hazelcast.org/docs/3.12/manual/html-single/#SpringIntegration
alfresco@alfvm01:alfresco$

 

After the update and a restart, the Share Clustering is able to start and it is working successfully:

29-Nov-2021 08:34:12.776 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
29-Nov-2021 08:34:12.777 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.55]
29-Nov-2021 08:34:12.796 INFO [main] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying deployment descriptor [alfresco/alfresco-7.1.0.1/tomcat/conf/Catalina/localhost/share.xml]
...
29-Nov-2021 08:34:26.437 INFO [main] com.hazelcast.system.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] Hazelcast 3.12.6 (20200130 - be02cc5) starting at [alfvm01.domain.com]:5801
29-Nov-2021 08:34:26.437 INFO [main] com.hazelcast.system.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved.
...
29-Nov-2021 08:34:27.729 INFO [main] com.hazelcast.core.LifecycleService.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] [alfvm01.domain.com]:5801 is STARTING
...
29-Nov-2021 08:34:28.790 INFO [main] com.hazelcast.core.LifecycleService.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] [alfvm01.domain.com]:5801 is STARTED

 

Currently, the Alfresco documentation contains the wrong references to the 2.4 version. I opened a PR to correct the documentation to use the 3.12 version instead (impacts all versions starting from ACS 7.0) so hopefully it should be updated soon. In the meantime, check that you are using the correct versions! In case your server does have internet access, then you will not have any issues but that means that Alfresco will always perform internet lookups to retrieve the 2.4 version of the XSD definition.

 

Cet article Alfresco – Share Clustering fail with ‘Ignored XML validation warning’, again est apparu en premier sur Blog dbi services.

Alfresco – Documents are searchable only after 3min

$
0
0

I had a case at a customer recently where newly uploaded documents into Alfresco would always be searchable but only after 2min45s to 3min. The environment in question is an Alfresco Content Services 7.1 with High Availability (Repository and Share Clustering, Solr Sharding on multi-nodes, …) used for QA/TEST. It’s an ongoing project to upgrade an Alfresco 6.1 to 7.1 and during the testing, the documents take time to be visible through searches, everything else works properly.

 

Since there are a few similar environments on these exact same versions and setup, I tried to replicate the issue on two others but without success. On other instances, documents are searchable properly within the next 15 to 20s more or less, which is then expected based on the Solr Tracker schedule. No specific configurations were put that are out of the ordinary, it’s a rather straight forward setup that matches the previous one.

 

Since it’s a new version (ACS 7.1 / ASS 2.0.2), I thought that maybe it could be linked to the Sharding methods or the number of Shards, even if it shouldn’t (except if there is a bug, of course). So, I did some tests to reduce the number of Shards, change the Sharding method as well as completely remove Sharding and going back to a standard Alfresco/Archive cores setup. Here is an example of the main steps that can be used to remove the current Shards and create a unique new one for live documents:

### Solr Node1 & Node2
## Remove Solr Shards
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-0"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-1"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-2"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive-0"
## Stop Solr
$ sudo systemctl stop solr.service
## Cleanup config
$ rm -rf $SOLR_HOME/solrhome/rerank--a*
## Cleanup indexes
$ ls $SOLR_DATA_HOME/
content  index  models
$ rm -rf $SOLR_DATA_HOME/*/*
## Start Solr
$ sudo systemctl start solr.service
## Create Solr Shard for alfresco-0
$ solr_node_id=1    # for Solr Node2: solr_node_id=2
$ range=25000000
$ total_shards=20
$ for shard_id in `seq 0 0`; do
  begin_range=$((${shard_id} * ${range}))
  end_range=$(((${shard_id} + 1) * ${range}))
  curl -v "http://localhost:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=${total_shards}&numNodes=${total_shards}&nodeInstance=${solr_node_id}&template=rerank&coreName=alfresco&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
  echo ""
  echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
  echo ""
  sleep 2
$ done

 

After a full reindex, the behavior was the same, as we could expect. My next test would have been to try to revert to the previous Alfresco Search Services version (ASS 1.4.3) that was used but while doing the testing and checking the SUMMARY and REPORT generated by Solr (E.g.: http://localhost:8983/solr/admin/cores?action=SUMMARY&core=alfresco-0), I found it strange that the value of “Date for last TX on server” and “Last Index TX Commit Date” didn’t match the time when I uploaded my latest document on Alfresco, it was delayed… I deleted and re-uploaded the document again and saw the same thing, the time didn’t match. This could only be because of Operating System time that doesn’t match between the Solr and Alfresco/DB servers.

 

What happened is that these servers do not have access to internet, and they weren’t set with an internal Time Server. The “systemd-timesyncd” service was enabled but it couldn’t synchronize the time because of that:

root@solr_node1:~$ timedatectl status
                      Local time: Mon 2021-12-13 12:35:34 UTC
                  Universal time: Mon 2021-12-13 12:35:34 UTC
                        RTC time: Mon 2021-12-13 12:38:05
                       Time zone: Etc/UTC (UTC, +0000)
       System clock synchronized: no
systemd-timesyncd.service active: yes
                 RTC in local TZ: no
root@solr_node1:~$
root@solr_node1:~$ timedatectl set-ntp off
root@solr_node1:~$ timedatectl set-ntp on
root@solr_node1:~$
root@solr_node1:~$ systemctl restart systemd-timesyncd.service
root@solr_node1:~$
root@solr_node1:~$ systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-12-13 12:38:55 UTC; 30s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 29451 (systemd-timesyn)
   Status: "Connecting to time server 91.189.94.4:123 (ntp.ubuntu.com)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─29451 /lib/systemd/systemd-timesyncd

Dec 13 12:38:55 solr_node1 systemd[1]: Starting Network Time Synchronization...
Dec 13 12:38:55 solr_node1 systemd[1]: Started Network Time Synchronization.
Dec 13 12:39:05 solr_node1 systemd-timesyncd[29451]: Timed out waiting for reply from 91.189.91.157:123 (ntp.ubuntu.com).
Dec 13 12:39:15 solr_node1 systemd-timesyncd[29451]: Timed out waiting for reply from 91.189.89.198:123 (ntp.ubuntu.com).
root@solr_node1:~$

 

As a quick workaround, the time was manually synchronized:

root@solr_node1:~$ date -s "13 Dec 2021 12:41:16Z"
Mon Dec 13 12:41:16 UTC 2021
root@solr_node1:~$

 

Right after, the issue was gone, documents were searchable around 20s after the upload to Alfresco. Obviously, the long-term solution is to setup correctly the Operating System with the customer’s correct Time Servers. If they are blocking internet, they must probably have their dedicated Time Servers. For information, this is how to configure custom Time Servers on Ubuntu 18.04:

root@solr_node1:~$ vi /etc/systemd/timesyncd.conf
root@solr_node1:~$
root@solr_node1:~$ grep -v '^#' /etc/systemd/timesyncd.conf
[Time]
NTP=ntp1.domain.com
FallbackNTP=ntp2.domain.com
root@solr_node1:~$
root@solr_node1:~$ systemctl restart systemd-timesyncd.service
root@solr_node1:~$
root@solr_node1:~$ systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-12-13 15:28:26 UTC; 15s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 29817 (systemd-timesyn)
   Status: "Synchronized to time server 10.10.10.10:123 (ntp1.domain.com)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─29817 /lib/systemd/systemd-timesyncd

Dec 13 15:28:25 solr_node1 systemd[1]: Starting Network Time Synchronization...
Dec 13 15:28:26 solr_node1 systemd[1]: Started Network Time Synchronization.
Dec 13 15:28:35 solr_node1 systemd-timesyncd[29817]: Synchronized to time server 10.10.10.10:123 (ntp1.domain.com).
root@solr_node1:~$
root@solr_node1:~$ timedatectl
                      Local time: Mon 2021-12-13 15:28:50 UTC
                  Universal time: Mon 2021-12-13 15:28:50 UTC
                        RTC time: Mon 2021-12-13 15:28:50
                       Time zone: Etc/UTC (UTC, +0000)
       System clock synchronized: yes
systemd-timesyncd.service active: yes
                 RTC in local TZ: no
root@solr_node1:~$

 

Cet article Alfresco – Documents are searchable only after 3min est apparu en premier sur Blog dbi services.

Alfresco – Removing JMX settings via the AttributeService since the Revert doesn’t work

$
0
0

At a customer, I recently faced a problem with the JMX settings that couldn’t be reverted. If you already worked with Alfresco, you know that it’s possible to save configurations through the Alfresco Administration Console and that doing so will store these settings into the Database. This has several drawbacks like the fact that it’s then impossible to manage your Alfresco through its configuration files since the DB settings will always take precedence and that can lead to nasty surprises. Another potential problem is that the settings will then be globally managed, meaning that you cannot have distinct values on distinct Alfresco Nodes (in case of clustering). Therefore, a best practice is to always use the Alfresco configuration files and not the JMX Settings, except for some quick testing but you must never forget to revert them.

During an upgrade to Alfresco Content Services 7.1.0.1, I had the unpleasant surprise, at that customer, that there were JMX Settings being used for the Solr configuration (and 1 for Lucene as well but not shown on the Administration Console) that I couldn’t remove. These settings were remainder, coming from a very old system that we didn’t manage at the time. As part of the upgrade process, to match our Best Practices, the JMX Settings were checked, and all removed using the “Revert” button on the Alfresco Administration Console. There was no problem with that on a few environments, but it was, unfortunately, not the case for the PROD where it just didn’t work. Trying to use the “Revert” button on the Alfresco Administration Console ended up with the following error and logs:

2022-02-03 20:15:14,962  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-6] admin-systemsummary.get.js Start
2022-02-03 20:15:15,052  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-6] admin-systemsummary.get.js End 90 ms
2022-02-03 20:15:18,165  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-4] admin-jmx-settings.get.js Start
2022-02-03 20:15:18,185  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-4] admin-jmx-settings.get.js End 19 ms
2022-02-03 20:15:37,373  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Resolving and compiling script path: jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-remote-api-11.153.jar!/alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/support-tools/admin-jmx-settings.post.js
2022-02-03 20:15:37,373  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Found script resource import: classpath:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/admin-common.lib.js
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Succesfully located script 'classpath:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/admin-common.lib.js'
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Found script resource import: classpath:alfresco/templates/webscripts/org/alfresco/repository/admin/admin-common.lib.js
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Succesfully located script 'classpath:alfresco/templates/webscripts/org/alfresco/repository/admin/admin-common.lib.js'
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Imports resolved, adding resource 'classpath:alfresco/templates/webscripts/org/alfresco/repository/admin/admin-common.lib.js
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Imports resolved, adding resource 'classpath:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/admin-common.lib.js
2022-02-03 20:15:37,374  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-1] Imports resolved, adding resource '_root
2022-02-03 20:15:37,383  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-1] admin-jmx-settings.post.js Start
2022-02-03 20:15:37,384  DEBUG [repo.jscript.ScriptLogger] [exec-1] beanName: Alfresco:Category=Search,Type=Configuration,id1=managed,id2=solr
2022-02-03 20:15:37,415  INFO  [management.subsystems.ChildApplicationContextFactory] [exec-1] Starting 'Search' subsystem, ID: [Search, managed, solr]
2022-02-03 20:15:37,735  WARN  [management.subsystems.ChildApplicationContextFactory$ChildApplicationContext] [exec-1] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
2022-02-03 20:15:38,237  WARN  [management.subsystems.ChildApplicationContextFactory] [exec-1] Startup of 'Search' subsystem, ID: [Search, managed, solr] failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1689)
        ...
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
        at org.springframework.beans.BeanWrapperImpl.createNotWritablePropertyException(BeanWrapperImpl.java:243)
        at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:432)
        at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
        ...
2022-02-03 20:15:38,238  ERROR [management.subsystems.PropertyBackedBeanAdapter] [exec-1] java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
2022-02-03 20:15:38,239  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-1] admin-jmx-settings.post.js Exception
org.mozilla.javascript.WrappedException: Wrapped javax.management.RuntimeMBeanException: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter? (classpath*:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/support-tools/admin-jmx-settings.post.js#486)
        at org.alfresco.enterprise.repo.management.script.ScriptableMBeanOperations$4.call(ScriptableMBeanOperations.java:398)
        at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:98)
        at org.mozilla.javascript.gen.classpath__alfresco_enterprise_webscripts_org_alfresco_enterprise_repository_admin_support_tools_admin_jmx_settings_post_js_20._c_main_17(classpath*:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/support-tools/admin-jmx-settings.post.js:486)
        ...
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
        at org.springframework.beans.BeanWrapperImpl.createNotWritablePropertyException(BeanWrapperImpl.java:243)
        at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:432)
        at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
        ...
2022-02-03 20:15:38,240  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-1] admin-jmx-settings.post.js End 857 ms
2022-02-03 20:15:38,242  ERROR [extensions.webscripts.AbstractRuntime] [exec-1] Exception from executeScript: 01030006 Wrapped Exception (with status template): 01030131 Failed to execute script 'classpath*:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/support-tools/admin-jmx-settings.post.js': java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
org.springframework.extensions.webscripts.WebScriptException: 01030006 Wrapped Exception (with status template): 01030131 Failed to execute script 'classpath*:alfresco/enterprise/webscripts/org/alfresco/enterprise/repository/admin/support-tools/admin-jmx-settings.post.js': java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'search.solrIndexCheckService' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-enterprise-repository-11.153.jar!/alfresco/subsystems/Search/solr/solr-jmx-context.xml]: Cannot resolve reference to bean 'solrAdminClient' while setting bean property 'solrAdminClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrAdminClient' defined in URL [jar:file:/opt/alfresco/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-11.140.jar!/alfresco/subsystems/Search/solr/solr-search-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
        at org.springframework.extensions.webscripts.AbstractWebScript.createStatusException(AbstractWebScript.java:1139)
        at org.springframework.extensions.webscripts.DeclarativeWebScript.execute(DeclarativeWebScript.java:171)
        at org.alfresco.repo.web.scripts.RepositoryContainer.lambda$transactionedExecute$2(RepositoryContainer.java:556)
        ...
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'solrHost' of bean class [org.alfresco.repo.solr.SOLRAdminClient]: Bean property 'solrHost' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
        at org.springframework.beans.BeanWrapperImpl.createNotWritablePropertyException(BeanWrapperImpl.java:243)
        at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:432)
        at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
        ...

 

So, what to do when JMX Settings cannot be Reverted like that? There is always the possibility to clean the Database directly (while Alfresco isn’t running) but the DB tables that store the JMX Settings are rather complex. It’s not impossible but it’s definitively not the recommended option if you can avoid it. Of course, if Alfresco cannot start at all anymore, you will have to go through the Database and remove things in there, so look at the following tables: alf_prop_link, alf_prop_value, alf_prop_string_value, alf_prop_root and alf_prop_unique_ctx. However, if Alfresco can start, then you have a much nicer and much safer way to remove JMX Settings: using the AttributeService!

The AttributeService is an interface of the Alfresco Java API to manage attributes. There isn’t much documentation about it but there are a few technical presentations: Alfresco’s Attribute Service Primer (June 2013) & Alfresco Tech Talk Live (Episode 75) (April 2014). The idea to use this service actually came initially from Bindu Wavell while we were discussing this topic on the Alfresco Discord (don’t hesitate to join us there) with other members of the Alfresco Community.

This AttributeService if very good for specific purposes but it’s initially part of the Java API, meaning that you would need to write a piece of Java to use it. That might be a problem for some customers or for you directly, if you aren’t really proficient in development. Fortunately, there is something, that (almost?) everybody in the Alfresco Community knows, called the JavaScript Console. It’s an addon that allows you to use the Alfresco JavaScript API on the Repository directly, by executing the code in the Share UI (i.e. in your browser). This addon also allows to do JavaScript-Java interoperability, meaning that you can use the Java API through the JavaScript Console. Here is an example of how to use the AttributeService.getAttributes method in the JavaScript Console:

var context = Packages.org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext();
var attributeService = context.getBean("attributeService", Packages.org.alfresco.repo.attributes.AttributeServiceImpl);

attributeService.getAttributes(function(id, value, keys) {
    print(' > id: ' + id);
    print('  >> key: ["' + keys[0] + '", "' + keys[1] + '"]');
    print('  >> value: ' + value);
    print('');
    return true;
}, ["keyCheck"]);

The first 2 lines above are related to the interoperability and the rest simply list all Attributes that share the same key(s) (in the above example, the key is: [“keyCheck”]). Using the AttributeService in this way is really simple and it might be harder to find the correct key(s) to use because there is no documentation on it. Obviously, if it’s related to your custom attributes, then you should know the keys since you created them, but what about the Alfresco OutOfTheBox ones? Alfresco made it so that it is unfortunately impossible (as far as I could see) to retrieve and list all attributes in one go. You would need to first find at least the top-level key for the attribute you are looking for before you can retrieve the associated value(s). It took me some time but, in the end, I was able to find what I was looking for inside the alf_prop_string_value DB table. The key(s) and its associated values are stored on this table and therefore to find them, you can just list its content. Most of the Alfresco OOTB keys appear to have a alf_prop_string_value.string_value starting with a dot. It’s not always the case as you can see above (it’s not [“.keyCheck”] but simply [“keyCheck”]) but it does gives already a certain list of keys to go through. Here is an example:

SQL> SELECT id, string_value
 2   FROM alf_prop_string_value
 3   WHERE string_value like '.%'
 4   ORDER BY 1 ASC;
  id              string_value
------  ---------------------------------
    21  .PropertyBackedBeans
    46  .ChainingUserRegistrySynchronizer
    55  .empty
    58  .repoUsages
    62  .SHARD_STATE
  1372  .clusterInfo
  1373  .cluster_name
  1375  .clusterMembers
  1377  .host_name
  1379  .ip_address
  1381  .port
  1382  .clustering_enabled
  1383  .last_registered
  1384  .cluster_node_type

 

For the JMX Settings specifically, the top-level key to be used is [“.PropertyBackedBeans”]. It is also possible to filter the list of attributes to retrieve by specifying a sub-level key. Going back to my customer case, even if the Alfresco Administration Console showed only one MBean (Alfresco:Category=Search,Type=Configuration,id1=managed,id2=solr), the AttributeService returned two set of Attributes stored on the DB, as I said before, one for Solr and one for Lucene:

The sub-level keys can be seen on the above screenshot, but you can also find their values from the DB as I said earlier as well as from the MBean name. For example, the MBean “Alfresco:Category=Search,Type=Configuration,id1=managed,id2=solr” can be translated to the key of [“.PropertyBackedBeans”, “Search$managed$solr”] (cat$id1$id2 in this case). Here are some more examples on how to retrieve the attributes using the AttributeService methods (getAttributes using a top-level key only, getAttributes using a top and sub-level key and another method getAttribute (without the s) to retrieve the value of a single attribute):

So, retrieving attributes is good and all but we still have our JMX Settings present… The next step is therefore to remove them and for that purpose, we will use the same top-level and sub-level keys that we found. First, removing the Lucene JMX Settings:

var context = Packages.org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext();
var attributeService = context.getBean("attributeService", Packages.org.alfresco.repo.attributes.AttributeServiceImpl);

attributeService.getAttributes(function(id, value, keys) {
    print(' > id: ' + id);
    print('  >> key: ["' + keys[0] + '", "' + keys[1] + '"]');
    print('  >> value: ' + value);
    //if ((keys[0] == ".PropertyBackedBeans") && (keys[1] == "Search$managed$solr")) {
    if ((keys[0] == ".PropertyBackedBeans") && (keys[1] == "Search$managed$lucene")) {
        attributeService.removeAttribute([keys[0], keys[1]]);
        print('   >>> The attribute for ["' + keys[0] + '", "' + keys[1] + '"] has been removed');
    }
    print('');
    return true;
}, [".PropertyBackedBeans"]);

 

Then, removing the Solr JMX Settings:

var context = Packages.org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext();
var attributeService = context.getBean("attributeService", Packages.org.alfresco.repo.attributes.AttributeServiceImpl);

attributeService.getAttributes(function(id, value, keys) {
    print(' > id: ' + id);
    print('  >> key: ["' + keys[0] + '", "' + keys[1] + '"]');
    print('  >> value: ' + value);
    if ((keys[0] == ".PropertyBackedBeans") && (keys[1] == "Search$managed$solr")) {
    //if ((keys[0] == ".PropertyBackedBeans") && (keys[1] == "Search$managed$lucene")) {
        attributeService.removeAttribute([keys[0], keys[1]]);
        print('   >>> The attribute for ["' + keys[0] + '", "' + keys[1] + '"] has been removed');
    }
    print('');
    return true;
}, [".PropertyBackedBeans"]);

 

It is also possible to obtain the same result by simply filtering the sub-level key on the method arguments (using [“.PropertyBackedBeans”, “Search$managed$solr”] on line 15 instead of [“.PropertyBackedBeans”]). The result would be exactly the same, but the above “if” statement make sure that you only remove what you expect to remove. It’s just another level of check, to prevent human error. Another alternative could be to use the removeAttribute method directly (so just the lines 1, 2 and 10 above), since the top-level and sub-level keys are known, it’s not really need to retrieve them first via the getAttributes… Therefore, proceed as prefered.

If you want the output of the JavaScript Console to appear on the Tomcat logs, you can replace “print” with “logger.warn” or “logger.info”. Here is an example of log generated for these actions:

  1. List JMX Attributes (cd2b1a49208e85e40e4978d80d59afd8.js) >> 2 sets of properties shown
  2. Remove Lucene JMX Attributes (cca083e1fc36fd7eb6691b47193a3885.js)
  3. Remove Solr JMX Attributes (716300901e28026ffc632490eed87be1.js)
  4. List JMX Attributes (cd2b1a49208e85e40e4978d80d59afd8.js) >> no properties remaining
2022-02-14 20:17:32,555  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-49] Resolving and compiling script path: cd2b1a49208e85e40e4978d80d59afd8.js
2022-02-14 20:17:32,562  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-49] cd2b1a49208e85e40e4978d80d59afd8.js Start
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]  > id: 21
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]   >> key: [".PropertyBackedBeans", "Search$managed$solr"]
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]   >> value: {solr.backup.alfresco.numberToKeep=3, search.solrTrackingSupport.enabled=true, solr.backup.archive.remoteBackupLocation=${dir.root}/solrBackup/archive, solr.backup.archive.cronExpression=0 0 4 * * ?, solr.host=localhost, solr.backup.alfresco.remoteBackupLocation=${dir.root}/solrBackup/alfresco, solr.backup.archive.numberToKeep=3, solr.backup.alfresco.cronExpression=0 0 2 * * ?, solr.port=8080, solr.port.ssl=8443}
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]  > id: 22 - key: .PropertyBackedBeans - Search$managed$lucene - value: {index.recovery.maximumPoolSize=5}
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]   >> key: [".PropertyBackedBeans", "Search$managed$lucene"]
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]   >> value: {index.recovery.maximumPoolSize=5}
2022-02-14 20:17:32,564  INFO  [repo.jscript.ScriptLogger] [exec-49]
2022-02-14 20:17:32,564  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-49] cd2b1a49208e85e40e4978d80d59afd8.js End 2 ms
2022-02-14 20:17:52,197  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-41] Resolving and compiling script path: cca083e1fc36fd7eb6691b47193a3885.js
2022-02-14 20:17:52,204  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-41] cca083e1fc36fd7eb6691b47193a3885.js Start
2022-02-14 20:17:52,206  INFO  [repo.jscript.ScriptLogger] [exec-41]  > id: 21
2022-02-14 20:17:52,206  INFO  [repo.jscript.ScriptLogger] [exec-41]   >> key: [".PropertyBackedBeans", "Search$managed$solr"]
2022-02-14 20:17:52,206  INFO  [repo.jscript.ScriptLogger] [exec-41]   >> value: {solr.backup.alfresco.numberToKeep=3, search.solrTrackingSupport.enabled=true, solr.backup.archive.remoteBackupLocation=${dir.root}/solrBackup/archive, solr.backup.archive.cronExpression=0 0 4 * * ?, solr.host=localhost, solr.backup.alfresco.remoteBackupLocation=${dir.root}/solrBackup/alfresco, solr.backup.archive.numberToKeep=3, solr.backup.alfresco.cronExpression=0 0 2 * * ?, solr.port=8080, solr.port.ssl=8443}
2022-02-14 20:17:52,207  INFO  [repo.jscript.ScriptLogger] [exec-41]
2022-02-14 20:17:52,207  INFO  [repo.jscript.ScriptLogger] [exec-41]  > id: 22 - key: .PropertyBackedBeans - Search$managed$lucene - value: {index.recovery.maximumPoolSize=5}
2022-02-14 20:17:52,207  INFO  [repo.jscript.ScriptLogger] [exec-41]   >> key: [".PropertyBackedBeans", "Search$managed$lucene"]
2022-02-14 20:17:52,207  INFO  [repo.jscript.ScriptLogger] [exec-41]   >> value: {index.recovery.maximumPoolSize=5}
2022-02-14 20:17:52,210  INFO  [repo.jscript.ScriptLogger] [exec-41]    >>> The attribute for [".PropertyBackedBeans", "Search$managed$lucene"] has been removed
2022-02-14 20:17:52,210  INFO  [repo.jscript.ScriptLogger] [exec-41]
2022-02-14 20:17:52,211  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-41] cca083e1fc36fd7eb6691b47193a3885.js End 6 ms
2022-02-14 20:18:41,840  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-12] Resolving and compiling script path: 716300901e28026ffc632490eed87be1.js
2022-02-14 20:18:41,847  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-12] 716300901e28026ffc632490eed87be1.js Start
2022-02-14 20:18:41,849  INFO  [repo.jscript.ScriptLogger] [exec-12]  > id: 21
2022-02-14 20:18:41,849  INFO  [repo.jscript.ScriptLogger] [exec-12]   >> key: [".PropertyBackedBeans", "Search$managed$solr"]
2022-02-14 20:18:41,849  INFO  [repo.jscript.ScriptLogger] [exec-12]   >> value: {solr.backup.alfresco.numberToKeep=3, search.solrTrackingSupport.enabled=true, solr.backup.archive.remoteBackupLocation=${dir.root}/solrBackup/archive, solr.backup.archive.cronExpression=0 0 4 * * ?, solr.host=localhost, solr.backup.alfresco.remoteBackupLocation=${dir.root}/solrBackup/alfresco, solr.backup.archive.numberToKeep=3, solr.backup.alfresco.cronExpression=0 0 2 * * ?, solr.port=8080, solr.port.ssl=8443}
2022-02-14 20:18:41,850  INFO  [repo.jscript.ScriptLogger] [exec-12]    >>> The attribute for [".PropertyBackedBeans", "Search$managed$solr"] has been removed
2022-02-14 20:18:41,850  INFO  [repo.jscript.ScriptLogger] [exec-12]
2022-02-14 20:18:41,850  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-12] 716300901e28026ffc632490eed87be1.js End 3 ms
2022-02-14 20:18:57,199  DEBUG [repo.jscript.RhinoScriptProcessor] [exec-37] Resolving and compiling script path: cd2b1a49208e85e40e4978d80d59afd8.js
2022-02-14 20:18:57,205  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-37] cd2b1a49208e85e40e4978d80d59afd8.js Start
2022-02-14 20:18:57,207  DEBUG [jscript.RhinoScriptProcessor.calls] [exec-37] cd2b1a49208e85e40e4978d80d59afd8.js End 1 ms

 

As shown above, the execution was done successfully, no errors and all the JMX Settings were finally gone:

A small restart of Alfresco, to make sure nothing has been broken and to clean the cache and you are good to go.

 

Cet article Alfresco – Removing JMX settings via the AttributeService since the Revert doesn’t work est apparu en premier sur Blog dbi services.

Alfresco Clustering – Solr6

$
0
0

In previous blogs, I talked about some basis and presented some possible architectures for Alfresco, I talked about the Clustering setup for the Alfresco Repository, the Alfresco Share and for ActiveMQ. I also setup an Apache HTTPD as a Load Balancer. In this one, I will talk about the last layer that I wanted to present, which is Solr and more particularly Solr6 (Alfresco Search Services) Sharding. I planned on writing a blog related to Solr Sharding Concepts & Methods to explain what it brings concretely but unfortunately, it’s not ready yet. I will try to post it in the next few weeks, if I find the time.

 

I. Solr configuration modes

So, Solr supports/provides three configuration modes:

  • Master-Slave
  • SolrCloud
  • Standalone


Master-Slave
: It’s a first specific configuration mode which is pretty old. In this one, the Master node is the only to index the content and all the Slave nodes will replicate the Master’s index. This is a first step to provide a Clustering solution with Solr, and Alfresco supports it, but this solution has some important drawbacks. For example, and contrary to an ActiveMQ Master-Slave solution, Solr cannot change the Master. Therefore, if you lose your Master, there is no indexing happening anymore and you need to manually change the configuration file on each of the remaining nodes to specify a new Master and target all the remaining Slaves nodes to use the new Master. This isn’t what I will be talking about in this blog.

SolrCloud: It’s another specific configuration mode which is a little bit more recent, introduced in Solr4 I believe. SolrCloud is a true Clustering solution using a ZooKeeper Server. It adds an additional layer on top of a Standalone Solr which is slowing it down a little bit, especially on infrastructures with a huge demand on indexing. But at some points, when you start having dozens of Solr nodes, you need a central place to organize and configure them and that’s what SolrCloud is very good at. This solution provides Fault Tolerance as well as High Availability. I’m not sure if SolrCloud could be used by Alfresco because sure SolrCloud also has Shards and its behaviour is pretty similar to a Standalone Solr but it’s not entirely working in the same way. Maybe it’s possible, however I have never seen it so far. Might be the subject of some testing later… In any cases, using a SolrCloud for Alfresco might not be that useful because it’s really easier to setup a Master-Master Solr mixed with Solr Sharding for pretty much the same benefits. So, I won’t talk about SolrCloud here either.

You guessed it, in this blog, I will only talk about Standalone Solr nodes and only using Shards. Alfresco supports Solr Shards only since the version 5.1. Before that, it wasn’t possible to use this feature, even if Solr4 provided it already. When using the two default cores (the famous “alfresco” & “archive” cores), with all Alfresco versions (all supporting Solr… So since Alfresco 4), it is possible to have a High Available Solr installation by setting up two Solr Standalone nodes and putting a Load Balancer in front of it but in this case, there is no communication between the Solr nodes so, it’s only a HA solution, nothing more.

 

In the architectures that I presented in the first blog of this series, if you remember the schema N°5 (you probably don’t but no worry, I didn’t either), I put a link between the two Solr nodes and I mentioned the following related to this architecture:
“N°5: […]. Between the two Solr nodes, I put a Clustering link, that’s in case you are using Solr Sharding. If you are using the default cores (alfresco and archive), then there is no communication between distinct Solr nodes. If you are using Solr Sharding and if you want a HA architecture, then you will have the same Shards on both Solr nodes and in this case, there will be communications between the Solr nodes, it’s not really a Clustering so to speak, that’s how Solr Sharding is working but I still used the same representation.”

 

II. Solr Shards creation

As mentioned earlier in this blog, there are real Cluster solutions with Solr but in the case of Alfresco, because of the features that Alfresco adds like the Shard Registration, there is no real need to set up complex things like that. Having just a simple Master-Master installation of Solr6 with Sharding is already a very good and strong solution to provide Fault Tolerance, High Availability, Automatic Failover, Performance improvements, aso… So how can that be setup?

First, you will need to install at least two Solr Standalone nodes. You can use exactly the same setup for all nodes and it’s also exactly the same setup to use the default cores or Solr Sharding so just do what you are always doing. For the Tracking, you will need to use the Load Balancer URL so it can target all Repository nodes, if there are several.

If you created the default cores, you can remove them easily:

[alfresco@solr_n1 ~]$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 150
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">524</int></lst>
</response>
* Connection #0 to host localhost left intact
[alfresco@solr_n1 ~]$
[alfresco@solr_n1 ~]$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 150
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">485</int></lst>
</response>
* Connection #0 to host localhost left intact
[alfresco@solr_n1 ~]$

 

A status of “0” means that it’s successful.

Once that’s done, you can then simply create the Shards. In this example, I will:

  • use the DB_ID_RANGE method
  • use two Solr nodes
  • for workspace://SpacesStore: create 2 Shards out of a maximum of 10 with a range of 20M on maximum 10 Solr Servers
  • for archive://SpacesStore: create 1 Shard out of a maximum of 4 with a range of 50M on maximum 10 Solr Servers

Since I will use only two Solr nodes and since I want a High Availability on each of the Shards, I will need to have them all on both nodes. With a simple loop, it’s pretty easy to create all the Shards:

[alfresco@solr_n1 ~]$ solr_host=localhost
[alfresco@solr_n1 ~]$ solr_node_id=1
[alfresco@solr_n1 ~]$ range=20000000
[alfresco@solr_n1 ~]$ total_shards=10
[alfresco@solr_n1 ~]$ total_nodes=10
[alfresco@solr_n1 ~]$ for shard_id in `seq 0 1`; do
>   begin_range=$((${shard_id} * ${range}))
>   end_range=$(((${shard_id} + 1) * ${range}))
>   curl -v "http://${solr_host}:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=${total_shards}&numNodes=${total_nodes}&nodeInstance=${solr_node_id}&template=rerank&coreName=alfresco&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
>   echo ""
>   echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
>   echo ""
>   sleep 2
> done

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=10&numNodes=10&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-20000000&property.shard.instance=0 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 182
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">254</int></lst><str name="core">alfresco-0</str>
</response>
* Connection #0 to host localhost left intact

  -->  Range N°0 created with: 0-20000000


*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=10&numNodes=10&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=20000000-40000000&property.shard.instance=1 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 182
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">228</int></lst><str name="core">alfresco-1</str>
</response>
* Connection #0 to host localhost left intact

  -->  Range N°1 created with: 20000000-40000000

[alfresco@solr_n1 ~]$
[alfresco@solr_n1 ~]$ range=50000000
[alfresco@solr_n1 ~]$ total_shards=4
[alfresco@solr_n1 ~]$ for shard_id in `seq 0 0`; do
>   begin_range=$((${shard_id} * ${range}))
>   end_range=$(((${shard_id} + 1) * ${range}))
>   curl -v "http://${solr_host}:8983/solr/admin/cores?action=newCore&storeRef=archive://SpacesStore&numShards=${total_shards}&numNodes=${total_nodes}&nodeInstance=${solr_node_id}&template=rerank&coreName=archive&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
>   echo ""
>   echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
>   echo ""
>   sleep 2
> done

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8983 (#0)
> GET /solr/admin/cores?action=newCore&storeRef=archive://SpacesStore&numShards=4&numNodes=10&nodeInstance=1&template=rerank&coreName=archive&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0 HTTP/1.1
> Host: localhost:8983
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Content-Length: 181
<
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">231</int></lst><str name="core">archive-0</str>
</response>
* Connection #0 to host localhost left intact

-->  Range N°0 created with: 0-50000000

[alfresco@solr_n1 ~]$

 

On the Solr node2, to create the same Shards (another Instance of each Shard) and therefore provide the expected setup, just re-execute the same commands but replacing solr_node_id=1 with solr_node_id=2. That’s all there is to do on Solr side, just creating the Shards is sufficient. On the Alfresco side, configure the Shards registration to use the Dynamic mode:

[alfresco@alf_n1 ~]$ cat $CATALINA_HOME/shared/classes/alfresco-global.properties
...
# Solr Sharding
solr.useDynamicShardRegistration=true
search.solrShardRegistry.purgeOnInit=true
search.solrShardRegistry.shardInstanceTimeoutInSeconds=60
search.solrShardRegistry.maxAllowedReplicaTxCountDifference=500
...
[alfresco@alf_n1 ~]$

 

After a quick restart, all the Shard’s Instances will register themselves to Alfresco and you should see that each Shard has its two Shard’s Instances. Thanks to the constant Tracking, Alfresco knows which Shard’s Instances are healthy (up-to-date) and which ones aren’t (either lagging behind or completely silent). When performing searches, Alfresco will make a request to any of the healthy Shard’s Instances. Solr will be aware of the healthy Shard’s Instances as well and it will start the distribution of the search request to all the Shards for the parallel query. This is the communication between the Solr nodes that I mentioned earlier: it’s not really Clustering but rather query distribution between all the healthy Shard’s Instances.

 

 

Other posts of this series on Alfresco HA/Clustering:

L’article Alfresco Clustering – Solr6 est apparu en premier sur dbi Blog.

Alfresco – Share Clustering fail with ‘Ignored XML validation warning’

$
0
0

In a recent project on Alfresco, I had to setup a Clustering environment. It all went smoothly but I did face one single issue with the setup of the Clustering on the Alfresco Share layer. That’s something I never faced before and you will understand why below.

Initially, to setup the Alfresco Share Clustering, I used the sample file packaged in the distribution zip (E.g.: alfresco-content-services-distribution-6.1.0.5.zip):

<?xml version='1.0' encoding='UTF-8'?>
<beans 
       xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns_hz="http://www.hazelcast.com/schema/spring"
       xsi_schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.hazelcast.com/schema/spring
                https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd">

   <!--
        Hazelcast distributed messaging configuration - Share web-tier cluster config
        - see http://www.hazelcast.com/docs.jsp
        - and specifically http://docs.hazelcast.org/docs/2.4/manual/html-single/#SpringIntegration
   -->
   <!-- Configure cluster to use either Multicast or direct TCP-IP messaging - multicast is default -->
   <!-- Optionally specify network interfaces - server machines likely to have more than one interface -->
   <!-- The messaging topic - the "name" is also used by the persister config below -->
   <!--
   <hz:topic id="topic" instance-ref="webframework.cluster.slingshot" name="slingshot-topic"/>
   <hz:hazelcast id="webframework.cluster.slingshot">
      <hz:config>
         <hz:group name="slingshot" password="alfresco"/>
         <hz:network port="5801" port-auto-increment="true">
            <hz:join>
               <hz:multicast enabled="true"
                     multicast-group="224.2.2.5"
                     multicast-port="54327"/>
               <hz:tcp-ip enabled="false">
                  <hz:members></hz:members>
               </hz:tcp-ip>
            </hz:join>
            <hz:interfaces enabled="false">
               <hz:interface>192.168.1.*</hz:interface>
            </hz:interfaces>
         </hz:network>
      </hz:config>
   </hz:hazelcast>

   <bean id="webframework.cluster.clusterservice" class="org.alfresco.web.site.ClusterTopicService" init-method="init">
      <property name="hazelcastInstance" ref="webframework.cluster.slingshot" />
      <property name="hazelcastTopicName"><value>slingshot-topic</value></property>
   </bean>
   -->

</beans>

 

I obviously uncommented the whole section and configured it properly for the Share Clustering. The above content is only the default/sample content, nothing more.

Once configured, I restarted Alfresco but it failed with the following messages:

24-Aug-2019 14:35:12.974 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
24-Aug-2019 14:35:12.974 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.34
24-Aug-2019 14:35:12.988 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying configuration descriptor [/opt/tomcat/conf/Catalina/localhost/share.xml]
Aug 24, 2019 2:35:15 PM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Aug 24, 2019 2:35:15 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Aug 24, 2019 2:35:15 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
2019-08-23 14:35:16,052  WARN  [factory.xml.XmlBeanDefinitionReader] [localhost-startStop-1] Ignored XML validation warning
 org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; schema_reference.4: Failed to read schema document 'https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.warning(ErrorHandlerWrapper.java:100)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:392)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4218)
  ... 69 more
Caused by: java.net.ConnectException: Connection refused (Connection refused)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
	... 89 more
...
2019-08-23 14:35:16,067  ERROR [web.context.ContextLoader] [localhost-startStop-1] Context initialization failed
 org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [surf-config.xml]
Offending resource: class path resource [web-application-config.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
  ... 33 more
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
	... 42 more
Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from file [/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:397)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303)
	... 44 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
	... 64 more
...
24-Aug-2019 14:35:16.196 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
24-Aug-2019 14:35:16.198 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal Context [/share] startup failed due to previous errors
Aug 24, 2019 2:35:16 PM org.apache.catalina.core.ApplicationContext log
...

 

As you can see above, the message is pretty clear: there is a problem within the file “/opt/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml” which is causing Share to fail to start properly. The first warning message points you directly to the issue: “Failed to read schema document ‘https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd’

After checking the content of the sample file and comparing it with a working one, I found out what was wrong. To solve this specific issue, you can simply replace “https://hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd” with “http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd“. Please note the two differences in the URL:

  • Switch from “https” to “http
  • Switch from “hazelcast.com” to “www.hazelcast.com

 

The issue was actually caused by the fact that this installation was completely offline, with no access to internet. Because of that, Spring wasn’t able to check for the XSD file to validate the definition in the context file. The solution is therefore to switch the URL to http with www.hazelcast.com so that the Spring internal resolution can understand and use the local file to do the validation and not look for it online.

As mentioned previously, I never faced this issue before for two main reasons:

  • I usually don’t use the sample files provided by Alfresco, I always prefer to build my own
  • I mainly install Alfresco on servers which have internet access (outgoing communications allowed)

 

Once the URL is corrected, Alfresco Share is able to start and the Clustering is configured properly:

24-Aug-2019 14:37:22.558 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
24-Aug-2019 14:37:22.558 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.34
24-Aug-2019 14:37:22.573 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying configuration descriptor [/opt/tomcat/conf/Catalina/localhost/share.xml]
Aug 24, 2019 2:37:24 PM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Aug 24, 2019 2:37:25 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Aug 24, 2019 2:37:25 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Resolving domain name 'share_n1.domain' to address(es): [10.10.10.10]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Resolving domain name 'share_n2.domain' to address(es): [127.0.0.1, 10.10.10.11]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Interfaces is disabled, trying to pick one address from TCP-IP config addresses: [share_n1.domain/10.10.10.10, share_n2.domain/10.10.10.11, share_n2.domain/127.0.0.1]
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Prefer IPv4 stack is true.
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.AddressPicker
INFO: Picked Address[share_n2.domain]:5801, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=5801], bind any local is true
Aug 24, 2019 2:37:28 PM com.hazelcast.system
INFO: [share_n2.domain]:5801 [slingshot] Hazelcast Community Edition 2.4 (20121017) starting at Address[share_n2.domain]:5801
Aug 24, 2019 2:37:28 PM com.hazelcast.system
INFO: [share_n2.domain]:5801 [slingshot] Copyright (C) 2008-2012 Hazelcast.com
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [share_n2.domain]:5801 [slingshot] Address[share_n2.domain]:5801 is STARTING
Aug 24, 2019 2:37:28 PM com.hazelcast.impl.TcpIpJoiner
INFO: [share_n2.domain]:5801 [slingshot] Connecting to possible member: Address[share_n1.domain]:5801
Aug 24, 2019 2:37:28 PM com.hazelcast.nio.ConnectionManager
INFO: [share_n2.domain]:5801 [slingshot] 54991 accepted socket connection from share_n1.domain/10.10.10.10:5801
Aug 24, 2019 2:37:29 PM com.hazelcast.impl.Node
INFO: [share_n2.domain]:5801 [slingshot] ** setting master address to Address[share_n1.domain]:5801
Aug 24, 2019 2:37:35 PM com.hazelcast.cluster.ClusterManager
INFO: [share_n2.domain]:5801 [slingshot]

Members [2] {
	Member [share_n1.domain]:5801
	Member [share_n2.domain]:5801 this
}

Aug 24, 2019 2:37:37 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [share_n2.domain]:5801 [slingshot] Address[share_n2.domain]:5801 is STARTED
2019-08-23 14:37:37,664  INFO  [web.site.ClusterTopicService] [localhost-startStop-1] Init complete for Hazelcast cluster - listening on topic: share_hz_test
...

 

L’article Alfresco – Share Clustering fail with ‘Ignored XML validation warning’ est apparu en premier sur dbi Blog.

Solr Sharding – Concepts & Methods

$
0
0

A few weeks ago, I published a series of blog on the Alfresco Clustering, including Solr Sharding. At that time, I planned to first explain what is really the Solr Sharding, what are the different concepts and methods around it. Unfortunately, I didn’t get the time to write this blog so I had to post the one related to Solr even before explaining the basics. Today, I’m here to rights my wrong! Obviously, this blog has a focus on Alfresco related Solr Sharding since that’s what I do.

I. Solr Sharding – Concepts

The Sharding in general is the partitioning of a set of data in a specific way. There are several possibilities to do that, depending on the technology you are working on. In the scope of Solr, the Sharding is therefore the split of the Solr index into several smaller indices. You might be interested in the Solr Sharding because it improves the following points:

  • Fault Tolerance: with a single index, if you lose it, then… you lost it. If the index is split into several indices, then even if you are losing one part, you will still have all others that will continue working
  • High Availability: it provides more granularity than the single index. You might want for example to have a few small indices without HA and then have some others with HA because you configured them to contain some really important nodes of your repository
  • Automatic Failover: Alfresco knows automatically (with Dynamic Registration) which Shards are up-to-date and which ones are lagging behind so it will choose automatically the best Shards to handle the search queries so that you get the best results possible. In combination with the Fault Tolerance above, this gives the best possible HA solution with the less possible resources
  • Performance improvements: better performance in indexing since you will have several Shards indexing the same repository so you can have less work done by each Shards for example (depends on Sharding Method). Better performance in searches since the search query will be processes by all Shards in parallel on smaller parts of the index instead of being one single query on the full index

Based on benchmarks, Alfresco considers that a Solr Shard can contain up to 50 to 80 000 000 nodes. This is obviously not a hard limit, you can have a single Shard with 200 000 000 nodes but it is more of a best practice if you want to keep a fast and reliable index. With older versions of Alfresco (before the version 5.1), you couldn’t create Shards because Alfresco didn’t support it. So, at that time, there were no other solutions than having a single big index.

There is one additional thing that must be understood here: the 50 000 000 nodes soft limit is 50M nodes in the index, not in the repository. Let’s assume that you are using a DB_ID_RANGE method (see below for the explanation) with an assumed split of 65% live nodes, 20% archived nodes, 15% others (not indexed: renditions, other stores, …). So, if we are talking about the “workspace://SpacesStore” nodes (live ones), then if we want to fill a Shard with 50M nodes, we will have to use a DB_ID_RANGE of 100*50M/65 = 77M. Basically, the Shard should be more or less “full” once there are 77M IDs in the Database. For the “archive://SpacesStore” nodes (archived ones), it would be 100*50M/20 = 250M.

Alright so what are the main concepts in the Solr Sharding? There are several terms that need to be understood:

  • Node: It’s a Solr Server (a Solr installed using the Alfresco Search Services). Below, I will use “Solr Server” instead because I already use “nodes” (lowercase) for the Alfresco Documents so using “Node” (uppercase) for the Solr Server, it might be a little bit confusing…
  • Cluster: It’s a set of Solr Servers all working together to index the same repository
  • Shard: A part of the index. In other words, it’s a representation (virtual concept) of the index composed of a certain set of nodes (Alfresco Documents)
  • Shard Instance: It’s one Instance of a specific Shard. A Shard is like a virtual concept while the Instance is the implementation of that virtual concept for that piece of the index. Several Shard Instances of the same Shard will therefore contain the same set of Alfresco nodes
  • Shard Group: It’s a collection of Shards (several indices) that forms a complete index. Shards are part of the same index (same Shard Group) if they:
    • Track the same store (E.g.: workspace://SpacesStore)
    • Use the same template (E.g.: rerank)
    • Have the same number of Shards max (“numShards“)
    • Use the same configuration (Sharding methods, Solr settings, …)

Shard is often (wrongly) used in place of Shard Instance which might lead to some confusion… When you are reading “Shard”, sometimes it means the Shard itself (the virtual concept), sometimes it’s all its Shard Instances. This is these concepts can look like:
Solr Sharding - Concepts

II. Solr Sharding – Methods

Alfresco supports several methods for the Solr Sharding and they all have different attributes and different ways of working:

  • MOD_ACL_ID (ACL v1): Alfresco nodes and ACLs are grouped by their ACL ID and stored together in the same Shard. Different ACL IDs will be assigned randomly to different Shards (depending on the number of Shards you defined). Each Alfresco node using a specific ACL ID will be stored in the Shard already containing this ACL ID. This simplifies the search requests from Solr since ACLs and nodes are together, so permission checking is simple. If you have a lot of documents using the same ACL, then the distribution will not be even between Shards. Parameters:
    • shard.method=MOD_ACL_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • ACL_ID (ACL v2): This is the same as the MOD_ACL_ID, the only difference is that it changes the method to assign to ACL to the Shards so it is more evenly distributed but if you still have a lot of documents using the same ACL then you still have the same issue. Parameters:
    • shard.method=ACL_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • DB_ID: This is the default Sharding Method in Solr 6 which will evenly distribute the nodes in the different Shards based on their DB ID (“alf_node.id“). The ACLs are replicated on each of the Shards so that Solr is able to perform the permission checking. If you have a lot of ACLs, then this will obviously make the Shards a little bit bigger, but this is usually insignificant. Parameters:
    • shard.method=DB_ID
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • DB_ID_RANGE: Pretty much the same thing as the DB_ID but instead of looking into each DB ID one by one, it will just dispatch the DB IDs from the same range into the same Shard. The ranges are predefined at the Shard Instance creation and you cannot change them later, but this is also the only Sharding Method that allows you to add new Shards dynamically (auto-scaling) without the need to perform a full reindex. You should only create the needed number of Shards (to avoid unnecessary DB requests) but always prepare to have more in the future. The lower value of the range is included and the upper value is excluded (for Math lovers: [begin-end[ ;)). Since DB IDs are incremental (increase over time), performing a search query with a date filter might end-up as simple as checking inside a single Shard. Parameters:
    • shard.method=DB_ID_RANGE
    • shard.range=<begin-end>
    • shard.instance=<shard.instance>
  • DATE: Months will be assigned to a specific Shard sequentially and then nodes are indexed into the Shard that was assigned the current month. Therefore, if you have 2 Shards, each one will contain 6 months (Shard 1 = Months 1,3,5,7,9,11 // Shard 2 = Months 2,4,6,8,10,12). It is possible to assign consecutive months to the same Shard using the “shard.date.grouping” parameter which defines how many months should be grouped together (a semester for example). If the date of the property chosen as “shard.key” is null, the fallback method is to use DB_ID instead. Parameters:
    • shard.method=DATE
    • shard.key=cm:modified
    • shard.date.grouping=<1-12>
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • PROPERTY: A property is specified as the base for the Shard assignment. The first time that a node is indexed with a new value for this property, the node will be assigned randomly to a Shard. Each node coming in with the same value for this property will be assigned to the same Shard. Valid properties are either d:text (single line text), d:date (date only) or d:datetime (date+time). It is possible to use only a part of the property’s value using “shard.regex” (To keep only the first 4 digits (d) of a date for example: shard.regex=^\d{4}). If this property doesn’t exist on a node or if the regex doesn’t match (if any is specified), the fallback method is to use DB_ID instead. Parameters:
    • shard.method=PROPERTY
    • shard.key=cm:creator
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>
  • EXPLICIT_ID: Pretty much similar to the PROPERTY but instead of using the value of a “random” property, this method requires a specific property (d:text) to define explicitly on which Shard the node should be indexed. Therefore, this will require an update of the Data Model to have one property dedicated to the assignment of a node to a Shard. In case you are using several types of documents, then you will potentially want to do that for all. If this property doesn’t exist on a node or if an invalid Shard number is given, the fallback method is to use DB_ID instead. Parameters:
    • shard.method=EXPLICIT_ID
    • shard.key=<property> (E.g.: cm:targetShardInstance)
    • shard.instance=<shard.instance>
    • shard.count=<shard.count>

As you can see above, each Sharding Method has its own set of properties. You can define these properties in:

  • The template’s solrcore.properties file in which case it will apply to all Shard Instance creations
    • E.g.: $SOLR_HOME/solrhome/templates/rerank/conf/solrcore.properties
  • The URL/Command used to create the Shard Instance in which case it will only apply to the current Shard Instance creation
    • E.g.: curl -v “http://host:port/solr/admin/cores?action=newCore&…&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0

Summary of the benefits of each method:
Solr Sharding - Benefits

First supported versions for the Solr Sharding in Alfresco:
Solr Sharding - Availability

Hopefully, this is a good first look into the Solr Sharding. In a future blog, I will talk about the creation process and show some example of what is possible. If you want to take a look at the Alfresco documentation (link might change in the future since the Alfresco Documentation site will be changed), it doesn’t always explain everything in details, but it is an excellent starting point with a LOT of information.

L’article Solr Sharding – Concepts & Methods est apparu en premier sur dbi Blog.

CMIS – What importance does it have in ECM World?

$
0
0

As you know, there is a lot of vendors for Enterprise Content Management systems (ECM) and they all have different interfaces. Content Management Interoperability Services (CMIS) is a standard for improving interoperability between Enterprise Content Management systems. The vendor-neutral OASIS Web services interface specification published two versions of CMIS v1.0 and v1.1, then the Technical Committee was closed on 09 May 2017 and is no longer active but the standard is still used by almost all CMS products.

What this means?
In fact, you can write applications targeting Alfresco, Documentum, SharePoint and other ECM systems using CMIS without writing one line of a vendor-specific code, so one source code to interoperate with them all… Compare it with JDBC to connect to any database that provides a JDBC driver 😉
This kind of standardization must survive and be constantly up to date, because it enable applications to target different ECM repositories uniformly with a common interface and I think that is really cool.

CMIS Basics

CMIS Repository

At the root of the CMIS model and services is a repository, which is an instance of the content management system and its store of metadata, content, and indexes.

The repository is the end point to which all requests are directed. In the RESTful model, it is the root path of the resources being addressed in CMIS, then it is capable of describing itself and its capabilities.

CMIS Query

A CMIS Query is based upon SQL-92. The query is read-only and presents no data manipulation capabilities!

The syntax consists of the following clauses:

  • SELECT with a target list.
  • FROM with the object types being queried.
  • JOIN to perform a join between object types.
  • WHERE with the predicate.
  • IN and ANY to query multi-value properties.
  • CONTAINS to specify a full-text qualification.
  • IN_FOLDER and IN_TREE to search within a folder hierarchy.
  • ORDERBY to sort the results.

The CMIS query maps the object type into a relational structure where object type approximates a table, the object approximates a row, and the property approximates a column that can be multi-valued.

CMIS Services

CMIS provides services that you can access using SOAP or AtomPub, and include the following:

  • Repository services let you discover available repositories, get the capabilities of these repositories, and provide basic Data Dictionary information of what types are available in the repository.
  • Navigation services let you navigate the repository by accessing the folder tree and traversing the folder/child hierarchy.
  • Object services provide the basics (Create, Read, Update, Delete) and Control services on any object, including document, folder, policy, and relationship objects. For document objects, this includes setting and getting of properties, policies, and content streams.
  • Object services retrieve objects by path or object ID. Applications may also discover what actions users are allowed to perform.
  • Multi-filing services let you establish the hierarchy by adding or removing an object to or from a folder.
  • Discovery services provide Query and Change services, and a means of paging the results of the query.
  • Change services let you discover what content has changed since the last time checked, as specified by a special token. You can use Change services for external search indexing and replication services.
  • Versioning services control concurrent operation of the Object services by providing Check In and Check Out services. Version services also provide version histories for objects that are versioned.
  • Relationship services let you create, manage, and access relationships or associations between objects as well as allow an application to traverse those associations.
  • Policy services apply policies on document objects. Policies are free-form objects and can be used by implementations for security, record, or control policies.
  • ACL services let you create, manage, and access Access Control Lists to control who can perform certain operations on an object.

CMIS Bindings

Web Services (SOAP)
This binding is based on the SOAP protocol All services and operations defined in the CMIS domain model specification are present in the Web Services binding. For example, in Alfresco you can get a summary of the CMIS services from the following URL:

http://<hostname>:<port>/alfresco/cmis

AtomPUB (REST)
This RESTful binding is based on the Atom Publishing Protocol. Clients communicate with the repository by requesting the service document, which is obtained through a well-known URI. For example, in Alfresco the service document is at:

http://<hostname>:<port>/alfresco/api/-default-/public/cmis/versions/1.1/atom

Personnaly, I used AtomPUB which works very well, and I think is being the most performant and the most popular. But if you’ve ever looked at the XML that comes back from a CMIS AtomPub call you know how verbose it can be!

CMIS v1.0 vs v1.1

CMIS 1.1 has some exciting new features comparing to v1.0. I will not list all v1.1 news, but you can find below the two important news (for me):

Browser Binding

The Browser Binding is based on JSON, so the payloads that go between client and server are smaller, making it the fastest of the three bindings.
The original purpose of the Browser Binding was to make it easy for those building “single page” web apps, but I think apps of all types will move to the Browser Binding because it is easier to work with.

Type Mutability

This allows CMIS developers to create and update the repository’s content model with code. Sometimes you will need content types to store objects with metadata specific to your solution.
Before CMIS 1.1, you have to ship repository-specific content models and configuration instructions with your app.
With CMIS 1.1, developers can simply write install and config logic as part of the solution that will interrogate the repository to determine if any changes need to be made to the content model to support the solution.

So, for the moment we have CMIS 1.0 and 1.1, which is cool but as you know things are moving fast and the CMIS need to follow… Do you think that we will see a CMIS 2.0 soon?

L’article CMIS – What importance does it have in ECM World? est apparu en premier sur dbi Blog.


Solr Sharding – Shard creation

$
0
0

I wrote this blog in conjunction with the one about the Solr Sharding – Concepts & Methods a year ago and it was 95% completed but then I had other stuff to do and just forgot I didn’t publish it. It might be a little bit late but well, better late than never… It will complete the overview I wanted to share around the Alfresco Clustering and in particular around the Solr Sharding. In this blog, I will talk about the creation of Shards. This includes the distribution of the different Instances, explaining the global parameters that can be used and showing some examples of what can be done with the concrete commands to achieve that.

I. Shard distribution

One of the strong points of using the Solr Sharding is that you can do pretty much what you want with the distribution of the Shards. It means that you can choose the best distribution of Shards based on your requirements, based on the resources available (Number of Solr Servers, RAM, I/O, …) and then Alfresco can just work with that seamlessly. Let’s consider some situations:

  • 1 Solr Server – 2 Shards – No HA (1 Shard Instance per Shard)
  • 2 Solr Server – 2 Shards – No HA (1 Shard Instance per Shard)
  • 2 Solr Server – 2 Shards – HA (2+ Shard Instances per Shard)
  • 6 Solr Server – 3 Shards – HA (2+ Shard Instances per Shard)

For the above examples, there are several possible representation of the Shards repartitions across the different Solr Servers. If we consider all Shards in the same way (same number of Shard Instance for each), then you can represent the above examples as follow:

Sharding distribution 1

If the Shard N°1 is the most important one and you want this one to be available on all Solr Servers with a maximum of 2 Shards per Solr Server, then this is another possible solution:

Sharding distribution 2

There are several ways to distribute the Shards and the good thing is that it is not really linked with the Sharding Method used. What I mean is that you can define the distribution that you want and it will be possible whatever the Sharding Method is. However, in some cases, the Method used might have an impact on whether or not the chosen distribution make sense. If I take the above example again where the Shard N°1 would be considered he most important one, then it means that you should know exactly what is inside this Shard N°1 but if DB_ID is used, then the content of this Shard will be random… Therefore, even if there is no hard link, some choice might not make a lot of sense if both aspects aren’t considered ;).

Alfresco (ACS only, not community) provides a graphical representation of the Solr Shards on the Alfresco Administration Console (https://alfresco-dns.domain/alfresco/s/enterprise/admin/admin-flocs). This is very useful to quickly see what is setup, how it is organized and what is the status of each and every Shards: whether they are up-to-date, lagging behind or not running at all. Here is an example of 1 Shard Group composed of 5 Shards with 2 Instances each:

Shard Groups

Shard Instances

In addition to that, I always find it very useful to look at the Solr reports (https://solr-dns.domain/solr/admin/cores?action=REPORT and https://solr-dns.domain/solr/admin/cores?action=SUMMARY) since it gives an overview of exactly how many acls and nodes are indexed. These are well known reports for Alfresco but in case you never saw these, I would advise you to take a look.

II. Shard creation parameters

As mentioned in the previous blog related to the Sharding Methods, when creating a Shard Instance, you will need to define some parameters. Here, I will only define them in the URL/Command because it is easier to have everything there. In addition to these parameters specific to each Method, there are some that are global. Before diving into the commands, let’s take a look at a few parameters and what they represent:

  • storeRef: Which Alfresco Store should this Shard index
  • numShards: Maximum number of different Shards that can be created
    • For DB_ID_RANGE, even if you need only 2 Shards at the moment, put more here (like 10/20) to be able to create new Shards in the future as the index grows. Once this limit is defined, you cannot exceed it so keep some margin
    • For all other Methods, set that to the number of Shards needed
  • numNodes: Maximum number of Solr Servers that can be used
    • For DB_ID_RANGE, even if you have only 2 Solr Servers at the moment, put more here (like 10/20) to be able to install new Solr Servers and create Shard Instances in the future. Once this limit is defined, you cannot exceed it so keep some margin
    • For all other Methods, even if you have only 2 Solr Servers at the moment, put more here (like 10/20). Maybe in the future you will want to have the same Shards (fix number) on more Solr Servers. Once this limit is defined, you cannot exceed it so keep some margin
  • nodeInstance: The “ID/Number” of the Solr Server on which the command is going to be executed, from 1 to numNodes, included
  • template: Which template should be used as base to create the new Core. The templates can be found under <SOLR_HOME>/solrhome/templates/
  • coreName: The base name of the Solr Core that this Shard should be part of. If you do not specify one, it will be generated from the Alfresco storeRef (E.g.: “workspace-SpacesStore”). Usual names can be “alfresco” or “archive” for example (Name of the default non-sharded cores)
  • shardIds: An ID that controls the generated Core Name, Base URL and Solr Data storage. This is to differentiate instances of Shards on a single Solr Server. You might think that this is the “ID/Number” of the Shard but not necessarily: with the DB_ID_RANGE for example, you can have the same shardIds used on two different Solr Servers for different Shards because the important thing is the range, it’s not the shardIds parameter in this case. So be careful here, this might be confusing. A best practice is however to have this shardIds set to the real “ID/Number” of the Shard so that it avoids confusion in all cases
  • replicationFactor: Technically speaking, the replication of a Shard Instance is another Shard Instance indexing the same set of nodes (so from the same Shard). You can normally mention the “replicationFactor” parameter in Solr but with the way it was implemented for Alfresco, you don’t need to care about that actually. You will see in the example below that to have several Shard Instances for the same Shard, you only need to execute the same commands on different servers
  • property.XXX: All the properties that can be set in the template’s solrcore.properties as well as the Sharding Method specific ones like:
    • property.data.dir.root: The place where the index will be put
    • property.shard.method: The Sharding Method to be used to create this Shard Instance
    • property.shard.instance: This is supposed to be the real “ID/Number” of the Shard for which a Shard Instance should be created (from 0 to numShards-1)

In summary, with the above parameters:

  • The name of the Core will be: ${coreName}-${shardIds}
  • The Solr Data will be put under: ${data.dir.root}/${coreName}-${shardIds}
  • The Solr Home will be put under: ${solr.solr.home}/${template}–${coreName}–shards–${numShards}-x-${replicationFactor}–node–${nodeInstance}-of-${numNodes}/${coreName}-${shardIds}
  • The Base URL will be: ${solr.baseurl}/${coreName}-${shardIds}
  • The Shard that will be created (unless otherwise): ${property.shard.instance}

One final note about the parameters: you need to be extra careful with these. I will say it again but in case of DB_ID_RANGE for example, Solr will not care about the shardIds or the property.shard.instance, it will only care about what it needs to index and that is based on the range… If you are using the Dynamic Registration, Alfresco will (and this is where the confusion can start) show you (in the Admin Console > Search Services Sharding) wrong information because it will base itself on the “property.shard.instance” to know to which Shard this instance belongs to (or at least supposed to…). This is just a graphical representation of the Shard Instances (so normally no impact on searches) but still, if you want an efficient and correct graphical view, keep things consistent!

III. Examples

a. DB_ID_RANGE

I will use the “High Availability – 6 Solr Server – 3 Shards (2nd solution)” as working example to show which commands can be used to create these: 3 different Shards, 4 Shard Instances for each on the 6 Solr Servers. I will use the DB_ID_RANGE Method so it is easy to see the differences between each command and identify for which Shard an Instance will be created. I will use a range of 50 000 000, assume that we can go up to 20 Shards (so 1 000 000 000 at maximum) on up to 12 Solr Servers.

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1&property.shard.method=DB_ID_RANGE&property.shard.range=50000000-100000000&property.shard.instance=1
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0&property.shard.method=DB_ID_RANGE&property.shard.range=0-50000000&property.shard.instance=0
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=20&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=2&property.shard.method=DB_ID_RANGE&property.shard.range=100000000-150000000&property.shard.instance=2

b. DATE

In this section, I will use the same setup but with a DATE Sharding Method. I will keep the same details as well (3 Shards) and therefore, each Shard Instance will contain 4 of the 12 months. There are several ways to obtain this:

  • No grouping option (default 1): Shard N°1 will contain the months 1,4,7,10 // Shard N°2 will contain the months 2,5,8,11 // Shard N°3 will contain the months 3,6,9,12
  • Grouping of 2: Shard N°1 will contain the months 1,2,7,8 // Shard N°2 will contain the months 3,4,9,10 // Shard N°3 will contain the months 5,6,11,12
  • Grouping of 3: Shard N°1 will contain the months 1,2,3,10 // Shard N°2 will contain the months 4,5,6,11 // Shard N°3 will contain the months 7,8,9,12
  • Grouping of 4: Shard N°1 will contain the months 1,2,3,4 // Shard N°2 will contain the months 5,6,7,8 // Shard N°3 will contain the months 9,10,11,12

Here, I will be group the months by 4. Since this is not the DB_ID_RANGE Method, all the Shard Instances for a Solr Server can be created by single command. However, when doing so, you cannot specify the “property.shard.instance” because it would contain several values (0,1,2 for example) and it is as far as I know, not supported. Therefore, the Shards will be created based on the “shardIds” parameter which has no problem with comma separated list:

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=DATE&property.shard.key=cm:modified&property.shard.date.grouping=4&property.shard.count=3″

c. ACL_ID (ACL v2)

In this section, I will use the same setup but with an ACL_ID Sharding Method. I will keep the same details as well (3 Shards). Each of the three Shards will get assigned some of the ACLs of the Alfresco Repository and it will index all the Alfresco nodes that have these specific ACLs. Therefore, it will be a random assignment that might or might not be evenly distributed (the more ACLs you have, the more evenly it is supposed to be in theory):

  • For the Solr Server 1 – Shards 0 & 1:
    • curl -v “http://solr1:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=1&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 2 – Shards 1 & 2:
    • curl -v “http://solr2:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=2&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 3 – Shards 0 & 2:
    • curl -v “http://solr3:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=3&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 4 – Shards 0 & 1:
    • curl -v “http://solr4:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=4&template=rerank&coreName=alfresco&shardIds=0,1&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 5 – Shards 1 & 2:
    • curl -v “http://solr5:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=5&template=rerank&coreName=alfresco&shardIds=1,2&property.shard.method=ACL_ID&property.shard.count=3″
  • For the Solr Server 6 – Shards 0 & 2:
    • curl -v “http://solr6:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=3&numNodes=12&nodeInstance=6&template=rerank&coreName=alfresco&shardIds=0,2&property.shard.method=ACL_ID&property.shard.count=3″

IV. Conclusion & final remarks:

At first, it might be a little confusing to work with Solr Sharding because there are a lot of terms that might overlap each-other a little bit but once you get it, it is such a pleasure to so easily create this kind of indexing architecture. Some final remarks:

  • As mentioned previously, you can create all the Instances on a Solr Server using a single command, except if you are using the DB_ID_RANGE because that contains the one variable parameter that needs to change between two different Shards. If the Instances are part of the same Shard (with the same range), then you can create them all in a single command.
  • If you want to have different Shards on the same Solr Server, then you need to change “property.shard.instance” (because it is a different Shard) and “shardIds” (because the Core & Base URL needs to be unique per Solr Server). The Shard Instance will belong to the Shard specified in “property.shard.instance” by default. If not present, it will use “shardIds” (as always, unless there is a range specified for the DB_ID_RANGE Method because this takes precedence over anything else).
  • If you want to have several Instances of the same Shard on the same Solr Server, then you need to change “shardIds” and keep “property.shard.instance” the same. If you can avoid that, then you should, for simplicity and consistency, but if you have a requirement to have two Instances of the same Shard on the same Solr Server, it is still possible.

If you are interested in playing with the Solr Sharding but you don’t have an existing infrastructure in place, you might want to take a look at this GitHub project from Angel Borroy which should help you to go further. Have fun!

L’article Solr Sharding – Shard creation est apparu en premier sur dbi Blog.

Alfresco – ActiveMQ not starting, blocking Alfresco

$
0
0

As already mentioned in a previous blog, ActiveMQ has been used in the scope of Alfresco since quite some time. Initially, as an optional component but then, it became mandatory. Just like for the Database, if ActiveMQ isn’t installed or not reachable, Alfresco will never completely start. Of course, for the Database, you will see that quickly since there will be errors on the Alfresco startup logs but that’s not really the case for ActiveMQ because it is only a subsystem and Alfresco will just quietly wait for this “Messaging” subsystem to be available before continuing the startup process. In this blog, I will show a case I faced recently where ActiveMQ wouldn’t start for a non-obvious reason and therefore Alfresco was stuck in the startup process as well.

 

You can always try to disable the automatic startup of the “Messaging” subsystem (using “messaging.subsystem.autoStart=false“) and you might want to disable the Event one as well. However, it should only stop the automatic startup of the subsystem, that doesn’t mean that it won’t be started later, on-demand. Another alternative could be to use the in-memory broker queue (using something like “messaging.broker.url=vm://localhost?broker.persistent=false” and making sure you have the activemq broker jar loaded). These options are out of scope of this blog since I needed a real ActiveMQ installation, working.

 

So, in case the startup of Alfresco is blocked on the “Messaging” subsystem, the logs will contain something like:

alfresco@alf01:~$ cat /opt/tomcat/logs/catalina.out
...
2021-07-09 12:15:00,670  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Subscriptions' subsystem, ID: [Subscriptions, default]
2021-07-09 12:15:00,692  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Subscriptions' subsystem, ID: [Subscriptions, default] complete
2021-07-09 12:15:00,713  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Synchronization' subsystem, ID: [Synchronization, default]
2021-07-09 12:15:00,903  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Synchronization' subsystem, ID: [Synchronization, default] complete
2021-07-09 12:15:00,979  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco JVM - v11.0.10+9-Ubuntu-0ubuntu1.18.04; maximum heap size 4096.000MB
2021-07-09 12:15:01,019  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] ================================================================
2021-07-09 12:15:01,020  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco license: Mode ENTERPRISE, cluster:enabled granted to Trial User limited to 2 days expiring Sun Jul 11 00:00:00 CEST 2021 (2 days remaining).
2021-07-09 12:15:01,032  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Note: this is a limited trial of the Enterprise version of Alfresco Content Services that goes into read-only mode after 2 days. Request an extended 30-day trial at: https://www.alfresco.com/platform/content-services-ecm/trial/docker
2021-07-09 12:15:01,033  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] ================================================================
2021-07-09 12:15:01,034  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Server Mode :PRODUCTION
2021-07-09 12:15:01,035  INFO  [service.descriptor.DescriptorService] [localhost-startStop-1] Alfresco Content Services started (Enterprise). Current version: 6.1.1 (3 r1dba1394-b23) schema 12,005. Originally installed version: 6.1.1 (3 r1dba1394-b23) schema 12,005.
2021-07-09 12:15:01,102  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default]
2021-07-09 12:15:01,892  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'ActivitiesFeed' subsystem, ID: [ActivitiesFeed, default] complete
2021-07-09 12:15:02,612  INFO  [repo.authorization.AuthorizationService] [localhost-startStop-1] Preauthorized user: admin
2021-07-09 12:15:02,620  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Replication' subsystem, ID: [Replication, default]
2021-07-09 12:15:02,640  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Replication' subsystem, ID: [Replication, default] complete
2021-07-09 12:15:05,278  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Messaging' subsystem, ID: [Messaging, default]
2021-07-09 12:15:44,013  WARN  [repo.usage.RepoUsageMonitor] [DefaultScheduler_Worker-3] The Alfresco Content Services license will expire in 2 days.
09-Jul-2021 12:16:17.538 INFO [hz._hzInstance_1_slingshot.cached.thread-3] com.hazelcast.nio.SocketAcceptor.null [alf01.dbi-services.com]:5801 [slingshot] 5801 is accepting socket connection from /10.10.10.12:56601
09-Jul-2021 12:16:17.551 INFO [hz._hzInstance_1_slingshot.cached.thread-3] com.hazelcast.nio.ConnectionManager.null [alf01.dbi-services.com]:5801 [slingshot] 5801 accepted socket connection from /10.10.10.12:56601
09-Jul-2021 12:16:24.522 INFO [hz._hzInstance_1_slingshot.ServiceThread] com.hazelcast.cluster.ClusterManager.null [alf01.dbi-services.com]:5801 [slingshot]

Members [2] {
 Member [alf01.dbi-services.com]:5801 this
 Member [alf02.dbi-services.com]:5801
}

2021-07-09 12:17:29,624  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Member joined: 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
2021-07-09 12:17:29,629  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Current cluster members:
 10.10.10.11:5701 (hostname: alf01.dbi-services.com)
 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
alfresco@alf01:~$

 

As shown above, the last message during startup is “Starting ‘Messaging’ subsystem, ID: [Messaging, default]“. After that, nothing happens anymore (remaining messages are related to license status and cluster management). As mentioned previously, this is because ActiveMQ is either not running at all, currently starting or just unreachable. Looking at the ActiveMQ logs showed the below:

alfresco@alf01:~$ date
Fri Jul  9 12:18:01 CEST 2021
alfresco@alf01:~$
alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 12:14:33,968 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 12:14:33 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 12:14:35,745 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/data/activemq/kahadb] | org.apache.activemq.broker.BrokerService | main
alfresco@alf01:~$

 

ActiveMQ is apparently in the starting process but it is also stuck on the Persistence Adapter. Looking at the configuration and the current files present:

alfresco@alf01:~$ grep -A2 "<persistenceAdapter" /opt/activemq/conf/activemq.xml
        <persistenceAdapter>
            <kahaDB directory="/data/activemq/kahadb"/>
        </persistenceAdapter>
alfresco@alf01:~$
alfresco@alf01:~$ ll /data/activemq/kahadb/
total 180
drwxr-x--- 1 alfresco alfresco       52 Jul  9 12:14 ./
drwxr-x--- 1 alfresco alfresco       12 Jul  9 12:14 ../
-rw-r----- 1 alfresco alfresco        8 Jul  9 12:14 lock
alfresco@alf01:~$

 

So, the lock file seems present but there is no DB yet. This usually happens when the lock wasn’t set yet. This environment is an Alfresco Cluster, with therefore multiple nodes and multiple ActiveMQ as well. The simplest setup in this case is to use a shared storage for the kahaDB (using NAS in this case). To debug the issue, I tried to start the ActiveMQ but with a local path, which isn’t on a NAS. It started properly:

alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 12:22:11,112 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 12:22:11 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 12:22:14,604 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/opt/activemq/data/kahadb] | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:14,839 | INFO  | PListStore:[/opt/activemq/data/alfdms.b1/tmp_storage] started | org.apache.activemq.store.kahadb.plist.PListStoreImpl | main
2021-07-09 12:22:15,088 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-37899-1625826134875-0:1) is starting | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:15,176 | INFO  | Listening for connections at: tcp://alf01:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,181 | INFO  | Connector openwire started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,207 | INFO  | Listening for connections at: amqp://alf01:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,215 | INFO  | Connector amqp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,235 | INFO  | Listening for connections at: stomp://alf01:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,244 | INFO  | Connector stomp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,263 | INFO  | Listening for connections at: mqtt://alf01:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 12:22:15,268 | INFO  | Connector mqtt started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:15,855 | WARN  | ServletContext@o.e.j.s.ServletContextHandler@4f449e8f{/,null,STARTING} has uncovered http methods for path: / | org.eclipse.jetty.security.SecurityHandler | main
2021-07-09 12:22:16,039 | INFO  | Listening for connections at ws://alf01:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.ws.WSTransportServer | main
2021-07-09 12:22:16,041 | INFO  | Connector ws started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 12:22:16,043 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-37899-1625826134875-0:1) started | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:16,045 | INFO  | For help or more information please see: http://activemq.apache.org | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:16,052 | WARN  | Store limit is 10240 mb (current store usage is 0 mb). The data directory: /opt/activemq/data/kahadb only has 8960 mb of usable space. - resetting to maximum available disk space: 8960 mb | org.apache.activemq.broker.BrokerService | main
2021-07-09 12:22:17,585 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /admin | main
2021-07-09 12:22:18,425 | INFO  | ActiveMQ WebConsole available at http://0.0.0.0:8161/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 12:22:18,426 | INFO  | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 12:22:18,526 | INFO  | Initializing Spring FrameworkServlet 'dispatcher' | /admin | main
2021-07-09 12:22:18,802 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /api | main
2021-07-09 12:22:18,992 | INFO  | jolokia-agent: Using policy access restrictor classpath:/jolokia-access.xml | /api | main
alfresco@alf01:~$

 

As soon as ActiveMQ was running, Alfresco could continue the startup process as well:

2021-07-09 12:17:29,624  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Member joined: 10.10.10.12:5701 (hostname: alf02.dbi-services.com)
2021-07-09 12:17:29,629  INFO  [cluster.core.MembershipChangeLogger] [hz._hzInstance_1_MainRepository-e941bb53-3778-456a-b330-ecfb98f54c2a.event-5] Current cluster members:
 10.10.10.11:5701 (hostname: alf01.dbi-services.com)
 10.10.10.12:5701 (hostname: alf02.dbi-services.com)

2021-07-09 12:22:25,435  INFO  [management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Messaging' subsystem, ID: [Messaging, default] complete
2021-07-09 12:22:36,007  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 500 Web Scripts (+0 failed), 656 URLs
2021-07-09 12:22:36,020  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 1 Package Description Documents (+0 failed)
2021-07-09 12:22:36,021  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Schema Description Documents (+0 failed)
2021-07-09 12:22:36,106  INFO  [extensions.webscripts.DeclarativeRegistry] [asynchronouslyRefreshedCacheThreadPool1] Registered 0 Web Scripts (+0 failed), 0 URLs
...

 

So, this issue is linked to the NAS. Since I already faced this kind of issue in the past years, I tried looking at the ports used by the NAS for the nlockmgr (Lock Manager):

alfresco@alf01:~$ rpcinfo -p 10.10.1.101 | grep nlockmgr
    100021    1   udp  52352  nlockmgr
    100021    3   udp  52352  nlockmgr
    100021    4   udp  52352  nlockmgr
    100021    1   tcp  46364  nlockmgr
    100021    3   tcp  46364  nlockmgr
    100021    4   tcp  46364  nlockmgr
alfresco@alf01:~$

 

I asked a colleague to look at the traces on the network layer, to see if something was being blocked/dropped and he could confirm me that the issue was simply that the port tcp/46364 was closed on the FireWall between the Alfresco/ActiveMQ VM and the NAS. Opening the port allowed ActiveMQ to request a lock of the file and therefore to start properly while using the NAS (port opened ~6min after the startup):

alfresco@alf01:~$ cat /opt/activemq/logs/activemq.log
2021-07-09 13:51:07,231 | INFO  | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@130161f7: startup date [Fri Jul 09 13:51:07 CEST 2021]; root of context hierarchy | org.apache.activemq.xbean.XBeanBrokerFactory$1 | main
2021-07-09 13:51:10,349 | INFO  | Using Persistence Adapter: KahaDBPersistenceAdapter[/data/activemq/kahadb] | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:44,643 | INFO  | PListStore:[/opt/activemq/data/alfdms.b1/tmp_storage] started | org.apache.activemq.store.kahadb.plist.PListStoreImpl | main
2021-07-09 13:57:44,794 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-40847-1625831864661-0:1) is starting | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:44,819 | INFO  | Listening for connections at: tcp://alf01:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,821 | INFO  | Connector openwire started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,830 | INFO  | Listening for connections at: amqp://alf01:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,834 | INFO  | Connector amqp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,843 | INFO  | Listening for connections at: stomp://alf01:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,846 | INFO  | Connector stomp started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:44,857 | INFO  | Listening for connections at: mqtt://alf01:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.TransportServerThreadSupport | main
2021-07-09 13:57:44,859 | INFO  | Connector mqtt started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:45,171 | WARN  | ServletContext@o.e.j.s.ServletContextHandler@4f449e8f{/,null,STARTING} has uncovered http methods for path: / | org.eclipse.jetty.security.SecurityHandler | main
2021-07-09 13:57:45,273 | INFO  | Listening for connections at ws://alf01:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600 | org.apache.activemq.transport.ws.WSTransportServer | main
2021-07-09 13:57:45,274 | INFO  | Connector ws started | org.apache.activemq.broker.TransportConnector | main
2021-07-09 13:57:45,283 | INFO  | Apache ActiveMQ 5.15.6 (alfdms.b1, ID:alf01-40847-1625831864661-0:1) started | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:45,285 | INFO  | For help or more information please see: http://activemq.apache.org | org.apache.activemq.broker.BrokerService | main
2021-07-09 13:57:47,106 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /admin | main
2021-07-09 13:57:48,247 | INFO  | ActiveMQ WebConsole available at http://0.0.0.0:8161/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 13:57:48,247 | INFO  | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ | org.apache.activemq.web.WebConsoleStarter | main
2021-07-09 13:57:48,297 | INFO  | Initializing Spring FrameworkServlet 'dispatcher' | /admin | main
2021-07-09 13:57:48,484 | INFO  | No Spring WebApplicationInitializer types detected on classpath | /api | main
2021-07-09 13:57:48,640 | INFO  | jolokia-agent: Using policy access restrictor classpath:/jolokia-access.xml | /api | main
alfresco@alf01:~$
alfresco@alf01:~$ ll /data/activemq/kahadb/
total 180
drwxr-x--- 1 alfresco alfresco       52 Jul  9 13:57 ./
drwxr-x--- 1 alfresco alfresco       12 Jul  9 13:57 ../
-rw-r----- 1 alfresco alfresco  3554432 Jul  9 14:03 db-1.log
-rw-r----- 1 alfresco alfresco    53248 Jul  9 14:03 db.data
-rw-r----- 1 alfresco alfresco    53344 Jul  9 14:03 db.redo
-rw-r----- 1 alfresco alfresco        8 Jul  9 13:57 lock
alfresco@alf01:~$

 

There are other reasons why ActiveMQ might not start properly but usually, what’s happening will be written inside the logs. This one is one of the few cases I faced where it’s not that obvious…

 

L’article Alfresco – ActiveMQ not starting, blocking Alfresco est apparu en premier sur dbi Blog.

Alfresco – Custom Share action not working after disabling WebDAV servlet

$
0
0

On an Alfresco upgrade project I was working on recently, I faced an interesting issue where post upgrade, one of my custom Share action wasn’t working anymore. This action was used to create folder links for use on an external interface. When applied on a document, it would create a link to the parent folder for example and when applied on a folder, it would link to itself. Generated link could then be used from outside of Alfresco.

I created this custom action when I started working with Alfresco almost 10 years ago and I didn’t touch the source code since then, it always worked. Therefore, I was a little bit surprised when the action didn’t work anymore (the link would always redirect to the root of the Repository [/Company Home]) after the latest upgrade. The action is a simple JavaScript piece of code deployed as an AMP on the Share war file:

$ cat $ALF_HOME/tomcat/webapps/share/components/documentlibrary/folderlink.js
(function() {
  YAHOO.Bubbling.fire("registerAction", {
    actionName: "onActionFolderLink",
    fn: function dbiservices_onActionFolderLink(record) {
      var viewID = record.actionGroupId;
      var path = record.webdavUrl.replace('/webdav', '');
      ...

 

On this code, the “viewID” is used to know on which page and on which element is this action triggered. Possible values can be “folder-browse” (applied on a folder when you browse the repository), “document-browse” (applied on a document when you browse the repository) or “document-details” (applied on a document when viewing the details/preview of this document) for example. The second JavaScript variable “path” is supposed to be the path of the Alfresco Node. I used this “webdavUrl” when I created this method because I found that to be a simple way to retrieve the path, since you can use “record.displayName” to retrieve the name of the Node but you cannot use “record.displayPath” to retrieve its path (look at the end of this post for alternatives).

When trying to debug the issue, I used the JavaScript Console on the Share UI but my piece of code was working and giving me the correct outcome (using “document” instead of “record“). While looking further into the code, the issue was really that “record.webdavUrl” didn’t return anything when executed as part of the custom action while it was working properly on the JavaScript Console.

I couldn’t find anything on Alfresco side that would explain a different behavior between the two versions of Alfresco so I looked into the configuration instead (alfresco-global.properties) and saw that on the new server, the WebDAV was disabled. This was most probably done as part of a best practice, to disable whatever isn’t used. So, I tried to re-enable the WebDAV:

$ grep webdav $ALF_HOME/tomcat/shared/classes/alfresco-global.properties
webdav.enabled=true
system.webdav.servlet.enabled=true
system.webdav.activities.enabled=true
system.webdav.rootPath=${protocols.rootPath}

 

After a restart of Alfresco, the action suddenly worked without any problem. To do some more testing, I tried to enable only the “webdav.enabled=true” parameter but it stopped working again. So my next test was to enable only the servlet instead (“system.webdav.servlet.enabled=true“) and that was indeed sufficient.

Therefore, if you are using “webdavUrl” in any of your JavaScript code, make sure that you enable at least the servlet as follow:

$ grep webdav $ALF_HOME/tomcat/shared/classes/alfresco-global.properties
webdav.enabled=false
system.webdav.servlet.enabled=true
system.webdav.activities.enabled=false
system.webdav.rootPath=${protocols.rootPath}

 

There are other ways to retrieve the path of the working node on JavaScript inside a custom action so instead of enabling the WebDAV servlet, it is also possible (and probably better) to use another alternative. Here are the 4 different ways I know of, with an example value returned when executed on a Document:

  • record.webdavUrl -> ‘/webdav/dbi%20services/A%20Folder/My%20Document.docx’
  • record.location.path -> ‘/dbi services/A Folder’
  • record.location.repoPath -> ‘/dbi services/A Folder’
  • this.currentPath -> ‘/dbi services/A Folder’

 

As you can see, the values are rather similar, except for the node name (which can be retrieve with “record.displayName“) which is only present for the “webdavUrl” one. All the three other alternatives display the path up to the parent only. Therefore, if applied to a folder or document, you might also need the node name to be concatenated. In conclusion, if you do specifically need the “webdavUrl“, make sure that the “system.webdav.servlet.enabled” is set to true otherwise it won’t work.

 

L’article Alfresco – Custom Share action not working after disabling WebDAV servlet est apparu en premier sur dbi Blog.

Alfresco – Share Clustering fail with ‘Ignored XML validation warning’, again

$
0
0

In a previous blog, I mentioned an issue that I faced when upgrading an Alfresco Content Services 5.2 to 6.1 on a VM with no internet access. The solution was simply to change one of the schema “URL” so that it can fallback to local references, meaning that it will try to check and find the schema definition inside the jar files present in the classpath. When upgrading this exact same VM from 6.1 to 7.1, I had, again, the same error:

29-Nov-2021 08:19:07.891 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
29-Nov-2021 08:19:07.892 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.55]
29-Nov-2021 08:19:07.922 INFO [main] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying deployment descriptor [alfresco/alfresco-7.1.0.1/tomcat/conf/Catalina/localhost/share.xml]
2021-11-29 08:19:19,024  WARN  [factory.xml.XmlBeanDefinitionReader] [main] Ignored XML validation warning
 org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 92; schema_reference.4: Failed to read schema document 'http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
        at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
        at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.warning(ErrorHandlerWrapper.java:100)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:392)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
        at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4257)
        ...
Caused by: java.net.ConnectException: Connection refused (Connection refused)
...
2021-11-29 08:19:19,061  ERROR [web.context.ContextLoader] [main] Context initialization failed
 org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [surf-config.xml]
Offending resource: class path resource [web-application-config.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
Offending resource: class path resource [surf-config.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 19 in XML document from file [alfresco/alfresco-7.1.0.1/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 92; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'hz:topic'.
        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:104)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:266)
        ...
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:alfresco/web-extension/*-context.xml]
...
29-Nov-2021 08:19:19.074 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
29-Nov-2021 08:19:19.077 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal Context [/share] startup failed due to previous errors

 

The first thing I checked was obviously if there were any differences between the previous and the new versions of the custom-slingshot-application-context.xml files. There was none, so it is not exactly the same issue, but it has the same consequences:

alfresco@alfvm01:alfresco$ ll
total 16
drwxr-x---  4 alfresco alfresco 4096 Nov 26 09:15 ./
drwxr-xr-x 10 alfresco alfresco 4096 Nov 26 10:09 ../
drwxr-x---  8 alfresco alfresco 4096 Nov 29 08:11 alfresco-6.1.1.3/
drwxr-x---  8 alfresco alfresco 4096 Nov 29 14:44 alfresco-7.1.0.1/
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ diff alfresco-*/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
alfresco@alfvm01:alfresco$

 

Since the file should normally be fine and able to fetch classpath definitions, then the issue would most probably be that either there are no jar files present anymore or the specific version that Share is looking for (as written in the log file: hazelcast-spring-2.4.xsd) doesn’t exist/isn’t found. So that’s what I looked into then:

alfresco@alfvm01:alfresco$ find alfresco-*/tomcat/webapps/share/ -name "*hazelcast*jar*"
alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-2.4.jar
alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-2.4.jar
alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-3.12.6.jar
alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-3.12.6.jar
alfresco@alfvm01:alfresco$

 

As you can see, the version of Hazelcast has been upgraded from 2.4 to 3.12. So, it’s probably a version mismatch since the jar files are present properly. Therefore, looking for the 2.4 XSD definition file inside the jar file is the next step:

alfresco@alfvm01:alfresco$ jar -tvf alfresco-6.1.1.3/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-2.4.jar | grep 'hazelcast-spring.*xsd'
 44024 Wed Oct 17 17:51:56 CEST 2012 hazelcast-spring-2.4.xsd
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ jar -tvf alfresco-7.1.0.1/tomcat/webapps/share/WEB-INF/lib/hazelcast-spring-3.12.6.jar | grep 'hazelcast-spring.*xsd'
178900 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.8.xsd
106805 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.4.xsd
 56119 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.2.xsd
190415 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.9.xsd
 52802 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.1.xsd
294159 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.12.xsd
148564 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.6.xsd
 50037 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.0.xsd
262083 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.11.xsd
 62043 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.3.xsd
157063 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.7.xsd
129308 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.5.xsd
236019 Thu Jan 30 20:44:00 CET 2020 hazelcast-spring-3.10.xsd
alfresco@alfvm01:alfresco$

 

As seen, the 2.4 XSD definition isn’t available in the new jar file, which would therefore be the culprit. The solution should then be to use the correct XSD definition version (switch from 2.4 to 3.12) in the custom-slingshot-application-context.xml file:

alfresco@alfvm01:alfresco$ sed -i 's,2.4,3.12,' alfresco-7.1.0.1/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
alfresco@alfvm01:alfresco$
alfresco@alfvm01:alfresco$ diff alfresco-*/tomcat/shared/classes/alfresco/web-extension/custom-slingshot-application-context.xml
8c8
<                 http://www.hazelcast.com/schema/spring/hazelcast-spring-2.4.xsd">
---
>                 http://www.hazelcast.com/schema/spring/hazelcast-spring-3.12.xsd">
13c13
<         - and specifically http://docs.hazelcast.org/docs/2.4/manual/html-single/#SpringIntegration
---
>         - and specifically http://docs.hazelcast.org/docs/3.12/manual/html-single/#SpringIntegration
alfresco@alfvm01:alfresco$

 

After the update and a restart, the Share Clustering is able to start and it is working successfully:

29-Nov-2021 08:34:12.776 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
29-Nov-2021 08:34:12.777 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.55]
29-Nov-2021 08:34:12.796 INFO [main] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying deployment descriptor [alfresco/alfresco-7.1.0.1/tomcat/conf/Catalina/localhost/share.xml]
...
29-Nov-2021 08:34:26.437 INFO [main] com.hazelcast.system.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] Hazelcast 3.12.6 (20200130 - be02cc5) starting at [alfvm01.domain.com]:5801
29-Nov-2021 08:34:26.437 INFO [main] com.hazelcast.system.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved.
...
29-Nov-2021 08:34:27.729 INFO [main] com.hazelcast.core.LifecycleService.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] [alfvm01.domain.com]:5801 is STARTING
...
29-Nov-2021 08:34:28.790 INFO [main] com.hazelcast.core.LifecycleService.null [alfvm01.domain.com]:5801 [slingshot] [3.12.6] [alfvm01.domain.com]:5801 is STARTED

 

Currently, the Alfresco documentation contains the wrong references to the 2.4 version. I opened a PR to correct the documentation to use the 3.12 version instead (impacts all versions starting from ACS 7.0) so hopefully it should be updated soon. In the meantime, check that you are using the correct versions! In case your server does have internet access, then you will not have any issues but that means that Alfresco will always perform internet lookups to retrieve the 2.4 version of the XSD definition.

 

L’article Alfresco – Share Clustering fail with ‘Ignored XML validation warning’, again est apparu en premier sur dbi Blog.

Alfresco – Documents are searchable only after 3min

$
0
0

I had a case at a customer recently where newly uploaded documents into Alfresco would always be searchable but only after 2min45s to 3min. The environment in question is an Alfresco Content Services 7.1 with High Availability (Repository and Share Clustering, Solr Sharding on multi-nodes, …) used for QA/TEST. It’s an ongoing project to upgrade an Alfresco 6.1 to 7.1 and during the testing, the documents take time to be visible through searches, everything else works properly.

 

Since there are a few similar environments on these exact same versions and setup, I tried to replicate the issue on two others but without success. On other instances, documents are searchable properly within the next 15 to 20s more or less, which is then expected based on the Solr Tracker schedule. No specific configurations were put that are out of the ordinary, it’s a rather straight forward setup that matches the previous one.

 

Since it’s a new version (ACS 7.1 / ASS 2.0.2), I thought that maybe it could be linked to the Sharding methods or the number of Shards, even if it shouldn’t (except if there is a bug, of course). So, I did some tests to reduce the number of Shards, change the Sharding method as well as completely remove Sharding and going back to a standard Alfresco/Archive cores setup. Here is an example of the main steps that can be used to remove the current Shards and create a unique new one for live documents:

### Solr Node1 & Node2
## Remove Solr Shards
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-0"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-1"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=workspace://SpacesStore&coreName=alfresco-2"
$ curl -v "http://localhost:8983/solr/admin/cores?action=removeCore&storeRef=archive://SpacesStore&coreName=archive-0"
## Stop Solr
$ sudo systemctl stop solr.service
## Cleanup config
$ rm -rf $SOLR_HOME/solrhome/rerank--a*
## Cleanup indexes
$ ls $SOLR_DATA_HOME/
content  index  models
$ rm -rf $SOLR_DATA_HOME/*/*
## Start Solr
$ sudo systemctl start solr.service
## Create Solr Shard for alfresco-0
$ solr_node_id=1    # for Solr Node2: solr_node_id=2
$ range=25000000
$ total_shards=20
$ for shard_id in `seq 0 0`; do
  begin_range=$((${shard_id} * ${range}))
  end_range=$(((${shard_id} + 1) * ${range}))
  curl -v "http://localhost:8983/solr/admin/cores?action=newCore&storeRef=workspace://SpacesStore&numShards=${total_shards}&numNodes=${total_shards}&nodeInstance=${solr_node_id}&template=rerank&coreName=alfresco&shardIds=${shard_id}&property.shard.method=DB_ID_RANGE&property.shard.range=${begin_range}-${end_range}&property.shard.instance=${shard_id}"
  echo ""
  echo "  -->  Range N°${shard_id} created with: ${begin_range}-${end_range}"
  echo ""
  sleep 2
$ done

 

After a full reindex, the behavior was the same, as we could expect. My next test would have been to try to revert to the previous Alfresco Search Services version (ASS 1.4.3) that was used but while doing the testing and checking the SUMMARY and REPORT generated by Solr (E.g.: http://localhost:8983/solr/admin/cores?action=SUMMARY&core=alfresco-0), I found it strange that the value of “Date for last TX on server” and “Last Index TX Commit Date” didn’t match the time when I uploaded my latest document on Alfresco, it was delayed… I deleted and re-uploaded the document again and saw the same thing, the time didn’t match. This could only be because of Operating System time that doesn’t match between the Solr and Alfresco/DB servers.

 

What happened is that these servers do not have access to internet, and they weren’t set with an internal Time Server. The “systemd-timesyncd” service was enabled but it couldn’t synchronize the time because of that:

root@solr_node1:~$ timedatectl status
                      Local time: Mon 2021-12-13 12:35:34 UTC
                  Universal time: Mon 2021-12-13 12:35:34 UTC
                        RTC time: Mon 2021-12-13 12:38:05
                       Time zone: Etc/UTC (UTC, +0000)
       System clock synchronized: no
systemd-timesyncd.service active: yes
                 RTC in local TZ: no
root@solr_node1:~$
root@solr_node1:~$ timedatectl set-ntp off
root@solr_node1:~$ timedatectl set-ntp on
root@solr_node1:~$
root@solr_node1:~$ systemctl restart systemd-timesyncd.service
root@solr_node1:~$
root@solr_node1:~$ systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-12-13 12:38:55 UTC; 30s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 29451 (systemd-timesyn)
   Status: "Connecting to time server 91.189.94.4:123 (ntp.ubuntu.com)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─29451 /lib/systemd/systemd-timesyncd

Dec 13 12:38:55 solr_node1 systemd[1]: Starting Network Time Synchronization...
Dec 13 12:38:55 solr_node1 systemd[1]: Started Network Time Synchronization.
Dec 13 12:39:05 solr_node1 systemd-timesyncd[29451]: Timed out waiting for reply from 91.189.91.157:123 (ntp.ubuntu.com).
Dec 13 12:39:15 solr_node1 systemd-timesyncd[29451]: Timed out waiting for reply from 91.189.89.198:123 (ntp.ubuntu.com).
root@solr_node1:~$

 

As a quick workaround, the time was manually synchronized:

root@solr_node1:~$ date -s "13 Dec 2021 12:41:16Z"
Mon Dec 13 12:41:16 UTC 2021
root@solr_node1:~$

 

Right after, the issue was gone, documents were searchable around 20s after the upload to Alfresco. Obviously, the long-term solution is to setup correctly the Operating System with the customer’s correct Time Servers. If they are blocking internet, they must probably have their dedicated Time Servers. For information, this is how to configure custom Time Servers on Ubuntu 18.04:

root@solr_node1:~$ vi /etc/systemd/timesyncd.conf
root@solr_node1:~$
root@solr_node1:~$ grep -v '^#' /etc/systemd/timesyncd.conf
[Time]
NTP=ntp1.domain.com
FallbackNTP=ntp2.domain.com
root@solr_node1:~$
root@solr_node1:~$ systemctl restart systemd-timesyncd.service
root@solr_node1:~$
root@solr_node1:~$ systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-12-13 15:28:26 UTC; 15s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 29817 (systemd-timesyn)
   Status: "Synchronized to time server 10.10.10.10:123 (ntp1.domain.com)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─29817 /lib/systemd/systemd-timesyncd

Dec 13 15:28:25 solr_node1 systemd[1]: Starting Network Time Synchronization...
Dec 13 15:28:26 solr_node1 systemd[1]: Started Network Time Synchronization.
Dec 13 15:28:35 solr_node1 systemd-timesyncd[29817]: Synchronized to time server 10.10.10.10:123 (ntp1.domain.com).
root@solr_node1:~$
root@solr_node1:~$ timedatectl
                      Local time: Mon 2021-12-13 15:28:50 UTC
                  Universal time: Mon 2021-12-13 15:28:50 UTC
                        RTC time: Mon 2021-12-13 15:28:50
                       Time zone: Etc/UTC (UTC, +0000)
       System clock synchronized: yes
systemd-timesyncd.service active: yes
                 RTC in local TZ: no
root@solr_node1:~$

 

L’article Alfresco – Documents are searchable only after 3min est apparu en premier sur dbi Blog.

Viewing all 50 articles
Browse latest View live