Skip to content

Commit

Permalink
Allow to have a master/slave DB configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Valsecchi committed May 12, 2016
1 parent 1ee1394 commit 8c0d77e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 0 deletions.
9 changes: 9 additions & 0 deletions c2cgeoportal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,15 @@ def includeme(config):
config.include(pyramid_tm.includeme)
config.include("pyramid_closure")

if "sqlalchemy_slave.url" in settings and \
settings["sqlalchemy.url"] != settings["sqlalchemy_slave.url"]:
# Setup a slave DB connection and add a tween to switch between it and the default one.
log.info("Using a slave DB for reading")
engine_slave = sqlalchemy.engine_from_config(config.get_settings(), "sqlalchemy_slave.")
sqlahelper.add_engine(engine_slave, name="slave")
config.add_tween("c2cgeoportal.models.db_chooser_tween_factory",
over="pyramid_tm.tm_tween_factory")

# initialize the dbreflection module
dbreflection.init(engine)

Expand Down
22 changes: 22 additions & 0 deletions c2cgeoportal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,3 +974,25 @@ class Shorturl(Base):
creation = Column(DateTime)
last_hit = Column(DateTime)
nb_hits = Column(Integer)


def db_chooser_tween_factory(handler, registry):
"""
Tween factory to route to a slave DB for read-only queries.
Must be put over the pyramid_tm tween and sqlahelper must have a "slave" engine
configured.
"""
def db_chooser_tween(request):
session = DBSession()
old = session.bind
if request.method in ("GET", "OPTIONS"):
log.debug("Using slave database for %s %s" % (request.method, request.path))
session.bind = sqlahelper.get_engine("slave")
else:
log.debug("Using master database for %s %s" % (request.method, request.path))
try:
return handler(request)
finally:
session.bind = old

return db_chooser_tween
22 changes: 22 additions & 0 deletions doc/integrator/cluster.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,25 @@ In this case the first thing to do is to separate the services:
* Print
* WSGI application
* MapServer / MapCache / Memcached

To have better DB performances, one can setup multiple Postgres servers in a master/slave
configuration. To enable this feature on GeoMapFish, you must add this to your
``vars_<project>.yaml``:

.. code:: yaml
dbhost_slave: my_db_slave_hostname
sqlalchemy_slave:
url: postgresql://{dbuser}:{dbpassword}@{dbhost_slave}:{dbport}/{db}
Add in your project Makefile ``<package>.mk``:

.. code:: makefile
CONFIG_VARS += sqlalchemy_slave.url
Then, all the GET and OPTIONS requests will use one of the slave Postgres instances (DNS
pointing to more than one IP if you need it) and the rest will use the master instance.
It is assumed, here, that the views handling the GET and OPTIONS queries don't cause write
operations to the database (not supported by slave instances). If it's not the case in your
application (bad practice), don't use this feature.

0 comments on commit 8c0d77e

Please sign in to comment.