Tips on writing scalable apps
April 29th, 2008 | Published in Google App Engine
- Avoid contention on datastore entities. If every request to your app reads or writes a particular entity, latency will increase as your traffic goes up because reads and writes on a given entity are sequential. One example construct you should avoid at all costs is the gobal counter, i.e. an entity that keeps track of a count and is updated or read on every request. There are some interesting ways of simulating this behavior that don't require reads/writes on every request, and we'll talk about a handy way to cache entities for reads below.
- Avoid large entity groups. Any two entities that share a common ancestor belong to the same entity groups. All writes to an entity group are sequential, so large entity groups can bog down popular apps quickly if there are a lot of writes to that group. Instead, use small, localized groups in your design.
- Write sparingly. Writes are more expensive than reads; keep this in mind when designing your data model. If you can avoid a write--it's best to do so.
-
Define a
main()
function for code reuse. Instances of your app are kept running for a certain period after each request, so there's a chance that any request will hit an already-running app. Apps that definemain
as in the following example:
def main():
can reuse global variables, so although there's no guarantee that any given request will hit a running app instance, you can take advantage of this to non-deterministically cache entities and other expensive values. This works simply because App Engine will detect if
application = webapp.WSGIApplication(_URLS, debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == '__main__':
main()main()
is present in an already-loaded script and call it instead of re-importing. - Profile your code. You can use the Python profiler to profile your code's performance.