1
2
3
4
5
6
7
8
9
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
|
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.fr.xsl"?>
<!-- English Revision: 1829613 -->
<!-- French translation : Lucien GENTIS -->
<!-- Reviewed by : Vincent Deffontaines -->
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<modulesynopsis metafile="mod_proxy_balancer.xml.meta">
<name>mod_proxy_balancer</name>
<description>Extension de <module>mod_proxy</module> pour le support de
la répartition de charge</description>
<status>Extension</status>
<sourcefile>mod_proxy_balancer.c</sourcefile>
<identifier>proxy_balancer_module</identifier>
<summary>
<p>Pour pouvoir fonctionner, ce module <em>requiert</em> le
chargement de <module>mod_proxy</module>, et il fournit le support de
la répartition de charge pour tous les protocoles supportés. Parmi ces
protocoles, les plus importants sont :</p>
<ul>
<li>HTTP, avec le module <module>mod_proxy_http</module></li>
<li>FTP, avec le module <module>mod_proxy_ftp</module></li>
<li>AJP13, avec le module <module>mod_proxy_ajp</module></li>
<li>WebSocket, avec le module <module>mod_proxy_wstunnel</module></li>
</ul>
<p>L'algorithme de planification de la répartition de charge n'est pas
fourni par ce module, mais par ceux-ci :</p>
<ul>
<li><module>mod_lbmethod_byrequests</module></li>
<li><module>mod_lbmethod_bytraffic</module></li>
<li><module>mod_lbmethod_bybusyness</module></li>
<li><module>mod_lbmethod_heartbeat</module></li>
</ul>
<p>Ainsi, pour mettre en oeuvre la répartition de charge,
<module>mod_proxy</module>, <module>mod_proxy_balancer</module> et
au moins un des modules fournissant l'algorithme de planification de
la répartition de charge doivent être chargés dans le serveur.</p>
<note type="warning"><title>Avertissement</title>
<p>N'activez pas la fonctionnalité de mandataire avant d'avoir <a
href="mod_proxy.html#access">sécurisé votre serveur</a>. Les
serveurs mandataires ouverts sont dangereux non seulement pour
votre réseau, mais aussi pour l'Internet au sens large.</p>
</note>
</summary>
<seealso><module>mod_proxy</module></seealso>
<seealso><directive module="mod_proxy">BalancerMember</directive></seealso>
<seealso><directive module="mod_proxy">BalancerGrowth</directive></seealso>
<seealso><directive module="mod_proxy">BalancerPersist</directive></seealso>
<seealso><directive module="mod_proxy">BalancerInherit</directive></seealso>
<section id="scheduler">
<title>L'algorithme de planification de la répartition de
charge</title>
<p>A l'heure actuelle, 4 algorithmes de planification de la répartition de
charge sont disponibles : ils se basent respectivement sur le comptage des
requêtes (<module>mod_lbmethod_byrequests</module>), la mesure de
l'intensité du trafic (<module>mod_lbmethod_bytraffic</module>), le comptage
des requêtes en attente (<module>mod_lbmethod_bybusyness</module>) et la
mesure de l'activité du serveur (<module>mod_lbmethod_heartbeat</module>).
Ils sont contrôlés par la valeur de <code>lbmethod</code> dans la définition
du répartiteur. Voir la directive <directive
module="mod_proxy">ProxyPass</directive> pour plus de détails, et en
particulier la configuration du répartiteur et de ses membres.</p>
</section>
<section id="stickyness">
<title>Répartition de charge avec abonnement utilisateur
(stickyness)</title>
<p>Le répartiteur supporte l'abonnement utilisateur. Lorsqu'une
requête est mandatée vers un serveur d'arrière-plan particulier,
toutes les requêtes suivantes du même utilisateur seront alors
mandatées vers le même serveur d'arrière-plan. De nombreux
répartiteurs de charge implémentent cette fonctionnalité via une
table qui associe les adresses IP des clients aux serveurs
d'arrière-plan. Cette approche est transparente aux clients et aux
serveurs d'arrière-plan, mais induit certains problèmes :
distribution de charge inégale si les clients se trouvent eux-mêmes
derrière un mandataire, erreurs d'abonnement lorsqu'un client
possède une adresse IP dynamique qui peut changer au cours d'une
session et perte d'abonnement en cas de dépassement de la table de
correspondances.</p>
<p>Le module <module>mod_proxy_balancer</module> implémente
l'abonnement selon deux alternatives : les cookies et le codage
d'URL. Le cookie peut être fourni par le serveur d'arrière-plan ou
par le serveur web Apache lui-même, alors que le codage d'URL est en
général effectué par le serveur d'arrière-plan.</p>
</section>
<section id="example">
<title>Exemples de configuration d'un répartiteur</title>
<p>Avant de nous plonger dans les détails techniques, voici un
exemple d'utilisation de <module>mod_proxy_balancer</module> mettant
en oeuvre la répartition de charge entre deux serveurs
d'arrière-plan :
</p>
<highlight language="config">
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80
BalancerMember http://192.168.1.51:80
</Proxy>
ProxyPass "/test" "balancer://mycluster"
ProxyPassReverse "/test" "balancer://mycluster"
</highlight>
<p>Voici un autre exemple de répartiteur de charge avec
abonnement utilisant <module>mod_headers</module>,
fonctionnant même si le serveur d'arrière-plan ne définit pas de
cookie de session approprié :
</p>
<highlight language="config">
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80 route=1
BalancerMember http://192.168.1.51:80 route=2
ProxySet stickysession=ROUTEID
</Proxy>
ProxyPass "/test" "balancer://mycluster"
ProxyPassReverse "/test" "balancer://mycluster"
</highlight>
</section>
<section id="environment">
<title>Variables d'environnement exportées</title>
<p>A l'heure actuelle, 6 variables d'environnement sont exportées :</p>
<dl>
<!-- ============= BALANCER_SESSION_STICKY =============== -->
<dt><var><a name="balancer_session_sticky" id="balancer_session_sticky">BALANCER_SESSION_STICKY</a></var></dt>
<dd>
<p>Cette variable se voir assignée la valeur de
<var>stickysession</var> pour la requête courante. Il s'agit du
nom du cookie ou du paramètre de requête utilisé pour les sessions
avec abonnement.</p>
</dd>
<!-- ============= BALANCER_SESSION_ROUTE ================ -->
<dt><var><a name="balancer_session_route" id="balancer_session_route">BALANCER_SESSION_ROUTE</a></var></dt>
<dd>
<p>Cette variable se voit assignée la <var>route</var> interprétée
pour la requête courante.</p>
</dd>
<!-- ============= BALANCER_NAME ========================= -->
<dt><var><a name="balancer_name" id="balancer_name">BALANCER_NAME</a></var></dt>
<dd>
<p>Cette variable se voit assigné le nom du répartiteur pour la
requête courante. Il s'agit d'une valeur du style
<code>balancer://foo</code>.</p>
</dd>
<!-- ============= BALANCER_WORKER_NAME ================== -->
<dt><var><a name="balancer_worker_name" id="balancer_worker_name">BALANCER_WORKER_NAME</a></var></dt>
<dd>
<p>Cette variable se voit assigné le nom du membre du groupe de
répartition de charge utilisé pour la requête courante. Il s'agit
d'une valeur du style <code>http://hostA:1234</code>.</p>
</dd>
<!-- ============= BALANCER_WORKER_ROUTE ================= -->
<dt><var><a name="balancer_worker_route" id="balancer_worker_route">BALANCER_WORKER_ROUTE</a></var></dt>
<dd>
<p>Cette variable se voit assignée la <var>route</var> du membre du
groupe de répartition de charge qui sera utilisé pour la requête
courante.</p>
</dd>
<!-- ============= BALANCER_ROUTE_CHANGED ================= -->
<dt><var><a name="balancer_route_changed" id="balancer_route_changed">BALANCER_ROUTE_CHANGED</a></var></dt>
<dd>
<p>Cette variable est définie à 1 si la route de la session ne
correspond pas à celle du membre du groupe de répartition de charge
(BALANCER_SESSION_ROUTE != BALANCER_WORKER_ROUTE), ou si la session
ne possède pas encore de route établie. Elle peut servir à
déterminer quand il est éventuellement nécessaire d'envoyer au
client une route mise à jour lorsque les sessions persistantes sont
utilisées.</p>
</dd>
</dl>
</section>
<section id="balancer_manager">
<title>Activation du support du gestionnaire de répartiteur</title>
<p>Cette fonctionnalité <em>nécessite</em> le chargement du module
<module>mod_status</module>. Le gestionnaire de répartiteur permet
la mise à jour dynamique des membres du groupe de répartition de
charge. Vous pouvez utiliser le gestionnaire de répartiteur pour
modifier le facteur de charge d'un membre particulier, ou passer ce
dernier en mode hors ligne.
</p>
<p>Ainsi, pour mettre en oeuvre la gestion du répartiteur de charge,
<module>mod_status</module> et <module>mod_proxy_balancer</module>
doivent être chargés dans le serveur.</p>
<p>Pour permettre la gestion du répartiteur de charge aux
navigateurs appartenant au domaine example.com, ajoutez ces lignes à
votre fichier de configuration <code>httpd.conf</code> :</p>
<highlight language="config">
<Location "/balancer-manager">
SetHandler balancer-manager
Require host example.com
</Location>
</highlight>
<p>Vous pourrez alors accéder au gestionnaire du répartiteur de
charge en utilisant un navigateur web pour afficher la page
<code>http://nom.de.votre.serveur/balancer-manager</code>. Notez que
pour pouvoir contrôler dynamiquement un membre de groupe de
répartition, ce dernier ne doit pas être défini au sein d'une
section <code><Location ...></code>.</p>
</section>
<section id="stickyness_implementation">
<title>Détails à propos de la répartition de charge par abonnement
(stickyness)</title>
<p>Si l'abonnement s'appuie sur un cookie, vous devez définir le nom
de ce cookie dont le contenu précise le serveur d'arrière-plan à
utiliser. Pour ce faire, on utilise l'attribut
<var>stickysession</var> avec la directive <directive
module="mod_proxy">ProxyPass</directive> ou <directive
module="mod_proxy">ProxySet</directive>. Le nom du cookie est
sensible à la casse. Le répartiteur extrait le contenu du cookie et
recherche un serveur membre dont la <var>route</var> correspond à
cette valeur. La route doit aussi être définie dans la directive <directive
module="mod_proxy">ProxyPass</directive> ou <directive
module="mod_proxy">ProxySet</directive>. Le cookie peut être défini
soit par le serveur d'arrière-plan, soit, comme indiqué dans l'<a
href="#example">exemple</a> ci-dessus par le serveur web Apache
lui-même.</p>
<p>Certains serveurs d'arrière-plan, tels qu'Apache Tomcat,
utilisent une forme sensiblement différente de cookie d'abonnement.
Tomcat ajoute le nom de l'instance Tomcat à la fin de son
identifiant de session, précédé par un point. Ainsi, si le serveur
web Apache trouve un point dans la valeur du cookie d'abonnement, il
n'utilisera que la partie située après ce point pour
rechercher sa route. Pour que Tomcat puisse connaître son nom
d'instance, vous devez définir l'attribut <code>jvmRoute</code> dans
son fichier de configuration <code>conf/server.xml</code> à la
valeur de la <var>route</var> du serveur qui se connecte au Tomcat
considéré. Le nom du cookie de session utilisé par Tomcat (et plus
généralement par les applications web Java à base de servlets) est
<code>JSESSIONID</code> (en majuscules), mais peut être modifié.</p>
<p>La seconde méthode pour implémenter l'abonnement est le codage
d'URL. Ici, le serveur web recherche un paramètre dans l'URL de la
requête. Le nom du paramètre est spécifié par l'attribut
<var>stickysession</var>. Pour trouver un serveur membre, on
recherche un serveur dont la <var>route</var> est égale à la valeur
du paramètre. Comme il n'est pas aisé d'extraire et de manipuler
tous les liens URL contenus dans les réponses, le travail consistant
à ajouter les paramètres à chaque lien est généralement effectué par
le serveur d'arrière-plan qui génère le contenu. Bien qu'il soit
possible dans certains cas d'effectuer ces ajouts au niveau du
serveur web via les modules <module>mod_substitute</module> ou
<module>mod_sed</module>, cette méthode peut dégrader les
performances.</p>
<p>Les standards Java implémentent le codage d'URL de manière
sensiblement différente. Ils ajoutent une information de chemin à
l'URL en utilisant un point-virgule (<code>;</code>) comme
séparateur, puis ajoutent enfin l'identifiant de session. Comme dans
le cas des cookies, Apache Tomcat peut insérer la valeur de
l'attribut <code>jvmRoute</code> dans cette information de chemin.
Pour qu'Apache puisse trouver ce genre d'information de chemin, vous
devez définir <code>scolonpathdelim</code> à <code>On</code> dans la
directive <directive module="mod_proxy">ProxyPass</directive> ou
<directive module="mod_proxy">ProxySet</directive>.</p>
<p>Enfin, vous pouvez utiliser simultanément les cookies et le codage
d'URL en définissant le nom du cookie et le nom du paramètre d'URL
séparés par une barre verticale (<code>|</code>) comme dans
l'exemple suivant :</p>
<highlight language="config">
ProxyPass "/test" "balancer://mycluster" stickysession=JSESSIONID|jsessionid scolonpathdelim=On
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80 route=node1
BalancerMember http://192.168.1.51:80 route=node2
</Proxy>
</highlight>
<p>Si le cookie et le paramètre de requête fournissent tous deux une
information de route correcte pour la même requête, c'est
l'information en provenance du paramètre de requête qui sera
retenue.</p>
</section>
<section id="stickyness_troubleshooting">
<title>Résolution des problèmes liés à la répartition de charge par
abonnement</title>
<p>Si vous êtes confronté à des erreurs d'abonnement, comme la
nécessité pour les utilisateurs de se reconnecter suite à une perte
de session d'application, vous devez tout d'abord vérifier si ceci
n'est pas du à une indisponibilité sporadique des serveurs
d'arrière-plan ou à une erreur de configuration. La présence de
messages d'erreur de type proxy dans le journal des erreurs d'Apache
pourra révéler des problèmes de stabilité au niveau des serveurs
d'arrière-plan.</p>
<p>Pour contrôler votre configuration, regardez tout d'abord si
l'abonnement est à base de cookie ou de codage d'URL. L'étape
suivante consiste à enregistrer certaines données dans le journal
des accès en utilisant un <directive module="mod_log_config">format
de journalisation</directive> personnalisé. Les champs intéressants
sont les suivants :</p>
<dl>
<dt><code>%{MONCOOKIE}C</code></dt>
<dd>La valeur que contient le cookie de nom <code>MONCOOKIE</code>.
Le nom doit correspondre au nom défini par l'attribut
<var>stickysession</var>.</dd>
<dt><code>%{Set-Cookie}o</code></dt>
<dd>Ce champ contient tout cookie défini par le serveur
d'arrière-plan. Vous pouvez ainsi vérifier si le serveur
d'arrière-plan définit bien le cookie de session auquel vous vous
attendez, et à quelle valeur il est défini.</dd>
<dt><code>%{BALANCER_SESSION_STICKY}e</code></dt>
<dd>Le nom du cookie ou du paramètre de requête utilisé pour la
recherche de l'information de routage.</dd>
<dt><code>%{BALANCER_SESSION_ROUTE}e</code></dt>
<dd>L'information de routage extraite de la requête.</dd>
<dt><code>%{BALANCER_WORKER_ROUTE}e</code></dt>
<dd>La route du serveur choisi.</dd>
<dt><code>%{BALANCER_ROUTE_CHANGED}e</code></dt>
<dd>Contient la valeur <code>1</code> si la route extraite de la
requête est différente de la route du serveur ; autrement dit, le
traitement de la requête n'a pas pu être effectué dans le cadre
d'une répartition de charge par abonnement.</dd>
</dl>
<p>Les pertes de session sont souvent dues à des expirations de
session dont la valeur peut en général être configurée au niveau du
serveur d'arrière-plan.</p>
<p>Si le niveau de journalisation est défini à <code>debug</code> ou
plus, le répartiteur journalise aussi des informations détaillées à
propos de l'abonnement dans le journal des erreurs, ce qui facilite
la résolution des problèmes d'abonnement. Notez cependant que le
volume de journalisation pourra alors s'avérer trop important pour
un serveur en production sous forte charge.</p>
</section>
</modulesynopsis>
|