Add redis sentinel support (#1909)

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
This commit is contained in:
Tim Neumann
2021-06-18 19:25:08 +02:00
committed by GitHub
parent 1ef076bb9b
commit 2852722b50
3 changed files with 60 additions and 9 deletions

View File

@@ -297,6 +297,12 @@ to speed up various operations::
[redis] [redis]
location=redis://127.0.0.1:6379/1 location=redis://127.0.0.1:6379/1
sessions=false sessions=false
sentinels=[
["sentinel_host_1", 26379],
["sentinel_host_2", 26379],
["sentinel_host_3", 26379]
]
password=password
``location`` ``location``
The location of redis, as a URL of the form ``redis://[:password]@localhost:6379/0`` The location of redis, as a URL of the form ``redis://[:password]@localhost:6379/0``
@@ -305,6 +311,21 @@ to speed up various operations::
``session`` ``session``
When this is set to ``True``, redis will be used as the session storage. When this is set to ``True``, redis will be used as the session storage.
``sentinels``
Configures redis sentinels to use.
If you don't want to use redis sentinels, you should omit this option.
If this is set, redis via sentinels will be used instead of plain redis.
In this case the location should be of the form ``redis://my_master/0``.
The ``sentinels`` variable should be a json serialized list of sentinels,
each being a list with the two elements hostname and port.
You cannot provide a password within the location when using sentinels.
Note that the configuration format requires you to either place the entire
value on one line or make sure all values are indented by at least one space.
``password``
If your redis setup doesn't require a password or you already specified it in the location you can omit this option.
If this is set it will be passed to redis as the connection option PASSWORD.
If redis is not configured, pretix will store sessions and locks in the database. If memcached If redis is not configured, pretix will store sessions and locks in the database. If memcached
is configured, memcached will be used for caching instead of redis. is configured, memcached will be used for caching instead of redis.
@@ -343,11 +364,22 @@ an AMQP server (e.g. RabbitMQ) as a broker and redis or your database as a resul
[celery] [celery]
broker=amqp://guest:guest@localhost:5672// broker=amqp://guest:guest@localhost:5672//
backend=redis://localhost/0 backend=redis://localhost/0
broker_transport_options="{}"
backend_transport_options="{}"
RabbitMQ might be the better choice if you have a complex, multi-server, high-performance setup, RabbitMQ might be the better choice if you have a complex, multi-server, high-performance setup,
but as you already should have a redis instance ready for session and lock storage, we recommend but as you already should have a redis instance ready for session and lock storage, we recommend
redis for convenience. See the `Celery documentation`_ for more details. redis for convenience. See the `Celery documentation`_ for more details.
The two ``transport_options`` entries can be omitted in most cases.
If they are present they need to be a valid JSON dictionary.
For possible entries in that dictionary see the `Celery documentation`_.
To use redis with sentinels set the broker or backend to ``sentinel://sentinel_host_1:26379;sentinal_host_2:26379/0``
and the respective transport_options to ``{"master_name":"mymaster"}``.
If your redis instances behind the sentinel have a password use ``sentinel://:my_password@sentinel_host_1:26379;sentinal_host_2:26379/0``.
If your redis sentinels themselves have a password set the transport_options to ``{"master_name":"mymaster","sentinel_kwargs":{"password":"my_password"}}``.
Sentry Sentry
------ ------

View File

@@ -38,6 +38,7 @@ import logging
import os import os
import sys import sys
from urllib.parse import urlparse from urllib.parse import urlparse
from json import loads
import django.conf.locale import django.conf.locale
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
@@ -247,23 +248,35 @@ if HAS_MEMCACHED:
} }
HAS_REDIS = config.has_option('redis', 'location') HAS_REDIS = config.has_option('redis', 'location')
USE_REDIS_SENTINEL = config.has_option('redis', 'sentinels')
HAS_REDIS_PASSWORD = config.has_option('redis', 'password')
if HAS_REDIS: if HAS_REDIS:
OPTIONS = {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"REDIS_CLIENT_KWARGS": {"health_check_interval": 30}
}
if USE_REDIS_SENTINEL:
DJANGO_REDIS_CONNECTION_FACTORY = "django_redis.pool.SentinelConnectionFactory"
OPTIONS["CLIENT_CLASS"] = "django_redis.client.SentinelClient"
OPTIONS["CONNECTION_POOL_CLASS"] = "redis.sentinel.SentinelConnectionPool"
# See https://github.com/jazzband/django-redis/issues/540
OPTIONS["SENTINEL_KWARGS"] = {"socket_timeout": 1}
OPTIONS["SENTINELS"] = [tuple(sentinel) for sentinel in loads(config.get('redis', 'sentinels'))]
if HAS_REDIS_PASSWORD:
OPTIONS["PASSWORD"] = config.get('redis', 'password')
CACHES['redis'] = { CACHES['redis'] = {
"BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
"LOCATION": config.get('redis', 'location'), "LOCATION": config.get('redis', 'location'),
"OPTIONS": { "OPTIONS": OPTIONS
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"REDIS_CLIENT_KWARGS": {"health_check_interval": 30}
}
} }
CACHES['redis_sessions'] = { CACHES['redis_sessions'] = {
"BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
"LOCATION": config.get('redis', 'location'), "LOCATION": config.get('redis', 'location'),
"TIMEOUT": 3600 * 24 * 30, "TIMEOUT": 3600 * 24 * 30,
"OPTIONS": { "OPTIONS": OPTIONS
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"REDIS_CLIENT_KWARGS": {"health_check_interval": 30}
}
} }
if not HAS_MEMCACHED: if not HAS_MEMCACHED:
CACHES['default'] = CACHES['redis'] CACHES['default'] = CACHES['redis']
@@ -279,9 +292,15 @@ if not SESSION_ENGINE:
SESSION_ENGINE = "django.contrib.sessions.backends.db" SESSION_ENGINE = "django.contrib.sessions.backends.db"
HAS_CELERY = config.has_option('celery', 'broker') HAS_CELERY = config.has_option('celery', 'broker')
HAS_CELERY_BROKER_TRANSPORT_OPTS = config.has_option('celery', 'broker_transport_options')
HAS_CELERY_BACKEND_TRANSPORT_OPTS = config.has_option('celery', 'backend_transport_options')
if HAS_CELERY: if HAS_CELERY:
CELERY_BROKER_URL = config.get('celery', 'broker') CELERY_BROKER_URL = config.get('celery', 'broker')
CELERY_RESULT_BACKEND = config.get('celery', 'backend') CELERY_RESULT_BACKEND = config.get('celery', 'backend')
if HAS_CELERY_BROKER_TRANSPORT_OPTS:
CELERY_BROKER_TRANSPORT_OPTIONS = loads(config.get('celery', 'broker_transport_options'))
if HAS_CELERY_BACKEND_TRANSPORT_OPTS:
CELERY_RESULT_BACKEND_TRANSPORT_OPTIONS = loads(config.get('celery', 'backend_transport_options'))
else: else:
CELERY_TASK_ALWAYS_EAGER = True CELERY_TASK_ALWAYS_EAGER = True

View File

@@ -186,7 +186,7 @@ setup(
'django-oauth-toolkit==1.2.*', 'django-oauth-toolkit==1.2.*',
'django-otp==0.7.*,>=0.7.5', 'django-otp==0.7.*,>=0.7.5',
'django-phonenumber-field==4.0.*', 'django-phonenumber-field==4.0.*',
'django-redis==4.11.*', 'django-redis==5.0.*',
'django-scopes==1.2.*', 'django-scopes==1.2.*',
'django-statici18n==1.9.*', 'django-statici18n==1.9.*',
'djangorestframework==3.12.*', 'djangorestframework==3.12.*',