Это вторая часть серии кластеров 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 > |
В чем проблема в простом балансировщике нагрузки?
Если мы развернем веб-приложение, в котором оно использует сеанс, то на самом деле проблема возникает.
Я описываю с последовательностью
- Пользователь запрашивает одну веб-страницу, на этой веб-странице используются сеансы (например, корзина).
- Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. предположим, на этот раз его отправить на tomcat1.
- tomcat1 создайте сеанс и отправьте клиенту заголовок cookie.
- Балансировщик нагрузки просто действует как реле. его отправить обратно клиенту.
- в следующий раз пользователь снова запросит корзину на сервер. на этот раз пользователь также отправляет заголовок cookie
- Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить на tomcat2.
- Tomcat 2 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что этот сеанс доступен только в tomcat1. Итак, Tomcat 2 создает новый сеанс и отправляет новый файл cookie клиенту.
- Клиент получает ответ и обновляет cookie (его перезаписывают старый cookie).
- Клиент еще раз отправляет запрос на эту страницу и отправляет куки на сервер.
- Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить в Tomcat3.
- Tomcat 3 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что этот сеанс доступен только в tomcat2. Таким образом, tomcat3 создает новый сеанс и отправляет новый файл cookie клиенту.
- Клиент получает ответ и обновляет cookie. (Перезаписывает старый cookie).
- Клиент еще раз отправляет запрос на эту страницу и отправляет куки на сервер.
- Балансировщик нагрузки перехватывает запрос и использует метод циклического перебора для его отправки одному из котов. на этот раз его отправить на tomcat1.
- Tomcat 1 получает запрос и извлекает идентификатор сеанса. и этот идентификатор сеанса не совпадает с их управляемым сеансом. потому что идентификатор сеанса клиента обновляется tomcat 3 в последний раз. поэтому, хотя у tomcat 1 есть один объект сеанса, созданный этим клиентом. но идентификатор сеанса клиента неверен. Поэтому tomcat3 создает новый сеанс и отправляет новый файл cookie клиенту (для получения дополнительной информации смотрите видео ниже)
- Клиент получает ответ и обновляет куки.
Эта последовательность продолжается …
В результате на каждый запрос создается одна новая сессия. Вместо продолжения со старым.
Здесь основной причиной является балансировщик нагрузки . Если балансировщик нагрузки перенаправляет запрос правильно, то эта проблема устранена. Но как балансировщик нагрузки заранее знает об этом клиенте до его обработки конкретным экземпляром 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 Рамы Кришнана в блоге