Foren

Problemas de rendimiento con el portlet Communities

thumbnail
Ignacio Roncero Bazarra, geändert vor 12 Jahren.

Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Buenos días Gente,

estoy atascado con un problema desde hace ya un tiempo y se me empiezan a agotar las pruebas a realizar.

El problema es el siguiente:

Tengo una instalación de Liferay 6.0.5 sobre tomcat (el bundle) en mi equipo (portatil i5 con 4GB de RAM) que junto con el Eclipse Helios, el Plugin para Liferay del eclipse y el sdk de Liferay (liferay-plugins-sdk-6.0.5) hacen mi entorno de desarrollo.

El desarrollo de portlet ha ido bien, pero necesitaba crear 13000 páginas dentro de una comunidad (Guest) con una serie de portlets cada una (un visor de contenido, mapa web y login en unas; y un portlet propio, mapa web y login en otras). La creación la hice por medio de un portlet propio utilizando la API.

Pues, después de crear dichas 13000 páginas, cuando accedo al panel de control o a la configuración de las paginas el liferay se queda congelado durante un tiempo determinado (unos minutos) y luego reacciona y termina de ejecutar la petición. Esto solo ocurre al acceder a cualquier elemento del panel de control o de configuración de paginas (también ocurre en la configuración de los portlet incluidos en la paginas) pero NO ocurre mientras navego entre las paginas, ni cuando hago uso de los portlets de la misma, ni de mi propio portlet.

He seguido dos lineas investigación para ver que ocurria:

1º Por un lado lo primero que hice fue depurar la petición para ver que portlet o función se congelaba y comprobar si era cuestión del número de paginas (elementos en la tabla layout, en la tabla assetentry o en la tabla portletprefences).
En este caso he detectado que la lentitud viene del método process de la clase PortletRequestProcessor.java, pero solo cuando procesa el portlet Communities. He buceado un poco más en el código, si lo quereis/necesitais solo decidmelo y os subo aquí la traza.

2º La segunda fue cambiar la configuración de arranque del servidor, cambiar de servidor, aumentar memoria RAM, actualizar a la versión 6.0.6.
  • En este caso he cambiado los parámetros de configuración de java:
    En el fichero setenv.sh y setenv.bat he cambiado la línea
    set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF8 -Djava.net.preferIPv4Stack=true -Duser.timezone=Europe/Madrid -Xmx1024m -XX:MaxPermSize=256m"

    por la siguiente linea
    set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF8 -Djava.net.preferIPv4Stack=true -Duser.timezone=Europe/Madrid -Xmx2048m -XX:MaxPermSize=1024m"

    No puedo (y no creo que deba) subir más el parámetro de xmx. No hay diferencias de tiempos.
  • He probado a descargarme de nuevo la versión 6.0.5 y configurarla con el portal-ext.properties y la carpeta data. Pero sigue igual.
  • He probado a subirlo a un servidor de CentOS 5.5 (una máquina virtual, VMWare, sobre un i7 con 16GB de memoria RAM DDR3) con distintas configuraciones de memoria RAM (256MB, 2GB, 4GB y 8Gemoticon y a partir de los 2GB los resultados son los mismos. Cierto es que en esta configuración el tiempo de respuesta del servidor de liferay pasa de varios minutos a tan solo 45 segundos. Pero sigue siendo excesivo.
  • He probado a actualizar la versión 6.0.5 a la 6.0.6 (con todas las configuraciones antes comentadas) y los resultados son los mismos.


Las conclusiones que he sacado son:
  • La memoria RAM, mientras tenga suficiente, no mejora el rendimiento, por lo que no debe ser ese el problema.
  • He aumentado todo lo que he podido la reserva de memoria de java (xmx y MaxPermSize) y no mejora, por lo que no parece un problema de falta de recursos.
  • A priori no he encontrado (mediante la traza) ningún bucle en el código que identifique el problema (a causa de la gran cantidad de páginas).
  • He visto en internet configuraciones de mayor tamaño (en lo referente a número de paginas) y según se indica Liferay soporta manera al cantidad de datos.


La verdad es que se me acaban las ideas. ¿Alguien podría darme una orientación de por donde seguir indagando? Si necesitáis alguna otra información os la facilito.

Un saludo.
jm martinezg, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 2 Beitrittsdatum: 12.01.12 Neueste Beiträge
Puede que sea al acceder a la BBDD de meteadatos, que alguna tabla no tenga un índice, y haga algún tipos de full scan.

Segun la BBDD, Oracle / mysql, puedes intentar monitorizar que consultas se están haciendo cuando se accede al panel.
thumbnail
Sergio Sánchez, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

Regular Member Beiträge: 143 Beitrittsdatum: 06.07.11 Neueste Beiträge
Hola Ignacio,
deberías monitorizar la máquina virtual Java para ver lo que pasa con la memoria. Utiliza una herramienta como jvisualvm con plugins como VisualGC para ver como evoluciona con el tiempo las diferentes generaciones en que está dividida la memoria.
Diría que el PermSize (generación permanente) que has definido para los 2GB de memoria total máxima es demasiado.
Al monitorizar verás lo que se llega a utilizar en ese área y sería muy extraño que llegara a consumir 1GB. Sabiendo que solo tienes un portlet propio, con 256 MB para esa generación debería ser suficiente. Con 2GB en total y 256 MB para la generación permanente debería mejorar tu rendimiento, pero lo mejor es que monitorices el uso de memoria de la máquina virtual y entenderás mejor lo que está pasando.

Coméntame que resultados obtienes y si te puedo ayudar más

Un saludo
thumbnail
Ignacio Roncero Bazarra, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Gracias por responder gente,

Jm_Martinezg:
¿A que te refieres con los metadatos? ¿A los datos de las tablas de la bbdd o a los datos que están en el directorio data en el servidor (sistema de ficheros)?

Para la bbdd utilizo un PortgreSQL 8.4. He revisado las tablas que tiene mayor volumen de datos y tienen sus indices (al menos los indices que se debería crear según el esquema de instalación de liferay). Lo que no se es si la bbdd por detrás tiene creada las btree para poder usarlo. ¿Sabéis de algún método para comprobar eso?

Por otro lado he monitorizado las conexiones (con el pgAdmin) en el momento que accedia a la sección de Administrar páginas y no veo nada raro. Por raro quiero decir ningún proceso (consulta) bloqueada fuera de lo normal (antes de hacer petición alguna había consultas bloqueadas, pero a las tablas pg_database_datname_index, pg_database, pg_lock, pg_class_oi_index, pg_class, etc. Entiendo que estos bloqueos son ajenos a Liferay y más concretamente al problema que nos ocupa).

Sergio:
Me he instalado el VisualVM 1.3.3 y he realizado un seguimiento de la memoria. Los resultados son los siguientes:

Imagen a tamaño real
Esta imagen corresponde al tomcat recien arrancado. En ella se puede apreciar el proceso de arranque del servidor, donde el Heap size no supera los 250MB y el Heap usado ronda los 125MB.

Cuando lanzo la petición de acceder a Administrar páginas, el resultado es el siguiente:

Imagen a tamaño real
Esta imagen corresponde al tomcat después de haber gestionado la petición de Administrar páginas. La petición se lanzó entre las 9:34 y el 9:36. A partir de lanzar la petición se puede ver como la memoria usada heap va aumentando y liberandose en forma de dientes. Es decir aumenta el uso de memoria hasta un punto y luego libera, pero en cada ciclo requiere más memoria hasta llegar el heap size, para luego aumentar dicho heap size y seguir con el preceso. Así hasta las 9:38 que termina la petición. Un dato a tomar en cuenta es que (como las pruebas la realizo con la pantalla del VisualVM y del navegador por delante) cuando libera esos 200MB (a las 9:38) y vuelve a aumentar el uso de memoria hasta los 225MB es cuando cambia la pantalla del navegador y comienza a procesar la información que le ha dado el servidor de liferay (es decir, comienza a renderizar la página de Administración de páginas).

La verdad es que ese uso de memoria no se como interpretarlo.

Un saludo.
jm martinezg, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 2 Beitrittsdatum: 12.01.12 Neueste Beiträge
Me refería a los datos de la las tablas de la BBDD. A priori, por lo que comentas de los índices, no parece que sea ese el problema.
thumbnail
Ignacio Roncero Bazarra, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Buenas a todos,

aún no lo he solución pero puede ser que haya encontrado el problema. Resulta que en el algoritmo que creaba las paginas había algún error (o algo fallo), porque además de crearme las 13000 paginas, en una de ellas ha creado unas 50 o 60 paginas anidadas una dentro de la otra. Me estoy dedicando a borrarlas (pero 1 a 1 es muy lento),

¿si borrase el padre de esas páginas se borrarían las hijas también? o se quedarían huerfanas e irrecuperables?

He borrado ya muchas de esas páginas y no se si será autosugestión, pero parece que va bastante más rápido.

Un saludo.
thumbnail
Ignacio Roncero Bazarra, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Bueno gente,

he eliminado estas páginas anidadas (al final si eliminas la raíz también eliminas los hijos, lo he revisado en las tablas de bbdd). Después de eliminarlo ha se ha reducido el tiempo a la mitad aproximadamente.

Es decir, ahora tarda de 15 a 20 segundos por petición (en el servidor CentOS, donde al principio tardaba unos 45 seg). Lo que ya no se si ese tiempo es lógico o no.

Un saludo.
thumbnail
Fernando Nubla Durango, geändert vor 12 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 22 Beitrittsdatum: 01.09.09 Neueste Beiträge
Ignacio Roncero Bazarra:
Bueno gente,

he eliminado estas páginas anidadas (al final si eliminas la raíz también eliminas los hijos, lo he revisado en las tablas de bbdd). Después de eliminarlo ha se ha reducido el tiempo a la mitad aproximadamente.

Es decir, ahora tarda de 15 a 20 segundos por petición (en el servidor CentOS, donde al principio tardaba unos 45 seg). Lo que ya no se si ese tiempo es lógico o no.

Un saludo.



Hola,

una idea que nosotros tuvimos que aplicar, fue aumentar la cache de páginas, la primera carga sera lenta pero después al estar los id de las páginas en cache las cargas son muy rápidas.
Esto lo puedes configurar en los ficheros (en caso de cluster serían los siguientes)
hibernate-clustered.xml
liferay-multi-vm-clustered.xml

y una prueba fácil y rápida seria aumentar la cache por defecto a 14000 ( así las 13000 páginas que tienes estarían cacheadas).
<defaultCache
maxElementsInMemory="14000"
eternal="false"
timeToIdleSeconds="600"
overflowToDisk="false"
>

Si te va bien, luego ya sería aumentar la caché específica de las paginas y no la default.

un saludo
thumbnail
Ignacio Roncero Bazarra, geändert vor 11 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Hola de nuevo gente,

Retomo el hilo ya que hemos vuelto a tener dificultades y esta vez si hemos dado con el problema.

El problema que nos ocupaba era la lentitud al responder a acciones como editar un contenido estático o acceder al panel de control una vez creamos una gran cantidad de páginas en la plataforma (unas 13.000 aprox). Esta lentitud se redujo considerablemente al pasar del entorno de desarrollo al de preproducción (en nuestras mismas oficinas) y y más tarde al pasarlo al entorno de producción en el cliente el tiempo se hizo razonable (unos segundos por petición) así que lo achacamos a las capacidades de las máquinas y lo dejamos para más adelante... Pues bien ese tiempo ha llegado.

Una vez que el cliente ha empezado a introducir datos en la plataforma esta se ha ido ralentizando (vuelvo a indicar que solamente en la edición de contenidos, y los accesos al panel de control, principalmente. Los portlets desarrollados por nosotros van como rayos emoticon) hasta superar el límite de tiempo de espera aceptado por los proxies que hay intermedios (en nuestro caso 20 segundos), por lo que las peticiones se cortaban en el proxy.

Por lo que comenzarón las pruebas (nuevamente):

La primera prueba fue ir a las oficinas del cliente y hacer una prueba insitu (directamente en la red local del servidor de producción). Comprobamos que las peticiones se realizaban correctamente, pero requerían de un tiempo de espera de entre 1 y 2 minutos (para un simple acceso a la edición de un contenido). También revisamos que no se estuviesen produciendo errores en el transcurso de ese tiempo (los logs estaban limpios). Una vez visto esto revisamos que no hubiesen interbloqueos en la base de datos (en nuestro caso usamos PostgreSQL en su versión 8.4). Nada. La CPU no estaba a tope (siempre por debajo del 20% aproximadamente) y la memoria no consumida no superaba los 500MB (le tenemos asignados 2GB en producción, 4GB en preproducción y 1GB en desarrollo, para hacer pruebas).

Así que tocaba volver al punto donde dejamos hace ya muchos meses este tema y ver si esta vez dabamos con la solución. El siguiente paso fue revisar si era un problema de memoria, para ello utilizamos (como nos aconsejaron en el presente post) el VirtualVm tanto en desarrollo como en preproducción. Lo que volvimos a ver era lo mismo que siempre: La memoria aumentando con un dibujo parecido a dientes de sierra mientras duraba la operación. Nos llamo la atención que mientras en el servidor de desarrollo, un i5 con 4GB de memoria RAM y una buena carga de trabajo (eclipse, liferay, thunderbird, etc), en cada petición se podían apreciar 5 o 6 dientes de sierra (es decir, 5 o 6 liberaciones de memoria) en el servidor de preproducción, i7 con 16GB de memoria RAM y con mucha menos carga (ya que para las pruebas parábamos todas las máquinas virtuales que podíamos), se apreciaban solo 2 dientes (es decir, 2 liberaciones de memoria) y se resolvía mucho mas rápido (de 4 a 5 minutos que tardaba en desarrollo pasaba a 20 - 30 segundos en preproducción).

Eso nos hizo pensar que era un problema de memoria. Volvimos a realizar una gran cantidad de pruebas, aumentando y disminuyendo la memoria de java y no había cambios de ningún tipo.

También probamos a utilizar los parámetros de rendimiento en el portal-ext.properties. Parámetros del tipo
com.liferay.portal.servlet.filters.layoutcache.LayoutCacheFilter=true
Por ejemplo. Nada, los resultados eran los mismos. También probamos a aumentar la cache del ehcache a 15.000, después a 20.000 y después a 30.000. Los resultados fueron los mismos.

Así que como ya no nos quedaban más opciones volvimos a bucear en el código fuente de Liferay a ver si esta vez dábamos con la clave. Las otras veces realizábamos la traza desde el principio y nos acabamos perdiendo en el código y no encontrábamos muy bien donde se quedaba pillado pensando. Esta vez hemos estudiado las actions de edición de contenidos (paquete journal) y los jsp de edición de contenido edit_article.jsp, etc y nos contramos con este código en el fichero edit_article_structure_extra.jspf:

<aui:select label="" name="linkToLayout" showemptyoption="<%= true %>">

				&lt;%
				LayoutLister layoutLister = new LayoutLister();

				LayoutView layoutView = layoutLister.getLayoutView(layout.getGroupId(), layout.isPrivateLayout(), "root", locale);

				List layoutList = layoutView.getList();

				for (int i = 0; i &lt; layoutList.size(); i++) {

					// id | parentId | ls | obj id | name | img | depth

					String layoutDesc = (String)layoutList.get(i);

					String[] nodeValues = StringUtil.split(layoutDesc, "|");

					long objId = GetterUtil.getLong(nodeValues[3]);
					String name = nodeValues[4];

					int depth2 = 0;

					if (i != 0) {
						depth2 = GetterUtil.getInteger(nodeValues[6]);
					}

					for (int j = 0; j &lt; depth2; j++) {
						name = "-&nbsp;" + name;
					}

					Layout linkableLayout = null;

					try {
						linkableLayout = LayoutLocalServiceUtil.getLayout(objId);
					}
					catch (Exception e) {
					}

					if (linkableLayout != null) {
				%&gt;

						<aui:option label="<%= name %>" value="<%= linkableLayout.getLayoutId() %>" />

				&lt;%
				}
					}
				%&gt;

			</aui:select>

En el presente código se puede apreciar como obtiene una lista de layouts (páginas) a partir de la página inicial ("root") y las parsea para añadirlas a un combo. Pues siguiendo la pista al método
LayoutView layoutView = layoutLister.getLayoutView(layout.getGroupId(), layout.isPrivateLayout(), "root", locale);

Vemos lo siguiente:

	public LayoutView getLayoutView(
			long groupId, boolean privateLayout, String rootNodeName,
			Locale locale)
		throws PortalException, SystemException {

		_groupId = groupId;
		_privateLayout = privateLayout;
		_locale = locale;
		_nodeId = 1;

		_list = new ArrayList<string>();

		_list.add(
			"1|0|0|" + LayoutConstants.DEFAULT_PLID + "|" + rootNodeName +
				"|0");

		_createList(LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, _nodeId, 0);

		return new LayoutView(_list, _depth);
	}
</string>



	private void _createList(
			long parentLayoutId, int parentId, int depth)
		throws PortalException, SystemException {

		List<layout> layouts = LayoutLocalServiceUtil.getLayouts(
			_groupId, _privateLayout, parentLayoutId);

		for (int i = 0; i &lt; layouts.size(); i++) {
			Layout layout = layouts.get(i);

			if (i == 0) {
				depth++;

				if (depth &gt; _depth) {
					_depth = depth;
				}
			}

			StringBundler sb = new StringBundler(13);

			sb.append(++_nodeId);
			sb.append("|");
			sb.append(parentId);
			sb.append("|");

			if ((i + 1) == layouts.size()) {
				sb.append("1");
			}
			else {
				sb.append("0");
			}

			sb.append("|");
			sb.append(layout.getPlid());
			sb.append("|");
			sb.append(layout.getName(_locale));
			sb.append("|");
			//sb.append("9");
			sb.append("11");
			sb.append("|");
			sb.append(depth);

			_list.add(sb.toString());

			_createList(layout.getLayoutId(), _nodeId, depth);
		}
	}
</layout>


Es decir: En el método getLayoutView se llama a un método recursivo que recorre el árbol de layouts desde la primera hasta la última. En nuestro caso que tenemos 13.000 páginas de la siguiente manera (mas o menos)

- root
       - bloque 1
                - subbloque 1
                          - apartado 1
                                   - subapartado 1
                                              - pagina 1
                                              - pagina 2
                                              - pagina 3
                                   + subapartado 2
                                   + subapartado ...
                                   + subapartado 6
                          + apartado 2
                          + apartado ...
                          + apartado 11
                + subbloque 2
                + subbloque ...
                + subbloque 6
       + bloque 2
       + bloque ...
       + bloque 10

Pues el método recursivo realiza una gran cantidad de interactuaciones. La cosa se pone un poco peor, ya que dentro del método recursivo, en la línea:
List<layout> layouts = LayoutLocalServiceUtil.getLayouts(_groupId, _privateLayout, parentLayoutId);</layout>


Se realiza una consulta a base de datos para obtener las página hijas del layout que se está tratando. Por lo tanto se realiza una llamada a base de datos por cada página de este árbol... 13000 consultas!!!!!

Esto explica, tanto la lentitud como el consumo de memoria. Pero hay todavía varias cosas que no entiendo.
1º Por qué al aumentar la memoria permitida de Java, en este método no se consume toda la memoria permitida (por ejemplo los 4GB aprox del servidor de preproducción) sino que cuando llega a un pequeño límite de 200MB o 400MB libera y vuelve a aumentar (y dicho límite aumenta con cada liberación).
2º Para qué sirve el combo de linkToLayout del jsp edit_article_structure_extra.jspf. Está dentro de un div que está oculto (display none) y hemos revisado el código para guardar o actualizar un contenido y no se usa dicha variable (ni linkToLayout, ni linkToLayoutId) para nada. Imaginamos que para algo se debe de usar (si no se habría añadido dicho código, está claro), pero para que?
3º Por qué para formar el árbol de layout se permite que se realice una consulta por cada hoja? Para este tipo de algoritmo se suele traer toda la información posible de base de datos y luego tratarla. O bien traerse una información parcial (y la total es demasiado grande) y tratar esa información parcial.
4º Hemos visto que hay una buena cantidad de casos de éxitos en Liferay con portales en gran envergadura. ¿No les pasa es ellos también lo mismo?
5º hemos revisado los fuentes de la versión 6.1 y estos algoritmos son iguales. ¿Nadie se ha encontrado antes con el problema?


Todas estas preguntas nos hacen dudar. Lo primero que vamos a hacer es eliminar el trozo de código del edit_article_structure_extra.jspf para ver como reacciona la aplicación (lo vamos a hacer con un hook, en principio). Y confirmamos que ese es el problema (al menos en la lentitud de la edición de contenidos) buscaremos una solución un poco más elegante.

Para el acceso al panel de control y al gestor de páginas imagino que también usará el método getLayoutView de la clase LayoutLister, por lo que veremos como modificar el algoritmo para que no realice esa cantidad de peticiones a la base de datos.

Mantendremos informados sobre los resultados.
thumbnail
Sergio Sánchez, geändert vor 11 Jahren.

RE: Problemas de rendimiento con el portlet Communities

Regular Member Beiträge: 143 Beitrittsdatum: 06.07.11 Neueste Beiträge
Gracias por tu detallado análisis Ignacio.
Para casos como estos, donde un método no ofrece un buen rendimiento, es más rápido hacer un profiling de la aplicación en lugar de ir depurando.

Lo analizaré y te comento.

Un saludo
thumbnail
Ignacio Roncero Bazarra, geändert vor 11 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Gracias por tu respuesta Sergio,

ayer confirmamos lo que aventuramos en el post. El código incluido en el jsp edit_article_structure_extra.jspf es el que ralentiza la edición de contenido. Nuestro siguiente paso es, por un lado, mejorar el rendimiento del método getLayoutView de la clase LayoutLister (siempre como hook emoticon ), y por el otro, seguir investigando para que sirve el código del jsp.

Pues no sabía que al análisis de rendimiento se le llamaba "profiling" jeje. Y ahora que lo he buscado estoy viendo que hay multitud de herramientas para realizar los análisis. Para la próxima vez probaremos alguna. Muchas gracias.

Un saludo.
thumbnail
Ignacio Roncero Bazarra, geändert vor 11 Jahren.

RE: Problemas de rendimiento con el portlet Communities

New Member Beiträge: 21 Beitrittsdatum: 14.12.10 Neueste Beiträge
Buenos días Gente,

Ya hemos "solucionado" el problema. Os cuento:

Desarrollamos un plugin ext con una modificación de la clase LayoutLister para que, como indicábamos arriba, no accediese una vez por cada layout a la base de datos. Para ello la clase nos quedó tal que así:

public class LayoutLister{
	public LayoutView getLayoutView(
			long groupId, boolean privateLayout, String rootNodeName,
			Locale locale)
		throws PortalException, SystemException {

		_groupId = groupId;
		_privateLayout = privateLayout;
		_locale = locale;
		_nodeId = 1;

		_listLayouts = new ArrayList<string>();
		_layoutsMap = new HashMap<long, list<layout>&gt;();
		_listLayouts.add(
			"1|0|0|" + LayoutConstants.DEFAULT_PLID + "|" + rootNodeName +
				"|0");
		try{
			_getAllLayout();
			_createMap();
			_createList();
		}catch(Exception e){
			System.out.println(e);
		}
		return new LayoutView(_listLayouts, _depth);
	}
	
	private void _getAllLayout()
		throws PortalException, SystemException {
		_layouts = LayoutLocalServiceUtil.getLayouts(
				_groupId, _privateLayout);
		
	}
	
	private void _createMap(){
		if(_layouts.size()&gt;1){
			for(int i = 0; i &lt; _layouts.size() -1 ; i++){
				boolean finded = false;
				Layout layout_i = _layouts.get(i);
				int j = i + 1;
				while(j &lt; (_layouts.size() -1) &amp;&amp; !finded){
					Layout layout_j = _layouts.get(j++);
					if(layout_i.getParentLayoutId() != layout_j.getParentLayoutId())
						finded = true;
				}
				if(!finded)
					j++;
				_layoutsMap.put(layout_i.getParentLayoutId(), _layouts.subList(i, j));
				i = j - 1;			
			}
		}else if(_listLayouts.size()==1)
			_layoutsMap.put(_layouts.get(0).getParentLayoutId(), _layouts);
	}
	
	private void _createList(){
		if(_layoutsMap.size()&gt;0){
			List<layout> layouts = _layoutsMap.get(LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
			_createListRecursive(layouts, _nodeId, 0);
		}
	}
	private void _createListRecursive(List<layout> layouts, int parentId, int depth){
		if(layouts != null &amp;&amp; layouts.size()&gt;0){
			for(int i = 0; i &lt; layouts.size(); i++){
				Layout layout = layouts.get(i);
				if( i == 0){
					depth++;
					if(depth &gt; _depth){
						_depth = depth;
					}
				}
				StringBundler sb = new StringBundler(13);
				sb.append(++_nodeId);
				sb.append("|");
				sb.append(parentId);
				sb.append("|");
				
				if((i + 1) == layouts.size()){
					sb.append("1");
				}else{
					sb.append("0");
				}
				sb.append("|");
				sb.append(layout.getPlid());
				sb.append("|");
				sb.append(layout.getName(_locale));
				sb.append("|");
				//sb.append("9");
				sb.append("11");
				sb.append("|");
				sb.append(depth);
	
				_listLayouts.add(sb.toString());
				if(_layoutsMap.containsKey(layout.getLayoutId()))
					_createListRecursive(_layoutsMap.get(layout.getLayoutId()), _nodeId, depth);
			}
		}
	}
	
	private long _groupId;
	private boolean _privateLayout;
	private Locale _locale;
	private int _nodeId;
	private List<string> _listLayouts;
	private int _depth;
	private List<layout> _layouts;
	private HashMap<long, list<layout>&gt; _layoutsMap;
}
</long,></layout></string></layout></layout></long,></string>


El rendimiento del método getLayoutView mejoró considerablemente, ya que solamente accedía a base de datos con la línea _layouts = LayoutLocalServiceUtil.getLayouts(_groupId, _privateLayout); y el código para generar la lista de páginas en el formato debido (_listLayouts) tiene un buen rendimiento (ya que es de orden lineal).

Pero nos encontramos con dos problemas:

  • el método LayoutLocalServiceUtil.getLayouts seguía tardando demasiado.
  • En el jsp edit_article_structure_extra.jspf se volvía a recorrer todos los layouts accediendo a base de datos por cada uno de ellos.


Por lo tanto no bastaba con modificar el código de la clase LayoutLister. Así que repasamos los pasos dados y volvimos a buscar información al respecto. Como lo que más sentido (viendo el código) tenia era el tema de la cache (con ehcache) y como las pruebas que hicimos la otra vez no nos dieron ningún resultado (de hecho no encontramos diferencia entre una configuración y otra) volvimos a buscar información sobre comprobar que la configuración de ehcache es correcta en tiempo de ejecución y encontramos los atributos de los beans que teníamos que observar. Con esto y probando distintas configuración vimos que la configuración en el portal-ext.properties que funcionaba era:

net.sf.ehcache.configurationResourceName=/myEhcache/liferay-single-vm.xml


y no:

ehcache.single.vm.config.location=/myEhcache/liferay-single-vm.xml


(al menos a nosotros)

Modificamos la configuración por defecto de 10.000 elementos como tenía a 200.000 elementos (durante 1200 segundos, que son 20 minutos). Y voilà la operación se redujo (sin modificar la clase LayoutLister) a varios segundos (unos 3 o 4 en el servidor de preproducción).

Hemos realizado pruebas con dicha configuración de ehcache y sin ella, monitorizando las consultas selects a la tabla layout de la base de datos. La conclusión ha sido:
  • Cuando aumentábamos la cache al acceder a la página principal realizaba de 5 a 6 consultas a la tabla layout y cuando accedíamos posteriormente a la edición de contenido de dicha página no realizaba más consultas a dicha tabla.
  • Cuando dejábamos la cache por defecto (10.000 elementos) una vez situados en la página principal, al acceder a la edición de contenido de dicha página se realizaban unas 22.000 consultas.

Por lo tanto la cache ahora si está funcionando correctamente.

Gracias por la ayuda prestada y espero que este post le sirva a alguien, pues nosotros ya hemos gastado suficientes recursos en un problema que teníamos debido a una mala configuración.

Un saludo.
thumbnail
Sergio Sánchez, geändert vor 11 Jahren.

RE: Problemas de rendimiento con el portlet Communities

Regular Member Beiträge: 143 Beitrittsdatum: 06.07.11 Neueste Beiträge
Hola Ignacio, leyendo tu último post, como bien dices, se trata de un problema provocado porque debido a la gran cantidad de páginas que tenéis, el dimensionamiento por defecto para la caché se muestra insuficiente. Una vez se ha aumentado el tamaño máximo de la caché, el tiempo de respuesta es adecuado porque no se vuelve a generar la gran cantidad de consultas que observabais antes.

La conclusión a la que llegasteis es correcta, pero el cambio en la configuración no es el más adecuado.

Os sugeriría la siguiente configuración (válida para vuestra versión):

1.- El cambio en la configuración de los espacios de caché de Liferay supone cambiar el fichero liferay-multi-vm.xml (o liferay-multi-vm-vlustered.xml). Este fichero lo podéis obtener desde el código fuente o desde el fichero portal-impl.jar
2.- Aumentar el tamaño máximo de objetos almacenados para las cachés que observéis que tienen muchas pérdidas. Estas estadísticas las podéis obtener a través de un cliente JMX, analizando la información de MBeans de net.sf.ehcache. Apuntad aquellas cachés que tengan una gran cantidad de inMemoryMisses.
3.- Modificar el tamaño de cachés en una modificación del fichero XML original y almacenarlo con otro nombre en WEB-INF/classes. Por ejemplo, podéis guardarlo de esta forma: WEB-INF/classes/cache-custom/liferay-multi-vm.xml
6.- Referenciar con la propiedad de portal-ext.properties, el nuevo fichero modificado en base a la ruta del cargador de clases, que sería:
ehcache.multi.vm.config.location=/cache-custom/liferay-multi-vm.xml.

Tenéis más información en: https://www.liferay.com/documentation/liferay-portal/6.0/administration/-/ai/distributed-cachi-4

Un saludo.