Fórumok

Message bus performances

Fabio De Pra, módosítva 9 év-val korábban

Message bus performances

New Member Bejegyzések: 24 Csatlakozás dátuma: 2013.11.04. Legújabb bejegyzések
Hi,
I'm having some performance troubles using Liferay's Synchronous Message Bus.

I'm using synchronous message bus in a jsp and I noticed that the response message cames after 10 seconds.
This slowdown is too much even if my laptop is not too fast.

Logging the request method and listener method the main slowdown is in the message receiving phase.

Any suggestion about improving the response time?
Thanks in advance.

Here is the code of methods and the log results:

Synchronous request
try {
            if (log.isTraceEnabled()) log.trace("products/util/systemsforselect start");
            String jsonResponse = (String) MessageBusUtil.sendSynchronousMessage("products/util/systemsforselect", message);
            if (log.isTraceEnabled()) log.trace("products/util/systemsforselect end");
            
           .....
            
        } catch (MessageBusException e) {
            log.error(e);
        }


Listener method that handle the request
private void handleSystemsForSelectRequest(Message message) {
        if (_log.isTraceEnabled()) _log.trace("ProductsUtilListener.handleSystemsForSelectRequest start");
        String localeString = message.getString("locale");
        
        JSONArray systemsJsonArray = JSONFactoryUtil.createJSONArray();
        
        if (localeString != null) {
            Locale locale = LocaleUtil.fromLanguageId(localeString);
        
            try {
                List<object[]> systemsData = ProductTreeLocalServiceUtil.findProductTreeLevelOne(locale, ProductsUtil.LEVEL_SYSTEMS_ID);
                
                if (systemsData != null &amp;&amp; systemsData.size() &gt; 0) {
                    if (_log.isTraceEnabled()) _log.trace("ProductsUtilListener.handleSystemsForSelectRequest for start");
                    for (Object[] rowData : systemsData) {
                        BigInteger treeLevelId = (BigInteger) rowData[0];
                        String name = (String) rowData[1];
                        String erpExternalId = "0";
                        try {
                            ProductTreeLevel productTreeLevel = ProductTreeLevelLocalServiceUtil.getProductTreeLevel(treeLevelId.longValue());
                            if (_log.isTraceEnabled()) _log.trace("ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load");
                            
                            if (productTreeLevel != null) {
                                erpExternalId = productTreeLevel.getErpExternalId();
                            }
                        } catch (PortalException e) {
                            // non gestito: viene sollevato se non viene trovato i livello
                        }
                        
                        // Costruzione oggetto JSON
                        JSONObject rowJson = JSONFactoryUtil.createJSONObject();
                        rowJson.put("treeLevelId", treeLevelId.longValue());
                        rowJson.put("name", name);
                        rowJson.put("erpExternalId", erpExternalId);
                        systemsJsonArray.put(rowJson);
                    }
                    if (_log.isTraceEnabled()) _log.trace("ProductsUtilListener.handleSystemsForSelectRequest for end");
                }
                
            } catch (SystemException e) {
                _log.error("handleSystemsForSelectRequest SystemException", e);
            }
            
            String responseString = systemsJsonArray.toString();
            Message responseMessage = MessageBusUtil.createResponseMessage(message);
            
            responseMessage.put("data", responseString);
            responseMessage.setPayload(responseString);

            MessageBusUtil.sendMessage(responseMessage.getDestinationName(), responseMessage);
        }
        
        if (_log.isTraceEnabled()) _log.trace("ProductsUtilListener.handleSystemsForSelectRequest end");
        
    }</object[]>


Log results show that the slowdown is between the exit of listener method and the message reception.

09:33:14,629 TRACE [http-bio-80-exec-43][AlgoritmaUtil:725] products/util/systemsforselect start
09:33:14,630 TRACE [http-bio-80-exec-43][ProductsUtilListener:42] ProductsUtilListener.receive message received
09:33:14,631 DEBUG [http-bio-80-exec-43][ProductsUtilListener:61] destinationName=products/util/systemsforselect
09:33:14,631 TRACE [http-bio-80-exec-43][ProductsUtilListener:91] ProductsUtilListener.handleSystemsForSelectRequest start
09:33:14,646 TRACE [http-bio-80-exec-43][ProductsUtilListener:103] ProductsUtilListener.handleSystemsForSelectRequest for start
09:33:14,657 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,660 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,662 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,663 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,665 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,667 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,671 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,673 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,675 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,676 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,678 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,680 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,682 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,684 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,686 TRACE [http-bio-80-exec-43][ProductsUtilListener:110] ProductsUtilListener.handleSystemsForSelectRequest productTreeLevel load
09:33:14,687 TRACE [http-bio-80-exec-43][ProductsUtilListener:126] ProductsUtilListener.handleSystemsForSelectRequest for end
09:33:14,687 TRACE [http-bio-80-exec-43][ProductsUtilListener:142] ProductsUtilListener.handleSystemsForSelectRequest end
09:33:24,689 TRACE [http-bio-80-exec-43][AlgoritmaUtil:727] products/util/systemsforselect end
thumbnail
David H Nebinger, módosítva 9 év-val korábban

RE: Message bus performances

Liferay Legend Bejegyzések: 14914 Csatlakozás dátuma: 2006.09.02. Legújabb bejegyzések
nested child queries never make sense.

I'd rework it so you get all data in a single call.

And it really makes no sense to be using the message bus anyway. Your code is in java, so clearly it's executed on the server (not sort of some ajax call). So you're adding in all of the overhead of json marshaling for absolutely no reason.
Fabio De Pra, módosítva 9 év-val korábban

RE: Message bus performances

New Member Bejegyzések: 24 Csatlakozás dátuma: 2013.11.04. Legújabb bejegyzések
Hi David,
I agree with you for child queries but in this case the number of row is low and the performances are acceptable.

I used message bus because I have to create a drow down list in a page with data handled in another portlet, withut copying the other portlet service jar and without query replication.

My question is why 10 secs for receiving the result in the caller?

09:33:14,687 TRACE [http-bio-80-exec-43][ProductsUtilListener:142] ProductsUtilListener.handleSystemsForSelectRequest end
09:33:24,689 TRACE [http-bio-80-exec-43][AlgoritmaUtil:727] products/util/systemsforselect end


I appreciate a suggestion for a diffrent approach.
In general, is synchronous message bus a good approach for sharing simple data between porlets?
thumbnail
Jack Bakker, módosítva 9 év-val korábban

RE: Message bus performances

Liferay Master Bejegyzések: 978 Csatlakozás dátuma: 2010.01.03. Legújabb bejegyzések
Fabio De Pra:

In general, is synchronous message bus a good approach for sharing simple data between porlets?


have you looked at IPC ?
thumbnail
David H Nebinger, módosítva 9 év-val korábban

RE: Message bus performances

Liferay Legend Bejegyzések: 14914 Csatlakozás dátuma: 2006.09.02. Legújabb bejegyzések
This makes no sense. You're not allowed to use the service jar, yet you are allowed to modify a message listener on the other side?

Why it takes 10 secs, I have no idea. I do believe that MB wasn't designed to work like this, it's really for a "send and forget" scenario (i.e. the MB is used to send an email, you send the email message and forget about it) because it does not behave like a regular messaging system. With the Message Bus, when you're in a cluster the messages are published via clusterlink to get them around to all nodes within the cluster. I think there may be issues with larger messages although I don't know for sure.

Whomever is giving you the "don't use the service jar" orders is just plain wrong. You don't sacrifice performance for the sake of not using a service jar. Maybe you don't want to expose the query logic; if that's the case, you just build a method into the XxxLocalServiceImpl to return the string.

Performance should be your primary concern, and therefore the service jar should be copied and used.
Enrico Borsoi, módosítva 9 év-val korábban

RE: Message bus performances

New Member Bejegyzések: 10 Csatlakozás dátuma: 2013.11.20. Legújabb bejegyzések
Hi,
I would like to say a word about this issue because I have a similar problem, that is: how can I share simple utility methods between different portlet?
From what you said here I understand I could do it by sharing the portlet jar, but this would imply to deploy and move the jar from one portlet to another everytime I do a modification on the portlet that contains the utility method.
Is this really the only way to solve this kind of problem?
thumbnail
David H Nebinger, módosítva 9 év-val korábban

RE: Message bus performances

Liferay Legend Bejegyzések: 14914 Csatlakozás dátuma: 2006.09.02. Legújabb bejegyzések
Enrico Borsoi:
Is this really the only way to solve this kind of problem?


No, there's lots of other options.

First, you could create a simple jar that contains your logic. Add the jar to an EXT plugin in the lib/portal directory and, when deployed, the jar file ends up in Liferay's ROOT/WEB-INF/lib directory. Plugins can then declare a dependency on it in liferay-plugin-package.properties. When hot deployed, Liferay will copy the jar to the deployed plugin for you. This option has an issue in that EXT plugins are hard to redeploy (think hard to update the jar) and impossible to undeploy.

Alternatively you could just put the jar into the global jar directory. This option has an issue in that you cannot overwrite the jar (think updating) while the app server is running, so you have to shut it down.

You could create an SB plugin and expose the API through a fake entity. The service jar can be included in dependent plugins WEB-INF/lib directory either directly or through some maven dependency magic. The service jar can be moved to the global jar directory, but this suffers from the same problem discussed above. This option has an issue in that Liferay tries to help manage versions of the service jar and service providing portlet scattered through the portal, so this can cause you to perform redeploys of otherwise unchanged plugins.
Enrico Borsoi, módosítva 9 év-val korábban

RE: Message bus performances

New Member Bejegyzések: 10 Csatlakozás dátuma: 2013.11.20. Legújabb bejegyzések
Ok thanks. I just thought there was a more straightforward way emoticon
thumbnail
David H Nebinger, módosítva 9 év-val korábban

RE: Message bus performances

Liferay Legend Bejegyzések: 14914 Csatlakozás dátuma: 2006.09.02. Legújabb bejegyzések
No straightforward way.

Best way is determined by requirements and environment. I don't think there's a perfect solution that fits all cases.

Me, I tend to prefer the SB approach because it really works well for many portal-based use cases. I also avoid the global lib like the plague because I don't want to force a server restart into my deployment process. But that doesn't mean it's the best solution and often times it may be better to go another way (i.e. 50 plugins all needing the SB service jar? well that's better then as global rather than 50 deployed copies).
Fabio De Pra, módosítva 8 év-val korábban

RE: Message bus performances

New Member Bejegyzések: 24 Csatlakozás dátuma: 2013.11.04. Legújabb bejegyzések
A simple workaround is set the timeout with a low value (ex 1) to avoid the default 5000ms timeout.

Looking to the source code of send method of SynchronousMessageListener class i found a wait(_timeout) but debugging seems that a notify is never called so the send wait until _timeout is reached.
public Object send() throws MessageBusException {
		String destinationName = _message.getDestinationName();
		String responseDestinationName = _message.getResponseDestinationName();

		_messageBus.registerMessageListener(responseDestinationName, this);

		try {
			synchronized (this) {
				_messageBus.sendMessage(destinationName, _message);

				wait(_timeout);

				if (_results == null) {
					throw new MessageBusException(
						"No reply received for message: " + _message);
				}
			}

			return _results;
		}
		catch (InterruptedException ie) {
			throw new MessageBusException(
				"Message sending interrupted for: " + _message, ie);
		}
		finally {
			_messageBus.unregisterMessageListener(
				responseDestinationName, this);

			EntityCacheUtil.clearLocalCache();
			FinderCacheUtil.clearLocalCache();
			ThreadLocalCacheManager.destroy();
		}
	}