File: node22.html

package info (click to toggle)
cherrypy 0.10-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 10,324 kB
  • ctags: 1,759
  • sloc: python: 14,411; sh: 6,915; perl: 2,472; makefile: 76
file content (252 lines) | stat: -rw-r--r-- 9,747 bytes parent folder | download
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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>21. Sample deployment configuration for a real-world website</title>
<META NAME="description" CONTENT="21. Sample deployment configuration for a real-world website">
<META NAME="keywords" CONTENT="howto">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="STYLESHEET" href="howto.css" type='text/css'>
<link rel="first" href="howto.html">
<link rel="contents" href="contents.html" title="Contents">

<LINK REL="next" HREF="node23.html">
<LINK REL="previous" HREF="node21.html">
<LINK REL="up" HREF="howto.html">
<LINK REL="next" HREF="node23.html">
<meta name='aesop' content='information'>
</head>
<body>
<DIV CLASS="navigation">
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node21.html"><img src="../icons/previous.gif"
  border="0" height="32"
  alt="Previous Page" width="32"></A></td>
<td><A HREF="howto.html"><img src="../icons/up.gif"
  border="0" height="32"
  alt="Up One Level" width="32"></A></td>
<td><A HREF="node23.html"><img src="../icons/next.gif"
  border="0" height="32"
  alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy HowTo</td>
<td><A HREF="node1.html"><img src="../icons/contents.gif"
  border="0" height="32"
  alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node21.html">20. How to use</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="howto.html">CherryPy HowTo</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node23.html">22. How to stream</A>
<br><hr>
</DIV>
<!--End of Navigation Panel-->
<!--Table of Child-Links-->
<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>

<UL CLASS="ChildLinks">
<LI><A href="node22.html#SECTION0022100000000000000000">21.1 Hardware</a>
<LI><A href="node22.html#SECTION0022200000000000000000">21.2 Software environment</a>
<LI><A href="node22.html#SECTION0022300000000000000000">21.3 CherryPy version</a>
<LI><A href="node22.html#SECTION0022400000000000000000">21.4 CherryPy server configuration</a>
<LI><A href="node22.html#SECTION0022500000000000000000">21.5 CherryPy server deployment</a>
<LI><A href="node22.html#SECTION0022600000000000000000">21.6 Database configuration</a>
<LI><A href="node22.html#SECTION0022700000000000000000">21.7 Sessions</a>
<LI><A href="node22.html#SECTION0022800000000000000000">21.8 Results</a>
</ul>
<!--End of Table of Child-Links-->
<HR>

<H1><A NAME="SECTION0022000000000000000000">
21. Sample deployment configuration for a real-world website</A>
</H1>

<P>
This HowTo describes a sample deployment configuration that I believe is well adapted for most "real-world" websites.
It is the configuration used by the <a class="url" href="http://www.cherrypy.org">http://www.cherrypy.org</a> website itself.

<P>

<H1><A NAME="SECTION0022100000000000000000">
21.1 Hardware</A>
</H1>
The website runs on the Celeron 1.3Ghz with 512MB RAM and shares the machine with about 30 other sites.
The choice of the hardware depends mostly on your budget and how much traffic you plan to get...

<P>

<H1><A NAME="SECTION0022200000000000000000">
21.2 Software environment</A>
</H1>
The site runs on Linux RedHat, but I believe it would run just as well on other OSes (including Windows).
It runs on Python-2.3, but I believe it would run just as well on Python-2.2 or Python-2.1. However, Python-2.3 seems
to be a bit faster than older versions.

<P>

<H1><A NAME="SECTION0022300000000000000000">
21.3 CherryPy version</A>
</H1>
The site usually uses the latest CVS version from CherryPy (currently the 0.9-final) version.
The 0.9 version seems to be much more stable than previous versions so if you are running an older version, I
highly recommend that you upgrade to that version.

<P>

<H1><A NAME="SECTION0022400000000000000000">
21.4 CherryPy server configuration</A>
</H1>
The site is deployed as a thread-pool server. I believe this is the best option for most websites.
It is configured to run with 10 threads and since each page is really fast to build, the site should be able to support
many (much more than 10) concurrent users...

<P>
The number of threads that you should use for your site depends on many criteria, including the number of concurrent
users you plan to have, the average time your pages take to build and the power (CPU and RAM) of the machine that
will run the site.

<P>

<H1><A NAME="SECTION0022500000000000000000">
21.5 CherryPy server deployment</A>
</H1>
The site is running "exposed" on port 80, which means that there is no other webserver (like Apache) involved.

<P>
In order to listen on port 80, the server has to be started by the user "root". However, running the server as "root"
is not very safe, so we use the special function <var>initAfterBind</var> to switch the user running the server to another
user. The code is very simple:

<P>
<div class="verbatim"><pre>
def initAfterBind():
    import os
    # We must switch the group first
    os.setegid(500)  # Replace with desired user id.
    os.seteuid(2524) # Idem
</pre></div>

<P>
Also, since the server runs a pool of threads, we must switch the user for all these threads as well (otherwise,
only the parent thread will be switched). To do so, we just use the <var>initThread</var> special function, like this:

<P>
<div class="verbatim"><pre>
def initThread(threadIndex):
    import os
    # We must switch the group first
    os.setegid(500)  # Replace with desired user id.
    os.seteuid(2524) # Idem
</pre></div>

<P>

<H1><A NAME="SECTION0022600000000000000000">
21.6 Database configuration</A>
</H1>
The site uses MySql as a database backend to log the requests that are being made to the server. Therefore, each request
triggers a database write.

<P>
Since the MySQLdb driver doesn't work well (from my experience) if we have several threads sharing the same database
connection, each thread is given its own database connection, so it doesn't interfer with other threads.

<P>
This is done very easily using the <var>initThread</var> special function and the <var>request</var> special variable, like this:

<P>
<div class="verbatim"><pre>
def initThread(threadIndex):
    time.sleep(threadIndex * 0.2) # Sleep 0.2 seconds between each new database connection to make sure MySql can keep up ...
    request.connection = MySQLdb.connect('host', 'user', 'password', 'name')
</pre></div>

<P>
This takes advantage of the fact that <var>request</var> is a special thread-aware class instance (so each thread can safely
set/get member variables without have to worry about other threads)

<P>
Then, when we need to run a query, we just use code like this:

<P>
<div class="verbatim"><pre>
c=request.connection.cursor()
c.execute(query)
res=c.fetchall()
c.close()
</pre></div>

<P>
And also, the forum on the website runs on top of ZODB and since ZODB doesn't support multiple threads by itself, I had to
install ZEO so each thread also behaves as a ZEO client.

<P>

<H1><A NAME="SECTION0022700000000000000000">
21.7 Sessions</A>
</H1>
The site also uses sessions (mostly for the forum, and also for one page in the online demo).
Sessions are configured to store the data in RAM. Since the code for managing sessions is thread-safe,
all threads have access to the same session data and everybody is happy :-)

<P>
I believe that other storage types for sessions (file, database, cookie) would work just as well.

<P>

<H1><A NAME="SECTION0022800000000000000000">
21.8 Results</A>
</H1>
As I write these lines, the site has been running with no problem with this new configuration for about 20 days and
I never had to restart it, proving that it is quite stable. Also, the RAM used by the threads has never increased,
proving that there is no memory leaks ...
It is true that the CherryPy.org website is not a "high-traffic" website, but it is still a good sign.

<P>
Note that if you're afraid that your CherryPy server might crash while you're sleeping, you can always set up a cronjob
to check that the site is still running and to restart it if it isn't ...

<P>

<DIV CLASS="navigation">
<p><hr>
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node21.html"><img src="../icons/previous.gif"
  border="0" height="32"
  alt="Previous Page" width="32"></A></td>
<td><A HREF="howto.html"><img src="../icons/up.gif"
  border="0" height="32"
  alt="Up One Level" width="32"></A></td>
<td><A HREF="node23.html"><img src="../icons/next.gif"
  border="0" height="32"
  alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy HowTo</td>
<td><A HREF="node1.html"><img src="../icons/contents.gif"
  border="0" height="32"
  alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node21.html">20. How to use</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="howto.html">CherryPy HowTo</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node23.html">22. How to stream</A>
<hr>
<span class="release-info">Release 0.10, documentation updated on 19 March 2004.</span>
</DIV>
<!--End of Navigation Panel-->
<ADDRESS>
See <i><a href="about.html">About this document...</a></i> for information on suggesting changes.
</ADDRESS>
</BODY>
</HTML>