We have been using TG 2.0 at ShootQ (shootq.com). The marketing
website is PHP based, but the application is all TG 2.0. Its a very
large and sophisticated application that we still think is very easy
to use :)
> Is the site Forward Facing or a backend?
Forward facing with thousands of users.
> How is the site deployed? (mod_wsgi, mod_python, apache2, proxy,
> paster, etc)
We use paste behind nginx on our application servers, which are
then behind a hardware load balancer which also provides SSL
acceleration.
> What templating engine is used? (Genshi, Mako, Jijna, etc)
Genshi for most of the application with Mako for performance
sensitive areas.
> How have web designers reacted to the constraints placed with the
> templating engine you used?
We love Genshi, and wouldn't use anything else if it performed
faster. I would like to see this become a big focus of TG in the
future. A faster version of Genshi!
> Are static files served by TG2?
No, they are served by nginx.
> How much daily traffic are you seeing? (hundreds, thousands, tens
> of thousands)
Tens of thousands of requests.
> What type of hardware/hosting? (virtual, virtual machine,
> dedicated, cluster, etc)
We are hosted on Joyent accelerators, which are essentially highly
optimized Solaris Zones.
> What implementation issues have you run into?
At the time we started, there was no transaction manager in TG 2.0.
In addition, we use MySQL master-slave replication for redundancy
and load balancing. We ended up rolling our own WSGI middleware
which:
1. Wraps all POST and DELETE requests in a transaction
automatically,
and routes all SQL to the MySQL master.
2. Routes all non-transactional (read) requests to a MySQL slave.
3. Allows us to flag certain requests as requiring the next
request to certain URIs to read from the MySQL master. This
is implemented as a decorator and a utility function. This is
so that writes quickly followed by reads don't suffer from
replication delay.
This is all possible thanks to WSGI and Elixir/SQLAlchemy making it
very easy to do.
In addition, we ran into issues early on with static resources being
served up too frequently and how to deal with this. We ended up
rolling our own little helper functions to generate URIs for our
static resources that include a "revision stamp" from our source
control repository. We then utilize nginx to force this content to
be cached by the browser. This makes it so that most of our static
content is requested only once by the browser until we manually
force it to be fetched again by changing the "stamp".
> What steps have been taken to plan for the thundering herd?
We make use of memcached, have a highly redundant infrastructure,
and have multiple instances of the application on each application
server, plus multiple application servers behind a hardware load
balancer.
We can scale horizontally by adding application servers and MySQL
slaves, and vertically by "turning up" the resources available to
our virtualized servers. In addition, most services run on their own
server (we have over 9 servers we currently run on).
We make use of memcached to cache intensive data like reports, and
have written a monitoring system that alerts us when resource usage
on our servers exceed a certain threshold. In addition, this system
has an OS X dashboard widget we implemented that allows us to see
the current status of all processes and resource usage across our
servers at a glance.
We also make use of Amazon S3 to keep user-generated content out of
our systems and our database, which allows us to scale up to many
hundreds of thousands of users without any concern.
> In particular, I notice shootq as a TG2 production site, but, they
> appear to run cakephp on the forward facing site and I assume
> they are using TG2 for the backend. Any input as to why the
> application development uses two frameworks?
We do this exact thing because, honestly, a marketing website
is very content driven, and its really not a great use case for
TurboGears in my opinion. There's a great deal of immediacy to PHP,
and being able to quickly push an update to the website without
having to restart the paste processes is a big win.
> I have seen some input regarding using TG2 for facebook and I
> am wondering what sort of hardware and environment I'm going to
> have to deploy to run the application based on some real-world
> experience. I don't need to know the url of the sites, but,
> would like to get a little real-world data so that I can plan
> accordingly.
Take a look at Joyent. They offer free accelerators for Facebook
applications, last I checked. They are nice, as long as you aren't
doing heavy I/O.
Best of luck to you!
--
Jonathan LaCour
http://cleverdevil.org
http://shootq.com
If you don't mind me asking, what did you decide to use instead of
ToscaWidgets and what were your reasons?
Thanks
Iain
On Friday 29 May 2009, cd34 wrote:
> What are some sites using TurboGears 2.0 in a production setting?
>
> Is the site Forward Facing or a backend?
Facing forward.
> How is the site deployed? (mod_wsgi, mod_python, apache2, proxy,
> paster, etc)
Currently nginx as load balancer distributing the load on 4 cherrypy
instances. For TG2 this would be paste, which is faster than cherrypy V2 used
in TG1
> What templating engine is used? (Genshi, Mako, Jijna, etc)
Genshi.
> How have web designers reacted to the constraints placed with the
> templating engine you used?
Web designers? Hehe. Ok, I'm not a web-designer, but I wrote all the stuff
myself. I doubt a web-designer will face a lot of issues. The design is
generally something you put into place and then have someone who can program
set up the templates. Genshi templates are very easy and require only basic
programming skills - hey, even my wife can handle that and she's not a
programmer (although she has a decent understanding of HTML and CSS)
> Are static files served by TG2?
No. Static files are served by nginx with a separate subdomain for images (the
site is image-heavy). Subdomains for things like images are generally a good
idea, because most browsers have a limitation towards how many concurrent
connections they use for one domain (usually a max of 4). If you have images
or videos served from a second domain you can get browsers to open more
concurrent connections. Broadband gives most users the bandwidth to do that,
so in the end your page loads faster for a better user-experience.
> How much daily traffic are you seeing? (hundreds, thousands, tens of
> thousands)
Depending on the day it goes up to 80.000 pages a day with about 60 hits per
page.
> What type of hardware/hosting? (virtual, virtual machine, dedicated,
> cluster, etc)
Dedicated servers.Two dual dual-core (4 cores total) machines with 4GB memory
each. Another two virtual dedicated servers for image and ad-serving.
> What implementation issues have you run into?
Not a lot with TG1. Porting to TG2 will take a bit of a rewrite, particularly
in the area of SA (their API changed, so using the newer version requires
rewriting all queries) and identity handling. Neither of the two should be an
issue if you start out with TG2.
> What steps have been taken to plan for the thundering herd?
The setup allows to just plug in more servers. The website is unlikely to grow
suddenly, it's more a "permanent growth over time" kinda site. Particularly
with the recent change to avoid Genshi "match" tags (suggested by Mark Ramm),
we now can handle roughly 100.000 pages a day. The moment we hit 80.000 a day
on a permanent basis we'll just add another server and load-balance with
nginx or pull the database onto another dedicated server.
In a TG2 setting I'd do some stress testing with mod_wsgi. It's supposed to be
faster from what I read.
Be aware that TG (either version) is memory hungry like many other similar
app-engines/frameworks. So plan on as much memory as you can get within your
budget. We started with 2GB memory per machine but had to upgrade to 4GB
after a couple of months. Also consider your database in that calculation.
Budget permitting I'd opt for a separate database server that is directly LAN
connected to a second NIC of the servers. That way you'd have one machine
just to handle database. In a combined setup (as we currently use), you have
to up the memory to allow for decent database performance - that also depends
on what database you use (we use postgresql for many reasons, consistent
performance being one of them, having many features that you can trust your
payroll with being another. Mysql never was a choice for us. It's faster in
simple read-operations, but IMHO lacks seriously when it comes to data
integrity and error checking. But that's a discussion for a database list)
Only Mark can answer that question but I also don't use any widgets.
Widgets are typically used for UI elements like forms and such and I
use a javascript library for these things. This means that the web app
only sends JSON that define a UI (imagine a simple dict) and on the
client a javascript library consumes this JSON and presents the user
with the appropriate elements. I use extjs actually.
Reasons: providing a UI definition from the web app as opposed to
rendered html allows connecting to your web app with clients that are
not web browsers. For example I distribute a desktop app that users
can use to talk to the web app. This desktop app also understands the
JSON UI definition format I use so it can present the user with a UI
of its own too.
This setup makes your web app code much cleaner, more maintainable and
more extendable. I understand that widgets, tosca in particular, are
designed to not pollute your web app code and separate concerns but
having all UI stuff on the client in javascript code is even better in
my opinion. Complex web apps have javascript in them anyway. And these
days there are really fantastic javascript libraries out there that
make UI design absolutely painless, extjs is just one example, there
are tons more.
Cheers,
Daniel
--
Psss, psss, put it down! - http://www.cafepress.com/putitdown
[...]
>> How have web designers reacted to the constraints placed with the
>> templating engine you used?
>
> We love Genshi, and wouldn't use anything else if it performed
> faster. I would like to see this become a big focus of TG in the
> future. A faster version of Genshi!
chameleon.genshi is an implementation of genshi that has speeds in the
range of mako. The only thing is that it is missing i18n support ATM.
We should concentrate on helping chameleon people to get the hooks in
place to support i18n...
Florent.
> chameleon.genshi is an implementation of genshi that has speeds
> in the range of mako. The only thing is that it is missing i18n
> support ATM. We should concentrate on helping chameleon people to
> get the hooks in place to support i18n...
I spent several infuriating hours attempting to get this to install
once, and completely gave up on it. I think it had to do with the
fact that lxml is one of the most preposterously difficult to build
libraries in the world. But, I could be misremembering.
Also, IIRC, the documentation was totally non-existent on how one
might actually use it with TG.
Well... I installed it on dev machines for Windows, Linux and MacosX
so I don't share your POV. Even if I concede it is not the easiest lib
to install.
As for the TG2 support it is in the core of the renderers... and I
could provide more info and even real directions if you transformed
that into some helpful docs for us :) deal?
Florent.
> Well... I installed it on dev machines for Windows, Linux and
> MacosX so I don't share your POV. Even if I concede it is not the
> easiest lib to install.
Of course, not 30 seconds after I posted this, I tried to
easy_install it on my Mac, and it worked like a champ. So it looks
like things have changed since I last tried it out, at least on the
Mac. I'll have to try Solaris at some point soon as well.
> As for the TG2 support it is in the core of the renderers...
> and I could provide more info and even real directions if you
> transformed that into some helpful docs for us :) deal?
We're still using a slightly old version of TG 2.0, and are using
legacy "buffet" support to render templates. One of these days we'll
upgrade to TG 2.0 final, and I'll definitely take you up on it :)
Any ideas on how we might be able to try chameleon.genshi through
the buffet support would be helpful, of course :)
I know that recently the repoze guys have been cutting out lxml
dependencies and other hard to compile issues, might have been something
like that.
Iain
Does anyone know of any good tutorials for this kind of desing? I'd love
to check out some simple code.
Iain
We're not really doing any traditional web-forms, everything is
ajax/jquery and TW introduced overhead that we did not need.
We also needed to minify/concatenate all our JS resources, use css
sprites (small images all concatenated into a single file and
displayed in the right places by css), and minified css, all of which
was easier if we controlled all that stuff.
--Mark Ramm
there is no difference between an ajax-call or a "normal" http-request,
so whatever the browser transmits to persuade your web-apps that the
request is authenticated and authorized is transmitted as well.
repoze.who usually uses cookies afaik.
Diez
Actually the sprites aren't an issue in TG1 or TG2. IMHO the issue is css and
js compression/combination. Zope does this quite nicely, but AFAIK TW in
combination with TG does not (haven't checked recently).
That would be a major point on my wishlist. At least if TW could combine and
compress js/css would already help a lot. Having some kind of plugin/entry
point to TG that allows putting all those resources together would be even
better. That would allow me to strip at least 20 requests per page...
Uwe
Authentication is done in the same way as without any javascript
stuff. I.e. you decorate the methods of your controllers with the
appropriate @identity.require decorators or wrap the entire controller
in identity.SecureObject (these are the tg1 names, maybe tg2 is
different, but same concept).
The javascript client code will post an http request and one of your
methods will return JSON. If the user is not authenticated you send
some error message in the JSON response, the client code will check
this, if it's there, display an error message or redirect or whatever.
If there is no error, then the user was authenticated and the client
code can start processing the legitimate JSON response it asked for.
There is no magic here. You write controllers to return html (A) and
other controllers to return JSON (B). Let's say html (A) is just a
couple of <div> elements and a reference to a static javascript source
(C). The source (C) will contain javascript code that will send http
requests to (B), get the response, process it and, for example, create
UI elements in the <div> elements of (A). Voila la, you just generated
a dynamic UI entirely from javascript client code.
The advantages are clear, controller (A) only returns a bare html
source and doesn't worry about anything else, while controller (B)
only returns JSON that defines your UI. And the client code (C) will
actually render the UI but that is only being done on the client, i.e.
the web browser, where this kind of stuff really belongs. Your
controller code is not polluted with all sorts of UI stuff, it's all
being done on the client using javascript client code.
Daniel Fetchinson wrote:
>>> I use extjs actually.
>>>
>>> Reasons: providing a UI definition from the web app as opposed to
>>> rendered html allows connecting to your web app with clients that are
>>> not web browsers. For example I distribute a desktop app that users
>>> can use to talk to the web app. This desktop app also understands the
>>> JSON UI definition format I use so it can present the user with a UI
>>> of its own too.
>>>
>>> Daniel,
If you don't mind saying, did you use some library to "understand" the
JSON UI Definition in your desktop app? Or did you code for it.
Is the desktop app written in Python?
Thanks.
-Rodney
No, I use a very simple UI definition format that I invented myself,
it's nothing fancy, in python it looks like this for forms:
fiels = [ dict( type='text', name='name', label='Your Name',
not_empty=True ), ........ ]
so it's a list of dicts, each dict defining a form entry. For example
a radio button is defined like this:
dict(
type='radio',
name='sex',
label='Sex',
value=[
dict( name='male', label='Male', checked=False ),
dict( name='female', label='Female', checked=False ) ],
not_empty=False )
These is then parsed by javascript in an obvious way, without using
any library. The desktop app is also written in python and this python
app parses the above list the same way and presents the user with the
appropriate form.
There are sophisticated xml formats for storing all sorts of
sophisticated UI's (for example wx does this I think) but this kind of
stuff is too heavy weight for me, all I need are forms, for which the
above very simple model is sufficient.