运维开发实践 - Django Redis Sentinel

1. 背景

- django==3.2.15
- djangorestframework==3.13.1
- django-redis==5.2.0
- redis==4.5.1

当我们的Django需要使用redis sentinel模式时,会安装

pip install django-redis-sentinel

在实际使用时发现, django-redis-sentinel太久没更新,其与我们Django,django-redis之间不兼容;

2.解决方案

2.1. 手写django-redis-sentinel

2.1.1. redis_sentinel_client.py

# redis_sentinel_client.py
import logging
from typing import Any, Optional

from django_redis.client import DefaultClient


__LOG__ = logging.getLogger(__name__)

from django_redis.util import CacheKey

from redis.sentinel import Sentinel

class SentinelClient(DefaultClient):
    def __init__(self, server, params, backend):
        super(SentinelClient, self).__init__(server,params,backend)
        self._connection_string = server
        sentinel_kwargs = self._options.get("SENTINEL_KWARGS", None)
        master_name, sentinel_hosts, db = self.parse_connection_string(self._connection_string)
        sentinel = Sentinel(sentinels=sentinel_hosts, sentinel_kwargs=sentinel_kwargs)
        host, port = sentinel.discover_master(master_name)
        password = self._options.get("PASSWORD", None)
        self._server = list()
        self._server.append(self.ret_refis_connect_url(host, port, db, password))
        slaves = sentinel.discover_slaves(master_name)
        for host, port in slaves:
            self._server.append(self.ret_refis_connect_url(host, port, db, password))
        __LOG__.info("Finding {}".__format__(self._server))

    def ret_refis_connect_url(self, host, port, db, password):
        if password != None:
            return "redis://:%s@%s:%s/%s"%(password, host, port, db)
        return "redis://%s:%s/%s"%(host, port, db)

    def parse_connection_string(self, connstring):
        try:
            connection_params = connstring.split("/")
            # 我们约定将第一个redis host设为redis master
            master_name = connection_params[0]
            servers = [host_port.split(":") for host_port in connection_params[1].split(",")]
            sentinel_hosts = [(host, int(port)) for host,port in servers]
            db = connection_params[2]
        except (ValueError, TypeError, IndexError):
            raise Exception("Incorrect format '%s'"%(connstring))
        return master_name, sentinel_hosts, db
    
    def make_key(self, key: Any, version: Optional[Any] = None, prefix: Optional[str] = None):
        if prefix is None:
            prefix = self._backend.key_prefix
        return CacheKey('%s:%s'%(prefix, key))

2.1.2. settings.py

# settings.py
# redis master: 192.168.31.175:6379
# redis sentinel_01: 192.168.31.174:6379
# redis_sentinel_02: 192.168.31.173:6379
...
CACHES = {
	"default": {
		"BACKEND": "django_redis.cache.RedisCache",
		# 我们默认第一个host为redis master
		"LOCATION": "mymaster/192.168.31.175:6379,192.168.31.174:6379,192.168.31.173:6379/0",
		"OPTIONS": {
			"PASSWORD": os.environ.get("REDIS_PASSWORD"),
			"SENTINEL_KWARGS": {"password": os.environ.get("REDIS_SENTINEL_PASSWORD"), "socket_timeout": 3},
			"CLIENT_CLASS": "redis_sentinel_client.SentinelClient",
			"SERIALIZER": "django_redis.serializers.json.JSONSerializer"
		},
		"KEY_PREFIX": "liyuan"
	}
}

...

3. reference

  • django-redis-sentinel

你可能感兴趣的:(django,redis,运维开发)