2016-03-10 3 views
2

Я хочу, чтобы HttpSessions Tomcat был на диске, чтобы его можно было использовать в масштабируемой облачной среде. Дело в том, что будет несколько узлов Tomcat (в облаке PaaS), а клиенты могут быть направлены на любой из них. Мы хотим сохранять и загружать сеансы из общего дискового блока.Tomcat - Как перенести сеанс непосредственно на диск с помощью PersistentManager + FileStore

я настроил PersistentManager таким образом:

context.xml

<Manager className="org.apache.catalina.session.PersistentManager"> 
    <Store className="org.apache.catalina.session.FileStore" directory="c:/somedir"/> 
</Manager> 

Проблема заключается в том, что сессии, по-видимому, никогда не выгружаются на диск.

Я изменил <Manager> конфигурации при добавлении maxIdleBackup:

<Manager className="org.apache.catalina.session.PersistentManager maxIdleBackup="1"> 

Таким образом, он занимает почти минуту, пока я не вижу сеанс сохраняется на диске. Как ни странно, документ утверждает, что он должен принять вокруг второй:

maxIdleBackup: Временной интервал (в секундах) с момента последнего доступа к сеанса, прежде чем он имеет право на время сохранялось на сессии магазина или -1, чтобы отключить эту функцию. По умолчанию эта функция отключена .

Другие конфигурации:

После documentation я установить свойство системы

org.apache.catalina.session.StandardSession.ACTIVITY_CHECK -> true 

Есть ли способ, чтобы немедленно промойте сессию на диск? Возможно ли, что любое изменение в сеансе также сохраняется сразу?

UPDATE:

Я пытался заставить пассивирование сессии и промывке на диск с maxIdleBackup="0" minIdleSwap="0" maxIdleSwap="1", но он по-прежнему занимает почти минуту.

+0

Существует большая разница между «никогда» и «почти минуту». Я бы предположил, что единица времени - это минуты, а не секунды. Но это действительно работает. Я использую эту технику для масштабирования, а не для многоадресной передачи, которая помещает каждую сессию в каждый Tomcat, что кажется полным безумием для меня, и я счастлив терпеть случайную потерю валюты. – EJP

ответ

0

я наконец-то удалось решить эту проблему:

  1. Я продлил org.apache.catalina.session.ManagerBase перекрывая каждый метод, который используется сеансов карты суперкласса, так что он напал на файл (или кэш) непосредственно.

Пример:

@Override 
public HashMap<String, String> getSession(String sessionId) { 
    Session s = getSessionFromStore(sessionId); 
    if (s == null) { 
     if (log.isInfoEnabled()) { 
      log.info("Session not found " + sessionId); 
     } 
     return null; 
    } 

    Enumeration<String> ee = s.getSession().getAttributeNames(); 
    if (ee == null || !ee.hasMoreElements()) { 
     return null; 
    } 

    HashMap<String, String> map = new HashMap<>(); 
    while (ee.hasMoreElements()) { 
     String attrName = ee.nextElement(); 
     map.put(attrName, getSessionAttribute(sessionId, attrName)); 
    } 

    return map; 

} 

ВАЖНО:

загружать и выгружать методы должны быть оставлены пустыми:

@Override 
    public void load() throws ClassNotFoundException, IOException { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void unload() throws IOException { 
     // TODO Auto-generated method stub 

    } 

Вы должны переопределить startInternal и stopInternal для предотвращения ошибок на стадиях жизненного цикла :

@Override 
protected synchronized void startInternal() throws LifecycleException { 

    super.startInternal(); 

    // Load unloaded sessions, if any 
    try { 
     load(); 
    } catch (Throwable t) { 
     ExceptionUtils.handleThrowable(t); 
     log.error(sm.getString("standardManager.managerLoad"), t); 
    } 

    setState(LifecycleState.STARTING); 
} 

@Override 
protected synchronized void stopInternal() throws LifecycleException { 

    if (log.isDebugEnabled()) { 
     log.debug("Stopping"); 
    } 

    setState(LifecycleState.STOPPING); 

    // Write out sessions 
    try { 
     unload(); 
    } catch (Throwable t) { 
     ExceptionUtils.handleThrowable(t); 
     log.error(sm.getString("standardManager.managerUnload"), t); 
    } 

    // Expire all active sessions 
    Session sessions[] = findSessions(); 
    for (int i = 0; i < sessions.length; i++) { 
     Session session = sessions[i]; 
     try { 
      if (session.isValid()) { 
       session.expire(); 
      } 
     } catch (Throwable t) { 
      ExceptionUtils.handleThrowable(t); 
     } finally { 
      // Measure against memory leaking if references to the session 
      // object are kept in a shared field somewhere 
      session.recycle(); 
     } 
    } 

    // Require a new random number generator if we are restarted 
    super.stopInternal(); 
} 
  1. Вышеприведенное позволяет всегда читать из файла (или кеша), но как насчет операций записи ?. Для этого я продлил org.apache.catalina.session.StandardSession, переопределяя public void setAttribute(String name, Object value, boolean notify) и public void removeAttribute(String name, boolean notify).

Пример:

@Override 
public void setAttribute(String name, Object value, boolean notify) { 
    super.setAttribute(name, value, notify); 
    ((DataGridManager)this.getManager()).getCacheManager().getCache("sessions").put(this.getIdInternal(), this); 
} 

@Override 
public void removeAttribute(String name, boolean notify) { 
    super.removeAttribute(name, notify); 
    ((DataGridManager)this.getManager()).getCacheManager().getCache("sessions").put(this.getIdInternal(), this); 
} 

ВАЖНО:

В нашем случае резервная копия реальной сессия закончилась тем, что кэш-память (не файл), и когда мы читаем расширенное заседание Tomcat от него (в нашем классе ManagerBase impl) мы должны были настроить его как бы уродливым способом, чтобы все работало:

private Session getSessionFromStore(String sessionId){ 
     DataGridSession s = (DataGridSession)cacheManager.getCache("sessions").get(sessionId); 
     if(s!=null){ 
      try { 
       Field notesField; 
       notesField = StandardSession.class.getDeclaredField("notes"); 
       notesField.setAccessible(true); 
       notesField.set(s, new HashMap<String, Object>()); 
       s.setManager(this); 
      } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { 
       throw new RuntimeException(e); 
      } 
     } 
     return s; 
    } 
1

Можно также использовать этот клапан, который является частью распределения Tomcat (по крайней мере, в версии 8):

<Valve className="org.apache.catalina.valves.PersistentValve"/> 

Этот узел должен быть вставлен перед <Manager className="org.apache.catalina.session.PersistentManager"> узла в файле context.xml.

Затем он будет использовать магазин, чтобы поддерживать сеанс в каждом HTTP-запросе. Обратите внимание, что в документации предполагается, что только один HTTP-запрос будет производиться одним и тем же клиентом одновременно.

Это позволит вам использовать не липкий балансировщик нагрузки перед серверами java ee.

1

Я наткнулся на это потому, что Tomcat принимает минуту до выключения, как только я добавил PersistentManager к конфигурации, но это относится к вашей проблеме тоже:

Причина, по которой он занимает минуту упорствовать с PersistentManager является потому что вы не скорректировали processExpiresFrequency. Этот параметр регулирует, как часто PersistentManager будет работать это фоновые процессы истечь сессии, сохраняются их и т.д. Значение по умолчанию равно 6. (См Документов http://tomcat.apache.org/tomcat-8.5-doc/config/manager.html#Standard_Implementation)

Per коды, это значение умножается на engine.backgroundProcessorDelay, которые вам установленный на ваш элемент <Engine>. Значение по умолчанию равно 10. Таким образом, 6 * 10 составляет 60 секунд. Если вы добавите processExpiresFrequency="1" на свой элемент <Manager>, вы увидите, что он будет выключен намного быстрее (10 секунд). Если это не достаточно быстро, вы можете отрегулировать backgroundProcessorDelay, чтобы быть ниже. Вы также хотите установить maxIdleBackup в 1. Вы не получите абсолютно немедленной настойчивости, но это очень быстро и не требует самоописанной «уродливой настройки» в принятом ответе.

(см комментарии о backgroundProcessorDelay по методу setMaxIdleBackup в http://svn.apache.org/repos/asf/tomcat/tc8.5.x/tags/TOMCAT_8_5_6/java/org/apache/catalina/session/PersistentManagerBase.java)

+0

Я ценю ваш вход, я попробую. – codependent