Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 32fc3b7

Browse files
authored
Remove configuration options for direct TCP replication. (#13647)
Removes the ability to configure legacy direct TCP replication. Workers now require Redis to run.
1 parent 8edf3f6 commit 32fc3b7

File tree

12 files changed

+63
-78
lines changed

12 files changed

+63
-78
lines changed

.github/workflows/tests.yml

-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ jobs:
204204
POSTGRES: ${{ matrix.job.postgres && 1}}
205205
MULTI_POSTGRES: ${{ (matrix.job.postgres == 'multi-postgres') && 1}}
206206
WORKERS: ${{ matrix.job.workers && 1 }}
207-
REDIS: 1
208207
BLACKLIST: ${{ matrix.job.workers && 'synapse-blacklist-with-workers' }}
209208
TOP: ${{ github.workspace }}
210209

changelog.d/13647.removal

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove the ability to use direct TCP replication with workers. Direct TCP replication was deprecated in Synapse v1.18.0. Workers now require using Redis.

docs/upgrade.md

+15
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,21 @@ process, for example:
9191
9292
# Upgrading to v1.67.0
9393
94+
## Direct TCP replication is no longer supported: migrate to Redis
95+
96+
Redis support was added in v1.13.0 with it becoming the recommended method in
97+
v1.18.0. It replaced the old direct TCP connections (which was deprecated as of
98+
v1.18.0) to the main process. With Redis, rather than all the workers connecting
99+
to the main process, all the workers and the main process connect to Redis,
100+
which relays replication commands between processes. This can give a significant
101+
CPU saving on the main process and is a prerequisite for upcoming
102+
performance improvements.
103+
104+
To migrate to Redis add the [`redis` config](./workers.md#shared-configuration),
105+
and remove the TCP `replication` listener from config of the master and
106+
`worker_replication_port` from worker config. Note that a HTTP listener with a
107+
`replication` resource is still required.
108+
94109
## Minimum version of Poetry is now v1.2.0
95110
96111
The minimum supported version of poetry is now 1.2. This should only affect

docs/usage/configuration/config_documentation.md

-2
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,6 @@ Sub-options for each listener include:
431431

432432
* `metrics`: (see the docs [here](../../metrics-howto.md)),
433433

434-
* `replication`: (deprecated as of Synapse 1.18, see the docs [here](../../workers.md)).
435-
436434
* `tls`: set to true to enable TLS for this listener. Will use the TLS key/cert specified in tls_private_key_path / tls_certificate_path.
437435

438436
* `x_forwarded`: Only valid for an 'http' listener. Set to true to use the X-Forwarded-For header as the client IP. Useful when Synapse is

docs/workers.md

+5-17
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,8 @@ stream between all configured Synapse processes. Additionally, processes may
3232
make HTTP requests to each other, primarily for operations which need to wait
3333
for a reply ─ such as sending an event.
3434

35-
Redis support was added in v1.13.0 with it becoming the recommended method in
36-
v1.18.0. It replaced the old direct TCP connections (which is deprecated as of
37-
v1.18.0) to the main process. With Redis, rather than all the workers connecting
38-
to the main process, all the workers and the main process connect to Redis,
39-
which relays replication commands between processes. This can give a significant
40-
cpu saving on the main process and will be a prerequisite for upcoming
41-
performance improvements.
35+
All the workers and the main process connect to Redis, which relays replication
36+
commands between processes.
4237

4338
If Redis support is enabled Synapse will use it as a shared cache, as well as a
4439
pub/sub mechanism.
@@ -330,7 +325,6 @@ effects of bursts of events from that bridge on events sent by normal users.
330325

331326
Additionally, the writing of specific streams (such as events) can be moved off
332327
of the main process to a particular worker.
333-
(This is only supported with Redis-based replication.)
334328

335329
To enable this, the worker must have a HTTP replication listener configured,
336330
have a `worker_name` and be listed in the `instance_map` config. The same worker
@@ -600,15 +594,9 @@ equivalent to `synapse.app.generic_worker`:
600594

601595
## Migration from old config
602596

603-
There are two main independent changes that have been made: introducing Redis
604-
support and merging apps into `synapse.app.generic_worker`. Both these changes
605-
are backwards compatible and so no changes to the config are required, however
606-
server admins are encouraged to plan to migrate to Redis as the old style direct
607-
TCP replication config is deprecated.
608-
609-
To migrate to Redis add the `redis` config as above, and optionally remove the
610-
TCP `replication` listener from master and `worker_replication_port` from worker
611-
config.
597+
A main change that has occurred is the merging of worker apps into
598+
`synapse.app.generic_worker`. This change is backwards compatible and so no
599+
changes to the config are required.
612600

613601
To migrate apps to use `synapse.app.generic_worker` simply update the
614602
`worker_app` option in the worker configs, and where worker are started (e.g.

synapse/app/homeserver.py

-11
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
from synapse.logging.context import LoggingContext
5858
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
5959
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
60-
from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory
6160
from synapse.rest import ClientRestResource
6261
from synapse.rest.admin import AdminRestResource
6362
from synapse.rest.health import HealthResource
@@ -290,16 +289,6 @@ def start_listening(self) -> None:
290289
manhole_settings=self.config.server.manhole_settings,
291290
manhole_globals={"hs": self},
292291
)
293-
elif listener.type == "replication":
294-
services = listen_tcp(
295-
listener.bind_addresses,
296-
listener.port,
297-
ReplicationStreamProtocolFactory(self),
298-
)
299-
for s in services:
300-
self.get_reactor().addSystemEventTrigger(
301-
"before", "shutdown", s.stopListening
302-
)
303292
elif listener.type == "metrics":
304293
if not self.config.metrics.enable_metrics:
305294
logger.warning(

synapse/config/server.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636

3737
logger = logging.Logger(__name__)
3838

39+
DIRECT_TCP_ERROR = """
40+
Using direct TCP replication for workers is no longer supported.
41+
42+
Please see https://matrix-org.github.io/synapse/latest/upgrade.html#direct-tcp-replication-is-no-longer-supported-migrate-to-redis
43+
"""
44+
3945
# by default, we attempt to listen on both '::' *and* '0.0.0.0' because some OSes
4046
# (Windows, macOS, other BSD/Linux where net.ipv6.bindv6only is set) will only listen
4147
# on IPv6 when '::' is set.
@@ -165,7 +171,6 @@ def generate_ip_set(
165171
"http",
166172
"metrics",
167173
"manhole",
168-
"replication",
169174
}
170175

171176
KNOWN_RESOURCES = {
@@ -515,7 +520,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
515520
):
516521
raise ConfigError("allowed_avatar_mimetypes must be a list")
517522

518-
self.listeners = [parse_listener_def(x) for x in config.get("listeners", [])]
523+
self.listeners = [
524+
parse_listener_def(i, x) for i, x in enumerate(config.get("listeners", []))
525+
]
519526

520527
# no_tls is not really supported any more, but let's grandfather it in
521528
# here.
@@ -880,9 +887,12 @@ def read_gc_thresholds(
880887
)
881888

882889

883-
def parse_listener_def(listener: Any) -> ListenerConfig:
890+
def parse_listener_def(num: int, listener: Any) -> ListenerConfig:
884891
"""parse a listener config from the config file"""
885892
listener_type = listener["type"]
893+
# Raise a helpful error if direct TCP replication is still configured.
894+
if listener_type == "replication":
895+
raise ConfigError(DIRECT_TCP_ERROR, ("listeners", str(num), "type"))
886896

887897
port = listener.get("port")
888898
if not isinstance(port, int):

synapse/config/workers.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
RoutableShardedWorkerHandlingConfig,
2828
ShardedWorkerHandlingConfig,
2929
)
30-
from .server import ListenerConfig, parse_listener_def
30+
from .server import DIRECT_TCP_ERROR, ListenerConfig, parse_listener_def
3131

3232
_FEDERATION_SENDER_WITH_SEND_FEDERATION_ENABLED_ERROR = """
3333
The send_federation config option must be disabled in the main
@@ -128,7 +128,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
128128
self.worker_app = None
129129

130130
self.worker_listeners = [
131-
parse_listener_def(x) for x in config.get("worker_listeners", [])
131+
parse_listener_def(i, x)
132+
for i, x in enumerate(config.get("worker_listeners", []))
132133
]
133134
self.worker_daemonize = bool(config.get("worker_daemonize"))
134135
self.worker_pid_file = config.get("worker_pid_file")
@@ -142,7 +143,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
142143
self.worker_replication_host = config.get("worker_replication_host", None)
143144

144145
# The port on the main synapse for TCP replication
145-
self.worker_replication_port = config.get("worker_replication_port", None)
146+
if "worker_replication_port" in config:
147+
raise ConfigError(DIRECT_TCP_ERROR, ("worker_replication_port",))
146148

147149
# The port on the main synapse for HTTP replication endpoint
148150
self.worker_replication_http_port = config.get("worker_replication_http_port")

synapse/replication/tcp/handler.py

+21-37
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
from synapse.metrics import LaterGauge
3737
from synapse.metrics.background_process_metrics import run_as_background_process
38-
from synapse.replication.tcp.client import DirectTcpReplicationClientFactory
3938
from synapse.replication.tcp.commands import (
4039
ClearUserSyncsCommand,
4140
Command,
@@ -332,46 +331,31 @@ async def _process_command(
332331

333332
def start_replication(self, hs: "HomeServer") -> None:
334333
"""Helper method to start replication."""
335-
if hs.config.redis.redis_enabled:
336-
from synapse.replication.tcp.redis import (
337-
RedisDirectTcpReplicationClientFactory,
338-
)
334+
from synapse.replication.tcp.redis import RedisDirectTcpReplicationClientFactory
339335

340-
# First let's ensure that we have a ReplicationStreamer started.
341-
hs.get_replication_streamer()
336+
# First let's ensure that we have a ReplicationStreamer started.
337+
hs.get_replication_streamer()
342338

343-
# We need two connections to redis, one for the subscription stream and
344-
# one to send commands to (as you can't send further redis commands to a
345-
# connection after SUBSCRIBE is called).
339+
# We need two connections to redis, one for the subscription stream and
340+
# one to send commands to (as you can't send further redis commands to a
341+
# connection after SUBSCRIBE is called).
346342

347-
# First create the connection for sending commands.
348-
outbound_redis_connection = hs.get_outbound_redis_connection()
343+
# First create the connection for sending commands.
344+
outbound_redis_connection = hs.get_outbound_redis_connection()
349345

350-
# Now create the factory/connection for the subscription stream.
351-
self._factory = RedisDirectTcpReplicationClientFactory(
352-
hs,
353-
outbound_redis_connection,
354-
channel_names=self._channels_to_subscribe_to,
355-
)
356-
hs.get_reactor().connectTCP(
357-
hs.config.redis.redis_host,
358-
hs.config.redis.redis_port,
359-
self._factory,
360-
timeout=30,
361-
bindAddress=None,
362-
)
363-
else:
364-
client_name = hs.get_instance_name()
365-
self._factory = DirectTcpReplicationClientFactory(hs, client_name, self)
366-
host = hs.config.worker.worker_replication_host
367-
port = hs.config.worker.worker_replication_port
368-
hs.get_reactor().connectTCP(
369-
host,
370-
port,
371-
self._factory,
372-
timeout=30,
373-
bindAddress=None,
374-
)
346+
# Now create the factory/connection for the subscription stream.
347+
self._factory = RedisDirectTcpReplicationClientFactory(
348+
hs,
349+
outbound_redis_connection,
350+
channel_names=self._channels_to_subscribe_to,
351+
)
352+
hs.get_reactor().connectTCP(
353+
hs.config.redis.redis_host,
354+
hs.config.redis.redis_port,
355+
self._factory,
356+
timeout=30,
357+
bindAddress=None,
358+
)
375359

376360
def get_streams(self) -> Dict[str, Stream]:
377361
"""Get a map from stream name to all streams."""

tests/app/test_openid_listener.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def test_openid_listener(self, names, expectation):
6161
}
6262

6363
# Listen with the config
64-
self.hs._listen_http(parse_listener_def(config))
64+
self.hs._listen_http(parse_listener_def(0, config))
6565

6666
# Grab the resource from the site that was told to listen
6767
site = self.reactor.tcpServers[0][1]
@@ -109,7 +109,7 @@ def test_openid_listener(self, names, expectation):
109109
}
110110

111111
# Listen with the config
112-
self.hs._listener_http(self.hs.config, parse_listener_def(config))
112+
self.hs._listener_http(self.hs.config, parse_listener_def(0, config))
113113

114114
# Grab the resource from the site that was told to listen
115115
site = self.reactor.tcpServers[0][1]

tests/test_server.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def _make_request(self, method: bytes, path: bytes) -> FakeChannel:
228228
site = SynapseSite(
229229
"test",
230230
"site_tag",
231-
parse_listener_def({"type": "http", "port": 0}),
231+
parse_listener_def(0, {"type": "http", "port": 0}),
232232
self.resource,
233233
"1.0",
234234
max_request_body_size=4096,

tests/utils.py

-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ def default_config(
135135
"enable_registration_captcha": False,
136136
"macaroon_secret_key": "not even a little secret",
137137
"password_providers": [],
138-
"worker_replication_url": "",
139138
"worker_app": None,
140139
"block_non_admin_invites": False,
141140
"federation_domain_whitelist": None,

0 commit comments

Comments
 (0)