2011-08-25 13 views
11

Tengo un problema de rendimiento con mis solicitudes JSF/RichFaces/Facelets ajax y por lo que puedo decir es porque el árbol de componentes completo se está reconstruyendo en cada solicitud de AJAX. Esto está sucediendo incluso si uso ajaxSingle = true, ajuste secciones en a4j: región, declaro una sola sección para rerendering o ninguna en absoluto. Nuestra página es una página dinámica con muchos niveles anidados. La página puede contener alrededor de 800-900 campos (inputText, calendarios enriquecidos, selectOneMenus, etc.). El tiempo de carga inicial es un problema, pero entiendo ese problema, son muchos campos. Una vez que tengamos ese tiempo de construcción/renderización inicial, hemos diseñado todas las demás acciones para que sean ajax y solo reenviar lo que se necesita. A partir de los registros de depuración facelets veo mensajes como este en cualquier llamada ajax:Vista JSF obteniendo reconstrucción en cada solicitud de Ajax

2011-08-24 22:19:03,054 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took 
24445ms to build view: /oconsole/appfile.xhtml 
2011-08-24 22:19:09,377 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took 
6323ms to render view: /oconsole/appfile.xhtml 

No estoy seguro de si hay algo que estamos haciendo está causando la reconstrucción de todo el árbol de componentes o facelets es determinar esta necesidad requerida por alguna razón (caché obsoleto?). Aquí está nuestra pila: JBoss 5.1 JSF 1.2 RichFaces. 3.3.3.Final Facelets 1.1.15 Seam 2.1.2

que han intentado añadir algunos parámetros de contexto para ver si ayudarían, pero no hicieron nada: facelets.BUILD_BEFORE_RESTORE = false facelets.REFRESH_PERIOD = - 1 o 5 (como en 5 min)

¿Hay alguna forma de saber si nuestras vistas se almacenan en la memoria caché correctamente? No descuidamos un método de ahorro de estado, por lo que creo que está predeterminado en el lado del servidor. Todas nuestras solicitudes suceden dentro de las conversaciones de larga duración. No estaba seguro de si esto juega un papel, ya que pensé que las vistas se almacenan en caché en el nivel de la sesión. Cualquier ayuda será enormemente apreciada, gracias.

actualización después de más de depuración:

El AjaxViewHandler (que tiene una variable miembro de la FaceletsViewHandler) tiene developmentMode = true conjunto. No estoy seguro de si esto está causando facelets para no almacenar en caché las vistas por lo que los cambios se actualizarán durante los ciclos de desarrollo ...? Ha sido muy difícil encontrar información sobre el almacenamiento en caché de facelets/JSF y el comportamiento y control de eso. Además, cuando agrego config param:

<context-param> 
<param-name>facelets.DEVELOPMENT</param-name> 
<param-value>false</param-value> 
</context-param> 

Esto no tomó! En el depurador todavía veo verdadero conjunto. Como tenemos muchas subvistas, también probé com.sun.faces.numberOfLogicalViews y com.sun.faces.numberOfViewsInSession hasta 1000 desde 15 (valor predeterminado) y esto no tuvo ningún efecto.

También traté de cambiar al ahorro de estado del lado del cliente sin suerte. Quedando sin ideas .... espero que alguien pueda ayudar ....

Parece Seam 2.1 de auto-inicializa RichFaces y no estoy seguro de si eso tiene algo que ver con eso .....

+0

Sé que esta es una vieja pregunta ... pero con tantos campos, puede considerar hacer esto: http://industrieit.com/blog/2011/11/stateless-jsf-high-performance-zero-per -request-memory-overhead/ –

Respuesta

5

Al igual que con cualquier problema de rendimiento, un generador de perfiles ayudaría enormemente a localizar los cuellos de botella. (Sí, sabes que es la fase de restore_view, pero no en la fase de restore_view).

Dicho esto, la fase de restauración de la vista restaura la vista completa, no solo las partes que serán procesadas o renderizadas. Citando la RichFaces taglib documentation: proceso

: Id [ 's] (en formato de UIComponent.findComponent llamada()) de los componentes, procesado en las fases 2-5 en caso de AjaxRequest causadas por este componente.Puede ser Identificación única, lista separada por comas de los Id de, o la expresión EL con matriz o colección

RESTORE_VIEW es la fase 1. También:

reRender: Id [ 's] (en formato de escala UIComponent.findComponent()) de componentes, representados en el caso de AjaxRequest causada por este componente. Puede ser Identificación única, lista separada por comas de los Id de, o la expresión EL con matriz o colección

Por otra parte, no estoy seguro de que UIComponent.findComponent() se implementa mediante una estructura de datos más adecuado que un árbol de componentes. (Encontrar algo en el árbol de componentes se reduciría a la búsqueda lineal ...).

He observado efectos similares con JSF 2.0 (Mojarra). Mi conclusión fue que las vistas no deben contener más de un par de docenas de UIComponents, independientemente de si se representan. (Dicho de otro modo, AJAX no es adecuado para la navegación de la página.) Estamos indefensos para mantener las vistas pequeñas al incluir solo los componentes que están actualmente visibles en la vista, y cambiar de vista si deben aparecer muchos componentes nuevos. Es decir, en lugar de una vista con 10 pestañas con 30 componentes cada una, tendríamos 10 vistas, cada una con el contenido de una sola pestaña. Un inconveniente de este enfoque es que los componentes se eliminan cuando se cambian las pestañas, lo que hace que se pierda cualquier estado que no se tenga en los granos de respaldo.

No afirmo que esta sea una buena solución. Por desgracia, fue el mejor que encontré al analizar esto hace un par de semanas. Me encantaría que me mostraran uno mejor, también.

Editar Cuando digo restaurar, me refiero a ViewHandler.restoreView(), que llama tanto para una solicitud GET inicial y una devolución de datos. Es incorrecto decir que restoreView simplemente reutilizaría una vista existente como está. Por ejemplo, los JSF 2.0 mandatos de especificaciones en la sección 7.6.2.7:]

El método restoreView() deben cumplir las siguientes funciones:

Todas las implementaciones deben:

  • Si no viewId podrían ser identificados , return null.
  • llamar al método de la StateManager asociado restoreView(), pasando la instancia FacesContext para la solicitud actual y la viewId calculado, y volver la UIViewRoot vuelto, que puede ser null.

y en la sección 7.7.2:

implementaciones JSF soportar dos mecanismos primarios para el ahorro de estado, en función del valor del parámetro de inicialización javax.faces.STATE_SAVING_METHOD (véase la Sección 11.1. 3 "Configuración de la aplicación Parámetros"). Los valores posibles para este parámetro proporcionan una indicación general del enfoque que se utilizará, al tiempo que permite implementaciones de JSF para innovar en los detalles técnicos:

  • cliente - [...]
  • servidor: causa que el estado guardado se almacene en el servidor entre las solicitudes. Las implementaciones que deseen habilitar su estado guardado para conmutar por error a una instancia de contenedor diferente deben tener esto en cuenta cuando implementen su servidor estrategia de ahorro de estado lateral. La implementación predeterminada serializa la vista en los modos cliente y servidor. En el modo de servidor , esta vista serializada se almacena en la sesión y se envía una clave única para recuperar la vista al cliente . Al almacenar la vista serializada en la sesión, la conmutación por error puede realizarse utilizando los mecanismos habituales proporcionados por el contenedor .

Dicho de otra manera, el soporte AJAX añadió a JSF (tanto el añadido por RichFaces 3 a JSF 1.2, y el incorporado en JSF 2.0) tiene por objeto reducir el consumo de ancho de banda de red, no servidor de consumo de CPU lado.

+0

Meriton gracias por su aporte, pero estoy confundido. Se supone que todo el punto de Ajax es capaz de hacer una rerender parcial muy rápido, detrás de escena. Pensé que JSF/Facelets/Richfaces almacena/almacena en caché las vistas y reutilizará el árbol de componentes construido si puede. Cuando dice "restaurar" arriba, creo que debemos tener en claro la restauración desde el caché o la reconstrucción. Me preocupa principalmente que haya especificado a través de las etiquetas RichFaces toda la información que solo necesito que se actualice un subconjunto muy pequeño de la página en esta acción, ¿por qué crearía todo el árbol? –

+0

He ampliado mi respuesta para responder sus preguntas. – meriton

+0

Gracias de nuevo Meriton por su seguimiento. Parece que nuestra única opción es ajustar el rendimiento de nuestra lógica que crea estas vistas dinámicas y dividirlas por diseño. Esto es muy decepcionante desde una perspectiva de diseño de JSF/Facelets, ser tan ineficiente cuando no es necesario, no lo entiendo. –

1

Según mi análisis, el problema se debe a la implementación de facelets. Sobre la base de depurador de las siguientes líneas de FaceletViewHandler clase, provoca una reconstrucción del árbol en cada solicitud (incluso AJAX) (buildBeforeRestore es falso, por lo que se invoca buildView método):

 // build view - but not if we're in "buildBeforeRestore" 
     // land and we've already got a populated view. Note 
     // that this optimizations breaks if there's a "c:if" in 
     // the page that toggles as a result of request processing - 
     // should that be handled? Or 
     // is this optimization simply so minor that it should just 
     // be trimmed altogether? 
     if (!this.buildBeforeRestore 
       || viewToRender.getChildren().isEmpty()) { 
      this.buildView(context, viewToRender); 
     } 

Así que en mi mente para resolver el problema del árbol reconstruir en cada solicitud es profundizar en la implementación de facelets y realizar la reimplementación ... Preferiría reestructurar la vista y minimizar el número de componentes, por lo que el tiempo de compilación del árbol es bajo.

Cuestiones relacionadas