Статьи

Серия кластеров Tomcat, часть 2: Балансировщик сродства к сеансу

Это вторая часть серии кластеров Tomcat . В первой части мы обсудили, как настроить простой балансировщик нагрузки. И мы увидели, как балансировщик нагрузки распределяет запросы к экземплярам tomcat в циклическом порядке. В этом посте мы поговорим о том, что является проблемой, которая возникает в простом балансировщике нагрузки, когда мы вводим сессии в нашем веб-приложении. И мы увидим, как решить эту проблему.

Как работает сессия в Servlet / Tomcat?

Прежде чем углубляться в проблему, давайте посмотрим на управление сессиями в Tomcat .

Если какая-либо из страниц / сервлетов создает сеанс, то Tomcat создает объект сеанса и присоединяет его к группе сеансов (структура, подобная HashMap), и этот сеанс можно идентифицировать с помощью идентификатора сеанса, который является просто случайным числом. генерируется с помощью любого из алгоритмов хеширования. Затем отвечает клиенту с полем заголовка cookie. Это поле заголовка cookie является парой ключ-значение. Таким образом, tomcat создает jsessioid, который является ключом, а случайный идентификатор сеанса является значением.

Когда ответ достигает клиента (веб-браузер), он обновляет значение cookie. Если он уже существует, он переопределяет значение cookie. С этого момента браузер отправляет cookie-файл, прикрепленный к запросу, на этот сервер.

HTTP — это протокол без сохранения состояния. Таким образом, сервер не может найти клиентский сеанс тривиально. Таким образом, сервер читает заголовок запроса и извлекает значение cookie и случайный идентификатор сессии. Затем выполняется поиск в группе сеансов, поддерживаемой Tomcat. Затем tomcat получает сессию этого конкретного клиента (веб-браузер).

Если значение cookie-файла клиента не совпадает в группе сеансов, Tomcat создает совершенно новый сеанс и отправляет новый cookie-файл в браузер. Затем браузер обновляет его.

Этот код index.jsp предназначен для развертывания всех экземпляров Tomcat .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.Date"%>
 
<%@page import="java.util.List"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
 
<font size="5" color="#0000FF">
        Instance 1
 
        </font>
 
        <hr>
 
        <font size="5" color="#CC0000">
 
        Session Id : <%=request.getSession().getId()%>
 
        Is it New Session : <%=request.getSession().isNew()%>
 
        Session Creation Date : <%=new Date(request.getSession().getCreationTime())%>
 
        Session Access Date : <%=new Date(request.getSession().getLastAccessedTime())%>
 
        </font>
        <b>Cart List </b>
 
        <hr>
 
        <ul>
        <%
 
                String bookName = request.getParameter("bookName");
                List<string> listOfBooks = (List<string>) request.getSession().getAttribute("Books");
 
                if (listOfBooks == null) {
                    listOfBooks = new ArrayList<string>();
                    request.getSession().setAttribute("Books", listOfBooks);
                }
                if (bookName != null) {
                    listOfBooks.add(bookName);
                    request.getSession().setAttribute("Books", listOfBooks);
                }
 
                for (String book : listOfBooks) {
                    out.println("<li>"+book + "</li>
");
                }
 
        %>
        </string></string></string></ul>
        <hr>
        <form action="index.jsp" method="post">
            Book Name <input type="text" name="bookName">
 
            <input type="submit" value="Add to Cart">
        </form>
        <hr>

В чем проблема в простом балансировщике нагрузки?
Если мы развернем веб-приложение, в котором оно использует сеанс, то на самом деле проблема возникает.

Я описываю с последовательностью

  1. Пользователь запрашивает одну веб-страницу, на этой веб-странице используются сеансы (например, корзина).
  2. Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. предположим, на этот раз его отправить на tomcat1.
  3. tomcat1 создайте сеанс и отправьте клиенту заголовок cookie.
  4. Балансировщик нагрузки просто действует как реле. его отправить обратно клиенту.
  5. в следующий раз пользователь снова запросит корзину на сервер. на этот раз пользователь также отправляет заголовок cookie
  6. Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить на tomcat2.
  7. Tomcat 2 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что этот сеанс доступен только в tomcat1. Итак, Tomcat 2 создает новый сеанс и отправляет новый файл cookie клиенту.
  8. Клиент получает ответ и обновляет cookie (его перезаписывают старый cookie).
  9. Клиент еще раз отправляет запрос на эту страницу и отправляет куки на сервер.
  10. Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить в Tomcat3.
  11. Tomcat 3 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что этот сеанс доступен только в tomcat2. Таким образом, tomcat3 создает новый сеанс и отправляет новый файл cookie клиенту.
  12. Клиент получает ответ и обновляет cookie. (Перезаписывает старый cookie).
  13. Клиент еще раз отправляет запрос на эту страницу и отправляет куки на сервер.
  14. Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить на tomcat1.
  15. Tomcat 1 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что идентификатор сеанса клиента обновляется tomcat 3 в последний раз. поэтому, хотя у tomcat 1 есть один объект сеанса, созданный этим клиентом. но идентификатор сеанса клиента неверен. Поэтому tomcat3 создает новый сеанс и отправляет новый файл cookie клиенту (для получения дополнительной информации смотрите видео ниже)
  16. Клиент получает ответ и обновляет куки.

Эта последовательность продолжается …

В результате на каждый запрос создается одна новая сессия. Вместо продолжения со старым.

Здесь основной причиной является балансировщик нагрузки . Если балансировщик нагрузки перенаправляет запрос правильно, то эта проблема устранена. Но как балансировщик нагрузки заранее знает об этом клиенте до его обработки конкретным экземпляром Tomcat.

HTTP — это протокол без сохранения состояния. Так что HTTP не помогает в этой ситуации. И другая информация — это cookie-файл jsessionid. Это хорошо, но это просто случайное значение. Поэтому мы не можем принять решение на основе этого случайного значения.

например:

Cookie: JSESSIONID = 40025608F7B50E42DFA2785329079227

Сходство сессий / Sticky Session

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

jvmRoute

Файл конфигурации Tomcat (server.xml) содержит тег <Engine>, для которого есть атрибут jvmRoute. Итак, отредактируйте файл конфигурации и обновите тег <Engine> следующим образом

1
<Engine name='Catalina' defaultHost='localhost“ jvmRoute=“tomcat1” >

здесь мы упоминаем jvmRoute = ‘tomcat1 ′

Здесь tomcat1 — рабочее имя этого экземпляра Tomcat. Проверьте файл worker.properties в последнем сообщении .

Добавьте эту строку ко всем файлам экземпляров Tomcat conf / server.xml и перезапустите экземпляры Tomcat.

Теперь все экземпляры Tomcat генерируют шаблон идентификатора сеанса, как этот

<Случайное значение, как и раньше>. <Значение jvmRoute>

например:

Cookie: JSESSIONID = 40025608F7B50E42DFA2785329079227.tomcat1

Здесь, в конце значения, мы можем увидеть, какой экземпляр Tomcat сгенерировал этот конкретный сеанс. Таким образом, балансировщик нагрузки может легко определить, куда нам нужно делегировать запрос. В данном случае это tomcat1.

Поэтому обновите все файлы экземпляров tomcat conf / server.xml, чтобы добавить свойство jvmRoute в соответствующие значения имени работника. и перезапустите экземпляры. Все проблемы устранены, и весь баланс нагрузки работает отлично даже в приложениях, основанных на сеансах. Но есть еще один недостаток

Допустим, что 5 пользователей получают доступ к сайту. Сходство сеанса настроено. Вот

Tomcat 1 обслуживает 2 пользователей,

Tomcat 2 обслуживает 2 пользователя,

Tomcat 2 обслуживает 1 пользователя, а затем внезапно происходит сбой одного из экземпляров. Тогда что случилось?

Предположим, что экземпляр 1 (tomcat1) завершился ошибкой, тогда эти 2 пользователя потеряли свой сеанс. Но их запросы перенаправляются в один из оставшихся экземпляров tomcat (tomcat2, tomcat3). Таким образом, они все еще имеют доступ к веб-странице. Но они потеряли предыдущие сессии. Это один из недостатков. Но по сравнению с последним балансировщиком нагрузки он работает и в веб-приложении на основе сеансов.

В следующем посте мы увидим, как настроить репликацию сеанса в балансировщике нагрузки.

видео

http://www.youtube.com/watch?feature=player_embedded&v=-9C2ZtdAAFY

Ссылка: Tomcat Clustering Series Часть 2: Балансировщик аффинной загрузки сеанса от нашего партнера JCG Рамы Кришнана в блоге