Procházet zdrojové kódy

Add Unix socket support for Redis connections (#15644)

Adds a new configuration setting to connect to Redis via a Unix
socket instead of over TCP. Disabled by default.
tags/v1.85.0rc1
Jason Little před 11 měsíci
committed by GitHub
rodič
revize
c835befd10
V databázi nebyl nalezen žádný známý klíč pro tento podpis ID GPG klíče: 4AEE18F83AFDEB23
7 změnil soubory, kde provedl 100 přidání a 23 odebrání
  1. +1
    -0
      changelog.d/15644.feature
  2. +4
    -0
      docs/usage/configuration/config_documentation.md
  3. +3
    -0
      stubs/txredisapi.pyi
  4. +1
    -0
      synapse/config/redis.py
  5. +9
    -1
      synapse/replication/tcp/handler.py
  6. +54
    -8
      synapse/replication/tcp/redis.py
  7. +28
    -14
      synapse/server.py

+ 1
- 0
changelog.d/15644.feature Zobrazit soubor

@@ -0,0 +1 @@
Add Unix socket support for Redis connections. Contributed by Jason Little.

+ 4
- 0
docs/usage/configuration/config_documentation.md Zobrazit soubor

@@ -3979,6 +3979,8 @@ This setting has the following sub-options:
* `enabled`: whether to use Redis support. Defaults to false. * `enabled`: whether to use Redis support. Defaults to false.
* `host` and `port`: Optional host and port to use to connect to redis. Defaults to * `host` and `port`: Optional host and port to use to connect to redis. Defaults to
localhost and 6379 localhost and 6379
* `path`: The full path to a local Unix socket file. **If this is used, `host` and
`port` are ignored.** Defaults to `/tmp/redis.sock'
* `password`: Optional password if configured on the Redis instance. * `password`: Optional password if configured on the Redis instance.
* `dbid`: Optional redis dbid if needs to connect to specific redis logical db. * `dbid`: Optional redis dbid if needs to connect to specific redis logical db.
* `use_tls`: Whether to use tls connection. Defaults to false. * `use_tls`: Whether to use tls connection. Defaults to false.
@@ -3991,6 +3993,8 @@ This setting has the following sub-options:


_Changed in Synapse 1.84.0: Added use\_tls, certificate\_file, private\_key\_file, ca\_file and ca\_path attributes_ _Changed in Synapse 1.84.0: Added use\_tls, certificate\_file, private\_key\_file, ca\_file and ca\_path attributes_


_Changed in Synapse 1.85.0: Added path option to use a local Unix socket_

Example configuration: Example configuration:
```yaml ```yaml
redis: redis:


+ 3
- 0
stubs/txredisapi.pyi Zobrazit soubor

@@ -61,6 +61,9 @@ def lazyConnection(
# most methods to it via ConnectionHandler.__getattr__. # most methods to it via ConnectionHandler.__getattr__.
class ConnectionHandler(RedisProtocol): class ConnectionHandler(RedisProtocol):
def disconnect(self) -> "Deferred[None]": ... def disconnect(self) -> "Deferred[None]": ...
def __repr__(self) -> str: ...

class UnixConnectionHandler(ConnectionHandler): ...


class RedisFactory(protocol.ReconnectingClientFactory): class RedisFactory(protocol.ReconnectingClientFactory):
continueTrying: bool continueTrying: bool


+ 1
- 0
synapse/config/redis.py Zobrazit soubor

@@ -33,6 +33,7 @@ class RedisConfig(Config):


self.redis_host = redis_config.get("host", "localhost") self.redis_host = redis_config.get("host", "localhost")
self.redis_port = redis_config.get("port", 6379) self.redis_port = redis_config.get("port", 6379)
self.redis_path = redis_config.get("path", None)
self.redis_dbid = redis_config.get("dbid", None) self.redis_dbid = redis_config.get("dbid", None)
self.redis_password = redis_config.get("password") self.redis_password = redis_config.get("password")




+ 9
- 1
synapse/replication/tcp/handler.py Zobrazit soubor

@@ -352,7 +352,15 @@ class ReplicationCommandHandler:


reactor = hs.get_reactor() reactor = hs.get_reactor()
redis_config = hs.config.redis redis_config = hs.config.redis
if hs.config.redis.redis_use_tls:
if redis_config.redis_path is not None:
reactor.connectUNIX(
redis_config.redis_path,
self._factory,
timeout=30,
checkPID=False,
)

elif hs.config.redis.redis_use_tls:
ssl_context_factory = ClientContextFactory(hs.config.redis) ssl_context_factory = ClientContextFactory(hs.config.redis)
reactor.connectSSL( reactor.connectSSL(
redis_config.redis_host, redis_config.redis_host,


+ 54
- 8
synapse/replication/tcp/redis.py Zobrazit soubor

@@ -17,7 +17,12 @@ from inspect import isawaitable
from typing import TYPE_CHECKING, Any, Generic, List, Optional, Type, TypeVar, cast from typing import TYPE_CHECKING, Any, Generic, List, Optional, Type, TypeVar, cast


import attr import attr
import txredisapi
from txredisapi import (
ConnectionHandler,
RedisFactory,
SubscriberProtocol,
UnixConnectionHandler,
)
from zope.interface import implementer from zope.interface import implementer


from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.address import IPv4Address, IPv6Address
@@ -68,7 +73,7 @@ class ConstantProperty(Generic[T, V]):




@implementer(IReplicationConnection) @implementer(IReplicationConnection)
class RedisSubscriber(txredisapi.SubscriberProtocol):
class RedisSubscriber(SubscriberProtocol):
"""Connection to redis subscribed to replication stream. """Connection to redis subscribed to replication stream.


This class fulfils two functions: This class fulfils two functions:
@@ -95,7 +100,7 @@ class RedisSubscriber(txredisapi.SubscriberProtocol):
synapse_handler: "ReplicationCommandHandler" synapse_handler: "ReplicationCommandHandler"
synapse_stream_prefix: str synapse_stream_prefix: str
synapse_channel_names: List[str] synapse_channel_names: List[str]
synapse_outbound_redis_connection: txredisapi.ConnectionHandler
synapse_outbound_redis_connection: ConnectionHandler


def __init__(self, *args: Any, **kwargs: Any): def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -229,7 +234,7 @@ class RedisSubscriber(txredisapi.SubscriberProtocol):
) )




class SynapseRedisFactory(txredisapi.RedisFactory):
class SynapseRedisFactory(RedisFactory):
"""A subclass of RedisFactory that periodically sends pings to ensure that """A subclass of RedisFactory that periodically sends pings to ensure that
we detect dead connections. we detect dead connections.
""" """
@@ -245,7 +250,7 @@ class SynapseRedisFactory(txredisapi.RedisFactory):
dbid: Optional[int], dbid: Optional[int],
poolsize: int, poolsize: int,
isLazy: bool = False, isLazy: bool = False,
handler: Type = txredisapi.ConnectionHandler,
handler: Type = ConnectionHandler,
charset: str = "utf-8", charset: str = "utf-8",
password: Optional[str] = None, password: Optional[str] = None,
replyTimeout: int = 30, replyTimeout: int = 30,
@@ -326,7 +331,7 @@ class RedisDirectTcpReplicationClientFactory(SynapseRedisFactory):
def __init__( def __init__(
self, self,
hs: "HomeServer", hs: "HomeServer",
outbound_redis_connection: txredisapi.ConnectionHandler,
outbound_redis_connection: ConnectionHandler,
channel_names: List[str], channel_names: List[str],
): ):
super().__init__( super().__init__(
@@ -368,7 +373,7 @@ def lazyConnection(
reconnect: bool = True, reconnect: bool = True,
password: Optional[str] = None, password: Optional[str] = None,
replyTimeout: int = 30, replyTimeout: int = 30,
) -> txredisapi.ConnectionHandler:
) -> ConnectionHandler:
"""Creates a connection to Redis that is lazily set up and reconnects if the """Creates a connection to Redis that is lazily set up and reconnects if the
connections is lost. connections is lost.
""" """
@@ -380,7 +385,7 @@ def lazyConnection(
dbid=dbid, dbid=dbid,
poolsize=1, poolsize=1,
isLazy=True, isLazy=True,
handler=txredisapi.ConnectionHandler,
handler=ConnectionHandler,
password=password, password=password,
replyTimeout=replyTimeout, replyTimeout=replyTimeout,
) )
@@ -408,3 +413,44 @@ def lazyConnection(
) )


return factory.handler return factory.handler


def lazyUnixConnection(
hs: "HomeServer",
path: str = "/tmp/redis.sock",
dbid: Optional[int] = None,
reconnect: bool = True,
password: Optional[str] = None,
replyTimeout: int = 30,
) -> ConnectionHandler:
"""Creates a connection to Redis that is lazily set up and reconnects if the
connection is lost.

Returns:
A subclass of ConnectionHandler, which is a UnixConnectionHandler in this case.
"""

uuid = path

factory = SynapseRedisFactory(
hs,
uuid=uuid,
dbid=dbid,
poolsize=1,
isLazy=True,
handler=UnixConnectionHandler,
password=password,
replyTimeout=replyTimeout,
)
factory.continueTrying = reconnect

reactor = hs.get_reactor()

reactor.connectUNIX(
path,
factory,
timeout=30,
checkPID=False,
)

return factory.handler

+ 28
- 14
synapse/server.py Zobrazit soubor

@@ -864,22 +864,36 @@ class HomeServer(metaclass=abc.ABCMeta):


# We only want to import redis module if we're using it, as we have # We only want to import redis module if we're using it, as we have
# `txredisapi` as an optional dependency. # `txredisapi` as an optional dependency.
from synapse.replication.tcp.redis import lazyConnection
from synapse.replication.tcp.redis import lazyConnection, lazyUnixConnection


logger.info(
"Connecting to redis (host=%r port=%r) for external cache",
self.config.redis.redis_host,
self.config.redis.redis_port,
)
if self.config.redis.redis_path is None:
logger.info(
"Connecting to redis (host=%r port=%r) for external cache",
self.config.redis.redis_host,
self.config.redis.redis_port,
)


return lazyConnection(
hs=self,
host=self.config.redis.redis_host,
port=self.config.redis.redis_port,
dbid=self.config.redis.redis_dbid,
password=self.config.redis.redis_password,
reconnect=True,
)
return lazyConnection(
hs=self,
host=self.config.redis.redis_host,
port=self.config.redis.redis_port,
dbid=self.config.redis.redis_dbid,
password=self.config.redis.redis_password,
reconnect=True,
)
else:
logger.info(
"Connecting to redis (path=%r) for external cache",
self.config.redis.redis_path,
)

return lazyUnixConnection(
hs=self,
path=self.config.redis.redis_path,
dbid=self.config.redis.redis_dbid,
password=self.config.redis.redis_password,
reconnect=True,
)


def should_send_federation(self) -> bool: def should_send_federation(self) -> bool:
"Should this server be sending federation traffic directly?" "Should this server be sending federation traffic directly?"


Načítá se…
Zrušit
Uložit